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 // TODO: JAL-3048 not needed for Jalview-JS
1618 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1621 chooser.setFileView(new JalviewFileView());
1622 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1624 int value = chooser.showSaveDialog(this);
1626 if (value == JalviewFileChooser.APPROVE_OPTION)
1628 final Desktop me = this;
1629 final java.io.File choice = chooser.getSelectedFile();
1630 setProjectFile(choice);
1632 new Thread(new Runnable()
1637 // TODO: refactor to Jalview desktop session controller action.
1638 setProgressBar(MessageManager.formatMessage(
1639 "label.saving_jalview_project", new Object[]
1640 { choice.getName() }), choice.hashCode());
1641 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1642 choice.getParent());
1643 // TODO catch and handle errors for savestate
1644 // TODO prevent user from messing with the Desktop whilst we're saving
1647 new Jalview2XML().saveState(choice);
1648 } catch (OutOfMemoryError oom)
1651 "Whilst saving current state to " + choice.getName(),
1653 } catch (Exception ex)
1656 "Problems whilst trying to save to " + choice.getName(),
1658 JvOptionPane.showMessageDialog(me,
1659 MessageManager.formatMessage(
1660 "label.error_whilst_saving_current_state_to",
1662 { choice.getName() }),
1663 MessageManager.getString("label.couldnt_save_project"),
1664 JvOptionPane.WARNING_MESSAGE);
1666 setProgressBar(null, choice.hashCode());
1672 private void setProjectFile(File choice)
1674 this.projectFile = choice;
1677 public File getProjectFile()
1679 return this.projectFile;
1689 public void loadState_actionPerformed(ActionEvent e)
1691 // TODO: JAL-3048 not needed for Jalview-JS
1693 JalviewFileChooser chooser = new JalviewFileChooser(
1694 Cache.getProperty("LAST_DIRECTORY"), new String[]
1697 { "Jalview Project", "Jalview Project (old)" },
1699 chooser.setFileView(new JalviewFileView());
1700 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1702 int value = chooser.showOpenDialog(this);
1704 if (value == JalviewFileChooser.APPROVE_OPTION)
1706 final File selectedFile = chooser.getSelectedFile();
1707 setProjectFile(selectedFile);
1708 final String choice = selectedFile.getAbsolutePath();
1709 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1710 new Thread(new Runnable()
1715 setProgressBar(MessageManager.formatMessage(
1716 "label.loading_jalview_project", new Object[]
1717 { choice }), choice.hashCode());
1720 new Jalview2XML().loadJalviewAlign(choice);
1721 } catch (OutOfMemoryError oom)
1723 new OOMWarning("Whilst loading project from " + choice, oom);
1724 } catch (Exception ex)
1727 "Problems whilst loading project from " + choice, ex);
1728 JvOptionPane.showMessageDialog(Desktop.desktop,
1729 MessageManager.formatMessage(
1730 "label.error_whilst_loading_project_from",
1733 MessageManager.getString("label.couldnt_load_project"),
1734 JvOptionPane.WARNING_MESSAGE);
1736 setProgressBar(null, choice.hashCode());
1743 public void inputSequence_actionPerformed(ActionEvent e)
1745 new SequenceFetcher(this);
1748 JPanel progressPanel;
1750 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1752 public void startLoading(final Object fileName)
1754 if (fileLoadingCount == 0)
1756 fileLoadingPanels.add(addProgressPanel(MessageManager
1757 .formatMessage("label.loading_file", new Object[]
1763 private JPanel addProgressPanel(String string)
1765 if (progressPanel == null)
1767 progressPanel = new JPanel(new GridLayout(1, 1));
1768 totalProgressCount = 0;
1769 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1771 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1772 JProgressBar progressBar = new JProgressBar();
1773 progressBar.setIndeterminate(true);
1775 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1777 thisprogress.add(progressBar, BorderLayout.CENTER);
1778 progressPanel.add(thisprogress);
1779 ((GridLayout) progressPanel.getLayout()).setRows(
1780 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1781 ++totalProgressCount;
1782 instance.validate();
1783 return thisprogress;
1786 int totalProgressCount = 0;
1788 private void removeProgressPanel(JPanel progbar)
1790 if (progressPanel != null)
1792 synchronized (progressPanel)
1794 progressPanel.remove(progbar);
1795 GridLayout gl = (GridLayout) progressPanel.getLayout();
1796 gl.setRows(gl.getRows() - 1);
1797 if (--totalProgressCount < 1)
1799 this.getContentPane().remove(progressPanel);
1800 progressPanel = null;
1807 public void stopLoading()
1810 if (fileLoadingCount < 1)
1812 while (fileLoadingPanels.size() > 0)
1814 removeProgressPanel(fileLoadingPanels.remove(0));
1816 fileLoadingPanels.clear();
1817 fileLoadingCount = 0;
1822 public static int getViewCount(String alignmentId)
1824 AlignmentViewport[] aps = getViewports(alignmentId);
1825 return (aps == null) ? 0 : aps.length;
1830 * @param alignmentId
1831 * - if null, all sets are returned
1832 * @return all AlignmentPanels concerning the alignmentId sequence set
1834 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1836 if (Desktop.desktop == null)
1838 // no frames created and in headless mode
1839 // TODO: verify that frames are recoverable when in headless mode
1842 List<AlignmentPanel> aps = new ArrayList<>();
1843 AlignFrame[] frames = getAlignFrames();
1848 for (AlignFrame af : frames)
1850 for (AlignmentPanel ap : af.alignPanels)
1852 if (alignmentId == null
1853 || alignmentId.equals(ap.av.getSequenceSetId()))
1859 if (aps.size() == 0)
1863 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1868 * get all the viewports on an alignment.
1870 * @param sequenceSetId
1871 * unique alignment id (may be null - all viewports returned in that
1873 * @return all viewports on the alignment bound to sequenceSetId
1875 public static AlignmentViewport[] getViewports(String sequenceSetId)
1877 List<AlignmentViewport> viewp = new ArrayList<>();
1878 if (desktop != null)
1880 AlignFrame[] frames = Desktop.getAlignFrames();
1882 for (AlignFrame afr : frames)
1884 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1885 .equals(sequenceSetId))
1887 if (afr.alignPanels != null)
1889 for (AlignmentPanel ap : afr.alignPanels)
1891 if (sequenceSetId == null
1892 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1900 viewp.add(afr.getViewport());
1904 if (viewp.size() > 0)
1906 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1913 * Explode the views in the given frame into separate AlignFrame
1917 public static void explodeViews(AlignFrame af)
1919 int size = af.alignPanels.size();
1925 for (int i = 0; i < size; i++)
1927 AlignmentPanel ap = af.alignPanels.get(i);
1928 AlignFrame newaf = new AlignFrame(ap);
1931 * Restore the view's last exploded frame geometry if known. Multiple
1932 * views from one exploded frame share and restore the same (frame)
1933 * position and size.
1935 Rectangle geometry = ap.av.getExplodedGeometry();
1936 if (geometry != null)
1938 newaf.setBounds(geometry);
1941 ap.av.setGatherViewsHere(false);
1943 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1944 AlignFrame.DEFAULT_HEIGHT);
1947 af.alignPanels.clear();
1948 af.closeMenuItem_actionPerformed(true);
1953 * Gather expanded views (separate AlignFrame's) with the same sequence set
1954 * identifier back in to this frame as additional views, and close the
1955 * expanded views. Note the expanded frames may themselves have multiple
1956 * views. We take the lot.
1960 public void gatherViews(AlignFrame source)
1962 source.viewport.setGatherViewsHere(true);
1963 source.viewport.setExplodedGeometry(source.getBounds());
1964 JInternalFrame[] frames = desktop.getAllFrames();
1965 String viewId = source.viewport.getSequenceSetId();
1967 for (int t = 0; t < frames.length; t++)
1969 if (frames[t] instanceof AlignFrame && frames[t] != source)
1971 AlignFrame af = (AlignFrame) frames[t];
1972 boolean gatherThis = false;
1973 for (int a = 0; a < af.alignPanels.size(); a++)
1975 AlignmentPanel ap = af.alignPanels.get(a);
1976 if (viewId.equals(ap.av.getSequenceSetId()))
1979 ap.av.setGatherViewsHere(false);
1980 ap.av.setExplodedGeometry(af.getBounds());
1981 source.addAlignmentPanel(ap, false);
1987 af.alignPanels.clear();
1988 af.closeMenuItem_actionPerformed(true);
1995 jalview.gui.VamsasApplication v_client = null;
1998 public void vamsasImport_actionPerformed(ActionEvent e)
2000 // TODO: JAL-3048 not needed for Jalview-JS
2002 if (v_client == null)
2004 // Load and try to start a session.
2005 JalviewFileChooser chooser = new JalviewFileChooser(
2006 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2008 chooser.setFileView(new JalviewFileView());
2009 chooser.setDialogTitle(
2010 MessageManager.getString("label.open_saved_vamsas_session"));
2011 chooser.setToolTipText(MessageManager.getString(
2012 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2014 int value = chooser.showOpenDialog(this);
2016 if (value == JalviewFileChooser.APPROVE_OPTION)
2018 String fle = chooser.getSelectedFile().toString();
2019 if (!vamsasImport(chooser.getSelectedFile()))
2021 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2022 MessageManager.formatMessage(
2023 "label.couldnt_import_as_vamsas_session",
2027 .getString("label.vamsas_document_import_failed"),
2028 JvOptionPane.ERROR_MESSAGE);
2034 jalview.bin.Cache.log.error(
2035 "Implementation error - load session from a running session is not supported.");
2040 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2043 * @return true if import was a success and a session was started.
2045 public boolean vamsasImport(URL url)
2047 // TODO: create progress bar
2048 if (v_client != null)
2051 jalview.bin.Cache.log.error(
2052 "Implementation error - load session from a running session is not supported.");
2058 // copy the URL content to a temporary local file
2059 // TODO: be a bit cleverer here with nio (?!)
2060 File file = File.createTempFile("vdocfromurl", ".vdj");
2061 FileOutputStream fos = new FileOutputStream(file);
2062 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2063 byte[] buffer = new byte[2048];
2065 while ((ln = bis.read(buffer)) > -1)
2067 fos.write(buffer, 0, ln);
2071 v_client = new jalview.gui.VamsasApplication(this, file,
2072 url.toExternalForm());
2073 } catch (Exception ex)
2075 jalview.bin.Cache.log.error(
2076 "Failed to create new vamsas session from contents of URL "
2081 setupVamsasConnectedGui();
2082 v_client.initial_update(); // TODO: thread ?
2083 return v_client.inSession();
2087 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2090 * @return true if import was a success and a session was started.
2092 public boolean vamsasImport(File file)
2094 if (v_client != null)
2097 jalview.bin.Cache.log.error(
2098 "Implementation error - load session from a running session is not supported.");
2102 setProgressBar(MessageManager.formatMessage(
2103 "status.importing_vamsas_session_from", new Object[]
2104 { file.getName() }), file.hashCode());
2107 v_client = new jalview.gui.VamsasApplication(this, file, null);
2108 } catch (Exception ex)
2110 setProgressBar(MessageManager.formatMessage(
2111 "status.importing_vamsas_session_from", new Object[]
2112 { file.getName() }), file.hashCode());
2113 jalview.bin.Cache.log.error(
2114 "New vamsas session from existing session file failed:", ex);
2117 setupVamsasConnectedGui();
2118 v_client.initial_update(); // TODO: thread ?
2119 setProgressBar(MessageManager.formatMessage(
2120 "status.importing_vamsas_session_from", new Object[]
2121 { file.getName() }), file.hashCode());
2122 return v_client.inSession();
2125 public boolean joinVamsasSession(String mysesid)
2127 if (v_client != null)
2129 throw new Error(MessageManager
2130 .getString("error.try_join_vamsas_session_another"));
2132 if (mysesid == null)
2135 MessageManager.getString("error.invalid_vamsas_session_id"));
2137 v_client = new VamsasApplication(this, mysesid);
2138 setupVamsasConnectedGui();
2139 v_client.initial_update();
2140 return (v_client.inSession());
2144 public void vamsasStart_actionPerformed(ActionEvent e)
2146 if (v_client == null)
2149 // we just start a default session for moment.
2151 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2152 * getProperty("LAST_DIRECTORY"));
2154 * chooser.setFileView(new JalviewFileView());
2155 * chooser.setDialogTitle("Load Vamsas file");
2156 * chooser.setToolTipText("Import");
2158 * int value = chooser.showOpenDialog(this);
2160 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2161 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2163 v_client = new VamsasApplication(this);
2164 setupVamsasConnectedGui();
2165 v_client.initial_update(); // TODO: thread ?
2169 // store current data in session.
2170 v_client.push_update(); // TODO: thread
2174 protected void setupVamsasConnectedGui()
2176 vamsasStart.setText(MessageManager.getString("label.session_update"));
2177 vamsasSave.setVisible(true);
2178 vamsasStop.setVisible(true);
2179 vamsasImport.setVisible(false); // Document import to existing session is
2180 // not possible for vamsas-client-1.0.
2183 protected void setupVamsasDisconnectedGui()
2185 vamsasSave.setVisible(false);
2186 vamsasStop.setVisible(false);
2187 vamsasImport.setVisible(true);
2189 .setText(MessageManager.getString("label.new_vamsas_session"));
2193 public void vamsasStop_actionPerformed(ActionEvent e)
2195 if (v_client != null)
2197 v_client.end_session();
2199 setupVamsasDisconnectedGui();
2203 protected void buildVamsasStMenu()
2205 if (v_client == null)
2207 String[] sess = null;
2210 sess = VamsasApplication.getSessionList();
2211 } catch (Exception e)
2213 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2219 jalview.bin.Cache.log.debug(
2220 "Got current sessions list: " + sess.length + " entries.");
2221 VamsasStMenu.removeAll();
2222 for (int i = 0; i < sess.length; i++)
2224 JMenuItem sessit = new JMenuItem();
2225 sessit.setText(sess[i]);
2226 sessit.setToolTipText(MessageManager
2227 .formatMessage("label.connect_to_session", new Object[]
2229 final Desktop dsktp = this;
2230 final String mysesid = sess[i];
2231 sessit.addActionListener(new ActionListener()
2235 public void actionPerformed(ActionEvent e)
2237 if (dsktp.v_client == null)
2239 Thread rthr = new Thread(new Runnable()
2245 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2246 dsktp.setupVamsasConnectedGui();
2247 dsktp.v_client.initial_update();
2255 VamsasStMenu.add(sessit);
2257 // don't show an empty menu.
2258 VamsasStMenu.setVisible(sess.length > 0);
2263 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2264 VamsasStMenu.removeAll();
2265 VamsasStMenu.setVisible(false);
2270 // Not interested in the content. Just hide ourselves.
2271 VamsasStMenu.setVisible(false);
2276 public void vamsasSave_actionPerformed(ActionEvent e)
2278 // TODO: JAL-3048 not needed for Jalview-JS
2280 if (v_client != null)
2282 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2283 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2286 chooser.setFileView(new JalviewFileView());
2287 chooser.setDialogTitle(MessageManager
2288 .getString("label.save_vamsas_document_archive"));
2290 int value = chooser.showSaveDialog(this);
2292 if (value == JalviewFileChooser.APPROVE_OPTION)
2294 java.io.File choice = chooser.getSelectedFile();
2295 JPanel progpanel = addProgressPanel(MessageManager
2296 .formatMessage("label.saving_vamsas_doc", new Object[]
2297 { choice.getName() }));
2298 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2299 String warnmsg = null;
2300 String warnttl = null;
2303 v_client.vclient.storeDocument(choice);
2306 warnttl = "Serious Problem saving Vamsas Document";
2307 warnmsg = ex.toString();
2308 jalview.bin.Cache.log
2309 .error("Error Whilst saving document to " + choice, ex);
2311 } catch (Exception ex)
2313 warnttl = "Problem saving Vamsas Document.";
2314 warnmsg = ex.toString();
2315 jalview.bin.Cache.log.warn(
2316 "Exception Whilst saving document to " + choice, ex);
2319 removeProgressPanel(progpanel);
2320 if (warnmsg != null)
2322 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2324 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2330 JPanel vamUpdate = null;
2333 * hide vamsas user gui bits when a vamsas document event is being handled.
2336 * true to hide gui, false to reveal gui
2338 public void setVamsasUpdate(boolean b)
2340 Cache.log.debug("Setting gui for Vamsas update "
2341 + (b ? "in progress" : "finished"));
2343 if (vamUpdate != null)
2345 this.removeProgressPanel(vamUpdate);
2349 vamUpdate = this.addProgressPanel(
2350 MessageManager.getString("label.updating_vamsas_session"));
2352 vamsasStart.setVisible(!b);
2353 vamsasStop.setVisible(!b);
2354 vamsasSave.setVisible(!b);
2357 public JInternalFrame[] getAllFrames()
2359 return desktop.getAllFrames();
2363 * Checks the given url to see if it gives a response indicating that the user
2364 * should be informed of a new questionnaire.
2368 public void checkForQuestionnaire(String url)
2370 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2371 // javax.swing.SwingUtilities.invokeLater(jvq);
2372 new Thread(jvq).start();
2375 public void checkURLLinks()
2377 // Thread off the URL link checker
2378 addDialogThread(new Runnable()
2383 if (/** @j2sNative false && */ // BH 2018
2384 Cache.getDefault("CHECKURLLINKS", true))
2386 // check what the actual links are - if it's just the default don't
2387 // bother with the warning
2388 List<String> links = Preferences.sequenceUrlLinks
2391 // only need to check links if there is one with a
2392 // SEQUENCE_ID which is not the default EMBL_EBI link
2393 ListIterator<String> li = links.listIterator();
2394 boolean check = false;
2395 List<JLabel> urls = new ArrayList<>();
2396 while (li.hasNext())
2398 String link = li.next();
2399 if (link.contains(SEQUENCE_ID)
2400 && !UrlConstants.isDefaultString(link))
2403 int barPos = link.indexOf("|");
2404 String urlMsg = barPos == -1 ? link
2405 : link.substring(0, barPos) + ": "
2406 + link.substring(barPos + 1);
2407 urls.add(new JLabel(urlMsg));
2415 // ask user to check in case URL links use old style tokens
2416 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2417 JPanel msgPanel = new JPanel();
2418 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2419 msgPanel.add(Box.createVerticalGlue());
2420 JLabel msg = new JLabel(MessageManager
2421 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2422 JLabel msg2 = new JLabel(MessageManager
2423 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2425 for (JLabel url : urls)
2431 final JCheckBox jcb = new JCheckBox(
2432 MessageManager.getString("label.do_not_display_again"));
2433 jcb.addActionListener(new ActionListener()
2436 public void actionPerformed(ActionEvent e)
2438 // update Cache settings for "don't show this again"
2439 boolean showWarningAgain = !jcb.isSelected();
2440 Cache.setProperty("CHECKURLLINKS",
2441 Boolean.valueOf(showWarningAgain).toString());
2446 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2448 .getString("label.SEQUENCE_ID_no_longer_used"),
2449 JvOptionPane.WARNING_MESSAGE);
2456 * Proxy class for JDesktopPane which optionally displays the current memory
2457 * usage and highlights the desktop area with a red bar if free memory runs
2462 public class MyDesktopPane extends JDesktopPane
2463 implements Runnable, PropertyChangeListener
2466 public Object[] dialogData;
2470 public void propertyChange(PropertyChangeEvent event)
2472 Object val = event.getNewValue();
2473 String name = event.getPropertyName();
2474 System.out.println(name);
2475 switch (event.getSource().getClass().getName())
2477 case "javax.swing.JOptionPane":
2481 onDialogReturn(val);
2484 if (val instanceof Integer)
2486 onDialogReturn(((Integer) val).intValue());
2490 onDialogReturn(val);
2495 case "javax.swing.ColorChooserDialog":
2498 case "SelectedColor":
2499 onDialogReturn(val);
2503 case "javax.swing.JFileChooser":
2506 case "SelectedFile":
2507 // in JavaScript, this File object will have a _bytes property,
2508 // because the file data has already been loaded
2509 onDialogReturn(new Object[] { (File) val });
2514 System.out.println(event.getSource().getClass().getName() + " "
2515 + event.getPropertyName() + ": " + event.getNewValue());
2518 // JSCOmponent.DialogCaller interface
2519 void onDialogReturn(Object value)
2521 switch ((String) dialogData[0])
2523 case "SelectedFile":
2525 dialogData[0] = value;
2526 ((Runnable) dialogData[1]).run();
2528 case "label.select_feature_colour":
2529 ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
2534 // JSCOmponent.DialogCaller interface
2535 void onDialogReturn(int value)
2537 if (value != Math.floor(value))
2539 // in JavaScript, this will be NaN, oddly enough
2543 switch ((String) dialogData[0])
2546 dialogData[0] = Integer.valueOf(value);
2547 ((Runnable) dialogData[1]).run();
2549 case "label.input_alignment_from_url":
2550 // reconstruct the parameter data
2552 AlignViewport viewport = (AlignViewport) dialogData[1];
2553 JComboBox history = (JComboBox) dialogData[2];
2554 // the rest of this is unchangaed
2555 if (reply != JvOptionPane.OK_OPTION)
2560 String url = history.getSelectedItem().toString();
2562 if (url.toLowerCase().endsWith(".jar"))
2564 if (viewport != null)
2566 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2567 FileFormat.Jalview);
2571 new FileLoader().LoadFile(url, DataSourceType.URL,
2572 FileFormat.Jalview);
2577 FileFormatI format = null;
2580 format = new IdentifyFile().identify(url, DataSourceType.URL);
2581 } catch (FileFormatException e)
2583 // TODO revise error handling, distinguish between
2584 // URL not found and response not valid
2589 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2590 MessageManager.formatMessage("label.couldnt_locate",
2593 MessageManager.getString("label.url_not_found"),
2594 JvOptionPane.WARNING_MESSAGE);
2599 if (viewport != null)
2601 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2606 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2615 private static final float ONE_MB = 1048576f;
2617 boolean showMemoryUsage = false;
2621 java.text.NumberFormat df;
2623 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2626 public MyDesktopPane(boolean showMemoryUsage)
2628 showMemoryUsage(showMemoryUsage);
2631 public void showMemoryUsage(boolean showMemory)
2633 this.showMemoryUsage = showMemory;
2636 Thread worker = new Thread(this);
2642 public boolean isShowMemoryUsage()
2644 return showMemoryUsage;
2650 df = java.text.NumberFormat.getNumberInstance();
2651 df.setMaximumFractionDigits(2);
2652 runtime = Runtime.getRuntime();
2654 while (showMemoryUsage)
2658 maxMemory = runtime.maxMemory() / ONE_MB;
2659 allocatedMemory = runtime.totalMemory() / ONE_MB;
2660 freeMemory = runtime.freeMemory() / ONE_MB;
2661 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2663 percentUsage = (totalFreeMemory / maxMemory) * 100;
2665 // if (percentUsage < 20)
2667 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2669 // instance.set.setBorder(border1);
2672 // sleep after showing usage
2674 } catch (Exception ex)
2676 ex.printStackTrace();
2682 public void paintComponent(Graphics g)
2684 if (showMemoryUsage && g != null && df != null)
2686 if (percentUsage < 20)
2688 g.setColor(Color.red);
2690 FontMetrics fm = g.getFontMetrics();
2693 g.drawString(MessageManager.formatMessage("label.memory_stats",
2695 { df.format(totalFreeMemory), df.format(maxMemory),
2696 df.format(percentUsage) }),
2697 10, getHeight() - fm.getHeight());
2705 * Accessor method to quickly get all the AlignmentFrames loaded.
2707 * @return an array of AlignFrame, or null if none found
2709 public static AlignFrame[] getAlignFrames()
2711 if (Jalview.isHeadlessMode())
2713 // Desktop.desktop is null in headless mode
2714 return new AlignFrame[] { Jalview.currentAlignFrame };
2717 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2723 List<AlignFrame> avp = new ArrayList<>();
2725 for (int i = frames.length - 1; i > -1; i--)
2727 if (frames[i] instanceof AlignFrame)
2729 avp.add((AlignFrame) frames[i]);
2731 else if (frames[i] instanceof SplitFrame)
2734 * Also check for a split frame containing an AlignFrame
2736 GSplitFrame sf = (GSplitFrame) frames[i];
2737 if (sf.getTopFrame() instanceof AlignFrame)
2739 avp.add((AlignFrame) sf.getTopFrame());
2741 if (sf.getBottomFrame() instanceof AlignFrame)
2743 avp.add((AlignFrame) sf.getBottomFrame());
2747 if (avp.size() == 0)
2751 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2756 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2760 public GStructureViewer[] getJmols()
2762 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2768 List<GStructureViewer> avp = new ArrayList<>();
2770 for (int i = frames.length - 1; i > -1; i--)
2772 if (frames[i] instanceof AppJmol)
2774 GStructureViewer af = (GStructureViewer) frames[i];
2778 if (avp.size() == 0)
2782 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2787 * Add Groovy Support to Jalview
2790 public void groovyShell_actionPerformed()
2794 openGroovyConsole();
2795 } catch (Exception ex)
2797 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2798 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2800 MessageManager.getString("label.couldnt_create_groovy_shell"),
2801 MessageManager.getString("label.groovy_support_failed"),
2802 JvOptionPane.ERROR_MESSAGE);
2807 * Open the Groovy console
2809 void openGroovyConsole()
2811 if (groovyConsole == null)
2813 groovyConsole = new groovy.ui.Console();
2814 groovyConsole.setVariable("Jalview", this);
2815 groovyConsole.run();
2818 * We allow only one console at a time, so that AlignFrame menu option
2819 * 'Calculate | Run Groovy script' is unambiguous.
2820 * Disable 'Groovy Console', and enable 'Run script', when the console is
2821 * opened, and the reverse when it is closed
2823 Window window = (Window) groovyConsole.getFrame();
2824 window.addWindowListener(new WindowAdapter()
2827 public void windowClosed(WindowEvent e)
2830 * rebind CMD-Q from Groovy Console to Jalview Quit
2833 enableExecuteGroovy(false);
2839 * show Groovy console window (after close and reopen)
2841 ((Window) groovyConsole.getFrame()).setVisible(true);
2844 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2845 * and disable opening a second console
2847 enableExecuteGroovy(true);
2851 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2852 * binding when opened
2854 protected void addQuitHandler()
2856 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2857 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2858 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2860 getRootPane().getActionMap().put("Quit", new AbstractAction()
2863 public void actionPerformed(ActionEvent e)
2871 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2874 * true if Groovy console is open
2876 public void enableExecuteGroovy(boolean enabled)
2879 * disable opening a second Groovy console
2880 * (or re-enable when the console is closed)
2882 groovyShell.setEnabled(!enabled);
2884 AlignFrame[] alignFrames = getAlignFrames();
2885 if (alignFrames != null)
2887 for (AlignFrame af : alignFrames)
2889 af.setGroovyEnabled(enabled);
2895 * Progress bars managed by the IProgressIndicator method.
2897 private Hashtable<Long, JPanel> progressBars;
2899 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2904 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2907 public void setProgressBar(String message, long id)
2909 if (progressBars == null)
2911 progressBars = new Hashtable<>();
2912 progressBarHandlers = new Hashtable<>();
2915 if (progressBars.get(new Long(id)) != null)
2917 JPanel panel = progressBars.remove(new Long(id));
2918 if (progressBarHandlers.contains(new Long(id)))
2920 progressBarHandlers.remove(new Long(id));
2922 removeProgressPanel(panel);
2926 progressBars.put(new Long(id), addProgressPanel(message));
2933 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2934 * jalview.gui.IProgressIndicatorHandler)
2937 public void registerHandler(final long id,
2938 final IProgressIndicatorHandler handler)
2940 if (progressBarHandlers == null
2941 || !progressBars.containsKey(new Long(id)))
2943 throw new Error(MessageManager.getString(
2944 "error.call_setprogressbar_before_registering_handler"));
2946 progressBarHandlers.put(new Long(id), handler);
2947 final JPanel progressPanel = progressBars.get(new Long(id));
2948 if (handler.canCancel())
2950 JButton cancel = new JButton(
2951 MessageManager.getString("action.cancel"));
2952 final IProgressIndicator us = this;
2953 cancel.addActionListener(new ActionListener()
2957 public void actionPerformed(ActionEvent e)
2959 handler.cancelActivity(id);
2960 us.setProgressBar(MessageManager
2961 .formatMessage("label.cancelled_params", new Object[]
2962 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2966 progressPanel.add(cancel, BorderLayout.EAST);
2972 * @return true if any progress bars are still active
2975 public boolean operationInProgress()
2977 if (progressBars != null && progressBars.size() > 0)
2985 * This will return the first AlignFrame holding the given viewport instance.
2986 * It will break if there are more than one AlignFrames viewing a particular
2990 * @return alignFrame for viewport
2992 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2994 if (desktop != null)
2996 AlignmentPanel[] aps = getAlignmentPanels(
2997 viewport.getSequenceSetId());
2998 for (int panel = 0; aps != null && panel < aps.length; panel++)
3000 if (aps[panel] != null && aps[panel].av == viewport)
3002 return aps[panel].alignFrame;
3009 public VamsasApplication getVamsasApplication()
3016 * flag set if jalview GUI is being operated programmatically
3018 private boolean inBatchMode = false;
3021 * check if jalview GUI is being operated programmatically
3023 * @return inBatchMode
3025 public boolean isInBatchMode()
3031 * set flag if jalview GUI is being operated programmatically
3033 * @param inBatchMode
3035 public void setInBatchMode(boolean inBatchMode)
3037 this.inBatchMode = inBatchMode;
3040 public void startServiceDiscovery()
3042 startServiceDiscovery(false);
3045 public void startServiceDiscovery(boolean blocking)
3047 boolean alive = true;
3048 Thread t0 = null, t1 = null, t2 = null;
3049 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3052 // todo: changesupport handlers need to be transferred
3053 if (discoverer == null)
3055 discoverer = new jalview.ws.jws1.Discoverer();
3056 // register PCS handler for desktop.
3057 discoverer.addPropertyChangeListener(changeSupport);
3059 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3060 // until we phase out completely
3061 (t0 = new Thread(discoverer)).start();
3064 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3066 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3067 .startDiscoverer(changeSupport);
3071 // TODO: do rest service discovery
3080 } catch (Exception e)
3083 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3084 || (t3 != null && t3.isAlive())
3085 || (t0 != null && t0.isAlive());
3091 * called to check if the service discovery process completed successfully.
3095 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3097 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3099 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3100 .getErrorMessages();
3103 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3105 if (serviceChangedDialog == null)
3107 // only run if we aren't already displaying one of these.
3108 addDialogThread(serviceChangedDialog = new Runnable()
3115 * JalviewDialog jd =new JalviewDialog() {
3117 * @Override protected void cancelPressed() { // TODO
3118 * Auto-generated method stub
3120 * }@Override protected void okPressed() { // TODO
3121 * Auto-generated method stub
3123 * }@Override protected void raiseClosed() { // TODO
3124 * Auto-generated method stub
3126 * } }; jd.initDialogFrame(new
3127 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3128 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3129 * + " or mis-configured HTTP proxy settings.<br/>" +
3130 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3132 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3133 * ), true, true, "Web Service Configuration Problem", 450,
3136 * jd.waitForInput();
3138 JvOptionPane.showConfirmDialog(Desktop.desktop,
3139 new JLabel("<html><table width=\"450\"><tr><td>"
3140 + ermsg + "</td></tr></table>"
3141 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3142 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3143 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3144 + " Tools->Preferences dialog box to change them.</p></html>"),
3145 "Web Service Configuration Problem",
3146 JvOptionPane.DEFAULT_OPTION,
3147 JvOptionPane.ERROR_MESSAGE);
3148 serviceChangedDialog = null;
3157 "Errors reported by JABA discovery service. Check web services preferences.\n"
3164 private Runnable serviceChangedDialog = null;
3167 * start a thread to open a URL in the configured browser. Pops up a warning
3168 * dialog to the user if there is an exception when calling out to the browser
3173 public static void showUrl(final String url)
3175 showUrl(url, Desktop.instance);
3179 * Like showUrl but allows progress handler to be specified
3183 * (null) or object implementing IProgressIndicator
3185 public static void showUrl(final String url,
3186 final IProgressIndicator progress)
3188 new Thread(new Runnable()
3195 if (progress != null)
3197 progress.setProgressBar(MessageManager
3198 .formatMessage("status.opening_params", new Object[]
3199 { url }), this.hashCode());
3201 jalview.util.BrowserLauncher.openURL(url);
3202 } catch (Exception ex)
3204 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3206 .getString("label.web_browser_not_found_unix"),
3207 MessageManager.getString("label.web_browser_not_found"),
3208 JvOptionPane.WARNING_MESSAGE);
3210 ex.printStackTrace();
3212 if (progress != null)
3214 progress.setProgressBar(null, this.hashCode());
3220 public static WsParamSetManager wsparamManager = null;
3222 public static ParamManager getUserParameterStore()
3224 if (wsparamManager == null)
3226 wsparamManager = new WsParamSetManager();
3228 return wsparamManager;
3232 * static hyperlink handler proxy method for use by Jalview's internal windows
3236 public static void hyperlinkUpdate(HyperlinkEvent e)
3238 if (e.getEventType() == EventType.ACTIVATED)
3243 url = e.getURL().toString();
3244 Desktop.showUrl(url);
3245 } catch (Exception x)
3249 if (Cache.log != null)
3251 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3256 "Couldn't handle string " + url + " as a URL.");
3259 // ignore any exceptions due to dud links.
3266 * single thread that handles display of dialogs to user.
3268 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3271 * flag indicating if dialogExecutor should try to acquire a permit
3273 private volatile boolean dialogPause = true;
3278 private java.util.concurrent.Semaphore block = new Semaphore(0);
3280 private static groovy.ui.Console groovyConsole;
3283 * add another dialog thread to the queue
3287 public void addDialogThread(final Runnable prompter)
3289 dialogExecutor.submit(new Runnable()
3299 } catch (InterruptedException x)
3304 if (instance == null)
3310 SwingUtilities.invokeAndWait(prompter);
3311 } catch (Exception q)
3313 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3319 public void startDialogQueue()
3321 // set the flag so we don't pause waiting for another permit and semaphore
3322 // the current task to begin
3323 dialogPause = false;
3328 protected void snapShotWindow_actionPerformed(ActionEvent e)
3332 ImageMaker im = new jalview.util.ImageMaker(
3333 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3334 getHeight(), of = new File("Jalview_snapshot"
3335 + System.currentTimeMillis() + ".eps"),
3336 "View of desktop", null, 0, false);
3339 paintAll(im.getGraphics());
3341 } catch (Exception q)
3343 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3347 Cache.log.info("Successfully written snapshot to file "
3348 + of.getAbsolutePath());
3352 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3353 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3354 * and location last time the view was expanded (if any). However it does not
3355 * remember the split pane divider location - this is set to match the
3356 * 'exploding' frame.
3360 public void explodeViews(SplitFrame sf)
3362 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3363 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3364 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3366 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3368 int viewCount = topPanels.size();
3375 * Processing in reverse order works, forwards order leaves the first panels
3376 * not visible. I don't know why!
3378 for (int i = viewCount - 1; i >= 0; i--)
3381 * Make new top and bottom frames. These take over the respective
3382 * AlignmentPanel objects, including their AlignmentViewports, so the
3383 * cdna/protein relationships between the viewports is carried over to the
3386 * explodedGeometry holds the (x, y) position of the previously exploded
3387 * SplitFrame, and the (width, height) of the AlignFrame component
3389 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3390 AlignFrame newTopFrame = new AlignFrame(topPanel);
3391 newTopFrame.setSize(oldTopFrame.getSize());
3392 newTopFrame.setVisible(true);
3393 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3394 .getExplodedGeometry();
3395 if (geometry != null)
3397 newTopFrame.setSize(geometry.getSize());
3400 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3401 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3402 newBottomFrame.setSize(oldBottomFrame.getSize());
3403 newBottomFrame.setVisible(true);
3404 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3405 .getExplodedGeometry();
3406 if (geometry != null)
3408 newBottomFrame.setSize(geometry.getSize());
3411 topPanel.av.setGatherViewsHere(false);
3412 bottomPanel.av.setGatherViewsHere(false);
3413 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3415 if (geometry != null)
3417 splitFrame.setLocation(geometry.getLocation());
3419 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3423 * Clear references to the panels (now relocated in the new SplitFrames)
3424 * before closing the old SplitFrame.
3427 bottomPanels.clear();
3432 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3433 * back into the given SplitFrame as additional views. Note that the gathered
3434 * frames may themselves have multiple views.
3438 public void gatherViews(GSplitFrame source)
3441 * special handling of explodedGeometry for a view within a SplitFrame: - it
3442 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3443 * height) of the AlignFrame component
3445 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3446 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3447 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3448 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3449 myBottomFrame.viewport
3450 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3451 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3452 myTopFrame.viewport.setGatherViewsHere(true);
3453 myBottomFrame.viewport.setGatherViewsHere(true);
3454 String topViewId = myTopFrame.viewport.getSequenceSetId();
3455 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3457 JInternalFrame[] frames = desktop.getAllFrames();
3458 for (JInternalFrame frame : frames)
3460 if (frame instanceof SplitFrame && frame != source)
3462 SplitFrame sf = (SplitFrame) frame;
3463 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3464 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3465 boolean gatherThis = false;
3466 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3468 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3469 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3470 if (topViewId.equals(topPanel.av.getSequenceSetId())
3471 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3474 topPanel.av.setGatherViewsHere(false);
3475 bottomPanel.av.setGatherViewsHere(false);
3476 topPanel.av.setExplodedGeometry(
3477 new Rectangle(sf.getLocation(), topFrame.getSize()));
3478 bottomPanel.av.setExplodedGeometry(
3479 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3480 myTopFrame.addAlignmentPanel(topPanel, false);
3481 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3487 topFrame.getAlignPanels().clear();
3488 bottomFrame.getAlignPanels().clear();
3495 * The dust settles...give focus to the tab we did this from.
3497 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3500 public static groovy.ui.Console getGroovyConsole()
3502 return groovyConsole;
3506 * handles the payload of a drag and drop event.
3508 * TODO refactor to desktop utilities class
3511 * - Data source strings extracted from the drop event
3513 * - protocol for each data source extracted from the drop event
3517 * - the payload from the drop event
3520 public static void transferFromDropTarget(List<Object> files,
3521 List<DataSourceType> protocols, DropTargetDropEvent evt,
3522 Transferable t) throws Exception
3525 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3527 // DataFlavor[] flavors = t.getTransferDataFlavors();
3528 // for (int i = 0; i < flavors.length; i++) {
3529 // if (flavors[i].isFlavorJavaFileListType()) {
3530 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3531 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3532 // for (int j = 0; j < list.size(); j++) {
3533 // File file = (File) list.get(j);
3534 // byte[] data = getDroppedFileBytes(file);
3535 // fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
3536 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3537 // target.setText(new String(data));
3539 // dtde.dropComplete(true);
3544 DataFlavor uriListFlavor = new DataFlavor(
3545 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3548 urlFlavour = new DataFlavor(
3549 "application/x-java-url; class=java.net.URL");
3550 } catch (ClassNotFoundException cfe)
3552 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3555 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3560 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3561 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3562 // means url may be null.
3565 protocols.add(DataSourceType.URL);
3566 files.add(url.toString());
3567 Cache.log.debug("Drop handled as URL dataflavor "
3568 + files.get(files.size() - 1));
3573 if (Platform.isAMac())
3576 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3580 } catch (Throwable ex)
3582 Cache.log.debug("URL drop handler failed.", ex);
3585 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3587 // Works on Windows and MacOSX
3588 Cache.log.debug("Drop handled as javaFileListFlavor");
3589 for (Object file : (List) t
3590 .getTransferData(DataFlavor.javaFileListFlavor))
3593 protocols.add(DataSourceType.FILE);
3598 // Unix like behaviour
3599 boolean added = false;
3601 if (t.isDataFlavorSupported(uriListFlavor))
3603 Cache.log.debug("Drop handled as uriListFlavor");
3604 // This is used by Unix drag system
3605 data = (String) t.getTransferData(uriListFlavor);
3609 // fallback to text: workaround - on OSX where there's a JVM bug
3610 Cache.log.debug("standard URIListFlavor failed. Trying text");
3611 // try text fallback
3612 DataFlavor textDf = new DataFlavor(
3613 "text/plain;class=java.lang.String");
3614 if (t.isDataFlavorSupported(textDf))
3616 data = (String) t.getTransferData(textDf);
3619 Cache.log.debug("Plain text drop content returned "
3620 + (data == null ? "Null - failed" : data));
3625 while (protocols.size() < files.size())
3627 Cache.log.debug("Adding missing FILE protocol for "
3628 + files.get(protocols.size()));
3629 protocols.add(DataSourceType.FILE);
3631 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3632 data, "\r\n"); st.hasMoreTokens();)
3635 String s = st.nextToken();
3636 if (s.startsWith("#"))
3638 // the line is a comment (as per the RFC 2483)
3641 java.net.URI uri = new java.net.URI(s);
3642 if (uri.getScheme().toLowerCase().startsWith("http"))
3644 protocols.add(DataSourceType.URL);
3645 files.add(uri.toString());
3649 // otherwise preserve old behaviour: catch all for file objects
3650 java.io.File file = new java.io.File(uri);
3651 protocols.add(DataSourceType.FILE);
3652 files.add(file.toString());
3657 if (Cache.log.isDebugEnabled())
3659 if (data == null || !added)
3662 if (t.getTransferDataFlavors() != null
3663 && t.getTransferDataFlavors().length > 0)
3666 "Couldn't resolve drop data. Here are the supported flavors:");
3667 for (DataFlavor fl : t.getTransferDataFlavors())
3670 "Supported transfer dataflavor: " + fl.toString());
3671 Object df = t.getTransferData(fl);
3674 Cache.log.debug("Retrieves: " + df);
3678 Cache.log.debug("Retrieved nothing");
3684 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3690 if (Platform.isWindows())
3693 Cache.log.debug("Scanning dropped content for Windows Link Files");
3695 // resolve any .lnk files in the file drop
3696 for (int f = 0; f < files.size(); f++)
3698 String source = files.get(f).toString().toLowerCase();
3699 if (protocols.get(f).equals(DataSourceType.FILE)
3700 && (source.endsWith(".lnk") || source.endsWith(".url")
3701 || source.endsWith(".site")))
3704 Object obj = files.get(f);
3705 File lf = (obj instanceof File ? (File) obj : new File((String) obj));
3706 // process link file to get a URL
3707 Cache.log.debug("Found potential link file: " + lf);
3708 WindowsShortcut wscfile = new WindowsShortcut(lf);
3709 String fullname = wscfile.getRealFilename();
3710 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3711 files.set(f, fullname);
3712 Cache.log.debug("Parsed real filename " + fullname
3713 + " to extract protocol: " + protocols.get(f));
3715 catch (Exception ex)
3717 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3725 * Sets the Preferences property for experimental features to True or False
3726 * depending on the state of the controlling menu item
3729 protected void showExperimental_actionPerformed(boolean selected)
3731 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3735 * Answers a (possibly empty) list of any structure viewer frames (currently
3736 * for either Jmol or Chimera) which are currently open. This may optionally
3737 * be restricted to viewers of a specified class, or viewers linked to a
3738 * specified alignment panel.
3741 * if not null, only return viewers linked to this panel
3742 * @param structureViewerClass
3743 * if not null, only return viewers of this class
3746 public List<StructureViewerBase> getStructureViewers(
3747 AlignmentPanel apanel,
3748 Class<? extends StructureViewerBase> structureViewerClass)
3750 List<StructureViewerBase> result = new ArrayList<>();
3751 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3753 for (JInternalFrame frame : frames)
3755 if (frame instanceof StructureViewerBase)
3757 if (structureViewerClass == null
3758 || structureViewerClass.isInstance(frame))
3761 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3763 result.add((StructureViewerBase) frame);