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("Exception when trying to set APQHandlers");
371 } catch (Throwable t)
373 System.out.println("Throwable when trying to set APQHandlers");
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
428 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
429 + "\n" + "Jalview Installation: "
430 + jalview.bin.Cache.getDefault("INSTALLATION",
432 + "\n" + "Build Date: "
433 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
434 + "\n" + "Java version: "
435 + System.getProperty("java.version") + "\n"
436 + System.getProperty("os.arch") + " "
437 + System.getProperty("os.name") + " "
438 + System.getProperty("os.version")
439 + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
441 + System.getProperty(
443 + File.separator + "bin"
444 + File.separator + "java"
448 showConsole(showjconsole);
450 showNews.setVisible(false);
452 experimentalFeatures.setSelected(showExperimental());
454 getIdentifiersOrgData();
458 this.addWindowListener(new WindowAdapter()
461 public void windowClosing(WindowEvent evt)
468 this.addMouseListener(ma = new MouseAdapter()
471 public void mousePressed(MouseEvent evt)
473 if (evt.isPopupTrigger()) // Mac
475 showPasteMenu(evt.getX(), evt.getY());
480 public void mouseReleased(MouseEvent evt)
482 if (evt.isPopupTrigger()) // Windows
484 showPasteMenu(evt.getX(), evt.getY());
488 desktop.addMouseListener(ma);
490 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
491 // Spawn a thread that shows the splashscreen
492 SwingUtilities.invokeLater(new Runnable()
501 // Thread off a new instance of the file chooser - this reduces the time it
502 // takes to open it later on.
503 new Thread(new Runnable()
508 Cache.log.debug("Filechooser init thread started.");
509 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
510 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
512 Cache.log.debug("Filechooser init thread finished.");
515 // Add the service change listener
516 changeSupport.addJalviewPropertyChangeListener("services",
517 new PropertyChangeListener()
521 public void propertyChange(PropertyChangeEvent evt)
523 Cache.log.debug("Firing service changed event for "
524 + evt.getNewValue());
525 JalviewServicesChanged(evt);
532 * Answers true if user preferences to enable experimental features is True
537 public boolean showExperimental()
539 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
540 Boolean.FALSE.toString());
541 return Boolean.valueOf(experimental).booleanValue();
544 public void doConfigureStructurePrefs()
546 // configure services
547 StructureSelectionManager ssm = StructureSelectionManager
548 .getStructureSelectionManager(this);
549 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
551 ssm.setAddTempFacAnnot(jalview.bin.Cache
552 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
553 ssm.setProcessSecondaryStructure(jalview.bin.Cache
554 .getDefault(Preferences.STRUCT_FROM_PDB, true));
555 ssm.setSecStructServices(
556 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
560 ssm.setAddTempFacAnnot(false);
561 ssm.setProcessSecondaryStructure(false);
562 ssm.setSecStructServices(false);
566 public void checkForNews()
568 final Desktop me = this;
569 // Thread off the news reader, in case there are connection problems.
570 new Thread(new Runnable()
575 Cache.log.debug("Starting news thread.");
577 jvnews = new BlogReader(me);
578 showNews.setVisible(true);
579 Cache.log.debug("Completed news thread.");
584 public void getIdentifiersOrgData()
586 // Thread off the identifiers fetcher
587 new Thread(new Runnable()
592 Cache.log.debug("Downloading data from identifiers.org");
593 UrlDownloadClient client = new UrlDownloadClient();
596 client.download(IdOrgSettings.getUrl(),
597 IdOrgSettings.getDownloadLocation());
598 } catch (IOException e)
600 Cache.log.debug("Exception downloading identifiers.org data"
609 protected void showNews_actionPerformed(ActionEvent e)
611 showNews(showNews.isSelected());
614 void showNews(boolean visible)
617 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
618 showNews.setSelected(visible);
619 if (visible && !jvnews.isVisible())
621 new Thread(new Runnable()
626 long now = System.currentTimeMillis();
627 Desktop.instance.setProgressBar(
628 MessageManager.getString("status.refreshing_news"),
630 jvnews.refreshNews();
631 Desktop.instance.setProgressBar(null, now);
640 * recover the last known dimensions for a jalview window
643 * - empty string is desktop, all other windows have unique prefix
644 * @return null or last known dimensions scaled to current geometry (if last
645 * window geom was known)
647 Rectangle getLastKnownDimensions(String windowName)
649 // TODO: lock aspect ratio for scaling desktop Bug #0058199
650 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
651 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
652 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
653 String width = jalview.bin.Cache
654 .getProperty(windowName + "SCREEN_WIDTH");
655 String height = jalview.bin.Cache
656 .getProperty(windowName + "SCREEN_HEIGHT");
657 if ((x != null) && (y != null) && (width != null) && (height != null))
659 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
660 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
661 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
663 // attempt #1 - try to cope with change in screen geometry - this
664 // version doesn't preserve original jv aspect ratio.
665 // take ratio of current screen size vs original screen size.
666 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
667 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
668 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
669 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
670 // rescale the bounds depending upon the current screen geometry.
671 ix = (int) (ix * sw);
672 iw = (int) (iw * sw);
673 iy = (int) (iy * sh);
674 ih = (int) (ih * sh);
675 while (ix >= screenSize.width)
677 jalview.bin.Cache.log.debug(
678 "Window geometry location recall error: shifting horizontal to within screenbounds.");
679 ix -= screenSize.width;
681 while (iy >= screenSize.height)
683 jalview.bin.Cache.log.debug(
684 "Window geometry location recall error: shifting vertical to within screenbounds.");
685 iy -= screenSize.height;
687 jalview.bin.Cache.log.debug(
688 "Got last known dimensions for " + windowName + ": x:" + ix
689 + " y:" + iy + " width:" + iw + " height:" + ih);
691 // return dimensions for new instance
692 return new Rectangle(ix, iy, iw, ih);
697 private void doVamsasClientCheck()
699 if (jalview.bin.Cache.vamsasJarsPresent())
701 setupVamsasDisconnectedGui();
702 VamsasMenu.setVisible(true);
703 final Desktop us = this;
704 VamsasMenu.addMenuListener(new MenuListener()
706 // this listener remembers when the menu was first selected, and
707 // doesn't rebuild the session list until it has been cleared and
709 boolean refresh = true;
712 public void menuCanceled(MenuEvent e)
718 public void menuDeselected(MenuEvent e)
724 public void menuSelected(MenuEvent e)
728 us.buildVamsasStMenu();
733 vamsasStart.setVisible(true);
737 void showPasteMenu(int x, int y)
739 JPopupMenu popup = new JPopupMenu();
740 JMenuItem item = new JMenuItem(
741 MessageManager.getString("label.paste_new_window"));
742 item.addActionListener(new ActionListener()
745 public void actionPerformed(ActionEvent evt)
752 popup.show(this, x, y);
759 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
760 Transferable contents = c.getContents(this);
762 if (contents != null)
764 String file = (String) contents
765 .getTransferData(DataFlavor.stringFlavor);
767 FileFormatI format = new IdentifyFile().identify(file,
768 DataSourceType.PASTE);
770 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
773 } catch (Exception ex)
776 "Unable to paste alignment from system clipboard:\n" + ex);
781 * Adds and opens the given frame to the desktop
792 public static synchronized void addInternalFrame(
793 final JInternalFrame frame, String title, int w, int h)
795 addInternalFrame(frame, title, true, w, h, true, false);
799 * Add an internal frame to the Jalview desktop
806 * When true, display frame immediately, otherwise, caller must call
807 * setVisible themselves.
813 public static synchronized void addInternalFrame(
814 final JInternalFrame frame, String title, boolean makeVisible,
817 addInternalFrame(frame, title, makeVisible, w, h, true, false);
821 * Add an internal frame to the Jalview desktop and make it visible
834 public static synchronized void addInternalFrame(
835 final JInternalFrame frame, String title, int w, int h,
838 addInternalFrame(frame, title, true, w, h, resizable, false);
842 * Add an internal frame to the Jalview desktop
849 * When true, display frame immediately, otherwise, caller must call
850 * setVisible themselves.
857 * @param ignoreMinSize
858 * Do not set the default minimum size for frame
860 public static synchronized void addInternalFrame(
861 final JInternalFrame frame, String title, boolean makeVisible,
862 int w, int h, boolean resizable, boolean ignoreMinSize)
865 // TODO: allow callers to determine X and Y position of frame (eg. via
867 // TODO: consider fixing method to update entries in the window submenu with
868 // the current window title
870 frame.setTitle(title);
871 if (frame.getWidth() < 1 || frame.getHeight() < 1)
875 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
876 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
877 // IF JALVIEW IS RUNNING HEADLESS
878 // ///////////////////////////////////////////////
879 if (instance == null || (System.getProperty("java.awt.headless") != null
880 && System.getProperty("java.awt.headless").equals("true")))
889 frame.setMinimumSize(
890 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
892 // Set default dimension for Alignment Frame window.
893 // The Alignment Frame window could be added from a number of places,
895 // I did this here in order not to miss out on any Alignment frame.
896 if (frame instanceof AlignFrame)
898 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
899 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
903 frame.setVisible(makeVisible);
904 frame.setClosable(true);
905 frame.setResizable(resizable);
906 frame.setMaximizable(resizable);
907 frame.setIconifiable(resizable);
908 frame.setOpaque(false);
910 if (frame.getX() < 1 && frame.getY() < 1)
912 frame.setLocation(xOffset * openFrameCount,
913 yOffset * ((openFrameCount - 1) % 10) + yOffset);
917 * add an entry for the new frame in the Window menu
918 * (and remove it when the frame is closed)
920 final JMenuItem menuItem = new JMenuItem(title);
921 frame.addInternalFrameListener(new InternalFrameAdapter()
924 public void internalFrameActivated(InternalFrameEvent evt)
926 JInternalFrame itf = desktop.getSelectedFrame();
929 if (itf instanceof AlignFrame)
931 Jalview.setCurrentAlignFrame((AlignFrame) itf);
938 public void internalFrameClosed(InternalFrameEvent evt)
940 PaintRefresher.RemoveComponent(frame);
943 * defensive check to prevent frames being
944 * added half off the window
946 if (openFrameCount > 0)
952 * ensure no reference to alignFrame retained by menu item listener
954 if (menuItem.getActionListeners().length > 0)
956 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
958 windowMenu.remove(menuItem);
962 menuItem.addActionListener(new ActionListener()
965 public void actionPerformed(ActionEvent e)
969 frame.setSelected(true);
970 frame.setIcon(false);
971 } catch (java.beans.PropertyVetoException ex)
978 setKeyBindings(frame);
982 windowMenu.add(menuItem);
987 frame.setSelected(true);
988 frame.requestFocus();
989 } catch (java.beans.PropertyVetoException ve)
991 } catch (java.lang.ClassCastException cex)
994 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1000 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1005 private static void setKeyBindings(JInternalFrame frame)
1007 @SuppressWarnings("serial")
1008 final Action closeAction = new AbstractAction()
1011 public void actionPerformed(ActionEvent e)
1018 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1020 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1021 InputEvent.CTRL_DOWN_MASK);
1022 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1023 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
1025 InputMap inputMap = frame
1026 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1027 String ctrlW = ctrlWKey.toString();
1028 inputMap.put(ctrlWKey, ctrlW);
1029 inputMap.put(cmdWKey, ctrlW);
1031 ActionMap actionMap = frame.getActionMap();
1032 actionMap.put(ctrlW, closeAction);
1036 public void lostOwnership(Clipboard clipboard, Transferable contents)
1040 Desktop.jalviewClipboard = null;
1043 internalCopy = false;
1047 public void dragEnter(DropTargetDragEvent evt)
1052 public void dragExit(DropTargetEvent evt)
1057 public void dragOver(DropTargetDragEvent evt)
1062 public void dropActionChanged(DropTargetDragEvent evt)
1073 public void drop(DropTargetDropEvent evt)
1075 boolean success = true;
1076 // JAL-1552 - acceptDrop required before getTransferable call for
1077 // Java's Transferable for native dnd
1078 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1079 Transferable t = evt.getTransferable();
1080 List<String> files = new ArrayList<>();
1081 List<DataSourceType> protocols = new ArrayList<>();
1085 Desktop.transferFromDropTarget(files, protocols, evt, t);
1086 } catch (Exception e)
1088 e.printStackTrace();
1096 for (int i = 0; i < files.size(); i++)
1098 String file = files.get(i).toString();
1099 DataSourceType protocol = (protocols == null)
1100 ? DataSourceType.FILE
1102 FileFormatI format = null;
1104 if (file.endsWith(".jar"))
1106 format = FileFormat.Jalview;
1111 format = new IdentifyFile().identify(file, protocol);
1114 new FileLoader().LoadFile(file, protocol, format);
1117 } catch (Exception ex)
1122 evt.dropComplete(success); // need this to ensure input focus is properly
1123 // transfered to any new windows created
1133 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1135 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1136 JalviewFileChooser chooser = JalviewFileChooser
1137 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
1139 chooser.setFileView(new JalviewFileView());
1140 chooser.setDialogTitle(
1141 MessageManager.getString("label.open_local_file"));
1142 chooser.setToolTipText(MessageManager.getString("action.open"));
1144 int value = chooser.showOpenDialog(this);
1146 if (value == JalviewFileChooser.APPROVE_OPTION)
1148 String choice = chooser.getSelectedFile().getPath();
1149 Cache.setProperty("LAST_DIRECTORY",
1150 chooser.getSelectedFile().getParent());
1152 FileFormatI format = chooser.getSelectedFormat();
1155 * Call IdentifyFile to verify the file contains what its extension implies.
1156 * Skip this step for dynamically added file formats, because
1157 * IdentifyFile does not know how to recognise them.
1159 if (FileFormats.getInstance().isIdentifiable(format))
1163 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1164 } catch (FileFormatException e)
1166 // format = null; //??
1170 if (viewport != null)
1172 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1177 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1189 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1191 // This construct allows us to have a wider textfield
1193 JLabel label = new JLabel(
1194 MessageManager.getString("label.input_file_url"));
1195 final JComboBox history = new JComboBox();
1197 JPanel panel = new JPanel(new GridLayout(2, 1));
1200 history.setPreferredSize(new Dimension(400, 20));
1201 history.setEditable(true);
1202 history.addItem("http://www.");
1204 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1208 if (historyItems != null)
1210 st = new StringTokenizer(historyItems, "\t");
1212 while (st.hasMoreTokens())
1214 history.addItem(st.nextElement());
1218 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1219 MessageManager.getString("label.input_alignment_from_url"),
1220 JvOptionPane.OK_CANCEL_OPTION);
1222 if (reply != JvOptionPane.OK_OPTION)
1227 String url = history.getSelectedItem().toString();
1229 if (url.toLowerCase().endsWith(".jar"))
1231 if (viewport != null)
1233 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1234 FileFormat.Jalview);
1238 new FileLoader().LoadFile(url, DataSourceType.URL,
1239 FileFormat.Jalview);
1244 FileFormatI format = null;
1247 format = new IdentifyFile().identify(url, DataSourceType.URL);
1248 } catch (FileFormatException e)
1250 // TODO revise error handling, distinguish between
1251 // URL not found and response not valid
1256 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1257 MessageManager.formatMessage("label.couldnt_locate",
1260 MessageManager.getString("label.url_not_found"),
1261 JvOptionPane.WARNING_MESSAGE);
1266 if (viewport != null)
1268 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1273 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1279 * Opens the CutAndPaste window for the user to paste an alignment in to
1282 * - if not null, the pasted alignment is added to the current
1283 * alignment; if null, to a new alignment window
1286 public void inputTextboxMenuItem_actionPerformed(
1287 AlignmentViewPanel viewPanel)
1289 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1290 cap.setForInput(viewPanel);
1291 Desktop.addInternalFrame(cap,
1292 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1302 //System.out.println("********** Desktop.quit()");
1303 //System.out.println(savingFiles.toString());
1304 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1305 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1307 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1308 screen.height + "");
1309 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1310 getWidth(), getHeight()));
1312 if (jconsole != null)
1314 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1315 jconsole.stopConsole();
1319 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1322 if (dialogExecutor != null)
1324 dialogExecutor.shutdownNow();
1326 closeAll_actionPerformed(null);
1328 if (groovyConsole != null)
1330 // suppress a possible repeat prompt to save script
1331 groovyConsole.setDirty(false);
1332 groovyConsole.exit();
1337 private void storeLastKnownDimensions(String string, Rectangle jc)
1339 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1340 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1341 + " height:" + jc.height);
1343 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1344 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1345 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1346 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1356 public void aboutMenuItem_actionPerformed(ActionEvent e)
1358 // StringBuffer message = getAboutMessage(false);
1359 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1361 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1362 new Thread(new Runnable()
1367 new SplashScreen(true);
1372 public StringBuffer getAboutMessage(boolean shortv)
1374 StringBuffer message = new StringBuffer();
1375 message.append("<html>");
1378 message.append("<h1><strong>Version: "
1379 + jalview.bin.Cache.getProperty("VERSION")
1380 + "</strong></h1>");
1381 message.append("<strong>Last Updated: <em>"
1382 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1383 + "</em></strong>");
1389 message.append("<strong>Version "
1390 + jalview.bin.Cache.getProperty("VERSION")
1391 + "; last updated: "
1392 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1395 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1396 .equals("Checking"))
1398 message.append("<br>...Checking latest version...</br>");
1400 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1401 .equals(jalview.bin.Cache.getProperty("VERSION")))
1403 boolean red = false;
1404 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1405 .indexOf("automated build") == -1)
1408 // Displayed when code version and jnlp version do not match and code
1409 // version is not a development build
1410 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1413 message.append("<br>!! Version "
1414 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1416 + " is available for download from "
1417 + jalview.bin.Cache.getDefault("www.jalview.org",
1418 "http://www.jalview.org")
1422 message.append("</div>");
1425 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1427 "The Jalview Authors (See AUTHORS file for current list)")
1428 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1429 + "<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"
1430 + "<br><br>If you use Jalview, please cite:"
1431 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1432 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1433 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1445 public void documentationMenuItem_actionPerformed(ActionEvent e)
1449 Help.showHelpWindow();
1450 } catch (Exception ex)
1456 public void closeAll_actionPerformed(ActionEvent e)
1458 // TODO show a progress bar while closing?
1459 JInternalFrame[] frames = desktop.getAllFrames();
1460 for (int i = 0; i < frames.length; i++)
1464 frames[i].setClosed(true);
1465 } catch (java.beans.PropertyVetoException ex)
1469 Jalview.setCurrentAlignFrame(null);
1470 System.out.println("ALL CLOSED");
1471 if (v_client != null)
1473 // TODO clear binding to vamsas document objects on close_all
1477 * reset state of singleton objects as appropriate (clear down session state
1478 * when all windows are closed)
1480 StructureSelectionManager ssm = StructureSelectionManager
1481 .getStructureSelectionManager(this);
1489 public void raiseRelated_actionPerformed(ActionEvent e)
1491 reorderAssociatedWindows(false, false);
1495 public void minimizeAssociated_actionPerformed(ActionEvent e)
1497 reorderAssociatedWindows(true, false);
1500 void closeAssociatedWindows()
1502 reorderAssociatedWindows(false, true);
1508 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1512 protected void garbageCollect_actionPerformed(ActionEvent e)
1514 // We simply collect the garbage
1515 jalview.bin.Cache.log.debug("Collecting garbage...");
1517 jalview.bin.Cache.log.debug("Finished garbage collection.");
1524 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1528 protected void showMemusage_actionPerformed(ActionEvent e)
1530 desktop.showMemoryUsage(showMemusage.isSelected());
1537 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1541 protected void showConsole_actionPerformed(ActionEvent e)
1543 showConsole(showConsole.isSelected());
1546 Console jconsole = null;
1549 * control whether the java console is visible or not
1553 void showConsole(boolean selected)
1555 showConsole.setSelected(selected);
1556 // TODO: decide if we should update properties file
1557 Cache.setProperty("SHOW_JAVA_CONSOLE",
1558 Boolean.valueOf(selected).toString());
1559 jconsole.setVisible(selected);
1562 void reorderAssociatedWindows(boolean minimize, boolean close)
1564 JInternalFrame[] frames = desktop.getAllFrames();
1565 if (frames == null || frames.length < 1)
1570 AlignmentViewport source = null, target = null;
1571 if (frames[0] instanceof AlignFrame)
1573 source = ((AlignFrame) frames[0]).getCurrentView();
1575 else if (frames[0] instanceof TreePanel)
1577 source = ((TreePanel) frames[0]).getViewPort();
1579 else if (frames[0] instanceof PCAPanel)
1581 source = ((PCAPanel) frames[0]).av;
1583 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1585 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1590 for (int i = 0; i < frames.length; i++)
1593 if (frames[i] == null)
1597 if (frames[i] instanceof AlignFrame)
1599 target = ((AlignFrame) frames[i]).getCurrentView();
1601 else if (frames[i] instanceof TreePanel)
1603 target = ((TreePanel) frames[i]).getViewPort();
1605 else if (frames[i] instanceof PCAPanel)
1607 target = ((PCAPanel) frames[i]).av;
1609 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1611 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1614 if (source == target)
1620 frames[i].setClosed(true);
1624 frames[i].setIcon(minimize);
1627 frames[i].toFront();
1631 } catch (java.beans.PropertyVetoException ex)
1646 protected void preferences_actionPerformed(ActionEvent e)
1652 * Shows a file chooser dialog and writes out the current session as a Jalview
1656 public void saveState_actionPerformed()
1658 saveState_actionPerformed(false);
1661 public void saveState_actionPerformed(boolean saveAs)
1663 java.io.File projectFile = getProjectFile();
1664 // autoSave indicates we already have a file and don't need to ask
1665 boolean autoSave = projectFile != null && !saveAs
1666 && BackupFiles.getEnabled();
1668 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1669 // saveAs="+saveAs+", Backups
1670 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1672 boolean approveSave = false;
1675 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1678 chooser.setFileView(new JalviewFileView());
1679 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1681 int value = chooser.showSaveDialog(this);
1683 if (value == JalviewFileChooser.APPROVE_OPTION)
1685 projectFile = chooser.getSelectedFile();
1686 setProjectFile(projectFile);
1691 if (approveSave || autoSave)
1693 final Desktop me = this;
1694 final java.io.File chosenFile = projectFile;
1695 new Thread(new Runnable()
1700 // TODO: refactor to Jalview desktop session controller action.
1701 setProgressBar(MessageManager.formatMessage(
1702 "label.saving_jalview_project", new Object[]
1703 { chosenFile.getName() }), chosenFile.hashCode());
1704 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1705 chosenFile.getParent());
1706 // TODO catch and handle errors for savestate
1707 // TODO prevent user from messing with the Desktop whilst we're saving
1710 BackupFiles backupfiles = new BackupFiles(chosenFile);
1712 new Jalview2XML().saveState(backupfiles.getTempFile());
1714 backupfiles.setWriteSuccess(true);
1715 backupfiles.rollBackupsAndRenameTempFile();
1716 } catch (OutOfMemoryError oom)
1718 new OOMWarning("Whilst saving current state to "
1719 + chosenFile.getName(), oom);
1720 } catch (Exception ex)
1722 Cache.log.error("Problems whilst trying to save to "
1723 + chosenFile.getName(), ex);
1724 JvOptionPane.showMessageDialog(me,
1725 MessageManager.formatMessage(
1726 "label.error_whilst_saving_current_state_to",
1728 { chosenFile.getName() }),
1729 MessageManager.getString("label.couldnt_save_project"),
1730 JvOptionPane.WARNING_MESSAGE);
1732 setProgressBar(null, chosenFile.hashCode());
1739 public void saveAsState_actionPerformed(ActionEvent e)
1741 saveState_actionPerformed(true);
1744 private void setProjectFile(File choice)
1746 this.projectFile = choice;
1749 public File getProjectFile()
1751 return this.projectFile;
1755 * Shows a file chooser dialog and tries to read in the selected file as a
1759 public void loadState_actionPerformed()
1761 final String[] suffix = new String[] { "jvp", "jar" };
1762 final String[] desc = new String[] { "Jalview Project",
1763 "Jalview Project (old)" };
1764 JalviewFileChooser chooser = new JalviewFileChooser(
1765 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1766 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1768 chooser.setFileView(new JalviewFileView());
1769 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1771 int value = chooser.showOpenDialog(this);
1773 if (value == JalviewFileChooser.APPROVE_OPTION)
1775 final File selectedFile = chooser.getSelectedFile();
1776 setProjectFile(selectedFile);
1777 final String choice = selectedFile.getAbsolutePath();
1778 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1779 new Thread(new Runnable()
1784 setProgressBar(MessageManager.formatMessage(
1785 "label.loading_jalview_project", new Object[]
1786 { choice }), choice.hashCode());
1789 new Jalview2XML().loadJalviewAlign(choice);
1790 } catch (OutOfMemoryError oom)
1792 new OOMWarning("Whilst loading project from " + choice, oom);
1793 } catch (Exception ex)
1796 "Problems whilst loading project from " + choice, ex);
1797 JvOptionPane.showMessageDialog(Desktop.desktop,
1798 MessageManager.formatMessage(
1799 "label.error_whilst_loading_project_from",
1802 MessageManager.getString("label.couldnt_load_project"),
1803 JvOptionPane.WARNING_MESSAGE);
1805 setProgressBar(null, choice.hashCode());
1812 public void inputSequence_actionPerformed(ActionEvent e)
1814 new SequenceFetcher(this);
1817 JPanel progressPanel;
1819 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1821 public void startLoading(final String fileName)
1823 if (fileLoadingCount == 0)
1825 fileLoadingPanels.add(addProgressPanel(MessageManager
1826 .formatMessage("label.loading_file", new Object[]
1832 private JPanel addProgressPanel(String string)
1834 if (progressPanel == null)
1836 progressPanel = new JPanel(new GridLayout(1, 1));
1837 totalProgressCount = 0;
1838 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1840 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1841 JProgressBar progressBar = new JProgressBar();
1842 progressBar.setIndeterminate(true);
1844 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1846 thisprogress.add(progressBar, BorderLayout.CENTER);
1847 progressPanel.add(thisprogress);
1848 ((GridLayout) progressPanel.getLayout()).setRows(
1849 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1850 ++totalProgressCount;
1851 instance.validate();
1852 return thisprogress;
1855 int totalProgressCount = 0;
1857 private void removeProgressPanel(JPanel progbar)
1859 if (progressPanel != null)
1861 synchronized (progressPanel)
1863 progressPanel.remove(progbar);
1864 GridLayout gl = (GridLayout) progressPanel.getLayout();
1865 gl.setRows(gl.getRows() - 1);
1866 if (--totalProgressCount < 1)
1868 this.getContentPane().remove(progressPanel);
1869 progressPanel = null;
1876 public void stopLoading()
1879 if (fileLoadingCount < 1)
1881 while (fileLoadingPanels.size() > 0)
1883 removeProgressPanel(fileLoadingPanels.remove(0));
1885 fileLoadingPanels.clear();
1886 fileLoadingCount = 0;
1891 public static int getViewCount(String alignmentId)
1893 AlignmentViewport[] aps = getViewports(alignmentId);
1894 return (aps == null) ? 0 : aps.length;
1899 * @param alignmentId
1900 * - if null, all sets are returned
1901 * @return all AlignmentPanels concerning the alignmentId sequence set
1903 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1905 if (Desktop.desktop == null)
1907 // no frames created and in headless mode
1908 // TODO: verify that frames are recoverable when in headless mode
1911 List<AlignmentPanel> aps = new ArrayList<>();
1912 AlignFrame[] frames = getAlignFrames();
1917 for (AlignFrame af : frames)
1919 for (AlignmentPanel ap : af.alignPanels)
1921 if (alignmentId == null
1922 || alignmentId.equals(ap.av.getSequenceSetId()))
1928 if (aps.size() == 0)
1932 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1937 * get all the viewports on an alignment.
1939 * @param sequenceSetId
1940 * unique alignment id (may be null - all viewports returned in that
1942 * @return all viewports on the alignment bound to sequenceSetId
1944 public static AlignmentViewport[] getViewports(String sequenceSetId)
1946 List<AlignmentViewport> viewp = new ArrayList<>();
1947 if (desktop != null)
1949 AlignFrame[] frames = Desktop.getAlignFrames();
1951 for (AlignFrame afr : frames)
1953 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1954 .equals(sequenceSetId))
1956 if (afr.alignPanels != null)
1958 for (AlignmentPanel ap : afr.alignPanels)
1960 if (sequenceSetId == null
1961 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1969 viewp.add(afr.getViewport());
1973 if (viewp.size() > 0)
1975 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1982 * Explode the views in the given frame into separate AlignFrame
1986 public static void explodeViews(AlignFrame af)
1988 int size = af.alignPanels.size();
1994 for (int i = 0; i < size; i++)
1996 AlignmentPanel ap = af.alignPanels.get(i);
1997 AlignFrame newaf = new AlignFrame(ap);
2000 * Restore the view's last exploded frame geometry if known. Multiple
2001 * views from one exploded frame share and restore the same (frame)
2002 * position and size.
2004 Rectangle geometry = ap.av.getExplodedGeometry();
2005 if (geometry != null)
2007 newaf.setBounds(geometry);
2010 ap.av.setGatherViewsHere(false);
2012 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2013 AlignFrame.DEFAULT_HEIGHT);
2016 af.alignPanels.clear();
2017 af.closeMenuItem_actionPerformed(true);
2022 * Gather expanded views (separate AlignFrame's) with the same sequence set
2023 * identifier back in to this frame as additional views, and close the
2024 * expanded views. Note the expanded frames may themselves have multiple
2025 * views. We take the lot.
2029 public void gatherViews(AlignFrame source)
2031 source.viewport.setGatherViewsHere(true);
2032 source.viewport.setExplodedGeometry(source.getBounds());
2033 JInternalFrame[] frames = desktop.getAllFrames();
2034 String viewId = source.viewport.getSequenceSetId();
2036 for (int t = 0; t < frames.length; t++)
2038 if (frames[t] instanceof AlignFrame && frames[t] != source)
2040 AlignFrame af = (AlignFrame) frames[t];
2041 boolean gatherThis = false;
2042 for (int a = 0; a < af.alignPanels.size(); a++)
2044 AlignmentPanel ap = af.alignPanels.get(a);
2045 if (viewId.equals(ap.av.getSequenceSetId()))
2048 ap.av.setGatherViewsHere(false);
2049 ap.av.setExplodedGeometry(af.getBounds());
2050 source.addAlignmentPanel(ap, false);
2056 af.alignPanels.clear();
2057 af.closeMenuItem_actionPerformed(true);
2064 jalview.gui.VamsasApplication v_client = null;
2067 public void vamsasImport_actionPerformed(ActionEvent e)
2069 if (v_client == null)
2071 // Load and try to start a session.
2072 JalviewFileChooser chooser = new JalviewFileChooser(
2073 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2075 chooser.setFileView(new JalviewFileView());
2076 chooser.setDialogTitle(
2077 MessageManager.getString("label.open_saved_vamsas_session"));
2078 chooser.setToolTipText(MessageManager.getString(
2079 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2081 int value = chooser.showOpenDialog(this);
2083 if (value == JalviewFileChooser.APPROVE_OPTION)
2085 String fle = chooser.getSelectedFile().toString();
2086 if (!vamsasImport(chooser.getSelectedFile()))
2088 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2089 MessageManager.formatMessage(
2090 "label.couldnt_import_as_vamsas_session",
2094 .getString("label.vamsas_document_import_failed"),
2095 JvOptionPane.ERROR_MESSAGE);
2101 jalview.bin.Cache.log.error(
2102 "Implementation error - load session from a running session is not supported.");
2107 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2110 * @return true if import was a success and a session was started.
2112 public boolean vamsasImport(URL url)
2114 // TODO: create progress bar
2115 if (v_client != null)
2118 jalview.bin.Cache.log.error(
2119 "Implementation error - load session from a running session is not supported.");
2125 // copy the URL content to a temporary local file
2126 // TODO: be a bit cleverer here with nio (?!)
2127 File file = File.createTempFile("vdocfromurl", ".vdj");
2128 FileOutputStream fos = new FileOutputStream(file);
2129 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2130 byte[] buffer = new byte[2048];
2132 while ((ln = bis.read(buffer)) > -1)
2134 fos.write(buffer, 0, ln);
2138 v_client = new jalview.gui.VamsasApplication(this, file,
2139 url.toExternalForm());
2140 } catch (Exception ex)
2142 jalview.bin.Cache.log.error(
2143 "Failed to create new vamsas session from contents of URL "
2148 setupVamsasConnectedGui();
2149 v_client.initial_update(); // TODO: thread ?
2150 return v_client.inSession();
2154 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2157 * @return true if import was a success and a session was started.
2159 public boolean vamsasImport(File file)
2161 if (v_client != null)
2164 jalview.bin.Cache.log.error(
2165 "Implementation error - load session from a running session is not supported.");
2169 setProgressBar(MessageManager.formatMessage(
2170 "status.importing_vamsas_session_from", new Object[]
2171 { file.getName() }), file.hashCode());
2174 v_client = new jalview.gui.VamsasApplication(this, file, null);
2175 } catch (Exception ex)
2177 setProgressBar(MessageManager.formatMessage(
2178 "status.importing_vamsas_session_from", new Object[]
2179 { file.getName() }), file.hashCode());
2180 jalview.bin.Cache.log.error(
2181 "New vamsas session from existing session file failed:", ex);
2184 setupVamsasConnectedGui();
2185 v_client.initial_update(); // TODO: thread ?
2186 setProgressBar(MessageManager.formatMessage(
2187 "status.importing_vamsas_session_from", new Object[]
2188 { file.getName() }), file.hashCode());
2189 return v_client.inSession();
2192 public boolean joinVamsasSession(String mysesid)
2194 if (v_client != null)
2196 throw new Error(MessageManager
2197 .getString("error.try_join_vamsas_session_another"));
2199 if (mysesid == null)
2202 MessageManager.getString("error.invalid_vamsas_session_id"));
2204 v_client = new VamsasApplication(this, mysesid);
2205 setupVamsasConnectedGui();
2206 v_client.initial_update();
2207 return (v_client.inSession());
2211 public void vamsasStart_actionPerformed(ActionEvent e)
2213 if (v_client == null)
2216 // we just start a default session for moment.
2218 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2219 * getProperty("LAST_DIRECTORY"));
2221 * chooser.setFileView(new JalviewFileView());
2222 * chooser.setDialogTitle("Load Vamsas file");
2223 * chooser.setToolTipText("Import");
2225 * int value = chooser.showOpenDialog(this);
2227 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2228 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2230 v_client = new VamsasApplication(this);
2231 setupVamsasConnectedGui();
2232 v_client.initial_update(); // TODO: thread ?
2236 // store current data in session.
2237 v_client.push_update(); // TODO: thread
2241 protected void setupVamsasConnectedGui()
2243 vamsasStart.setText(MessageManager.getString("label.session_update"));
2244 vamsasSave.setVisible(true);
2245 vamsasStop.setVisible(true);
2246 vamsasImport.setVisible(false); // Document import to existing session is
2247 // not possible for vamsas-client-1.0.
2250 protected void setupVamsasDisconnectedGui()
2252 vamsasSave.setVisible(false);
2253 vamsasStop.setVisible(false);
2254 vamsasImport.setVisible(true);
2256 .setText(MessageManager.getString("label.new_vamsas_session"));
2260 public void vamsasStop_actionPerformed(ActionEvent e)
2262 if (v_client != null)
2264 v_client.end_session();
2266 setupVamsasDisconnectedGui();
2270 protected void buildVamsasStMenu()
2272 if (v_client == null)
2274 String[] sess = null;
2277 sess = VamsasApplication.getSessionList();
2278 } catch (Exception e)
2280 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2286 jalview.bin.Cache.log.debug(
2287 "Got current sessions list: " + sess.length + " entries.");
2288 VamsasStMenu.removeAll();
2289 for (int i = 0; i < sess.length; i++)
2291 JMenuItem sessit = new JMenuItem();
2292 sessit.setText(sess[i]);
2293 sessit.setToolTipText(MessageManager
2294 .formatMessage("label.connect_to_session", new Object[]
2296 final Desktop dsktp = this;
2297 final String mysesid = sess[i];
2298 sessit.addActionListener(new ActionListener()
2302 public void actionPerformed(ActionEvent e)
2304 if (dsktp.v_client == null)
2306 Thread rthr = new Thread(new Runnable()
2312 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2313 dsktp.setupVamsasConnectedGui();
2314 dsktp.v_client.initial_update();
2322 VamsasStMenu.add(sessit);
2324 // don't show an empty menu.
2325 VamsasStMenu.setVisible(sess.length > 0);
2330 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2331 VamsasStMenu.removeAll();
2332 VamsasStMenu.setVisible(false);
2337 // Not interested in the content. Just hide ourselves.
2338 VamsasStMenu.setVisible(false);
2343 public void vamsasSave_actionPerformed(ActionEvent e)
2345 if (v_client != null)
2347 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2348 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2351 chooser.setFileView(new JalviewFileView());
2352 chooser.setDialogTitle(MessageManager
2353 .getString("label.save_vamsas_document_archive"));
2355 int value = chooser.showSaveDialog(this);
2357 if (value == JalviewFileChooser.APPROVE_OPTION)
2359 java.io.File choice = chooser.getSelectedFile();
2360 JPanel progpanel = addProgressPanel(MessageManager
2361 .formatMessage("label.saving_vamsas_doc", new Object[]
2362 { choice.getName() }));
2363 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2364 String warnmsg = null;
2365 String warnttl = null;
2368 v_client.vclient.storeDocument(choice);
2371 warnttl = "Serious Problem saving Vamsas Document";
2372 warnmsg = ex.toString();
2373 jalview.bin.Cache.log
2374 .error("Error Whilst saving document to " + choice, ex);
2376 } catch (Exception ex)
2378 warnttl = "Problem saving Vamsas Document.";
2379 warnmsg = ex.toString();
2380 jalview.bin.Cache.log.warn(
2381 "Exception Whilst saving document to " + choice, ex);
2384 removeProgressPanel(progpanel);
2385 if (warnmsg != null)
2387 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2389 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2395 JPanel vamUpdate = null;
2398 * hide vamsas user gui bits when a vamsas document event is being handled.
2401 * true to hide gui, false to reveal gui
2403 public void setVamsasUpdate(boolean b)
2405 Cache.log.debug("Setting gui for Vamsas update "
2406 + (b ? "in progress" : "finished"));
2408 if (vamUpdate != null)
2410 this.removeProgressPanel(vamUpdate);
2414 vamUpdate = this.addProgressPanel(
2415 MessageManager.getString("label.updating_vamsas_session"));
2417 vamsasStart.setVisible(!b);
2418 vamsasStop.setVisible(!b);
2419 vamsasSave.setVisible(!b);
2422 public JInternalFrame[] getAllFrames()
2424 return desktop.getAllFrames();
2428 * Checks the given url to see if it gives a response indicating that the user
2429 * should be informed of a new questionnaire.
2433 public void checkForQuestionnaire(String url)
2435 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2436 // javax.swing.SwingUtilities.invokeLater(jvq);
2437 new Thread(jvq).start();
2440 public void checkURLLinks()
2442 // Thread off the URL link checker
2443 addDialogThread(new Runnable()
2448 if (Cache.getDefault("CHECKURLLINKS", true))
2450 // check what the actual links are - if it's just the default don't
2451 // bother with the warning
2452 List<String> links = Preferences.sequenceUrlLinks
2455 // only need to check links if there is one with a
2456 // SEQUENCE_ID which is not the default EMBL_EBI link
2457 ListIterator<String> li = links.listIterator();
2458 boolean check = false;
2459 List<JLabel> urls = new ArrayList<>();
2460 while (li.hasNext())
2462 String link = li.next();
2463 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2464 && !UrlConstants.isDefaultString(link))
2467 int barPos = link.indexOf("|");
2468 String urlMsg = barPos == -1 ? link
2469 : link.substring(0, barPos) + ": "
2470 + link.substring(barPos + 1);
2471 urls.add(new JLabel(urlMsg));
2479 // ask user to check in case URL links use old style tokens
2480 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2481 JPanel msgPanel = new JPanel();
2482 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2483 msgPanel.add(Box.createVerticalGlue());
2484 JLabel msg = new JLabel(MessageManager
2485 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2486 JLabel msg2 = new JLabel(MessageManager
2487 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2489 for (JLabel url : urls)
2495 final JCheckBox jcb = new JCheckBox(
2496 MessageManager.getString("label.do_not_display_again"));
2497 jcb.addActionListener(new ActionListener()
2500 public void actionPerformed(ActionEvent e)
2502 // update Cache settings for "don't show this again"
2503 boolean showWarningAgain = !jcb.isSelected();
2504 Cache.setProperty("CHECKURLLINKS",
2505 Boolean.valueOf(showWarningAgain).toString());
2510 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2512 .getString("label.SEQUENCE_ID_no_longer_used"),
2513 JvOptionPane.WARNING_MESSAGE);
2520 * Proxy class for JDesktopPane which optionally displays the current memory
2521 * usage and highlights the desktop area with a red bar if free memory runs
2526 public class MyDesktopPane extends JDesktopPane implements Runnable
2529 private static final float ONE_MB = 1048576f;
2531 boolean showMemoryUsage = false;
2535 java.text.NumberFormat df;
2537 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2540 public MyDesktopPane(boolean showMemoryUsage)
2542 showMemoryUsage(showMemoryUsage);
2545 public void showMemoryUsage(boolean showMemory)
2547 this.showMemoryUsage = showMemory;
2550 Thread worker = new Thread(this);
2556 public boolean isShowMemoryUsage()
2558 return showMemoryUsage;
2564 df = java.text.NumberFormat.getNumberInstance();
2565 df.setMaximumFractionDigits(2);
2566 runtime = Runtime.getRuntime();
2568 while (showMemoryUsage)
2572 maxMemory = runtime.maxMemory() / ONE_MB;
2573 allocatedMemory = runtime.totalMemory() / ONE_MB;
2574 freeMemory = runtime.freeMemory() / ONE_MB;
2575 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2577 percentUsage = (totalFreeMemory / maxMemory) * 100;
2579 // if (percentUsage < 20)
2581 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2583 // instance.set.setBorder(border1);
2586 // sleep after showing usage
2588 } catch (Exception ex)
2590 ex.printStackTrace();
2596 public void paintComponent(Graphics g)
2598 if (showMemoryUsage && g != null && df != null)
2600 if (percentUsage < 20)
2602 g.setColor(Color.red);
2604 FontMetrics fm = g.getFontMetrics();
2607 g.drawString(MessageManager.formatMessage("label.memory_stats",
2609 { df.format(totalFreeMemory), df.format(maxMemory),
2610 df.format(percentUsage) }),
2611 10, getHeight() - fm.getHeight());
2618 * Accessor method to quickly get all the AlignmentFrames loaded.
2620 * @return an array of AlignFrame, or null if none found
2622 public static AlignFrame[] getAlignFrames()
2624 if (Jalview.isHeadlessMode())
2626 // Desktop.desktop is null in headless mode
2627 return new AlignFrame[] { Jalview.currentAlignFrame };
2630 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2636 List<AlignFrame> avp = new ArrayList<>();
2638 for (int i = frames.length - 1; i > -1; i--)
2640 if (frames[i] instanceof AlignFrame)
2642 avp.add((AlignFrame) frames[i]);
2644 else if (frames[i] instanceof SplitFrame)
2647 * Also check for a split frame containing an AlignFrame
2649 GSplitFrame sf = (GSplitFrame) frames[i];
2650 if (sf.getTopFrame() instanceof AlignFrame)
2652 avp.add((AlignFrame) sf.getTopFrame());
2654 if (sf.getBottomFrame() instanceof AlignFrame)
2656 avp.add((AlignFrame) sf.getBottomFrame());
2660 if (avp.size() == 0)
2664 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2669 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2673 public GStructureViewer[] getJmols()
2675 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2681 List<GStructureViewer> avp = new ArrayList<>();
2683 for (int i = frames.length - 1; i > -1; i--)
2685 if (frames[i] instanceof AppJmol)
2687 GStructureViewer af = (GStructureViewer) frames[i];
2691 if (avp.size() == 0)
2695 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2700 * Add Groovy Support to Jalview
2703 public void groovyShell_actionPerformed()
2707 openGroovyConsole();
2708 } catch (Exception ex)
2710 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2711 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2713 MessageManager.getString("label.couldnt_create_groovy_shell"),
2714 MessageManager.getString("label.groovy_support_failed"),
2715 JvOptionPane.ERROR_MESSAGE);
2720 * Open the Groovy console
2722 void openGroovyConsole()
2724 if (groovyConsole == null)
2726 groovyConsole = new groovy.ui.Console();
2727 groovyConsole.setVariable("Jalview", this);
2728 groovyConsole.run();
2731 * We allow only one console at a time, so that AlignFrame menu option
2732 * 'Calculate | Run Groovy script' is unambiguous.
2733 * Disable 'Groovy Console', and enable 'Run script', when the console is
2734 * opened, and the reverse when it is closed
2736 Window window = (Window) groovyConsole.getFrame();
2737 window.addWindowListener(new WindowAdapter()
2740 public void windowClosed(WindowEvent e)
2743 * rebind CMD-Q from Groovy Console to Jalview Quit
2746 enableExecuteGroovy(false);
2752 * show Groovy console window (after close and reopen)
2754 ((Window) groovyConsole.getFrame()).setVisible(true);
2757 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2758 * and disable opening a second console
2760 enableExecuteGroovy(true);
2764 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2765 * binding when opened
2767 protected void addQuitHandler()
2769 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2770 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2771 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2773 getRootPane().getActionMap().put("Quit", new AbstractAction()
2776 public void actionPerformed(ActionEvent e)
2784 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2787 * true if Groovy console is open
2789 public void enableExecuteGroovy(boolean enabled)
2792 * disable opening a second Groovy console
2793 * (or re-enable when the console is closed)
2795 groovyShell.setEnabled(!enabled);
2797 AlignFrame[] alignFrames = getAlignFrames();
2798 if (alignFrames != null)
2800 for (AlignFrame af : alignFrames)
2802 af.setGroovyEnabled(enabled);
2808 * Progress bars managed by the IProgressIndicator method.
2810 private Hashtable<Long, JPanel> progressBars;
2812 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2817 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2820 public void setProgressBar(String message, long id)
2822 if (progressBars == null)
2824 progressBars = new Hashtable<>();
2825 progressBarHandlers = new Hashtable<>();
2828 if (progressBars.get(Long.valueOf(id)) != null)
2830 JPanel panel = progressBars.remove(Long.valueOf(id));
2831 if (progressBarHandlers.contains(Long.valueOf(id)))
2833 progressBarHandlers.remove(Long.valueOf(id));
2835 removeProgressPanel(panel);
2839 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2846 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2847 * jalview.gui.IProgressIndicatorHandler)
2850 public void registerHandler(final long id,
2851 final IProgressIndicatorHandler handler)
2853 if (progressBarHandlers == null
2854 || !progressBars.containsKey(Long.valueOf(id)))
2856 throw new Error(MessageManager.getString(
2857 "error.call_setprogressbar_before_registering_handler"));
2859 progressBarHandlers.put(Long.valueOf(id), handler);
2860 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2861 if (handler.canCancel())
2863 JButton cancel = new JButton(
2864 MessageManager.getString("action.cancel"));
2865 final IProgressIndicator us = this;
2866 cancel.addActionListener(new ActionListener()
2870 public void actionPerformed(ActionEvent e)
2872 handler.cancelActivity(id);
2873 us.setProgressBar(MessageManager
2874 .formatMessage("label.cancelled_params", new Object[]
2875 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2879 progressPanel.add(cancel, BorderLayout.EAST);
2885 * @return true if any progress bars are still active
2888 public boolean operationInProgress()
2890 if (progressBars != null && progressBars.size() > 0)
2898 * This will return the first AlignFrame holding the given viewport instance.
2899 * It will break if there are more than one AlignFrames viewing a particular
2903 * @return alignFrame for viewport
2905 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2907 if (desktop != null)
2909 AlignmentPanel[] aps = getAlignmentPanels(
2910 viewport.getSequenceSetId());
2911 for (int panel = 0; aps != null && panel < aps.length; panel++)
2913 if (aps[panel] != null && aps[panel].av == viewport)
2915 return aps[panel].alignFrame;
2922 public VamsasApplication getVamsasApplication()
2929 * flag set if jalview GUI is being operated programmatically
2931 private boolean inBatchMode = false;
2934 * check if jalview GUI is being operated programmatically
2936 * @return inBatchMode
2938 public boolean isInBatchMode()
2944 * set flag if jalview GUI is being operated programmatically
2946 * @param inBatchMode
2948 public void setInBatchMode(boolean inBatchMode)
2950 this.inBatchMode = inBatchMode;
2953 public void startServiceDiscovery()
2955 startServiceDiscovery(false);
2958 public void startServiceDiscovery(boolean blocking)
2960 boolean alive = true;
2961 Thread t0 = null, t1 = null, t2 = null;
2962 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2965 // todo: changesupport handlers need to be transferred
2966 if (discoverer == null)
2968 discoverer = new jalview.ws.jws1.Discoverer();
2969 // register PCS handler for desktop.
2970 discoverer.addPropertyChangeListener(changeSupport);
2972 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2973 // until we phase out completely
2974 (t0 = new Thread(discoverer)).start();
2977 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2979 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2980 .startDiscoverer(changeSupport);
2984 // TODO: do rest service discovery
2993 } catch (Exception e)
2996 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2997 || (t3 != null && t3.isAlive())
2998 || (t0 != null && t0.isAlive());
3004 * called to check if the service discovery process completed successfully.
3008 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3010 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3012 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3013 .getErrorMessages();
3016 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3018 if (serviceChangedDialog == null)
3020 // only run if we aren't already displaying one of these.
3021 addDialogThread(serviceChangedDialog = new Runnable()
3028 * JalviewDialog jd =new JalviewDialog() {
3030 * @Override protected void cancelPressed() { // TODO
3031 * Auto-generated method stub
3033 * }@Override protected void okPressed() { // TODO
3034 * Auto-generated method stub
3036 * }@Override protected void raiseClosed() { // TODO
3037 * Auto-generated method stub
3039 * } }; jd.initDialogFrame(new
3040 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3041 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3042 * + " or mis-configured HTTP proxy settings.<br/>" +
3043 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3045 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3046 * ), true, true, "Web Service Configuration Problem", 450,
3049 * jd.waitForInput();
3051 JvOptionPane.showConfirmDialog(Desktop.desktop,
3052 new JLabel("<html><table width=\"450\"><tr><td>"
3053 + ermsg + "</td></tr></table>"
3054 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3055 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3056 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3057 + " Tools->Preferences dialog box to change them.</p></html>"),
3058 "Web Service Configuration Problem",
3059 JvOptionPane.DEFAULT_OPTION,
3060 JvOptionPane.ERROR_MESSAGE);
3061 serviceChangedDialog = null;
3070 "Errors reported by JABA discovery service. Check web services preferences.\n"
3077 private Runnable serviceChangedDialog = null;
3080 * start a thread to open a URL in the configured browser. Pops up a warning
3081 * dialog to the user if there is an exception when calling out to the browser
3086 public static void showUrl(final String url)
3088 showUrl(url, Desktop.instance);
3092 * Like showUrl but allows progress handler to be specified
3096 * (null) or object implementing IProgressIndicator
3098 public static void showUrl(final String url,
3099 final IProgressIndicator progress)
3101 new Thread(new Runnable()
3108 if (progress != null)
3110 progress.setProgressBar(MessageManager
3111 .formatMessage("status.opening_params", new Object[]
3112 { url }), this.hashCode());
3114 jalview.util.BrowserLauncher.openURL(url);
3115 } catch (Exception ex)
3117 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3119 .getString("label.web_browser_not_found_unix"),
3120 MessageManager.getString("label.web_browser_not_found"),
3121 JvOptionPane.WARNING_MESSAGE);
3123 ex.printStackTrace();
3125 if (progress != null)
3127 progress.setProgressBar(null, this.hashCode());
3133 public static WsParamSetManager wsparamManager = null;
3135 public static ParamManager getUserParameterStore()
3137 if (wsparamManager == null)
3139 wsparamManager = new WsParamSetManager();
3141 return wsparamManager;
3145 * static hyperlink handler proxy method for use by Jalview's internal windows
3149 public static void hyperlinkUpdate(HyperlinkEvent e)
3151 if (e.getEventType() == EventType.ACTIVATED)
3156 url = e.getURL().toString();
3157 Desktop.showUrl(url);
3158 } catch (Exception x)
3162 if (Cache.log != null)
3164 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3169 "Couldn't handle string " + url + " as a URL.");
3172 // ignore any exceptions due to dud links.
3179 * single thread that handles display of dialogs to user.
3181 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3184 * flag indicating if dialogExecutor should try to acquire a permit
3186 private volatile boolean dialogPause = true;
3191 private java.util.concurrent.Semaphore block = new Semaphore(0);
3193 private static groovy.ui.Console groovyConsole;
3196 * add another dialog thread to the queue
3200 public void addDialogThread(final Runnable prompter)
3202 dialogExecutor.submit(new Runnable()
3212 } catch (InterruptedException x)
3217 if (instance == null)
3223 SwingUtilities.invokeAndWait(prompter);
3224 } catch (Exception q)
3226 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3232 public void startDialogQueue()
3234 // set the flag so we don't pause waiting for another permit and semaphore
3235 // the current task to begin
3236 dialogPause = false;
3241 protected void snapShotWindow_actionPerformed(ActionEvent e)
3245 ImageMaker im = new jalview.util.ImageMaker(
3246 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3247 getHeight(), of = new File("Jalview_snapshot"
3248 + System.currentTimeMillis() + ".eps"),
3249 "View of desktop", null, 0, false);
3252 paintAll(im.getGraphics());
3254 } catch (Exception q)
3256 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3260 Cache.log.info("Successfully written snapshot to file "
3261 + of.getAbsolutePath());
3265 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3266 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3267 * and location last time the view was expanded (if any). However it does not
3268 * remember the split pane divider location - this is set to match the
3269 * 'exploding' frame.
3273 public void explodeViews(SplitFrame sf)
3275 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3276 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3277 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3279 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3281 int viewCount = topPanels.size();
3288 * Processing in reverse order works, forwards order leaves the first panels
3289 * not visible. I don't know why!
3291 for (int i = viewCount - 1; i >= 0; i--)
3294 * Make new top and bottom frames. These take over the respective
3295 * AlignmentPanel objects, including their AlignmentViewports, so the
3296 * cdna/protein relationships between the viewports is carried over to the
3299 * explodedGeometry holds the (x, y) position of the previously exploded
3300 * SplitFrame, and the (width, height) of the AlignFrame component
3302 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3303 AlignFrame newTopFrame = new AlignFrame(topPanel);
3304 newTopFrame.setSize(oldTopFrame.getSize());
3305 newTopFrame.setVisible(true);
3306 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3307 .getExplodedGeometry();
3308 if (geometry != null)
3310 newTopFrame.setSize(geometry.getSize());
3313 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3314 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3315 newBottomFrame.setSize(oldBottomFrame.getSize());
3316 newBottomFrame.setVisible(true);
3317 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3318 .getExplodedGeometry();
3319 if (geometry != null)
3321 newBottomFrame.setSize(geometry.getSize());
3324 topPanel.av.setGatherViewsHere(false);
3325 bottomPanel.av.setGatherViewsHere(false);
3326 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3328 if (geometry != null)
3330 splitFrame.setLocation(geometry.getLocation());
3332 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3336 * Clear references to the panels (now relocated in the new SplitFrames)
3337 * before closing the old SplitFrame.
3340 bottomPanels.clear();
3345 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3346 * back into the given SplitFrame as additional views. Note that the gathered
3347 * frames may themselves have multiple views.
3351 public void gatherViews(GSplitFrame source)
3354 * special handling of explodedGeometry for a view within a SplitFrame: - it
3355 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3356 * height) of the AlignFrame component
3358 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3359 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3360 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3361 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3362 myBottomFrame.viewport
3363 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3364 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3365 myTopFrame.viewport.setGatherViewsHere(true);
3366 myBottomFrame.viewport.setGatherViewsHere(true);
3367 String topViewId = myTopFrame.viewport.getSequenceSetId();
3368 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3370 JInternalFrame[] frames = desktop.getAllFrames();
3371 for (JInternalFrame frame : frames)
3373 if (frame instanceof SplitFrame && frame != source)
3375 SplitFrame sf = (SplitFrame) frame;
3376 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3377 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3378 boolean gatherThis = false;
3379 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3381 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3382 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3383 if (topViewId.equals(topPanel.av.getSequenceSetId())
3384 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3387 topPanel.av.setGatherViewsHere(false);
3388 bottomPanel.av.setGatherViewsHere(false);
3389 topPanel.av.setExplodedGeometry(
3390 new Rectangle(sf.getLocation(), topFrame.getSize()));
3391 bottomPanel.av.setExplodedGeometry(
3392 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3393 myTopFrame.addAlignmentPanel(topPanel, false);
3394 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3400 topFrame.getAlignPanels().clear();
3401 bottomFrame.getAlignPanels().clear();
3408 * The dust settles...give focus to the tab we did this from.
3410 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3413 public static groovy.ui.Console getGroovyConsole()
3415 return groovyConsole;
3419 * handles the payload of a drag and drop event.
3421 * TODO refactor to desktop utilities class
3424 * - Data source strings extracted from the drop event
3426 * - protocol for each data source extracted from the drop event
3430 * - the payload from the drop event
3433 public static void transferFromDropTarget(List<String> files,
3434 List<DataSourceType> protocols, DropTargetDropEvent evt,
3435 Transferable t) throws Exception
3438 DataFlavor uriListFlavor = new DataFlavor(
3439 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3442 urlFlavour = new DataFlavor(
3443 "application/x-java-url; class=java.net.URL");
3444 } catch (ClassNotFoundException cfe)
3446 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3449 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3454 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3455 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3456 // means url may be null.
3459 protocols.add(DataSourceType.URL);
3460 files.add(url.toString());
3461 Cache.log.debug("Drop handled as URL dataflavor "
3462 + files.get(files.size() - 1));
3467 if (Platform.isAMac())
3470 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3474 } catch (Throwable ex)
3476 Cache.log.debug("URL drop handler failed.", ex);
3479 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3481 // Works on Windows and MacOSX
3482 Cache.log.debug("Drop handled as javaFileListFlavor");
3483 for (Object file : (List) t
3484 .getTransferData(DataFlavor.javaFileListFlavor))
3486 files.add(((File) file).toString());
3487 protocols.add(DataSourceType.FILE);
3492 // Unix like behaviour
3493 boolean added = false;
3495 if (t.isDataFlavorSupported(uriListFlavor))
3497 Cache.log.debug("Drop handled as uriListFlavor");
3498 // This is used by Unix drag system
3499 data = (String) t.getTransferData(uriListFlavor);
3503 // fallback to text: workaround - on OSX where there's a JVM bug
3504 Cache.log.debug("standard URIListFlavor failed. Trying text");
3505 // try text fallback
3506 DataFlavor textDf = new DataFlavor(
3507 "text/plain;class=java.lang.String");
3508 if (t.isDataFlavorSupported(textDf))
3510 data = (String) t.getTransferData(textDf);
3513 Cache.log.debug("Plain text drop content returned "
3514 + (data == null ? "Null - failed" : data));
3519 while (protocols.size() < files.size())
3521 Cache.log.debug("Adding missing FILE protocol for "
3522 + files.get(protocols.size()));
3523 protocols.add(DataSourceType.FILE);
3525 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3526 data, "\r\n"); st.hasMoreTokens();)
3529 String s = st.nextToken();
3530 if (s.startsWith("#"))
3532 // the line is a comment (as per the RFC 2483)
3535 java.net.URI uri = new java.net.URI(s);
3536 if (uri.getScheme().toLowerCase().startsWith("http"))
3538 protocols.add(DataSourceType.URL);
3539 files.add(uri.toString());
3543 // otherwise preserve old behaviour: catch all for file objects
3544 java.io.File file = new java.io.File(uri);
3545 protocols.add(DataSourceType.FILE);
3546 files.add(file.toString());
3551 if (Cache.log.isDebugEnabled())
3553 if (data == null || !added)
3556 if (t.getTransferDataFlavors() != null
3557 && t.getTransferDataFlavors().length > 0)
3560 "Couldn't resolve drop data. Here are the supported flavors:");
3561 for (DataFlavor fl : t.getTransferDataFlavors())
3564 "Supported transfer dataflavor: " + fl.toString());
3565 Object df = t.getTransferData(fl);
3568 Cache.log.debug("Retrieves: " + df);
3572 Cache.log.debug("Retrieved nothing");
3578 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3584 if (Platform.isWindows())
3587 Cache.log.debug("Scanning dropped content for Windows Link Files");
3589 // resolve any .lnk files in the file drop
3590 for (int f = 0; f < files.size(); f++)
3592 String source = files.get(f).toLowerCase();
3593 if (protocols.get(f).equals(DataSourceType.FILE)
3594 && (source.endsWith(".lnk") || source.endsWith(".url")
3595 || source.endsWith(".site")))
3599 File lf = new File(files.get(f));
3600 // process link file to get a URL
3601 Cache.log.debug("Found potential link file: " + lf);
3602 WindowsShortcut wscfile = new WindowsShortcut(lf);
3603 String fullname = wscfile.getRealFilename();
3604 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3605 files.set(f, fullname);
3606 Cache.log.debug("Parsed real filename " + fullname
3607 + " to extract protocol: " + protocols.get(f));
3608 } catch (Exception ex)
3611 "Couldn't parse " + files.get(f) + " as a link file.",
3620 * Sets the Preferences property for experimental features to True or False
3621 * depending on the state of the controlling menu item
3624 protected void showExperimental_actionPerformed(boolean selected)
3626 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3630 * Answers a (possibly empty) list of any structure viewer frames (currently
3631 * for either Jmol or Chimera) which are currently open. This may optionally
3632 * be restricted to viewers of a specified class, or viewers linked to a
3633 * specified alignment panel.
3636 * if not null, only return viewers linked to this panel
3637 * @param structureViewerClass
3638 * if not null, only return viewers of this class
3641 public List<StructureViewerBase> getStructureViewers(
3642 AlignmentPanel apanel,
3643 Class<? extends StructureViewerBase> structureViewerClass)
3645 List<StructureViewerBase> result = new ArrayList<>();
3646 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3648 for (JInternalFrame frame : frames)
3650 if (frame instanceof StructureViewerBase)
3652 if (structureViewerClass == null
3653 || structureViewerClass.isInstance(frame))
3656 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3658 result.add((StructureViewerBase) frame);