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
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 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1303 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1305 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1306 screen.height + "");
1307 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1308 getWidth(), getHeight()));
1310 if (jconsole != null)
1312 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1313 jconsole.stopConsole();
1317 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1320 if (dialogExecutor != null)
1322 dialogExecutor.shutdownNow();
1324 closeAll_actionPerformed(null);
1326 if (groovyConsole != null)
1328 // suppress a possible repeat prompt to save script
1329 groovyConsole.setDirty(false);
1330 groovyConsole.exit();
1335 private void storeLastKnownDimensions(String string, Rectangle jc)
1337 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1338 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1339 + " height:" + jc.height);
1341 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1342 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1343 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1344 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1354 public void aboutMenuItem_actionPerformed(ActionEvent e)
1356 // StringBuffer message = getAboutMessage(false);
1357 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1359 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1360 new Thread(new Runnable()
1365 new SplashScreen(true);
1370 public StringBuffer getAboutMessage(boolean shortv)
1372 StringBuffer message = new StringBuffer();
1373 message.append("<html>");
1376 message.append("<h1><strong>Version: "
1377 + jalview.bin.Cache.getProperty("VERSION")
1378 + "</strong></h1>");
1379 message.append("<strong>Last Updated: <em>"
1380 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1381 + "</em></strong>");
1387 message.append("<strong>Version "
1388 + jalview.bin.Cache.getProperty("VERSION")
1389 + "; last updated: "
1390 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1393 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1394 .equals("Checking"))
1396 message.append("<br>...Checking latest version...</br>");
1398 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1399 .equals(jalview.bin.Cache.getProperty("VERSION")))
1401 boolean red = false;
1402 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1403 .indexOf("automated build") == -1)
1406 // Displayed when code version and jnlp version do not match and code
1407 // version is not a development build
1408 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1411 message.append("<br>!! Version "
1412 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1414 + " is available for download from "
1415 + jalview.bin.Cache.getDefault("www.jalview.org",
1416 "http://www.jalview.org")
1420 message.append("</div>");
1423 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1425 "The Jalview Authors (See AUTHORS file for current list)")
1426 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1427 + "<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"
1428 + "<br><br>If you use Jalview, please cite:"
1429 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1430 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1431 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1443 public void documentationMenuItem_actionPerformed(ActionEvent e)
1447 Help.showHelpWindow();
1448 } catch (Exception ex)
1454 public void closeAll_actionPerformed(ActionEvent e)
1456 // TODO show a progress bar while closing?
1457 JInternalFrame[] frames = desktop.getAllFrames();
1458 for (int i = 0; i < frames.length; i++)
1462 frames[i].setClosed(true);
1463 } catch (java.beans.PropertyVetoException ex)
1467 Jalview.setCurrentAlignFrame(null);
1468 System.out.println("ALL CLOSED");
1469 if (v_client != null)
1471 // TODO clear binding to vamsas document objects on close_all
1475 * reset state of singleton objects as appropriate (clear down session state
1476 * when all windows are closed)
1478 StructureSelectionManager ssm = StructureSelectionManager
1479 .getStructureSelectionManager(this);
1487 public void raiseRelated_actionPerformed(ActionEvent e)
1489 reorderAssociatedWindows(false, false);
1493 public void minimizeAssociated_actionPerformed(ActionEvent e)
1495 reorderAssociatedWindows(true, false);
1498 void closeAssociatedWindows()
1500 reorderAssociatedWindows(false, true);
1506 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1510 protected void garbageCollect_actionPerformed(ActionEvent e)
1512 // We simply collect the garbage
1513 jalview.bin.Cache.log.debug("Collecting garbage...");
1515 jalview.bin.Cache.log.debug("Finished garbage collection.");
1522 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1526 protected void showMemusage_actionPerformed(ActionEvent e)
1528 desktop.showMemoryUsage(showMemusage.isSelected());
1535 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1539 protected void showConsole_actionPerformed(ActionEvent e)
1541 showConsole(showConsole.isSelected());
1544 Console jconsole = null;
1547 * control whether the java console is visible or not
1551 void showConsole(boolean selected)
1553 showConsole.setSelected(selected);
1554 // TODO: decide if we should update properties file
1555 Cache.setProperty("SHOW_JAVA_CONSOLE",
1556 Boolean.valueOf(selected).toString());
1557 jconsole.setVisible(selected);
1560 void reorderAssociatedWindows(boolean minimize, boolean close)
1562 JInternalFrame[] frames = desktop.getAllFrames();
1563 if (frames == null || frames.length < 1)
1568 AlignViewportI source = null;
1569 AlignViewportI target = null;
1570 if (frames[0] instanceof AlignFrame)
1572 source = ((AlignFrame) frames[0]).getCurrentView();
1574 else if (frames[0] instanceof TreePanel)
1576 source = ((TreePanel) frames[0]).getViewPort();
1578 else if (frames[0] instanceof PCAPanel)
1580 source = ((PCAPanel) frames[0]).av;
1582 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1584 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1589 for (int i = 0; i < frames.length; i++)
1592 if (frames[i] == null)
1596 if (frames[i] instanceof AlignFrame)
1598 target = ((AlignFrame) frames[i]).getCurrentView();
1600 else if (frames[i] instanceof TreePanel)
1602 target = ((TreePanel) frames[i]).getViewPort();
1604 else if (frames[i] instanceof PCAPanel)
1606 target = ((PCAPanel) frames[i]).av;
1608 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1610 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1613 if (source == target)
1619 frames[i].setClosed(true);
1623 frames[i].setIcon(minimize);
1626 frames[i].toFront();
1630 } catch (java.beans.PropertyVetoException ex)
1645 protected void preferences_actionPerformed(ActionEvent e)
1651 * Shows a file chooser dialog and writes out the current session as a Jalview
1655 public void saveState_actionPerformed()
1657 saveState_actionPerformed(false);
1660 public void saveState_actionPerformed(boolean saveAs)
1662 java.io.File projectFile = getProjectFile();
1663 // autoSave indicates we already have a file and don't need to ask
1664 boolean autoSave = projectFile != null && !saveAs
1665 && BackupFiles.getEnabled();
1667 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1668 // saveAs="+saveAs+", Backups
1669 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1671 boolean approveSave = false;
1674 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1677 chooser.setFileView(new JalviewFileView());
1678 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1680 int value = chooser.showSaveDialog(this);
1682 if (value == JalviewFileChooser.APPROVE_OPTION)
1684 projectFile = chooser.getSelectedFile();
1685 setProjectFile(projectFile);
1690 if (approveSave || autoSave)
1692 final Desktop me = this;
1693 final java.io.File chosenFile = projectFile;
1694 new Thread(new Runnable()
1699 // TODO: refactor to Jalview desktop session controller action.
1700 setProgressBar(MessageManager.formatMessage(
1701 "label.saving_jalview_project", new Object[]
1702 { chosenFile.getName() }), chosenFile.hashCode());
1703 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1704 chosenFile.getParent());
1705 // TODO catch and handle errors for savestate
1706 // TODO prevent user from messing with the Desktop whilst we're saving
1709 BackupFiles backupfiles = new BackupFiles(chosenFile);
1711 new Jalview2XML().saveState(backupfiles.getTempFile());
1713 backupfiles.setWriteSuccess(true);
1714 backupfiles.rollBackupsAndRenameTempFile();
1715 } catch (OutOfMemoryError oom)
1717 new OOMWarning("Whilst saving current state to "
1718 + chosenFile.getName(), oom);
1719 } catch (Exception ex)
1721 Cache.log.error("Problems whilst trying to save to "
1722 + chosenFile.getName(), ex);
1723 JvOptionPane.showMessageDialog(me,
1724 MessageManager.formatMessage(
1725 "label.error_whilst_saving_current_state_to",
1727 { chosenFile.getName() }),
1728 MessageManager.getString("label.couldnt_save_project"),
1729 JvOptionPane.WARNING_MESSAGE);
1731 setProgressBar(null, chosenFile.hashCode());
1738 public void saveAsState_actionPerformed(ActionEvent e)
1740 saveState_actionPerformed(true);
1743 private void setProjectFile(File choice)
1745 this.projectFile = choice;
1748 public File getProjectFile()
1750 return this.projectFile;
1754 * Shows a file chooser dialog and tries to read in the selected file as a
1758 public void loadState_actionPerformed()
1760 final String[] suffix = new String[] { "jvp", "jar" };
1761 final String[] desc = new String[] { "Jalview Project",
1762 "Jalview Project (old)" };
1763 JalviewFileChooser chooser = new JalviewFileChooser(
1764 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1765 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1767 chooser.setFileView(new JalviewFileView());
1768 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1770 int value = chooser.showOpenDialog(this);
1772 if (value == JalviewFileChooser.APPROVE_OPTION)
1774 final File selectedFile = chooser.getSelectedFile();
1775 setProjectFile(selectedFile);
1776 final String choice = selectedFile.getAbsolutePath();
1777 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1778 new Thread(new Runnable()
1783 setProgressBar(MessageManager.formatMessage(
1784 "label.loading_jalview_project", new Object[]
1785 { choice }), choice.hashCode());
1788 new Jalview2XML().loadJalviewAlign(choice);
1789 } catch (OutOfMemoryError oom)
1791 new OOMWarning("Whilst loading project from " + choice, oom);
1792 } catch (Exception ex)
1795 "Problems whilst loading project from " + choice, ex);
1796 JvOptionPane.showMessageDialog(Desktop.desktop,
1797 MessageManager.formatMessage(
1798 "label.error_whilst_loading_project_from",
1801 MessageManager.getString("label.couldnt_load_project"),
1802 JvOptionPane.WARNING_MESSAGE);
1804 setProgressBar(null, choice.hashCode());
1811 public void inputSequence_actionPerformed(ActionEvent e)
1813 new SequenceFetcher(this);
1816 JPanel progressPanel;
1818 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1820 public void startLoading(final String fileName)
1822 if (fileLoadingCount == 0)
1824 fileLoadingPanels.add(addProgressPanel(MessageManager
1825 .formatMessage("label.loading_file", new Object[]
1831 private JPanel addProgressPanel(String string)
1833 if (progressPanel == null)
1835 progressPanel = new JPanel(new GridLayout(1, 1));
1836 totalProgressCount = 0;
1837 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1839 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1840 JProgressBar progressBar = new JProgressBar();
1841 progressBar.setIndeterminate(true);
1843 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1845 thisprogress.add(progressBar, BorderLayout.CENTER);
1846 progressPanel.add(thisprogress);
1847 ((GridLayout) progressPanel.getLayout()).setRows(
1848 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1849 ++totalProgressCount;
1850 instance.validate();
1851 return thisprogress;
1854 int totalProgressCount = 0;
1856 private void removeProgressPanel(JPanel progbar)
1858 if (progressPanel != null)
1860 synchronized (progressPanel)
1862 progressPanel.remove(progbar);
1863 GridLayout gl = (GridLayout) progressPanel.getLayout();
1864 gl.setRows(gl.getRows() - 1);
1865 if (--totalProgressCount < 1)
1867 this.getContentPane().remove(progressPanel);
1868 progressPanel = null;
1875 public void stopLoading()
1878 if (fileLoadingCount < 1)
1880 while (fileLoadingPanels.size() > 0)
1882 removeProgressPanel(fileLoadingPanels.remove(0));
1884 fileLoadingPanels.clear();
1885 fileLoadingCount = 0;
1890 public static int getViewCount(String alignmentId)
1892 AlignmentViewport[] aps = getViewports(alignmentId);
1893 return (aps == null) ? 0 : aps.length;
1898 * @param alignmentId
1899 * - if null, all sets are returned
1900 * @return all AlignmentPanels concerning the alignmentId sequence set
1902 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1904 if (Desktop.desktop == null)
1906 // no frames created and in headless mode
1907 // TODO: verify that frames are recoverable when in headless mode
1910 List<AlignmentPanel> aps = new ArrayList<>();
1911 AlignFrame[] frames = getAlignFrames();
1916 for (AlignFrame af : frames)
1918 for (AlignmentPanel ap : af.alignPanels)
1920 if (alignmentId == null
1921 || alignmentId.equals(ap.av.getSequenceSetId()))
1927 if (aps.size() == 0)
1931 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1936 * get all the viewports on an alignment.
1938 * @param sequenceSetId
1939 * unique alignment id (may be null - all viewports returned in that
1941 * @return all viewports on the alignment bound to sequenceSetId
1943 public static AlignmentViewport[] getViewports(String sequenceSetId)
1945 List<AlignmentViewport> viewp = new ArrayList<>();
1946 if (desktop != null)
1948 AlignFrame[] frames = Desktop.getAlignFrames();
1950 for (AlignFrame afr : frames)
1952 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1953 .equals(sequenceSetId))
1955 if (afr.alignPanels != null)
1957 for (AlignmentPanel ap : afr.alignPanels)
1959 if (sequenceSetId == null
1960 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1968 viewp.add(afr.getViewport());
1972 if (viewp.size() > 0)
1974 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1981 * Explode the views in the given frame into separate AlignFrame
1985 public static void explodeViews(AlignFrame af)
1987 int size = af.alignPanels.size();
1993 for (int i = 0; i < size; i++)
1995 AlignmentPanel ap = af.alignPanels.get(i);
1996 AlignFrame newaf = new AlignFrame(ap);
1999 * Restore the view's last exploded frame geometry if known. Multiple
2000 * views from one exploded frame share and restore the same (frame)
2001 * position and size.
2003 Rectangle geometry = ap.av.getExplodedGeometry();
2004 if (geometry != null)
2006 newaf.setBounds(geometry);
2009 ap.av.setGatherViewsHere(false);
2011 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2012 AlignFrame.DEFAULT_HEIGHT);
2015 af.alignPanels.clear();
2016 af.closeMenuItem_actionPerformed(true);
2021 * Gather expanded views (separate AlignFrame's) with the same sequence set
2022 * identifier back in to this frame as additional views, and close the
2023 * expanded views. Note the expanded frames may themselves have multiple
2024 * views. We take the lot.
2028 public void gatherViews(AlignFrame source)
2030 source.viewport.setGatherViewsHere(true);
2031 source.viewport.setExplodedGeometry(source.getBounds());
2032 JInternalFrame[] frames = desktop.getAllFrames();
2033 String viewId = source.viewport.getSequenceSetId();
2035 for (int t = 0; t < frames.length; t++)
2037 if (frames[t] instanceof AlignFrame && frames[t] != source)
2039 AlignFrame af = (AlignFrame) frames[t];
2040 boolean gatherThis = false;
2041 for (int a = 0; a < af.alignPanels.size(); a++)
2043 AlignmentPanel ap = af.alignPanels.get(a);
2044 if (viewId.equals(ap.av.getSequenceSetId()))
2047 ap.av.setGatherViewsHere(false);
2048 ap.av.setExplodedGeometry(af.getBounds());
2049 source.addAlignmentPanel(ap, false);
2055 af.alignPanels.clear();
2056 af.closeMenuItem_actionPerformed(true);
2063 jalview.gui.VamsasApplication v_client = null;
2066 public void vamsasImport_actionPerformed(ActionEvent e)
2068 if (v_client == null)
2070 // Load and try to start a session.
2071 JalviewFileChooser chooser = new JalviewFileChooser(
2072 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2074 chooser.setFileView(new JalviewFileView());
2075 chooser.setDialogTitle(
2076 MessageManager.getString("label.open_saved_vamsas_session"));
2077 chooser.setToolTipText(MessageManager.getString(
2078 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2080 int value = chooser.showOpenDialog(this);
2082 if (value == JalviewFileChooser.APPROVE_OPTION)
2084 String fle = chooser.getSelectedFile().toString();
2085 if (!vamsasImport(chooser.getSelectedFile()))
2087 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2088 MessageManager.formatMessage(
2089 "label.couldnt_import_as_vamsas_session",
2093 .getString("label.vamsas_document_import_failed"),
2094 JvOptionPane.ERROR_MESSAGE);
2100 jalview.bin.Cache.log.error(
2101 "Implementation error - load session from a running session is not supported.");
2106 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2109 * @return true if import was a success and a session was started.
2111 public boolean vamsasImport(URL url)
2113 // TODO: create progress bar
2114 if (v_client != null)
2117 jalview.bin.Cache.log.error(
2118 "Implementation error - load session from a running session is not supported.");
2124 // copy the URL content to a temporary local file
2125 // TODO: be a bit cleverer here with nio (?!)
2126 File file = File.createTempFile("vdocfromurl", ".vdj");
2127 FileOutputStream fos = new FileOutputStream(file);
2128 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2129 byte[] buffer = new byte[2048];
2131 while ((ln = bis.read(buffer)) > -1)
2133 fos.write(buffer, 0, ln);
2137 v_client = new jalview.gui.VamsasApplication(this, file,
2138 url.toExternalForm());
2139 } catch (Exception ex)
2141 jalview.bin.Cache.log.error(
2142 "Failed to create new vamsas session from contents of URL "
2147 setupVamsasConnectedGui();
2148 v_client.initial_update(); // TODO: thread ?
2149 return v_client.inSession();
2153 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2156 * @return true if import was a success and a session was started.
2158 public boolean vamsasImport(File file)
2160 if (v_client != null)
2163 jalview.bin.Cache.log.error(
2164 "Implementation error - load session from a running session is not supported.");
2168 setProgressBar(MessageManager.formatMessage(
2169 "status.importing_vamsas_session_from", new Object[]
2170 { file.getName() }), file.hashCode());
2173 v_client = new jalview.gui.VamsasApplication(this, file, null);
2174 } catch (Exception ex)
2176 setProgressBar(MessageManager.formatMessage(
2177 "status.importing_vamsas_session_from", new Object[]
2178 { file.getName() }), file.hashCode());
2179 jalview.bin.Cache.log.error(
2180 "New vamsas session from existing session file failed:", ex);
2183 setupVamsasConnectedGui();
2184 v_client.initial_update(); // TODO: thread ?
2185 setProgressBar(MessageManager.formatMessage(
2186 "status.importing_vamsas_session_from", new Object[]
2187 { file.getName() }), file.hashCode());
2188 return v_client.inSession();
2191 public boolean joinVamsasSession(String mysesid)
2193 if (v_client != null)
2195 throw new Error(MessageManager
2196 .getString("error.try_join_vamsas_session_another"));
2198 if (mysesid == null)
2201 MessageManager.getString("error.invalid_vamsas_session_id"));
2203 v_client = new VamsasApplication(this, mysesid);
2204 setupVamsasConnectedGui();
2205 v_client.initial_update();
2206 return (v_client.inSession());
2210 public void vamsasStart_actionPerformed(ActionEvent e)
2212 if (v_client == null)
2215 // we just start a default session for moment.
2217 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2218 * getProperty("LAST_DIRECTORY"));
2220 * chooser.setFileView(new JalviewFileView());
2221 * chooser.setDialogTitle("Load Vamsas file");
2222 * chooser.setToolTipText("Import");
2224 * int value = chooser.showOpenDialog(this);
2226 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2227 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2229 v_client = new VamsasApplication(this);
2230 setupVamsasConnectedGui();
2231 v_client.initial_update(); // TODO: thread ?
2235 // store current data in session.
2236 v_client.push_update(); // TODO: thread
2240 protected void setupVamsasConnectedGui()
2242 vamsasStart.setText(MessageManager.getString("label.session_update"));
2243 vamsasSave.setVisible(true);
2244 vamsasStop.setVisible(true);
2245 vamsasImport.setVisible(false); // Document import to existing session is
2246 // not possible for vamsas-client-1.0.
2249 protected void setupVamsasDisconnectedGui()
2251 vamsasSave.setVisible(false);
2252 vamsasStop.setVisible(false);
2253 vamsasImport.setVisible(true);
2255 .setText(MessageManager.getString("label.new_vamsas_session"));
2259 public void vamsasStop_actionPerformed(ActionEvent e)
2261 if (v_client != null)
2263 v_client.end_session();
2265 setupVamsasDisconnectedGui();
2269 protected void buildVamsasStMenu()
2271 if (v_client == null)
2273 String[] sess = null;
2276 sess = VamsasApplication.getSessionList();
2277 } catch (Exception e)
2279 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2285 jalview.bin.Cache.log.debug(
2286 "Got current sessions list: " + sess.length + " entries.");
2287 VamsasStMenu.removeAll();
2288 for (int i = 0; i < sess.length; i++)
2290 JMenuItem sessit = new JMenuItem();
2291 sessit.setText(sess[i]);
2292 sessit.setToolTipText(MessageManager
2293 .formatMessage("label.connect_to_session", new Object[]
2295 final Desktop dsktp = this;
2296 final String mysesid = sess[i];
2297 sessit.addActionListener(new ActionListener()
2301 public void actionPerformed(ActionEvent e)
2303 if (dsktp.v_client == null)
2305 Thread rthr = new Thread(new Runnable()
2311 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2312 dsktp.setupVamsasConnectedGui();
2313 dsktp.v_client.initial_update();
2321 VamsasStMenu.add(sessit);
2323 // don't show an empty menu.
2324 VamsasStMenu.setVisible(sess.length > 0);
2329 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2330 VamsasStMenu.removeAll();
2331 VamsasStMenu.setVisible(false);
2336 // Not interested in the content. Just hide ourselves.
2337 VamsasStMenu.setVisible(false);
2342 public void vamsasSave_actionPerformed(ActionEvent e)
2344 if (v_client != null)
2346 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2347 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2350 chooser.setFileView(new JalviewFileView());
2351 chooser.setDialogTitle(MessageManager
2352 .getString("label.save_vamsas_document_archive"));
2354 int value = chooser.showSaveDialog(this);
2356 if (value == JalviewFileChooser.APPROVE_OPTION)
2358 java.io.File choice = chooser.getSelectedFile();
2359 JPanel progpanel = addProgressPanel(MessageManager
2360 .formatMessage("label.saving_vamsas_doc", new Object[]
2361 { choice.getName() }));
2362 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2363 String warnmsg = null;
2364 String warnttl = null;
2367 v_client.vclient.storeDocument(choice);
2370 warnttl = "Serious Problem saving Vamsas Document";
2371 warnmsg = ex.toString();
2372 jalview.bin.Cache.log
2373 .error("Error Whilst saving document to " + choice, ex);
2375 } catch (Exception ex)
2377 warnttl = "Problem saving Vamsas Document.";
2378 warnmsg = ex.toString();
2379 jalview.bin.Cache.log.warn(
2380 "Exception Whilst saving document to " + choice, ex);
2383 removeProgressPanel(progpanel);
2384 if (warnmsg != null)
2386 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2388 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2394 JPanel vamUpdate = null;
2397 * hide vamsas user gui bits when a vamsas document event is being handled.
2400 * true to hide gui, false to reveal gui
2402 public void setVamsasUpdate(boolean b)
2404 Cache.log.debug("Setting gui for Vamsas update "
2405 + (b ? "in progress" : "finished"));
2407 if (vamUpdate != null)
2409 this.removeProgressPanel(vamUpdate);
2413 vamUpdate = this.addProgressPanel(
2414 MessageManager.getString("label.updating_vamsas_session"));
2416 vamsasStart.setVisible(!b);
2417 vamsasStop.setVisible(!b);
2418 vamsasSave.setVisible(!b);
2421 public JInternalFrame[] getAllFrames()
2423 return desktop.getAllFrames();
2427 * Checks the given url to see if it gives a response indicating that the user
2428 * should be informed of a new questionnaire.
2432 public void checkForQuestionnaire(String url)
2434 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2435 // javax.swing.SwingUtilities.invokeLater(jvq);
2436 new Thread(jvq).start();
2439 public void checkURLLinks()
2441 // Thread off the URL link checker
2442 addDialogThread(new Runnable()
2447 if (Cache.getDefault("CHECKURLLINKS", true))
2449 // check what the actual links are - if it's just the default don't
2450 // bother with the warning
2451 List<String> links = Preferences.sequenceUrlLinks
2454 // only need to check links if there is one with a
2455 // SEQUENCE_ID which is not the default EMBL_EBI link
2456 ListIterator<String> li = links.listIterator();
2457 boolean check = false;
2458 List<JLabel> urls = new ArrayList<>();
2459 while (li.hasNext())
2461 String link = li.next();
2462 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2463 && !UrlConstants.isDefaultString(link))
2466 int barPos = link.indexOf("|");
2467 String urlMsg = barPos == -1 ? link
2468 : link.substring(0, barPos) + ": "
2469 + link.substring(barPos + 1);
2470 urls.add(new JLabel(urlMsg));
2478 // ask user to check in case URL links use old style tokens
2479 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2480 JPanel msgPanel = new JPanel();
2481 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2482 msgPanel.add(Box.createVerticalGlue());
2483 JLabel msg = new JLabel(MessageManager
2484 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2485 JLabel msg2 = new JLabel(MessageManager
2486 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2488 for (JLabel url : urls)
2494 final JCheckBox jcb = new JCheckBox(
2495 MessageManager.getString("label.do_not_display_again"));
2496 jcb.addActionListener(new ActionListener()
2499 public void actionPerformed(ActionEvent e)
2501 // update Cache settings for "don't show this again"
2502 boolean showWarningAgain = !jcb.isSelected();
2503 Cache.setProperty("CHECKURLLINKS",
2504 Boolean.valueOf(showWarningAgain).toString());
2509 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2511 .getString("label.SEQUENCE_ID_no_longer_used"),
2512 JvOptionPane.WARNING_MESSAGE);
2519 * Proxy class for JDesktopPane which optionally displays the current memory
2520 * usage and highlights the desktop area with a red bar if free memory runs
2525 public class MyDesktopPane extends JDesktopPane implements Runnable
2528 private static final float ONE_MB = 1048576f;
2530 boolean showMemoryUsage = false;
2534 java.text.NumberFormat df;
2536 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2539 public MyDesktopPane(boolean showMemoryUsage)
2541 showMemoryUsage(showMemoryUsage);
2544 public void showMemoryUsage(boolean showMemory)
2546 this.showMemoryUsage = showMemory;
2549 Thread worker = new Thread(this);
2555 public boolean isShowMemoryUsage()
2557 return showMemoryUsage;
2563 df = java.text.NumberFormat.getNumberInstance();
2564 df.setMaximumFractionDigits(2);
2565 runtime = Runtime.getRuntime();
2567 while (showMemoryUsage)
2571 maxMemory = runtime.maxMemory() / ONE_MB;
2572 allocatedMemory = runtime.totalMemory() / ONE_MB;
2573 freeMemory = runtime.freeMemory() / ONE_MB;
2574 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2576 percentUsage = (totalFreeMemory / maxMemory) * 100;
2578 // if (percentUsage < 20)
2580 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2582 // instance.set.setBorder(border1);
2585 // sleep after showing usage
2587 } catch (Exception ex)
2589 ex.printStackTrace();
2595 public void paintComponent(Graphics g)
2597 if (showMemoryUsage && g != null && df != null)
2599 if (percentUsage < 20)
2601 g.setColor(Color.red);
2603 FontMetrics fm = g.getFontMetrics();
2606 g.drawString(MessageManager.formatMessage("label.memory_stats",
2608 { df.format(totalFreeMemory), df.format(maxMemory),
2609 df.format(percentUsage) }),
2610 10, getHeight() - fm.getHeight());
2617 * Accessor method to quickly get all the AlignmentFrames loaded.
2619 * @return an array of AlignFrame, or null if none found
2621 public static AlignFrame[] getAlignFrames()
2623 if (Jalview.isHeadlessMode())
2625 // Desktop.desktop is null in headless mode
2626 return new AlignFrame[] { Jalview.currentAlignFrame };
2629 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2635 List<AlignFrame> avp = new ArrayList<>();
2637 for (int i = frames.length - 1; i > -1; i--)
2639 if (frames[i] instanceof AlignFrame)
2641 avp.add((AlignFrame) frames[i]);
2643 else if (frames[i] instanceof SplitFrame)
2646 * Also check for a split frame containing an AlignFrame
2648 GSplitFrame sf = (GSplitFrame) frames[i];
2649 if (sf.getTopFrame() instanceof AlignFrame)
2651 avp.add((AlignFrame) sf.getTopFrame());
2653 if (sf.getBottomFrame() instanceof AlignFrame)
2655 avp.add((AlignFrame) sf.getBottomFrame());
2659 if (avp.size() == 0)
2663 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2668 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2672 public GStructureViewer[] getJmols()
2674 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2680 List<GStructureViewer> avp = new ArrayList<>();
2682 for (int i = frames.length - 1; i > -1; i--)
2684 if (frames[i] instanceof AppJmol)
2686 GStructureViewer af = (GStructureViewer) frames[i];
2690 if (avp.size() == 0)
2694 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2699 * Add Groovy Support to Jalview
2702 public void groovyShell_actionPerformed()
2706 openGroovyConsole();
2707 } catch (Exception ex)
2709 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2710 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2712 MessageManager.getString("label.couldnt_create_groovy_shell"),
2713 MessageManager.getString("label.groovy_support_failed"),
2714 JvOptionPane.ERROR_MESSAGE);
2719 * Open the Groovy console
2721 void openGroovyConsole()
2723 if (groovyConsole == null)
2725 groovyConsole = new groovy.ui.Console();
2726 groovyConsole.setVariable("Jalview", this);
2727 groovyConsole.run();
2730 * We allow only one console at a time, so that AlignFrame menu option
2731 * 'Calculate | Run Groovy script' is unambiguous.
2732 * Disable 'Groovy Console', and enable 'Run script', when the console is
2733 * opened, and the reverse when it is closed
2735 Window window = (Window) groovyConsole.getFrame();
2736 window.addWindowListener(new WindowAdapter()
2739 public void windowClosed(WindowEvent e)
2742 * rebind CMD-Q from Groovy Console to Jalview Quit
2745 enableExecuteGroovy(false);
2751 * show Groovy console window (after close and reopen)
2753 ((Window) groovyConsole.getFrame()).setVisible(true);
2756 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2757 * and disable opening a second console
2759 enableExecuteGroovy(true);
2763 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2764 * binding when opened
2766 protected void addQuitHandler()
2768 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2769 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2770 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2772 getRootPane().getActionMap().put("Quit", new AbstractAction()
2775 public void actionPerformed(ActionEvent e)
2783 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2786 * true if Groovy console is open
2788 public void enableExecuteGroovy(boolean enabled)
2791 * disable opening a second Groovy console
2792 * (or re-enable when the console is closed)
2794 groovyShell.setEnabled(!enabled);
2796 AlignFrame[] alignFrames = getAlignFrames();
2797 if (alignFrames != null)
2799 for (AlignFrame af : alignFrames)
2801 af.setGroovyEnabled(enabled);
2807 * Progress bars managed by the IProgressIndicator method.
2809 private Hashtable<Long, JPanel> progressBars;
2811 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2816 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2819 public void setProgressBar(String message, long id)
2821 if (progressBars == null)
2823 progressBars = new Hashtable<>();
2824 progressBarHandlers = new Hashtable<>();
2827 if (progressBars.get(Long.valueOf(id)) != null)
2829 JPanel panel = progressBars.remove(Long.valueOf(id));
2830 if (progressBarHandlers.contains(Long.valueOf(id)))
2832 progressBarHandlers.remove(Long.valueOf(id));
2834 removeProgressPanel(panel);
2838 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2845 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2846 * jalview.gui.IProgressIndicatorHandler)
2849 public void registerHandler(final long id,
2850 final IProgressIndicatorHandler handler)
2852 if (progressBarHandlers == null
2853 || !progressBars.containsKey(Long.valueOf(id)))
2855 throw new Error(MessageManager.getString(
2856 "error.call_setprogressbar_before_registering_handler"));
2858 progressBarHandlers.put(Long.valueOf(id), handler);
2859 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2860 if (handler.canCancel())
2862 JButton cancel = new JButton(
2863 MessageManager.getString("action.cancel"));
2864 final IProgressIndicator us = this;
2865 cancel.addActionListener(new ActionListener()
2869 public void actionPerformed(ActionEvent e)
2871 handler.cancelActivity(id);
2872 us.setProgressBar(MessageManager
2873 .formatMessage("label.cancelled_params", new Object[]
2874 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2878 progressPanel.add(cancel, BorderLayout.EAST);
2884 * @return true if any progress bars are still active
2887 public boolean operationInProgress()
2889 if (progressBars != null && progressBars.size() > 0)
2897 * This will return the first AlignFrame holding the given viewport instance.
2898 * It will break if there are more than one AlignFrames viewing a particular
2902 * @return alignFrame for viewport
2904 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2906 if (desktop != null)
2908 AlignmentPanel[] aps = getAlignmentPanels(
2909 viewport.getSequenceSetId());
2910 for (int panel = 0; aps != null && panel < aps.length; panel++)
2912 if (aps[panel] != null && aps[panel].av == viewport)
2914 return aps[panel].alignFrame;
2921 public VamsasApplication getVamsasApplication()
2928 * flag set if jalview GUI is being operated programmatically
2930 private boolean inBatchMode = false;
2933 * check if jalview GUI is being operated programmatically
2935 * @return inBatchMode
2937 public boolean isInBatchMode()
2943 * set flag if jalview GUI is being operated programmatically
2945 * @param inBatchMode
2947 public void setInBatchMode(boolean inBatchMode)
2949 this.inBatchMode = inBatchMode;
2952 public void startServiceDiscovery()
2954 startServiceDiscovery(false);
2957 public void startServiceDiscovery(boolean blocking)
2959 boolean alive = true;
2960 Thread t0 = null, t1 = null, t2 = null;
2961 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2964 // todo: changesupport handlers need to be transferred
2965 if (discoverer == null)
2967 discoverer = new jalview.ws.jws1.Discoverer();
2968 // register PCS handler for desktop.
2969 discoverer.addPropertyChangeListener(changeSupport);
2971 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2972 // until we phase out completely
2973 (t0 = new Thread(discoverer)).start();
2976 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2978 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2979 .startDiscoverer(changeSupport);
2983 // TODO: do rest service discovery
2992 } catch (Exception e)
2995 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2996 || (t3 != null && t3.isAlive())
2997 || (t0 != null && t0.isAlive());
3003 * called to check if the service discovery process completed successfully.
3007 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3009 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3011 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3012 .getErrorMessages();
3015 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3017 if (serviceChangedDialog == null)
3019 // only run if we aren't already displaying one of these.
3020 addDialogThread(serviceChangedDialog = new Runnable()
3027 * JalviewDialog jd =new JalviewDialog() {
3029 * @Override protected void cancelPressed() { // TODO
3030 * Auto-generated method stub
3032 * }@Override protected void okPressed() { // TODO
3033 * Auto-generated method stub
3035 * }@Override protected void raiseClosed() { // TODO
3036 * Auto-generated method stub
3038 * } }; jd.initDialogFrame(new
3039 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3040 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3041 * + " or mis-configured HTTP proxy settings.<br/>" +
3042 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3044 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3045 * ), true, true, "Web Service Configuration Problem", 450,
3048 * jd.waitForInput();
3050 JvOptionPane.showConfirmDialog(Desktop.desktop,
3051 new JLabel("<html><table width=\"450\"><tr><td>"
3052 + ermsg + "</td></tr></table>"
3053 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3054 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3055 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3056 + " Tools->Preferences dialog box to change them.</p></html>"),
3057 "Web Service Configuration Problem",
3058 JvOptionPane.DEFAULT_OPTION,
3059 JvOptionPane.ERROR_MESSAGE);
3060 serviceChangedDialog = null;
3069 "Errors reported by JABA discovery service. Check web services preferences.\n"
3076 private Runnable serviceChangedDialog = null;
3079 * start a thread to open a URL in the configured browser. Pops up a warning
3080 * dialog to the user if there is an exception when calling out to the browser
3085 public static void showUrl(final String url)
3087 showUrl(url, Desktop.instance);
3091 * Like showUrl but allows progress handler to be specified
3095 * (null) or object implementing IProgressIndicator
3097 public static void showUrl(final String url,
3098 final IProgressIndicator progress)
3100 new Thread(new Runnable()
3107 if (progress != null)
3109 progress.setProgressBar(MessageManager
3110 .formatMessage("status.opening_params", new Object[]
3111 { url }), this.hashCode());
3113 jalview.util.BrowserLauncher.openURL(url);
3114 } catch (Exception ex)
3116 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3118 .getString("label.web_browser_not_found_unix"),
3119 MessageManager.getString("label.web_browser_not_found"),
3120 JvOptionPane.WARNING_MESSAGE);
3122 ex.printStackTrace();
3124 if (progress != null)
3126 progress.setProgressBar(null, this.hashCode());
3132 public static WsParamSetManager wsparamManager = null;
3134 public static ParamManager getUserParameterStore()
3136 if (wsparamManager == null)
3138 wsparamManager = new WsParamSetManager();
3140 return wsparamManager;
3144 * static hyperlink handler proxy method for use by Jalview's internal windows
3148 public static void hyperlinkUpdate(HyperlinkEvent e)
3150 if (e.getEventType() == EventType.ACTIVATED)
3155 url = e.getURL().toString();
3156 Desktop.showUrl(url);
3157 } catch (Exception x)
3161 if (Cache.log != null)
3163 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3168 "Couldn't handle string " + url + " as a URL.");
3171 // ignore any exceptions due to dud links.
3178 * single thread that handles display of dialogs to user.
3180 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3183 * flag indicating if dialogExecutor should try to acquire a permit
3185 private volatile boolean dialogPause = true;
3190 private java.util.concurrent.Semaphore block = new Semaphore(0);
3192 private static groovy.ui.Console groovyConsole;
3195 * add another dialog thread to the queue
3199 public void addDialogThread(final Runnable prompter)
3201 dialogExecutor.submit(new Runnable()
3211 } catch (InterruptedException x)
3216 if (instance == null)
3222 SwingUtilities.invokeAndWait(prompter);
3223 } catch (Exception q)
3225 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3231 public void startDialogQueue()
3233 // set the flag so we don't pause waiting for another permit and semaphore
3234 // the current task to begin
3235 dialogPause = false;
3240 protected void snapShotWindow_actionPerformed(ActionEvent e)
3244 ImageMaker im = new jalview.util.ImageMaker(
3245 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3246 getHeight(), of = new File("Jalview_snapshot"
3247 + System.currentTimeMillis() + ".eps"),
3248 "View of desktop", null, 0, false);
3251 paintAll(im.getGraphics());
3253 } catch (Exception q)
3255 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3259 Cache.log.info("Successfully written snapshot to file "
3260 + of.getAbsolutePath());
3264 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3265 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3266 * and location last time the view was expanded (if any). However it does not
3267 * remember the split pane divider location - this is set to match the
3268 * 'exploding' frame.
3272 public void explodeViews(SplitFrame sf)
3274 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3275 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3276 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3278 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3280 int viewCount = topPanels.size();
3287 * Processing in reverse order works, forwards order leaves the first panels
3288 * not visible. I don't know why!
3290 for (int i = viewCount - 1; i >= 0; i--)
3293 * Make new top and bottom frames. These take over the respective
3294 * AlignmentPanel objects, including their AlignmentViewports, so the
3295 * cdna/protein relationships between the viewports is carried over to the
3298 * explodedGeometry holds the (x, y) position of the previously exploded
3299 * SplitFrame, and the (width, height) of the AlignFrame component
3301 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3302 AlignFrame newTopFrame = new AlignFrame(topPanel);
3303 newTopFrame.setSize(oldTopFrame.getSize());
3304 newTopFrame.setVisible(true);
3305 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3306 .getExplodedGeometry();
3307 if (geometry != null)
3309 newTopFrame.setSize(geometry.getSize());
3312 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3313 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3314 newBottomFrame.setSize(oldBottomFrame.getSize());
3315 newBottomFrame.setVisible(true);
3316 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3317 .getExplodedGeometry();
3318 if (geometry != null)
3320 newBottomFrame.setSize(geometry.getSize());
3323 topPanel.av.setGatherViewsHere(false);
3324 bottomPanel.av.setGatherViewsHere(false);
3325 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3327 if (geometry != null)
3329 splitFrame.setLocation(geometry.getLocation());
3331 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3335 * Clear references to the panels (now relocated in the new SplitFrames)
3336 * before closing the old SplitFrame.
3339 bottomPanels.clear();
3344 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3345 * back into the given SplitFrame as additional views. Note that the gathered
3346 * frames may themselves have multiple views.
3350 public void gatherViews(GSplitFrame source)
3353 * special handling of explodedGeometry for a view within a SplitFrame: - it
3354 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3355 * height) of the AlignFrame component
3357 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3358 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3359 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3360 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3361 myBottomFrame.viewport
3362 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3363 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3364 myTopFrame.viewport.setGatherViewsHere(true);
3365 myBottomFrame.viewport.setGatherViewsHere(true);
3366 String topViewId = myTopFrame.viewport.getSequenceSetId();
3367 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3369 JInternalFrame[] frames = desktop.getAllFrames();
3370 for (JInternalFrame frame : frames)
3372 if (frame instanceof SplitFrame && frame != source)
3374 SplitFrame sf = (SplitFrame) frame;
3375 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3376 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3377 boolean gatherThis = false;
3378 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3380 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3381 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3382 if (topViewId.equals(topPanel.av.getSequenceSetId())
3383 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3386 topPanel.av.setGatherViewsHere(false);
3387 bottomPanel.av.setGatherViewsHere(false);
3388 topPanel.av.setExplodedGeometry(
3389 new Rectangle(sf.getLocation(), topFrame.getSize()));
3390 bottomPanel.av.setExplodedGeometry(
3391 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3392 myTopFrame.addAlignmentPanel(topPanel, false);
3393 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3399 topFrame.getAlignPanels().clear();
3400 bottomFrame.getAlignPanels().clear();
3407 * The dust settles...give focus to the tab we did this from.
3409 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3412 public static groovy.ui.Console getGroovyConsole()
3414 return groovyConsole;
3418 * handles the payload of a drag and drop event.
3420 * TODO refactor to desktop utilities class
3423 * - Data source strings extracted from the drop event
3425 * - protocol for each data source extracted from the drop event
3429 * - the payload from the drop event
3432 public static void transferFromDropTarget(List<String> files,
3433 List<DataSourceType> protocols, DropTargetDropEvent evt,
3434 Transferable t) throws Exception
3437 DataFlavor uriListFlavor = new DataFlavor(
3438 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3441 urlFlavour = new DataFlavor(
3442 "application/x-java-url; class=java.net.URL");
3443 } catch (ClassNotFoundException cfe)
3445 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3448 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3453 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3454 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3455 // means url may be null.
3458 protocols.add(DataSourceType.URL);
3459 files.add(url.toString());
3460 Cache.log.debug("Drop handled as URL dataflavor "
3461 + files.get(files.size() - 1));
3466 if (Platform.isAMac())
3469 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3473 } catch (Throwable ex)
3475 Cache.log.debug("URL drop handler failed.", ex);
3478 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3480 // Works on Windows and MacOSX
3481 Cache.log.debug("Drop handled as javaFileListFlavor");
3482 for (Object file : (List) t
3483 .getTransferData(DataFlavor.javaFileListFlavor))
3485 files.add(((File) file).toString());
3486 protocols.add(DataSourceType.FILE);
3491 // Unix like behaviour
3492 boolean added = false;
3494 if (t.isDataFlavorSupported(uriListFlavor))
3496 Cache.log.debug("Drop handled as uriListFlavor");
3497 // This is used by Unix drag system
3498 data = (String) t.getTransferData(uriListFlavor);
3502 // fallback to text: workaround - on OSX where there's a JVM bug
3503 Cache.log.debug("standard URIListFlavor failed. Trying text");
3504 // try text fallback
3505 DataFlavor textDf = new DataFlavor(
3506 "text/plain;class=java.lang.String");
3507 if (t.isDataFlavorSupported(textDf))
3509 data = (String) t.getTransferData(textDf);
3512 Cache.log.debug("Plain text drop content returned "
3513 + (data == null ? "Null - failed" : data));
3518 while (protocols.size() < files.size())
3520 Cache.log.debug("Adding missing FILE protocol for "
3521 + files.get(protocols.size()));
3522 protocols.add(DataSourceType.FILE);
3524 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3525 data, "\r\n"); st.hasMoreTokens();)
3528 String s = st.nextToken();
3529 if (s.startsWith("#"))
3531 // the line is a comment (as per the RFC 2483)
3534 java.net.URI uri = new java.net.URI(s);
3535 if (uri.getScheme().toLowerCase().startsWith("http"))
3537 protocols.add(DataSourceType.URL);
3538 files.add(uri.toString());
3542 // otherwise preserve old behaviour: catch all for file objects
3543 java.io.File file = new java.io.File(uri);
3544 protocols.add(DataSourceType.FILE);
3545 files.add(file.toString());
3550 if (Cache.log.isDebugEnabled())
3552 if (data == null || !added)
3555 if (t.getTransferDataFlavors() != null
3556 && t.getTransferDataFlavors().length > 0)
3559 "Couldn't resolve drop data. Here are the supported flavors:");
3560 for (DataFlavor fl : t.getTransferDataFlavors())
3563 "Supported transfer dataflavor: " + fl.toString());
3564 Object df = t.getTransferData(fl);
3567 Cache.log.debug("Retrieves: " + df);
3571 Cache.log.debug("Retrieved nothing");
3577 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3583 if (Platform.isWindows())
3586 Cache.log.debug("Scanning dropped content for Windows Link Files");
3588 // resolve any .lnk files in the file drop
3589 for (int f = 0; f < files.size(); f++)
3591 String source = files.get(f).toLowerCase();
3592 if (protocols.get(f).equals(DataSourceType.FILE)
3593 && (source.endsWith(".lnk") || source.endsWith(".url")
3594 || source.endsWith(".site")))
3598 File lf = new File(files.get(f));
3599 // process link file to get a URL
3600 Cache.log.debug("Found potential link file: " + lf);
3601 WindowsShortcut wscfile = new WindowsShortcut(lf);
3602 String fullname = wscfile.getRealFilename();
3603 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3604 files.set(f, fullname);
3605 Cache.log.debug("Parsed real filename " + fullname
3606 + " to extract protocol: " + protocols.get(f));
3607 } catch (Exception ex)
3610 "Couldn't parse " + files.get(f) + " as a link file.",
3619 * Sets the Preferences property for experimental features to True or False
3620 * depending on the state of the controlling menu item
3623 protected void showExperimental_actionPerformed(boolean selected)
3625 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3629 * Answers a (possibly empty) list of any structure viewer frames (currently
3630 * for either Jmol or Chimera) which are currently open. This may optionally
3631 * be restricted to viewers of a specified class, or viewers linked to a
3632 * specified alignment panel.
3635 * if not null, only return viewers linked to this panel
3636 * @param structureViewerClass
3637 * if not null, only return viewers of this class
3640 public List<StructureViewerBase> getStructureViewers(
3641 AlignmentPanel apanel,
3642 Class<? extends StructureViewerBase> structureViewerClass)
3644 List<StructureViewerBase> result = new ArrayList<>();
3645 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3647 for (JInternalFrame frame : frames)
3649 if (frame instanceof StructureViewerBase)
3651 if (structureViewerClass == null
3652 || structureViewerClass.isInstance(frame))
3655 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3657 result.add((StructureViewerBase) frame);