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 AlignmentViewport source = null, target = null;
1569 if (frames[0] instanceof AlignFrame)
1571 source = ((AlignFrame) frames[0]).getCurrentView();
1573 else if (frames[0] instanceof TreePanel)
1575 source = ((TreePanel) frames[0]).getViewPort();
1577 else if (frames[0] instanceof PCAPanel)
1579 source = ((PCAPanel) frames[0]).av;
1581 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1583 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1588 for (int i = 0; i < frames.length; i++)
1591 if (frames[i] == null)
1595 if (frames[i] instanceof AlignFrame)
1597 target = ((AlignFrame) frames[i]).getCurrentView();
1599 else if (frames[i] instanceof TreePanel)
1601 target = ((TreePanel) frames[i]).getViewPort();
1603 else if (frames[i] instanceof PCAPanel)
1605 target = ((PCAPanel) frames[i]).av;
1607 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1609 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1612 if (source == target)
1618 frames[i].setClosed(true);
1622 frames[i].setIcon(minimize);
1625 frames[i].toFront();
1629 } catch (java.beans.PropertyVetoException ex)
1644 protected void preferences_actionPerformed(ActionEvent e)
1650 * Shows a file chooser dialog and writes out the current session as a Jalview
1654 public void saveState_actionPerformed()
1656 saveState_actionPerformed(false);
1659 public void saveState_actionPerformed(boolean saveAs)
1661 java.io.File projectFile = getProjectFile();
1662 // autoSave indicates we already have a file and don't need to ask
1663 boolean autoSave = projectFile != null && !saveAs
1664 && BackupFiles.getEnabled();
1666 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1667 // saveAs="+saveAs+", Backups
1668 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1670 boolean approveSave = false;
1673 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1676 chooser.setFileView(new JalviewFileView());
1677 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1679 int value = chooser.showSaveDialog(this);
1681 if (value == JalviewFileChooser.APPROVE_OPTION)
1683 projectFile = chooser.getSelectedFile();
1684 setProjectFile(projectFile);
1689 if (approveSave || autoSave)
1691 final Desktop me = this;
1692 final java.io.File chosenFile = projectFile;
1693 new Thread(new Runnable()
1698 // TODO: refactor to Jalview desktop session controller action.
1699 setProgressBar(MessageManager.formatMessage(
1700 "label.saving_jalview_project", new Object[]
1701 { chosenFile.getName() }), chosenFile.hashCode());
1702 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1703 chosenFile.getParent());
1704 // TODO catch and handle errors for savestate
1705 // TODO prevent user from messing with the Desktop whilst we're saving
1708 BackupFiles backupfiles = new BackupFiles(chosenFile);
1710 new Jalview2XML().saveState(backupfiles.getTempFile());
1712 backupfiles.setWriteSuccess(true);
1713 backupfiles.rollBackupsAndRenameTempFile();
1714 } catch (OutOfMemoryError oom)
1716 new OOMWarning("Whilst saving current state to "
1717 + chosenFile.getName(), oom);
1718 } catch (Exception ex)
1720 Cache.log.error("Problems whilst trying to save to "
1721 + chosenFile.getName(), ex);
1722 JvOptionPane.showMessageDialog(me,
1723 MessageManager.formatMessage(
1724 "label.error_whilst_saving_current_state_to",
1726 { chosenFile.getName() }),
1727 MessageManager.getString("label.couldnt_save_project"),
1728 JvOptionPane.WARNING_MESSAGE);
1730 setProgressBar(null, chosenFile.hashCode());
1737 public void saveAsState_actionPerformed(ActionEvent e)
1739 saveState_actionPerformed(true);
1742 private void setProjectFile(File choice)
1744 this.projectFile = choice;
1747 public File getProjectFile()
1749 return this.projectFile;
1753 * Shows a file chooser dialog and tries to read in the selected file as a
1757 public void loadState_actionPerformed()
1759 final String[] suffix = new String[] { "jvp", "jar" };
1760 final String[] desc = new String[] { "Jalview Project",
1761 "Jalview Project (old)" };
1762 JalviewFileChooser chooser = new JalviewFileChooser(
1763 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1764 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1766 chooser.setFileView(new JalviewFileView());
1767 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1769 int value = chooser.showOpenDialog(this);
1771 if (value == JalviewFileChooser.APPROVE_OPTION)
1773 final File selectedFile = chooser.getSelectedFile();
1774 setProjectFile(selectedFile);
1775 final String choice = selectedFile.getAbsolutePath();
1776 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1777 new Thread(new Runnable()
1782 setProgressBar(MessageManager.formatMessage(
1783 "label.loading_jalview_project", new Object[]
1784 { choice }), choice.hashCode());
1787 new Jalview2XML().loadJalviewAlign(choice);
1788 } catch (OutOfMemoryError oom)
1790 new OOMWarning("Whilst loading project from " + choice, oom);
1791 } catch (Exception ex)
1794 "Problems whilst loading project from " + choice, ex);
1795 JvOptionPane.showMessageDialog(Desktop.desktop,
1796 MessageManager.formatMessage(
1797 "label.error_whilst_loading_project_from",
1800 MessageManager.getString("label.couldnt_load_project"),
1801 JvOptionPane.WARNING_MESSAGE);
1803 setProgressBar(null, choice.hashCode());
1810 public void inputSequence_actionPerformed(ActionEvent e)
1812 new SequenceFetcher(this);
1815 JPanel progressPanel;
1817 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1819 public void startLoading(final String fileName)
1821 if (fileLoadingCount == 0)
1823 fileLoadingPanels.add(addProgressPanel(MessageManager
1824 .formatMessage("label.loading_file", new Object[]
1830 private JPanel addProgressPanel(String string)
1832 if (progressPanel == null)
1834 progressPanel = new JPanel(new GridLayout(1, 1));
1835 totalProgressCount = 0;
1836 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1838 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1839 JProgressBar progressBar = new JProgressBar();
1840 progressBar.setIndeterminate(true);
1842 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1844 thisprogress.add(progressBar, BorderLayout.CENTER);
1845 progressPanel.add(thisprogress);
1846 ((GridLayout) progressPanel.getLayout()).setRows(
1847 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1848 ++totalProgressCount;
1849 instance.validate();
1850 return thisprogress;
1853 int totalProgressCount = 0;
1855 private void removeProgressPanel(JPanel progbar)
1857 if (progressPanel != null)
1859 synchronized (progressPanel)
1861 progressPanel.remove(progbar);
1862 GridLayout gl = (GridLayout) progressPanel.getLayout();
1863 gl.setRows(gl.getRows() - 1);
1864 if (--totalProgressCount < 1)
1866 this.getContentPane().remove(progressPanel);
1867 progressPanel = null;
1874 public void stopLoading()
1877 if (fileLoadingCount < 1)
1879 while (fileLoadingPanels.size() > 0)
1881 removeProgressPanel(fileLoadingPanels.remove(0));
1883 fileLoadingPanels.clear();
1884 fileLoadingCount = 0;
1889 public static int getViewCount(String alignmentId)
1891 AlignmentViewport[] aps = getViewports(alignmentId);
1892 return (aps == null) ? 0 : aps.length;
1897 * @param alignmentId
1898 * - if null, all sets are returned
1899 * @return all AlignmentPanels concerning the alignmentId sequence set
1901 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1903 if (Desktop.desktop == null)
1905 // no frames created and in headless mode
1906 // TODO: verify that frames are recoverable when in headless mode
1909 List<AlignmentPanel> aps = new ArrayList<>();
1910 AlignFrame[] frames = getAlignFrames();
1915 for (AlignFrame af : frames)
1917 for (AlignmentPanel ap : af.alignPanels)
1919 if (alignmentId == null
1920 || alignmentId.equals(ap.av.getSequenceSetId()))
1926 if (aps.size() == 0)
1930 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1935 * get all the viewports on an alignment.
1937 * @param sequenceSetId
1938 * unique alignment id (may be null - all viewports returned in that
1940 * @return all viewports on the alignment bound to sequenceSetId
1942 public static AlignmentViewport[] getViewports(String sequenceSetId)
1944 List<AlignmentViewport> viewp = new ArrayList<>();
1945 if (desktop != null)
1947 AlignFrame[] frames = Desktop.getAlignFrames();
1949 for (AlignFrame afr : frames)
1951 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1952 .equals(sequenceSetId))
1954 if (afr.alignPanels != null)
1956 for (AlignmentPanel ap : afr.alignPanels)
1958 if (sequenceSetId == null
1959 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1967 viewp.add(afr.getViewport());
1971 if (viewp.size() > 0)
1973 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1980 * Explode the views in the given frame into separate AlignFrame
1984 public static void explodeViews(AlignFrame af)
1986 int size = af.alignPanels.size();
1992 for (int i = 0; i < size; i++)
1994 AlignmentPanel ap = af.alignPanels.get(i);
1995 AlignFrame newaf = new AlignFrame(ap);
1998 * Restore the view's last exploded frame geometry if known. Multiple
1999 * views from one exploded frame share and restore the same (frame)
2000 * position and size.
2002 Rectangle geometry = ap.av.getExplodedGeometry();
2003 if (geometry != null)
2005 newaf.setBounds(geometry);
2008 ap.av.setGatherViewsHere(false);
2010 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2011 AlignFrame.DEFAULT_HEIGHT);
2014 af.alignPanels.clear();
2015 af.closeMenuItem_actionPerformed(true);
2020 * Gather expanded views (separate AlignFrame's) with the same sequence set
2021 * identifier back in to this frame as additional views, and close the
2022 * expanded views. Note the expanded frames may themselves have multiple
2023 * views. We take the lot.
2027 public void gatherViews(AlignFrame source)
2029 source.viewport.setGatherViewsHere(true);
2030 source.viewport.setExplodedGeometry(source.getBounds());
2031 JInternalFrame[] frames = desktop.getAllFrames();
2032 String viewId = source.viewport.getSequenceSetId();
2034 for (int t = 0; t < frames.length; t++)
2036 if (frames[t] instanceof AlignFrame && frames[t] != source)
2038 AlignFrame af = (AlignFrame) frames[t];
2039 boolean gatherThis = false;
2040 for (int a = 0; a < af.alignPanels.size(); a++)
2042 AlignmentPanel ap = af.alignPanels.get(a);
2043 if (viewId.equals(ap.av.getSequenceSetId()))
2046 ap.av.setGatherViewsHere(false);
2047 ap.av.setExplodedGeometry(af.getBounds());
2048 source.addAlignmentPanel(ap, false);
2054 af.alignPanels.clear();
2055 af.closeMenuItem_actionPerformed(true);
2062 jalview.gui.VamsasApplication v_client = null;
2065 public void vamsasImport_actionPerformed(ActionEvent e)
2067 if (v_client == null)
2069 // Load and try to start a session.
2070 JalviewFileChooser chooser = new JalviewFileChooser(
2071 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2073 chooser.setFileView(new JalviewFileView());
2074 chooser.setDialogTitle(
2075 MessageManager.getString("label.open_saved_vamsas_session"));
2076 chooser.setToolTipText(MessageManager.getString(
2077 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2079 int value = chooser.showOpenDialog(this);
2081 if (value == JalviewFileChooser.APPROVE_OPTION)
2083 String fle = chooser.getSelectedFile().toString();
2084 if (!vamsasImport(chooser.getSelectedFile()))
2086 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2087 MessageManager.formatMessage(
2088 "label.couldnt_import_as_vamsas_session",
2092 .getString("label.vamsas_document_import_failed"),
2093 JvOptionPane.ERROR_MESSAGE);
2099 jalview.bin.Cache.log.error(
2100 "Implementation error - load session from a running session is not supported.");
2105 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2108 * @return true if import was a success and a session was started.
2110 public boolean vamsasImport(URL url)
2112 // TODO: create progress bar
2113 if (v_client != null)
2116 jalview.bin.Cache.log.error(
2117 "Implementation error - load session from a running session is not supported.");
2123 // copy the URL content to a temporary local file
2124 // TODO: be a bit cleverer here with nio (?!)
2125 File file = File.createTempFile("vdocfromurl", ".vdj");
2126 FileOutputStream fos = new FileOutputStream(file);
2127 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2128 byte[] buffer = new byte[2048];
2130 while ((ln = bis.read(buffer)) > -1)
2132 fos.write(buffer, 0, ln);
2136 v_client = new jalview.gui.VamsasApplication(this, file,
2137 url.toExternalForm());
2138 } catch (Exception ex)
2140 jalview.bin.Cache.log.error(
2141 "Failed to create new vamsas session from contents of URL "
2146 setupVamsasConnectedGui();
2147 v_client.initial_update(); // TODO: thread ?
2148 return v_client.inSession();
2152 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2155 * @return true if import was a success and a session was started.
2157 public boolean vamsasImport(File file)
2159 if (v_client != null)
2162 jalview.bin.Cache.log.error(
2163 "Implementation error - load session from a running session is not supported.");
2167 setProgressBar(MessageManager.formatMessage(
2168 "status.importing_vamsas_session_from", new Object[]
2169 { file.getName() }), file.hashCode());
2172 v_client = new jalview.gui.VamsasApplication(this, file, null);
2173 } catch (Exception ex)
2175 setProgressBar(MessageManager.formatMessage(
2176 "status.importing_vamsas_session_from", new Object[]
2177 { file.getName() }), file.hashCode());
2178 jalview.bin.Cache.log.error(
2179 "New vamsas session from existing session file failed:", ex);
2182 setupVamsasConnectedGui();
2183 v_client.initial_update(); // TODO: thread ?
2184 setProgressBar(MessageManager.formatMessage(
2185 "status.importing_vamsas_session_from", new Object[]
2186 { file.getName() }), file.hashCode());
2187 return v_client.inSession();
2190 public boolean joinVamsasSession(String mysesid)
2192 if (v_client != null)
2194 throw new Error(MessageManager
2195 .getString("error.try_join_vamsas_session_another"));
2197 if (mysesid == null)
2200 MessageManager.getString("error.invalid_vamsas_session_id"));
2202 v_client = new VamsasApplication(this, mysesid);
2203 setupVamsasConnectedGui();
2204 v_client.initial_update();
2205 return (v_client.inSession());
2209 public void vamsasStart_actionPerformed(ActionEvent e)
2211 if (v_client == null)
2214 // we just start a default session for moment.
2216 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2217 * getProperty("LAST_DIRECTORY"));
2219 * chooser.setFileView(new JalviewFileView());
2220 * chooser.setDialogTitle("Load Vamsas file");
2221 * chooser.setToolTipText("Import");
2223 * int value = chooser.showOpenDialog(this);
2225 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2226 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2228 v_client = new VamsasApplication(this);
2229 setupVamsasConnectedGui();
2230 v_client.initial_update(); // TODO: thread ?
2234 // store current data in session.
2235 v_client.push_update(); // TODO: thread
2239 protected void setupVamsasConnectedGui()
2241 vamsasStart.setText(MessageManager.getString("label.session_update"));
2242 vamsasSave.setVisible(true);
2243 vamsasStop.setVisible(true);
2244 vamsasImport.setVisible(false); // Document import to existing session is
2245 // not possible for vamsas-client-1.0.
2248 protected void setupVamsasDisconnectedGui()
2250 vamsasSave.setVisible(false);
2251 vamsasStop.setVisible(false);
2252 vamsasImport.setVisible(true);
2254 .setText(MessageManager.getString("label.new_vamsas_session"));
2258 public void vamsasStop_actionPerformed(ActionEvent e)
2260 if (v_client != null)
2262 v_client.end_session();
2264 setupVamsasDisconnectedGui();
2268 protected void buildVamsasStMenu()
2270 if (v_client == null)
2272 String[] sess = null;
2275 sess = VamsasApplication.getSessionList();
2276 } catch (Exception e)
2278 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2284 jalview.bin.Cache.log.debug(
2285 "Got current sessions list: " + sess.length + " entries.");
2286 VamsasStMenu.removeAll();
2287 for (int i = 0; i < sess.length; i++)
2289 JMenuItem sessit = new JMenuItem();
2290 sessit.setText(sess[i]);
2291 sessit.setToolTipText(MessageManager
2292 .formatMessage("label.connect_to_session", new Object[]
2294 final Desktop dsktp = this;
2295 final String mysesid = sess[i];
2296 sessit.addActionListener(new ActionListener()
2300 public void actionPerformed(ActionEvent e)
2302 if (dsktp.v_client == null)
2304 Thread rthr = new Thread(new Runnable()
2310 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2311 dsktp.setupVamsasConnectedGui();
2312 dsktp.v_client.initial_update();
2320 VamsasStMenu.add(sessit);
2322 // don't show an empty menu.
2323 VamsasStMenu.setVisible(sess.length > 0);
2328 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2329 VamsasStMenu.removeAll();
2330 VamsasStMenu.setVisible(false);
2335 // Not interested in the content. Just hide ourselves.
2336 VamsasStMenu.setVisible(false);
2341 public void vamsasSave_actionPerformed(ActionEvent e)
2343 if (v_client != null)
2345 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2346 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2349 chooser.setFileView(new JalviewFileView());
2350 chooser.setDialogTitle(MessageManager
2351 .getString("label.save_vamsas_document_archive"));
2353 int value = chooser.showSaveDialog(this);
2355 if (value == JalviewFileChooser.APPROVE_OPTION)
2357 java.io.File choice = chooser.getSelectedFile();
2358 JPanel progpanel = addProgressPanel(MessageManager
2359 .formatMessage("label.saving_vamsas_doc", new Object[]
2360 { choice.getName() }));
2361 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2362 String warnmsg = null;
2363 String warnttl = null;
2366 v_client.vclient.storeDocument(choice);
2369 warnttl = "Serious Problem saving Vamsas Document";
2370 warnmsg = ex.toString();
2371 jalview.bin.Cache.log
2372 .error("Error Whilst saving document to " + choice, ex);
2374 } catch (Exception ex)
2376 warnttl = "Problem saving Vamsas Document.";
2377 warnmsg = ex.toString();
2378 jalview.bin.Cache.log.warn(
2379 "Exception Whilst saving document to " + choice, ex);
2382 removeProgressPanel(progpanel);
2383 if (warnmsg != null)
2385 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2387 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2393 JPanel vamUpdate = null;
2396 * hide vamsas user gui bits when a vamsas document event is being handled.
2399 * true to hide gui, false to reveal gui
2401 public void setVamsasUpdate(boolean b)
2403 Cache.log.debug("Setting gui for Vamsas update "
2404 + (b ? "in progress" : "finished"));
2406 if (vamUpdate != null)
2408 this.removeProgressPanel(vamUpdate);
2412 vamUpdate = this.addProgressPanel(
2413 MessageManager.getString("label.updating_vamsas_session"));
2415 vamsasStart.setVisible(!b);
2416 vamsasStop.setVisible(!b);
2417 vamsasSave.setVisible(!b);
2420 public JInternalFrame[] getAllFrames()
2422 return desktop.getAllFrames();
2426 * Checks the given url to see if it gives a response indicating that the user
2427 * should be informed of a new questionnaire.
2431 public void checkForQuestionnaire(String url)
2433 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2434 // javax.swing.SwingUtilities.invokeLater(jvq);
2435 new Thread(jvq).start();
2438 public void checkURLLinks()
2440 // Thread off the URL link checker
2441 addDialogThread(new Runnable()
2446 if (Cache.getDefault("CHECKURLLINKS", true))
2448 // check what the actual links are - if it's just the default don't
2449 // bother with the warning
2450 List<String> links = Preferences.sequenceUrlLinks
2453 // only need to check links if there is one with a
2454 // SEQUENCE_ID which is not the default EMBL_EBI link
2455 ListIterator<String> li = links.listIterator();
2456 boolean check = false;
2457 List<JLabel> urls = new ArrayList<>();
2458 while (li.hasNext())
2460 String link = li.next();
2461 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2462 && !UrlConstants.isDefaultString(link))
2465 int barPos = link.indexOf("|");
2466 String urlMsg = barPos == -1 ? link
2467 : link.substring(0, barPos) + ": "
2468 + link.substring(barPos + 1);
2469 urls.add(new JLabel(urlMsg));
2477 // ask user to check in case URL links use old style tokens
2478 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2479 JPanel msgPanel = new JPanel();
2480 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2481 msgPanel.add(Box.createVerticalGlue());
2482 JLabel msg = new JLabel(MessageManager
2483 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2484 JLabel msg2 = new JLabel(MessageManager
2485 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2487 for (JLabel url : urls)
2493 final JCheckBox jcb = new JCheckBox(
2494 MessageManager.getString("label.do_not_display_again"));
2495 jcb.addActionListener(new ActionListener()
2498 public void actionPerformed(ActionEvent e)
2500 // update Cache settings for "don't show this again"
2501 boolean showWarningAgain = !jcb.isSelected();
2502 Cache.setProperty("CHECKURLLINKS",
2503 Boolean.valueOf(showWarningAgain).toString());
2508 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2510 .getString("label.SEQUENCE_ID_no_longer_used"),
2511 JvOptionPane.WARNING_MESSAGE);
2518 * Proxy class for JDesktopPane which optionally displays the current memory
2519 * usage and highlights the desktop area with a red bar if free memory runs
2524 public class MyDesktopPane extends JDesktopPane implements Runnable
2527 private static final float ONE_MB = 1048576f;
2529 boolean showMemoryUsage = false;
2533 java.text.NumberFormat df;
2535 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2538 public MyDesktopPane(boolean showMemoryUsage)
2540 showMemoryUsage(showMemoryUsage);
2543 public void showMemoryUsage(boolean showMemory)
2545 this.showMemoryUsage = showMemory;
2548 Thread worker = new Thread(this);
2554 public boolean isShowMemoryUsage()
2556 return showMemoryUsage;
2562 df = java.text.NumberFormat.getNumberInstance();
2563 df.setMaximumFractionDigits(2);
2564 runtime = Runtime.getRuntime();
2566 while (showMemoryUsage)
2570 maxMemory = runtime.maxMemory() / ONE_MB;
2571 allocatedMemory = runtime.totalMemory() / ONE_MB;
2572 freeMemory = runtime.freeMemory() / ONE_MB;
2573 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2575 percentUsage = (totalFreeMemory / maxMemory) * 100;
2577 // if (percentUsage < 20)
2579 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2581 // instance.set.setBorder(border1);
2584 // sleep after showing usage
2586 } catch (Exception ex)
2588 ex.printStackTrace();
2594 public void paintComponent(Graphics g)
2596 if (showMemoryUsage && g != null && df != null)
2598 if (percentUsage < 20)
2600 g.setColor(Color.red);
2602 FontMetrics fm = g.getFontMetrics();
2605 g.drawString(MessageManager.formatMessage("label.memory_stats",
2607 { df.format(totalFreeMemory), df.format(maxMemory),
2608 df.format(percentUsage) }),
2609 10, getHeight() - fm.getHeight());
2616 * Accessor method to quickly get all the AlignmentFrames loaded.
2618 * @return an array of AlignFrame, or null if none found
2620 public static AlignFrame[] getAlignFrames()
2622 if (Jalview.isHeadlessMode())
2624 // Desktop.desktop is null in headless mode
2625 return new AlignFrame[] { Jalview.currentAlignFrame };
2628 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2634 List<AlignFrame> avp = new ArrayList<>();
2636 for (int i = frames.length - 1; i > -1; i--)
2638 if (frames[i] instanceof AlignFrame)
2640 avp.add((AlignFrame) frames[i]);
2642 else if (frames[i] instanceof SplitFrame)
2645 * Also check for a split frame containing an AlignFrame
2647 GSplitFrame sf = (GSplitFrame) frames[i];
2648 if (sf.getTopFrame() instanceof AlignFrame)
2650 avp.add((AlignFrame) sf.getTopFrame());
2652 if (sf.getBottomFrame() instanceof AlignFrame)
2654 avp.add((AlignFrame) sf.getBottomFrame());
2658 if (avp.size() == 0)
2662 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2667 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2671 public GStructureViewer[] getJmols()
2673 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2679 List<GStructureViewer> avp = new ArrayList<>();
2681 for (int i = frames.length - 1; i > -1; i--)
2683 if (frames[i] instanceof AppJmol)
2685 GStructureViewer af = (GStructureViewer) frames[i];
2689 if (avp.size() == 0)
2693 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2698 * Add Groovy Support to Jalview
2701 public void groovyShell_actionPerformed()
2705 openGroovyConsole();
2706 } catch (Exception ex)
2708 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2709 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2711 MessageManager.getString("label.couldnt_create_groovy_shell"),
2712 MessageManager.getString("label.groovy_support_failed"),
2713 JvOptionPane.ERROR_MESSAGE);
2718 * Open the Groovy console
2720 void openGroovyConsole()
2722 if (groovyConsole == null)
2724 groovyConsole = new groovy.ui.Console();
2725 groovyConsole.setVariable("Jalview", this);
2726 groovyConsole.run();
2729 * We allow only one console at a time, so that AlignFrame menu option
2730 * 'Calculate | Run Groovy script' is unambiguous.
2731 * Disable 'Groovy Console', and enable 'Run script', when the console is
2732 * opened, and the reverse when it is closed
2734 Window window = (Window) groovyConsole.getFrame();
2735 window.addWindowListener(new WindowAdapter()
2738 public void windowClosed(WindowEvent e)
2741 * rebind CMD-Q from Groovy Console to Jalview Quit
2744 enableExecuteGroovy(false);
2750 * show Groovy console window (after close and reopen)
2752 ((Window) groovyConsole.getFrame()).setVisible(true);
2755 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2756 * and disable opening a second console
2758 enableExecuteGroovy(true);
2762 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2763 * binding when opened
2765 protected void addQuitHandler()
2767 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2768 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2769 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2771 getRootPane().getActionMap().put("Quit", new AbstractAction()
2774 public void actionPerformed(ActionEvent e)
2782 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2785 * true if Groovy console is open
2787 public void enableExecuteGroovy(boolean enabled)
2790 * disable opening a second Groovy console
2791 * (or re-enable when the console is closed)
2793 groovyShell.setEnabled(!enabled);
2795 AlignFrame[] alignFrames = getAlignFrames();
2796 if (alignFrames != null)
2798 for (AlignFrame af : alignFrames)
2800 af.setGroovyEnabled(enabled);
2806 * Progress bars managed by the IProgressIndicator method.
2808 private Hashtable<Long, JPanel> progressBars;
2810 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2815 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2818 public void setProgressBar(String message, long id)
2820 if (progressBars == null)
2822 progressBars = new Hashtable<>();
2823 progressBarHandlers = new Hashtable<>();
2826 if (progressBars.get(Long.valueOf(id)) != null)
2828 JPanel panel = progressBars.remove(Long.valueOf(id));
2829 if (progressBarHandlers.contains(Long.valueOf(id)))
2831 progressBarHandlers.remove(Long.valueOf(id));
2833 removeProgressPanel(panel);
2837 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2844 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2845 * jalview.gui.IProgressIndicatorHandler)
2848 public void registerHandler(final long id,
2849 final IProgressIndicatorHandler handler)
2851 if (progressBarHandlers == null
2852 || !progressBars.containsKey(Long.valueOf(id)))
2854 throw new Error(MessageManager.getString(
2855 "error.call_setprogressbar_before_registering_handler"));
2857 progressBarHandlers.put(Long.valueOf(id), handler);
2858 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2859 if (handler.canCancel())
2861 JButton cancel = new JButton(
2862 MessageManager.getString("action.cancel"));
2863 final IProgressIndicator us = this;
2864 cancel.addActionListener(new ActionListener()
2868 public void actionPerformed(ActionEvent e)
2870 handler.cancelActivity(id);
2871 us.setProgressBar(MessageManager
2872 .formatMessage("label.cancelled_params", new Object[]
2873 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2877 progressPanel.add(cancel, BorderLayout.EAST);
2883 * @return true if any progress bars are still active
2886 public boolean operationInProgress()
2888 if (progressBars != null && progressBars.size() > 0)
2896 * This will return the first AlignFrame holding the given viewport instance.
2897 * It will break if there are more than one AlignFrames viewing a particular
2901 * @return alignFrame for viewport
2903 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2905 if (desktop != null)
2907 AlignmentPanel[] aps = getAlignmentPanels(
2908 viewport.getSequenceSetId());
2909 for (int panel = 0; aps != null && panel < aps.length; panel++)
2911 if (aps[panel] != null && aps[panel].av == viewport)
2913 return aps[panel].alignFrame;
2920 public VamsasApplication getVamsasApplication()
2927 * flag set if jalview GUI is being operated programmatically
2929 private boolean inBatchMode = false;
2932 * check if jalview GUI is being operated programmatically
2934 * @return inBatchMode
2936 public boolean isInBatchMode()
2942 * set flag if jalview GUI is being operated programmatically
2944 * @param inBatchMode
2946 public void setInBatchMode(boolean inBatchMode)
2948 this.inBatchMode = inBatchMode;
2951 public void startServiceDiscovery()
2953 startServiceDiscovery(false);
2956 public void startServiceDiscovery(boolean blocking)
2958 boolean alive = true;
2959 Thread t0 = null, t1 = null, t2 = null;
2960 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2963 // todo: changesupport handlers need to be transferred
2964 if (discoverer == null)
2966 discoverer = new jalview.ws.jws1.Discoverer();
2967 // register PCS handler for desktop.
2968 discoverer.addPropertyChangeListener(changeSupport);
2970 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2971 // until we phase out completely
2972 (t0 = new Thread(discoverer)).start();
2975 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2977 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2978 .startDiscoverer(changeSupport);
2982 // TODO: do rest service discovery
2991 } catch (Exception e)
2994 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2995 || (t3 != null && t3.isAlive())
2996 || (t0 != null && t0.isAlive());
3002 * called to check if the service discovery process completed successfully.
3006 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3008 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3010 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3011 .getErrorMessages();
3014 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3016 if (serviceChangedDialog == null)
3018 // only run if we aren't already displaying one of these.
3019 addDialogThread(serviceChangedDialog = new Runnable()
3026 * JalviewDialog jd =new JalviewDialog() {
3028 * @Override protected void cancelPressed() { // TODO
3029 * Auto-generated method stub
3031 * }@Override protected void okPressed() { // TODO
3032 * Auto-generated method stub
3034 * }@Override protected void raiseClosed() { // TODO
3035 * Auto-generated method stub
3037 * } }; jd.initDialogFrame(new
3038 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3039 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3040 * + " or mis-configured HTTP proxy settings.<br/>" +
3041 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3043 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3044 * ), true, true, "Web Service Configuration Problem", 450,
3047 * jd.waitForInput();
3049 JvOptionPane.showConfirmDialog(Desktop.desktop,
3050 new JLabel("<html><table width=\"450\"><tr><td>"
3051 + ermsg + "</td></tr></table>"
3052 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3053 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3054 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3055 + " Tools->Preferences dialog box to change them.</p></html>"),
3056 "Web Service Configuration Problem",
3057 JvOptionPane.DEFAULT_OPTION,
3058 JvOptionPane.ERROR_MESSAGE);
3059 serviceChangedDialog = null;
3068 "Errors reported by JABA discovery service. Check web services preferences.\n"
3075 private Runnable serviceChangedDialog = null;
3078 * start a thread to open a URL in the configured browser. Pops up a warning
3079 * dialog to the user if there is an exception when calling out to the browser
3084 public static void showUrl(final String url)
3086 showUrl(url, Desktop.instance);
3090 * Like showUrl but allows progress handler to be specified
3094 * (null) or object implementing IProgressIndicator
3096 public static void showUrl(final String url,
3097 final IProgressIndicator progress)
3099 new Thread(new Runnable()
3106 if (progress != null)
3108 progress.setProgressBar(MessageManager
3109 .formatMessage("status.opening_params", new Object[]
3110 { url }), this.hashCode());
3112 jalview.util.BrowserLauncher.openURL(url);
3113 } catch (Exception ex)
3115 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3117 .getString("label.web_browser_not_found_unix"),
3118 MessageManager.getString("label.web_browser_not_found"),
3119 JvOptionPane.WARNING_MESSAGE);
3121 ex.printStackTrace();
3123 if (progress != null)
3125 progress.setProgressBar(null, this.hashCode());
3131 public static WsParamSetManager wsparamManager = null;
3133 public static ParamManager getUserParameterStore()
3135 if (wsparamManager == null)
3137 wsparamManager = new WsParamSetManager();
3139 return wsparamManager;
3143 * static hyperlink handler proxy method for use by Jalview's internal windows
3147 public static void hyperlinkUpdate(HyperlinkEvent e)
3149 if (e.getEventType() == EventType.ACTIVATED)
3154 url = e.getURL().toString();
3155 Desktop.showUrl(url);
3156 } catch (Exception x)
3160 if (Cache.log != null)
3162 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3167 "Couldn't handle string " + url + " as a URL.");
3170 // ignore any exceptions due to dud links.
3177 * single thread that handles display of dialogs to user.
3179 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3182 * flag indicating if dialogExecutor should try to acquire a permit
3184 private volatile boolean dialogPause = true;
3189 private java.util.concurrent.Semaphore block = new Semaphore(0);
3191 private static groovy.ui.Console groovyConsole;
3194 * add another dialog thread to the queue
3198 public void addDialogThread(final Runnable prompter)
3200 dialogExecutor.submit(new Runnable()
3210 } catch (InterruptedException x)
3215 if (instance == null)
3221 SwingUtilities.invokeAndWait(prompter);
3222 } catch (Exception q)
3224 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3230 public void startDialogQueue()
3232 // set the flag so we don't pause waiting for another permit and semaphore
3233 // the current task to begin
3234 dialogPause = false;
3239 protected void snapShotWindow_actionPerformed(ActionEvent e)
3243 ImageMaker im = new jalview.util.ImageMaker(
3244 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3245 getHeight(), of = new File("Jalview_snapshot"
3246 + System.currentTimeMillis() + ".eps"),
3247 "View of desktop", null, 0, false);
3250 paintAll(im.getGraphics());
3252 } catch (Exception q)
3254 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3258 Cache.log.info("Successfully written snapshot to file "
3259 + of.getAbsolutePath());
3263 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3264 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3265 * and location last time the view was expanded (if any). However it does not
3266 * remember the split pane divider location - this is set to match the
3267 * 'exploding' frame.
3271 public void explodeViews(SplitFrame sf)
3273 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3274 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3275 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3277 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3279 int viewCount = topPanels.size();
3286 * Processing in reverse order works, forwards order leaves the first panels
3287 * not visible. I don't know why!
3289 for (int i = viewCount - 1; i >= 0; i--)
3292 * Make new top and bottom frames. These take over the respective
3293 * AlignmentPanel objects, including their AlignmentViewports, so the
3294 * cdna/protein relationships between the viewports is carried over to the
3297 * explodedGeometry holds the (x, y) position of the previously exploded
3298 * SplitFrame, and the (width, height) of the AlignFrame component
3300 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3301 AlignFrame newTopFrame = new AlignFrame(topPanel);
3302 newTopFrame.setSize(oldTopFrame.getSize());
3303 newTopFrame.setVisible(true);
3304 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3305 .getExplodedGeometry();
3306 if (geometry != null)
3308 newTopFrame.setSize(geometry.getSize());
3311 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3312 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3313 newBottomFrame.setSize(oldBottomFrame.getSize());
3314 newBottomFrame.setVisible(true);
3315 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3316 .getExplodedGeometry();
3317 if (geometry != null)
3319 newBottomFrame.setSize(geometry.getSize());
3322 topPanel.av.setGatherViewsHere(false);
3323 bottomPanel.av.setGatherViewsHere(false);
3324 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3326 if (geometry != null)
3328 splitFrame.setLocation(geometry.getLocation());
3330 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3334 * Clear references to the panels (now relocated in the new SplitFrames)
3335 * before closing the old SplitFrame.
3338 bottomPanels.clear();
3343 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3344 * back into the given SplitFrame as additional views. Note that the gathered
3345 * frames may themselves have multiple views.
3349 public void gatherViews(GSplitFrame source)
3352 * special handling of explodedGeometry for a view within a SplitFrame: - it
3353 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3354 * height) of the AlignFrame component
3356 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3357 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3358 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3359 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3360 myBottomFrame.viewport
3361 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3362 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3363 myTopFrame.viewport.setGatherViewsHere(true);
3364 myBottomFrame.viewport.setGatherViewsHere(true);
3365 String topViewId = myTopFrame.viewport.getSequenceSetId();
3366 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3368 JInternalFrame[] frames = desktop.getAllFrames();
3369 for (JInternalFrame frame : frames)
3371 if (frame instanceof SplitFrame && frame != source)
3373 SplitFrame sf = (SplitFrame) frame;
3374 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3375 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3376 boolean gatherThis = false;
3377 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3379 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3380 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3381 if (topViewId.equals(topPanel.av.getSequenceSetId())
3382 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3385 topPanel.av.setGatherViewsHere(false);
3386 bottomPanel.av.setGatherViewsHere(false);
3387 topPanel.av.setExplodedGeometry(
3388 new Rectangle(sf.getLocation(), topFrame.getSize()));
3389 bottomPanel.av.setExplodedGeometry(
3390 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3391 myTopFrame.addAlignmentPanel(topPanel, false);
3392 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3398 topFrame.getAlignPanels().clear();
3399 bottomFrame.getAlignPanels().clear();
3406 * The dust settles...give focus to the tab we did this from.
3408 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3411 public static groovy.ui.Console getGroovyConsole()
3413 return groovyConsole;
3417 * handles the payload of a drag and drop event.
3419 * TODO refactor to desktop utilities class
3422 * - Data source strings extracted from the drop event
3424 * - protocol for each data source extracted from the drop event
3428 * - the payload from the drop event
3431 public static void transferFromDropTarget(List<String> files,
3432 List<DataSourceType> protocols, DropTargetDropEvent evt,
3433 Transferable t) throws Exception
3436 DataFlavor uriListFlavor = new DataFlavor(
3437 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3440 urlFlavour = new DataFlavor(
3441 "application/x-java-url; class=java.net.URL");
3442 } catch (ClassNotFoundException cfe)
3444 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3447 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3452 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3453 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3454 // means url may be null.
3457 protocols.add(DataSourceType.URL);
3458 files.add(url.toString());
3459 Cache.log.debug("Drop handled as URL dataflavor "
3460 + files.get(files.size() - 1));
3465 if (Platform.isAMac())
3468 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3472 } catch (Throwable ex)
3474 Cache.log.debug("URL drop handler failed.", ex);
3477 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3479 // Works on Windows and MacOSX
3480 Cache.log.debug("Drop handled as javaFileListFlavor");
3481 for (Object file : (List) t
3482 .getTransferData(DataFlavor.javaFileListFlavor))
3484 files.add(((File) file).toString());
3485 protocols.add(DataSourceType.FILE);
3490 // Unix like behaviour
3491 boolean added = false;
3493 if (t.isDataFlavorSupported(uriListFlavor))
3495 Cache.log.debug("Drop handled as uriListFlavor");
3496 // This is used by Unix drag system
3497 data = (String) t.getTransferData(uriListFlavor);
3501 // fallback to text: workaround - on OSX where there's a JVM bug
3502 Cache.log.debug("standard URIListFlavor failed. Trying text");
3503 // try text fallback
3504 DataFlavor textDf = new DataFlavor(
3505 "text/plain;class=java.lang.String");
3506 if (t.isDataFlavorSupported(textDf))
3508 data = (String) t.getTransferData(textDf);
3511 Cache.log.debug("Plain text drop content returned "
3512 + (data == null ? "Null - failed" : data));
3517 while (protocols.size() < files.size())
3519 Cache.log.debug("Adding missing FILE protocol for "
3520 + files.get(protocols.size()));
3521 protocols.add(DataSourceType.FILE);
3523 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3524 data, "\r\n"); st.hasMoreTokens();)
3527 String s = st.nextToken();
3528 if (s.startsWith("#"))
3530 // the line is a comment (as per the RFC 2483)
3533 java.net.URI uri = new java.net.URI(s);
3534 if (uri.getScheme().toLowerCase().startsWith("http"))
3536 protocols.add(DataSourceType.URL);
3537 files.add(uri.toString());
3541 // otherwise preserve old behaviour: catch all for file objects
3542 java.io.File file = new java.io.File(uri);
3543 protocols.add(DataSourceType.FILE);
3544 files.add(file.toString());
3549 if (Cache.log.isDebugEnabled())
3551 if (data == null || !added)
3554 if (t.getTransferDataFlavors() != null
3555 && t.getTransferDataFlavors().length > 0)
3558 "Couldn't resolve drop data. Here are the supported flavors:");
3559 for (DataFlavor fl : t.getTransferDataFlavors())
3562 "Supported transfer dataflavor: " + fl.toString());
3563 Object df = t.getTransferData(fl);
3566 Cache.log.debug("Retrieves: " + df);
3570 Cache.log.debug("Retrieved nothing");
3576 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3582 if (Platform.isWindows())
3585 Cache.log.debug("Scanning dropped content for Windows Link Files");
3587 // resolve any .lnk files in the file drop
3588 for (int f = 0; f < files.size(); f++)
3590 String source = files.get(f).toLowerCase();
3591 if (protocols.get(f).equals(DataSourceType.FILE)
3592 && (source.endsWith(".lnk") || source.endsWith(".url")
3593 || source.endsWith(".site")))
3597 File lf = new File(files.get(f));
3598 // process link file to get a URL
3599 Cache.log.debug("Found potential link file: " + lf);
3600 WindowsShortcut wscfile = new WindowsShortcut(lf);
3601 String fullname = wscfile.getRealFilename();
3602 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3603 files.set(f, fullname);
3604 Cache.log.debug("Parsed real filename " + fullname
3605 + " to extract protocol: " + protocols.get(f));
3606 } catch (Exception ex)
3609 "Couldn't parse " + files.get(f) + " as a link file.",
3618 * Sets the Preferences property for experimental features to True or False
3619 * depending on the state of the controlling menu item
3622 protected void showExperimental_actionPerformed(boolean selected)
3624 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3628 * Answers a (possibly empty) list of any structure viewer frames (currently
3629 * for either Jmol or Chimera) which are currently open. This may optionally
3630 * be restricted to viewers of a specified class, or viewers linked to a
3631 * specified alignment panel.
3634 * if not null, only return viewers linked to this panel
3635 * @param structureViewerClass
3636 * if not null, only return viewers of this class
3639 public List<StructureViewerBase> getStructureViewers(
3640 AlignmentPanel apanel,
3641 Class<? extends StructureViewerBase> structureViewerClass)
3643 List<StructureViewerBase> result = new ArrayList<>();
3644 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3646 for (JInternalFrame frame : frames)
3648 if (frame instanceof StructureViewerBase)
3650 if (structureViewerClass == null
3651 || structureViewerClass.isInstance(frame))
3654 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3656 result.add((StructureViewerBase) frame);