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.BackupFiles;
28 import jalview.io.DataSourceType;
29 import jalview.io.FileFormat;
30 import jalview.io.FileFormatException;
31 import jalview.io.FileFormatI;
32 import jalview.io.FileFormats;
33 import jalview.io.FileLoader;
34 import jalview.io.FormatAdapter;
35 import jalview.io.IdentifyFile;
36 import jalview.io.JalviewFileChooser;
37 import jalview.io.JalviewFileView;
38 import jalview.jbgui.GSplitFrame;
39 import jalview.jbgui.GStructureViewer;
40 import jalview.project.Jalview2XML;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
80 import java.io.BufferedInputStream;
82 import java.io.FileOutputStream;
83 import java.io.FileWriter;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.HashMap;
88 import java.util.Hashtable;
89 import java.util.List;
90 import java.util.ListIterator;
91 import java.util.StringTokenizer;
92 import java.util.Vector;
93 import java.util.concurrent.ExecutorService;
94 import java.util.concurrent.Executors;
95 import java.util.concurrent.Semaphore;
97 import javax.swing.AbstractAction;
98 import javax.swing.Action;
99 import javax.swing.ActionMap;
100 import javax.swing.Box;
101 import javax.swing.BoxLayout;
102 import javax.swing.DefaultDesktopManager;
103 import javax.swing.DesktopManager;
104 import javax.swing.InputMap;
105 import javax.swing.JButton;
106 import javax.swing.JCheckBox;
107 import javax.swing.JComboBox;
108 import javax.swing.JComponent;
109 import javax.swing.JDesktopPane;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.KeyStroke;
117 import javax.swing.SwingUtilities;
118 import javax.swing.event.HyperlinkEvent;
119 import javax.swing.event.HyperlinkEvent.EventType;
120 import javax.swing.event.InternalFrameAdapter;
121 import javax.swing.event.InternalFrameEvent;
122 import javax.swing.event.MenuEvent;
123 import javax.swing.event.MenuListener;
125 import org.stackoverflowusers.file.WindowsShortcut;
132 * @version $Revision: 1.155 $
134 public class Desktop extends jalview.jbgui.GDesktop
135 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
136 jalview.api.StructureSelectionManagerProvider
138 private static int DEFAULT_MIN_WIDTH = 300;
140 private static int DEFAULT_MIN_HEIGHT = 250;
142 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
144 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
146 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
148 protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
150 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
152 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
155 * news reader - null if it was never started.
157 private BlogReader jvnews = null;
159 private File projectFile;
163 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
165 public void addJalviewPropertyChangeListener(
166 PropertyChangeListener listener)
168 changeSupport.addJalviewPropertyChangeListener(listener);
172 * @param propertyName
174 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
175 * java.beans.PropertyChangeListener)
177 public void addJalviewPropertyChangeListener(String propertyName,
178 PropertyChangeListener listener)
180 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
184 * @param propertyName
186 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
187 * java.beans.PropertyChangeListener)
189 public void removeJalviewPropertyChangeListener(String propertyName,
190 PropertyChangeListener listener)
192 changeSupport.removeJalviewPropertyChangeListener(propertyName,
196 /** Singleton Desktop instance */
197 public static Desktop instance;
199 public static MyDesktopPane desktop;
201 static int openFrameCount = 0;
203 static final int xOffset = 30;
205 static final int yOffset = 30;
207 public static jalview.ws.jws1.Discoverer discoverer;
209 public static Object[] jalviewClipboard;
211 public static boolean internalCopy = false;
213 static int fileLoadingCount = 0;
215 class MyDesktopManager implements DesktopManager
218 private DesktopManager delegate;
220 public MyDesktopManager(DesktopManager delegate)
222 this.delegate = delegate;
226 public void activateFrame(JInternalFrame f)
230 delegate.activateFrame(f);
231 } catch (NullPointerException npe)
233 Point p = getMousePosition();
234 instance.showPasteMenu(p.x, p.y);
239 public void beginDraggingFrame(JComponent f)
241 delegate.beginDraggingFrame(f);
245 public void beginResizingFrame(JComponent f, int direction)
247 delegate.beginResizingFrame(f, direction);
251 public void closeFrame(JInternalFrame f)
253 delegate.closeFrame(f);
257 public void deactivateFrame(JInternalFrame f)
259 delegate.deactivateFrame(f);
263 public void deiconifyFrame(JInternalFrame f)
265 delegate.deiconifyFrame(f);
269 public void dragFrame(JComponent f, int newX, int newY)
275 delegate.dragFrame(f, newX, newY);
279 public void endDraggingFrame(JComponent f)
281 delegate.endDraggingFrame(f);
286 public void endResizingFrame(JComponent f)
288 delegate.endResizingFrame(f);
293 public void iconifyFrame(JInternalFrame f)
295 delegate.iconifyFrame(f);
299 public void maximizeFrame(JInternalFrame f)
301 delegate.maximizeFrame(f);
305 public void minimizeFrame(JInternalFrame f)
307 delegate.minimizeFrame(f);
311 public void openFrame(JInternalFrame f)
313 delegate.openFrame(f);
317 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
324 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
328 public void setBoundsForFrame(JComponent f, int newX, int newY,
329 int newWidth, int newHeight)
331 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
334 // All other methods, simply delegate
339 * Creates a new Desktop object.
344 * A note to implementors. It is ESSENTIAL that any activities that might
345 * block are spawned off as threads rather than waited for during this
349 doVamsasClientCheck();
351 doConfigureStructurePrefs();
352 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
354 if (!Platform.isAMac())
356 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
360 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
366 APQHandlers.setAPQHandlers(this);
367 } catch (Exception e)
369 System.out.println("Cannot set APQHandlers");
370 // e.printStackTrace();
371 } catch (Throwable t)
373 System.out.println("Cannot set APQHandlers");
374 // t.printStackTrace();
378 addWindowListener(new WindowAdapter()
382 public void windowClosing(WindowEvent ev)
388 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
391 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
393 desktop = new MyDesktopPane(selmemusage);
394 showMemusage.setSelected(selmemusage);
395 desktop.setBackground(Color.white);
397 getContentPane().setLayout(new BorderLayout());
398 // alternate config - have scrollbars - see notes in JAL-153
399 // JScrollPane sp = new JScrollPane();
400 // sp.getViewport().setView(desktop);
401 // getContentPane().add(sp, BorderLayout.CENTER);
402 getContentPane().add(desktop, BorderLayout.CENTER);
403 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
405 // This line prevents Windows Look&Feel resizing all new windows to maximum
406 // if previous window was maximised
407 desktop.setDesktopManager(new MyDesktopManager(
408 (Platform.isWindows() ? new DefaultDesktopManager()
410 ? new AquaInternalFrameManager(
411 desktop.getDesktopManager())
412 : desktop.getDesktopManager())));
414 Rectangle dims = getLastKnownDimensions("");
421 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
422 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
425 jconsole = new Console(this, showjconsole);
426 // add essential build information
427 jconsole.setHeader(jalview.bin.Cache.getVersionDetailsForConsole());
429 showConsole(showjconsole);
431 showNews.setVisible(false);
433 experimentalFeatures.setSelected(showExperimental());
435 getIdentifiersOrgData();
439 this.addWindowListener(new WindowAdapter()
442 public void windowClosing(WindowEvent evt)
449 this.addMouseListener(ma = new MouseAdapter()
452 public void mousePressed(MouseEvent evt)
454 if (evt.isPopupTrigger()) // Mac
456 showPasteMenu(evt.getX(), evt.getY());
461 public void mouseReleased(MouseEvent evt)
463 if (evt.isPopupTrigger()) // Windows
465 showPasteMenu(evt.getX(), evt.getY());
469 desktop.addMouseListener(ma);
471 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
472 // Spawn a thread that shows the splashscreen
473 SwingUtilities.invokeLater(new Runnable()
482 // Thread off a new instance of the file chooser - this reduces the time it
483 // takes to open it later on.
484 new Thread(new Runnable()
489 Cache.log.debug("Filechooser init thread started.");
490 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
491 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
493 Cache.log.debug("Filechooser init thread finished.");
496 // Add the service change listener
497 changeSupport.addJalviewPropertyChangeListener("services",
498 new PropertyChangeListener()
502 public void propertyChange(PropertyChangeEvent evt)
504 Cache.log.debug("Firing service changed event for "
505 + evt.getNewValue());
506 JalviewServicesChanged(evt);
513 * Answers true if user preferences to enable experimental features is True
518 public boolean showExperimental()
520 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
521 Boolean.FALSE.toString());
522 return Boolean.valueOf(experimental).booleanValue();
525 public void doConfigureStructurePrefs()
527 // configure services
528 StructureSelectionManager ssm = StructureSelectionManager
529 .getStructureSelectionManager(this);
530 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
532 ssm.setAddTempFacAnnot(jalview.bin.Cache
533 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
534 ssm.setProcessSecondaryStructure(jalview.bin.Cache
535 .getDefault(Preferences.STRUCT_FROM_PDB, true));
536 ssm.setSecStructServices(
537 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
541 ssm.setAddTempFacAnnot(false);
542 ssm.setProcessSecondaryStructure(false);
543 ssm.setSecStructServices(false);
547 public void checkForNews()
549 final Desktop me = this;
550 // Thread off the news reader, in case there are connection problems.
551 new Thread(new Runnable()
556 Cache.log.debug("Starting news thread.");
558 jvnews = new BlogReader(me);
559 showNews.setVisible(true);
560 Cache.log.debug("Completed news thread.");
565 public void getIdentifiersOrgData()
567 // Thread off the identifiers fetcher
568 new Thread(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"
590 protected void showNews_actionPerformed(ActionEvent e)
592 showNews(showNews.isSelected());
595 void showNews(boolean visible)
598 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
599 showNews.setSelected(visible);
600 if (visible && !jvnews.isVisible())
602 new Thread(new Runnable()
607 long now = System.currentTimeMillis();
608 Desktop.instance.setProgressBar(
609 MessageManager.getString("status.refreshing_news"),
611 jvnews.refreshNews();
612 Desktop.instance.setProgressBar(null, now);
621 * recover the last known dimensions for a jalview window
624 * - empty string is desktop, all other windows have unique prefix
625 * @return null or last known dimensions scaled to current geometry (if last
626 * window geom was known)
628 Rectangle getLastKnownDimensions(String windowName)
630 // TODO: lock aspect ratio for scaling desktop Bug #0058199
631 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
632 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
633 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
634 String width = jalview.bin.Cache
635 .getProperty(windowName + "SCREEN_WIDTH");
636 String height = jalview.bin.Cache
637 .getProperty(windowName + "SCREEN_HEIGHT");
638 if ((x != null) && (y != null) && (width != null) && (height != null))
640 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
641 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
642 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
644 // attempt #1 - try to cope with change in screen geometry - this
645 // version doesn't preserve original jv aspect ratio.
646 // take ratio of current screen size vs original screen size.
647 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
648 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
649 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
650 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
651 // rescale the bounds depending upon the current screen geometry.
652 ix = (int) (ix * sw);
653 iw = (int) (iw * sw);
654 iy = (int) (iy * sh);
655 ih = (int) (ih * sh);
656 while (ix >= screenSize.width)
658 jalview.bin.Cache.log.debug(
659 "Window geometry location recall error: shifting horizontal to within screenbounds.");
660 ix -= screenSize.width;
662 while (iy >= screenSize.height)
664 jalview.bin.Cache.log.debug(
665 "Window geometry location recall error: shifting vertical to within screenbounds.");
666 iy -= screenSize.height;
668 jalview.bin.Cache.log.debug(
669 "Got last known dimensions for " + windowName + ": x:" + ix
670 + " y:" + iy + " width:" + iw + " height:" + ih);
672 // return dimensions for new instance
673 return new Rectangle(ix, iy, iw, ih);
678 private void doVamsasClientCheck()
680 if (jalview.bin.Cache.vamsasJarsPresent())
682 setupVamsasDisconnectedGui();
683 VamsasMenu.setVisible(true);
684 final Desktop us = this;
685 VamsasMenu.addMenuListener(new MenuListener()
687 // this listener remembers when the menu was first selected, and
688 // doesn't rebuild the session list until it has been cleared and
690 boolean refresh = true;
693 public void menuCanceled(MenuEvent e)
699 public void menuDeselected(MenuEvent e)
705 public void menuSelected(MenuEvent e)
709 us.buildVamsasStMenu();
714 vamsasStart.setVisible(true);
718 void showPasteMenu(int x, int y)
720 JPopupMenu popup = new JPopupMenu();
721 JMenuItem item = new JMenuItem(
722 MessageManager.getString("label.paste_new_window"));
723 item.addActionListener(new ActionListener()
726 public void actionPerformed(ActionEvent evt)
733 popup.show(this, x, y);
740 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
741 Transferable contents = c.getContents(this);
743 if (contents != null)
745 String file = (String) contents
746 .getTransferData(DataFlavor.stringFlavor);
748 FileFormatI format = new IdentifyFile().identify(file,
749 DataSourceType.PASTE);
751 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
754 } catch (Exception ex)
757 "Unable to paste alignment from system clipboard:\n" + ex);
762 * Adds and opens the given frame to the desktop
773 public static synchronized void addInternalFrame(
774 final JInternalFrame frame, String title, int w, int h)
776 addInternalFrame(frame, title, true, w, h, true, false);
780 * Add an internal frame to the Jalview desktop
787 * When true, display frame immediately, otherwise, caller must call
788 * setVisible themselves.
794 public static synchronized void addInternalFrame(
795 final JInternalFrame frame, String title, boolean makeVisible,
798 addInternalFrame(frame, title, makeVisible, w, h, true, false);
802 * Add an internal frame to the Jalview desktop and make it visible
815 public static synchronized void addInternalFrame(
816 final JInternalFrame frame, String title, int w, int h,
819 addInternalFrame(frame, title, true, w, h, resizable, false);
823 * Add an internal frame to the Jalview desktop
830 * When true, display frame immediately, otherwise, caller must call
831 * setVisible themselves.
838 * @param ignoreMinSize
839 * Do not set the default minimum size for frame
841 public static synchronized void addInternalFrame(
842 final JInternalFrame frame, String title, boolean makeVisible,
843 int w, int h, boolean resizable, boolean ignoreMinSize)
846 // TODO: allow callers to determine X and Y position of frame (eg. via
848 // TODO: consider fixing method to update entries in the window submenu with
849 // the current window title
851 frame.setTitle(title);
852 if (frame.getWidth() < 1 || frame.getHeight() < 1)
856 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
857 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
858 // IF JALVIEW IS RUNNING HEADLESS
859 // ///////////////////////////////////////////////
860 if (instance == null || (System.getProperty("java.awt.headless") != null
861 && System.getProperty("java.awt.headless").equals("true")))
870 frame.setMinimumSize(
871 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
873 // Set default dimension for Alignment Frame window.
874 // The Alignment Frame window could be added from a number of places,
876 // I did this here in order not to miss out on any Alignment frame.
877 if (frame instanceof AlignFrame)
879 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
880 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
884 frame.setVisible(makeVisible);
885 frame.setClosable(true);
886 frame.setResizable(resizable);
887 frame.setMaximizable(resizable);
888 frame.setIconifiable(resizable);
889 frame.setOpaque(false);
891 if (frame.getX() < 1 && frame.getY() < 1)
893 frame.setLocation(xOffset * openFrameCount,
894 yOffset * ((openFrameCount - 1) % 10) + yOffset);
898 * add an entry for the new frame in the Window menu
899 * (and remove it when the frame is closed)
901 final JMenuItem menuItem = new JMenuItem(title);
902 frame.addInternalFrameListener(new InternalFrameAdapter()
905 public void internalFrameActivated(InternalFrameEvent evt)
907 JInternalFrame itf = desktop.getSelectedFrame();
910 if (itf instanceof AlignFrame)
912 Jalview.setCurrentAlignFrame((AlignFrame) itf);
919 public void internalFrameClosed(InternalFrameEvent evt)
921 PaintRefresher.RemoveComponent(frame);
924 * defensive check to prevent frames being
925 * added half off the window
927 if (openFrameCount > 0)
933 * ensure no reference to alignFrame retained by menu item listener
935 if (menuItem.getActionListeners().length > 0)
937 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
939 windowMenu.remove(menuItem);
943 menuItem.addActionListener(new ActionListener()
946 public void actionPerformed(ActionEvent e)
950 frame.setSelected(true);
951 frame.setIcon(false);
952 } catch (java.beans.PropertyVetoException ex)
959 setKeyBindings(frame);
963 windowMenu.add(menuItem);
968 frame.setSelected(true);
969 frame.requestFocus();
970 } catch (java.beans.PropertyVetoException ve)
972 } catch (java.lang.ClassCastException cex)
975 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
981 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
986 private static void setKeyBindings(JInternalFrame frame)
988 @SuppressWarnings("serial")
989 final Action closeAction = new AbstractAction()
992 public void actionPerformed(ActionEvent e)
999 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1001 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1002 InputEvent.CTRL_DOWN_MASK);
1003 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1004 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
1006 InputMap inputMap = frame
1007 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1008 String ctrlW = ctrlWKey.toString();
1009 inputMap.put(ctrlWKey, ctrlW);
1010 inputMap.put(cmdWKey, ctrlW);
1012 ActionMap actionMap = frame.getActionMap();
1013 actionMap.put(ctrlW, closeAction);
1017 public void lostOwnership(Clipboard clipboard, Transferable contents)
1021 Desktop.jalviewClipboard = null;
1024 internalCopy = false;
1028 public void dragEnter(DropTargetDragEvent evt)
1033 public void dragExit(DropTargetEvent evt)
1038 public void dragOver(DropTargetDragEvent evt)
1043 public void dropActionChanged(DropTargetDragEvent evt)
1054 public void drop(DropTargetDropEvent evt)
1056 boolean success = true;
1057 // JAL-1552 - acceptDrop required before getTransferable call for
1058 // Java's Transferable for native dnd
1059 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1060 Transferable t = evt.getTransferable();
1061 List<String> files = new ArrayList<>();
1062 List<DataSourceType> protocols = new ArrayList<>();
1066 Desktop.transferFromDropTarget(files, protocols, evt, t);
1067 } catch (Exception e)
1069 e.printStackTrace();
1077 for (int i = 0; i < files.size(); i++)
1079 String file = files.get(i).toString();
1080 DataSourceType protocol = (protocols == null)
1081 ? DataSourceType.FILE
1083 FileFormatI format = null;
1085 if (file.endsWith(".jar"))
1087 format = FileFormat.Jalview;
1092 format = new IdentifyFile().identify(file, protocol);
1095 new FileLoader().LoadFile(file, protocol, format);
1098 } catch (Exception ex)
1103 evt.dropComplete(success); // need this to ensure input focus is properly
1104 // transfered to any new windows created
1114 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1116 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1117 JalviewFileChooser chooser = JalviewFileChooser
1118 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
1120 chooser.setFileView(new JalviewFileView());
1121 chooser.setDialogTitle(
1122 MessageManager.getString("label.open_local_file"));
1123 chooser.setToolTipText(MessageManager.getString("action.open"));
1125 int value = chooser.showOpenDialog(this);
1127 if (value == JalviewFileChooser.APPROVE_OPTION)
1129 String choice = chooser.getSelectedFile().getPath();
1130 Cache.setProperty("LAST_DIRECTORY",
1131 chooser.getSelectedFile().getParent());
1133 FileFormatI format = chooser.getSelectedFormat();
1136 * Call IdentifyFile to verify the file contains what its extension implies.
1137 * Skip this step for dynamically added file formats, because
1138 * IdentifyFile does not know how to recognise them.
1140 if (FileFormats.getInstance().isIdentifiable(format))
1144 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1145 } catch (FileFormatException e)
1147 // format = null; //??
1151 if (viewport != null)
1153 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1158 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1170 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1172 // This construct allows us to have a wider textfield
1174 JLabel label = new JLabel(
1175 MessageManager.getString("label.input_file_url"));
1176 final JComboBox history = new JComboBox();
1178 JPanel panel = new JPanel(new GridLayout(2, 1));
1181 history.setPreferredSize(new Dimension(400, 20));
1182 history.setEditable(true);
1183 history.addItem("http://www.");
1185 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1189 if (historyItems != null)
1191 st = new StringTokenizer(historyItems, "\t");
1193 while (st.hasMoreTokens())
1195 history.addItem(st.nextElement());
1199 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1200 MessageManager.getString("label.input_alignment_from_url"),
1201 JvOptionPane.OK_CANCEL_OPTION);
1203 if (reply != JvOptionPane.OK_OPTION)
1208 String url = history.getSelectedItem().toString();
1210 if (url.toLowerCase().endsWith(".jar"))
1212 if (viewport != null)
1214 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1215 FileFormat.Jalview);
1219 new FileLoader().LoadFile(url, DataSourceType.URL,
1220 FileFormat.Jalview);
1225 FileFormatI format = null;
1228 format = new IdentifyFile().identify(url, DataSourceType.URL);
1229 } catch (FileFormatException e)
1231 // TODO revise error handling, distinguish between
1232 // URL not found and response not valid
1237 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1238 MessageManager.formatMessage("label.couldnt_locate",
1241 MessageManager.getString("label.url_not_found"),
1242 JvOptionPane.WARNING_MESSAGE);
1247 if (viewport != null)
1249 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1254 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1260 * Opens the CutAndPaste window for the user to paste an alignment in to
1263 * - if not null, the pasted alignment is added to the current
1264 * alignment; if null, to a new alignment window
1267 public void inputTextboxMenuItem_actionPerformed(
1268 AlignmentViewPanel viewPanel)
1270 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1271 cap.setForInput(viewPanel);
1272 Desktop.addInternalFrame(cap,
1273 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1283 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1284 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1286 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1287 screen.height + "");
1288 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1289 getWidth(), getHeight()));
1291 if (jconsole != null)
1293 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1294 jconsole.stopConsole();
1298 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1301 if (dialogExecutor != null)
1303 dialogExecutor.shutdownNow();
1305 closeAll_actionPerformed(null);
1307 if (groovyConsole != null)
1309 // suppress a possible repeat prompt to save script
1310 groovyConsole.setDirty(false);
1311 groovyConsole.exit();
1316 private void storeLastKnownDimensions(String string, Rectangle jc)
1318 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1319 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1320 + " height:" + jc.height);
1322 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1323 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1324 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1325 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1335 public void aboutMenuItem_actionPerformed(ActionEvent e)
1337 // StringBuffer message = getAboutMessage(false);
1338 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1340 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1341 new Thread(new Runnable()
1346 new SplashScreen(true);
1351 public StringBuffer getAboutMessage(boolean shortv)
1353 StringBuffer message = new StringBuffer();
1354 message.append("<html>");
1357 message.append("<h1><strong>Version: "
1358 + jalview.bin.Cache.getProperty("VERSION")
1359 + "</strong></h1>");
1360 message.append("<strong>Built: <em>"
1361 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1362 + "</em> from " + jalview.bin.Cache.getBuildDetailsForSplash()
1369 message.append("<strong>Version "
1370 + jalview.bin.Cache.getProperty("VERSION")
1371 + "; last updated: "
1372 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1375 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1376 .equals("Checking"))
1378 // JBP removed this message for 2.11: May be reinstated in future version
1379 // message.append("<br>...Checking latest version...</br>");
1381 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1382 .equals(jalview.bin.Cache.getProperty("VERSION")))
1384 boolean red = false;
1385 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1386 .indexOf("automated build") == -1)
1389 // Displayed when code version and jnlp version do not match and code
1390 // version is not a development build
1391 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1394 message.append("<br>!! Version "
1395 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1397 + " is available for download from "
1398 + jalview.bin.Cache.getDefault("www.jalview.org",
1399 "http://www.jalview.org")
1403 message.append("</div>");
1406 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1408 "The Jalview Authors (See AUTHORS file for current list)")
1409 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1410 + "<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"
1411 + "<br><br>If you use Jalview, please cite:"
1412 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1413 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1414 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1426 public void documentationMenuItem_actionPerformed(ActionEvent e)
1430 Help.showHelpWindow();
1431 } catch (Exception ex)
1437 public void closeAll_actionPerformed(ActionEvent e)
1439 // TODO show a progress bar while closing?
1440 JInternalFrame[] frames = desktop.getAllFrames();
1441 for (int i = 0; i < frames.length; i++)
1445 frames[i].setClosed(true);
1446 } catch (java.beans.PropertyVetoException ex)
1450 Jalview.setCurrentAlignFrame(null);
1451 System.out.println("ALL CLOSED");
1452 if (v_client != null)
1454 // TODO clear binding to vamsas document objects on close_all
1458 * reset state of singleton objects as appropriate (clear down session state
1459 * when all windows are closed)
1461 StructureSelectionManager ssm = StructureSelectionManager
1462 .getStructureSelectionManager(this);
1470 public void raiseRelated_actionPerformed(ActionEvent e)
1472 reorderAssociatedWindows(false, false);
1476 public void minimizeAssociated_actionPerformed(ActionEvent e)
1478 reorderAssociatedWindows(true, false);
1481 void closeAssociatedWindows()
1483 reorderAssociatedWindows(false, true);
1489 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1493 protected void garbageCollect_actionPerformed(ActionEvent e)
1495 // We simply collect the garbage
1496 jalview.bin.Cache.log.debug("Collecting garbage...");
1498 jalview.bin.Cache.log.debug("Finished garbage collection.");
1505 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1509 protected void showMemusage_actionPerformed(ActionEvent e)
1511 desktop.showMemoryUsage(showMemusage.isSelected());
1518 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1522 protected void showConsole_actionPerformed(ActionEvent e)
1524 showConsole(showConsole.isSelected());
1527 Console jconsole = null;
1530 * control whether the java console is visible or not
1534 void showConsole(boolean selected)
1536 showConsole.setSelected(selected);
1537 // TODO: decide if we should update properties file
1538 Cache.setProperty("SHOW_JAVA_CONSOLE",
1539 Boolean.valueOf(selected).toString());
1540 jconsole.setVisible(selected);
1543 void reorderAssociatedWindows(boolean minimize, boolean close)
1545 JInternalFrame[] frames = desktop.getAllFrames();
1546 if (frames == null || frames.length < 1)
1551 AlignmentViewport source = null, target = null;
1552 if (frames[0] instanceof AlignFrame)
1554 source = ((AlignFrame) frames[0]).getCurrentView();
1556 else if (frames[0] instanceof TreePanel)
1558 source = ((TreePanel) frames[0]).getViewPort();
1560 else if (frames[0] instanceof PCAPanel)
1562 source = ((PCAPanel) frames[0]).av;
1564 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1566 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1571 for (int i = 0; i < frames.length; i++)
1574 if (frames[i] == null)
1578 if (frames[i] instanceof AlignFrame)
1580 target = ((AlignFrame) frames[i]).getCurrentView();
1582 else if (frames[i] instanceof TreePanel)
1584 target = ((TreePanel) frames[i]).getViewPort();
1586 else if (frames[i] instanceof PCAPanel)
1588 target = ((PCAPanel) frames[i]).av;
1590 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1592 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1595 if (source == target)
1601 frames[i].setClosed(true);
1605 frames[i].setIcon(minimize);
1608 frames[i].toFront();
1612 } catch (java.beans.PropertyVetoException ex)
1627 protected void preferences_actionPerformed(ActionEvent e)
1633 * Shows a file chooser dialog and writes out the current session as a Jalview
1637 public void saveState_actionPerformed()
1639 saveState_actionPerformed(false);
1642 public void saveState_actionPerformed(boolean saveAs)
1644 java.io.File projectFile = getProjectFile();
1645 // autoSave indicates we already have a file and don't need to ask
1646 boolean autoSave = projectFile != null && !saveAs
1647 && BackupFiles.getEnabled();
1649 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1650 // saveAs="+saveAs+", Backups
1651 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1653 boolean approveSave = false;
1656 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1659 chooser.setFileView(new JalviewFileView());
1660 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1662 int value = chooser.showSaveDialog(this);
1664 if (value == JalviewFileChooser.APPROVE_OPTION)
1666 projectFile = chooser.getSelectedFile();
1667 setProjectFile(projectFile);
1672 if (approveSave || autoSave)
1674 final Desktop me = this;
1675 final java.io.File chosenFile = projectFile;
1676 new Thread(new Runnable()
1681 // TODO: refactor to Jalview desktop session controller action.
1682 setProgressBar(MessageManager.formatMessage(
1683 "label.saving_jalview_project", new Object[]
1684 { chosenFile.getName() }), chosenFile.hashCode());
1685 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1686 chosenFile.getParent());
1687 // TODO catch and handle errors for savestate
1688 // TODO prevent user from messing with the Desktop whilst we're saving
1691 BackupFiles backupfiles = new BackupFiles(chosenFile);
1693 new Jalview2XML().saveState(backupfiles.getTempFile());
1695 backupfiles.setWriteSuccess(true);
1696 backupfiles.rollBackupsAndRenameTempFile();
1697 } catch (OutOfMemoryError oom)
1699 new OOMWarning("Whilst saving current state to "
1700 + chosenFile.getName(), oom);
1701 } catch (Exception ex)
1703 Cache.log.error("Problems whilst trying to save to "
1704 + chosenFile.getName(), ex);
1705 JvOptionPane.showMessageDialog(me,
1706 MessageManager.formatMessage(
1707 "label.error_whilst_saving_current_state_to",
1709 { chosenFile.getName() }),
1710 MessageManager.getString("label.couldnt_save_project"),
1711 JvOptionPane.WARNING_MESSAGE);
1713 setProgressBar(null, chosenFile.hashCode());
1720 public void saveAsState_actionPerformed(ActionEvent e)
1722 saveState_actionPerformed(true);
1725 private void setProjectFile(File choice)
1727 this.projectFile = choice;
1730 public File getProjectFile()
1732 return this.projectFile;
1736 * Shows a file chooser dialog and tries to read in the selected file as a
1740 public void loadState_actionPerformed()
1742 final String[] suffix = new String[] { "jvp", "jar" };
1743 final String[] desc = new String[] { "Jalview Project",
1744 "Jalview Project (old)" };
1745 JalviewFileChooser chooser = new JalviewFileChooser(
1746 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1747 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1749 chooser.setFileView(new JalviewFileView());
1750 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1752 int value = chooser.showOpenDialog(this);
1754 if (value == JalviewFileChooser.APPROVE_OPTION)
1756 final File selectedFile = chooser.getSelectedFile();
1757 setProjectFile(selectedFile);
1758 final String choice = selectedFile.getAbsolutePath();
1759 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1760 new Thread(new Runnable()
1765 setProgressBar(MessageManager.formatMessage(
1766 "label.loading_jalview_project", new Object[]
1767 { choice }), choice.hashCode());
1770 new Jalview2XML().loadJalviewAlign(choice);
1771 } catch (OutOfMemoryError oom)
1773 new OOMWarning("Whilst loading project from " + choice, oom);
1774 } catch (Exception ex)
1777 "Problems whilst loading project from " + choice, ex);
1778 JvOptionPane.showMessageDialog(Desktop.desktop,
1779 MessageManager.formatMessage(
1780 "label.error_whilst_loading_project_from",
1783 MessageManager.getString("label.couldnt_load_project"),
1784 JvOptionPane.WARNING_MESSAGE);
1786 setProgressBar(null, choice.hashCode());
1793 public void inputSequence_actionPerformed(ActionEvent e)
1795 new SequenceFetcher(this);
1798 JPanel progressPanel;
1800 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1802 public void startLoading(final String fileName)
1804 if (fileLoadingCount == 0)
1806 fileLoadingPanels.add(addProgressPanel(MessageManager
1807 .formatMessage("label.loading_file", new Object[]
1813 private JPanel addProgressPanel(String string)
1815 if (progressPanel == null)
1817 progressPanel = new JPanel(new GridLayout(1, 1));
1818 totalProgressCount = 0;
1819 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1821 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1822 JProgressBar progressBar = new JProgressBar();
1823 progressBar.setIndeterminate(true);
1825 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1827 thisprogress.add(progressBar, BorderLayout.CENTER);
1828 progressPanel.add(thisprogress);
1829 ((GridLayout) progressPanel.getLayout()).setRows(
1830 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1831 ++totalProgressCount;
1832 instance.validate();
1833 return thisprogress;
1836 int totalProgressCount = 0;
1838 private void removeProgressPanel(JPanel progbar)
1840 if (progressPanel != null)
1842 synchronized (progressPanel)
1844 progressPanel.remove(progbar);
1845 GridLayout gl = (GridLayout) progressPanel.getLayout();
1846 gl.setRows(gl.getRows() - 1);
1847 if (--totalProgressCount < 1)
1849 this.getContentPane().remove(progressPanel);
1850 progressPanel = null;
1857 public void stopLoading()
1860 if (fileLoadingCount < 1)
1862 while (fileLoadingPanels.size() > 0)
1864 removeProgressPanel(fileLoadingPanels.remove(0));
1866 fileLoadingPanels.clear();
1867 fileLoadingCount = 0;
1872 public static int getViewCount(String alignmentId)
1874 AlignmentViewport[] aps = getViewports(alignmentId);
1875 return (aps == null) ? 0 : aps.length;
1880 * @param alignmentId
1881 * - if null, all sets are returned
1882 * @return all AlignmentPanels concerning the alignmentId sequence set
1884 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1886 if (Desktop.desktop == null)
1888 // no frames created and in headless mode
1889 // TODO: verify that frames are recoverable when in headless mode
1892 List<AlignmentPanel> aps = new ArrayList<>();
1893 AlignFrame[] frames = getAlignFrames();
1898 for (AlignFrame af : frames)
1900 for (AlignmentPanel ap : af.alignPanels)
1902 if (alignmentId == null
1903 || alignmentId.equals(ap.av.getSequenceSetId()))
1909 if (aps.size() == 0)
1913 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1918 * get all the viewports on an alignment.
1920 * @param sequenceSetId
1921 * unique alignment id (may be null - all viewports returned in that
1923 * @return all viewports on the alignment bound to sequenceSetId
1925 public static AlignmentViewport[] getViewports(String sequenceSetId)
1927 List<AlignmentViewport> viewp = new ArrayList<>();
1928 if (desktop != null)
1930 AlignFrame[] frames = Desktop.getAlignFrames();
1932 for (AlignFrame afr : frames)
1934 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1935 .equals(sequenceSetId))
1937 if (afr.alignPanels != null)
1939 for (AlignmentPanel ap : afr.alignPanels)
1941 if (sequenceSetId == null
1942 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1950 viewp.add(afr.getViewport());
1954 if (viewp.size() > 0)
1956 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1963 * Explode the views in the given frame into separate AlignFrame
1967 public static void explodeViews(AlignFrame af)
1969 int size = af.alignPanels.size();
1975 for (int i = 0; i < size; i++)
1977 AlignmentPanel ap = af.alignPanels.get(i);
1978 AlignFrame newaf = new AlignFrame(ap);
1981 * Restore the view's last exploded frame geometry if known. Multiple
1982 * views from one exploded frame share and restore the same (frame)
1983 * position and size.
1985 Rectangle geometry = ap.av.getExplodedGeometry();
1986 if (geometry != null)
1988 newaf.setBounds(geometry);
1991 ap.av.setGatherViewsHere(false);
1993 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1994 AlignFrame.DEFAULT_HEIGHT);
1997 af.alignPanels.clear();
1998 af.closeMenuItem_actionPerformed(true);
2003 * Gather expanded views (separate AlignFrame's) with the same sequence set
2004 * identifier back in to this frame as additional views, and close the
2005 * expanded views. Note the expanded frames may themselves have multiple
2006 * views. We take the lot.
2010 public void gatherViews(AlignFrame source)
2012 source.viewport.setGatherViewsHere(true);
2013 source.viewport.setExplodedGeometry(source.getBounds());
2014 JInternalFrame[] frames = desktop.getAllFrames();
2015 String viewId = source.viewport.getSequenceSetId();
2017 for (int t = 0; t < frames.length; t++)
2019 if (frames[t] instanceof AlignFrame && frames[t] != source)
2021 AlignFrame af = (AlignFrame) frames[t];
2022 boolean gatherThis = false;
2023 for (int a = 0; a < af.alignPanels.size(); a++)
2025 AlignmentPanel ap = af.alignPanels.get(a);
2026 if (viewId.equals(ap.av.getSequenceSetId()))
2029 ap.av.setGatherViewsHere(false);
2030 ap.av.setExplodedGeometry(af.getBounds());
2031 source.addAlignmentPanel(ap, false);
2037 af.alignPanels.clear();
2038 af.closeMenuItem_actionPerformed(true);
2045 jalview.gui.VamsasApplication v_client = null;
2048 public void vamsasImport_actionPerformed(ActionEvent e)
2050 if (v_client == null)
2052 // Load and try to start a session.
2053 JalviewFileChooser chooser = new JalviewFileChooser(
2054 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2056 chooser.setFileView(new JalviewFileView());
2057 chooser.setDialogTitle(
2058 MessageManager.getString("label.open_saved_vamsas_session"));
2059 chooser.setToolTipText(MessageManager.getString(
2060 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2062 int value = chooser.showOpenDialog(this);
2064 if (value == JalviewFileChooser.APPROVE_OPTION)
2066 String fle = chooser.getSelectedFile().toString();
2067 if (!vamsasImport(chooser.getSelectedFile()))
2069 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2070 MessageManager.formatMessage(
2071 "label.couldnt_import_as_vamsas_session",
2075 .getString("label.vamsas_document_import_failed"),
2076 JvOptionPane.ERROR_MESSAGE);
2082 jalview.bin.Cache.log.error(
2083 "Implementation error - load session from a running session is not supported.");
2088 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2091 * @return true if import was a success and a session was started.
2093 public boolean vamsasImport(URL url)
2095 // TODO: create progress bar
2096 if (v_client != null)
2099 jalview.bin.Cache.log.error(
2100 "Implementation error - load session from a running session is not supported.");
2106 // copy the URL content to a temporary local file
2107 // TODO: be a bit cleverer here with nio (?!)
2108 File file = File.createTempFile("vdocfromurl", ".vdj");
2109 FileOutputStream fos = new FileOutputStream(file);
2110 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2111 byte[] buffer = new byte[2048];
2113 while ((ln = bis.read(buffer)) > -1)
2115 fos.write(buffer, 0, ln);
2119 v_client = new jalview.gui.VamsasApplication(this, file,
2120 url.toExternalForm());
2121 } catch (Exception ex)
2123 jalview.bin.Cache.log.error(
2124 "Failed to create new vamsas session from contents of URL "
2129 setupVamsasConnectedGui();
2130 v_client.initial_update(); // TODO: thread ?
2131 return v_client.inSession();
2135 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2138 * @return true if import was a success and a session was started.
2140 public boolean vamsasImport(File file)
2142 if (v_client != null)
2145 jalview.bin.Cache.log.error(
2146 "Implementation error - load session from a running session is not supported.");
2150 setProgressBar(MessageManager.formatMessage(
2151 "status.importing_vamsas_session_from", new Object[]
2152 { file.getName() }), file.hashCode());
2155 v_client = new jalview.gui.VamsasApplication(this, file, null);
2156 } catch (Exception ex)
2158 setProgressBar(MessageManager.formatMessage(
2159 "status.importing_vamsas_session_from", new Object[]
2160 { file.getName() }), file.hashCode());
2161 jalview.bin.Cache.log.error(
2162 "New vamsas session from existing session file failed:", ex);
2165 setupVamsasConnectedGui();
2166 v_client.initial_update(); // TODO: thread ?
2167 setProgressBar(MessageManager.formatMessage(
2168 "status.importing_vamsas_session_from", new Object[]
2169 { file.getName() }), file.hashCode());
2170 return v_client.inSession();
2173 public boolean joinVamsasSession(String mysesid)
2175 if (v_client != null)
2177 throw new Error(MessageManager
2178 .getString("error.try_join_vamsas_session_another"));
2180 if (mysesid == null)
2183 MessageManager.getString("error.invalid_vamsas_session_id"));
2185 v_client = new VamsasApplication(this, mysesid);
2186 setupVamsasConnectedGui();
2187 v_client.initial_update();
2188 return (v_client.inSession());
2192 public void vamsasStart_actionPerformed(ActionEvent e)
2194 if (v_client == null)
2197 // we just start a default session for moment.
2199 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2200 * getProperty("LAST_DIRECTORY"));
2202 * chooser.setFileView(new JalviewFileView());
2203 * chooser.setDialogTitle("Load Vamsas file");
2204 * chooser.setToolTipText("Import");
2206 * int value = chooser.showOpenDialog(this);
2208 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2209 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2211 v_client = new VamsasApplication(this);
2212 setupVamsasConnectedGui();
2213 v_client.initial_update(); // TODO: thread ?
2217 // store current data in session.
2218 v_client.push_update(); // TODO: thread
2222 protected void setupVamsasConnectedGui()
2224 vamsasStart.setText(MessageManager.getString("label.session_update"));
2225 vamsasSave.setVisible(true);
2226 vamsasStop.setVisible(true);
2227 vamsasImport.setVisible(false); // Document import to existing session is
2228 // not possible for vamsas-client-1.0.
2231 protected void setupVamsasDisconnectedGui()
2233 vamsasSave.setVisible(false);
2234 vamsasStop.setVisible(false);
2235 vamsasImport.setVisible(true);
2237 .setText(MessageManager.getString("label.new_vamsas_session"));
2241 public void vamsasStop_actionPerformed(ActionEvent e)
2243 if (v_client != null)
2245 v_client.end_session();
2247 setupVamsasDisconnectedGui();
2251 protected void buildVamsasStMenu()
2253 if (v_client == null)
2255 String[] sess = null;
2258 sess = VamsasApplication.getSessionList();
2259 } catch (Exception e)
2261 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2267 jalview.bin.Cache.log.debug(
2268 "Got current sessions list: " + sess.length + " entries.");
2269 VamsasStMenu.removeAll();
2270 for (int i = 0; i < sess.length; i++)
2272 JMenuItem sessit = new JMenuItem();
2273 sessit.setText(sess[i]);
2274 sessit.setToolTipText(MessageManager
2275 .formatMessage("label.connect_to_session", new Object[]
2277 final Desktop dsktp = this;
2278 final String mysesid = sess[i];
2279 sessit.addActionListener(new ActionListener()
2283 public void actionPerformed(ActionEvent e)
2285 if (dsktp.v_client == null)
2287 Thread rthr = new Thread(new Runnable()
2293 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2294 dsktp.setupVamsasConnectedGui();
2295 dsktp.v_client.initial_update();
2303 VamsasStMenu.add(sessit);
2305 // don't show an empty menu.
2306 VamsasStMenu.setVisible(sess.length > 0);
2311 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2312 VamsasStMenu.removeAll();
2313 VamsasStMenu.setVisible(false);
2318 // Not interested in the content. Just hide ourselves.
2319 VamsasStMenu.setVisible(false);
2324 public void vamsasSave_actionPerformed(ActionEvent e)
2326 if (v_client != null)
2328 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2329 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2332 chooser.setFileView(new JalviewFileView());
2333 chooser.setDialogTitle(MessageManager
2334 .getString("label.save_vamsas_document_archive"));
2336 int value = chooser.showSaveDialog(this);
2338 if (value == JalviewFileChooser.APPROVE_OPTION)
2340 java.io.File choice = chooser.getSelectedFile();
2341 JPanel progpanel = addProgressPanel(MessageManager
2342 .formatMessage("label.saving_vamsas_doc", new Object[]
2343 { choice.getName() }));
2344 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2345 String warnmsg = null;
2346 String warnttl = null;
2349 v_client.vclient.storeDocument(choice);
2352 warnttl = "Serious Problem saving Vamsas Document";
2353 warnmsg = ex.toString();
2354 jalview.bin.Cache.log
2355 .error("Error Whilst saving document to " + choice, ex);
2357 } catch (Exception ex)
2359 warnttl = "Problem saving Vamsas Document.";
2360 warnmsg = ex.toString();
2361 jalview.bin.Cache.log.warn(
2362 "Exception Whilst saving document to " + choice, ex);
2365 removeProgressPanel(progpanel);
2366 if (warnmsg != null)
2368 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2370 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2376 JPanel vamUpdate = null;
2379 * hide vamsas user gui bits when a vamsas document event is being handled.
2382 * true to hide gui, false to reveal gui
2384 public void setVamsasUpdate(boolean b)
2386 Cache.log.debug("Setting gui for Vamsas update "
2387 + (b ? "in progress" : "finished"));
2389 if (vamUpdate != null)
2391 this.removeProgressPanel(vamUpdate);
2395 vamUpdate = this.addProgressPanel(
2396 MessageManager.getString("label.updating_vamsas_session"));
2398 vamsasStart.setVisible(!b);
2399 vamsasStop.setVisible(!b);
2400 vamsasSave.setVisible(!b);
2403 public JInternalFrame[] getAllFrames()
2405 return desktop.getAllFrames();
2409 * Checks the given url to see if it gives a response indicating that the user
2410 * should be informed of a new questionnaire.
2414 public void checkForQuestionnaire(String url)
2416 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2417 // javax.swing.SwingUtilities.invokeLater(jvq);
2418 new Thread(jvq).start();
2421 public void checkURLLinks()
2423 // Thread off the URL link checker
2424 addDialogThread(new Runnable()
2429 if (Cache.getDefault("CHECKURLLINKS", true))
2431 // check what the actual links are - if it's just the default don't
2432 // bother with the warning
2433 List<String> links = Preferences.sequenceUrlLinks
2436 // only need to check links if there is one with a
2437 // SEQUENCE_ID which is not the default EMBL_EBI link
2438 ListIterator<String> li = links.listIterator();
2439 boolean check = false;
2440 List<JLabel> urls = new ArrayList<>();
2441 while (li.hasNext())
2443 String link = li.next();
2444 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2445 && !UrlConstants.isDefaultString(link))
2448 int barPos = link.indexOf("|");
2449 String urlMsg = barPos == -1 ? link
2450 : link.substring(0, barPos) + ": "
2451 + link.substring(barPos + 1);
2452 urls.add(new JLabel(urlMsg));
2460 // ask user to check in case URL links use old style tokens
2461 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2462 JPanel msgPanel = new JPanel();
2463 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2464 msgPanel.add(Box.createVerticalGlue());
2465 JLabel msg = new JLabel(MessageManager
2466 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2467 JLabel msg2 = new JLabel(MessageManager
2468 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2470 for (JLabel url : urls)
2476 final JCheckBox jcb = new JCheckBox(
2477 MessageManager.getString("label.do_not_display_again"));
2478 jcb.addActionListener(new ActionListener()
2481 public void actionPerformed(ActionEvent e)
2483 // update Cache settings for "don't show this again"
2484 boolean showWarningAgain = !jcb.isSelected();
2485 Cache.setProperty("CHECKURLLINKS",
2486 Boolean.valueOf(showWarningAgain).toString());
2491 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2493 .getString("label.SEQUENCE_ID_no_longer_used"),
2494 JvOptionPane.WARNING_MESSAGE);
2501 * Proxy class for JDesktopPane which optionally displays the current memory
2502 * usage and highlights the desktop area with a red bar if free memory runs
2507 public class MyDesktopPane extends JDesktopPane implements Runnable
2510 private static final float ONE_MB = 1048576f;
2512 boolean showMemoryUsage = false;
2516 java.text.NumberFormat df;
2518 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2521 public MyDesktopPane(boolean showMemoryUsage)
2523 showMemoryUsage(showMemoryUsage);
2526 public void showMemoryUsage(boolean showMemory)
2528 this.showMemoryUsage = showMemory;
2531 Thread worker = new Thread(this);
2537 public boolean isShowMemoryUsage()
2539 return showMemoryUsage;
2545 df = java.text.NumberFormat.getNumberInstance();
2546 df.setMaximumFractionDigits(2);
2547 runtime = Runtime.getRuntime();
2549 while (showMemoryUsage)
2553 maxMemory = runtime.maxMemory() / ONE_MB;
2554 allocatedMemory = runtime.totalMemory() / ONE_MB;
2555 freeMemory = runtime.freeMemory() / ONE_MB;
2556 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2558 percentUsage = (totalFreeMemory / maxMemory) * 100;
2560 // if (percentUsage < 20)
2562 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2564 // instance.set.setBorder(border1);
2567 // sleep after showing usage
2569 } catch (Exception ex)
2571 ex.printStackTrace();
2577 public void paintComponent(Graphics g)
2579 if (showMemoryUsage && g != null && df != null)
2581 if (percentUsage < 20)
2583 g.setColor(Color.red);
2585 FontMetrics fm = g.getFontMetrics();
2588 g.drawString(MessageManager.formatMessage("label.memory_stats",
2590 { df.format(totalFreeMemory), df.format(maxMemory),
2591 df.format(percentUsage) }),
2592 10, getHeight() - fm.getHeight());
2599 * Accessor method to quickly get all the AlignmentFrames loaded.
2601 * @return an array of AlignFrame, or null if none found
2603 public static AlignFrame[] getAlignFrames()
2605 if (Jalview.isHeadlessMode())
2607 // Desktop.desktop is null in headless mode
2608 return new AlignFrame[] { Jalview.currentAlignFrame };
2611 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2617 List<AlignFrame> avp = new ArrayList<>();
2619 for (int i = frames.length - 1; i > -1; i--)
2621 if (frames[i] instanceof AlignFrame)
2623 avp.add((AlignFrame) frames[i]);
2625 else if (frames[i] instanceof SplitFrame)
2628 * Also check for a split frame containing an AlignFrame
2630 GSplitFrame sf = (GSplitFrame) frames[i];
2631 if (sf.getTopFrame() instanceof AlignFrame)
2633 avp.add((AlignFrame) sf.getTopFrame());
2635 if (sf.getBottomFrame() instanceof AlignFrame)
2637 avp.add((AlignFrame) sf.getBottomFrame());
2641 if (avp.size() == 0)
2645 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2650 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2654 public GStructureViewer[] getJmols()
2656 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2662 List<GStructureViewer> avp = new ArrayList<>();
2664 for (int i = frames.length - 1; i > -1; i--)
2666 if (frames[i] instanceof AppJmol)
2668 GStructureViewer af = (GStructureViewer) frames[i];
2672 if (avp.size() == 0)
2676 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2681 * Add Groovy Support to Jalview
2684 public void groovyShell_actionPerformed()
2688 openGroovyConsole();
2689 } catch (Exception ex)
2691 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2692 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2694 MessageManager.getString("label.couldnt_create_groovy_shell"),
2695 MessageManager.getString("label.groovy_support_failed"),
2696 JvOptionPane.ERROR_MESSAGE);
2701 * Open the Groovy console
2703 void openGroovyConsole()
2705 if (groovyConsole == null)
2707 groovyConsole = new groovy.ui.Console();
2708 groovyConsole.setVariable("Jalview", this);
2709 groovyConsole.run();
2712 * We allow only one console at a time, so that AlignFrame menu option
2713 * 'Calculate | Run Groovy script' is unambiguous.
2714 * Disable 'Groovy Console', and enable 'Run script', when the console is
2715 * opened, and the reverse when it is closed
2717 Window window = (Window) groovyConsole.getFrame();
2718 window.addWindowListener(new WindowAdapter()
2721 public void windowClosed(WindowEvent e)
2724 * rebind CMD-Q from Groovy Console to Jalview Quit
2727 enableExecuteGroovy(false);
2733 * show Groovy console window (after close and reopen)
2735 ((Window) groovyConsole.getFrame()).setVisible(true);
2738 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2739 * and disable opening a second console
2741 enableExecuteGroovy(true);
2745 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2746 * binding when opened
2748 protected void addQuitHandler()
2750 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2751 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2752 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2754 getRootPane().getActionMap().put("Quit", new AbstractAction()
2757 public void actionPerformed(ActionEvent e)
2765 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2768 * true if Groovy console is open
2770 public void enableExecuteGroovy(boolean enabled)
2773 * disable opening a second Groovy console
2774 * (or re-enable when the console is closed)
2776 groovyShell.setEnabled(!enabled);
2778 AlignFrame[] alignFrames = getAlignFrames();
2779 if (alignFrames != null)
2781 for (AlignFrame af : alignFrames)
2783 af.setGroovyEnabled(enabled);
2789 * Progress bars managed by the IProgressIndicator method.
2791 private Hashtable<Long, JPanel> progressBars;
2793 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2798 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2801 public void setProgressBar(String message, long id)
2803 if (progressBars == null)
2805 progressBars = new Hashtable<>();
2806 progressBarHandlers = new Hashtable<>();
2809 if (progressBars.get(Long.valueOf(id)) != null)
2811 JPanel panel = progressBars.remove(Long.valueOf(id));
2812 if (progressBarHandlers.contains(Long.valueOf(id)))
2814 progressBarHandlers.remove(Long.valueOf(id));
2816 removeProgressPanel(panel);
2820 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2827 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2828 * jalview.gui.IProgressIndicatorHandler)
2831 public void registerHandler(final long id,
2832 final IProgressIndicatorHandler handler)
2834 if (progressBarHandlers == null
2835 || !progressBars.containsKey(Long.valueOf(id)))
2837 throw new Error(MessageManager.getString(
2838 "error.call_setprogressbar_before_registering_handler"));
2840 progressBarHandlers.put(Long.valueOf(id), handler);
2841 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2842 if (handler.canCancel())
2844 JButton cancel = new JButton(
2845 MessageManager.getString("action.cancel"));
2846 final IProgressIndicator us = this;
2847 cancel.addActionListener(new ActionListener()
2851 public void actionPerformed(ActionEvent e)
2853 handler.cancelActivity(id);
2854 us.setProgressBar(MessageManager
2855 .formatMessage("label.cancelled_params", new Object[]
2856 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2860 progressPanel.add(cancel, BorderLayout.EAST);
2866 * @return true if any progress bars are still active
2869 public boolean operationInProgress()
2871 if (progressBars != null && progressBars.size() > 0)
2879 * This will return the first AlignFrame holding the given viewport instance.
2880 * It will break if there are more than one AlignFrames viewing a particular
2884 * @return alignFrame for viewport
2886 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2888 if (desktop != null)
2890 AlignmentPanel[] aps = getAlignmentPanels(
2891 viewport.getSequenceSetId());
2892 for (int panel = 0; aps != null && panel < aps.length; panel++)
2894 if (aps[panel] != null && aps[panel].av == viewport)
2896 return aps[panel].alignFrame;
2903 public VamsasApplication getVamsasApplication()
2910 * flag set if jalview GUI is being operated programmatically
2912 private boolean inBatchMode = false;
2915 * check if jalview GUI is being operated programmatically
2917 * @return inBatchMode
2919 public boolean isInBatchMode()
2925 * set flag if jalview GUI is being operated programmatically
2927 * @param inBatchMode
2929 public void setInBatchMode(boolean inBatchMode)
2931 this.inBatchMode = inBatchMode;
2934 public void startServiceDiscovery()
2936 startServiceDiscovery(false);
2939 public void startServiceDiscovery(boolean blocking)
2941 boolean alive = true;
2942 Thread t0 = null, t1 = null, t2 = null;
2943 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2946 // todo: changesupport handlers need to be transferred
2947 if (discoverer == null)
2949 discoverer = new jalview.ws.jws1.Discoverer();
2950 // register PCS handler for desktop.
2951 discoverer.addPropertyChangeListener(changeSupport);
2953 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2954 // until we phase out completely
2955 (t0 = new Thread(discoverer)).start();
2958 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2960 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2961 .startDiscoverer(changeSupport);
2965 // TODO: do rest service discovery
2974 } catch (Exception e)
2977 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2978 || (t3 != null && t3.isAlive())
2979 || (t0 != null && t0.isAlive());
2985 * called to check if the service discovery process completed successfully.
2989 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2991 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2993 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2994 .getErrorMessages();
2997 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2999 if (serviceChangedDialog == null)
3001 // only run if we aren't already displaying one of these.
3002 addDialogThread(serviceChangedDialog = new Runnable()
3009 * JalviewDialog jd =new JalviewDialog() {
3011 * @Override protected void cancelPressed() { // TODO
3012 * Auto-generated method stub
3014 * }@Override protected void okPressed() { // TODO
3015 * Auto-generated method stub
3017 * }@Override protected void raiseClosed() { // TODO
3018 * Auto-generated method stub
3020 * } }; jd.initDialogFrame(new
3021 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3022 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3023 * + " or mis-configured HTTP proxy settings.<br/>" +
3024 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3026 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3027 * ), true, true, "Web Service Configuration Problem", 450,
3030 * jd.waitForInput();
3032 JvOptionPane.showConfirmDialog(Desktop.desktop,
3033 new JLabel("<html><table width=\"450\"><tr><td>"
3034 + ermsg + "</td></tr></table>"
3035 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3036 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3037 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3038 + " Tools->Preferences dialog box to change them.</p></html>"),
3039 "Web Service Configuration Problem",
3040 JvOptionPane.DEFAULT_OPTION,
3041 JvOptionPane.ERROR_MESSAGE);
3042 serviceChangedDialog = null;
3051 "Errors reported by JABA discovery service. Check web services preferences.\n"
3058 private Runnable serviceChangedDialog = null;
3061 * start a thread to open a URL in the configured browser. Pops up a warning
3062 * dialog to the user if there is an exception when calling out to the browser
3067 public static void showUrl(final String url)
3069 showUrl(url, Desktop.instance);
3073 * Like showUrl but allows progress handler to be specified
3077 * (null) or object implementing IProgressIndicator
3079 public static void showUrl(final String url,
3080 final IProgressIndicator progress)
3082 new Thread(new Runnable()
3089 if (progress != null)
3091 progress.setProgressBar(MessageManager
3092 .formatMessage("status.opening_params", new Object[]
3093 { url }), this.hashCode());
3095 jalview.util.BrowserLauncher.openURL(url);
3096 } catch (Exception ex)
3098 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3100 .getString("label.web_browser_not_found_unix"),
3101 MessageManager.getString("label.web_browser_not_found"),
3102 JvOptionPane.WARNING_MESSAGE);
3104 ex.printStackTrace();
3106 if (progress != null)
3108 progress.setProgressBar(null, this.hashCode());
3114 public static WsParamSetManager wsparamManager = null;
3116 public static ParamManager getUserParameterStore()
3118 if (wsparamManager == null)
3120 wsparamManager = new WsParamSetManager();
3122 return wsparamManager;
3126 * static hyperlink handler proxy method for use by Jalview's internal windows
3130 public static void hyperlinkUpdate(HyperlinkEvent e)
3132 if (e.getEventType() == EventType.ACTIVATED)
3137 url = e.getURL().toString();
3138 Desktop.showUrl(url);
3139 } catch (Exception x)
3143 if (Cache.log != null)
3145 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3150 "Couldn't handle string " + url + " as a URL.");
3153 // ignore any exceptions due to dud links.
3160 * single thread that handles display of dialogs to user.
3162 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3165 * flag indicating if dialogExecutor should try to acquire a permit
3167 private volatile boolean dialogPause = true;
3172 private java.util.concurrent.Semaphore block = new Semaphore(0);
3174 private static groovy.ui.Console groovyConsole;
3177 * add another dialog thread to the queue
3181 public void addDialogThread(final Runnable prompter)
3183 dialogExecutor.submit(new Runnable()
3193 } catch (InterruptedException x)
3198 if (instance == null)
3204 SwingUtilities.invokeAndWait(prompter);
3205 } catch (Exception q)
3207 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3213 public void startDialogQueue()
3215 // set the flag so we don't pause waiting for another permit and semaphore
3216 // the current task to begin
3217 dialogPause = false;
3222 protected void snapShotWindow_actionPerformed(ActionEvent e)
3226 ImageMaker im = new jalview.util.ImageMaker(
3227 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3228 getHeight(), of = new File("Jalview_snapshot"
3229 + System.currentTimeMillis() + ".eps"),
3230 "View of desktop", null, 0, false);
3233 paintAll(im.getGraphics());
3235 } catch (Exception q)
3237 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3241 Cache.log.info("Successfully written snapshot to file "
3242 + of.getAbsolutePath());
3246 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3247 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3248 * and location last time the view was expanded (if any). However it does not
3249 * remember the split pane divider location - this is set to match the
3250 * 'exploding' frame.
3254 public void explodeViews(SplitFrame sf)
3256 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3257 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3258 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3260 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3262 int viewCount = topPanels.size();
3269 * Processing in reverse order works, forwards order leaves the first panels
3270 * not visible. I don't know why!
3272 for (int i = viewCount - 1; i >= 0; i--)
3275 * Make new top and bottom frames. These take over the respective
3276 * AlignmentPanel objects, including their AlignmentViewports, so the
3277 * cdna/protein relationships between the viewports is carried over to the
3280 * explodedGeometry holds the (x, y) position of the previously exploded
3281 * SplitFrame, and the (width, height) of the AlignFrame component
3283 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3284 AlignFrame newTopFrame = new AlignFrame(topPanel);
3285 newTopFrame.setSize(oldTopFrame.getSize());
3286 newTopFrame.setVisible(true);
3287 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3288 .getExplodedGeometry();
3289 if (geometry != null)
3291 newTopFrame.setSize(geometry.getSize());
3294 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3295 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3296 newBottomFrame.setSize(oldBottomFrame.getSize());
3297 newBottomFrame.setVisible(true);
3298 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3299 .getExplodedGeometry();
3300 if (geometry != null)
3302 newBottomFrame.setSize(geometry.getSize());
3305 topPanel.av.setGatherViewsHere(false);
3306 bottomPanel.av.setGatherViewsHere(false);
3307 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3309 if (geometry != null)
3311 splitFrame.setLocation(geometry.getLocation());
3313 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3317 * Clear references to the panels (now relocated in the new SplitFrames)
3318 * before closing the old SplitFrame.
3321 bottomPanels.clear();
3326 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3327 * back into the given SplitFrame as additional views. Note that the gathered
3328 * frames may themselves have multiple views.
3332 public void gatherViews(GSplitFrame source)
3335 * special handling of explodedGeometry for a view within a SplitFrame: - it
3336 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3337 * height) of the AlignFrame component
3339 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3340 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3341 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3342 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3343 myBottomFrame.viewport
3344 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3345 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3346 myTopFrame.viewport.setGatherViewsHere(true);
3347 myBottomFrame.viewport.setGatherViewsHere(true);
3348 String topViewId = myTopFrame.viewport.getSequenceSetId();
3349 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3351 JInternalFrame[] frames = desktop.getAllFrames();
3352 for (JInternalFrame frame : frames)
3354 if (frame instanceof SplitFrame && frame != source)
3356 SplitFrame sf = (SplitFrame) frame;
3357 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3358 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3359 boolean gatherThis = false;
3360 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3362 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3363 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3364 if (topViewId.equals(topPanel.av.getSequenceSetId())
3365 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3368 topPanel.av.setGatherViewsHere(false);
3369 bottomPanel.av.setGatherViewsHere(false);
3370 topPanel.av.setExplodedGeometry(
3371 new Rectangle(sf.getLocation(), topFrame.getSize()));
3372 bottomPanel.av.setExplodedGeometry(
3373 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3374 myTopFrame.addAlignmentPanel(topPanel, false);
3375 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3381 topFrame.getAlignPanels().clear();
3382 bottomFrame.getAlignPanels().clear();
3389 * The dust settles...give focus to the tab we did this from.
3391 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3394 public static groovy.ui.Console getGroovyConsole()
3396 return groovyConsole;
3400 * handles the payload of a drag and drop event.
3402 * TODO refactor to desktop utilities class
3405 * - Data source strings extracted from the drop event
3407 * - protocol for each data source extracted from the drop event
3411 * - the payload from the drop event
3414 public static void transferFromDropTarget(List<String> files,
3415 List<DataSourceType> protocols, DropTargetDropEvent evt,
3416 Transferable t) throws Exception
3419 DataFlavor uriListFlavor = new DataFlavor(
3420 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3423 urlFlavour = new DataFlavor(
3424 "application/x-java-url; class=java.net.URL");
3425 } catch (ClassNotFoundException cfe)
3427 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3430 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3435 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3436 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3437 // means url may be null.
3440 protocols.add(DataSourceType.URL);
3441 files.add(url.toString());
3442 Cache.log.debug("Drop handled as URL dataflavor "
3443 + files.get(files.size() - 1));
3448 if (Platform.isAMac())
3451 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3455 } catch (Throwable ex)
3457 Cache.log.debug("URL drop handler failed.", ex);
3460 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3462 // Works on Windows and MacOSX
3463 Cache.log.debug("Drop handled as javaFileListFlavor");
3464 for (Object file : (List) t
3465 .getTransferData(DataFlavor.javaFileListFlavor))
3467 files.add(((File) file).toString());
3468 protocols.add(DataSourceType.FILE);
3473 // Unix like behaviour
3474 boolean added = false;
3476 if (t.isDataFlavorSupported(uriListFlavor))
3478 Cache.log.debug("Drop handled as uriListFlavor");
3479 // This is used by Unix drag system
3480 data = (String) t.getTransferData(uriListFlavor);
3484 // fallback to text: workaround - on OSX where there's a JVM bug
3485 Cache.log.debug("standard URIListFlavor failed. Trying text");
3486 // try text fallback
3487 DataFlavor textDf = new DataFlavor(
3488 "text/plain;class=java.lang.String");
3489 if (t.isDataFlavorSupported(textDf))
3491 data = (String) t.getTransferData(textDf);
3494 Cache.log.debug("Plain text drop content returned "
3495 + (data == null ? "Null - failed" : data));
3500 while (protocols.size() < files.size())
3502 Cache.log.debug("Adding missing FILE protocol for "
3503 + files.get(protocols.size()));
3504 protocols.add(DataSourceType.FILE);
3506 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3507 data, "\r\n"); st.hasMoreTokens();)
3510 String s = st.nextToken();
3511 if (s.startsWith("#"))
3513 // the line is a comment (as per the RFC 2483)
3516 java.net.URI uri = new java.net.URI(s);
3517 if (uri.getScheme().toLowerCase().startsWith("http"))
3519 protocols.add(DataSourceType.URL);
3520 files.add(uri.toString());
3524 // otherwise preserve old behaviour: catch all for file objects
3525 java.io.File file = new java.io.File(uri);
3526 protocols.add(DataSourceType.FILE);
3527 files.add(file.toString());
3532 if (Cache.log.isDebugEnabled())
3534 if (data == null || !added)
3537 if (t.getTransferDataFlavors() != null
3538 && t.getTransferDataFlavors().length > 0)
3541 "Couldn't resolve drop data. Here are the supported flavors:");
3542 for (DataFlavor fl : t.getTransferDataFlavors())
3545 "Supported transfer dataflavor: " + fl.toString());
3546 Object df = t.getTransferData(fl);
3549 Cache.log.debug("Retrieves: " + df);
3553 Cache.log.debug("Retrieved nothing");
3559 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3565 if (Platform.isWindows())
3568 Cache.log.debug("Scanning dropped content for Windows Link Files");
3570 // resolve any .lnk files in the file drop
3571 for (int f = 0; f < files.size(); f++)
3573 String source = files.get(f).toLowerCase();
3574 if (protocols.get(f).equals(DataSourceType.FILE)
3575 && (source.endsWith(".lnk") || source.endsWith(".url")
3576 || source.endsWith(".site")))
3580 File lf = new File(files.get(f));
3581 // process link file to get a URL
3582 Cache.log.debug("Found potential link file: " + lf);
3583 WindowsShortcut wscfile = new WindowsShortcut(lf);
3584 String fullname = wscfile.getRealFilename();
3585 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3586 files.set(f, fullname);
3587 Cache.log.debug("Parsed real filename " + fullname
3588 + " to extract protocol: " + protocols.get(f));
3589 } catch (Exception ex)
3592 "Couldn't parse " + files.get(f) + " as a link file.",
3601 * Sets the Preferences property for experimental features to True or False
3602 * depending on the state of the controlling menu item
3605 protected void showExperimental_actionPerformed(boolean selected)
3607 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3611 * Answers a (possibly empty) list of any structure viewer frames (currently
3612 * for either Jmol or Chimera) which are currently open. This may optionally
3613 * be restricted to viewers of a specified class, or viewers linked to a
3614 * specified alignment panel.
3617 * if not null, only return viewers linked to this panel
3618 * @param structureViewerClass
3619 * if not null, only return viewers of this class
3622 public List<StructureViewerBase> getStructureViewers(
3623 AlignmentPanel apanel,
3624 Class<? extends StructureViewerBase> structureViewerClass)
3626 List<StructureViewerBase> result = new ArrayList<>();
3627 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3629 for (JInternalFrame frame : frames)
3631 if (frame instanceof StructureViewerBase)
3633 if (structureViewerClass == null
3634 || structureViewerClass.isInstance(frame))
3637 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3639 result.add((StructureViewerBase) frame);