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 jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.bin.Jalview;
27 import jalview.io.DataSourceType;
28 import jalview.io.FileFormat;
29 import jalview.io.FileFormatException;
30 import jalview.io.FileFormatI;
31 import jalview.io.FileFormats;
32 import jalview.io.FileLoader;
33 import jalview.io.FormatAdapter;
34 import jalview.io.IdentifyFile;
35 import jalview.io.JalviewFileChooser;
36 import jalview.io.JalviewFileView;
37 import jalview.jbgui.GSplitFrame;
38 import jalview.jbgui.GStructureViewer;
39 import jalview.structure.StructureSelectionManager;
40 import jalview.urls.IdOrgSettings;
41 import jalview.util.ImageMaker;
42 import jalview.util.MessageManager;
43 import jalview.util.Platform;
44 import jalview.util.UrlConstants;
45 import jalview.viewmodel.AlignmentViewport;
46 import jalview.ws.params.ParamManager;
47 import jalview.ws.utils.UrlDownloadClient;
49 import java.awt.BorderLayout;
50 import java.awt.Color;
51 import java.awt.Dimension;
52 import java.awt.FontMetrics;
53 import java.awt.Graphics;
54 import java.awt.GridLayout;
55 import java.awt.Point;
56 import java.awt.Rectangle;
57 import java.awt.Toolkit;
58 import java.awt.Window;
59 import java.awt.datatransfer.Clipboard;
60 import java.awt.datatransfer.ClipboardOwner;
61 import java.awt.datatransfer.DataFlavor;
62 import java.awt.datatransfer.Transferable;
63 import java.awt.desktop.AboutEvent;
64 import java.awt.desktop.AboutHandler;
65 import java.awt.desktop.PreferencesEvent;
66 import java.awt.desktop.PreferencesHandler;
67 import java.awt.desktop.QuitEvent;
68 import java.awt.desktop.QuitHandler;
69 import java.awt.desktop.QuitResponse;
70 import java.awt.desktop.QuitStrategy;
71 import java.awt.dnd.DnDConstants;
72 import java.awt.dnd.DropTargetDragEvent;
73 import java.awt.dnd.DropTargetDropEvent;
74 import java.awt.dnd.DropTargetEvent;
75 import java.awt.dnd.DropTargetListener;
76 import java.awt.event.ActionEvent;
77 import java.awt.event.ActionListener;
78 import java.awt.event.InputEvent;
79 import java.awt.event.KeyEvent;
80 import java.awt.event.MouseAdapter;
81 import java.awt.event.MouseEvent;
82 import java.awt.event.WindowAdapter;
83 import java.awt.event.WindowEvent;
84 import java.beans.PropertyChangeEvent;
85 import java.beans.PropertyChangeListener;
86 import java.io.BufferedInputStream;
88 import java.io.FileOutputStream;
89 import java.io.FileWriter;
90 import java.io.IOException;
92 import java.util.ArrayList;
93 import java.util.HashMap;
94 import java.util.Hashtable;
95 import java.util.List;
96 import java.util.ListIterator;
97 import java.util.StringTokenizer;
98 import java.util.Vector;
99 import java.util.concurrent.ExecutorService;
100 import java.util.concurrent.Executors;
101 import java.util.concurrent.Semaphore;
103 import javax.swing.AbstractAction;
104 import javax.swing.Action;
105 import javax.swing.ActionMap;
106 import javax.swing.Box;
107 import javax.swing.BoxLayout;
108 import javax.swing.DefaultDesktopManager;
109 import javax.swing.DesktopManager;
110 import javax.swing.InputMap;
111 import javax.swing.JButton;
112 import javax.swing.JCheckBox;
113 import javax.swing.JComboBox;
114 import javax.swing.JComponent;
115 import javax.swing.JDesktopPane;
116 import javax.swing.JInternalFrame;
117 import javax.swing.JLabel;
118 import javax.swing.JMenuItem;
119 import javax.swing.JOptionPane;
120 import javax.swing.JPanel;
121 import javax.swing.JPopupMenu;
122 import javax.swing.JProgressBar;
123 import javax.swing.KeyStroke;
124 import javax.swing.SwingUtilities;
125 import javax.swing.event.HyperlinkEvent;
126 import javax.swing.event.HyperlinkEvent.EventType;
127 import javax.swing.event.InternalFrameAdapter;
128 import javax.swing.event.InternalFrameEvent;
129 import javax.swing.event.MenuEvent;
130 import javax.swing.event.MenuListener;
132 import org.stackoverflowusers.file.WindowsShortcut;
139 * @version $Revision: 1.155 $
141 public class Desktop extends jalview.jbgui.GDesktop
142 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
143 jalview.api.StructureSelectionManagerProvider
145 private static int DEFAULT_MIN_WIDTH = 300;
147 private static int DEFAULT_MIN_HEIGHT = 250;
149 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
151 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
153 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
155 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
157 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
160 * news reader - null if it was never started.
162 private BlogReader jvnews = null;
164 private File projectFile;
168 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
170 public void addJalviewPropertyChangeListener(
171 PropertyChangeListener listener)
173 changeSupport.addJalviewPropertyChangeListener(listener);
177 * @param propertyName
179 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
180 * java.beans.PropertyChangeListener)
182 public void addJalviewPropertyChangeListener(String propertyName,
183 PropertyChangeListener listener)
185 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
189 * @param propertyName
191 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
192 * java.beans.PropertyChangeListener)
194 public void removeJalviewPropertyChangeListener(String propertyName,
195 PropertyChangeListener listener)
197 changeSupport.removeJalviewPropertyChangeListener(propertyName,
201 /** Singleton Desktop instance */
202 public static Desktop instance;
204 public static MyDesktopPane desktop;
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"));
359 if (!Platform.isAMac())
361 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
366 // this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
367 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
369 hdesktop.setAboutHandler(new AboutHandler()
372 public void handleAbout(AboutEvent e)
374 aboutMenuItem_actionPerformed(null);
377 hdesktop.setPreferencesHandler(new PreferencesHandler()
380 public void handlePreferences(PreferencesEvent e)
382 preferences_actionPerformed(null);
385 hdesktop.setQuitHandler(new QuitHandler()
388 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
390 int n = JOptionPane.showConfirmDialog(null,
391 MessageManager.getString("label.quit_jalview"),
392 MessageManager.getString("action.quit"),
393 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
395 if (n == JOptionPane.OK_OPTION)
397 System.out.println("Shortcut Quit confirmed by user");
399 r.performQuit(); // probably won't reach this line, but just in case
404 System.out.println("Shortcut Quit cancelled by user");
408 hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
412 addWindowListener(new WindowAdapter()
416 public void windowClosing(WindowEvent ev)
422 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
425 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
427 desktop = new MyDesktopPane(selmemusage);
428 showMemusage.setSelected(selmemusage);
429 desktop.setBackground(Color.white);
431 getContentPane().setLayout(new BorderLayout());
432 // alternate config - have scrollbars - see notes in JAL-153
433 // JScrollPane sp = new JScrollPane();
434 // sp.getViewport().setView(desktop);
435 // getContentPane().add(sp, BorderLayout.CENTER);
436 getContentPane().add(desktop, BorderLayout.CENTER);
437 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
439 // This line prevents Windows Look&Feel resizing all new windows to maximum
440 // if previous window was maximised
441 desktop.setDesktopManager(new MyDesktopManager(
442 (Platform.isWindows() ? new DefaultDesktopManager()
444 ? new AquaInternalFrameManager(
445 desktop.getDesktopManager())
446 : desktop.getDesktopManager())));
448 Rectangle dims = getLastKnownDimensions("");
455 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
456 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
459 jconsole = new Console(this, showjconsole);
460 // add essential build information
462 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
463 + "\n" + "Jalview Installation: "
464 + jalview.bin.Cache.getDefault("INSTALLATION",
466 + "\n" + "Build Date: "
467 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
468 + "\n" + "Java version: "
469 + System.getProperty("java.version") + "\n"
470 + System.getProperty("os.arch") + " "
471 + System.getProperty("os.name") + " "
472 + System.getProperty("os.version"));
474 showConsole(showjconsole);
476 showNews.setVisible(false);
478 experimentalFeatures.setSelected(showExperimental());
480 getIdentifiersOrgData();
484 this.addWindowListener(new WindowAdapter()
487 public void windowClosing(WindowEvent evt)
494 this.addMouseListener(ma = new MouseAdapter()
497 public void mousePressed(MouseEvent evt)
499 if (evt.isPopupTrigger()) // Mac
501 showPasteMenu(evt.getX(), evt.getY());
506 public void mouseReleased(MouseEvent evt)
508 if (evt.isPopupTrigger()) // Windows
510 showPasteMenu(evt.getX(), evt.getY());
514 desktop.addMouseListener(ma);
516 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
517 // Spawn a thread that shows the splashscreen
518 SwingUtilities.invokeLater(new Runnable()
527 // Thread off a new instance of the file chooser - this reduces the time it
528 // takes to open it later on.
529 new Thread(new Runnable()
534 Cache.log.debug("Filechooser init thread started.");
535 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
536 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
538 Cache.log.debug("Filechooser init thread finished.");
541 // Add the service change listener
542 changeSupport.addJalviewPropertyChangeListener("services",
543 new PropertyChangeListener()
547 public void propertyChange(PropertyChangeEvent evt)
549 Cache.log.debug("Firing service changed event for "
550 + evt.getNewValue());
551 JalviewServicesChanged(evt);
558 * Answers true if user preferences to enable experimental features is True
563 public boolean showExperimental()
565 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
566 Boolean.FALSE.toString());
567 return Boolean.valueOf(experimental).booleanValue();
570 public void doConfigureStructurePrefs()
572 // configure services
573 StructureSelectionManager ssm = StructureSelectionManager
574 .getStructureSelectionManager(this);
575 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
577 ssm.setAddTempFacAnnot(jalview.bin.Cache
578 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
579 ssm.setProcessSecondaryStructure(jalview.bin.Cache
580 .getDefault(Preferences.STRUCT_FROM_PDB, true));
581 ssm.setSecStructServices(
582 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
586 ssm.setAddTempFacAnnot(false);
587 ssm.setProcessSecondaryStructure(false);
588 ssm.setSecStructServices(false);
592 public void checkForNews()
594 final Desktop me = this;
595 // Thread off the news reader, in case there are connection problems.
596 new Thread(new Runnable()
601 Cache.log.debug("Starting news thread.");
603 jvnews = new BlogReader(me);
604 showNews.setVisible(true);
605 Cache.log.debug("Completed news thread.");
610 public void getIdentifiersOrgData()
612 // Thread off the identifiers fetcher
613 new Thread(new Runnable()
618 Cache.log.debug("Downloading data from identifiers.org");
619 UrlDownloadClient client = new UrlDownloadClient();
622 client.download(IdOrgSettings.getUrl(),
623 IdOrgSettings.getDownloadLocation());
624 } catch (IOException e)
626 Cache.log.debug("Exception downloading identifiers.org data"
635 protected void showNews_actionPerformed(ActionEvent e)
637 showNews(showNews.isSelected());
640 void showNews(boolean visible)
643 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
644 showNews.setSelected(visible);
645 if (visible && !jvnews.isVisible())
647 new Thread(new Runnable()
652 long now = System.currentTimeMillis();
653 Desktop.instance.setProgressBar(
654 MessageManager.getString("status.refreshing_news"),
656 jvnews.refreshNews();
657 Desktop.instance.setProgressBar(null, now);
666 * recover the last known dimensions for a jalview window
669 * - empty string is desktop, all other windows have unique prefix
670 * @return null or last known dimensions scaled to current geometry (if last
671 * window geom was known)
673 Rectangle getLastKnownDimensions(String windowName)
675 // TODO: lock aspect ratio for scaling desktop Bug #0058199
676 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
677 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
678 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
679 String width = jalview.bin.Cache
680 .getProperty(windowName + "SCREEN_WIDTH");
681 String height = jalview.bin.Cache
682 .getProperty(windowName + "SCREEN_HEIGHT");
683 if ((x != null) && (y != null) && (width != null) && (height != null))
685 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
686 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
687 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
689 // attempt #1 - try to cope with change in screen geometry - this
690 // version doesn't preserve original jv aspect ratio.
691 // take ratio of current screen size vs original screen size.
692 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
693 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
694 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
695 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
696 // rescale the bounds depending upon the current screen geometry.
697 ix = (int) (ix * sw);
698 iw = (int) (iw * sw);
699 iy = (int) (iy * sh);
700 ih = (int) (ih * sh);
701 while (ix >= screenSize.width)
703 jalview.bin.Cache.log.debug(
704 "Window geometry location recall error: shifting horizontal to within screenbounds.");
705 ix -= screenSize.width;
707 while (iy >= screenSize.height)
709 jalview.bin.Cache.log.debug(
710 "Window geometry location recall error: shifting vertical to within screenbounds.");
711 iy -= screenSize.height;
713 jalview.bin.Cache.log.debug(
714 "Got last known dimensions for " + windowName + ": x:" + ix
715 + " y:" + iy + " width:" + iw + " height:" + ih);
717 // return dimensions for new instance
718 return new Rectangle(ix, iy, iw, ih);
723 private void doVamsasClientCheck()
725 if (jalview.bin.Cache.vamsasJarsPresent())
727 setupVamsasDisconnectedGui();
728 VamsasMenu.setVisible(true);
729 final Desktop us = this;
730 VamsasMenu.addMenuListener(new MenuListener()
732 // this listener remembers when the menu was first selected, and
733 // doesn't rebuild the session list until it has been cleared and
735 boolean refresh = true;
738 public void menuCanceled(MenuEvent e)
744 public void menuDeselected(MenuEvent e)
750 public void menuSelected(MenuEvent e)
754 us.buildVamsasStMenu();
759 vamsasStart.setVisible(true);
763 void showPasteMenu(int x, int y)
765 JPopupMenu popup = new JPopupMenu();
766 JMenuItem item = new JMenuItem(
767 MessageManager.getString("label.paste_new_window"));
768 item.addActionListener(new ActionListener()
771 public void actionPerformed(ActionEvent evt)
778 popup.show(this, x, y);
785 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
786 Transferable contents = c.getContents(this);
788 if (contents != null)
790 String file = (String) contents
791 .getTransferData(DataFlavor.stringFlavor);
793 FileFormatI format = new IdentifyFile().identify(file,
794 DataSourceType.PASTE);
796 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
799 } catch (Exception ex)
802 "Unable to paste alignment from system clipboard:\n" + ex);
807 * Adds and opens the given frame to the desktop
818 public static synchronized void addInternalFrame(
819 final JInternalFrame frame, String title, int w, int h)
821 addInternalFrame(frame, title, true, w, h, true, false);
825 * Add an internal frame to the Jalview desktop
832 * When true, display frame immediately, otherwise, caller must call
833 * setVisible themselves.
839 public static synchronized void addInternalFrame(
840 final JInternalFrame frame, String title, boolean makeVisible,
843 addInternalFrame(frame, title, makeVisible, w, h, true, false);
847 * Add an internal frame to the Jalview desktop and make it visible
860 public static synchronized void addInternalFrame(
861 final JInternalFrame frame, String title, int w, int h,
864 addInternalFrame(frame, title, true, w, h, resizable, false);
868 * Add an internal frame to the Jalview desktop
875 * When true, display frame immediately, otherwise, caller must call
876 * setVisible themselves.
883 * @param ignoreMinSize
884 * Do not set the default minimum size for frame
886 public static synchronized void addInternalFrame(
887 final JInternalFrame frame, String title, boolean makeVisible,
888 int w, int h, boolean resizable, boolean ignoreMinSize)
891 // TODO: allow callers to determine X and Y position of frame (eg. via
893 // TODO: consider fixing method to update entries in the window submenu with
894 // the current window title
896 frame.setTitle(title);
897 if (frame.getWidth() < 1 || frame.getHeight() < 1)
901 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
902 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
903 // IF JALVIEW IS RUNNING HEADLESS
904 // ///////////////////////////////////////////////
905 if (instance == null || (System.getProperty("java.awt.headless") != null
906 && System.getProperty("java.awt.headless").equals("true")))
915 frame.setMinimumSize(
916 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
918 // Set default dimension for Alignment Frame window.
919 // The Alignment Frame window could be added from a number of places,
921 // I did this here in order not to miss out on any Alignment frame.
922 if (frame instanceof AlignFrame)
924 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
925 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
929 frame.setVisible(makeVisible);
930 frame.setClosable(true);
931 frame.setResizable(resizable);
932 frame.setMaximizable(resizable);
933 frame.setIconifiable(resizable);
934 frame.setOpaque(false);
936 if (frame.getX() < 1 && frame.getY() < 1)
938 frame.setLocation(xOffset * openFrameCount,
939 yOffset * ((openFrameCount - 1) % 10) + yOffset);
943 * add an entry for the new frame in the Window menu
944 * (and remove it when the frame is closed)
946 final JMenuItem menuItem = new JMenuItem(title);
947 frame.addInternalFrameListener(new InternalFrameAdapter()
950 public void internalFrameActivated(InternalFrameEvent evt)
952 JInternalFrame itf = desktop.getSelectedFrame();
955 if (itf instanceof AlignFrame)
957 Jalview.setCurrentAlignFrame((AlignFrame) itf);
964 public void internalFrameClosed(InternalFrameEvent evt)
966 PaintRefresher.RemoveComponent(frame);
969 * defensive check to prevent frames being
970 * added half off the window
972 if (openFrameCount > 0)
978 * ensure no reference to alignFrame retained by menu item listener
980 if (menuItem.getActionListeners().length > 0)
982 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
984 windowMenu.remove(menuItem);
988 menuItem.addActionListener(new ActionListener()
991 public void actionPerformed(ActionEvent e)
995 frame.setSelected(true);
996 frame.setIcon(false);
997 } catch (java.beans.PropertyVetoException ex)
1004 setKeyBindings(frame);
1008 windowMenu.add(menuItem);
1013 frame.setSelected(true);
1014 frame.requestFocus();
1015 } catch (java.beans.PropertyVetoException ve)
1017 } catch (java.lang.ClassCastException cex)
1020 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1026 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1031 private static void setKeyBindings(JInternalFrame frame)
1033 @SuppressWarnings("serial")
1034 final Action closeAction = new AbstractAction()
1037 public void actionPerformed(ActionEvent e)
1044 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1046 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1047 InputEvent.CTRL_DOWN_MASK);
1048 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1049 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1051 InputMap inputMap = frame
1052 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1053 String ctrlW = ctrlWKey.toString();
1054 inputMap.put(ctrlWKey, ctrlW);
1055 inputMap.put(cmdWKey, ctrlW);
1057 ActionMap actionMap = frame.getActionMap();
1058 actionMap.put(ctrlW, closeAction);
1062 public void lostOwnership(Clipboard clipboard, Transferable contents)
1066 Desktop.jalviewClipboard = null;
1069 internalCopy = false;
1073 public void dragEnter(DropTargetDragEvent evt)
1078 public void dragExit(DropTargetEvent evt)
1083 public void dragOver(DropTargetDragEvent evt)
1088 public void dropActionChanged(DropTargetDragEvent evt)
1099 public void drop(DropTargetDropEvent evt)
1101 boolean success = true;
1102 // JAL-1552 - acceptDrop required before getTransferable call for
1103 // Java's Transferable for native dnd
1104 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1105 Transferable t = evt.getTransferable();
1106 List<String> files = new ArrayList<>();
1107 List<DataSourceType> protocols = new ArrayList<>();
1111 Desktop.transferFromDropTarget(files, protocols, evt, t);
1112 } catch (Exception e)
1114 e.printStackTrace();
1122 for (int i = 0; i < files.size(); i++)
1124 String file = files.get(i).toString();
1125 DataSourceType protocol = (protocols == null)
1126 ? DataSourceType.FILE
1128 FileFormatI format = null;
1130 if (file.endsWith(".jar"))
1132 format = FileFormat.Jalview;
1137 format = new IdentifyFile().identify(file, protocol);
1140 new FileLoader().LoadFile(file, protocol, format);
1143 } catch (Exception ex)
1148 evt.dropComplete(success); // need this to ensure input focus is properly
1149 // transfered to any new windows created
1159 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1161 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1162 JalviewFileChooser chooser = JalviewFileChooser
1163 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1165 chooser.setFileView(new JalviewFileView());
1166 chooser.setDialogTitle(
1167 MessageManager.getString("label.open_local_file"));
1168 chooser.setToolTipText(MessageManager.getString("action.open"));
1170 int value = chooser.showOpenDialog(this);
1172 if (value == JalviewFileChooser.APPROVE_OPTION)
1174 String choice = chooser.getSelectedFile().getPath();
1175 Cache.setProperty("LAST_DIRECTORY",
1176 chooser.getSelectedFile().getParent());
1178 FileFormatI format = chooser.getSelectedFormat();
1181 * Call IdentifyFile to verify the file contains what its extension implies.
1182 * Skip this step for dynamically added file formats, because
1183 * IdentifyFile does not know how to recognise them.
1185 if (FileFormats.getInstance().isIdentifiable(format))
1189 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1190 } catch (FileFormatException e)
1192 // format = null; //??
1196 if (viewport != null)
1198 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1203 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1215 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1217 // This construct allows us to have a wider textfield
1219 JLabel label = new JLabel(
1220 MessageManager.getString("label.input_file_url"));
1221 final JComboBox history = new JComboBox();
1223 JPanel panel = new JPanel(new GridLayout(2, 1));
1226 history.setPreferredSize(new Dimension(400, 20));
1227 history.setEditable(true);
1228 history.addItem("http://www.");
1230 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1234 if (historyItems != null)
1236 st = new StringTokenizer(historyItems, "\t");
1238 while (st.hasMoreTokens())
1240 history.addItem(st.nextElement());
1244 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1245 MessageManager.getString("label.input_alignment_from_url"),
1246 JvOptionPane.OK_CANCEL_OPTION);
1248 if (reply != JvOptionPane.OK_OPTION)
1253 String url = history.getSelectedItem().toString();
1255 if (url.toLowerCase().endsWith(".jar"))
1257 if (viewport != null)
1259 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1260 FileFormat.Jalview);
1264 new FileLoader().LoadFile(url, DataSourceType.URL,
1265 FileFormat.Jalview);
1270 FileFormatI format = null;
1273 format = new IdentifyFile().identify(url, DataSourceType.URL);
1274 } catch (FileFormatException e)
1276 // TODO revise error handling, distinguish between
1277 // URL not found and response not valid
1282 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1283 MessageManager.formatMessage("label.couldnt_locate",
1286 MessageManager.getString("label.url_not_found"),
1287 JvOptionPane.WARNING_MESSAGE);
1292 if (viewport != null)
1294 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1299 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1305 * Opens the CutAndPaste window for the user to paste an alignment in to
1308 * - if not null, the pasted alignment is added to the current
1309 * alignment; if null, to a new alignment window
1312 public void inputTextboxMenuItem_actionPerformed(
1313 AlignmentViewPanel viewPanel)
1315 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1316 cap.setForInput(viewPanel);
1317 Desktop.addInternalFrame(cap,
1318 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1328 System.out.println("********** Desktop.quit()");
1329 System.out.println(savingFiles.toString());
1330 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1331 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1333 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1334 screen.height + "");
1335 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1336 getWidth(), getHeight()));
1338 if (jconsole != null)
1340 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1341 jconsole.stopConsole();
1345 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1348 if (dialogExecutor != null)
1350 dialogExecutor.shutdownNow();
1352 closeAll_actionPerformed(null);
1354 if (groovyConsole != null)
1356 // suppress a possible repeat prompt to save script
1357 groovyConsole.setDirty(false);
1358 groovyConsole.exit();
1363 private void storeLastKnownDimensions(String string, Rectangle jc)
1365 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1366 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1367 + " height:" + jc.height);
1369 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1370 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1371 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1372 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1382 public void aboutMenuItem_actionPerformed(ActionEvent e)
1384 // StringBuffer message = getAboutMessage(false);
1385 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1387 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1388 new Thread(new Runnable()
1393 new SplashScreen(true);
1398 public StringBuffer getAboutMessage(boolean shortv)
1400 StringBuffer message = new StringBuffer();
1401 message.append("<html>");
1404 message.append("<h1><strong>Version: "
1405 + jalview.bin.Cache.getProperty("VERSION")
1406 + "</strong></h1>");
1407 message.append("<strong>Last Updated: <em>"
1408 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1409 + "</em></strong>");
1415 message.append("<strong>Version "
1416 + jalview.bin.Cache.getProperty("VERSION")
1417 + "; last updated: "
1418 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1421 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1422 .equals("Checking"))
1424 message.append("<br>...Checking latest version...</br>");
1426 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1427 .equals(jalview.bin.Cache.getProperty("VERSION")))
1429 boolean red = false;
1430 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1431 .indexOf("automated build") == -1)
1434 // Displayed when code version and jnlp version do not match and code
1435 // version is not a development build
1436 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1439 message.append("<br>!! Version "
1440 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1442 + " is available for download from "
1443 + jalview.bin.Cache.getDefault("www.jalview.org",
1444 "http://www.jalview.org")
1448 message.append("</div>");
1451 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1453 "The Jalview Authors (See AUTHORS file for current list)")
1454 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1455 + "<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"
1456 + "<br><br>If you use Jalview, please cite:"
1457 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1458 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1459 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1471 public void documentationMenuItem_actionPerformed(ActionEvent e)
1475 Help.showHelpWindow();
1476 } catch (Exception ex)
1482 public void closeAll_actionPerformed(ActionEvent e)
1484 // TODO show a progress bar while closing?
1485 JInternalFrame[] frames = desktop.getAllFrames();
1486 for (int i = 0; i < frames.length; i++)
1490 frames[i].setClosed(true);
1491 } catch (java.beans.PropertyVetoException ex)
1495 Jalview.setCurrentAlignFrame(null);
1496 System.out.println("ALL CLOSED");
1497 if (v_client != null)
1499 // TODO clear binding to vamsas document objects on close_all
1503 * reset state of singleton objects as appropriate (clear down session state
1504 * when all windows are closed)
1506 StructureSelectionManager ssm = StructureSelectionManager
1507 .getStructureSelectionManager(this);
1515 public void raiseRelated_actionPerformed(ActionEvent e)
1517 reorderAssociatedWindows(false, false);
1521 public void minimizeAssociated_actionPerformed(ActionEvent e)
1523 reorderAssociatedWindows(true, false);
1526 void closeAssociatedWindows()
1528 reorderAssociatedWindows(false, true);
1534 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1538 protected void garbageCollect_actionPerformed(ActionEvent e)
1540 // We simply collect the garbage
1541 jalview.bin.Cache.log.debug("Collecting garbage...");
1543 jalview.bin.Cache.log.debug("Finished garbage collection.");
1550 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1554 protected void showMemusage_actionPerformed(ActionEvent e)
1556 desktop.showMemoryUsage(showMemusage.isSelected());
1563 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1567 protected void showConsole_actionPerformed(ActionEvent e)
1569 showConsole(showConsole.isSelected());
1572 Console jconsole = null;
1575 * control whether the java console is visible or not
1579 void showConsole(boolean selected)
1581 showConsole.setSelected(selected);
1582 // TODO: decide if we should update properties file
1583 Cache.setProperty("SHOW_JAVA_CONSOLE",
1584 Boolean.valueOf(selected).toString());
1585 jconsole.setVisible(selected);
1588 void reorderAssociatedWindows(boolean minimize, boolean close)
1590 JInternalFrame[] frames = desktop.getAllFrames();
1591 if (frames == null || frames.length < 1)
1596 AlignmentViewport source = null, target = null;
1597 if (frames[0] instanceof AlignFrame)
1599 source = ((AlignFrame) frames[0]).getCurrentView();
1601 else if (frames[0] instanceof TreePanel)
1603 source = ((TreePanel) frames[0]).getViewPort();
1605 else if (frames[0] instanceof PCAPanel)
1607 source = ((PCAPanel) frames[0]).av;
1609 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1611 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1616 for (int i = 0; i < frames.length; i++)
1619 if (frames[i] == null)
1623 if (frames[i] instanceof AlignFrame)
1625 target = ((AlignFrame) frames[i]).getCurrentView();
1627 else if (frames[i] instanceof TreePanel)
1629 target = ((TreePanel) frames[i]).getViewPort();
1631 else if (frames[i] instanceof PCAPanel)
1633 target = ((PCAPanel) frames[i]).av;
1635 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1637 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1640 if (source == target)
1646 frames[i].setClosed(true);
1650 frames[i].setIcon(minimize);
1653 frames[i].toFront();
1657 } catch (java.beans.PropertyVetoException ex)
1672 protected void preferences_actionPerformed(ActionEvent e)
1684 public void saveState_actionPerformed(ActionEvent e)
1686 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1689 chooser.setFileView(new JalviewFileView());
1690 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1692 int value = chooser.showSaveDialog(this);
1694 if (value == JalviewFileChooser.APPROVE_OPTION)
1696 final Desktop me = this;
1697 final java.io.File choice = chooser.getSelectedFile();
1698 setProjectFile(choice);
1700 new Thread(new Runnable()
1705 // TODO: refactor to Jalview desktop session controller action.
1706 setProgressBar(MessageManager.formatMessage(
1707 "label.saving_jalview_project", new Object[]
1708 { choice.getName() }), choice.hashCode());
1709 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1710 choice.getParent());
1711 // TODO catch and handle errors for savestate
1712 // TODO prevent user from messing with the Desktop whilst we're saving
1715 new Jalview2XML().saveState(choice);
1716 } catch (OutOfMemoryError oom)
1719 "Whilst saving current state to " + choice.getName(),
1721 } catch (Exception ex)
1724 "Problems whilst trying to save to " + choice.getName(),
1726 JvOptionPane.showMessageDialog(me,
1727 MessageManager.formatMessage(
1728 "label.error_whilst_saving_current_state_to",
1730 { choice.getName() }),
1731 MessageManager.getString("label.couldnt_save_project"),
1732 JvOptionPane.WARNING_MESSAGE);
1734 setProgressBar(null, choice.hashCode());
1740 private void setProjectFile(File choice)
1742 this.projectFile = choice;
1745 public File getProjectFile()
1747 return this.projectFile;
1757 public void loadState_actionPerformed(ActionEvent e)
1759 JalviewFileChooser chooser = new JalviewFileChooser(
1760 Cache.getProperty("LAST_DIRECTORY"), new String[]
1763 { "Jalview Project", "Jalview Project (old)" },
1765 chooser.setFileView(new JalviewFileView());
1766 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1768 int value = chooser.showOpenDialog(this);
1770 if (value == JalviewFileChooser.APPROVE_OPTION)
1772 final File selectedFile = chooser.getSelectedFile();
1773 setProjectFile(selectedFile);
1774 final String choice = selectedFile.getAbsolutePath();
1775 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1776 new Thread(new Runnable()
1781 setProgressBar(MessageManager.formatMessage(
1782 "label.loading_jalview_project", new Object[]
1783 { choice }), choice.hashCode());
1786 new Jalview2XML().loadJalviewAlign(choice);
1787 } catch (OutOfMemoryError oom)
1789 new OOMWarning("Whilst loading project from " + choice, oom);
1790 } catch (Exception ex)
1793 "Problems whilst loading project from " + choice, ex);
1794 JvOptionPane.showMessageDialog(Desktop.desktop,
1795 MessageManager.formatMessage(
1796 "label.error_whilst_loading_project_from",
1799 MessageManager.getString("label.couldnt_load_project"),
1800 JvOptionPane.WARNING_MESSAGE);
1802 setProgressBar(null, choice.hashCode());
1809 public void inputSequence_actionPerformed(ActionEvent e)
1811 new SequenceFetcher(this);
1814 JPanel progressPanel;
1816 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1818 public void startLoading(final String fileName)
1820 if (fileLoadingCount == 0)
1822 fileLoadingPanels.add(addProgressPanel(MessageManager
1823 .formatMessage("label.loading_file", new Object[]
1829 private JPanel addProgressPanel(String string)
1831 if (progressPanel == null)
1833 progressPanel = new JPanel(new GridLayout(1, 1));
1834 totalProgressCount = 0;
1835 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1837 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1838 JProgressBar progressBar = new JProgressBar();
1839 progressBar.setIndeterminate(true);
1841 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1843 thisprogress.add(progressBar, BorderLayout.CENTER);
1844 progressPanel.add(thisprogress);
1845 ((GridLayout) progressPanel.getLayout()).setRows(
1846 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1847 ++totalProgressCount;
1848 instance.validate();
1849 return thisprogress;
1852 int totalProgressCount = 0;
1854 private void removeProgressPanel(JPanel progbar)
1856 if (progressPanel != null)
1858 synchronized (progressPanel)
1860 progressPanel.remove(progbar);
1861 GridLayout gl = (GridLayout) progressPanel.getLayout();
1862 gl.setRows(gl.getRows() - 1);
1863 if (--totalProgressCount < 1)
1865 this.getContentPane().remove(progressPanel);
1866 progressPanel = null;
1873 public void stopLoading()
1876 if (fileLoadingCount < 1)
1878 while (fileLoadingPanels.size() > 0)
1880 removeProgressPanel(fileLoadingPanels.remove(0));
1882 fileLoadingPanels.clear();
1883 fileLoadingCount = 0;
1888 public static int getViewCount(String alignmentId)
1890 AlignmentViewport[] aps = getViewports(alignmentId);
1891 return (aps == null) ? 0 : aps.length;
1896 * @param alignmentId
1897 * - if null, all sets are returned
1898 * @return all AlignmentPanels concerning the alignmentId sequence set
1900 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1902 if (Desktop.desktop == null)
1904 // no frames created and in headless mode
1905 // TODO: verify that frames are recoverable when in headless mode
1908 List<AlignmentPanel> aps = new ArrayList<>();
1909 AlignFrame[] frames = getAlignFrames();
1914 for (AlignFrame af : frames)
1916 for (AlignmentPanel ap : af.alignPanels)
1918 if (alignmentId == null
1919 || alignmentId.equals(ap.av.getSequenceSetId()))
1925 if (aps.size() == 0)
1929 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1934 * get all the viewports on an alignment.
1936 * @param sequenceSetId
1937 * unique alignment id (may be null - all viewports returned in that
1939 * @return all viewports on the alignment bound to sequenceSetId
1941 public static AlignmentViewport[] getViewports(String sequenceSetId)
1943 List<AlignmentViewport> viewp = new ArrayList<>();
1944 if (desktop != null)
1946 AlignFrame[] frames = Desktop.getAlignFrames();
1948 for (AlignFrame afr : frames)
1950 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1951 .equals(sequenceSetId))
1953 if (afr.alignPanels != null)
1955 for (AlignmentPanel ap : afr.alignPanels)
1957 if (sequenceSetId == null
1958 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1966 viewp.add(afr.getViewport());
1970 if (viewp.size() > 0)
1972 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1979 * Explode the views in the given frame into separate AlignFrame
1983 public static void explodeViews(AlignFrame af)
1985 int size = af.alignPanels.size();
1991 for (int i = 0; i < size; i++)
1993 AlignmentPanel ap = af.alignPanels.get(i);
1994 AlignFrame newaf = new AlignFrame(ap);
1997 * Restore the view's last exploded frame geometry if known. Multiple
1998 * views from one exploded frame share and restore the same (frame)
1999 * position and size.
2001 Rectangle geometry = ap.av.getExplodedGeometry();
2002 if (geometry != null)
2004 newaf.setBounds(geometry);
2007 ap.av.setGatherViewsHere(false);
2009 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2010 AlignFrame.DEFAULT_HEIGHT);
2013 af.alignPanels.clear();
2014 af.closeMenuItem_actionPerformed(true);
2019 * Gather expanded views (separate AlignFrame's) with the same sequence set
2020 * identifier back in to this frame as additional views, and close the
2021 * expanded views. Note the expanded frames may themselves have multiple
2022 * views. We take the lot.
2026 public void gatherViews(AlignFrame source)
2028 source.viewport.setGatherViewsHere(true);
2029 source.viewport.setExplodedGeometry(source.getBounds());
2030 JInternalFrame[] frames = desktop.getAllFrames();
2031 String viewId = source.viewport.getSequenceSetId();
2033 for (int t = 0; t < frames.length; t++)
2035 if (frames[t] instanceof AlignFrame && frames[t] != source)
2037 AlignFrame af = (AlignFrame) frames[t];
2038 boolean gatherThis = false;
2039 for (int a = 0; a < af.alignPanels.size(); a++)
2041 AlignmentPanel ap = af.alignPanels.get(a);
2042 if (viewId.equals(ap.av.getSequenceSetId()))
2045 ap.av.setGatherViewsHere(false);
2046 ap.av.setExplodedGeometry(af.getBounds());
2047 source.addAlignmentPanel(ap, false);
2053 af.alignPanels.clear();
2054 af.closeMenuItem_actionPerformed(true);
2061 jalview.gui.VamsasApplication v_client = null;
2064 public void vamsasImport_actionPerformed(ActionEvent e)
2066 if (v_client == null)
2068 // Load and try to start a session.
2069 JalviewFileChooser chooser = new JalviewFileChooser(
2070 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2072 chooser.setFileView(new JalviewFileView());
2073 chooser.setDialogTitle(
2074 MessageManager.getString("label.open_saved_vamsas_session"));
2075 chooser.setToolTipText(MessageManager.getString(
2076 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2078 int value = chooser.showOpenDialog(this);
2080 if (value == JalviewFileChooser.APPROVE_OPTION)
2082 String fle = chooser.getSelectedFile().toString();
2083 if (!vamsasImport(chooser.getSelectedFile()))
2085 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2086 MessageManager.formatMessage(
2087 "label.couldnt_import_as_vamsas_session",
2091 .getString("label.vamsas_document_import_failed"),
2092 JvOptionPane.ERROR_MESSAGE);
2098 jalview.bin.Cache.log.error(
2099 "Implementation error - load session from a running session is not supported.");
2104 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2107 * @return true if import was a success and a session was started.
2109 public boolean vamsasImport(URL url)
2111 // TODO: create progress bar
2112 if (v_client != null)
2115 jalview.bin.Cache.log.error(
2116 "Implementation error - load session from a running session is not supported.");
2122 // copy the URL content to a temporary local file
2123 // TODO: be a bit cleverer here with nio (?!)
2124 File file = File.createTempFile("vdocfromurl", ".vdj");
2125 FileOutputStream fos = new FileOutputStream(file);
2126 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2127 byte[] buffer = new byte[2048];
2129 while ((ln = bis.read(buffer)) > -1)
2131 fos.write(buffer, 0, ln);
2135 v_client = new jalview.gui.VamsasApplication(this, file,
2136 url.toExternalForm());
2137 } catch (Exception ex)
2139 jalview.bin.Cache.log.error(
2140 "Failed to create new vamsas session from contents of URL "
2145 setupVamsasConnectedGui();
2146 v_client.initial_update(); // TODO: thread ?
2147 return v_client.inSession();
2151 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2154 * @return true if import was a success and a session was started.
2156 public boolean vamsasImport(File file)
2158 if (v_client != null)
2161 jalview.bin.Cache.log.error(
2162 "Implementation error - load session from a running session is not supported.");
2166 setProgressBar(MessageManager.formatMessage(
2167 "status.importing_vamsas_session_from", new Object[]
2168 { file.getName() }), file.hashCode());
2171 v_client = new jalview.gui.VamsasApplication(this, file, null);
2172 } catch (Exception ex)
2174 setProgressBar(MessageManager.formatMessage(
2175 "status.importing_vamsas_session_from", new Object[]
2176 { file.getName() }), file.hashCode());
2177 jalview.bin.Cache.log.error(
2178 "New vamsas session from existing session file failed:", ex);
2181 setupVamsasConnectedGui();
2182 v_client.initial_update(); // TODO: thread ?
2183 setProgressBar(MessageManager.formatMessage(
2184 "status.importing_vamsas_session_from", new Object[]
2185 { file.getName() }), file.hashCode());
2186 return v_client.inSession();
2189 public boolean joinVamsasSession(String mysesid)
2191 if (v_client != null)
2193 throw new Error(MessageManager
2194 .getString("error.try_join_vamsas_session_another"));
2196 if (mysesid == null)
2199 MessageManager.getString("error.invalid_vamsas_session_id"));
2201 v_client = new VamsasApplication(this, mysesid);
2202 setupVamsasConnectedGui();
2203 v_client.initial_update();
2204 return (v_client.inSession());
2208 public void vamsasStart_actionPerformed(ActionEvent e)
2210 if (v_client == null)
2213 // we just start a default session for moment.
2215 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2216 * getProperty("LAST_DIRECTORY"));
2218 * chooser.setFileView(new JalviewFileView());
2219 * chooser.setDialogTitle("Load Vamsas file");
2220 * chooser.setToolTipText("Import");
2222 * int value = chooser.showOpenDialog(this);
2224 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2225 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2227 v_client = new VamsasApplication(this);
2228 setupVamsasConnectedGui();
2229 v_client.initial_update(); // TODO: thread ?
2233 // store current data in session.
2234 v_client.push_update(); // TODO: thread
2238 protected void setupVamsasConnectedGui()
2240 vamsasStart.setText(MessageManager.getString("label.session_update"));
2241 vamsasSave.setVisible(true);
2242 vamsasStop.setVisible(true);
2243 vamsasImport.setVisible(false); // Document import to existing session is
2244 // not possible for vamsas-client-1.0.
2247 protected void setupVamsasDisconnectedGui()
2249 vamsasSave.setVisible(false);
2250 vamsasStop.setVisible(false);
2251 vamsasImport.setVisible(true);
2253 .setText(MessageManager.getString("label.new_vamsas_session"));
2257 public void vamsasStop_actionPerformed(ActionEvent e)
2259 if (v_client != null)
2261 v_client.end_session();
2263 setupVamsasDisconnectedGui();
2267 protected void buildVamsasStMenu()
2269 if (v_client == null)
2271 String[] sess = null;
2274 sess = VamsasApplication.getSessionList();
2275 } catch (Exception e)
2277 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2283 jalview.bin.Cache.log.debug(
2284 "Got current sessions list: " + sess.length + " entries.");
2285 VamsasStMenu.removeAll();
2286 for (int i = 0; i < sess.length; i++)
2288 JMenuItem sessit = new JMenuItem();
2289 sessit.setText(sess[i]);
2290 sessit.setToolTipText(MessageManager
2291 .formatMessage("label.connect_to_session", new Object[]
2293 final Desktop dsktp = this;
2294 final String mysesid = sess[i];
2295 sessit.addActionListener(new ActionListener()
2299 public void actionPerformed(ActionEvent e)
2301 if (dsktp.v_client == null)
2303 Thread rthr = new Thread(new Runnable()
2309 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2310 dsktp.setupVamsasConnectedGui();
2311 dsktp.v_client.initial_update();
2319 VamsasStMenu.add(sessit);
2321 // don't show an empty menu.
2322 VamsasStMenu.setVisible(sess.length > 0);
2327 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2328 VamsasStMenu.removeAll();
2329 VamsasStMenu.setVisible(false);
2334 // Not interested in the content. Just hide ourselves.
2335 VamsasStMenu.setVisible(false);
2340 public void vamsasSave_actionPerformed(ActionEvent e)
2342 if (v_client != null)
2344 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2345 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2348 chooser.setFileView(new JalviewFileView());
2349 chooser.setDialogTitle(MessageManager
2350 .getString("label.save_vamsas_document_archive"));
2352 int value = chooser.showSaveDialog(this);
2354 if (value == JalviewFileChooser.APPROVE_OPTION)
2356 java.io.File choice = chooser.getSelectedFile();
2357 JPanel progpanel = addProgressPanel(MessageManager
2358 .formatMessage("label.saving_vamsas_doc", new Object[]
2359 { choice.getName() }));
2360 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2361 String warnmsg = null;
2362 String warnttl = null;
2365 v_client.vclient.storeDocument(choice);
2368 warnttl = "Serious Problem saving Vamsas Document";
2369 warnmsg = ex.toString();
2370 jalview.bin.Cache.log
2371 .error("Error Whilst saving document to " + choice, ex);
2373 } catch (Exception ex)
2375 warnttl = "Problem saving Vamsas Document.";
2376 warnmsg = ex.toString();
2377 jalview.bin.Cache.log.warn(
2378 "Exception Whilst saving document to " + choice, ex);
2381 removeProgressPanel(progpanel);
2382 if (warnmsg != null)
2384 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2386 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2392 JPanel vamUpdate = null;
2395 * hide vamsas user gui bits when a vamsas document event is being handled.
2398 * true to hide gui, false to reveal gui
2400 public void setVamsasUpdate(boolean b)
2402 Cache.log.debug("Setting gui for Vamsas update "
2403 + (b ? "in progress" : "finished"));
2405 if (vamUpdate != null)
2407 this.removeProgressPanel(vamUpdate);
2411 vamUpdate = this.addProgressPanel(
2412 MessageManager.getString("label.updating_vamsas_session"));
2414 vamsasStart.setVisible(!b);
2415 vamsasStop.setVisible(!b);
2416 vamsasSave.setVisible(!b);
2419 public JInternalFrame[] getAllFrames()
2421 return desktop.getAllFrames();
2425 * Checks the given url to see if it gives a response indicating that the user
2426 * should be informed of a new questionnaire.
2430 public void checkForQuestionnaire(String url)
2432 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2433 // javax.swing.SwingUtilities.invokeLater(jvq);
2434 new Thread(jvq).start();
2437 public void checkURLLinks()
2439 // Thread off the URL link checker
2440 addDialogThread(new Runnable()
2445 if (Cache.getDefault("CHECKURLLINKS", true))
2447 // check what the actual links are - if it's just the default don't
2448 // bother with the warning
2449 List<String> links = Preferences.sequenceUrlLinks
2452 // only need to check links if there is one with a
2453 // SEQUENCE_ID which is not the default EMBL_EBI link
2454 ListIterator<String> li = links.listIterator();
2455 boolean check = false;
2456 List<JLabel> urls = new ArrayList<>();
2457 while (li.hasNext())
2459 String link = li.next();
2460 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2461 && !UrlConstants.isDefaultString(link))
2464 int barPos = link.indexOf("|");
2465 String urlMsg = barPos == -1 ? link
2466 : link.substring(0, barPos) + ": "
2467 + link.substring(barPos + 1);
2468 urls.add(new JLabel(urlMsg));
2476 // ask user to check in case URL links use old style tokens
2477 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2478 JPanel msgPanel = new JPanel();
2479 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2480 msgPanel.add(Box.createVerticalGlue());
2481 JLabel msg = new JLabel(MessageManager
2482 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2483 JLabel msg2 = new JLabel(MessageManager
2484 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2486 for (JLabel url : urls)
2492 final JCheckBox jcb = new JCheckBox(
2493 MessageManager.getString("label.do_not_display_again"));
2494 jcb.addActionListener(new ActionListener()
2497 public void actionPerformed(ActionEvent e)
2499 // update Cache settings for "don't show this again"
2500 boolean showWarningAgain = !jcb.isSelected();
2501 Cache.setProperty("CHECKURLLINKS",
2502 Boolean.valueOf(showWarningAgain).toString());
2507 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2509 .getString("label.SEQUENCE_ID_no_longer_used"),
2510 JvOptionPane.WARNING_MESSAGE);
2517 * Proxy class for JDesktopPane which optionally displays the current memory
2518 * usage and highlights the desktop area with a red bar if free memory runs
2523 public class MyDesktopPane extends JDesktopPane implements Runnable
2526 private static final float ONE_MB = 1048576f;
2528 boolean showMemoryUsage = false;
2532 java.text.NumberFormat df;
2534 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2537 public MyDesktopPane(boolean showMemoryUsage)
2539 showMemoryUsage(showMemoryUsage);
2542 public void showMemoryUsage(boolean showMemory)
2544 this.showMemoryUsage = showMemory;
2547 Thread worker = new Thread(this);
2553 public boolean isShowMemoryUsage()
2555 return showMemoryUsage;
2561 df = java.text.NumberFormat.getNumberInstance();
2562 df.setMaximumFractionDigits(2);
2563 runtime = Runtime.getRuntime();
2565 while (showMemoryUsage)
2569 maxMemory = runtime.maxMemory() / ONE_MB;
2570 allocatedMemory = runtime.totalMemory() / ONE_MB;
2571 freeMemory = runtime.freeMemory() / ONE_MB;
2572 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2574 percentUsage = (totalFreeMemory / maxMemory) * 100;
2576 // if (percentUsage < 20)
2578 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2580 // instance.set.setBorder(border1);
2583 // sleep after showing usage
2585 } catch (Exception ex)
2587 ex.printStackTrace();
2593 public void paintComponent(Graphics g)
2595 if (showMemoryUsage && g != null && df != null)
2597 if (percentUsage < 20)
2599 g.setColor(Color.red);
2601 FontMetrics fm = g.getFontMetrics();
2604 g.drawString(MessageManager.formatMessage("label.memory_stats",
2606 { df.format(totalFreeMemory), df.format(maxMemory),
2607 df.format(percentUsage) }),
2608 10, getHeight() - fm.getHeight());
2615 * Accessor method to quickly get all the AlignmentFrames loaded.
2617 * @return an array of AlignFrame, or null if none found
2619 public static AlignFrame[] getAlignFrames()
2621 if (Jalview.isHeadlessMode())
2623 // Desktop.desktop is null in headless mode
2624 return new AlignFrame[] { Jalview.currentAlignFrame };
2627 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2633 List<AlignFrame> avp = new ArrayList<>();
2635 for (int i = frames.length - 1; i > -1; i--)
2637 if (frames[i] instanceof AlignFrame)
2639 avp.add((AlignFrame) frames[i]);
2641 else if (frames[i] instanceof SplitFrame)
2644 * Also check for a split frame containing an AlignFrame
2646 GSplitFrame sf = (GSplitFrame) frames[i];
2647 if (sf.getTopFrame() instanceof AlignFrame)
2649 avp.add((AlignFrame) sf.getTopFrame());
2651 if (sf.getBottomFrame() instanceof AlignFrame)
2653 avp.add((AlignFrame) sf.getBottomFrame());
2657 if (avp.size() == 0)
2661 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2666 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2670 public GStructureViewer[] getJmols()
2672 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2678 List<GStructureViewer> avp = new ArrayList<>();
2680 for (int i = frames.length - 1; i > -1; i--)
2682 if (frames[i] instanceof AppJmol)
2684 GStructureViewer af = (GStructureViewer) frames[i];
2688 if (avp.size() == 0)
2692 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2697 * Add Groovy Support to Jalview
2700 public void groovyShell_actionPerformed()
2704 openGroovyConsole();
2705 } catch (Exception ex)
2707 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2708 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2710 MessageManager.getString("label.couldnt_create_groovy_shell"),
2711 MessageManager.getString("label.groovy_support_failed"),
2712 JvOptionPane.ERROR_MESSAGE);
2717 * Open the Groovy console
2719 void openGroovyConsole()
2721 if (groovyConsole == null)
2723 groovyConsole = new groovy.ui.Console();
2724 groovyConsole.setVariable("Jalview", this);
2725 groovyConsole.run();
2728 * We allow only one console at a time, so that AlignFrame menu option
2729 * 'Calculate | Run Groovy script' is unambiguous.
2730 * Disable 'Groovy Console', and enable 'Run script', when the console is
2731 * opened, and the reverse when it is closed
2733 Window window = (Window) groovyConsole.getFrame();
2734 window.addWindowListener(new WindowAdapter()
2737 public void windowClosed(WindowEvent e)
2740 * rebind CMD-Q from Groovy Console to Jalview Quit
2743 enableExecuteGroovy(false);
2749 * show Groovy console window (after close and reopen)
2751 ((Window) groovyConsole.getFrame()).setVisible(true);
2754 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2755 * and disable opening a second console
2757 enableExecuteGroovy(true);
2761 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2762 * binding when opened
2764 protected void addQuitHandler()
2766 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2767 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2768 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2770 getRootPane().getActionMap().put("Quit", new AbstractAction()
2773 public void actionPerformed(ActionEvent e)
2781 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2784 * true if Groovy console is open
2786 public void enableExecuteGroovy(boolean enabled)
2789 * disable opening a second Groovy console
2790 * (or re-enable when the console is closed)
2792 groovyShell.setEnabled(!enabled);
2794 AlignFrame[] alignFrames = getAlignFrames();
2795 if (alignFrames != null)
2797 for (AlignFrame af : alignFrames)
2799 af.setGroovyEnabled(enabled);
2805 * Progress bars managed by the IProgressIndicator method.
2807 private Hashtable<Long, JPanel> progressBars;
2809 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2814 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2817 public void setProgressBar(String message, long id)
2819 if (progressBars == null)
2821 progressBars = new Hashtable<>();
2822 progressBarHandlers = new Hashtable<>();
2825 if (progressBars.get(new Long(id)) != null)
2827 JPanel panel = progressBars.remove(new Long(id));
2828 if (progressBarHandlers.contains(new Long(id)))
2830 progressBarHandlers.remove(new Long(id));
2832 removeProgressPanel(panel);
2836 progressBars.put(new Long(id), addProgressPanel(message));
2843 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2844 * jalview.gui.IProgressIndicatorHandler)
2847 public void registerHandler(final long id,
2848 final IProgressIndicatorHandler handler)
2850 if (progressBarHandlers == null
2851 || !progressBars.containsKey(new Long(id)))
2853 throw new Error(MessageManager.getString(
2854 "error.call_setprogressbar_before_registering_handler"));
2856 progressBarHandlers.put(new Long(id), handler);
2857 final JPanel progressPanel = progressBars.get(new Long(id));
2858 if (handler.canCancel())
2860 JButton cancel = new JButton(
2861 MessageManager.getString("action.cancel"));
2862 final IProgressIndicator us = this;
2863 cancel.addActionListener(new ActionListener()
2867 public void actionPerformed(ActionEvent e)
2869 handler.cancelActivity(id);
2870 us.setProgressBar(MessageManager
2871 .formatMessage("label.cancelled_params", new Object[]
2872 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2876 progressPanel.add(cancel, BorderLayout.EAST);
2882 * @return true if any progress bars are still active
2885 public boolean operationInProgress()
2887 if (progressBars != null && progressBars.size() > 0)
2895 * This will return the first AlignFrame holding the given viewport instance.
2896 * It will break if there are more than one AlignFrames viewing a particular
2900 * @return alignFrame for viewport
2902 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2904 if (desktop != null)
2906 AlignmentPanel[] aps = getAlignmentPanels(
2907 viewport.getSequenceSetId());
2908 for (int panel = 0; aps != null && panel < aps.length; panel++)
2910 if (aps[panel] != null && aps[panel].av == viewport)
2912 return aps[panel].alignFrame;
2919 public VamsasApplication getVamsasApplication()
2926 * flag set if jalview GUI is being operated programmatically
2928 private boolean inBatchMode = false;
2931 * check if jalview GUI is being operated programmatically
2933 * @return inBatchMode
2935 public boolean isInBatchMode()
2941 * set flag if jalview GUI is being operated programmatically
2943 * @param inBatchMode
2945 public void setInBatchMode(boolean inBatchMode)
2947 this.inBatchMode = inBatchMode;
2950 public void startServiceDiscovery()
2952 startServiceDiscovery(false);
2955 public void startServiceDiscovery(boolean blocking)
2957 boolean alive = true;
2958 Thread t0 = null, t1 = null, t2 = null;
2959 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2962 // todo: changesupport handlers need to be transferred
2963 if (discoverer == null)
2965 discoverer = new jalview.ws.jws1.Discoverer();
2966 // register PCS handler for desktop.
2967 discoverer.addPropertyChangeListener(changeSupport);
2969 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2970 // until we phase out completely
2971 (t0 = new Thread(discoverer)).start();
2974 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2976 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2977 .startDiscoverer(changeSupport);
2981 // TODO: do rest service discovery
2990 } catch (Exception e)
2993 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2994 || (t3 != null && t3.isAlive())
2995 || (t0 != null && t0.isAlive());
3001 * called to check if the service discovery process completed successfully.
3005 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3007 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3009 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3010 .getErrorMessages();
3013 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3015 if (serviceChangedDialog == null)
3017 // only run if we aren't already displaying one of these.
3018 addDialogThread(serviceChangedDialog = new Runnable()
3025 * JalviewDialog jd =new JalviewDialog() {
3027 * @Override protected void cancelPressed() { // TODO
3028 * Auto-generated method stub
3030 * }@Override protected void okPressed() { // TODO
3031 * Auto-generated method stub
3033 * }@Override protected void raiseClosed() { // TODO
3034 * Auto-generated method stub
3036 * } }; jd.initDialogFrame(new
3037 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3038 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3039 * + " or mis-configured HTTP proxy settings.<br/>" +
3040 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3042 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3043 * ), true, true, "Web Service Configuration Problem", 450,
3046 * jd.waitForInput();
3048 JvOptionPane.showConfirmDialog(Desktop.desktop,
3049 new JLabel("<html><table width=\"450\"><tr><td>"
3050 + ermsg + "</td></tr></table>"
3051 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3052 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3053 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3054 + " Tools->Preferences dialog box to change them.</p></html>"),
3055 "Web Service Configuration Problem",
3056 JvOptionPane.DEFAULT_OPTION,
3057 JvOptionPane.ERROR_MESSAGE);
3058 serviceChangedDialog = null;
3067 "Errors reported by JABA discovery service. Check web services preferences.\n"
3074 private Runnable serviceChangedDialog = null;
3077 * start a thread to open a URL in the configured browser. Pops up a warning
3078 * dialog to the user if there is an exception when calling out to the browser
3083 public static void showUrl(final String url)
3085 showUrl(url, Desktop.instance);
3089 * Like showUrl but allows progress handler to be specified
3093 * (null) or object implementing IProgressIndicator
3095 public static void showUrl(final String url,
3096 final IProgressIndicator progress)
3098 new Thread(new Runnable()
3105 if (progress != null)
3107 progress.setProgressBar(MessageManager
3108 .formatMessage("status.opening_params", new Object[]
3109 { url }), this.hashCode());
3111 jalview.util.BrowserLauncher.openURL(url);
3112 } catch (Exception ex)
3114 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3116 .getString("label.web_browser_not_found_unix"),
3117 MessageManager.getString("label.web_browser_not_found"),
3118 JvOptionPane.WARNING_MESSAGE);
3120 ex.printStackTrace();
3122 if (progress != null)
3124 progress.setProgressBar(null, this.hashCode());
3130 public static WsParamSetManager wsparamManager = null;
3132 public static ParamManager getUserParameterStore()
3134 if (wsparamManager == null)
3136 wsparamManager = new WsParamSetManager();
3138 return wsparamManager;
3142 * static hyperlink handler proxy method for use by Jalview's internal windows
3146 public static void hyperlinkUpdate(HyperlinkEvent e)
3148 if (e.getEventType() == EventType.ACTIVATED)
3153 url = e.getURL().toString();
3154 Desktop.showUrl(url);
3155 } catch (Exception x)
3159 if (Cache.log != null)
3161 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3166 "Couldn't handle string " + url + " as a URL.");
3169 // ignore any exceptions due to dud links.
3176 * single thread that handles display of dialogs to user.
3178 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3181 * flag indicating if dialogExecutor should try to acquire a permit
3183 private volatile boolean dialogPause = true;
3188 private java.util.concurrent.Semaphore block = new Semaphore(0);
3190 private static groovy.ui.Console groovyConsole;
3193 * add another dialog thread to the queue
3197 public void addDialogThread(final Runnable prompter)
3199 dialogExecutor.submit(new Runnable()
3209 } catch (InterruptedException x)
3214 if (instance == null)
3220 SwingUtilities.invokeAndWait(prompter);
3221 } catch (Exception q)
3223 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3229 public void startDialogQueue()
3231 // set the flag so we don't pause waiting for another permit and semaphore
3232 // the current task to begin
3233 dialogPause = false;
3238 protected void snapShotWindow_actionPerformed(ActionEvent e)
3242 ImageMaker im = new jalview.util.ImageMaker(
3243 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3244 getHeight(), of = new File("Jalview_snapshot"
3245 + System.currentTimeMillis() + ".eps"),
3246 "View of desktop", null, 0, false);
3249 paintAll(im.getGraphics());
3251 } catch (Exception q)
3253 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3257 Cache.log.info("Successfully written snapshot to file "
3258 + of.getAbsolutePath());
3262 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3263 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3264 * and location last time the view was expanded (if any). However it does not
3265 * remember the split pane divider location - this is set to match the
3266 * 'exploding' frame.
3270 public void explodeViews(SplitFrame sf)
3272 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3273 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3274 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3276 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3278 int viewCount = topPanels.size();
3285 * Processing in reverse order works, forwards order leaves the first panels
3286 * not visible. I don't know why!
3288 for (int i = viewCount - 1; i >= 0; i--)
3291 * Make new top and bottom frames. These take over the respective
3292 * AlignmentPanel objects, including their AlignmentViewports, so the
3293 * cdna/protein relationships between the viewports is carried over to the
3296 * explodedGeometry holds the (x, y) position of the previously exploded
3297 * SplitFrame, and the (width, height) of the AlignFrame component
3299 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3300 AlignFrame newTopFrame = new AlignFrame(topPanel);
3301 newTopFrame.setSize(oldTopFrame.getSize());
3302 newTopFrame.setVisible(true);
3303 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3304 .getExplodedGeometry();
3305 if (geometry != null)
3307 newTopFrame.setSize(geometry.getSize());
3310 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3311 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3312 newBottomFrame.setSize(oldBottomFrame.getSize());
3313 newBottomFrame.setVisible(true);
3314 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3315 .getExplodedGeometry();
3316 if (geometry != null)
3318 newBottomFrame.setSize(geometry.getSize());
3321 topPanel.av.setGatherViewsHere(false);
3322 bottomPanel.av.setGatherViewsHere(false);
3323 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3325 if (geometry != null)
3327 splitFrame.setLocation(geometry.getLocation());
3329 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3333 * Clear references to the panels (now relocated in the new SplitFrames)
3334 * before closing the old SplitFrame.
3337 bottomPanels.clear();
3342 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3343 * back into the given SplitFrame as additional views. Note that the gathered
3344 * frames may themselves have multiple views.
3348 public void gatherViews(GSplitFrame source)
3351 * special handling of explodedGeometry for a view within a SplitFrame: - it
3352 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3353 * height) of the AlignFrame component
3355 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3356 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3357 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3358 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3359 myBottomFrame.viewport
3360 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3361 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3362 myTopFrame.viewport.setGatherViewsHere(true);
3363 myBottomFrame.viewport.setGatherViewsHere(true);
3364 String topViewId = myTopFrame.viewport.getSequenceSetId();
3365 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3367 JInternalFrame[] frames = desktop.getAllFrames();
3368 for (JInternalFrame frame : frames)
3370 if (frame instanceof SplitFrame && frame != source)
3372 SplitFrame sf = (SplitFrame) frame;
3373 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3374 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3375 boolean gatherThis = false;
3376 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3378 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3379 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3380 if (topViewId.equals(topPanel.av.getSequenceSetId())
3381 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3384 topPanel.av.setGatherViewsHere(false);
3385 bottomPanel.av.setGatherViewsHere(false);
3386 topPanel.av.setExplodedGeometry(
3387 new Rectangle(sf.getLocation(), topFrame.getSize()));
3388 bottomPanel.av.setExplodedGeometry(
3389 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3390 myTopFrame.addAlignmentPanel(topPanel, false);
3391 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3397 topFrame.getAlignPanels().clear();
3398 bottomFrame.getAlignPanels().clear();
3405 * The dust settles...give focus to the tab we did this from.
3407 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3410 public static groovy.ui.Console getGroovyConsole()
3412 return groovyConsole;
3416 * handles the payload of a drag and drop event.
3418 * TODO refactor to desktop utilities class
3421 * - Data source strings extracted from the drop event
3423 * - protocol for each data source extracted from the drop event
3427 * - the payload from the drop event
3430 public static void transferFromDropTarget(List<String> files,
3431 List<DataSourceType> protocols, DropTargetDropEvent evt,
3432 Transferable t) throws Exception
3435 DataFlavor uriListFlavor = new DataFlavor(
3436 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3439 urlFlavour = new DataFlavor(
3440 "application/x-java-url; class=java.net.URL");
3441 } catch (ClassNotFoundException cfe)
3443 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3446 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3451 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3452 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3453 // means url may be null.
3456 protocols.add(DataSourceType.URL);
3457 files.add(url.toString());
3458 Cache.log.debug("Drop handled as URL dataflavor "
3459 + files.get(files.size() - 1));
3464 if (Platform.isAMac())
3467 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3471 } catch (Throwable ex)
3473 Cache.log.debug("URL drop handler failed.", ex);
3476 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3478 // Works on Windows and MacOSX
3479 Cache.log.debug("Drop handled as javaFileListFlavor");
3480 for (Object file : (List) t
3481 .getTransferData(DataFlavor.javaFileListFlavor))
3483 files.add(((File) file).toString());
3484 protocols.add(DataSourceType.FILE);
3489 // Unix like behaviour
3490 boolean added = false;
3492 if (t.isDataFlavorSupported(uriListFlavor))
3494 Cache.log.debug("Drop handled as uriListFlavor");
3495 // This is used by Unix drag system
3496 data = (String) t.getTransferData(uriListFlavor);
3500 // fallback to text: workaround - on OSX where there's a JVM bug
3501 Cache.log.debug("standard URIListFlavor failed. Trying text");
3502 // try text fallback
3503 DataFlavor textDf = new DataFlavor(
3504 "text/plain;class=java.lang.String");
3505 if (t.isDataFlavorSupported(textDf))
3507 data = (String) t.getTransferData(textDf);
3510 Cache.log.debug("Plain text drop content returned "
3511 + (data == null ? "Null - failed" : data));
3516 while (protocols.size() < files.size())
3518 Cache.log.debug("Adding missing FILE protocol for "
3519 + files.get(protocols.size()));
3520 protocols.add(DataSourceType.FILE);
3522 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3523 data, "\r\n"); st.hasMoreTokens();)
3526 String s = st.nextToken();
3527 if (s.startsWith("#"))
3529 // the line is a comment (as per the RFC 2483)
3532 java.net.URI uri = new java.net.URI(s);
3533 if (uri.getScheme().toLowerCase().startsWith("http"))
3535 protocols.add(DataSourceType.URL);
3536 files.add(uri.toString());
3540 // otherwise preserve old behaviour: catch all for file objects
3541 java.io.File file = new java.io.File(uri);
3542 protocols.add(DataSourceType.FILE);
3543 files.add(file.toString());
3548 if (Cache.log.isDebugEnabled())
3550 if (data == null || !added)
3553 if (t.getTransferDataFlavors() != null
3554 && t.getTransferDataFlavors().length > 0)
3557 "Couldn't resolve drop data. Here are the supported flavors:");
3558 for (DataFlavor fl : t.getTransferDataFlavors())
3561 "Supported transfer dataflavor: " + fl.toString());
3562 Object df = t.getTransferData(fl);
3565 Cache.log.debug("Retrieves: " + df);
3569 Cache.log.debug("Retrieved nothing");
3575 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3581 if (Platform.isWindows())
3584 Cache.log.debug("Scanning dropped content for Windows Link Files");
3586 // resolve any .lnk files in the file drop
3587 for (int f = 0; f < files.size(); f++)
3589 String source = files.get(f).toLowerCase();
3590 if (protocols.get(f).equals(DataSourceType.FILE)
3591 && (source.endsWith(".lnk") || source.endsWith(".url")
3592 || source.endsWith(".site")))
3596 File lf = new File(files.get(f));
3597 // process link file to get a URL
3598 Cache.log.debug("Found potential link file: " + lf);
3599 WindowsShortcut wscfile = new WindowsShortcut(lf);
3600 String fullname = wscfile.getRealFilename();
3601 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3602 files.set(f, fullname);
3603 Cache.log.debug("Parsed real filename " + fullname
3604 + " to extract protocol: " + protocols.get(f));
3605 } catch (Exception ex)
3608 "Couldn't parse " + files.get(f) + " as a link file.",
3617 * Sets the Preferences property for experimental features to True or False
3618 * depending on the state of the controlling menu item
3621 protected void showExperimental_actionPerformed(boolean selected)
3623 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3627 * Answers a (possibly empty) list of any structure viewer frames (currently
3628 * for either Jmol or Chimera) which are currently open. This may optionally
3629 * be restricted to viewers of a specified class, or viewers linked to a
3630 * specified alignment panel.
3633 * if not null, only return viewers linked to this panel
3634 * @param structureViewerClass
3635 * if not null, only return viewers of this class
3638 public List<StructureViewerBase> getStructureViewers(
3639 AlignmentPanel apanel,
3640 Class<? extends StructureViewerBase> structureViewerClass)
3642 List<StructureViewerBase> result = new ArrayList<>();
3643 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3645 for (JInternalFrame frame : frames)
3647 if (frame instanceof StructureViewerBase)
3649 if (structureViewerClass == null
3650 || structureViewerClass.isInstance(frame))
3653 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3655 result.add((StructureViewerBase) frame);