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 static jalview.util.UrlConstants.SEQUENCE_ID;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.gui.ImageExporter.ImageWriterI;
30 import jalview.io.DataSourceType;
31 import jalview.io.FileFormat;
32 import jalview.io.FileFormatException;
33 import jalview.io.FileFormatI;
34 import jalview.io.FileFormats;
35 import jalview.io.FileLoader;
36 import jalview.io.FormatAdapter;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JalviewFileChooser;
39 import jalview.io.JalviewFileView;
40 import jalview.jbgui.GSplitFrame;
41 import jalview.jbgui.GStructureViewer;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.urls.IdOrgSettings;
44 import jalview.util.BrowserLauncher;
45 import jalview.util.ImageMaker.TYPE;
46 import jalview.util.MessageManager;
47 import jalview.util.Platform;
48 import jalview.util.UrlConstants;
49 import jalview.util.dialogrunner.RunResponse;
50 import jalview.viewmodel.AlignmentViewport;
51 import jalview.ws.params.ParamManager;
52 import jalview.ws.utils.UrlDownloadClient;
54 import java.awt.BorderLayout;
55 import java.awt.Color;
56 import java.awt.Dimension;
57 import java.awt.FontMetrics;
58 import java.awt.Graphics;
59 import java.awt.GridLayout;
60 import java.awt.Point;
61 import java.awt.Rectangle;
62 import java.awt.Toolkit;
63 import java.awt.Window;
64 import java.awt.datatransfer.Clipboard;
65 import java.awt.datatransfer.ClipboardOwner;
66 import java.awt.datatransfer.DataFlavor;
67 import java.awt.datatransfer.Transferable;
68 import java.awt.dnd.DnDConstants;
69 import java.awt.dnd.DropTargetDragEvent;
70 import java.awt.dnd.DropTargetDropEvent;
71 import java.awt.dnd.DropTargetEvent;
72 import java.awt.dnd.DropTargetListener;
73 import java.awt.event.ActionEvent;
74 import java.awt.event.ActionListener;
75 import java.awt.event.InputEvent;
76 import java.awt.event.KeyEvent;
77 import java.awt.event.MouseAdapter;
78 import java.awt.event.MouseEvent;
79 import java.awt.event.WindowAdapter;
80 import java.awt.event.WindowEvent;
81 import java.beans.PropertyChangeEvent;
82 import java.beans.PropertyChangeListener;
83 import java.io.BufferedInputStream;
85 import java.io.FileOutputStream;
86 import java.io.IOException;
88 import java.util.ArrayList;
89 import java.util.Hashtable;
90 import java.util.List;
91 import java.util.ListIterator;
92 import java.util.StringTokenizer;
93 import java.util.Vector;
94 import java.util.concurrent.ExecutorService;
95 import java.util.concurrent.Executors;
96 import java.util.concurrent.Semaphore;
98 import javax.swing.AbstractAction;
99 import javax.swing.Action;
100 import javax.swing.ActionMap;
101 import javax.swing.Box;
102 import javax.swing.BoxLayout;
103 import javax.swing.DefaultDesktopManager;
104 import javax.swing.DesktopManager;
105 import javax.swing.InputMap;
106 import javax.swing.JButton;
107 import javax.swing.JCheckBox;
108 import javax.swing.JComboBox;
109 import javax.swing.JComponent;
110 import javax.swing.JDesktopPane;
111 import javax.swing.JFrame;
112 import javax.swing.JInternalFrame;
113 import javax.swing.JLabel;
114 import javax.swing.JMenuItem;
115 import javax.swing.JPanel;
116 import javax.swing.JPopupMenu;
117 import javax.swing.JProgressBar;
118 import javax.swing.JTextField;
119 import javax.swing.KeyStroke;
120 import javax.swing.SwingUtilities;
121 import javax.swing.event.HyperlinkEvent;
122 import javax.swing.event.HyperlinkEvent.EventType;
123 import javax.swing.event.InternalFrameAdapter;
124 import javax.swing.event.InternalFrameEvent;
125 import javax.swing.event.MenuEvent;
126 import javax.swing.event.MenuListener;
128 import org.stackoverflowusers.file.WindowsShortcut;
135 * @version $Revision: 1.155 $
137 public class Desktop extends jalview.jbgui.GDesktop
138 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
139 jalview.api.StructureSelectionManagerProvider
141 private static int DEFAULT_MIN_WIDTH = 300;
143 private static int DEFAULT_MIN_HEIGHT = 250;
145 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
147 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
149 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
151 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
154 * news reader - null if it was never started.
156 private BlogReader jvnews = null;
158 private File projectFile;
162 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
164 public void addJalviewPropertyChangeListener(
165 PropertyChangeListener listener)
167 changeSupport.addJalviewPropertyChangeListener(listener);
171 * @param propertyName
173 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
174 * java.beans.PropertyChangeListener)
176 public void addJalviewPropertyChangeListener(String propertyName,
177 PropertyChangeListener listener)
179 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
183 * @param propertyName
185 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
186 * java.beans.PropertyChangeListener)
188 public void removeJalviewPropertyChangeListener(String propertyName,
189 PropertyChangeListener listener)
191 changeSupport.removeJalviewPropertyChangeListener(propertyName,
195 /** Singleton Desktop instance */
196 public static Desktop instance;
198 public static MyDesktopPane desktop;
200 public static MyDesktopPane getDesktop()
202 // BH 2018 could use currentThread() here as a reference to a
203 // Hashtable<Thread, MyDesktopPane> in JavaScript
207 static int openFrameCount = 0;
209 static final int xOffset = 30;
211 static final int yOffset = 30;
213 public static jalview.ws.jws1.Discoverer discoverer;
215 public static Object[] jalviewClipboard;
217 public static boolean internalCopy = false;
219 static int fileLoadingCount = 0;
221 class MyDesktopManager implements DesktopManager
224 private DesktopManager delegate;
226 public MyDesktopManager(DesktopManager delegate)
228 this.delegate = delegate;
232 public void activateFrame(JInternalFrame f)
236 delegate.activateFrame(f);
237 } catch (NullPointerException npe)
239 Point p = getMousePosition();
240 instance.showPasteMenu(p.x, p.y);
245 public void beginDraggingFrame(JComponent f)
247 delegate.beginDraggingFrame(f);
251 public void beginResizingFrame(JComponent f, int direction)
253 delegate.beginResizingFrame(f, direction);
257 public void closeFrame(JInternalFrame f)
259 delegate.closeFrame(f);
263 public void deactivateFrame(JInternalFrame f)
265 delegate.deactivateFrame(f);
269 public void deiconifyFrame(JInternalFrame f)
271 delegate.deiconifyFrame(f);
275 public void dragFrame(JComponent f, int newX, int newY)
281 delegate.dragFrame(f, newX, newY);
285 public void endDraggingFrame(JComponent f)
287 delegate.endDraggingFrame(f);
292 public void endResizingFrame(JComponent f)
294 delegate.endResizingFrame(f);
299 public void iconifyFrame(JInternalFrame f)
301 delegate.iconifyFrame(f);
305 public void maximizeFrame(JInternalFrame f)
307 delegate.maximizeFrame(f);
311 public void minimizeFrame(JInternalFrame f)
313 delegate.minimizeFrame(f);
317 public void openFrame(JInternalFrame f)
319 delegate.openFrame(f);
323 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
330 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
334 public void setBoundsForFrame(JComponent f, int newX, int newY,
335 int newWidth, int newHeight)
337 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
340 // All other methods, simply delegate
345 * Creates a new Desktop object.
350 * A note to implementors. It is ESSENTIAL that any activities that might block
351 * are spawned off as threads rather than waited for during this constructor.
356 doVamsasClientCheck();
359 doConfigureStructurePrefs();
360 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
361 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
362 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
364 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
366 desktop = new MyDesktopPane(selmemusage);
369 showMemusage.setSelected(selmemusage);
370 desktop.setBackground(Color.white);
371 getContentPane().setLayout(new BorderLayout());
372 // alternate config - have scrollbars - see notes in JAL-153
373 // JScrollPane sp = new JScrollPane();
374 // sp.getViewport().setView(desktop);
375 // getContentPane().add(sp, BorderLayout.CENTER);
377 // BH 2018 - just an experiment to try unclipped JInternalFrames.
378 // Must set for all three to be active:
381 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
382 ((JComponent) getContentPane()).putClientProperty("swingjs.overflow.hidden", "false");
383 desktop.putClientProperty("swingjs.overflow.hidden", "false");
386 getContentPane().add(desktop, BorderLayout.CENTER);
387 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
389 // This line prevents Windows Look&Feel resizing all new windows to maximum
390 // if previous window was maximised
391 desktop.setDesktopManager(new MyDesktopManager(
392 (Platform.isWindows() ? new DefaultDesktopManager()
394 ? new AquaInternalFrameManager(
395 desktop.getDesktopManager())
396 : desktop.getDesktopManager())));
398 Rectangle dims = getLastKnownDimensions("");
405 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
406 int xPos = Math.max(5, (screenSize.width - 900) / 2);
407 int yPos = Math.max(5, (screenSize.height - 650) / 2);
408 setBounds(xPos, yPos, 900, 650);
411 boolean doFullLoad = /** @j2sNative ! */true;
415 jconsole = new Console(this, showjconsole);
416 // add essential build information
417 jconsole.setHeader("Jalview Version: "
418 + jalview.bin.Cache.getProperty("VERSION") + "\n"
419 + "Jalview Installation: "
420 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
421 + "\n" + "Build Date: "
422 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
423 + "Java version: " + System.getProperty("java.version") + "\n"
424 + System.getProperty("os.arch") + " "
425 + System.getProperty("os.name") + " "
426 + System.getProperty("os.version"));
428 showConsole(showjconsole);
430 showNews.setVisible(false);
432 experimentalFeatures.setSelected(showExperimental());
434 getIdentifiersOrgData();
438 // Spawn a thread that shows the splashscreen
440 SwingUtilities.invokeLater(new Runnable()
449 // Thread off a new instance of the file chooser - this reduces the time it
450 // takes to open it later on.
451 new Thread(new Runnable()
456 Cache.log.debug("Filechooser init thread started.");
457 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
458 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
460 Cache.log.debug("Filechooser init thread finished.");
463 // Add the service change listener
464 changeSupport.addJalviewPropertyChangeListener("services",
465 new PropertyChangeListener()
469 public void propertyChange(PropertyChangeEvent evt)
471 Cache.log.debug("Firing service changed event for "
472 + evt.getNewValue());
473 JalviewServicesChanged(evt);
480 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
482 this.addWindowListener(new WindowAdapter()
485 public void windowClosing(WindowEvent evt)
492 this.addMouseListener(ma = new MouseAdapter()
495 public void mousePressed(MouseEvent evt)
497 if (evt.isPopupTrigger()) // Mac
499 showPasteMenu(evt.getX(), evt.getY());
504 public void mouseReleased(MouseEvent evt)
506 if (evt.isPopupTrigger()) // Windows
508 showPasteMenu(evt.getX(), evt.getY());
512 desktop.addMouseListener(ma);
517 * Answers true if user preferences to enable experimental features is True
522 public boolean showExperimental()
524 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
525 Boolean.FALSE.toString());
526 return Boolean.valueOf(experimental).booleanValue();
529 public void doConfigureStructurePrefs()
531 // configure services
532 StructureSelectionManager ssm = StructureSelectionManager
533 .getStructureSelectionManager(this);
534 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
536 ssm.setAddTempFacAnnot(jalview.bin.Cache
537 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
538 ssm.setProcessSecondaryStructure(jalview.bin.Cache
539 .getDefault(Preferences.STRUCT_FROM_PDB, true));
540 ssm.setSecStructServices(
541 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
545 ssm.setAddTempFacAnnot(false);
546 ssm.setProcessSecondaryStructure(false);
547 ssm.setSecStructServices(false);
551 public void checkForNews()
553 final Desktop me = this;
554 // Thread off the news reader, in case there are connection problems.
555 new Thread(new Runnable()
560 Cache.log.debug("Starting news thread.");
561 jvnews = new BlogReader(me);
562 showNews.setVisible(true);
563 Cache.log.debug("Completed news thread.");
568 public void getIdentifiersOrgData()
570 // Thread off the identifiers fetcher
571 new Thread(new Runnable()
576 Cache.log.debug("Downloading data from identifiers.org");
577 UrlDownloadClient client = new UrlDownloadClient();
580 client.download(IdOrgSettings.getUrl(),
581 IdOrgSettings.getDownloadLocation());
582 } catch (IOException e)
584 Cache.log.debug("Exception downloading identifiers.org data"
593 protected void showNews_actionPerformed(ActionEvent e)
595 showNews(showNews.isSelected());
598 void showNews(boolean visible)
600 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
601 showNews.setSelected(visible);
602 if (visible && !jvnews.isVisible())
604 new Thread(new Runnable()
609 long now = System.currentTimeMillis();
610 Desktop.instance.setProgressBar(
611 MessageManager.getString("status.refreshing_news"), now);
612 jvnews.refreshNews();
613 Desktop.instance.setProgressBar(null, now);
621 * recover the last known dimensions for a jalview window
624 * - empty string is desktop, all other windows have unique prefix
625 * @return null or last known dimensions scaled to current geometry (if last
626 * window geom was known)
628 Rectangle getLastKnownDimensions(String windowName)
630 // TODO: lock aspect ratio for scaling desktop Bug #0058199
631 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
632 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
633 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
634 String width = jalview.bin.Cache
635 .getProperty(windowName + "SCREEN_WIDTH");
636 String height = jalview.bin.Cache
637 .getProperty(windowName + "SCREEN_HEIGHT");
638 if ((x != null) && (y != null) && (width != null) && (height != null))
640 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
641 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
642 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
644 // attempt #1 - try to cope with change in screen geometry - this
645 // version doesn't preserve original jv aspect ratio.
646 // take ratio of current screen size vs original screen size.
647 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
648 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
649 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
650 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
651 // rescale the bounds depending upon the current screen geometry.
652 ix = (int) (ix * sw);
653 iw = (int) (iw * sw);
654 iy = (int) (iy * sh);
655 ih = (int) (ih * sh);
656 while (ix >= screenSize.width)
658 jalview.bin.Cache.log.debug(
659 "Window geometry location recall error: shifting horizontal to within screenbounds.");
660 ix -= screenSize.width;
662 while (iy >= screenSize.height)
664 jalview.bin.Cache.log.debug(
665 "Window geometry location recall error: shifting vertical to within screenbounds.");
666 iy -= screenSize.height;
668 jalview.bin.Cache.log.debug(
669 "Got last known dimensions for " + windowName + ": x:" + ix
670 + " y:" + iy + " width:" + iw + " height:" + ih);
672 // return dimensions for new instance
673 return new Rectangle(ix, iy, iw, ih);
678 private void doVamsasClientCheck()
680 if (Cache.vamsasJarsPresent())
682 setupVamsasDisconnectedGui();
683 VamsasMenu.setVisible(true);
684 final Desktop us = this;
685 VamsasMenu.addMenuListener(new MenuListener()
687 // this listener remembers when the menu was first selected, and
688 // doesn't rebuild the session list until it has been cleared and
690 boolean refresh = true;
693 public void menuCanceled(MenuEvent e)
699 public void menuDeselected(MenuEvent e)
705 public void menuSelected(MenuEvent e)
709 us.buildVamsasStMenu();
714 vamsasStart.setVisible(true);
718 void showPasteMenu(int x, int y)
720 JPopupMenu popup = new JPopupMenu();
721 JMenuItem item = new JMenuItem(
722 MessageManager.getString("label.paste_new_window"));
723 item.addActionListener(new ActionListener()
726 public void actionPerformed(ActionEvent evt)
733 popup.show(this, x, y);
740 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
741 Transferable contents = c.getContents(this);
743 if (contents != null)
745 String file = (String) contents
746 .getTransferData(DataFlavor.stringFlavor);
748 FileFormatI format = new IdentifyFile().identify(file,
749 DataSourceType.PASTE);
751 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
754 } catch (Exception ex)
757 "Unable to paste alignment from system clipboard:\n" + ex);
762 * Adds and opens the given frame to the desktop
773 public static synchronized void addInternalFrame(
774 final JInternalFrame frame, String title, int w, int h)
776 addInternalFrame(frame, title, true, w, h, true, false);
780 * Add an internal frame to the Jalview desktop
787 * When true, display frame immediately, otherwise, caller must call
788 * setVisible themselves.
794 public static synchronized void addInternalFrame(
795 final JInternalFrame frame, String title, boolean makeVisible,
798 addInternalFrame(frame, title, makeVisible, w, h, true, false);
802 * Add an internal frame to the Jalview desktop and make it visible
815 public static synchronized void addInternalFrame(
816 final JInternalFrame frame, String title, int w, int h,
819 addInternalFrame(frame, title, true, w, h, resizable, false);
823 * Add an internal frame to the Jalview desktop
830 * When true, display frame immediately, otherwise, caller must call
831 * setVisible themselves.
838 * @param ignoreMinSize
839 * Do not set the default minimum size for frame
841 public static synchronized void addInternalFrame(
842 final JInternalFrame frame, String title, boolean makeVisible,
843 int w, int h, boolean resizable, boolean ignoreMinSize)
846 // TODO: allow callers to determine X and Y position of frame (eg. via
848 // TODO: consider fixing method to update entries in the window submenu with
849 // the current window title
851 frame.setTitle(title);
852 if (frame.getWidth() < 1 || frame.getHeight() < 1)
856 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
857 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
858 // IF JALVIEW IS RUNNING HEADLESS
859 // ///////////////////////////////////////////////
860 if (instance == null || (System.getProperty("java.awt.headless") != null
861 && System.getProperty("java.awt.headless").equals("true")))
870 frame.setMinimumSize(
871 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
873 // Set default dimension for Alignment Frame window.
874 // The Alignment Frame window could be added from a number of places,
876 // I did this here in order not to miss out on any Alignment frame.
877 if (frame instanceof AlignFrame)
879 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
880 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
884 frame.setVisible(makeVisible);
885 frame.setClosable(true);
886 frame.setResizable(resizable);
887 frame.setMaximizable(resizable);
888 frame.setIconifiable(resizable);
889 frame.setOpaque(/** @j2sNative true || */
892 if (frame.getX() < 1 && frame.getY() < 1)
894 frame.setLocation(xOffset * openFrameCount,
895 yOffset * ((openFrameCount - 1) % 10) + yOffset);
899 * add an entry for the new frame in the Window menu
900 * (and remove it when the frame is closed)
902 final JMenuItem menuItem = new JMenuItem(title);
903 frame.addInternalFrameListener(new InternalFrameAdapter()
906 public void internalFrameActivated(InternalFrameEvent evt)
908 JInternalFrame itf = desktop.getSelectedFrame();
911 if (itf instanceof AlignFrame)
913 Jalview.setCurrentAlignFrame((AlignFrame) itf);
920 public void internalFrameClosed(InternalFrameEvent evt)
922 PaintRefresher.RemoveComponent(frame);
925 * defensive check to prevent frames being
926 * added half off the window
928 if (openFrameCount > 0)
934 * ensure no reference to alignFrame retained by menu item listener
936 if (menuItem.getActionListeners().length > 0)
938 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
940 windowMenu.remove(menuItem);
944 menuItem.addActionListener(new ActionListener()
947 public void actionPerformed(ActionEvent e)
951 frame.setSelected(true);
952 frame.setIcon(false);
953 } catch (java.beans.PropertyVetoException ex)
955 // System.err.println(ex.toString());
960 setKeyBindings(frame);
964 windowMenu.add(menuItem);
969 frame.setSelected(true);
970 frame.requestFocus();
971 } catch (java.beans.PropertyVetoException ve)
973 } catch (java.lang.ClassCastException cex)
976 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
982 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
987 private static void setKeyBindings(JInternalFrame frame)
989 @SuppressWarnings("serial")
990 final Action closeAction = new AbstractAction()
993 public void actionPerformed(ActionEvent e)
1000 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1002 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1003 InputEvent.CTRL_DOWN_MASK);
1004 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1005 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1007 InputMap inputMap = frame
1008 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1009 String ctrlW = ctrlWKey.toString();
1010 inputMap.put(ctrlWKey, ctrlW);
1011 inputMap.put(cmdWKey, ctrlW);
1013 ActionMap actionMap = frame.getActionMap();
1014 actionMap.put(ctrlW, closeAction);
1018 public void lostOwnership(Clipboard clipboard, Transferable contents)
1022 Desktop.jalviewClipboard = null;
1025 internalCopy = false;
1029 public void dragEnter(DropTargetDragEvent evt)
1034 public void dragExit(DropTargetEvent evt)
1039 public void dragOver(DropTargetDragEvent evt)
1044 public void dropActionChanged(DropTargetDragEvent evt)
1055 public void drop(DropTargetDropEvent evt)
1057 boolean success = true;
1058 // JAL-1552 - acceptDrop required before getTransferable call for
1059 // Java's Transferable for native dnd
1060 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1061 Transferable t = evt.getTransferable();
1062 List<Object> files = new ArrayList<>();
1063 List<DataSourceType> protocols = new ArrayList<>();
1067 Desktop.transferFromDropTarget(files, protocols, evt, t);
1068 } catch (Exception e)
1070 e.printStackTrace();
1078 for (int i = 0; i < files.size(); i++)
1080 // BH 2018 File or String
1081 Object file = files.get(i);
1082 String fileName = file.toString();
1083 DataSourceType protocol = (protocols == null)
1084 ? DataSourceType.FILE
1086 FileFormatI format = null;
1088 if (fileName.endsWith(".jar"))
1090 format = FileFormat.Jalview;
1095 format = new IdentifyFile().identify(file, protocol);
1098 new FileLoader().LoadFile(null, file, protocol, format);
1101 } catch (Exception ex)
1106 evt.dropComplete(success); // need this to ensure input focus is properly
1107 // transfered to any new windows created
1117 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1119 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1120 JalviewFileChooser chooser = JalviewFileChooser
1121 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1123 chooser.setFileView(new JalviewFileView());
1124 chooser.setDialogTitle(
1125 MessageManager.getString("label.open_local_file"));
1126 chooser.setToolTipText(MessageManager.getString("action.open"));
1128 chooser.addResponse(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1134 File selectedFile = chooser.getSelectedFile();
1135 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1137 FileFormatI format = chooser.getSelectedFormat();
1140 * Call IdentifyFile to verify the file contains what its extension implies.
1141 * Skip this step for dynamically added file formats, because
1142 * IdentifyFile does not know how to recognise them.
1144 if (FileFormats.getInstance().isIdentifiable(format))
1148 format = new IdentifyFile().identify(selectedFile,
1149 DataSourceType.FILE);
1150 } catch (FileFormatException e)
1152 // format = null; //??
1156 new FileLoader().LoadFile(viewport, selectedFile,
1157 DataSourceType.FILE, format);
1160 chooser.showOpenDialog(this);
1164 * Shows a dialog for input of a URL at which to retrieve alignment data
1169 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1171 // This construct allows us to have a wider textfield
1173 JLabel label = new JLabel(
1174 MessageManager.getString("label.input_file_url"));
1176 JPanel panel = new JPanel(new GridLayout(2, 1));
1180 * the URL to fetch is
1181 * Java: an editable combobox with history
1182 * JS: (pending JAL-3038) a plain text field
1185 String urlBase = "http://www.";
1188 history = new JTextField(urlBase, 35);
1192 JComboBox<String> asCombo = new JComboBox<>();
1193 asCombo.setPreferredSize(new Dimension(400, 20));
1194 asCombo.setEditable(true);
1195 asCombo.addItem(urlBase);
1196 String historyItems = Cache.getProperty("RECENT_URL");
1197 if (historyItems != null)
1199 for (String token : historyItems.split("\\t"))
1201 asCombo.addItem(token);
1208 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1209 MessageManager.getString("action.cancel") };
1210 RunResponse action = new RunResponse(JvOptionPane.OK_OPTION) {
1214 String url = Jalview.isJS() ? ((JTextField) history).getText()
1215 : ((JComboBox<String>) history).getSelectedItem()
1218 if (url.toLowerCase().endsWith(".jar"))
1220 if (viewport != null)
1222 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1223 FileFormat.Jalview);
1227 new FileLoader().LoadFile(url, DataSourceType.URL,
1228 FileFormat.Jalview);
1233 FileFormatI format = null;
1236 format = new IdentifyFile().identify(url, DataSourceType.URL);
1237 } catch (FileFormatException e)
1239 // TODO revise error handling, distinguish between
1240 // URL not found and response not valid
1245 String msg = MessageManager.formatMessage("label.couldnt_locate", url);
1246 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1247 MessageManager.getString("label.url_not_found"),
1248 JvOptionPane.WARNING_MESSAGE);
1253 if (viewport != null)
1255 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1260 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1264 String dialogOption = MessageManager
1265 .getString("label.input_alignment_from_url");
1266 JvOptionPane.newOptionDialog(desktop).addResponse(action)
1267 .showInternalDialog(panel, dialogOption,
1268 JvOptionPane.YES_NO_CANCEL_OPTION,
1269 JvOptionPane.PLAIN_MESSAGE, null, options,
1270 MessageManager.getString("action.ok"));
1274 * Opens the CutAndPaste window for the user to paste an alignment in to
1277 * - if not null, the pasted alignment is added to the current
1278 * alignment; if null, to a new alignment window
1281 public void inputTextboxMenuItem_actionPerformed(
1282 AlignmentViewPanel viewPanel)
1284 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1285 cap.setForInput(viewPanel);
1286 Desktop.addInternalFrame(cap,
1287 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1297 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1298 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1300 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1301 screen.height + "");
1302 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1303 getWidth(), getHeight()));
1305 if (jconsole != null)
1307 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1308 jconsole.stopConsole();
1312 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1315 if (dialogExecutor != null)
1317 dialogExecutor.shutdownNow();
1319 closeAll_actionPerformed(null);
1321 if (groovyConsole != null)
1323 // suppress a possible repeat prompt to save script
1324 groovyConsole.setDirty(false);
1325 groovyConsole.exit();
1330 private void storeLastKnownDimensions(String string, Rectangle jc)
1332 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1333 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1334 + " height:" + jc.height);
1336 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1337 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1338 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1339 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1349 public void aboutMenuItem_actionPerformed(ActionEvent e)
1351 // StringBuffer message = getAboutMessage(false);
1352 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1354 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1355 new Thread(new Runnable()
1360 new SplashScreen(true);
1365 public StringBuffer getAboutMessage(boolean shortv)
1367 StringBuffer message = new StringBuffer();
1368 message.append("<html>");
1371 message.append("<h1><strong>Version: "
1372 + jalview.bin.Cache.getProperty("VERSION")
1373 + "</strong></h1>");
1374 message.append("<strong>Last Updated: <em>"
1375 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1376 + "</em></strong>");
1382 message.append("<strong>Version "
1383 + jalview.bin.Cache.getProperty("VERSION")
1384 + "; last updated: "
1385 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1388 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1389 .equals("Checking"))
1391 message.append("<br>...Checking latest version...</br>");
1393 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1394 .equals(jalview.bin.Cache.getProperty("VERSION")))
1396 boolean red = false;
1397 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1398 .indexOf("automated build") == -1)
1401 // Displayed when code version and jnlp version do not match and code
1402 // version is not a development build
1403 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1406 message.append("<br>!! Version "
1407 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1409 + " is available for download from "
1410 + jalview.bin.Cache.getDefault("www.jalview.org",
1411 "http://www.jalview.org")
1415 message.append("</div>");
1418 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1420 "The Jalview Authors (See AUTHORS file for current list)")
1421 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1422 + "<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"
1423 + "<br><br>If you use Jalview, please cite:"
1424 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1425 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1426 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1432 * Action on requesting Help documentation
1435 public void documentationMenuItem_actionPerformed()
1441 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1445 Help.showHelpWindow();
1447 } catch (Exception ex)
1449 System.err.println("Error opening help: " + ex.getMessage());
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 // TODO: decide if we should update properties file
1554 if (jconsole != null) // BH 2018
1556 showConsole.setSelected(selected);
1557 Cache.setProperty("SHOW_JAVA_CONSOLE",
1558 Boolean.valueOf(selected).toString());
1559 jconsole.setVisible(selected);
1563 void reorderAssociatedWindows(boolean minimize, boolean close)
1565 JInternalFrame[] frames = desktop.getAllFrames();
1566 if (frames == null || frames.length < 1)
1571 AlignmentViewport source = null, target = null;
1572 if (frames[0] instanceof AlignFrame)
1574 source = ((AlignFrame) frames[0]).getCurrentView();
1576 else if (frames[0] instanceof TreePanel)
1578 source = ((TreePanel) frames[0]).getViewPort();
1580 else if (frames[0] instanceof PCAPanel)
1582 source = ((PCAPanel) frames[0]).av;
1584 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1586 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1591 for (int i = 0; i < frames.length; i++)
1594 if (frames[i] == null)
1598 if (frames[i] instanceof AlignFrame)
1600 target = ((AlignFrame) frames[i]).getCurrentView();
1602 else if (frames[i] instanceof TreePanel)
1604 target = ((TreePanel) frames[i]).getViewPort();
1606 else if (frames[i] instanceof PCAPanel)
1608 target = ((PCAPanel) frames[i]).av;
1610 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1612 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1615 if (source == target)
1621 frames[i].setClosed(true);
1625 frames[i].setIcon(minimize);
1628 frames[i].toFront();
1632 } catch (java.beans.PropertyVetoException ex)
1647 protected void preferences_actionPerformed(ActionEvent e)
1653 * Prompts the user to choose a file and then saves the Jalview state as a
1654 * Jalview project file
1657 public void saveState_actionPerformed(boolean asCastor)
1659 JalviewFileChooser chooser = new JalviewFileChooser(
1660 asCastor ? "jvp" : "jvx",
1663 chooser.setFileView(new JalviewFileView());
1664 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1665 int option = chooser.showSaveDialog(this);
1666 if (option == JalviewFileChooser.APPROVE_OPTION)
1668 File choice = chooser.getSelectedFile();
1669 setProjectFile(choice);
1671 new Thread(new Runnable()
1676 // TODO: refactor to Jalview desktop session controller action.
1677 setProgressBar(MessageManager.formatMessage(
1678 "label.saving_jalview_project", new Object[]
1679 { choice.getName() }), choice.hashCode());
1680 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1681 choice.getParent());
1682 // TODO catch and handle errors for savestate
1683 // TODO prevent user from messing with the Desktop whilst we're saving
1688 new Jalview2XML().saveState(choice);
1692 new jalview.project.Jalview2XML().saveState(choice);
1694 } catch (OutOfMemoryError oom)
1697 "Whilst saving current state to " + choice.getName(),
1699 } catch (Exception ex)
1702 "Problems whilst trying to save to " + choice.getName(),
1704 JvOptionPane.showMessageDialog(Desktop.this,
1705 MessageManager.formatMessage(
1706 "label.error_whilst_saving_current_state_to",
1708 { choice.getName() }),
1709 MessageManager.getString("label.couldnt_save_project"),
1710 JvOptionPane.WARNING_MESSAGE);
1712 setProgressBar(null, choice.hashCode());
1718 void setProjectFile(File choice)
1720 this.projectFile = choice;
1723 public File getProjectFile()
1725 return this.projectFile;
1729 * Prompts the user to choose a file and loads in as a Jalview project file
1732 public void loadState_actionPerformed(boolean asCastor)
1734 // TODO: GET RID OF .JVX BEFORE RELEASE JIM!
1735 final String[] suffix = asCastor ? new String[] { "jvp", "jar" }
1738 final String[] desc = asCastor
1740 { "Jalview Project", "Jalview Project (old)" }
1742 { "Jalview Project" };
1743 JalviewFileChooser chooser = new JalviewFileChooser(
1744 Cache.getProperty("LAST_DIRECTORY"), suffix,
1747 chooser.setFileView(new JalviewFileView());
1748 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1749 chooser.addResponse(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1754 File selectedFile = chooser.getSelectedFile();
1755 setProjectFile(selectedFile);
1756 final String choice = selectedFile.getAbsolutePath();
1757 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1758 new Thread(new Runnable()
1766 new Jalview2XML().loadJalviewAlign(choice);
1770 new jalview.project.Jalview2XML().loadJalviewAlign(choice);
1772 } catch (OutOfMemoryError oom)
1774 new OOMWarning("Whilst loading project from " + choice, oom);
1775 } catch (Exception ex)
1778 "Problems whilst loading project from " + choice, ex);
1779 JvOptionPane.showMessageDialog(Desktop.desktop,
1780 MessageManager.formatMessage(
1781 "label.error_whilst_loading_project_from",
1784 MessageManager.getString("label.couldnt_load_project"),
1785 JvOptionPane.WARNING_MESSAGE);
1792 chooser.showOpenDialog(this);
1796 public void inputSequence_actionPerformed(ActionEvent e)
1798 new SequenceFetcher(this);
1801 JPanel progressPanel;
1803 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1805 public void startLoading(final Object fileName)
1807 if (fileLoadingCount == 0)
1809 fileLoadingPanels.add(addProgressPanel(MessageManager
1810 .formatMessage("label.loading_file", new Object[]
1816 private JPanel addProgressPanel(String string)
1818 if (progressPanel == null)
1820 progressPanel = new JPanel(new GridLayout(1, 1));
1821 totalProgressCount = 0;
1822 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1824 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1825 JProgressBar progressBar = new JProgressBar();
1826 progressBar.setIndeterminate(true);
1828 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1830 thisprogress.add(progressBar, BorderLayout.CENTER);
1831 progressPanel.add(thisprogress);
1832 ((GridLayout) progressPanel.getLayout()).setRows(
1833 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1834 ++totalProgressCount;
1835 instance.validate();
1836 return thisprogress;
1839 int totalProgressCount = 0;
1841 private void removeProgressPanel(JPanel progbar)
1843 if (progressPanel != null)
1845 synchronized (progressPanel)
1847 progressPanel.remove(progbar);
1848 GridLayout gl = (GridLayout) progressPanel.getLayout();
1849 gl.setRows(gl.getRows() - 1);
1850 if (--totalProgressCount < 1)
1852 this.getContentPane().remove(progressPanel);
1853 progressPanel = null;
1860 public void stopLoading()
1863 if (fileLoadingCount < 1)
1865 while (fileLoadingPanels.size() > 0)
1867 removeProgressPanel(fileLoadingPanels.remove(0));
1869 fileLoadingPanels.clear();
1870 fileLoadingCount = 0;
1875 public static int getViewCount(String alignmentId)
1877 AlignmentViewport[] aps = getViewports(alignmentId);
1878 return (aps == null) ? 0 : aps.length;
1883 * @param alignmentId
1884 * - if null, all sets are returned
1885 * @return all AlignmentPanels concerning the alignmentId sequence set
1887 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1889 if (Desktop.desktop == null)
1891 // no frames created and in headless mode
1892 // TODO: verify that frames are recoverable when in headless mode
1895 List<AlignmentPanel> aps = new ArrayList<>();
1896 AlignFrame[] frames = getAlignFrames();
1901 for (AlignFrame af : frames)
1903 for (AlignmentPanel ap : af.alignPanels)
1905 if (alignmentId == null
1906 || alignmentId.equals(ap.av.getSequenceSetId()))
1912 if (aps.size() == 0)
1916 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1921 * get all the viewports on an alignment.
1923 * @param sequenceSetId
1924 * unique alignment id (may be null - all viewports returned in that
1926 * @return all viewports on the alignment bound to sequenceSetId
1928 public static AlignmentViewport[] getViewports(String sequenceSetId)
1930 List<AlignmentViewport> viewp = new ArrayList<>();
1931 if (desktop != null)
1933 AlignFrame[] frames = Desktop.getAlignFrames();
1935 for (AlignFrame afr : frames)
1937 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1938 .equals(sequenceSetId))
1940 if (afr.alignPanels != null)
1942 for (AlignmentPanel ap : afr.alignPanels)
1944 if (sequenceSetId == null
1945 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1953 viewp.add(afr.getViewport());
1957 if (viewp.size() > 0)
1959 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1966 * Explode the views in the given frame into separate AlignFrame
1970 public static void explodeViews(AlignFrame af)
1972 int size = af.alignPanels.size();
1978 for (int i = 0; i < size; i++)
1980 AlignmentPanel ap = af.alignPanels.get(i);
1981 AlignFrame newaf = new AlignFrame(ap);
1984 * Restore the view's last exploded frame geometry if known. Multiple
1985 * views from one exploded frame share and restore the same (frame)
1986 * position and size.
1988 Rectangle geometry = ap.av.getExplodedGeometry();
1989 if (geometry != null)
1991 newaf.setBounds(geometry);
1994 ap.av.setGatherViewsHere(false);
1996 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1997 AlignFrame.DEFAULT_HEIGHT);
2000 af.alignPanels.clear();
2001 af.closeMenuItem_actionPerformed(true);
2006 * Gather expanded views (separate AlignFrame's) with the same sequence set
2007 * identifier back in to this frame as additional views, and close the expanded
2008 * views. Note the expanded frames may themselves have multiple views. We take
2013 public void gatherViews(AlignFrame source)
2015 source.viewport.setGatherViewsHere(true);
2016 source.viewport.setExplodedGeometry(source.getBounds());
2017 JInternalFrame[] frames = desktop.getAllFrames();
2018 String viewId = source.viewport.getSequenceSetId();
2020 for (int t = 0; t < frames.length; t++)
2022 if (frames[t] instanceof AlignFrame && frames[t] != source)
2024 AlignFrame af = (AlignFrame) frames[t];
2025 boolean gatherThis = false;
2026 for (int a = 0; a < af.alignPanels.size(); a++)
2028 AlignmentPanel ap = af.alignPanels.get(a);
2029 if (viewId.equals(ap.av.getSequenceSetId()))
2032 ap.av.setGatherViewsHere(false);
2033 ap.av.setExplodedGeometry(af.getBounds());
2034 source.addAlignmentPanel(ap, false);
2040 af.alignPanels.clear();
2041 af.closeMenuItem_actionPerformed(true);
2048 jalview.gui.VamsasApplication v_client = null;
2051 public void vamsasImport_actionPerformed(ActionEvent e)
2053 // TODO: JAL-3048 not needed for Jalview-JS
2055 if (v_client == null)
2057 // Load and try to start a session.
2058 JalviewFileChooser chooser = new JalviewFileChooser(
2059 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2061 chooser.setFileView(new JalviewFileView());
2062 chooser.setDialogTitle(
2063 MessageManager.getString("label.open_saved_vamsas_session"));
2064 chooser.setToolTipText(MessageManager.getString(
2065 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2067 int value = chooser.showOpenDialog(this);
2069 if (value == JalviewFileChooser.APPROVE_OPTION)
2071 String fle = chooser.getSelectedFile().toString();
2072 if (!vamsasImport(chooser.getSelectedFile()))
2074 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2075 MessageManager.formatMessage(
2076 "label.couldnt_import_as_vamsas_session",
2080 .getString("label.vamsas_document_import_failed"),
2081 JvOptionPane.ERROR_MESSAGE);
2087 jalview.bin.Cache.log.error(
2088 "Implementation error - load session from a running session is not supported.");
2093 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2096 * @return true if import was a success and a session was started.
2098 public boolean vamsasImport(URL url)
2100 // TODO: create progress bar
2101 if (v_client != null)
2104 jalview.bin.Cache.log.error(
2105 "Implementation error - load session from a running session is not supported.");
2111 // copy the URL content to a temporary local file
2112 // TODO: be a bit cleverer here with nio (?!)
2113 File file = File.createTempFile("vdocfromurl", ".vdj");
2114 FileOutputStream fos = new FileOutputStream(file);
2115 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2116 byte[] buffer = new byte[2048];
2118 while ((ln = bis.read(buffer)) > -1)
2120 fos.write(buffer, 0, ln);
2124 v_client = new jalview.gui.VamsasApplication(this, file,
2125 url.toExternalForm());
2126 } catch (Exception ex)
2128 jalview.bin.Cache.log.error(
2129 "Failed to create new vamsas session from contents of URL "
2134 setupVamsasConnectedGui();
2135 v_client.initial_update(); // TODO: thread ?
2136 return v_client.inSession();
2140 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2143 * @return true if import was a success and a session was started.
2145 public boolean vamsasImport(File file)
2147 if (v_client != null)
2150 jalview.bin.Cache.log.error(
2151 "Implementation error - load session from a running session is not supported.");
2155 setProgressBar(MessageManager.formatMessage(
2156 "status.importing_vamsas_session_from", new Object[]
2157 { file.getName() }), file.hashCode());
2160 v_client = new jalview.gui.VamsasApplication(this, file, null);
2161 } catch (Exception ex)
2163 setProgressBar(MessageManager.formatMessage(
2164 "status.importing_vamsas_session_from", new Object[]
2165 { file.getName() }), file.hashCode());
2166 jalview.bin.Cache.log.error(
2167 "New vamsas session from existing session file failed:", ex);
2170 setupVamsasConnectedGui();
2171 v_client.initial_update(); // TODO: thread ?
2172 setProgressBar(MessageManager.formatMessage(
2173 "status.importing_vamsas_session_from", new Object[]
2174 { file.getName() }), file.hashCode());
2175 return v_client.inSession();
2178 public boolean joinVamsasSession(String mysesid)
2180 if (v_client != null)
2182 throw new Error(MessageManager
2183 .getString("error.try_join_vamsas_session_another"));
2185 if (mysesid == null)
2188 MessageManager.getString("error.invalid_vamsas_session_id"));
2190 v_client = new VamsasApplication(this, mysesid);
2191 setupVamsasConnectedGui();
2192 v_client.initial_update();
2193 return (v_client.inSession());
2197 public void vamsasStart_actionPerformed(ActionEvent e)
2199 if (v_client == null)
2202 // we just start a default session for moment.
2204 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2205 * getProperty("LAST_DIRECTORY"));
2207 * chooser.setFileView(new JalviewFileView());
2208 * chooser.setDialogTitle("Load Vamsas file");
2209 * chooser.setToolTipText("Import");
2211 * int value = chooser.showOpenDialog(this);
2213 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2214 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2216 v_client = new VamsasApplication(this);
2217 setupVamsasConnectedGui();
2218 v_client.initial_update(); // TODO: thread ?
2222 // store current data in session.
2223 v_client.push_update(); // TODO: thread
2227 protected void setupVamsasConnectedGui()
2229 vamsasStart.setText(MessageManager.getString("label.session_update"));
2230 vamsasSave.setVisible(true);
2231 vamsasStop.setVisible(true);
2232 vamsasImport.setVisible(false); // Document import to existing session is
2233 // not possible for vamsas-client-1.0.
2236 protected void setupVamsasDisconnectedGui()
2238 vamsasSave.setVisible(false);
2239 vamsasStop.setVisible(false);
2240 vamsasImport.setVisible(true);
2242 .setText(MessageManager.getString("label.new_vamsas_session"));
2246 public void vamsasStop_actionPerformed(ActionEvent e)
2248 if (v_client != null)
2250 v_client.end_session();
2252 setupVamsasDisconnectedGui();
2256 protected void buildVamsasStMenu()
2258 if (v_client == null)
2260 String[] sess = null;
2263 sess = VamsasApplication.getSessionList();
2264 } catch (Exception e)
2266 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2272 jalview.bin.Cache.log.debug(
2273 "Got current sessions list: " + sess.length + " entries.");
2274 VamsasStMenu.removeAll();
2275 for (int i = 0; i < sess.length; i++)
2277 JMenuItem sessit = new JMenuItem();
2278 sessit.setText(sess[i]);
2279 sessit.setToolTipText(MessageManager
2280 .formatMessage("label.connect_to_session", new Object[]
2282 final Desktop dsktp = this;
2283 final String mysesid = sess[i];
2284 sessit.addActionListener(new ActionListener()
2288 public void actionPerformed(ActionEvent e)
2290 if (dsktp.v_client == null)
2292 Thread rthr = new Thread(new Runnable()
2298 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2299 dsktp.setupVamsasConnectedGui();
2300 dsktp.v_client.initial_update();
2308 VamsasStMenu.add(sessit);
2310 // don't show an empty menu.
2311 VamsasStMenu.setVisible(sess.length > 0);
2316 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2317 VamsasStMenu.removeAll();
2318 VamsasStMenu.setVisible(false);
2323 // Not interested in the content. Just hide ourselves.
2324 VamsasStMenu.setVisible(false);
2329 public void vamsasSave_actionPerformed(ActionEvent e)
2331 // TODO: JAL-3048 not needed for Jalview-JS
2333 if (v_client != null)
2335 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2336 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2339 chooser.setFileView(new JalviewFileView());
2340 chooser.setDialogTitle(MessageManager
2341 .getString("label.save_vamsas_document_archive"));
2343 int value = chooser.showSaveDialog(this);
2345 if (value == JalviewFileChooser.APPROVE_OPTION)
2347 java.io.File choice = chooser.getSelectedFile();
2348 JPanel progpanel = addProgressPanel(MessageManager
2349 .formatMessage("label.saving_vamsas_doc", new Object[]
2350 { choice.getName() }));
2351 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2352 String warnmsg = null;
2353 String warnttl = null;
2356 v_client.vclient.storeDocument(choice);
2359 warnttl = "Serious Problem saving Vamsas Document";
2360 warnmsg = ex.toString();
2361 jalview.bin.Cache.log
2362 .error("Error Whilst saving document to " + choice, ex);
2364 } catch (Exception ex)
2366 warnttl = "Problem saving Vamsas Document.";
2367 warnmsg = ex.toString();
2368 jalview.bin.Cache.log.warn(
2369 "Exception Whilst saving document to " + choice, ex);
2372 removeProgressPanel(progpanel);
2373 if (warnmsg != null)
2375 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2377 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2383 JPanel vamUpdate = null;
2386 * hide vamsas user gui bits when a vamsas document event is being handled.
2389 * true to hide gui, false to reveal gui
2391 public void setVamsasUpdate(boolean b)
2393 Cache.log.debug("Setting gui for Vamsas update "
2394 + (b ? "in progress" : "finished"));
2396 if (vamUpdate != null)
2398 this.removeProgressPanel(vamUpdate);
2402 vamUpdate = this.addProgressPanel(
2403 MessageManager.getString("label.updating_vamsas_session"));
2405 vamsasStart.setVisible(!b);
2406 vamsasStop.setVisible(!b);
2407 vamsasSave.setVisible(!b);
2410 public JInternalFrame[] getAllFrames()
2412 return desktop.getAllFrames();
2416 * Checks the given url to see if it gives a response indicating that the user
2417 * should be informed of a new questionnaire.
2421 public void checkForQuestionnaire(String url)
2423 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2424 // javax.swing.SwingUtilities.invokeLater(jvq);
2425 new Thread(jvq).start();
2428 public void checkURLLinks()
2430 // Thread off the URL link checker
2431 addDialogThread(new Runnable()
2436 if (Cache.getDefault("CHECKURLLINKS", true))
2438 // check what the actual links are - if it's just the default don't
2439 // bother with the warning
2440 List<String> links = Preferences.sequenceUrlLinks
2443 // only need to check links if there is one with a
2444 // SEQUENCE_ID which is not the default EMBL_EBI link
2445 ListIterator<String> li = links.listIterator();
2446 boolean check = false;
2447 List<JLabel> urls = new ArrayList<>();
2448 while (li.hasNext())
2450 String link = li.next();
2451 if (link.contains(SEQUENCE_ID)
2452 && !UrlConstants.isDefaultString(link))
2455 int barPos = link.indexOf("|");
2456 String urlMsg = barPos == -1 ? link
2457 : link.substring(0, barPos) + ": "
2458 + link.substring(barPos + 1);
2459 urls.add(new JLabel(urlMsg));
2467 // ask user to check in case URL links use old style tokens
2468 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2469 JPanel msgPanel = new JPanel();
2470 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2471 msgPanel.add(Box.createVerticalGlue());
2472 JLabel msg = new JLabel(MessageManager
2473 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2474 JLabel msg2 = new JLabel(MessageManager
2475 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2477 for (JLabel url : urls)
2483 final JCheckBox jcb = new JCheckBox(
2484 MessageManager.getString("label.do_not_display_again"));
2485 jcb.addActionListener(new ActionListener()
2488 public void actionPerformed(ActionEvent e)
2490 // update Cache settings for "don't show this again"
2491 boolean showWarningAgain = !jcb.isSelected();
2492 Cache.setProperty("CHECKURLLINKS",
2493 Boolean.valueOf(showWarningAgain).toString());
2498 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2500 .getString("label.SEQUENCE_ID_no_longer_used"),
2501 JvOptionPane.WARNING_MESSAGE);
2508 * Proxy class for JDesktopPane which optionally displays the current memory
2509 * usage and highlights the desktop area with a red bar if free memory runs low.
2513 public class MyDesktopPane extends JDesktopPane
2516 private static final float ONE_MB = 1048576f;
2518 boolean showMemoryUsage = false;
2522 java.text.NumberFormat df;
2524 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2527 public MyDesktopPane(boolean showMemoryUsage)
2529 showMemoryUsage(showMemoryUsage);
2532 public void showMemoryUsage(boolean showMemory)
2534 this.showMemoryUsage = showMemory;
2537 Thread worker = new Thread(this);
2543 public boolean isShowMemoryUsage()
2545 return showMemoryUsage;
2551 df = java.text.NumberFormat.getNumberInstance();
2552 df.setMaximumFractionDigits(2);
2553 runtime = Runtime.getRuntime();
2555 while (showMemoryUsage)
2559 maxMemory = runtime.maxMemory() / ONE_MB;
2560 allocatedMemory = runtime.totalMemory() / ONE_MB;
2561 freeMemory = runtime.freeMemory() / ONE_MB;
2562 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2564 percentUsage = (totalFreeMemory / maxMemory) * 100;
2566 // if (percentUsage < 20)
2568 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2570 // instance.set.setBorder(border1);
2573 // sleep after showing usage
2575 } catch (Exception ex)
2577 ex.printStackTrace();
2583 public void paintComponent(Graphics g)
2585 if (showMemoryUsage && g != null && df != null)
2587 if (percentUsage < 20)
2589 g.setColor(Color.red);
2591 FontMetrics fm = g.getFontMetrics();
2594 g.drawString(MessageManager.formatMessage("label.memory_stats",
2596 { df.format(totalFreeMemory), df.format(maxMemory),
2597 df.format(percentUsage) }),
2598 10, getHeight() - fm.getHeight());
2605 * Accessor method to quickly get all the AlignmentFrames loaded.
2607 * @return an array of AlignFrame, or null if none found
2609 public static AlignFrame[] getAlignFrames()
2611 if (Jalview.isHeadlessMode())
2613 // Desktop.desktop is null in headless mode
2614 return new AlignFrame[] { Jalview.currentAlignFrame };
2617 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2623 List<AlignFrame> avp = new ArrayList<>();
2625 for (int i = frames.length - 1; i > -1; i--)
2627 if (frames[i] instanceof AlignFrame)
2629 avp.add((AlignFrame) frames[i]);
2631 else if (frames[i] instanceof SplitFrame)
2634 * Also check for a split frame containing an AlignFrame
2636 GSplitFrame sf = (GSplitFrame) frames[i];
2637 if (sf.getTopFrame() instanceof AlignFrame)
2639 avp.add((AlignFrame) sf.getTopFrame());
2641 if (sf.getBottomFrame() instanceof AlignFrame)
2643 avp.add((AlignFrame) sf.getBottomFrame());
2647 if (avp.size() == 0)
2651 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2656 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2660 public GStructureViewer[] getJmols()
2662 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2668 List<GStructureViewer> avp = new ArrayList<>();
2670 for (int i = frames.length - 1; i > -1; i--)
2672 if (frames[i] instanceof AppJmol)
2674 GStructureViewer af = (GStructureViewer) frames[i];
2678 if (avp.size() == 0)
2682 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2687 * Add Groovy Support to Jalview
2690 public void groovyShell_actionPerformed()
2694 openGroovyConsole();
2695 } catch (Exception ex)
2697 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2698 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2700 MessageManager.getString("label.couldnt_create_groovy_shell"),
2701 MessageManager.getString("label.groovy_support_failed"),
2702 JvOptionPane.ERROR_MESSAGE);
2707 * Open the Groovy console
2709 void openGroovyConsole()
2711 if (groovyConsole == null)
2713 groovyConsole = new groovy.ui.Console();
2714 groovyConsole.setVariable("Jalview", this);
2715 groovyConsole.run();
2718 * We allow only one console at a time, so that AlignFrame menu option
2719 * 'Calculate | Run Groovy script' is unambiguous.
2720 * Disable 'Groovy Console', and enable 'Run script', when the console is
2721 * opened, and the reverse when it is closed
2723 Window window = (Window) groovyConsole.getFrame();
2724 window.addWindowListener(new WindowAdapter()
2727 public void windowClosed(WindowEvent e)
2730 * rebind CMD-Q from Groovy Console to Jalview Quit
2733 enableExecuteGroovy(false);
2739 * show Groovy console window (after close and reopen)
2741 ((Window) groovyConsole.getFrame()).setVisible(true);
2744 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2745 * and disable opening a second console
2747 enableExecuteGroovy(true);
2751 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2754 protected void addQuitHandler()
2756 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2757 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2758 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2760 getRootPane().getActionMap().put("Quit", new AbstractAction()
2763 public void actionPerformed(ActionEvent e)
2771 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2774 * true if Groovy console is open
2776 public void enableExecuteGroovy(boolean enabled)
2779 * disable opening a second Groovy console
2780 * (or re-enable when the console is closed)
2782 groovyShell.setEnabled(!enabled);
2784 AlignFrame[] alignFrames = getAlignFrames();
2785 if (alignFrames != null)
2787 for (AlignFrame af : alignFrames)
2789 af.setGroovyEnabled(enabled);
2795 * Progress bars managed by the IProgressIndicator method.
2797 private Hashtable<Long, JPanel> progressBars;
2799 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2804 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2807 public void setProgressBar(String message, long id)
2809 if (progressBars == null)
2811 progressBars = new Hashtable<>();
2812 progressBarHandlers = new Hashtable<>();
2815 if (progressBars.get(new Long(id)) != null)
2817 JPanel panel = progressBars.remove(new Long(id));
2818 if (progressBarHandlers.contains(new Long(id)))
2820 progressBarHandlers.remove(new Long(id));
2822 removeProgressPanel(panel);
2826 progressBars.put(new Long(id), addProgressPanel(message));
2833 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2834 * jalview.gui.IProgressIndicatorHandler)
2837 public void registerHandler(final long id,
2838 final IProgressIndicatorHandler handler)
2840 if (progressBarHandlers == null
2841 || !progressBars.containsKey(new Long(id)))
2843 throw new Error(MessageManager.getString(
2844 "error.call_setprogressbar_before_registering_handler"));
2846 progressBarHandlers.put(new Long(id), handler);
2847 final JPanel progressPanel = progressBars.get(new Long(id));
2848 if (handler.canCancel())
2850 JButton cancel = new JButton(
2851 MessageManager.getString("action.cancel"));
2852 final IProgressIndicator us = this;
2853 cancel.addActionListener(new ActionListener()
2857 public void actionPerformed(ActionEvent e)
2859 handler.cancelActivity(id);
2860 us.setProgressBar(MessageManager
2861 .formatMessage("label.cancelled_params", new Object[]
2862 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2866 progressPanel.add(cancel, BorderLayout.EAST);
2872 * @return true if any progress bars are still active
2875 public boolean operationInProgress()
2877 if (progressBars != null && progressBars.size() > 0)
2885 * This will return the first AlignFrame holding the given viewport instance. It
2886 * will break if there are more than one AlignFrames viewing a particular av.
2889 * @return alignFrame for viewport
2891 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2893 if (desktop != null)
2895 AlignmentPanel[] aps = getAlignmentPanels(
2896 viewport.getSequenceSetId());
2897 for (int panel = 0; aps != null && panel < aps.length; panel++)
2899 if (aps[panel] != null && aps[panel].av == viewport)
2901 return aps[panel].alignFrame;
2908 public VamsasApplication getVamsasApplication()
2915 * flag set if jalview GUI is being operated programmatically
2917 private boolean inBatchMode = false;
2920 * check if jalview GUI is being operated programmatically
2922 * @return inBatchMode
2924 public boolean isInBatchMode()
2930 * set flag if jalview GUI is being operated programmatically
2932 * @param inBatchMode
2934 public void setInBatchMode(boolean inBatchMode)
2936 this.inBatchMode = inBatchMode;
2939 public void startServiceDiscovery()
2941 startServiceDiscovery(false);
2944 public void startServiceDiscovery(boolean blocking)
2946 boolean alive = true;
2947 Thread t0 = null, t1 = null, t2 = null;
2948 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2951 // todo: changesupport handlers need to be transferred
2952 if (discoverer == null)
2954 discoverer = new jalview.ws.jws1.Discoverer();
2955 // register PCS handler for desktop.
2956 discoverer.addPropertyChangeListener(changeSupport);
2958 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2959 // until we phase out completely
2960 (t0 = new Thread(discoverer)).start();
2963 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2965 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2966 .startDiscoverer(changeSupport);
2970 // TODO: do rest service discovery
2979 } catch (Exception e)
2982 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2983 || (t3 != null && t3.isAlive())
2984 || (t0 != null && t0.isAlive());
2990 * called to check if the service discovery process completed successfully.
2994 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2996 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2998 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2999 .getErrorMessages();
3002 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3004 if (serviceChangedDialog == null)
3006 // only run if we aren't already displaying one of these.
3007 addDialogThread(serviceChangedDialog = new Runnable()
3014 * JalviewDialog jd =new JalviewDialog() {
3016 * @Override protected void cancelPressed() { // TODO
3017 * Auto-generated method stub
3019 * }@Override protected void okPressed() { // TODO
3020 * Auto-generated method stub
3022 * }@Override protected void raiseClosed() { // TODO
3023 * Auto-generated method stub
3025 * } }; jd.initDialogFrame(new
3026 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3027 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3028 * + " or mis-configured HTTP proxy settings.<br/>" +
3029 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3031 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3032 * ), true, true, "Web Service Configuration Problem", 450,
3035 * jd.waitForInput();
3037 JvOptionPane.showConfirmDialog(Desktop.desktop,
3038 new JLabel("<html><table width=\"450\"><tr><td>"
3039 + ermsg + "</td></tr></table>"
3040 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3041 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3042 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3043 + " Tools->Preferences dialog box to change them.</p></html>"),
3044 "Web Service Configuration Problem",
3045 JvOptionPane.DEFAULT_OPTION,
3046 JvOptionPane.ERROR_MESSAGE);
3047 serviceChangedDialog = null;
3056 "Errors reported by JABA discovery service. Check web services preferences.\n"
3063 private Runnable serviceChangedDialog = null;
3066 * start a thread to open a URL in the configured browser. Pops up a warning
3067 * dialog to the user if there is an exception when calling out to the browser
3072 public static void showUrl(final String url)
3074 showUrl(url, Desktop.instance);
3078 * Like showUrl but allows progress handler to be specified
3082 * (null) or object implementing IProgressIndicator
3084 public static void showUrl(final String url,
3085 final IProgressIndicator progress)
3087 new Thread(new Runnable()
3094 if (progress != null)
3096 progress.setProgressBar(MessageManager
3097 .formatMessage("status.opening_params", new Object[]
3098 { url }), this.hashCode());
3100 jalview.util.BrowserLauncher.openURL(url);
3101 } catch (Exception ex)
3103 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3105 .getString("label.web_browser_not_found_unix"),
3106 MessageManager.getString("label.web_browser_not_found"),
3107 JvOptionPane.WARNING_MESSAGE);
3109 ex.printStackTrace();
3111 if (progress != null)
3113 progress.setProgressBar(null, this.hashCode());
3119 public static WsParamSetManager wsparamManager = null;
3121 public static ParamManager getUserParameterStore()
3123 if (wsparamManager == null)
3125 wsparamManager = new WsParamSetManager();
3127 return wsparamManager;
3131 * static hyperlink handler proxy method for use by Jalview's internal windows
3135 public static void hyperlinkUpdate(HyperlinkEvent e)
3137 if (e.getEventType() == EventType.ACTIVATED)
3142 url = e.getURL().toString();
3143 Desktop.showUrl(url);
3144 } catch (Exception x)
3148 if (Cache.log != null)
3150 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3155 "Couldn't handle string " + url + " as a URL.");
3158 // ignore any exceptions due to dud links.
3165 * single thread that handles display of dialogs to user.
3167 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3170 * flag indicating if dialogExecutor should try to acquire a permit
3172 private volatile boolean dialogPause = true;
3177 private java.util.concurrent.Semaphore block = new Semaphore(0);
3179 private static groovy.ui.Console groovyConsole;
3182 * add another dialog thread to the queue
3186 public void addDialogThread(final Runnable prompter)
3188 dialogExecutor.submit(new Runnable()
3198 } catch (InterruptedException x)
3203 if (instance == null)
3209 SwingUtilities.invokeAndWait(prompter);
3210 } catch (Exception q)
3212 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3218 public void startDialogQueue()
3220 // set the flag so we don't pause waiting for another permit and semaphore
3221 // the current task to begin
3222 dialogPause = false;
3227 * Outputs an image of the desktop to file in EPS format, after prompting the
3228 * user for choice of Text or Lineart character rendering (unless a preference
3229 * has been set). The file name is generated as
3232 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3236 protected void snapShotWindow_actionPerformed(ActionEvent e)
3238 // currently the menu option to do this is not shown
3241 int width = getWidth();
3242 int height = getHeight();
3244 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3245 ImageWriterI writer = new ImageWriterI()
3248 public void exportImage(Graphics g) throws Exception
3251 Cache.log.info("Successfully written snapshot to file "
3252 + of.getAbsolutePath());
3255 String title = "View of desktop";
3256 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3258 exporter.doExport(of, this, width, height, title);
3262 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3263 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3264 * location last time the view was expanded (if any). However it does not
3265 * remember the split pane divider location - this is set to match the
3266 * 'exploding' frame.
3270 public void explodeViews(SplitFrame sf)
3272 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3273 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3274 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3276 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3278 int viewCount = topPanels.size();
3285 * Processing in reverse order works, forwards order leaves the first panels
3286 * not visible. I don't know why!
3288 for (int i = viewCount - 1; i >= 0; i--)
3291 * Make new top and bottom frames. These take over the respective
3292 * AlignmentPanel objects, including their AlignmentViewports, so the
3293 * cdna/protein relationships between the viewports is carried over to the
3296 * explodedGeometry holds the (x, y) position of the previously exploded
3297 * SplitFrame, and the (width, height) of the AlignFrame component
3299 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3300 AlignFrame newTopFrame = new AlignFrame(topPanel);
3301 newTopFrame.setSize(oldTopFrame.getSize());
3302 newTopFrame.setVisible(true);
3303 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3304 .getExplodedGeometry();
3305 if (geometry != null)
3307 newTopFrame.setSize(geometry.getSize());
3310 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3311 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3312 newBottomFrame.setSize(oldBottomFrame.getSize());
3313 newBottomFrame.setVisible(true);
3314 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3315 .getExplodedGeometry();
3316 if (geometry != null)
3318 newBottomFrame.setSize(geometry.getSize());
3321 topPanel.av.setGatherViewsHere(false);
3322 bottomPanel.av.setGatherViewsHere(false);
3323 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3325 if (geometry != null)
3327 splitFrame.setLocation(geometry.getLocation());
3329 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3333 * Clear references to the panels (now relocated in the new SplitFrames)
3334 * before closing the old SplitFrame.
3337 bottomPanels.clear();
3342 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3343 * back into the given SplitFrame as additional views. Note that the gathered
3344 * frames may themselves have multiple views.
3348 public void gatherViews(GSplitFrame source)
3351 * special handling of explodedGeometry for a view within a SplitFrame: - it
3352 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3353 * height) of the AlignFrame component
3355 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3356 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3357 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3358 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3359 myBottomFrame.viewport
3360 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3361 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3362 myTopFrame.viewport.setGatherViewsHere(true);
3363 myBottomFrame.viewport.setGatherViewsHere(true);
3364 String topViewId = myTopFrame.viewport.getSequenceSetId();
3365 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3367 JInternalFrame[] frames = desktop.getAllFrames();
3368 for (JInternalFrame frame : frames)
3370 if (frame instanceof SplitFrame && frame != source)
3372 SplitFrame sf = (SplitFrame) frame;
3373 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3374 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3375 boolean gatherThis = false;
3376 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3378 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3379 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3380 if (topViewId.equals(topPanel.av.getSequenceSetId())
3381 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3384 topPanel.av.setGatherViewsHere(false);
3385 bottomPanel.av.setGatherViewsHere(false);
3386 topPanel.av.setExplodedGeometry(
3387 new Rectangle(sf.getLocation(), topFrame.getSize()));
3388 bottomPanel.av.setExplodedGeometry(
3389 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3390 myTopFrame.addAlignmentPanel(topPanel, false);
3391 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3397 topFrame.getAlignPanels().clear();
3398 bottomFrame.getAlignPanels().clear();
3405 * The dust settles...give focus to the tab we did this from.
3407 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3410 public static groovy.ui.Console getGroovyConsole()
3412 return groovyConsole;
3416 * handles the payload of a drag and drop event.
3418 * TODO refactor to desktop utilities class
3421 * - Data source strings extracted from the drop event
3423 * - protocol for each data source extracted from the drop event
3427 * - the payload from the drop event
3430 public static void transferFromDropTarget(List<Object> files,
3431 List<DataSourceType> protocols, DropTargetDropEvent evt,
3432 Transferable t) throws Exception
3435 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3437 // DataFlavor[] flavors = t.getTransferDataFlavors();
3438 // for (int i = 0; i < flavors.length; i++) {
3439 // if (flavors[i].isFlavorJavaFileListType()) {
3440 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3441 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3442 // for (int j = 0; j < list.size(); j++) {
3443 // File file = (File) list.get(j);
3444 // byte[] data = getDroppedFileBytes(file);
3445 // fileName.setText(file.getName() + " - " + data.length + " " +
3446 // evt.getLocation());
3447 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3448 // target.setText(new String(data));
3450 // dtde.dropComplete(true);
3455 DataFlavor uriListFlavor = new DataFlavor(
3456 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3459 urlFlavour = new DataFlavor(
3460 "application/x-java-url; class=java.net.URL");
3461 } catch (ClassNotFoundException cfe)
3463 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3466 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3471 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3472 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3473 // means url may be null.
3476 protocols.add(DataSourceType.URL);
3477 files.add(url.toString());
3478 Cache.log.debug("Drop handled as URL dataflavor "
3479 + files.get(files.size() - 1));
3484 if (Platform.isAMac())
3487 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3491 } catch (Throwable ex)
3493 Cache.log.debug("URL drop handler failed.", ex);
3496 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3498 // Works on Windows and MacOSX
3499 Cache.log.debug("Drop handled as javaFileListFlavor");
3500 for (Object file : (List) t
3501 .getTransferData(DataFlavor.javaFileListFlavor))
3504 protocols.add(DataSourceType.FILE);
3509 // Unix like behaviour
3510 boolean added = false;
3512 if (t.isDataFlavorSupported(uriListFlavor))
3514 Cache.log.debug("Drop handled as uriListFlavor");
3515 // This is used by Unix drag system
3516 data = (String) t.getTransferData(uriListFlavor);
3520 // fallback to text: workaround - on OSX where there's a JVM bug
3521 Cache.log.debug("standard URIListFlavor failed. Trying text");
3522 // try text fallback
3523 DataFlavor textDf = new DataFlavor(
3524 "text/plain;class=java.lang.String");
3525 if (t.isDataFlavorSupported(textDf))
3527 data = (String) t.getTransferData(textDf);
3530 Cache.log.debug("Plain text drop content returned "
3531 + (data == null ? "Null - failed" : data));
3536 while (protocols.size() < files.size())
3538 Cache.log.debug("Adding missing FILE protocol for "
3539 + files.get(protocols.size()));
3540 protocols.add(DataSourceType.FILE);
3542 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3543 data, "\r\n"); st.hasMoreTokens();)
3546 String s = st.nextToken();
3547 if (s.startsWith("#"))
3549 // the line is a comment (as per the RFC 2483)
3552 java.net.URI uri = new java.net.URI(s);
3553 if (uri.getScheme().toLowerCase().startsWith("http"))
3555 protocols.add(DataSourceType.URL);
3556 files.add(uri.toString());
3560 // otherwise preserve old behaviour: catch all for file objects
3561 java.io.File file = new java.io.File(uri);
3562 protocols.add(DataSourceType.FILE);
3563 files.add(file.toString());
3568 if (Cache.log.isDebugEnabled())
3570 if (data == null || !added)
3573 if (t.getTransferDataFlavors() != null
3574 && t.getTransferDataFlavors().length > 0)
3577 "Couldn't resolve drop data. Here are the supported flavors:");
3578 for (DataFlavor fl : t.getTransferDataFlavors())
3581 "Supported transfer dataflavor: " + fl.toString());
3582 Object df = t.getTransferData(fl);
3585 Cache.log.debug("Retrieves: " + df);
3589 Cache.log.debug("Retrieved nothing");
3595 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3601 if (Platform.isWindows())
3604 Cache.log.debug("Scanning dropped content for Windows Link Files");
3606 // resolve any .lnk files in the file drop
3607 for (int f = 0; f < files.size(); f++)
3609 String source = files.get(f).toString().toLowerCase();
3610 if (protocols.get(f).equals(DataSourceType.FILE)
3611 && (source.endsWith(".lnk") || source.endsWith(".url")
3612 || source.endsWith(".site")))
3616 Object obj = files.get(f);
3617 File lf = (obj instanceof File ? (File) obj
3618 : new File((String) obj));
3619 // process link file to get a URL
3620 Cache.log.debug("Found potential link file: " + lf);
3621 WindowsShortcut wscfile = new WindowsShortcut(lf);
3622 String fullname = wscfile.getRealFilename();
3623 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3624 files.set(f, fullname);
3625 Cache.log.debug("Parsed real filename " + fullname
3626 + " to extract protocol: " + protocols.get(f));
3627 } catch (Exception ex)
3630 "Couldn't parse " + files.get(f) + " as a link file.",
3639 * Sets the Preferences property for experimental features to True or False
3640 * depending on the state of the controlling menu item
3643 protected void showExperimental_actionPerformed(boolean selected)
3645 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3649 * Answers a (possibly empty) list of any structure viewer frames (currently for
3650 * either Jmol or Chimera) which are currently open. This may optionally be
3651 * restricted to viewers of a specified class, or viewers linked to a specified
3655 * if not null, only return viewers linked to this panel
3656 * @param structureViewerClass
3657 * if not null, only return viewers of this class
3660 public List<StructureViewerBase> getStructureViewers(
3661 AlignmentPanel apanel,
3662 Class<? extends StructureViewerBase> structureViewerClass)
3664 List<StructureViewerBase> result = new ArrayList<>();
3665 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3667 for (JInternalFrame frame : frames)
3669 if (frame instanceof StructureViewerBase)
3671 if (structureViewerClass == null
3672 || structureViewerClass.isInstance(frame))
3675 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3677 result.add((StructureViewerBase) frame);