2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import static jalview.util.UrlConstants.SEQUENCE_ID;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileFormats;
34 import jalview.io.FileLoader;
35 import jalview.io.FormatAdapter;
36 import jalview.io.IdentifyFile;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.jbgui.GSplitFrame;
40 import jalview.jbgui.GStructureViewer;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.util.dialogrunner.RunResponse;
48 import jalview.viewmodel.AlignmentViewport;
49 import jalview.ws.params.ParamManager;
50 import jalview.ws.utils.UrlDownloadClient;
52 import java.awt.BorderLayout;
53 import java.awt.Color;
54 import java.awt.Dimension;
55 import java.awt.FontMetrics;
56 import java.awt.Graphics;
57 import java.awt.GridLayout;
58 import java.awt.Point;
59 import java.awt.Rectangle;
60 import java.awt.Toolkit;
61 import java.awt.Window;
62 import java.awt.datatransfer.Clipboard;
63 import java.awt.datatransfer.ClipboardOwner;
64 import java.awt.datatransfer.DataFlavor;
65 import java.awt.datatransfer.Transferable;
66 import java.awt.dnd.DnDConstants;
67 import java.awt.dnd.DropTargetDragEvent;
68 import java.awt.dnd.DropTargetDropEvent;
69 import java.awt.dnd.DropTargetEvent;
70 import java.awt.dnd.DropTargetListener;
71 import java.awt.event.ActionEvent;
72 import java.awt.event.ActionListener;
73 import java.awt.event.InputEvent;
74 import java.awt.event.KeyEvent;
75 import java.awt.event.MouseAdapter;
76 import java.awt.event.MouseEvent;
77 import java.awt.event.WindowAdapter;
78 import java.awt.event.WindowEvent;
79 import java.beans.PropertyChangeEvent;
80 import java.beans.PropertyChangeListener;
81 import java.io.BufferedInputStream;
83 import java.io.FileOutputStream;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.Hashtable;
88 import java.util.List;
89 import java.util.ListIterator;
90 import java.util.StringTokenizer;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFrame;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.KeyStroke;
117 import javax.swing.SwingUtilities;
118 import javax.swing.event.HyperlinkEvent;
119 import javax.swing.event.HyperlinkEvent.EventType;
120 import javax.swing.event.InternalFrameAdapter;
121 import javax.swing.event.InternalFrameEvent;
122 import javax.swing.event.MenuEvent;
123 import javax.swing.event.MenuListener;
125 import org.stackoverflowusers.file.WindowsShortcut;
132 * @version $Revision: 1.155 $
134 public class Desktop extends jalview.jbgui.GDesktop
135 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
136 jalview.api.StructureSelectionManagerProvider
138 private static int DEFAULT_MIN_WIDTH = 300;
140 private static int DEFAULT_MIN_HEIGHT = 250;
142 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
144 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
146 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
148 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
151 * news reader - null if it was never started.
153 private BlogReader jvnews = null;
155 private File projectFile;
159 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
161 public void addJalviewPropertyChangeListener(
162 PropertyChangeListener listener)
164 changeSupport.addJalviewPropertyChangeListener(listener);
168 * @param propertyName
170 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
171 * java.beans.PropertyChangeListener)
173 public void addJalviewPropertyChangeListener(String propertyName,
174 PropertyChangeListener listener)
176 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
180 * @param propertyName
182 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
183 * java.beans.PropertyChangeListener)
185 public void removeJalviewPropertyChangeListener(String propertyName,
186 PropertyChangeListener listener)
188 changeSupport.removeJalviewPropertyChangeListener(propertyName,
192 /** Singleton Desktop instance */
193 public static Desktop instance;
195 public static MyDesktopPane desktop;
197 public static MyDesktopPane getDesktop()
199 // BH 2018 could use currentThread() here as a reference to a
200 // Hashtable<Thread, MyDesktopPane> in JavaScript
204 static int openFrameCount = 0;
206 static final int xOffset = 30;
208 static final int yOffset = 30;
210 public static jalview.ws.jws1.Discoverer discoverer;
212 public static Object[] jalviewClipboard;
214 public static boolean internalCopy = false;
216 static int fileLoadingCount = 0;
218 class MyDesktopManager implements DesktopManager
221 private DesktopManager delegate;
223 public MyDesktopManager(DesktopManager delegate)
225 this.delegate = delegate;
229 public void activateFrame(JInternalFrame f)
233 delegate.activateFrame(f);
234 } catch (NullPointerException npe)
236 Point p = getMousePosition();
237 instance.showPasteMenu(p.x, p.y);
242 public void beginDraggingFrame(JComponent f)
244 delegate.beginDraggingFrame(f);
248 public void beginResizingFrame(JComponent f, int direction)
250 delegate.beginResizingFrame(f, direction);
254 public void closeFrame(JInternalFrame f)
256 delegate.closeFrame(f);
260 public void deactivateFrame(JInternalFrame f)
262 delegate.deactivateFrame(f);
266 public void deiconifyFrame(JInternalFrame f)
268 delegate.deiconifyFrame(f);
272 public void dragFrame(JComponent f, int newX, int newY)
278 delegate.dragFrame(f, newX, newY);
282 public void endDraggingFrame(JComponent f)
284 delegate.endDraggingFrame(f);
289 public void endResizingFrame(JComponent f)
291 delegate.endResizingFrame(f);
296 public void iconifyFrame(JInternalFrame f)
298 delegate.iconifyFrame(f);
302 public void maximizeFrame(JInternalFrame f)
304 delegate.maximizeFrame(f);
308 public void minimizeFrame(JInternalFrame f)
310 delegate.minimizeFrame(f);
314 public void openFrame(JInternalFrame f)
316 delegate.openFrame(f);
320 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
327 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
331 public void setBoundsForFrame(JComponent f, int newX, int newY,
332 int newWidth, int newHeight)
334 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
337 // All other methods, simply delegate
342 * Creates a new Desktop object.
347 * A note to implementors. It is ESSENTIAL that any activities that might block
348 * are spawned off as threads rather than waited for during this constructor.
351 doVamsasClientCheck();
353 doConfigureStructurePrefs();
354 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
355 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
356 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
358 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
360 desktop = new MyDesktopPane(selmemusage);
361 showMemusage.setSelected(selmemusage);
362 desktop.setBackground(Color.white);
363 getContentPane().setLayout(new BorderLayout());
364 // alternate config - have scrollbars - see notes in JAL-153
365 // JScrollPane sp = new JScrollPane();
366 // sp.getViewport().setView(desktop);
367 // getContentPane().add(sp, BorderLayout.CENTER);
368 getContentPane().add(desktop, BorderLayout.CENTER);
369 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
371 // This line prevents Windows Look&Feel resizing all new windows to maximum
372 // if previous window was maximised
373 desktop.setDesktopManager(new MyDesktopManager(
374 (Platform.isWindows() ? new DefaultDesktopManager()
376 ? new AquaInternalFrameManager(
377 desktop.getDesktopManager())
378 : desktop.getDesktopManager())));
380 Rectangle dims = getLastKnownDimensions("");
387 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
388 int xPos = Math.max(5, (screenSize.width - 900) / 2);
389 int yPos = Math.max(5, (screenSize.height - 650) / 2);
390 setBounds(xPos, yPos, 900, 650);
399 jconsole = new Console(this, showjconsole);
400 // add essential build information
401 jconsole.setHeader("Jalview Version: "
402 + jalview.bin.Cache.getProperty("VERSION") + "\n"
403 + "Jalview Installation: "
404 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
405 + "\n" + "Build Date: "
406 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
407 + "Java version: " + System.getProperty("java.version") + "\n"
408 + System.getProperty("os.arch") + " "
409 + System.getProperty("os.name") + " "
410 + System.getProperty("os.version"));
412 showConsole(showjconsole);
414 showNews.setVisible(false);
416 experimentalFeatures.setSelected(showExperimental());
418 getIdentifiersOrgData();
422 // Spawn a thread that shows the splashscreen
424 SwingUtilities.invokeLater(new Runnable()
433 // Thread off a new instance of the file chooser - this reduces the time it
434 // takes to open it later on.
435 new Thread(new Runnable()
440 Cache.log.debug("Filechooser init thread started.");
441 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
442 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
444 Cache.log.debug("Filechooser init thread finished.");
447 // Add the service change listener
448 changeSupport.addJalviewPropertyChangeListener("services",
449 new PropertyChangeListener()
453 public void propertyChange(PropertyChangeEvent evt)
455 Cache.log.debug("Firing service changed event for "
456 + evt.getNewValue());
457 JalviewServicesChanged(evt);
462 } // end BH 2018 ignore
464 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
466 this.addWindowListener(new WindowAdapter()
469 public void windowClosing(WindowEvent evt)
476 this.addMouseListener(ma = new MouseAdapter()
479 public void mousePressed(MouseEvent evt)
481 if (evt.isPopupTrigger()) // Mac
483 showPasteMenu(evt.getX(), evt.getY());
488 public void mouseReleased(MouseEvent evt)
490 if (evt.isPopupTrigger()) // Windows
492 showPasteMenu(evt.getX(), evt.getY());
496 desktop.addMouseListener(ma);
501 * Answers true if user preferences to enable experimental features is True
506 public boolean showExperimental()
508 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
509 Boolean.FALSE.toString());
510 return Boolean.valueOf(experimental).booleanValue();
513 public void doConfigureStructurePrefs()
515 // configure services
516 StructureSelectionManager ssm = StructureSelectionManager
517 .getStructureSelectionManager(this);
518 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
520 ssm.setAddTempFacAnnot(jalview.bin.Cache
521 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
522 ssm.setProcessSecondaryStructure(jalview.bin.Cache
523 .getDefault(Preferences.STRUCT_FROM_PDB, true));
524 ssm.setSecStructServices(
525 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
529 ssm.setAddTempFacAnnot(false);
530 ssm.setProcessSecondaryStructure(false);
531 ssm.setSecStructServices(false);
535 public void checkForNews()
544 final Desktop me = this;
545 // Thread off the news reader, in case there are connection problems.
546 addDialogThread(new Runnable()
551 Cache.log.debug("Starting news thread.");
553 jvnews = new BlogReader(me);
554 showNews.setVisible(true);
555 Cache.log.debug("Completed news thread.");
561 public void getIdentifiersOrgData()
563 // Thread off the identifiers fetcher
564 addDialogThread(new Runnable()
569 Cache.log.debug("Downloading data from identifiers.org");
570 UrlDownloadClient client = new UrlDownloadClient();
573 client.download(IdOrgSettings.getUrl(),
574 IdOrgSettings.getDownloadLocation());
575 } catch (IOException e)
577 Cache.log.debug("Exception downloading identifiers.org data"
585 protected void showNews_actionPerformed(ActionEvent e)
587 showNews(showNews.isSelected());
590 void showNews(boolean visible)
599 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
600 showNews.setSelected(visible);
601 if (visible && !jvnews.isVisible())
603 new Thread(new Runnable()
608 long now = System.currentTimeMillis();
609 Desktop.instance.setProgressBar(
610 MessageManager.getString("status.refreshing_news"),
612 jvnews.refreshNews();
613 Desktop.instance.setProgressBar(null, now);
622 * recover the last known dimensions for a jalview window
625 * - empty string is desktop, all other windows have unique prefix
626 * @return null or last known dimensions scaled to current geometry (if last
627 * window geom was known)
629 Rectangle getLastKnownDimensions(String windowName)
631 // TODO: lock aspect ratio for scaling desktop Bug #0058199
632 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
633 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
634 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
635 String width = jalview.bin.Cache
636 .getProperty(windowName + "SCREEN_WIDTH");
637 String height = jalview.bin.Cache
638 .getProperty(windowName + "SCREEN_HEIGHT");
639 if ((x != null) && (y != null) && (width != null) && (height != null))
641 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
642 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
643 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
645 // attempt #1 - try to cope with change in screen geometry - this
646 // version doesn't preserve original jv aspect ratio.
647 // take ratio of current screen size vs original screen size.
648 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
649 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
650 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
651 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
652 // rescale the bounds depending upon the current screen geometry.
653 ix = (int) (ix * sw);
654 iw = (int) (iw * sw);
655 iy = (int) (iy * sh);
656 ih = (int) (ih * sh);
657 while (ix >= screenSize.width)
659 jalview.bin.Cache.log.debug(
660 "Window geometry location recall error: shifting horizontal to within screenbounds.");
661 ix -= screenSize.width;
663 while (iy >= screenSize.height)
665 jalview.bin.Cache.log.debug(
666 "Window geometry location recall error: shifting vertical to within screenbounds.");
667 iy -= screenSize.height;
669 jalview.bin.Cache.log.debug(
670 "Got last known dimensions for " + windowName + ": x:" + ix
671 + " y:" + iy + " width:" + iw + " height:" + ih);
673 // return dimensions for new instance
674 return new Rectangle(ix, iy, iw, ih);
679 private void doVamsasClientCheck()
681 if (/** @j2sNative false && */ // BH 2018
682 jalview.bin.Cache.vamsasJarsPresent())
684 setupVamsasDisconnectedGui();
685 VamsasMenu.setVisible(true);
686 final Desktop us = this;
687 VamsasMenu.addMenuListener(new MenuListener()
689 // this listener remembers when the menu was first selected, and
690 // doesn't rebuild the session list until it has been cleared and
692 boolean refresh = true;
695 public void menuCanceled(MenuEvent e)
701 public void menuDeselected(MenuEvent e)
707 public void menuSelected(MenuEvent e)
711 us.buildVamsasStMenu();
716 vamsasStart.setVisible(true);
720 void showPasteMenu(int x, int y)
722 JPopupMenu popup = new JPopupMenu();
723 JMenuItem item = new JMenuItem(
724 MessageManager.getString("label.paste_new_window"));
725 item.addActionListener(new ActionListener()
728 public void actionPerformed(ActionEvent evt)
735 popup.show(this, x, y);
742 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
743 Transferable contents = c.getContents(this);
745 if (contents != null)
747 String file = (String) contents
748 .getTransferData(DataFlavor.stringFlavor);
750 FileFormatI format = new IdentifyFile().identify(file,
751 DataSourceType.PASTE);
753 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
756 } catch (Exception ex)
759 "Unable to paste alignment from system clipboard:\n" + ex);
764 * Adds and opens the given frame to the desktop
775 public static synchronized void addInternalFrame(
776 final JInternalFrame frame, String title, int w, int h)
778 addInternalFrame(frame, title, true, w, h, true, false);
782 * Add an internal frame to the Jalview desktop
789 * When true, display frame immediately, otherwise, caller must call
790 * setVisible themselves.
796 public static synchronized void addInternalFrame(
797 final JInternalFrame frame, String title, boolean makeVisible,
800 addInternalFrame(frame, title, makeVisible, w, h, true, false);
804 * Add an internal frame to the Jalview desktop and make it visible
817 public static synchronized void addInternalFrame(
818 final JInternalFrame frame, String title, int w, int h,
821 addInternalFrame(frame, title, true, w, h, resizable, false);
825 * Add an internal frame to the Jalview desktop
832 * When true, display frame immediately, otherwise, caller must call
833 * setVisible themselves.
840 * @param ignoreMinSize
841 * Do not set the default minimum size for frame
843 public static synchronized void addInternalFrame(
844 final JInternalFrame frame, String title, boolean makeVisible,
845 int w, int h, boolean resizable, boolean ignoreMinSize)
848 // TODO: allow callers to determine X and Y position of frame (eg. via
850 // TODO: consider fixing method to update entries in the window submenu with
851 // the current window title
853 frame.setTitle(title);
854 if (frame.getWidth() < 1 || frame.getHeight() < 1)
858 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
859 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
860 // IF JALVIEW IS RUNNING HEADLESS
861 // ///////////////////////////////////////////////
862 if (instance == null || (System.getProperty("java.awt.headless") != null
863 && System.getProperty("java.awt.headless").equals("true")))
872 frame.setMinimumSize(
873 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
875 // Set default dimension for Alignment Frame window.
876 // The Alignment Frame window could be added from a number of places,
878 // I did this here in order not to miss out on any Alignment frame.
879 if (frame instanceof AlignFrame)
881 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
882 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
886 frame.setVisible(makeVisible);
887 frame.setClosable(true);
888 frame.setResizable(resizable);
889 frame.setMaximizable(resizable);
890 frame.setIconifiable(resizable);
891 frame.setOpaque(/** @j2sNative true || */
894 if (frame.getX() < 1 && frame.getY() < 1)
896 frame.setLocation(xOffset * openFrameCount,
897 yOffset * ((openFrameCount - 1) % 10) + yOffset);
901 * add an entry for the new frame in the Window menu
902 * (and remove it when the frame is closed)
904 final JMenuItem menuItem = new JMenuItem(title);
905 frame.addInternalFrameListener(new InternalFrameAdapter()
908 public void internalFrameActivated(InternalFrameEvent evt)
910 JInternalFrame itf = desktop.getSelectedFrame();
913 if (itf instanceof AlignFrame)
915 Jalview.setCurrentAlignFrame((AlignFrame) itf);
922 public void internalFrameClosed(InternalFrameEvent evt)
924 PaintRefresher.RemoveComponent(frame);
927 * defensive check to prevent frames being
928 * added half off the window
930 if (openFrameCount > 0)
936 * ensure no reference to alignFrame retained by menu item listener
938 if (menuItem.getActionListeners().length > 0)
940 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
942 windowMenu.remove(menuItem);
946 menuItem.addActionListener(new ActionListener()
949 public void actionPerformed(ActionEvent e)
953 frame.setSelected(true);
954 frame.setIcon(false);
955 } catch (java.beans.PropertyVetoException ex)
962 setKeyBindings(frame);
966 windowMenu.add(menuItem);
971 frame.setSelected(true);
972 frame.requestFocus();
973 } catch (java.beans.PropertyVetoException ve)
975 } catch (java.lang.ClassCastException cex)
978 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
984 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
989 private static void setKeyBindings(JInternalFrame frame)
991 @SuppressWarnings("serial")
992 final Action closeAction = new AbstractAction()
995 public void actionPerformed(ActionEvent e)
1002 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1004 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1005 InputEvent.CTRL_DOWN_MASK);
1006 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1007 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1009 InputMap inputMap = frame
1010 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1011 String ctrlW = ctrlWKey.toString();
1012 inputMap.put(ctrlWKey, ctrlW);
1013 inputMap.put(cmdWKey, ctrlW);
1015 ActionMap actionMap = frame.getActionMap();
1016 actionMap.put(ctrlW, closeAction);
1020 public void lostOwnership(Clipboard clipboard, Transferable contents)
1024 Desktop.jalviewClipboard = null;
1027 internalCopy = false;
1031 public void dragEnter(DropTargetDragEvent evt)
1036 public void dragExit(DropTargetEvent evt)
1041 public void dragOver(DropTargetDragEvent evt)
1046 public void dropActionChanged(DropTargetDragEvent evt)
1057 public void drop(DropTargetDropEvent evt)
1059 boolean success = true;
1060 // JAL-1552 - acceptDrop required before getTransferable call for
1061 // Java's Transferable for native dnd
1062 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1063 Transferable t = evt.getTransferable();
1064 List<Object> files = new ArrayList<>();
1065 List<DataSourceType> protocols = new ArrayList<>();
1069 Desktop.transferFromDropTarget(files, protocols, evt, t);
1070 } catch (Exception e)
1072 e.printStackTrace();
1080 for (int i = 0; i < files.size(); i++)
1082 // BH 2018 File or String
1083 Object file = files.get(i);
1084 String fileName = file.toString();
1085 DataSourceType protocol = (protocols == null)
1086 ? DataSourceType.FILE
1088 FileFormatI format = null;
1090 if (fileName.endsWith(".jar"))
1092 format = FileFormat.Jalview;
1097 format = new IdentifyFile().identify(file, protocol);
1100 new FileLoader().LoadFile(null, file, protocol, format);
1103 } catch (Exception ex)
1108 evt.dropComplete(success); // need this to ensure input focus is properly
1109 // transfered to any new windows created
1119 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1121 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1122 final JalviewFileChooser chooser = JalviewFileChooser
1123 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1125 chooser.setFileView(new JalviewFileView());
1126 chooser.setDialogTitle(
1127 MessageManager.getString("label.open_local_file"));
1128 chooser.setToolTipText(MessageManager.getString("action.open"));
1130 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1136 File selectedFile = chooser.getSelectedFile();
1137 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1139 FileFormatI format = chooser.getSelectedFormat();
1142 * Call IdentifyFile to verify the file contains what its extension implies.
1143 * Skip this step for dynamically added file formats, because
1144 * IdentifyFile does not know how to recognise them.
1146 if (FileFormats.getInstance().isIdentifiable(format))
1150 format = new IdentifyFile().identify(selectedFile,
1151 DataSourceType.FILE);
1152 } catch (FileFormatException e)
1154 // format = null; //??
1158 new FileLoader().LoadFile(viewport, selectedFile,
1159 DataSourceType.FILE, format);
1161 }).openDialog(this);
1171 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1173 // This construct allows us to have a wider textfield
1175 JLabel label = new JLabel(
1176 MessageManager.getString("label.input_file_url"));
1178 JComboBox history = new JComboBox();
1179 JPanel panel = new JPanel(new GridLayout(2, 1));
1182 history.setPreferredSize(new Dimension(400, 20));
1183 history.setEditable(true);
1184 history.addItem("http://www.");
1186 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1190 if (historyItems != null)
1192 st = new StringTokenizer(historyItems, "\t");
1194 while (st.hasMoreTokens())
1196 history.addItem(st.nextElement());
1200 // BH 2018 -- providing a callback for SwingJS
1201 // dialogOption is just a simple way to provide
1202 // context for the modal-like response.
1203 // The only requirement is that desktop implement
1204 // PropertyChangeListener, which is used already in Java
1205 // for changes in input value and such within the dialogs.
1207 String dialogOption = "label.input_alignment_from_url";
1208 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1209 desktop.onDialogReturn(JvOptionPane.showInternalConfirmDialog(desktop,
1210 panel, MessageManager.getString(dialogOption),
1211 JvOptionPane.OK_CANCEL_OPTION));
1213 // no code may follow this, as SwingJS will not block
1214 // callback in JavaScript comes via a property change event,
1215 // thus going into desktop.onDialogReturn(int) just the same as
1221 * Opens the CutAndPaste window for the user to paste an alignment in to
1224 * - if not null, the pasted alignment is added to the current
1225 * alignment; if null, to a new alignment window
1228 public void inputTextboxMenuItem_actionPerformed(
1229 AlignmentViewPanel viewPanel)
1231 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1232 cap.setForInput(viewPanel);
1233 Desktop.addInternalFrame(cap,
1234 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1244 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1245 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1247 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1248 screen.height + "");
1249 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1250 getWidth(), getHeight()));
1252 if (jconsole != null)
1254 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1255 jconsole.stopConsole();
1259 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1262 if (dialogExecutor != null)
1264 dialogExecutor.shutdownNow();
1266 closeAll_actionPerformed(null);
1268 if (groovyConsole != null)
1270 // suppress a possible repeat prompt to save script
1271 groovyConsole.setDirty(false);
1272 groovyConsole.exit();
1277 private void storeLastKnownDimensions(String string, Rectangle jc)
1279 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1280 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1281 + " height:" + jc.height);
1283 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1284 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1285 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1286 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1296 public void aboutMenuItem_actionPerformed(ActionEvent e)
1298 // StringBuffer message = getAboutMessage(false);
1299 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1301 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1302 new Thread(new Runnable()
1307 new SplashScreen(true);
1312 public StringBuffer getAboutMessage(boolean shortv)
1314 StringBuffer message = new StringBuffer();
1315 message.append("<html>");
1318 message.append("<h1><strong>Version: "
1319 + jalview.bin.Cache.getProperty("VERSION")
1320 + "</strong></h1>");
1321 message.append("<strong>Last Updated: <em>"
1322 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1323 + "</em></strong>");
1329 message.append("<strong>Version "
1330 + jalview.bin.Cache.getProperty("VERSION")
1331 + "; last updated: "
1332 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1335 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1336 .equals("Checking"))
1338 message.append("<br>...Checking latest version...</br>");
1340 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1341 .equals(jalview.bin.Cache.getProperty("VERSION")))
1343 boolean red = false;
1344 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1345 .indexOf("automated build") == -1)
1348 // Displayed when code version and jnlp version do not match and code
1349 // version is not a development build
1350 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1353 message.append("<br>!! Version "
1354 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1356 + " is available for download from "
1357 + jalview.bin.Cache.getDefault("www.jalview.org",
1358 "http://www.jalview.org")
1362 message.append("</div>");
1365 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1367 "The Jalview Authors (See AUTHORS file for current list)")
1368 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1369 + "<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"
1370 + "<br><br>If you use Jalview, please cite:"
1371 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1372 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1373 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1385 public void documentationMenuItem_actionPerformed(ActionEvent e)
1389 Help.showHelpWindow();
1390 } catch (Exception ex)
1396 public void closeAll_actionPerformed(ActionEvent e)
1398 // TODO show a progress bar while closing?
1399 JInternalFrame[] frames = desktop.getAllFrames();
1400 for (int i = 0; i < frames.length; i++)
1404 frames[i].setClosed(true);
1405 } catch (java.beans.PropertyVetoException ex)
1409 Jalview.setCurrentAlignFrame(null);
1410 System.out.println("ALL CLOSED");
1411 if (v_client != null)
1413 // TODO clear binding to vamsas document objects on close_all
1417 * reset state of singleton objects as appropriate (clear down session state
1418 * when all windows are closed)
1420 StructureSelectionManager ssm = StructureSelectionManager
1421 .getStructureSelectionManager(this);
1429 public void raiseRelated_actionPerformed(ActionEvent e)
1431 reorderAssociatedWindows(false, false);
1435 public void minimizeAssociated_actionPerformed(ActionEvent e)
1437 reorderAssociatedWindows(true, false);
1440 void closeAssociatedWindows()
1442 reorderAssociatedWindows(false, true);
1448 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1452 protected void garbageCollect_actionPerformed(ActionEvent e)
1454 // We simply collect the garbage
1455 jalview.bin.Cache.log.debug("Collecting garbage...");
1457 jalview.bin.Cache.log.debug("Finished garbage collection.");
1464 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1468 protected void showMemusage_actionPerformed(ActionEvent e)
1470 desktop.showMemoryUsage(showMemusage.isSelected());
1477 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1481 protected void showConsole_actionPerformed(ActionEvent e)
1483 showConsole(showConsole.isSelected());
1486 Console jconsole = null;
1489 * control whether the java console is visible or not
1493 void showConsole(boolean selected)
1495 // TODO: decide if we should update properties file
1496 if (jconsole != null) // BH 2018
1498 showConsole.setSelected(selected);
1499 Cache.setProperty("SHOW_JAVA_CONSOLE",
1500 Boolean.valueOf(selected).toString());
1501 jconsole.setVisible(selected);
1505 void reorderAssociatedWindows(boolean minimize, boolean close)
1507 JInternalFrame[] frames = desktop.getAllFrames();
1508 if (frames == null || frames.length < 1)
1513 AlignmentViewport source = null, target = null;
1514 if (frames[0] instanceof AlignFrame)
1516 source = ((AlignFrame) frames[0]).getCurrentView();
1518 else if (frames[0] instanceof TreePanel)
1520 source = ((TreePanel) frames[0]).getViewPort();
1522 else if (frames[0] instanceof PCAPanel)
1524 source = ((PCAPanel) frames[0]).av;
1526 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1528 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1533 for (int i = 0; i < frames.length; i++)
1536 if (frames[i] == null)
1540 if (frames[i] instanceof AlignFrame)
1542 target = ((AlignFrame) frames[i]).getCurrentView();
1544 else if (frames[i] instanceof TreePanel)
1546 target = ((TreePanel) frames[i]).getViewPort();
1548 else if (frames[i] instanceof PCAPanel)
1550 target = ((PCAPanel) frames[i]).av;
1552 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1554 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1557 if (source == target)
1563 frames[i].setClosed(true);
1567 frames[i].setIcon(minimize);
1570 frames[i].toFront();
1574 } catch (java.beans.PropertyVetoException ex)
1589 protected void preferences_actionPerformed(ActionEvent e)
1601 public void saveState_actionPerformed(ActionEvent e)
1603 // TODO: JAL-3048 not needed for Jalview-JS
1605 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1608 chooser.setFileView(new JalviewFileView());
1609 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1611 int value = chooser.showSaveDialog(this);
1613 if (value == JalviewFileChooser.APPROVE_OPTION)
1615 final Desktop me = this;
1616 final java.io.File choice = chooser.getSelectedFile();
1617 setProjectFile(choice);
1619 new Thread(new Runnable()
1624 // TODO: refactor to Jalview desktop session controller action.
1625 setProgressBar(MessageManager.formatMessage(
1626 "label.saving_jalview_project", new Object[]
1627 { choice.getName() }), choice.hashCode());
1628 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1629 choice.getParent());
1630 // TODO catch and handle errors for savestate
1631 // TODO prevent user from messing with the Desktop whilst we're saving
1634 new Jalview2XML().saveState(choice);
1635 } catch (OutOfMemoryError oom)
1638 "Whilst saving current state to " + choice.getName(),
1640 } catch (Exception ex)
1643 "Problems whilst trying to save to " + choice.getName(),
1645 JvOptionPane.showMessageDialog(me,
1646 MessageManager.formatMessage(
1647 "label.error_whilst_saving_current_state_to",
1649 { choice.getName() }),
1650 MessageManager.getString("label.couldnt_save_project"),
1651 JvOptionPane.WARNING_MESSAGE);
1653 setProgressBar(null, choice.hashCode());
1659 private void setProjectFile(File choice)
1661 this.projectFile = choice;
1664 public File getProjectFile()
1666 return this.projectFile;
1676 public void loadState_actionPerformed(ActionEvent e)
1678 // TODO: JAL-3048 not needed for Jalview-JS
1680 JalviewFileChooser chooser = new JalviewFileChooser(
1681 Cache.getProperty("LAST_DIRECTORY"), new String[]
1684 { "Jalview Project", "Jalview Project (old)" },
1686 chooser.setFileView(new JalviewFileView());
1687 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1689 int value = chooser.showOpenDialog(this);
1691 if (value == JalviewFileChooser.APPROVE_OPTION)
1693 final File selectedFile = chooser.getSelectedFile();
1694 setProjectFile(selectedFile);
1695 final String choice = selectedFile.getAbsolutePath();
1696 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1697 new Thread(new Runnable()
1702 setProgressBar(MessageManager.formatMessage(
1703 "label.loading_jalview_project", new Object[]
1704 { choice }), choice.hashCode());
1707 new Jalview2XML().loadJalviewAlign(choice);
1708 } catch (OutOfMemoryError oom)
1710 new OOMWarning("Whilst loading project from " + choice, oom);
1711 } catch (Exception ex)
1714 "Problems whilst loading project from " + choice, ex);
1715 JvOptionPane.showMessageDialog(Desktop.desktop,
1716 MessageManager.formatMessage(
1717 "label.error_whilst_loading_project_from",
1720 MessageManager.getString("label.couldnt_load_project"),
1721 JvOptionPane.WARNING_MESSAGE);
1723 setProgressBar(null, choice.hashCode());
1730 public void inputSequence_actionPerformed(ActionEvent e)
1732 new SequenceFetcher(this);
1735 JPanel progressPanel;
1737 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1739 public void startLoading(final Object fileName)
1741 if (fileLoadingCount == 0)
1743 fileLoadingPanels.add(addProgressPanel(MessageManager
1744 .formatMessage("label.loading_file", new Object[]
1750 private JPanel addProgressPanel(String string)
1752 if (progressPanel == null)
1754 progressPanel = new JPanel(new GridLayout(1, 1));
1755 totalProgressCount = 0;
1756 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1758 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1759 JProgressBar progressBar = new JProgressBar();
1760 progressBar.setIndeterminate(true);
1762 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1764 thisprogress.add(progressBar, BorderLayout.CENTER);
1765 progressPanel.add(thisprogress);
1766 ((GridLayout) progressPanel.getLayout()).setRows(
1767 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1768 ++totalProgressCount;
1769 instance.validate();
1770 return thisprogress;
1773 int totalProgressCount = 0;
1775 private void removeProgressPanel(JPanel progbar)
1777 if (progressPanel != null)
1779 synchronized (progressPanel)
1781 progressPanel.remove(progbar);
1782 GridLayout gl = (GridLayout) progressPanel.getLayout();
1783 gl.setRows(gl.getRows() - 1);
1784 if (--totalProgressCount < 1)
1786 this.getContentPane().remove(progressPanel);
1787 progressPanel = null;
1794 public void stopLoading()
1797 if (fileLoadingCount < 1)
1799 while (fileLoadingPanels.size() > 0)
1801 removeProgressPanel(fileLoadingPanels.remove(0));
1803 fileLoadingPanels.clear();
1804 fileLoadingCount = 0;
1809 public static int getViewCount(String alignmentId)
1811 AlignmentViewport[] aps = getViewports(alignmentId);
1812 return (aps == null) ? 0 : aps.length;
1817 * @param alignmentId
1818 * - if null, all sets are returned
1819 * @return all AlignmentPanels concerning the alignmentId sequence set
1821 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1823 if (Desktop.desktop == null)
1825 // no frames created and in headless mode
1826 // TODO: verify that frames are recoverable when in headless mode
1829 List<AlignmentPanel> aps = new ArrayList<>();
1830 AlignFrame[] frames = getAlignFrames();
1835 for (AlignFrame af : frames)
1837 for (AlignmentPanel ap : af.alignPanels)
1839 if (alignmentId == null
1840 || alignmentId.equals(ap.av.getSequenceSetId()))
1846 if (aps.size() == 0)
1850 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1855 * get all the viewports on an alignment.
1857 * @param sequenceSetId
1858 * unique alignment id (may be null - all viewports returned in that
1860 * @return all viewports on the alignment bound to sequenceSetId
1862 public static AlignmentViewport[] getViewports(String sequenceSetId)
1864 List<AlignmentViewport> viewp = new ArrayList<>();
1865 if (desktop != null)
1867 AlignFrame[] frames = Desktop.getAlignFrames();
1869 for (AlignFrame afr : frames)
1871 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1872 .equals(sequenceSetId))
1874 if (afr.alignPanels != null)
1876 for (AlignmentPanel ap : afr.alignPanels)
1878 if (sequenceSetId == null
1879 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1887 viewp.add(afr.getViewport());
1891 if (viewp.size() > 0)
1893 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1900 * Explode the views in the given frame into separate AlignFrame
1904 public static void explodeViews(AlignFrame af)
1906 int size = af.alignPanels.size();
1912 for (int i = 0; i < size; i++)
1914 AlignmentPanel ap = af.alignPanels.get(i);
1915 AlignFrame newaf = new AlignFrame(ap);
1918 * Restore the view's last exploded frame geometry if known. Multiple
1919 * views from one exploded frame share and restore the same (frame)
1920 * position and size.
1922 Rectangle geometry = ap.av.getExplodedGeometry();
1923 if (geometry != null)
1925 newaf.setBounds(geometry);
1928 ap.av.setGatherViewsHere(false);
1930 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1931 AlignFrame.DEFAULT_HEIGHT);
1934 af.alignPanels.clear();
1935 af.closeMenuItem_actionPerformed(true);
1940 * Gather expanded views (separate AlignFrame's) with the same sequence set
1941 * identifier back in to this frame as additional views, and close the expanded
1942 * views. Note the expanded frames may themselves have multiple views. We take
1947 public void gatherViews(AlignFrame source)
1949 source.viewport.setGatherViewsHere(true);
1950 source.viewport.setExplodedGeometry(source.getBounds());
1951 JInternalFrame[] frames = desktop.getAllFrames();
1952 String viewId = source.viewport.getSequenceSetId();
1954 for (int t = 0; t < frames.length; t++)
1956 if (frames[t] instanceof AlignFrame && frames[t] != source)
1958 AlignFrame af = (AlignFrame) frames[t];
1959 boolean gatherThis = false;
1960 for (int a = 0; a < af.alignPanels.size(); a++)
1962 AlignmentPanel ap = af.alignPanels.get(a);
1963 if (viewId.equals(ap.av.getSequenceSetId()))
1966 ap.av.setGatherViewsHere(false);
1967 ap.av.setExplodedGeometry(af.getBounds());
1968 source.addAlignmentPanel(ap, false);
1974 af.alignPanels.clear();
1975 af.closeMenuItem_actionPerformed(true);
1982 jalview.gui.VamsasApplication v_client = null;
1985 public void vamsasImport_actionPerformed(ActionEvent e)
1987 // TODO: JAL-3048 not needed for Jalview-JS
1989 if (v_client == null)
1991 // Load and try to start a session.
1992 JalviewFileChooser chooser = new JalviewFileChooser(
1993 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1995 chooser.setFileView(new JalviewFileView());
1996 chooser.setDialogTitle(
1997 MessageManager.getString("label.open_saved_vamsas_session"));
1998 chooser.setToolTipText(MessageManager.getString(
1999 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2001 int value = chooser.showOpenDialog(this);
2003 if (value == JalviewFileChooser.APPROVE_OPTION)
2005 String fle = chooser.getSelectedFile().toString();
2006 if (!vamsasImport(chooser.getSelectedFile()))
2008 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2009 MessageManager.formatMessage(
2010 "label.couldnt_import_as_vamsas_session",
2014 .getString("label.vamsas_document_import_failed"),
2015 JvOptionPane.ERROR_MESSAGE);
2021 jalview.bin.Cache.log.error(
2022 "Implementation error - load session from a running session is not supported.");
2027 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2030 * @return true if import was a success and a session was started.
2032 public boolean vamsasImport(URL url)
2034 // TODO: create progress bar
2035 if (v_client != null)
2038 jalview.bin.Cache.log.error(
2039 "Implementation error - load session from a running session is not supported.");
2045 // copy the URL content to a temporary local file
2046 // TODO: be a bit cleverer here with nio (?!)
2047 File file = File.createTempFile("vdocfromurl", ".vdj");
2048 FileOutputStream fos = new FileOutputStream(file);
2049 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2050 byte[] buffer = new byte[2048];
2052 while ((ln = bis.read(buffer)) > -1)
2054 fos.write(buffer, 0, ln);
2058 v_client = new jalview.gui.VamsasApplication(this, file,
2059 url.toExternalForm());
2060 } catch (Exception ex)
2062 jalview.bin.Cache.log.error(
2063 "Failed to create new vamsas session from contents of URL "
2068 setupVamsasConnectedGui();
2069 v_client.initial_update(); // TODO: thread ?
2070 return v_client.inSession();
2074 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2077 * @return true if import was a success and a session was started.
2079 public boolean vamsasImport(File file)
2081 if (v_client != null)
2084 jalview.bin.Cache.log.error(
2085 "Implementation error - load session from a running session is not supported.");
2089 setProgressBar(MessageManager.formatMessage(
2090 "status.importing_vamsas_session_from", new Object[]
2091 { file.getName() }), file.hashCode());
2094 v_client = new jalview.gui.VamsasApplication(this, file, null);
2095 } catch (Exception ex)
2097 setProgressBar(MessageManager.formatMessage(
2098 "status.importing_vamsas_session_from", new Object[]
2099 { file.getName() }), file.hashCode());
2100 jalview.bin.Cache.log.error(
2101 "New vamsas session from existing session file failed:", ex);
2104 setupVamsasConnectedGui();
2105 v_client.initial_update(); // TODO: thread ?
2106 setProgressBar(MessageManager.formatMessage(
2107 "status.importing_vamsas_session_from", new Object[]
2108 { file.getName() }), file.hashCode());
2109 return v_client.inSession();
2112 public boolean joinVamsasSession(String mysesid)
2114 if (v_client != null)
2116 throw new Error(MessageManager
2117 .getString("error.try_join_vamsas_session_another"));
2119 if (mysesid == null)
2122 MessageManager.getString("error.invalid_vamsas_session_id"));
2124 v_client = new VamsasApplication(this, mysesid);
2125 setupVamsasConnectedGui();
2126 v_client.initial_update();
2127 return (v_client.inSession());
2131 public void vamsasStart_actionPerformed(ActionEvent e)
2133 if (v_client == null)
2136 // we just start a default session for moment.
2138 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2139 * getProperty("LAST_DIRECTORY"));
2141 * chooser.setFileView(new JalviewFileView());
2142 * chooser.setDialogTitle("Load Vamsas file");
2143 * chooser.setToolTipText("Import");
2145 * int value = chooser.showOpenDialog(this);
2147 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2148 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2150 v_client = new VamsasApplication(this);
2151 setupVamsasConnectedGui();
2152 v_client.initial_update(); // TODO: thread ?
2156 // store current data in session.
2157 v_client.push_update(); // TODO: thread
2161 protected void setupVamsasConnectedGui()
2163 vamsasStart.setText(MessageManager.getString("label.session_update"));
2164 vamsasSave.setVisible(true);
2165 vamsasStop.setVisible(true);
2166 vamsasImport.setVisible(false); // Document import to existing session is
2167 // not possible for vamsas-client-1.0.
2170 protected void setupVamsasDisconnectedGui()
2172 vamsasSave.setVisible(false);
2173 vamsasStop.setVisible(false);
2174 vamsasImport.setVisible(true);
2176 .setText(MessageManager.getString("label.new_vamsas_session"));
2180 public void vamsasStop_actionPerformed(ActionEvent e)
2182 if (v_client != null)
2184 v_client.end_session();
2186 setupVamsasDisconnectedGui();
2190 protected void buildVamsasStMenu()
2192 if (v_client == null)
2194 String[] sess = null;
2197 sess = VamsasApplication.getSessionList();
2198 } catch (Exception e)
2200 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2206 jalview.bin.Cache.log.debug(
2207 "Got current sessions list: " + sess.length + " entries.");
2208 VamsasStMenu.removeAll();
2209 for (int i = 0; i < sess.length; i++)
2211 JMenuItem sessit = new JMenuItem();
2212 sessit.setText(sess[i]);
2213 sessit.setToolTipText(MessageManager
2214 .formatMessage("label.connect_to_session", new Object[]
2216 final Desktop dsktp = this;
2217 final String mysesid = sess[i];
2218 sessit.addActionListener(new ActionListener()
2222 public void actionPerformed(ActionEvent e)
2224 if (dsktp.v_client == null)
2226 Thread rthr = new Thread(new Runnable()
2232 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2233 dsktp.setupVamsasConnectedGui();
2234 dsktp.v_client.initial_update();
2242 VamsasStMenu.add(sessit);
2244 // don't show an empty menu.
2245 VamsasStMenu.setVisible(sess.length > 0);
2250 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2251 VamsasStMenu.removeAll();
2252 VamsasStMenu.setVisible(false);
2257 // Not interested in the content. Just hide ourselves.
2258 VamsasStMenu.setVisible(false);
2263 public void vamsasSave_actionPerformed(ActionEvent e)
2265 // TODO: JAL-3048 not needed for Jalview-JS
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 low.
2448 public class MyDesktopPane extends JDesktopPane
2449 implements Runnable, PropertyChangeListener
2452 public Object[] dialogData;
2456 public void propertyChange(PropertyChangeEvent event)
2458 Object val = event.getNewValue();
2459 String name = event.getPropertyName();
2460 System.out.println(name);
2461 switch (event.getSource().getClass().getName())
2463 case "javax.swing.JOptionPane":
2467 onDialogReturn(val);
2470 if (val instanceof Integer)
2472 onDialogReturn(((Integer) val).intValue());
2476 onDialogReturn(val);
2481 case "javax.swing.ColorChooserDialog":
2484 case "SelectedColor":
2485 onDialogReturn(val);
2489 case "javax.swing.JFileChooser":
2492 case "SelectedFile":
2493 // in JavaScript, this File object will have a _bytes property,
2494 // because the file data has already been loaded
2495 onDialogReturn(new Object[] { (File) val });
2500 System.out.println(event.getSource().getClass().getName() + " "
2501 + event.getPropertyName() + ": " + event.getNewValue());
2504 // JSCOmponent.DialogCaller interface
2505 void onDialogReturn(Object value)
2507 switch ((String) dialogData[0])
2509 case "SelectedFile":
2511 dialogData[0] = value;
2512 ((Runnable) dialogData[1]).run();
2514 case "label.select_feature_colour":
2515 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2520 // JSCOmponent.DialogCaller interface
2521 void onDialogReturn(int value)
2523 if (value != Math.floor(value))
2525 // in JavaScript, this will be NaN, oddly enough
2529 switch ((String) dialogData[0])
2532 dialogData[0] = Integer.valueOf(value);
2533 ((Runnable) dialogData[1]).run();
2535 case "label.input_alignment_from_url":
2536 // reconstruct the parameter data
2538 AlignViewport viewport = (AlignViewport) dialogData[1];
2539 JComboBox history = (JComboBox) dialogData[2];
2540 // the rest of this is unchangaed
2541 if (reply != JvOptionPane.OK_OPTION)
2546 String url = history.getSelectedItem().toString();
2548 if (url.toLowerCase().endsWith(".jar"))
2550 if (viewport != null)
2552 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2553 FileFormat.Jalview);
2557 new FileLoader().LoadFile(url, DataSourceType.URL,
2558 FileFormat.Jalview);
2563 FileFormatI format = null;
2566 format = new IdentifyFile().identify(url, DataSourceType.URL);
2567 } catch (FileFormatException e)
2569 // TODO revise error handling, distinguish between
2570 // URL not found and response not valid
2575 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2576 MessageManager.formatMessage("label.couldnt_locate",
2579 MessageManager.getString("label.url_not_found"),
2580 JvOptionPane.WARNING_MESSAGE);
2585 if (viewport != null)
2587 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2592 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2601 private static final float ONE_MB = 1048576f;
2603 boolean showMemoryUsage = false;
2607 java.text.NumberFormat df;
2609 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2612 public MyDesktopPane(boolean showMemoryUsage)
2614 showMemoryUsage(showMemoryUsage);
2617 public void showMemoryUsage(boolean showMemory)
2619 this.showMemoryUsage = showMemory;
2622 Thread worker = new Thread(this);
2628 public boolean isShowMemoryUsage()
2630 return showMemoryUsage;
2636 df = java.text.NumberFormat.getNumberInstance();
2637 df.setMaximumFractionDigits(2);
2638 runtime = Runtime.getRuntime();
2640 while (showMemoryUsage)
2644 maxMemory = runtime.maxMemory() / ONE_MB;
2645 allocatedMemory = runtime.totalMemory() / ONE_MB;
2646 freeMemory = runtime.freeMemory() / ONE_MB;
2647 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2649 percentUsage = (totalFreeMemory / maxMemory) * 100;
2651 // if (percentUsage < 20)
2653 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2655 // instance.set.setBorder(border1);
2658 // sleep after showing usage
2660 } catch (Exception ex)
2662 ex.printStackTrace();
2668 public void paintComponent(Graphics g)
2670 if (showMemoryUsage && g != null && df != null)
2672 if (percentUsage < 20)
2674 g.setColor(Color.red);
2676 FontMetrics fm = g.getFontMetrics();
2679 g.drawString(MessageManager.formatMessage("label.memory_stats",
2681 { df.format(totalFreeMemory), df.format(maxMemory),
2682 df.format(percentUsage) }),
2683 10, getHeight() - fm.getHeight());
2690 * Accessor method to quickly get all the AlignmentFrames loaded.
2692 * @return an array of AlignFrame, or null if none found
2694 public static AlignFrame[] getAlignFrames()
2696 if (Jalview.isHeadlessMode())
2698 // Desktop.desktop is null in headless mode
2699 return new AlignFrame[] { Jalview.currentAlignFrame };
2702 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2708 List<AlignFrame> avp = new ArrayList<>();
2710 for (int i = frames.length - 1; i > -1; i--)
2712 if (frames[i] instanceof AlignFrame)
2714 avp.add((AlignFrame) frames[i]);
2716 else if (frames[i] instanceof SplitFrame)
2719 * Also check for a split frame containing an AlignFrame
2721 GSplitFrame sf = (GSplitFrame) frames[i];
2722 if (sf.getTopFrame() instanceof AlignFrame)
2724 avp.add((AlignFrame) sf.getTopFrame());
2726 if (sf.getBottomFrame() instanceof AlignFrame)
2728 avp.add((AlignFrame) sf.getBottomFrame());
2732 if (avp.size() == 0)
2736 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2741 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2745 public GStructureViewer[] getJmols()
2747 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2753 List<GStructureViewer> avp = new ArrayList<>();
2755 for (int i = frames.length - 1; i > -1; i--)
2757 if (frames[i] instanceof AppJmol)
2759 GStructureViewer af = (GStructureViewer) frames[i];
2763 if (avp.size() == 0)
2767 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2772 * Add Groovy Support to Jalview
2775 public void groovyShell_actionPerformed()
2779 openGroovyConsole();
2780 } catch (Exception ex)
2782 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2783 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2785 MessageManager.getString("label.couldnt_create_groovy_shell"),
2786 MessageManager.getString("label.groovy_support_failed"),
2787 JvOptionPane.ERROR_MESSAGE);
2792 * Open the Groovy console
2794 void openGroovyConsole()
2796 if (groovyConsole == null)
2798 groovyConsole = new groovy.ui.Console();
2799 groovyConsole.setVariable("Jalview", this);
2800 groovyConsole.run();
2803 * We allow only one console at a time, so that AlignFrame menu option
2804 * 'Calculate | Run Groovy script' is unambiguous.
2805 * Disable 'Groovy Console', and enable 'Run script', when the console is
2806 * opened, and the reverse when it is closed
2808 Window window = (Window) groovyConsole.getFrame();
2809 window.addWindowListener(new WindowAdapter()
2812 public void windowClosed(WindowEvent e)
2815 * rebind CMD-Q from Groovy Console to Jalview Quit
2818 enableExecuteGroovy(false);
2824 * show Groovy console window (after close and reopen)
2826 ((Window) groovyConsole.getFrame()).setVisible(true);
2829 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2830 * and disable opening a second console
2832 enableExecuteGroovy(true);
2836 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2839 protected void addQuitHandler()
2841 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2842 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2843 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2845 getRootPane().getActionMap().put("Quit", new AbstractAction()
2848 public void actionPerformed(ActionEvent e)
2856 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2859 * true if Groovy console is open
2861 public void enableExecuteGroovy(boolean enabled)
2864 * disable opening a second Groovy console
2865 * (or re-enable when the console is closed)
2867 groovyShell.setEnabled(!enabled);
2869 AlignFrame[] alignFrames = getAlignFrames();
2870 if (alignFrames != null)
2872 for (AlignFrame af : alignFrames)
2874 af.setGroovyEnabled(enabled);
2880 * Progress bars managed by the IProgressIndicator method.
2882 private Hashtable<Long, JPanel> progressBars;
2884 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2889 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2892 public void setProgressBar(String message, long id)
2894 if (progressBars == null)
2896 progressBars = new Hashtable<>();
2897 progressBarHandlers = new Hashtable<>();
2900 if (progressBars.get(new Long(id)) != null)
2902 JPanel panel = progressBars.remove(new Long(id));
2903 if (progressBarHandlers.contains(new Long(id)))
2905 progressBarHandlers.remove(new Long(id));
2907 removeProgressPanel(panel);
2911 progressBars.put(new Long(id), addProgressPanel(message));
2918 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2919 * jalview.gui.IProgressIndicatorHandler)
2922 public void registerHandler(final long id,
2923 final IProgressIndicatorHandler handler)
2925 if (progressBarHandlers == null
2926 || !progressBars.containsKey(new Long(id)))
2928 throw new Error(MessageManager.getString(
2929 "error.call_setprogressbar_before_registering_handler"));
2931 progressBarHandlers.put(new Long(id), handler);
2932 final JPanel progressPanel = progressBars.get(new Long(id));
2933 if (handler.canCancel())
2935 JButton cancel = new JButton(
2936 MessageManager.getString("action.cancel"));
2937 final IProgressIndicator us = this;
2938 cancel.addActionListener(new ActionListener()
2942 public void actionPerformed(ActionEvent e)
2944 handler.cancelActivity(id);
2945 us.setProgressBar(MessageManager
2946 .formatMessage("label.cancelled_params", new Object[]
2947 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2951 progressPanel.add(cancel, BorderLayout.EAST);
2957 * @return true if any progress bars are still active
2960 public boolean operationInProgress()
2962 if (progressBars != null && progressBars.size() > 0)
2970 * This will return the first AlignFrame holding the given viewport instance. It
2971 * will break if there are more than one AlignFrames viewing a particular av.
2974 * @return alignFrame for viewport
2976 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2978 if (desktop != null)
2980 AlignmentPanel[] aps = getAlignmentPanels(
2981 viewport.getSequenceSetId());
2982 for (int panel = 0; aps != null && panel < aps.length; panel++)
2984 if (aps[panel] != null && aps[panel].av == viewport)
2986 return aps[panel].alignFrame;
2993 public VamsasApplication getVamsasApplication()
3000 * flag set if jalview GUI is being operated programmatically
3002 private boolean inBatchMode = false;
3005 * check if jalview GUI is being operated programmatically
3007 * @return inBatchMode
3009 public boolean isInBatchMode()
3015 * set flag if jalview GUI is being operated programmatically
3017 * @param inBatchMode
3019 public void setInBatchMode(boolean inBatchMode)
3021 this.inBatchMode = inBatchMode;
3024 public void startServiceDiscovery()
3026 startServiceDiscovery(false);
3029 public void startServiceDiscovery(boolean blocking)
3031 boolean alive = true;
3032 Thread t0 = null, t1 = null, t2 = null;
3033 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3036 // todo: changesupport handlers need to be transferred
3037 if (discoverer == null)
3039 discoverer = new jalview.ws.jws1.Discoverer();
3040 // register PCS handler for desktop.
3041 discoverer.addPropertyChangeListener(changeSupport);
3043 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3044 // until we phase out completely
3045 (t0 = new Thread(discoverer)).start();
3048 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3050 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3051 .startDiscoverer(changeSupport);
3055 // TODO: do rest service discovery
3064 } catch (Exception e)
3067 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3068 || (t3 != null && t3.isAlive())
3069 || (t0 != null && t0.isAlive());
3075 * called to check if the service discovery process completed successfully.
3079 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3081 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3083 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3084 .getErrorMessages();
3087 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3089 if (serviceChangedDialog == null)
3091 // only run if we aren't already displaying one of these.
3092 addDialogThread(serviceChangedDialog = new Runnable()
3099 * JalviewDialog jd =new JalviewDialog() {
3101 * @Override protected void cancelPressed() { // TODO
3102 * Auto-generated method stub
3104 * }@Override protected void okPressed() { // TODO
3105 * Auto-generated method stub
3107 * }@Override protected void raiseClosed() { // TODO
3108 * Auto-generated method stub
3110 * } }; jd.initDialogFrame(new
3111 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3112 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3113 * + " or mis-configured HTTP proxy settings.<br/>" +
3114 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3116 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3117 * ), true, true, "Web Service Configuration Problem", 450,
3120 * jd.waitForInput();
3122 JvOptionPane.showConfirmDialog(Desktop.desktop,
3123 new JLabel("<html><table width=\"450\"><tr><td>"
3124 + ermsg + "</td></tr></table>"
3125 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3126 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3127 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3128 + " Tools->Preferences dialog box to change them.</p></html>"),
3129 "Web Service Configuration Problem",
3130 JvOptionPane.DEFAULT_OPTION,
3131 JvOptionPane.ERROR_MESSAGE);
3132 serviceChangedDialog = null;
3141 "Errors reported by JABA discovery service. Check web services preferences.\n"
3148 private Runnable serviceChangedDialog = null;
3151 * start a thread to open a URL in the configured browser. Pops up a warning
3152 * dialog to the user if there is an exception when calling out to the browser
3157 public static void showUrl(final String url)
3159 showUrl(url, Desktop.instance);
3163 * Like showUrl but allows progress handler to be specified
3167 * (null) or object implementing IProgressIndicator
3169 public static void showUrl(final String url,
3170 final IProgressIndicator progress)
3172 new Thread(new Runnable()
3179 if (progress != null)
3181 progress.setProgressBar(MessageManager
3182 .formatMessage("status.opening_params", new Object[]
3183 { url }), this.hashCode());
3185 jalview.util.BrowserLauncher.openURL(url);
3186 } catch (Exception ex)
3188 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3190 .getString("label.web_browser_not_found_unix"),
3191 MessageManager.getString("label.web_browser_not_found"),
3192 JvOptionPane.WARNING_MESSAGE);
3194 ex.printStackTrace();
3196 if (progress != null)
3198 progress.setProgressBar(null, this.hashCode());
3204 public static WsParamSetManager wsparamManager = null;
3206 public static ParamManager getUserParameterStore()
3208 if (wsparamManager == null)
3210 wsparamManager = new WsParamSetManager();
3212 return wsparamManager;
3216 * static hyperlink handler proxy method for use by Jalview's internal windows
3220 public static void hyperlinkUpdate(HyperlinkEvent e)
3222 if (e.getEventType() == EventType.ACTIVATED)
3227 url = e.getURL().toString();
3228 Desktop.showUrl(url);
3229 } catch (Exception x)
3233 if (Cache.log != null)
3235 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3240 "Couldn't handle string " + url + " as a URL.");
3243 // ignore any exceptions due to dud links.
3250 * single thread that handles display of dialogs to user.
3252 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3255 * flag indicating if dialogExecutor should try to acquire a permit
3257 private volatile boolean dialogPause = true;
3262 private java.util.concurrent.Semaphore block = new Semaphore(0);
3264 private static groovy.ui.Console groovyConsole;
3267 * add another dialog thread to the queue
3271 public void addDialogThread(final Runnable prompter)
3273 dialogExecutor.submit(new Runnable()
3283 } catch (InterruptedException x)
3288 if (instance == null)
3294 SwingUtilities.invokeAndWait(prompter);
3295 } catch (Exception q)
3297 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3303 public void startDialogQueue()
3305 // set the flag so we don't pause waiting for another permit and semaphore
3306 // the current task to begin
3307 dialogPause = false;
3312 protected void snapShotWindow_actionPerformed(ActionEvent e)
3316 ImageMaker im = new jalview.util.ImageMaker(
3317 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3318 getHeight(), of = new File("Jalview_snapshot"
3319 + System.currentTimeMillis() + ".eps"),
3320 "View of desktop", null, 0, false);
3323 paintAll(im.getGraphics());
3325 } catch (Exception q)
3327 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3331 Cache.log.info("Successfully written snapshot to file "
3332 + of.getAbsolutePath());
3336 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3337 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3338 * location last time the view was expanded (if any). However it does not
3339 * remember the split pane divider location - this is set to match the
3340 * 'exploding' frame.
3344 public void explodeViews(SplitFrame sf)
3346 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3347 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3348 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3350 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3352 int viewCount = topPanels.size();
3359 * Processing in reverse order works, forwards order leaves the first panels
3360 * not visible. I don't know why!
3362 for (int i = viewCount - 1; i >= 0; i--)
3365 * Make new top and bottom frames. These take over the respective
3366 * AlignmentPanel objects, including their AlignmentViewports, so the
3367 * cdna/protein relationships between the viewports is carried over to the
3370 * explodedGeometry holds the (x, y) position of the previously exploded
3371 * SplitFrame, and the (width, height) of the AlignFrame component
3373 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3374 AlignFrame newTopFrame = new AlignFrame(topPanel);
3375 newTopFrame.setSize(oldTopFrame.getSize());
3376 newTopFrame.setVisible(true);
3377 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3378 .getExplodedGeometry();
3379 if (geometry != null)
3381 newTopFrame.setSize(geometry.getSize());
3384 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3385 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3386 newBottomFrame.setSize(oldBottomFrame.getSize());
3387 newBottomFrame.setVisible(true);
3388 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3389 .getExplodedGeometry();
3390 if (geometry != null)
3392 newBottomFrame.setSize(geometry.getSize());
3395 topPanel.av.setGatherViewsHere(false);
3396 bottomPanel.av.setGatherViewsHere(false);
3397 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3399 if (geometry != null)
3401 splitFrame.setLocation(geometry.getLocation());
3403 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3407 * Clear references to the panels (now relocated in the new SplitFrames)
3408 * before closing the old SplitFrame.
3411 bottomPanels.clear();
3416 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3417 * back into the given SplitFrame as additional views. Note that the gathered
3418 * frames may themselves have multiple views.
3422 public void gatherViews(GSplitFrame source)
3425 * special handling of explodedGeometry for a view within a SplitFrame: - it
3426 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3427 * height) of the AlignFrame component
3429 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3430 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3431 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3432 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3433 myBottomFrame.viewport
3434 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3435 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3436 myTopFrame.viewport.setGatherViewsHere(true);
3437 myBottomFrame.viewport.setGatherViewsHere(true);
3438 String topViewId = myTopFrame.viewport.getSequenceSetId();
3439 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3441 JInternalFrame[] frames = desktop.getAllFrames();
3442 for (JInternalFrame frame : frames)
3444 if (frame instanceof SplitFrame && frame != source)
3446 SplitFrame sf = (SplitFrame) frame;
3447 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3448 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3449 boolean gatherThis = false;
3450 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3452 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3453 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3454 if (topViewId.equals(topPanel.av.getSequenceSetId())
3455 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3458 topPanel.av.setGatherViewsHere(false);
3459 bottomPanel.av.setGatherViewsHere(false);
3460 topPanel.av.setExplodedGeometry(
3461 new Rectangle(sf.getLocation(), topFrame.getSize()));
3462 bottomPanel.av.setExplodedGeometry(
3463 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3464 myTopFrame.addAlignmentPanel(topPanel, false);
3465 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3471 topFrame.getAlignPanels().clear();
3472 bottomFrame.getAlignPanels().clear();
3479 * The dust settles...give focus to the tab we did this from.
3481 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3484 public static groovy.ui.Console getGroovyConsole()
3486 return groovyConsole;
3490 * handles the payload of a drag and drop event.
3492 * TODO refactor to desktop utilities class
3495 * - Data source strings extracted from the drop event
3497 * - protocol for each data source extracted from the drop event
3501 * - the payload from the drop event
3504 public static void transferFromDropTarget(List<Object> files,
3505 List<DataSourceType> protocols, DropTargetDropEvent evt,
3506 Transferable t) throws Exception
3509 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3511 // DataFlavor[] flavors = t.getTransferDataFlavors();
3512 // for (int i = 0; i < flavors.length; i++) {
3513 // if (flavors[i].isFlavorJavaFileListType()) {
3514 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3515 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3516 // for (int j = 0; j < list.size(); j++) {
3517 // File file = (File) list.get(j);
3518 // byte[] data = getDroppedFileBytes(file);
3519 // fileName.setText(file.getName() + " - " + data.length + " " +
3520 // evt.getLocation());
3521 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3522 // target.setText(new String(data));
3524 // dtde.dropComplete(true);
3529 DataFlavor uriListFlavor = new DataFlavor(
3530 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3533 urlFlavour = new DataFlavor(
3534 "application/x-java-url; class=java.net.URL");
3535 } catch (ClassNotFoundException cfe)
3537 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3540 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3545 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3546 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3547 // means url may be null.
3550 protocols.add(DataSourceType.URL);
3551 files.add(url.toString());
3552 Cache.log.debug("Drop handled as URL dataflavor "
3553 + files.get(files.size() - 1));
3558 if (Platform.isAMac())
3561 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3565 } catch (Throwable ex)
3567 Cache.log.debug("URL drop handler failed.", ex);
3570 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3572 // Works on Windows and MacOSX
3573 Cache.log.debug("Drop handled as javaFileListFlavor");
3574 for (Object file : (List) t
3575 .getTransferData(DataFlavor.javaFileListFlavor))
3578 protocols.add(DataSourceType.FILE);
3583 // Unix like behaviour
3584 boolean added = false;
3586 if (t.isDataFlavorSupported(uriListFlavor))
3588 Cache.log.debug("Drop handled as uriListFlavor");
3589 // This is used by Unix drag system
3590 data = (String) t.getTransferData(uriListFlavor);
3594 // fallback to text: workaround - on OSX where there's a JVM bug
3595 Cache.log.debug("standard URIListFlavor failed. Trying text");
3596 // try text fallback
3597 DataFlavor textDf = new DataFlavor(
3598 "text/plain;class=java.lang.String");
3599 if (t.isDataFlavorSupported(textDf))
3601 data = (String) t.getTransferData(textDf);
3604 Cache.log.debug("Plain text drop content returned "
3605 + (data == null ? "Null - failed" : data));
3610 while (protocols.size() < files.size())
3612 Cache.log.debug("Adding missing FILE protocol for "
3613 + files.get(protocols.size()));
3614 protocols.add(DataSourceType.FILE);
3616 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3617 data, "\r\n"); st.hasMoreTokens();)
3620 String s = st.nextToken();
3621 if (s.startsWith("#"))
3623 // the line is a comment (as per the RFC 2483)
3626 java.net.URI uri = new java.net.URI(s);
3627 if (uri.getScheme().toLowerCase().startsWith("http"))
3629 protocols.add(DataSourceType.URL);
3630 files.add(uri.toString());
3634 // otherwise preserve old behaviour: catch all for file objects
3635 java.io.File file = new java.io.File(uri);
3636 protocols.add(DataSourceType.FILE);
3637 files.add(file.toString());
3642 if (Cache.log.isDebugEnabled())
3644 if (data == null || !added)
3647 if (t.getTransferDataFlavors() != null
3648 && t.getTransferDataFlavors().length > 0)
3651 "Couldn't resolve drop data. Here are the supported flavors:");
3652 for (DataFlavor fl : t.getTransferDataFlavors())
3655 "Supported transfer dataflavor: " + fl.toString());
3656 Object df = t.getTransferData(fl);
3659 Cache.log.debug("Retrieves: " + df);
3663 Cache.log.debug("Retrieved nothing");
3669 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3675 if (Platform.isWindows())
3678 Cache.log.debug("Scanning dropped content for Windows Link Files");
3680 // resolve any .lnk files in the file drop
3681 for (int f = 0; f < files.size(); f++)
3683 String source = files.get(f).toString().toLowerCase();
3684 if (protocols.get(f).equals(DataSourceType.FILE)
3685 && (source.endsWith(".lnk") || source.endsWith(".url")
3686 || source.endsWith(".site")))
3690 Object obj = files.get(f);
3691 File lf = (obj instanceof File ? (File) obj
3692 : new File((String) obj));
3693 // process link file to get a URL
3694 Cache.log.debug("Found potential link file: " + lf);
3695 WindowsShortcut wscfile = new WindowsShortcut(lf);
3696 String fullname = wscfile.getRealFilename();
3697 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3698 files.set(f, fullname);
3699 Cache.log.debug("Parsed real filename " + fullname
3700 + " to extract protocol: " + protocols.get(f));
3701 } catch (Exception ex)
3704 "Couldn't parse " + files.get(f) + " as a link file.",
3713 * Sets the Preferences property for experimental features to True or False
3714 * depending on the state of the controlling menu item
3717 protected void showExperimental_actionPerformed(boolean selected)
3719 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3723 * Answers a (possibly empty) list of any structure viewer frames (currently for
3724 * either Jmol or Chimera) which are currently open. This may optionally be
3725 * restricted to viewers of a specified class, or viewers linked to a specified
3729 * if not null, only return viewers linked to this panel
3730 * @param structureViewerClass
3731 * if not null, only return viewers of this class
3734 public List<StructureViewerBase> getStructureViewers(
3735 AlignmentPanel apanel,
3736 Class<? extends StructureViewerBase> structureViewerClass)
3738 List<StructureViewerBase> result = new ArrayList<>();
3739 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3741 for (JInternalFrame frame : frames)
3743 if (frame instanceof StructureViewerBase)
3745 if (structureViewerClass == null
3746 || structureViewerClass.isInstance(frame))
3749 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3751 result.add((StructureViewerBase) frame);