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:
379 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
380 ((JComponent)getContentPane()).putClientProperty("swingjs.overflow.hidden", "false");
381 desktop.putClientProperty("swingjs.overflow.hidden", "false");
383 getContentPane().add(desktop, BorderLayout.CENTER);
384 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
386 // This line prevents Windows Look&Feel resizing all new windows to maximum
387 // if previous window was maximised
388 desktop.setDesktopManager(new MyDesktopManager(
389 (Platform.isWindows() ? new DefaultDesktopManager()
391 ? new AquaInternalFrameManager(
392 desktop.getDesktopManager())
393 : desktop.getDesktopManager())));
395 Rectangle dims = getLastKnownDimensions("");
402 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
403 int xPos = Math.max(5, (screenSize.width - 900) / 2);
404 int yPos = Math.max(5, (screenSize.height - 650) / 2);
405 setBounds(xPos, yPos, 900, 650);
408 boolean doFullLoad = /** @j2sNative ! */true;
412 jconsole = new Console(this, showjconsole);
413 // add essential build information
414 jconsole.setHeader("Jalview Version: "
415 + jalview.bin.Cache.getProperty("VERSION") + "\n"
416 + "Jalview Installation: "
417 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
418 + "\n" + "Build Date: "
419 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
420 + "Java version: " + System.getProperty("java.version") + "\n"
421 + System.getProperty("os.arch") + " "
422 + System.getProperty("os.name") + " "
423 + System.getProperty("os.version"));
425 showConsole(showjconsole);
427 showNews.setVisible(false);
429 experimentalFeatures.setSelected(showExperimental());
431 getIdentifiersOrgData();
435 // Spawn a thread that shows the splashscreen
437 SwingUtilities.invokeLater(new Runnable()
446 // Thread off a new instance of the file chooser - this reduces the time it
447 // takes to open it later on.
448 new Thread(new Runnable()
453 Cache.log.debug("Filechooser init thread started.");
454 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
455 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
457 Cache.log.debug("Filechooser init thread finished.");
460 // Add the service change listener
461 changeSupport.addJalviewPropertyChangeListener("services",
462 new PropertyChangeListener()
466 public void propertyChange(PropertyChangeEvent evt)
468 Cache.log.debug("Firing service changed event for "
469 + evt.getNewValue());
470 JalviewServicesChanged(evt);
477 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
479 this.addWindowListener(new WindowAdapter()
482 public void windowClosing(WindowEvent evt)
489 this.addMouseListener(ma = new MouseAdapter()
492 public void mousePressed(MouseEvent evt)
494 if (evt.isPopupTrigger()) // Mac
496 showPasteMenu(evt.getX(), evt.getY());
501 public void mouseReleased(MouseEvent evt)
503 if (evt.isPopupTrigger()) // Windows
505 showPasteMenu(evt.getX(), evt.getY());
509 desktop.addMouseListener(ma);
514 * Answers true if user preferences to enable experimental features is True
519 public boolean showExperimental()
521 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
522 Boolean.FALSE.toString());
523 return Boolean.valueOf(experimental).booleanValue();
526 public void doConfigureStructurePrefs()
528 // configure services
529 StructureSelectionManager ssm = StructureSelectionManager
530 .getStructureSelectionManager(this);
531 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
533 ssm.setAddTempFacAnnot(jalview.bin.Cache
534 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
535 ssm.setProcessSecondaryStructure(jalview.bin.Cache
536 .getDefault(Preferences.STRUCT_FROM_PDB, true));
537 ssm.setSecStructServices(
538 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
542 ssm.setAddTempFacAnnot(false);
543 ssm.setProcessSecondaryStructure(false);
544 ssm.setSecStructServices(false);
548 public void checkForNews()
550 final Desktop me = this;
551 // Thread off the news reader, in case there are connection problems.
552 new Thread(new Runnable()
557 Cache.log.debug("Starting news thread.");
558 jvnews = new BlogReader(me);
559 showNews.setVisible(true);
560 Cache.log.debug("Completed news thread.");
565 public void getIdentifiersOrgData()
567 // Thread off the identifiers fetcher
568 new Thread(new Runnable()
573 Cache.log.debug("Downloading data from identifiers.org");
574 UrlDownloadClient client = new UrlDownloadClient();
577 client.download(IdOrgSettings.getUrl(),
578 IdOrgSettings.getDownloadLocation());
579 } catch (IOException e)
581 Cache.log.debug("Exception downloading identifiers.org data"
590 protected void showNews_actionPerformed(ActionEvent e)
592 showNews(showNews.isSelected());
595 void showNews(boolean visible)
597 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
598 showNews.setSelected(visible);
599 if (visible && !jvnews.isVisible())
601 new Thread(new Runnable()
606 long now = System.currentTimeMillis();
607 Desktop.instance.setProgressBar(
608 MessageManager.getString("status.refreshing_news"), now);
609 jvnews.refreshNews();
610 Desktop.instance.setProgressBar(null, now);
618 * recover the last known dimensions for a jalview window
621 * - empty string is desktop, all other windows have unique prefix
622 * @return null or last known dimensions scaled to current geometry (if last
623 * window geom was known)
625 Rectangle getLastKnownDimensions(String windowName)
627 // TODO: lock aspect ratio for scaling desktop Bug #0058199
628 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
629 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
630 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
631 String width = jalview.bin.Cache
632 .getProperty(windowName + "SCREEN_WIDTH");
633 String height = jalview.bin.Cache
634 .getProperty(windowName + "SCREEN_HEIGHT");
635 if ((x != null) && (y != null) && (width != null) && (height != null))
637 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
638 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
639 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
641 // attempt #1 - try to cope with change in screen geometry - this
642 // version doesn't preserve original jv aspect ratio.
643 // take ratio of current screen size vs original screen size.
644 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
645 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
646 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
647 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
648 // rescale the bounds depending upon the current screen geometry.
649 ix = (int) (ix * sw);
650 iw = (int) (iw * sw);
651 iy = (int) (iy * sh);
652 ih = (int) (ih * sh);
653 while (ix >= screenSize.width)
655 jalview.bin.Cache.log.debug(
656 "Window geometry location recall error: shifting horizontal to within screenbounds.");
657 ix -= screenSize.width;
659 while (iy >= screenSize.height)
661 jalview.bin.Cache.log.debug(
662 "Window geometry location recall error: shifting vertical to within screenbounds.");
663 iy -= screenSize.height;
665 jalview.bin.Cache.log.debug(
666 "Got last known dimensions for " + windowName + ": x:" + ix
667 + " y:" + iy + " width:" + iw + " height:" + ih);
669 // return dimensions for new instance
670 return new Rectangle(ix, iy, iw, ih);
675 private void doVamsasClientCheck()
677 if (Cache.vamsasJarsPresent())
679 setupVamsasDisconnectedGui();
680 VamsasMenu.setVisible(true);
681 final Desktop us = this;
682 VamsasMenu.addMenuListener(new MenuListener()
684 // this listener remembers when the menu was first selected, and
685 // doesn't rebuild the session list until it has been cleared and
687 boolean refresh = true;
690 public void menuCanceled(MenuEvent e)
696 public void menuDeselected(MenuEvent e)
702 public void menuSelected(MenuEvent e)
706 us.buildVamsasStMenu();
711 vamsasStart.setVisible(true);
715 void showPasteMenu(int x, int y)
717 JPopupMenu popup = new JPopupMenu();
718 JMenuItem item = new JMenuItem(
719 MessageManager.getString("label.paste_new_window"));
720 item.addActionListener(new ActionListener()
723 public void actionPerformed(ActionEvent evt)
730 popup.show(this, x, y);
737 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
738 Transferable contents = c.getContents(this);
740 if (contents != null)
742 String file = (String) contents
743 .getTransferData(DataFlavor.stringFlavor);
745 FileFormatI format = new IdentifyFile().identify(file,
746 DataSourceType.PASTE);
748 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
751 } catch (Exception ex)
754 "Unable to paste alignment from system clipboard:\n" + ex);
759 * Adds and opens the given frame to the desktop
770 public static synchronized void addInternalFrame(
771 final JInternalFrame frame, String title, int w, int h)
773 addInternalFrame(frame, title, true, w, h, true, false);
777 * Add an internal frame to the Jalview desktop
784 * When true, display frame immediately, otherwise, caller must call
785 * setVisible themselves.
791 public static synchronized void addInternalFrame(
792 final JInternalFrame frame, String title, boolean makeVisible,
795 addInternalFrame(frame, title, makeVisible, w, h, true, false);
799 * Add an internal frame to the Jalview desktop and make it visible
812 public static synchronized void addInternalFrame(
813 final JInternalFrame frame, String title, int w, int h,
816 addInternalFrame(frame, title, true, w, h, resizable, false);
820 * Add an internal frame to the Jalview desktop
827 * When true, display frame immediately, otherwise, caller must call
828 * setVisible themselves.
835 * @param ignoreMinSize
836 * Do not set the default minimum size for frame
838 public static synchronized void addInternalFrame(
839 final JInternalFrame frame, String title, boolean makeVisible,
840 int w, int h, boolean resizable, boolean ignoreMinSize)
843 // TODO: allow callers to determine X and Y position of frame (eg. via
845 // TODO: consider fixing method to update entries in the window submenu with
846 // the current window title
848 frame.setTitle(title);
849 if (frame.getWidth() < 1 || frame.getHeight() < 1)
853 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
854 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
855 // IF JALVIEW IS RUNNING HEADLESS
856 // ///////////////////////////////////////////////
857 if (instance == null || (System.getProperty("java.awt.headless") != null
858 && System.getProperty("java.awt.headless").equals("true")))
867 frame.setMinimumSize(
868 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
870 // Set default dimension for Alignment Frame window.
871 // The Alignment Frame window could be added from a number of places,
873 // I did this here in order not to miss out on any Alignment frame.
874 if (frame instanceof AlignFrame)
876 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
877 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
881 frame.setVisible(makeVisible);
882 frame.setClosable(true);
883 frame.setResizable(resizable);
884 frame.setMaximizable(resizable);
885 frame.setIconifiable(resizable);
886 frame.setOpaque(/** @j2sNative true || */
889 if (frame.getX() < 1 && frame.getY() < 1)
891 frame.setLocation(xOffset * openFrameCount,
892 yOffset * ((openFrameCount - 1) % 10) + yOffset);
896 * add an entry for the new frame in the Window menu
897 * (and remove it when the frame is closed)
899 final JMenuItem menuItem = new JMenuItem(title);
900 frame.addInternalFrameListener(new InternalFrameAdapter()
903 public void internalFrameActivated(InternalFrameEvent evt)
905 JInternalFrame itf = desktop.getSelectedFrame();
908 if (itf instanceof AlignFrame)
910 Jalview.setCurrentAlignFrame((AlignFrame) itf);
917 public void internalFrameClosed(InternalFrameEvent evt)
919 PaintRefresher.RemoveComponent(frame);
922 * defensive check to prevent frames being
923 * added half off the window
925 if (openFrameCount > 0)
931 * ensure no reference to alignFrame retained by menu item listener
933 if (menuItem.getActionListeners().length > 0)
935 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
937 windowMenu.remove(menuItem);
941 menuItem.addActionListener(new ActionListener()
944 public void actionPerformed(ActionEvent e)
948 frame.setSelected(true);
949 frame.setIcon(false);
950 } catch (java.beans.PropertyVetoException ex)
952 // System.err.println(ex.toString());
957 setKeyBindings(frame);
961 windowMenu.add(menuItem);
966 frame.setSelected(true);
967 frame.requestFocus();
968 } catch (java.beans.PropertyVetoException ve)
970 } catch (java.lang.ClassCastException cex)
973 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
979 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
984 private static void setKeyBindings(JInternalFrame frame)
986 @SuppressWarnings("serial")
987 final Action closeAction = new AbstractAction()
990 public void actionPerformed(ActionEvent e)
997 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
999 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1000 InputEvent.CTRL_DOWN_MASK);
1001 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1002 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1004 InputMap inputMap = frame
1005 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1006 String ctrlW = ctrlWKey.toString();
1007 inputMap.put(ctrlWKey, ctrlW);
1008 inputMap.put(cmdWKey, ctrlW);
1010 ActionMap actionMap = frame.getActionMap();
1011 actionMap.put(ctrlW, closeAction);
1015 public void lostOwnership(Clipboard clipboard, Transferable contents)
1019 Desktop.jalviewClipboard = null;
1022 internalCopy = false;
1026 public void dragEnter(DropTargetDragEvent evt)
1031 public void dragExit(DropTargetEvent evt)
1036 public void dragOver(DropTargetDragEvent evt)
1041 public void dropActionChanged(DropTargetDragEvent evt)
1052 public void drop(DropTargetDropEvent evt)
1054 boolean success = true;
1055 // JAL-1552 - acceptDrop required before getTransferable call for
1056 // Java's Transferable for native dnd
1057 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1058 Transferable t = evt.getTransferable();
1059 List<Object> files = new ArrayList<>();
1060 List<DataSourceType> protocols = new ArrayList<>();
1064 Desktop.transferFromDropTarget(files, protocols, evt, t);
1065 } catch (Exception e)
1067 e.printStackTrace();
1075 for (int i = 0; i < files.size(); i++)
1077 // BH 2018 File or String
1078 Object file = files.get(i);
1079 String fileName = file.toString();
1080 DataSourceType protocol = (protocols == null)
1081 ? DataSourceType.FILE
1083 FileFormatI format = null;
1085 if (fileName.endsWith(".jar"))
1087 format = FileFormat.Jalview;
1092 format = new IdentifyFile().identify(file, protocol);
1095 new FileLoader().LoadFile(null, file, protocol, format);
1098 } catch (Exception ex)
1103 evt.dropComplete(success); // need this to ensure input focus is properly
1104 // transfered to any new windows created
1114 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1116 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1117 JalviewFileChooser chooser = JalviewFileChooser
1118 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1120 chooser.setFileView(new JalviewFileView());
1121 chooser.setDialogTitle(
1122 MessageManager.getString("label.open_local_file"));
1123 chooser.setToolTipText(MessageManager.getString("action.open"));
1125 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1131 File selectedFile = chooser.getSelectedFile();
1132 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1134 FileFormatI format = chooser.getSelectedFormat();
1137 * Call IdentifyFile to verify the file contains what its extension implies.
1138 * Skip this step for dynamically added file formats, because
1139 * IdentifyFile does not know how to recognise them.
1141 if (FileFormats.getInstance().isIdentifiable(format))
1145 format = new IdentifyFile().identify(selectedFile,
1146 DataSourceType.FILE);
1147 } catch (FileFormatException e)
1149 // format = null; //??
1153 new FileLoader().LoadFile(viewport, selectedFile,
1154 DataSourceType.FILE, format);
1156 }).showOpenDialog(this);
1160 * Shows a dialog for input of a URL at which to retrieve alignment data
1165 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1167 // This construct allows us to have a wider textfield
1169 JLabel label = new JLabel(
1170 MessageManager.getString("label.input_file_url"));
1172 JPanel panel = new JPanel(new GridLayout(2, 1));
1176 * the URL to fetch is
1177 * Java: an editable combobox with history
1178 * JS: (pending JAL-3038) a plain text field
1181 String urlBase = "http://www.";
1184 history = new JTextField(urlBase, 35);
1188 JComboBox<String> asCombo = new JComboBox<>();
1189 asCombo.setPreferredSize(new Dimension(400, 20));
1190 asCombo.setEditable(true);
1191 asCombo.addItem(urlBase);
1192 String historyItems = Cache.getProperty("RECENT_URL");
1193 if (historyItems != null)
1195 for (String token : historyItems.split("\\t"))
1197 asCombo.addItem(token);
1204 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1205 MessageManager.getString("action.cancel") };
1206 RunResponse action = new RunResponse(JvOptionPane.OK_OPTION) {
1210 String url = Jalview.isJS() ? ((JTextField) history).getText()
1211 : ((JComboBox<String>) history).getSelectedItem()
1214 if (url.toLowerCase().endsWith(".jar"))
1216 if (viewport != null)
1218 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1219 FileFormat.Jalview);
1223 new FileLoader().LoadFile(url, DataSourceType.URL,
1224 FileFormat.Jalview);
1229 FileFormatI format = null;
1232 format = new IdentifyFile().identify(url, DataSourceType.URL);
1233 } catch (FileFormatException e)
1235 // TODO revise error handling, distinguish between
1236 // URL not found and response not valid
1241 String msg = MessageManager.formatMessage("label.couldnt_locate", url);
1242 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1243 MessageManager.getString("label.url_not_found"),
1244 JvOptionPane.WARNING_MESSAGE);
1249 if (viewport != null)
1251 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1256 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1260 String dialogOption = MessageManager
1261 .getString("label.input_alignment_from_url");
1262 JvOptionPane.newOptionDialog(desktop).response(action)
1263 .showInternalDialog(panel, dialogOption,
1264 JvOptionPane.YES_NO_CANCEL_OPTION,
1265 JvOptionPane.PLAIN_MESSAGE, null, options,
1266 MessageManager.getString("action.ok"));
1270 * Opens the CutAndPaste window for the user to paste an alignment in to
1273 * - if not null, the pasted alignment is added to the current
1274 * alignment; if null, to a new alignment window
1277 public void inputTextboxMenuItem_actionPerformed(
1278 AlignmentViewPanel viewPanel)
1280 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1281 cap.setForInput(viewPanel);
1282 Desktop.addInternalFrame(cap,
1283 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1293 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1294 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1296 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1297 screen.height + "");
1298 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1299 getWidth(), getHeight()));
1301 if (jconsole != null)
1303 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1304 jconsole.stopConsole();
1308 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1311 if (dialogExecutor != null)
1313 dialogExecutor.shutdownNow();
1315 closeAll_actionPerformed(null);
1317 if (groovyConsole != null)
1319 // suppress a possible repeat prompt to save script
1320 groovyConsole.setDirty(false);
1321 groovyConsole.exit();
1326 private void storeLastKnownDimensions(String string, Rectangle jc)
1328 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1329 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1330 + " height:" + jc.height);
1332 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1333 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1334 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1335 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1345 public void aboutMenuItem_actionPerformed(ActionEvent e)
1347 // StringBuffer message = getAboutMessage(false);
1348 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1350 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1351 new Thread(new Runnable()
1356 new SplashScreen(true);
1361 public StringBuffer getAboutMessage(boolean shortv)
1363 StringBuffer message = new StringBuffer();
1364 message.append("<html>");
1367 message.append("<h1><strong>Version: "
1368 + jalview.bin.Cache.getProperty("VERSION")
1369 + "</strong></h1>");
1370 message.append("<strong>Last Updated: <em>"
1371 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1372 + "</em></strong>");
1378 message.append("<strong>Version "
1379 + jalview.bin.Cache.getProperty("VERSION")
1380 + "; last updated: "
1381 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1384 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1385 .equals("Checking"))
1387 message.append("<br>...Checking latest version...</br>");
1389 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1390 .equals(jalview.bin.Cache.getProperty("VERSION")))
1392 boolean red = false;
1393 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1394 .indexOf("automated build") == -1)
1397 // Displayed when code version and jnlp version do not match and code
1398 // version is not a development build
1399 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1402 message.append("<br>!! Version "
1403 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1405 + " is available for download from "
1406 + jalview.bin.Cache.getDefault("www.jalview.org",
1407 "http://www.jalview.org")
1411 message.append("</div>");
1414 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1416 "The Jalview Authors (See AUTHORS file for current list)")
1417 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1418 + "<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"
1419 + "<br><br>If you use Jalview, please cite:"
1420 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1421 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1422 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1428 * Action on requesting Help documentation
1431 public void documentationMenuItem_actionPerformed()
1437 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1441 Help.showHelpWindow();
1443 } catch (Exception ex)
1445 System.err.println("Error opening help: " + ex.getMessage());
1450 public void closeAll_actionPerformed(ActionEvent e)
1452 // TODO show a progress bar while closing?
1453 JInternalFrame[] frames = desktop.getAllFrames();
1454 for (int i = 0; i < frames.length; i++)
1458 frames[i].setClosed(true);
1459 } catch (java.beans.PropertyVetoException ex)
1463 Jalview.setCurrentAlignFrame(null);
1464 System.out.println("ALL CLOSED");
1465 if (v_client != null)
1467 // TODO clear binding to vamsas document objects on close_all
1471 * reset state of singleton objects as appropriate (clear down session state
1472 * when all windows are closed)
1474 StructureSelectionManager ssm = StructureSelectionManager
1475 .getStructureSelectionManager(this);
1483 public void raiseRelated_actionPerformed(ActionEvent e)
1485 reorderAssociatedWindows(false, false);
1489 public void minimizeAssociated_actionPerformed(ActionEvent e)
1491 reorderAssociatedWindows(true, false);
1494 void closeAssociatedWindows()
1496 reorderAssociatedWindows(false, true);
1502 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1506 protected void garbageCollect_actionPerformed(ActionEvent e)
1508 // We simply collect the garbage
1509 jalview.bin.Cache.log.debug("Collecting garbage...");
1511 jalview.bin.Cache.log.debug("Finished garbage collection.");
1518 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1522 protected void showMemusage_actionPerformed(ActionEvent e)
1524 desktop.showMemoryUsage(showMemusage.isSelected());
1531 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1535 protected void showConsole_actionPerformed(ActionEvent e)
1537 showConsole(showConsole.isSelected());
1540 Console jconsole = null;
1543 * control whether the java console is visible or not
1547 void showConsole(boolean selected)
1549 // TODO: decide if we should update properties file
1550 if (jconsole != null) // BH 2018
1552 showConsole.setSelected(selected);
1553 Cache.setProperty("SHOW_JAVA_CONSOLE",
1554 Boolean.valueOf(selected).toString());
1555 jconsole.setVisible(selected);
1559 void reorderAssociatedWindows(boolean minimize, boolean close)
1561 JInternalFrame[] frames = desktop.getAllFrames();
1562 if (frames == null || frames.length < 1)
1567 AlignmentViewport source = null, target = null;
1568 if (frames[0] instanceof AlignFrame)
1570 source = ((AlignFrame) frames[0]).getCurrentView();
1572 else if (frames[0] instanceof TreePanel)
1574 source = ((TreePanel) frames[0]).getViewPort();
1576 else if (frames[0] instanceof PCAPanel)
1578 source = ((PCAPanel) frames[0]).av;
1580 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1582 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1587 for (int i = 0; i < frames.length; i++)
1590 if (frames[i] == null)
1594 if (frames[i] instanceof AlignFrame)
1596 target = ((AlignFrame) frames[i]).getCurrentView();
1598 else if (frames[i] instanceof TreePanel)
1600 target = ((TreePanel) frames[i]).getViewPort();
1602 else if (frames[i] instanceof PCAPanel)
1604 target = ((PCAPanel) frames[i]).av;
1606 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1608 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1611 if (source == target)
1617 frames[i].setClosed(true);
1621 frames[i].setIcon(minimize);
1624 frames[i].toFront();
1628 } catch (java.beans.PropertyVetoException ex)
1643 protected void preferences_actionPerformed(ActionEvent e)
1649 * Prompts the user to choose a file and then saves the Jalview state as a
1650 * Jalview project file
1653 public void saveState_actionPerformed(boolean asCastor)
1655 JalviewFileChooser chooser = new JalviewFileChooser(
1656 asCastor ? "jvp" : "jvx",
1659 chooser.setFileView(new JalviewFileView());
1660 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1661 int option = chooser.showSaveDialog(this);
1662 if (option == JalviewFileChooser.APPROVE_OPTION)
1664 File choice = chooser.getSelectedFile();
1665 setProjectFile(choice);
1667 new Thread(new Runnable()
1672 // TODO: refactor to Jalview desktop session controller action.
1673 setProgressBar(MessageManager.formatMessage(
1674 "label.saving_jalview_project", new Object[]
1675 { choice.getName() }), choice.hashCode());
1676 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1677 choice.getParent());
1678 // TODO catch and handle errors for savestate
1679 // TODO prevent user from messing with the Desktop whilst we're saving
1684 new Jalview2XML().saveState(choice);
1688 new jalview.project.Jalview2XML().saveState(choice);
1690 } catch (OutOfMemoryError oom)
1693 "Whilst saving current state to " + choice.getName(),
1695 } catch (Exception ex)
1698 "Problems whilst trying to save to " + choice.getName(),
1700 JvOptionPane.showMessageDialog(Desktop.this,
1701 MessageManager.formatMessage(
1702 "label.error_whilst_saving_current_state_to",
1704 { choice.getName() }),
1705 MessageManager.getString("label.couldnt_save_project"),
1706 JvOptionPane.WARNING_MESSAGE);
1708 setProgressBar(null, choice.hashCode());
1714 void setProjectFile(File choice)
1716 this.projectFile = choice;
1719 public File getProjectFile()
1721 return this.projectFile;
1725 * Prompts the user to choose a file and loads in as a Jalview project file
1728 public void loadState_actionPerformed(boolean asCastor)
1730 // TODO: GET RID OF .JVX BEFORE RELEASE JIM!
1731 final String[] suffix = asCastor ? new String[] { "jvp", "jar" }
1734 final String[] desc = asCastor
1736 { "Jalview Project", "Jalview Project (old)" }
1738 { "Jalview Project" };
1739 JalviewFileChooser chooser = new JalviewFileChooser(
1740 Cache.getProperty("LAST_DIRECTORY"), suffix,
1743 chooser.setFileView(new JalviewFileView());
1744 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1745 chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
1750 File selectedFile = chooser.getSelectedFile();
1751 setProjectFile(selectedFile);
1752 final String choice = selectedFile.getAbsolutePath();
1753 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1754 new Thread(new Runnable()
1762 new Jalview2XML().loadJalviewAlign(choice);
1766 new jalview.project.Jalview2XML().loadJalviewAlign(choice);
1768 } catch (OutOfMemoryError oom)
1770 new OOMWarning("Whilst loading project from " + choice, oom);
1771 } catch (Exception ex)
1774 "Problems whilst loading project from " + choice, ex);
1775 JvOptionPane.showMessageDialog(Desktop.desktop,
1776 MessageManager.formatMessage(
1777 "label.error_whilst_loading_project_from",
1780 MessageManager.getString("label.couldnt_load_project"),
1781 JvOptionPane.WARNING_MESSAGE);
1788 chooser.showOpenDialog(this);
1792 public void inputSequence_actionPerformed(ActionEvent e)
1794 new SequenceFetcher(this);
1797 JPanel progressPanel;
1799 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1801 public void startLoading(final Object fileName)
1803 if (fileLoadingCount == 0)
1805 fileLoadingPanels.add(addProgressPanel(MessageManager
1806 .formatMessage("label.loading_file", new Object[]
1812 private JPanel addProgressPanel(String string)
1814 if (progressPanel == null)
1816 progressPanel = new JPanel(new GridLayout(1, 1));
1817 totalProgressCount = 0;
1818 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1820 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1821 JProgressBar progressBar = new JProgressBar();
1822 progressBar.setIndeterminate(true);
1824 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1826 thisprogress.add(progressBar, BorderLayout.CENTER);
1827 progressPanel.add(thisprogress);
1828 ((GridLayout) progressPanel.getLayout()).setRows(
1829 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1830 ++totalProgressCount;
1831 instance.validate();
1832 return thisprogress;
1835 int totalProgressCount = 0;
1837 private void removeProgressPanel(JPanel progbar)
1839 if (progressPanel != null)
1841 synchronized (progressPanel)
1843 progressPanel.remove(progbar);
1844 GridLayout gl = (GridLayout) progressPanel.getLayout();
1845 gl.setRows(gl.getRows() - 1);
1846 if (--totalProgressCount < 1)
1848 this.getContentPane().remove(progressPanel);
1849 progressPanel = null;
1856 public void stopLoading()
1859 if (fileLoadingCount < 1)
1861 while (fileLoadingPanels.size() > 0)
1863 removeProgressPanel(fileLoadingPanels.remove(0));
1865 fileLoadingPanels.clear();
1866 fileLoadingCount = 0;
1871 public static int getViewCount(String alignmentId)
1873 AlignmentViewport[] aps = getViewports(alignmentId);
1874 return (aps == null) ? 0 : aps.length;
1879 * @param alignmentId
1880 * - if null, all sets are returned
1881 * @return all AlignmentPanels concerning the alignmentId sequence set
1883 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1885 if (Desktop.desktop == null)
1887 // no frames created and in headless mode
1888 // TODO: verify that frames are recoverable when in headless mode
1891 List<AlignmentPanel> aps = new ArrayList<>();
1892 AlignFrame[] frames = getAlignFrames();
1897 for (AlignFrame af : frames)
1899 for (AlignmentPanel ap : af.alignPanels)
1901 if (alignmentId == null
1902 || alignmentId.equals(ap.av.getSequenceSetId()))
1908 if (aps.size() == 0)
1912 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1917 * get all the viewports on an alignment.
1919 * @param sequenceSetId
1920 * unique alignment id (may be null - all viewports returned in that
1922 * @return all viewports on the alignment bound to sequenceSetId
1924 public static AlignmentViewport[] getViewports(String sequenceSetId)
1926 List<AlignmentViewport> viewp = new ArrayList<>();
1927 if (desktop != null)
1929 AlignFrame[] frames = Desktop.getAlignFrames();
1931 for (AlignFrame afr : frames)
1933 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1934 .equals(sequenceSetId))
1936 if (afr.alignPanels != null)
1938 for (AlignmentPanel ap : afr.alignPanels)
1940 if (sequenceSetId == null
1941 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1949 viewp.add(afr.getViewport());
1953 if (viewp.size() > 0)
1955 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1962 * Explode the views in the given frame into separate AlignFrame
1966 public static void explodeViews(AlignFrame af)
1968 int size = af.alignPanels.size();
1974 for (int i = 0; i < size; i++)
1976 AlignmentPanel ap = af.alignPanels.get(i);
1977 AlignFrame newaf = new AlignFrame(ap);
1980 * Restore the view's last exploded frame geometry if known. Multiple
1981 * views from one exploded frame share and restore the same (frame)
1982 * position and size.
1984 Rectangle geometry = ap.av.getExplodedGeometry();
1985 if (geometry != null)
1987 newaf.setBounds(geometry);
1990 ap.av.setGatherViewsHere(false);
1992 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1993 AlignFrame.DEFAULT_HEIGHT);
1996 af.alignPanels.clear();
1997 af.closeMenuItem_actionPerformed(true);
2002 * Gather expanded views (separate AlignFrame's) with the same sequence set
2003 * identifier back in to this frame as additional views, and close the expanded
2004 * views. Note the expanded frames may themselves have multiple views. We take
2009 public void gatherViews(AlignFrame source)
2011 source.viewport.setGatherViewsHere(true);
2012 source.viewport.setExplodedGeometry(source.getBounds());
2013 JInternalFrame[] frames = desktop.getAllFrames();
2014 String viewId = source.viewport.getSequenceSetId();
2016 for (int t = 0; t < frames.length; t++)
2018 if (frames[t] instanceof AlignFrame && frames[t] != source)
2020 AlignFrame af = (AlignFrame) frames[t];
2021 boolean gatherThis = false;
2022 for (int a = 0; a < af.alignPanels.size(); a++)
2024 AlignmentPanel ap = af.alignPanels.get(a);
2025 if (viewId.equals(ap.av.getSequenceSetId()))
2028 ap.av.setGatherViewsHere(false);
2029 ap.av.setExplodedGeometry(af.getBounds());
2030 source.addAlignmentPanel(ap, false);
2036 af.alignPanels.clear();
2037 af.closeMenuItem_actionPerformed(true);
2044 jalview.gui.VamsasApplication v_client = null;
2047 public void vamsasImport_actionPerformed(ActionEvent e)
2049 // TODO: JAL-3048 not needed for Jalview-JS
2051 if (v_client == null)
2053 // Load and try to start a session.
2054 JalviewFileChooser chooser = new JalviewFileChooser(
2055 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2057 chooser.setFileView(new JalviewFileView());
2058 chooser.setDialogTitle(
2059 MessageManager.getString("label.open_saved_vamsas_session"));
2060 chooser.setToolTipText(MessageManager.getString(
2061 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2063 int value = chooser.showOpenDialog(this);
2065 if (value == JalviewFileChooser.APPROVE_OPTION)
2067 String fle = chooser.getSelectedFile().toString();
2068 if (!vamsasImport(chooser.getSelectedFile()))
2070 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2071 MessageManager.formatMessage(
2072 "label.couldnt_import_as_vamsas_session",
2076 .getString("label.vamsas_document_import_failed"),
2077 JvOptionPane.ERROR_MESSAGE);
2083 jalview.bin.Cache.log.error(
2084 "Implementation error - load session from a running session is not supported.");
2089 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2092 * @return true if import was a success and a session was started.
2094 public boolean vamsasImport(URL url)
2096 // TODO: create progress bar
2097 if (v_client != null)
2100 jalview.bin.Cache.log.error(
2101 "Implementation error - load session from a running session is not supported.");
2107 // copy the URL content to a temporary local file
2108 // TODO: be a bit cleverer here with nio (?!)
2109 File file = File.createTempFile("vdocfromurl", ".vdj");
2110 FileOutputStream fos = new FileOutputStream(file);
2111 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2112 byte[] buffer = new byte[2048];
2114 while ((ln = bis.read(buffer)) > -1)
2116 fos.write(buffer, 0, ln);
2120 v_client = new jalview.gui.VamsasApplication(this, file,
2121 url.toExternalForm());
2122 } catch (Exception ex)
2124 jalview.bin.Cache.log.error(
2125 "Failed to create new vamsas session from contents of URL "
2130 setupVamsasConnectedGui();
2131 v_client.initial_update(); // TODO: thread ?
2132 return v_client.inSession();
2136 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2139 * @return true if import was a success and a session was started.
2141 public boolean vamsasImport(File file)
2143 if (v_client != null)
2146 jalview.bin.Cache.log.error(
2147 "Implementation error - load session from a running session is not supported.");
2151 setProgressBar(MessageManager.formatMessage(
2152 "status.importing_vamsas_session_from", new Object[]
2153 { file.getName() }), file.hashCode());
2156 v_client = new jalview.gui.VamsasApplication(this, file, null);
2157 } catch (Exception ex)
2159 setProgressBar(MessageManager.formatMessage(
2160 "status.importing_vamsas_session_from", new Object[]
2161 { file.getName() }), file.hashCode());
2162 jalview.bin.Cache.log.error(
2163 "New vamsas session from existing session file failed:", ex);
2166 setupVamsasConnectedGui();
2167 v_client.initial_update(); // TODO: thread ?
2168 setProgressBar(MessageManager.formatMessage(
2169 "status.importing_vamsas_session_from", new Object[]
2170 { file.getName() }), file.hashCode());
2171 return v_client.inSession();
2174 public boolean joinVamsasSession(String mysesid)
2176 if (v_client != null)
2178 throw new Error(MessageManager
2179 .getString("error.try_join_vamsas_session_another"));
2181 if (mysesid == null)
2184 MessageManager.getString("error.invalid_vamsas_session_id"));
2186 v_client = new VamsasApplication(this, mysesid);
2187 setupVamsasConnectedGui();
2188 v_client.initial_update();
2189 return (v_client.inSession());
2193 public void vamsasStart_actionPerformed(ActionEvent e)
2195 if (v_client == null)
2198 // we just start a default session for moment.
2200 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2201 * getProperty("LAST_DIRECTORY"));
2203 * chooser.setFileView(new JalviewFileView());
2204 * chooser.setDialogTitle("Load Vamsas file");
2205 * chooser.setToolTipText("Import");
2207 * int value = chooser.showOpenDialog(this);
2209 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2210 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2212 v_client = new VamsasApplication(this);
2213 setupVamsasConnectedGui();
2214 v_client.initial_update(); // TODO: thread ?
2218 // store current data in session.
2219 v_client.push_update(); // TODO: thread
2223 protected void setupVamsasConnectedGui()
2225 vamsasStart.setText(MessageManager.getString("label.session_update"));
2226 vamsasSave.setVisible(true);
2227 vamsasStop.setVisible(true);
2228 vamsasImport.setVisible(false); // Document import to existing session is
2229 // not possible for vamsas-client-1.0.
2232 protected void setupVamsasDisconnectedGui()
2234 vamsasSave.setVisible(false);
2235 vamsasStop.setVisible(false);
2236 vamsasImport.setVisible(true);
2238 .setText(MessageManager.getString("label.new_vamsas_session"));
2242 public void vamsasStop_actionPerformed(ActionEvent e)
2244 if (v_client != null)
2246 v_client.end_session();
2248 setupVamsasDisconnectedGui();
2252 protected void buildVamsasStMenu()
2254 if (v_client == null)
2256 String[] sess = null;
2259 sess = VamsasApplication.getSessionList();
2260 } catch (Exception e)
2262 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2268 jalview.bin.Cache.log.debug(
2269 "Got current sessions list: " + sess.length + " entries.");
2270 VamsasStMenu.removeAll();
2271 for (int i = 0; i < sess.length; i++)
2273 JMenuItem sessit = new JMenuItem();
2274 sessit.setText(sess[i]);
2275 sessit.setToolTipText(MessageManager
2276 .formatMessage("label.connect_to_session", new Object[]
2278 final Desktop dsktp = this;
2279 final String mysesid = sess[i];
2280 sessit.addActionListener(new ActionListener()
2284 public void actionPerformed(ActionEvent e)
2286 if (dsktp.v_client == null)
2288 Thread rthr = new Thread(new Runnable()
2294 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2295 dsktp.setupVamsasConnectedGui();
2296 dsktp.v_client.initial_update();
2304 VamsasStMenu.add(sessit);
2306 // don't show an empty menu.
2307 VamsasStMenu.setVisible(sess.length > 0);
2312 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2313 VamsasStMenu.removeAll();
2314 VamsasStMenu.setVisible(false);
2319 // Not interested in the content. Just hide ourselves.
2320 VamsasStMenu.setVisible(false);
2325 public void vamsasSave_actionPerformed(ActionEvent e)
2327 // TODO: JAL-3048 not needed for Jalview-JS
2329 if (v_client != null)
2331 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2332 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2335 chooser.setFileView(new JalviewFileView());
2336 chooser.setDialogTitle(MessageManager
2337 .getString("label.save_vamsas_document_archive"));
2339 int value = chooser.showSaveDialog(this);
2341 if (value == JalviewFileChooser.APPROVE_OPTION)
2343 java.io.File choice = chooser.getSelectedFile();
2344 JPanel progpanel = addProgressPanel(MessageManager
2345 .formatMessage("label.saving_vamsas_doc", new Object[]
2346 { choice.getName() }));
2347 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2348 String warnmsg = null;
2349 String warnttl = null;
2352 v_client.vclient.storeDocument(choice);
2355 warnttl = "Serious Problem saving Vamsas Document";
2356 warnmsg = ex.toString();
2357 jalview.bin.Cache.log
2358 .error("Error Whilst saving document to " + choice, ex);
2360 } catch (Exception ex)
2362 warnttl = "Problem saving Vamsas Document.";
2363 warnmsg = ex.toString();
2364 jalview.bin.Cache.log.warn(
2365 "Exception Whilst saving document to " + choice, ex);
2368 removeProgressPanel(progpanel);
2369 if (warnmsg != null)
2371 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2373 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2379 JPanel vamUpdate = null;
2382 * hide vamsas user gui bits when a vamsas document event is being handled.
2385 * true to hide gui, false to reveal gui
2387 public void setVamsasUpdate(boolean b)
2389 Cache.log.debug("Setting gui for Vamsas update "
2390 + (b ? "in progress" : "finished"));
2392 if (vamUpdate != null)
2394 this.removeProgressPanel(vamUpdate);
2398 vamUpdate = this.addProgressPanel(
2399 MessageManager.getString("label.updating_vamsas_session"));
2401 vamsasStart.setVisible(!b);
2402 vamsasStop.setVisible(!b);
2403 vamsasSave.setVisible(!b);
2406 public JInternalFrame[] getAllFrames()
2408 return desktop.getAllFrames();
2412 * Checks the given url to see if it gives a response indicating that the user
2413 * should be informed of a new questionnaire.
2417 public void checkForQuestionnaire(String url)
2419 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2420 // javax.swing.SwingUtilities.invokeLater(jvq);
2421 new Thread(jvq).start();
2424 public void checkURLLinks()
2426 // Thread off the URL link checker
2427 addDialogThread(new Runnable()
2432 if (Cache.getDefault("CHECKURLLINKS", true))
2434 // check what the actual links are - if it's just the default don't
2435 // bother with the warning
2436 List<String> links = Preferences.sequenceUrlLinks
2439 // only need to check links if there is one with a
2440 // SEQUENCE_ID which is not the default EMBL_EBI link
2441 ListIterator<String> li = links.listIterator();
2442 boolean check = false;
2443 List<JLabel> urls = new ArrayList<>();
2444 while (li.hasNext())
2446 String link = li.next();
2447 if (link.contains(SEQUENCE_ID)
2448 && !UrlConstants.isDefaultString(link))
2451 int barPos = link.indexOf("|");
2452 String urlMsg = barPos == -1 ? link
2453 : link.substring(0, barPos) + ": "
2454 + link.substring(barPos + 1);
2455 urls.add(new JLabel(urlMsg));
2463 // ask user to check in case URL links use old style tokens
2464 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2465 JPanel msgPanel = new JPanel();
2466 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2467 msgPanel.add(Box.createVerticalGlue());
2468 JLabel msg = new JLabel(MessageManager
2469 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2470 JLabel msg2 = new JLabel(MessageManager
2471 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2473 for (JLabel url : urls)
2479 final JCheckBox jcb = new JCheckBox(
2480 MessageManager.getString("label.do_not_display_again"));
2481 jcb.addActionListener(new ActionListener()
2484 public void actionPerformed(ActionEvent e)
2486 // update Cache settings for "don't show this again"
2487 boolean showWarningAgain = !jcb.isSelected();
2488 Cache.setProperty("CHECKURLLINKS",
2489 Boolean.valueOf(showWarningAgain).toString());
2494 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2496 .getString("label.SEQUENCE_ID_no_longer_used"),
2497 JvOptionPane.WARNING_MESSAGE);
2504 * Proxy class for JDesktopPane which optionally displays the current memory
2505 * usage and highlights the desktop area with a red bar if free memory runs low.
2509 public class MyDesktopPane extends JDesktopPane
2512 private static final float ONE_MB = 1048576f;
2514 boolean showMemoryUsage = false;
2518 java.text.NumberFormat df;
2520 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2523 public MyDesktopPane(boolean showMemoryUsage)
2525 showMemoryUsage(showMemoryUsage);
2528 public void showMemoryUsage(boolean showMemory)
2530 this.showMemoryUsage = showMemory;
2533 Thread worker = new Thread(this);
2539 public boolean isShowMemoryUsage()
2541 return showMemoryUsage;
2547 df = java.text.NumberFormat.getNumberInstance();
2548 df.setMaximumFractionDigits(2);
2549 runtime = Runtime.getRuntime();
2551 while (showMemoryUsage)
2555 maxMemory = runtime.maxMemory() / ONE_MB;
2556 allocatedMemory = runtime.totalMemory() / ONE_MB;
2557 freeMemory = runtime.freeMemory() / ONE_MB;
2558 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2560 percentUsage = (totalFreeMemory / maxMemory) * 100;
2562 // if (percentUsage < 20)
2564 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2566 // instance.set.setBorder(border1);
2569 // sleep after showing usage
2571 } catch (Exception ex)
2573 ex.printStackTrace();
2579 public void paintComponent(Graphics g)
2581 if (showMemoryUsage && g != null && df != null)
2583 if (percentUsage < 20)
2585 g.setColor(Color.red);
2587 FontMetrics fm = g.getFontMetrics();
2590 g.drawString(MessageManager.formatMessage("label.memory_stats",
2592 { df.format(totalFreeMemory), df.format(maxMemory),
2593 df.format(percentUsage) }),
2594 10, getHeight() - fm.getHeight());
2601 * Accessor method to quickly get all the AlignmentFrames loaded.
2603 * @return an array of AlignFrame, or null if none found
2605 public static AlignFrame[] getAlignFrames()
2607 if (Jalview.isHeadlessMode())
2609 // Desktop.desktop is null in headless mode
2610 return new AlignFrame[] { Jalview.currentAlignFrame };
2613 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2619 List<AlignFrame> avp = new ArrayList<>();
2621 for (int i = frames.length - 1; i > -1; i--)
2623 if (frames[i] instanceof AlignFrame)
2625 avp.add((AlignFrame) frames[i]);
2627 else if (frames[i] instanceof SplitFrame)
2630 * Also check for a split frame containing an AlignFrame
2632 GSplitFrame sf = (GSplitFrame) frames[i];
2633 if (sf.getTopFrame() instanceof AlignFrame)
2635 avp.add((AlignFrame) sf.getTopFrame());
2637 if (sf.getBottomFrame() instanceof AlignFrame)
2639 avp.add((AlignFrame) sf.getBottomFrame());
2643 if (avp.size() == 0)
2647 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2652 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2656 public GStructureViewer[] getJmols()
2658 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2664 List<GStructureViewer> avp = new ArrayList<>();
2666 for (int i = frames.length - 1; i > -1; i--)
2668 if (frames[i] instanceof AppJmol)
2670 GStructureViewer af = (GStructureViewer) frames[i];
2674 if (avp.size() == 0)
2678 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2683 * Add Groovy Support to Jalview
2686 public void groovyShell_actionPerformed()
2690 openGroovyConsole();
2691 } catch (Exception ex)
2693 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2694 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2696 MessageManager.getString("label.couldnt_create_groovy_shell"),
2697 MessageManager.getString("label.groovy_support_failed"),
2698 JvOptionPane.ERROR_MESSAGE);
2703 * Open the Groovy console
2705 void openGroovyConsole()
2707 if (groovyConsole == null)
2709 groovyConsole = new groovy.ui.Console();
2710 groovyConsole.setVariable("Jalview", this);
2711 groovyConsole.run();
2714 * We allow only one console at a time, so that AlignFrame menu option
2715 * 'Calculate | Run Groovy script' is unambiguous.
2716 * Disable 'Groovy Console', and enable 'Run script', when the console is
2717 * opened, and the reverse when it is closed
2719 Window window = (Window) groovyConsole.getFrame();
2720 window.addWindowListener(new WindowAdapter()
2723 public void windowClosed(WindowEvent e)
2726 * rebind CMD-Q from Groovy Console to Jalview Quit
2729 enableExecuteGroovy(false);
2735 * show Groovy console window (after close and reopen)
2737 ((Window) groovyConsole.getFrame()).setVisible(true);
2740 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2741 * and disable opening a second console
2743 enableExecuteGroovy(true);
2747 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2750 protected void addQuitHandler()
2752 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2753 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2754 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2756 getRootPane().getActionMap().put("Quit", new AbstractAction()
2759 public void actionPerformed(ActionEvent e)
2767 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2770 * true if Groovy console is open
2772 public void enableExecuteGroovy(boolean enabled)
2775 * disable opening a second Groovy console
2776 * (or re-enable when the console is closed)
2778 groovyShell.setEnabled(!enabled);
2780 AlignFrame[] alignFrames = getAlignFrames();
2781 if (alignFrames != null)
2783 for (AlignFrame af : alignFrames)
2785 af.setGroovyEnabled(enabled);
2791 * Progress bars managed by the IProgressIndicator method.
2793 private Hashtable<Long, JPanel> progressBars;
2795 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2800 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2803 public void setProgressBar(String message, long id)
2805 if (progressBars == null)
2807 progressBars = new Hashtable<>();
2808 progressBarHandlers = new Hashtable<>();
2811 if (progressBars.get(new Long(id)) != null)
2813 JPanel panel = progressBars.remove(new Long(id));
2814 if (progressBarHandlers.contains(new Long(id)))
2816 progressBarHandlers.remove(new Long(id));
2818 removeProgressPanel(panel);
2822 progressBars.put(new Long(id), addProgressPanel(message));
2829 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2830 * jalview.gui.IProgressIndicatorHandler)
2833 public void registerHandler(final long id,
2834 final IProgressIndicatorHandler handler)
2836 if (progressBarHandlers == null
2837 || !progressBars.containsKey(new Long(id)))
2839 throw new Error(MessageManager.getString(
2840 "error.call_setprogressbar_before_registering_handler"));
2842 progressBarHandlers.put(new Long(id), handler);
2843 final JPanel progressPanel = progressBars.get(new Long(id));
2844 if (handler.canCancel())
2846 JButton cancel = new JButton(
2847 MessageManager.getString("action.cancel"));
2848 final IProgressIndicator us = this;
2849 cancel.addActionListener(new ActionListener()
2853 public void actionPerformed(ActionEvent e)
2855 handler.cancelActivity(id);
2856 us.setProgressBar(MessageManager
2857 .formatMessage("label.cancelled_params", new Object[]
2858 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2862 progressPanel.add(cancel, BorderLayout.EAST);
2868 * @return true if any progress bars are still active
2871 public boolean operationInProgress()
2873 if (progressBars != null && progressBars.size() > 0)
2881 * This will return the first AlignFrame holding the given viewport instance. It
2882 * will break if there are more than one AlignFrames viewing a particular av.
2885 * @return alignFrame for viewport
2887 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2889 if (desktop != null)
2891 AlignmentPanel[] aps = getAlignmentPanels(
2892 viewport.getSequenceSetId());
2893 for (int panel = 0; aps != null && panel < aps.length; panel++)
2895 if (aps[panel] != null && aps[panel].av == viewport)
2897 return aps[panel].alignFrame;
2904 public VamsasApplication getVamsasApplication()
2911 * flag set if jalview GUI is being operated programmatically
2913 private boolean inBatchMode = false;
2916 * check if jalview GUI is being operated programmatically
2918 * @return inBatchMode
2920 public boolean isInBatchMode()
2926 * set flag if jalview GUI is being operated programmatically
2928 * @param inBatchMode
2930 public void setInBatchMode(boolean inBatchMode)
2932 this.inBatchMode = inBatchMode;
2935 public void startServiceDiscovery()
2937 startServiceDiscovery(false);
2940 public void startServiceDiscovery(boolean blocking)
2942 boolean alive = true;
2943 Thread t0 = null, t1 = null, t2 = null;
2944 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2947 // todo: changesupport handlers need to be transferred
2948 if (discoverer == null)
2950 discoverer = new jalview.ws.jws1.Discoverer();
2951 // register PCS handler for desktop.
2952 discoverer.addPropertyChangeListener(changeSupport);
2954 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2955 // until we phase out completely
2956 (t0 = new Thread(discoverer)).start();
2959 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2961 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2962 .startDiscoverer(changeSupport);
2966 // TODO: do rest service discovery
2975 } catch (Exception e)
2978 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2979 || (t3 != null && t3.isAlive())
2980 || (t0 != null && t0.isAlive());
2986 * called to check if the service discovery process completed successfully.
2990 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2992 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2994 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2995 .getErrorMessages();
2998 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3000 if (serviceChangedDialog == null)
3002 // only run if we aren't already displaying one of these.
3003 addDialogThread(serviceChangedDialog = new Runnable()
3010 * JalviewDialog jd =new JalviewDialog() {
3012 * @Override protected void cancelPressed() { // TODO
3013 * Auto-generated method stub
3015 * }@Override protected void okPressed() { // TODO
3016 * Auto-generated method stub
3018 * }@Override protected void raiseClosed() { // TODO
3019 * Auto-generated method stub
3021 * } }; jd.initDialogFrame(new
3022 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3023 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3024 * + " or mis-configured HTTP proxy settings.<br/>" +
3025 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3027 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3028 * ), true, true, "Web Service Configuration Problem", 450,
3031 * jd.waitForInput();
3033 JvOptionPane.showConfirmDialog(Desktop.desktop,
3034 new JLabel("<html><table width=\"450\"><tr><td>"
3035 + ermsg + "</td></tr></table>"
3036 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3037 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3038 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3039 + " Tools->Preferences dialog box to change them.</p></html>"),
3040 "Web Service Configuration Problem",
3041 JvOptionPane.DEFAULT_OPTION,
3042 JvOptionPane.ERROR_MESSAGE);
3043 serviceChangedDialog = null;
3052 "Errors reported by JABA discovery service. Check web services preferences.\n"
3059 private Runnable serviceChangedDialog = null;
3062 * start a thread to open a URL in the configured browser. Pops up a warning
3063 * dialog to the user if there is an exception when calling out to the browser
3068 public static void showUrl(final String url)
3070 showUrl(url, Desktop.instance);
3074 * Like showUrl but allows progress handler to be specified
3078 * (null) or object implementing IProgressIndicator
3080 public static void showUrl(final String url,
3081 final IProgressIndicator progress)
3083 new Thread(new Runnable()
3090 if (progress != null)
3092 progress.setProgressBar(MessageManager
3093 .formatMessage("status.opening_params", new Object[]
3094 { url }), this.hashCode());
3096 jalview.util.BrowserLauncher.openURL(url);
3097 } catch (Exception ex)
3099 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3101 .getString("label.web_browser_not_found_unix"),
3102 MessageManager.getString("label.web_browser_not_found"),
3103 JvOptionPane.WARNING_MESSAGE);
3105 ex.printStackTrace();
3107 if (progress != null)
3109 progress.setProgressBar(null, this.hashCode());
3115 public static WsParamSetManager wsparamManager = null;
3117 public static ParamManager getUserParameterStore()
3119 if (wsparamManager == null)
3121 wsparamManager = new WsParamSetManager();
3123 return wsparamManager;
3127 * static hyperlink handler proxy method for use by Jalview's internal windows
3131 public static void hyperlinkUpdate(HyperlinkEvent e)
3133 if (e.getEventType() == EventType.ACTIVATED)
3138 url = e.getURL().toString();
3139 Desktop.showUrl(url);
3140 } catch (Exception x)
3144 if (Cache.log != null)
3146 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3151 "Couldn't handle string " + url + " as a URL.");
3154 // ignore any exceptions due to dud links.
3161 * single thread that handles display of dialogs to user.
3163 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3166 * flag indicating if dialogExecutor should try to acquire a permit
3168 private volatile boolean dialogPause = true;
3173 private java.util.concurrent.Semaphore block = new Semaphore(0);
3175 private static groovy.ui.Console groovyConsole;
3178 * add another dialog thread to the queue
3182 public void addDialogThread(final Runnable prompter)
3184 dialogExecutor.submit(new Runnable()
3194 } catch (InterruptedException x)
3199 if (instance == null)
3205 SwingUtilities.invokeAndWait(prompter);
3206 } catch (Exception q)
3208 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3214 public void startDialogQueue()
3216 // set the flag so we don't pause waiting for another permit and semaphore
3217 // the current task to begin
3218 dialogPause = false;
3223 * Outputs an image of the desktop to file in EPS format, after prompting the
3224 * user for choice of Text or Lineart character rendering (unless a preference
3225 * has been set). The file name is generated as
3228 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3232 protected void snapShotWindow_actionPerformed(ActionEvent e)
3234 // currently the menu option to do this is not shown
3237 int width = getWidth();
3238 int height = getHeight();
3240 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3241 ImageWriterI writer = new ImageWriterI()
3244 public void exportImage(Graphics g) throws Exception
3247 Cache.log.info("Successfully written snapshot to file "
3248 + of.getAbsolutePath());
3251 String title = "View of desktop";
3252 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3254 exporter.doExport(of, this, width, height, title);
3258 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3259 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3260 * location last time the view was expanded (if any). However it does not
3261 * remember the split pane divider location - this is set to match the
3262 * 'exploding' frame.
3266 public void explodeViews(SplitFrame sf)
3268 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3269 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3270 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3272 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3274 int viewCount = topPanels.size();
3281 * Processing in reverse order works, forwards order leaves the first panels
3282 * not visible. I don't know why!
3284 for (int i = viewCount - 1; i >= 0; i--)
3287 * Make new top and bottom frames. These take over the respective
3288 * AlignmentPanel objects, including their AlignmentViewports, so the
3289 * cdna/protein relationships between the viewports is carried over to the
3292 * explodedGeometry holds the (x, y) position of the previously exploded
3293 * SplitFrame, and the (width, height) of the AlignFrame component
3295 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3296 AlignFrame newTopFrame = new AlignFrame(topPanel);
3297 newTopFrame.setSize(oldTopFrame.getSize());
3298 newTopFrame.setVisible(true);
3299 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3300 .getExplodedGeometry();
3301 if (geometry != null)
3303 newTopFrame.setSize(geometry.getSize());
3306 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3307 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3308 newBottomFrame.setSize(oldBottomFrame.getSize());
3309 newBottomFrame.setVisible(true);
3310 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3311 .getExplodedGeometry();
3312 if (geometry != null)
3314 newBottomFrame.setSize(geometry.getSize());
3317 topPanel.av.setGatherViewsHere(false);
3318 bottomPanel.av.setGatherViewsHere(false);
3319 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3321 if (geometry != null)
3323 splitFrame.setLocation(geometry.getLocation());
3325 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3329 * Clear references to the panels (now relocated in the new SplitFrames)
3330 * before closing the old SplitFrame.
3333 bottomPanels.clear();
3338 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3339 * back into the given SplitFrame as additional views. Note that the gathered
3340 * frames may themselves have multiple views.
3344 public void gatherViews(GSplitFrame source)
3347 * special handling of explodedGeometry for a view within a SplitFrame: - it
3348 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3349 * height) of the AlignFrame component
3351 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3352 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3353 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3354 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3355 myBottomFrame.viewport
3356 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3357 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3358 myTopFrame.viewport.setGatherViewsHere(true);
3359 myBottomFrame.viewport.setGatherViewsHere(true);
3360 String topViewId = myTopFrame.viewport.getSequenceSetId();
3361 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3363 JInternalFrame[] frames = desktop.getAllFrames();
3364 for (JInternalFrame frame : frames)
3366 if (frame instanceof SplitFrame && frame != source)
3368 SplitFrame sf = (SplitFrame) frame;
3369 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3370 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3371 boolean gatherThis = false;
3372 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3374 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3375 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3376 if (topViewId.equals(topPanel.av.getSequenceSetId())
3377 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3380 topPanel.av.setGatherViewsHere(false);
3381 bottomPanel.av.setGatherViewsHere(false);
3382 topPanel.av.setExplodedGeometry(
3383 new Rectangle(sf.getLocation(), topFrame.getSize()));
3384 bottomPanel.av.setExplodedGeometry(
3385 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3386 myTopFrame.addAlignmentPanel(topPanel, false);
3387 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3393 topFrame.getAlignPanels().clear();
3394 bottomFrame.getAlignPanels().clear();
3401 * The dust settles...give focus to the tab we did this from.
3403 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3406 public static groovy.ui.Console getGroovyConsole()
3408 return groovyConsole;
3412 * handles the payload of a drag and drop event.
3414 * TODO refactor to desktop utilities class
3417 * - Data source strings extracted from the drop event
3419 * - protocol for each data source extracted from the drop event
3423 * - the payload from the drop event
3426 public static void transferFromDropTarget(List<Object> files,
3427 List<DataSourceType> protocols, DropTargetDropEvent evt,
3428 Transferable t) throws Exception
3431 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3433 // DataFlavor[] flavors = t.getTransferDataFlavors();
3434 // for (int i = 0; i < flavors.length; i++) {
3435 // if (flavors[i].isFlavorJavaFileListType()) {
3436 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3437 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3438 // for (int j = 0; j < list.size(); j++) {
3439 // File file = (File) list.get(j);
3440 // byte[] data = getDroppedFileBytes(file);
3441 // fileName.setText(file.getName() + " - " + data.length + " " +
3442 // evt.getLocation());
3443 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3444 // target.setText(new String(data));
3446 // dtde.dropComplete(true);
3451 DataFlavor uriListFlavor = new DataFlavor(
3452 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3455 urlFlavour = new DataFlavor(
3456 "application/x-java-url; class=java.net.URL");
3457 } catch (ClassNotFoundException cfe)
3459 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3462 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3467 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3468 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3469 // means url may be null.
3472 protocols.add(DataSourceType.URL);
3473 files.add(url.toString());
3474 Cache.log.debug("Drop handled as URL dataflavor "
3475 + files.get(files.size() - 1));
3480 if (Platform.isAMac())
3483 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3487 } catch (Throwable ex)
3489 Cache.log.debug("URL drop handler failed.", ex);
3492 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3494 // Works on Windows and MacOSX
3495 Cache.log.debug("Drop handled as javaFileListFlavor");
3496 for (Object file : (List) t
3497 .getTransferData(DataFlavor.javaFileListFlavor))
3500 protocols.add(DataSourceType.FILE);
3505 // Unix like behaviour
3506 boolean added = false;
3508 if (t.isDataFlavorSupported(uriListFlavor))
3510 Cache.log.debug("Drop handled as uriListFlavor");
3511 // This is used by Unix drag system
3512 data = (String) t.getTransferData(uriListFlavor);
3516 // fallback to text: workaround - on OSX where there's a JVM bug
3517 Cache.log.debug("standard URIListFlavor failed. Trying text");
3518 // try text fallback
3519 DataFlavor textDf = new DataFlavor(
3520 "text/plain;class=java.lang.String");
3521 if (t.isDataFlavorSupported(textDf))
3523 data = (String) t.getTransferData(textDf);
3526 Cache.log.debug("Plain text drop content returned "
3527 + (data == null ? "Null - failed" : data));
3532 while (protocols.size() < files.size())
3534 Cache.log.debug("Adding missing FILE protocol for "
3535 + files.get(protocols.size()));
3536 protocols.add(DataSourceType.FILE);
3538 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3539 data, "\r\n"); st.hasMoreTokens();)
3542 String s = st.nextToken();
3543 if (s.startsWith("#"))
3545 // the line is a comment (as per the RFC 2483)
3548 java.net.URI uri = new java.net.URI(s);
3549 if (uri.getScheme().toLowerCase().startsWith("http"))
3551 protocols.add(DataSourceType.URL);
3552 files.add(uri.toString());
3556 // otherwise preserve old behaviour: catch all for file objects
3557 java.io.File file = new java.io.File(uri);
3558 protocols.add(DataSourceType.FILE);
3559 files.add(file.toString());
3564 if (Cache.log.isDebugEnabled())
3566 if (data == null || !added)
3569 if (t.getTransferDataFlavors() != null
3570 && t.getTransferDataFlavors().length > 0)
3573 "Couldn't resolve drop data. Here are the supported flavors:");
3574 for (DataFlavor fl : t.getTransferDataFlavors())
3577 "Supported transfer dataflavor: " + fl.toString());
3578 Object df = t.getTransferData(fl);
3581 Cache.log.debug("Retrieves: " + df);
3585 Cache.log.debug("Retrieved nothing");
3591 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3597 if (Platform.isWindows())
3600 Cache.log.debug("Scanning dropped content for Windows Link Files");
3602 // resolve any .lnk files in the file drop
3603 for (int f = 0; f < files.size(); f++)
3605 String source = files.get(f).toString().toLowerCase();
3606 if (protocols.get(f).equals(DataSourceType.FILE)
3607 && (source.endsWith(".lnk") || source.endsWith(".url")
3608 || source.endsWith(".site")))
3612 Object obj = files.get(f);
3613 File lf = (obj instanceof File ? (File) obj
3614 : new File((String) obj));
3615 // process link file to get a URL
3616 Cache.log.debug("Found potential link file: " + lf);
3617 WindowsShortcut wscfile = new WindowsShortcut(lf);
3618 String fullname = wscfile.getRealFilename();
3619 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3620 files.set(f, fullname);
3621 Cache.log.debug("Parsed real filename " + fullname
3622 + " to extract protocol: " + protocols.get(f));
3623 } catch (Exception ex)
3626 "Couldn't parse " + files.get(f) + " as a link file.",
3635 * Sets the Preferences property for experimental features to True or False
3636 * depending on the state of the controlling menu item
3639 protected void showExperimental_actionPerformed(boolean selected)
3641 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3645 * Answers a (possibly empty) list of any structure viewer frames (currently for
3646 * either Jmol or Chimera) which are currently open. This may optionally be
3647 * restricted to viewers of a specified class, or viewers linked to a specified
3651 * if not null, only return viewers linked to this panel
3652 * @param structureViewerClass
3653 * if not null, only return viewers of this class
3656 public List<StructureViewerBase> getStructureViewers(
3657 AlignmentPanel apanel,
3658 Class<? extends StructureViewerBase> structureViewerClass)
3660 List<StructureViewerBase> result = new ArrayList<>();
3661 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3663 for (JInternalFrame frame : frames)
3665 if (frame instanceof StructureViewerBase)
3667 if (structureViewerClass == null
3668 || structureViewerClass.isInstance(frame))
3671 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3673 result.add((StructureViewerBase) frame);