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.BackupFiles;
31 import jalview.io.DataSourceType;
32 import jalview.io.FileFormat;
33 import jalview.io.FileFormatException;
34 import jalview.io.FileFormatI;
35 import jalview.io.FileFormats;
36 import jalview.io.FileLoader;
37 import jalview.io.FormatAdapter;
38 import jalview.io.IdentifyFile;
39 import jalview.io.JalviewFileChooser;
40 import jalview.io.JalviewFileView;
41 import jalview.jbgui.GSplitFrame;
42 import jalview.jbgui.GStructureViewer;
43 import jalview.project.Jalview2XML;
44 import jalview.structure.StructureSelectionManager;
45 import jalview.urls.IdOrgSettings;
46 import jalview.util.BrowserLauncher;
47 import jalview.util.ImageMaker.TYPE;
48 import jalview.util.MessageManager;
49 import jalview.util.Platform;
50 import jalview.util.UrlConstants;
51 import jalview.viewmodel.AlignmentViewport;
52 import jalview.ws.params.ParamManager;
53 import jalview.ws.utils.UrlDownloadClient;
55 import java.awt.BorderLayout;
56 import java.awt.Color;
57 import java.awt.Dimension;
58 import java.awt.FontMetrics;
59 import java.awt.Graphics;
60 import java.awt.GridLayout;
61 import java.awt.Point;
62 import java.awt.Rectangle;
63 import java.awt.Toolkit;
64 import java.awt.Window;
65 import java.awt.datatransfer.Clipboard;
66 import java.awt.datatransfer.ClipboardOwner;
67 import java.awt.datatransfer.DataFlavor;
68 import java.awt.datatransfer.Transferable;
69 import java.awt.dnd.DnDConstants;
70 import java.awt.dnd.DropTargetDragEvent;
71 import java.awt.dnd.DropTargetDropEvent;
72 import java.awt.dnd.DropTargetEvent;
73 import java.awt.dnd.DropTargetListener;
74 import java.awt.event.ActionEvent;
75 import java.awt.event.ActionListener;
76 import java.awt.event.InputEvent;
77 import java.awt.event.KeyEvent;
78 import java.awt.event.MouseAdapter;
79 import java.awt.event.MouseEvent;
80 import java.awt.event.WindowAdapter;
81 import java.awt.event.WindowEvent;
82 import java.beans.PropertyChangeEvent;
83 import java.beans.PropertyChangeListener;
84 import java.io.BufferedInputStream;
86 import java.io.FileOutputStream;
87 import java.io.IOException;
89 import java.util.ArrayList;
90 import java.util.Hashtable;
91 import java.util.List;
92 import java.util.ListIterator;
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.
351 * A note to implementors. It is ESSENTIAL that any activities that might
352 * block are spawned off as threads rather than waited for during this
356 if (!Platform.isJS())
358 doVamsasClientCheck();
361 doConfigureStructurePrefs();
362 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
363 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
364 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
366 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
368 desktop = new MyDesktopPane(selmemusage);
370 showMemusage.setSelected(selmemusage);
371 desktop.setBackground(Color.white);
372 getContentPane().setLayout(new BorderLayout());
373 // alternate config - have scrollbars - see notes in JAL-153
374 // JScrollPane sp = new JScrollPane();
375 // sp.getViewport().setView(desktop);
376 // getContentPane().add(sp, BorderLayout.CENTER);
378 // BH 2018 - just an experiment to try unclipped JInternalFrames.
381 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
384 getContentPane().add(desktop, BorderLayout.CENTER);
385 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
387 // This line prevents Windows Look&Feel resizing all new windows to maximum
388 // if previous window was maximised
389 desktop.setDesktopManager(new MyDesktopManager(
390 (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
391 : Platform.isAMacAndNotJS()
392 ? new AquaInternalFrameManager(
393 desktop.getDesktopManager())
394 : desktop.getDesktopManager())));
396 Rectangle dims = getLastKnownDimensions("");
403 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
404 int xPos = Math.max(5, (screenSize.width - 900) / 2);
405 int yPos = Math.max(5, (screenSize.height - 650) / 2);
406 setBounds(xPos, yPos, 900, 650);
409 if (!Platform.isJS())
417 jconsole = new Console(this, showjconsole);
418 // add essential build information
419 jconsole.setHeader("Jalview Version: "
420 + jalview.bin.Cache.getProperty("VERSION") + "\n"
421 + "Jalview Installation: "
422 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
423 + "\n" + "Build Date: "
424 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
425 + "Java version: " + System.getProperty("java.version") + "\n"
426 + System.getProperty("os.arch") + " "
427 + System.getProperty("os.name") + " "
428 + System.getProperty("os.version"));
430 showConsole(showjconsole);
432 showNews.setVisible(false);
434 experimentalFeatures.setSelected(showExperimental());
436 getIdentifiersOrgData();
440 // Spawn a thread that shows the splashscreen
442 SwingUtilities.invokeLater(new Runnable()
451 // Thread off a new instance of the file chooser - this reduces the time
453 // takes to open it later on.
454 new Thread(new Runnable()
459 Cache.log.debug("Filechooser init thread started.");
460 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
461 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
463 Cache.log.debug("Filechooser init thread finished.");
466 // Add the service change listener
467 changeSupport.addJalviewPropertyChangeListener("services",
468 new PropertyChangeListener()
472 public void propertyChange(PropertyChangeEvent evt)
474 Cache.log.debug("Firing service changed event for "
475 + evt.getNewValue());
476 JalviewServicesChanged(evt);
483 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
485 this.addWindowListener(new WindowAdapter()
488 public void windowClosing(WindowEvent evt)
495 this.addMouseListener(ma = new MouseAdapter()
498 public void mousePressed(MouseEvent evt)
500 if (evt.isPopupTrigger()) // Mac
502 showPasteMenu(evt.getX(), evt.getY());
507 public void mouseReleased(MouseEvent evt)
509 if (evt.isPopupTrigger()) // Windows
511 showPasteMenu(evt.getX(), evt.getY());
515 desktop.addMouseListener(ma);
520 * Answers true if user preferences to enable experimental features is True
525 public boolean showExperimental()
527 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
528 Boolean.FALSE.toString());
529 return Boolean.valueOf(experimental).booleanValue();
532 public void doConfigureStructurePrefs()
534 // configure services
535 StructureSelectionManager ssm = StructureSelectionManager
536 .getStructureSelectionManager(this);
537 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
539 ssm.setAddTempFacAnnot(jalview.bin.Cache
540 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
541 ssm.setProcessSecondaryStructure(jalview.bin.Cache
542 .getDefault(Preferences.STRUCT_FROM_PDB, true));
543 ssm.setSecStructServices(
544 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
548 ssm.setAddTempFacAnnot(false);
549 ssm.setProcessSecondaryStructure(false);
550 ssm.setSecStructServices(false);
554 public void checkForNews()
556 final Desktop me = this;
557 // Thread off the news reader, in case there are connection problems.
558 new Thread(new Runnable()
563 Cache.log.debug("Starting news thread.");
564 jvnews = new BlogReader(me);
565 showNews.setVisible(true);
566 Cache.log.debug("Completed news thread.");
571 public void getIdentifiersOrgData()
573 // Thread off the identifiers fetcher
574 new Thread(new Runnable()
579 Cache.log.debug("Downloading data from identifiers.org");
580 UrlDownloadClient client = new UrlDownloadClient();
583 client.download(IdOrgSettings.getUrl(),
584 IdOrgSettings.getDownloadLocation());
585 } catch (IOException e)
587 Cache.log.debug("Exception downloading identifiers.org data"
596 protected void showNews_actionPerformed(ActionEvent e)
598 showNews(showNews.isSelected());
601 void showNews(boolean visible)
603 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
604 showNews.setSelected(visible);
605 if (visible && !jvnews.isVisible())
607 new Thread(new Runnable()
612 long now = System.currentTimeMillis();
613 Desktop.instance.setProgressBar(
614 MessageManager.getString("status.refreshing_news"), now);
615 jvnews.refreshNews();
616 Desktop.instance.setProgressBar(null, now);
624 * recover the last known dimensions for a jalview window
627 * - empty string is desktop, all other windows have unique prefix
628 * @return null or last known dimensions scaled to current geometry (if last
629 * window geom was known)
631 Rectangle getLastKnownDimensions(String windowName)
633 // TODO: lock aspect ratio for scaling desktop Bug #0058199
634 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
635 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
636 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
637 String width = jalview.bin.Cache
638 .getProperty(windowName + "SCREEN_WIDTH");
639 String height = jalview.bin.Cache
640 .getProperty(windowName + "SCREEN_HEIGHT");
641 if ((x != null) && (y != null) && (width != null) && (height != null))
643 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
644 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
645 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
647 // attempt #1 - try to cope with change in screen geometry - this
648 // version doesn't preserve original jv aspect ratio.
649 // take ratio of current screen size vs original screen size.
650 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
651 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
652 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
653 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
654 // rescale the bounds depending upon the current screen geometry.
655 ix = (int) (ix * sw);
656 iw = (int) (iw * sw);
657 iy = (int) (iy * sh);
658 ih = (int) (ih * sh);
659 while (ix >= screenSize.width)
661 jalview.bin.Cache.log.debug(
662 "Window geometry location recall error: shifting horizontal to within screenbounds.");
663 ix -= screenSize.width;
665 while (iy >= screenSize.height)
667 jalview.bin.Cache.log.debug(
668 "Window geometry location recall error: shifting vertical to within screenbounds.");
669 iy -= screenSize.height;
671 jalview.bin.Cache.log.debug(
672 "Got last known dimensions for " + windowName + ": x:" + ix
673 + " y:" + iy + " width:" + iw + " height:" + ih);
675 // return dimensions for new instance
676 return new Rectangle(ix, iy, iw, ih);
681 private void doVamsasClientCheck()
683 if (Cache.vamsasJarsPresent())
685 setupVamsasDisconnectedGui();
686 VamsasMenu.setVisible(true);
687 final Desktop us = this;
688 VamsasMenu.addMenuListener(new MenuListener()
690 // this listener remembers when the menu was first selected, and
691 // doesn't rebuild the session list until it has been cleared and
693 boolean refresh = true;
696 public void menuCanceled(MenuEvent e)
702 public void menuDeselected(MenuEvent e)
708 public void menuSelected(MenuEvent e)
712 us.buildVamsasStMenu();
717 vamsasStart.setVisible(true);
721 void showPasteMenu(int x, int y)
723 JPopupMenu popup = new JPopupMenu();
724 JMenuItem item = new JMenuItem(
725 MessageManager.getString("label.paste_new_window"));
726 item.addActionListener(new ActionListener()
729 public void actionPerformed(ActionEvent evt)
736 popup.show(this, x, y);
743 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
744 Transferable contents = c.getContents(this);
746 if (contents != null)
748 String file = (String) contents
749 .getTransferData(DataFlavor.stringFlavor);
751 FileFormatI format = new IdentifyFile().identify(file,
752 DataSourceType.PASTE);
754 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
757 } catch (Exception ex)
760 "Unable to paste alignment from system clipboard:\n" + ex);
765 * Adds and opens the given frame to the desktop
776 public static synchronized void addInternalFrame(
777 final JInternalFrame frame, String title, int w, int h)
779 addInternalFrame(frame, title, true, w, h, true, false);
783 * Add an internal frame to the Jalview desktop
790 * When true, display frame immediately, otherwise, caller must call
791 * setVisible themselves.
797 public static synchronized void addInternalFrame(
798 final JInternalFrame frame, String title, boolean makeVisible,
801 addInternalFrame(frame, title, makeVisible, w, h, true, false);
805 * Add an internal frame to the Jalview desktop and make it visible
818 public static synchronized void addInternalFrame(
819 final JInternalFrame frame, String title, int w, int h,
822 addInternalFrame(frame, title, true, w, h, resizable, false);
826 * Add an internal frame to the Jalview desktop
833 * When true, display frame immediately, otherwise, caller must call
834 * setVisible themselves.
841 * @param ignoreMinSize
842 * Do not set the default minimum size for frame
844 public static synchronized void addInternalFrame(
845 final JInternalFrame frame, String title, boolean makeVisible,
846 int w, int h, boolean resizable, boolean ignoreMinSize)
849 // TODO: allow callers to determine X and Y position of frame (eg. via
851 // TODO: consider fixing method to update entries in the window submenu with
852 // the current window title
854 frame.setTitle(title);
855 if (frame.getWidth() < 1 || frame.getHeight() < 1)
859 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
860 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
861 // IF JALVIEW IS RUNNING HEADLESS
862 // ///////////////////////////////////////////////
863 if (instance == null || (System.getProperty("java.awt.headless") != null
864 && System.getProperty("java.awt.headless").equals("true")))
873 frame.setMinimumSize(
874 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
876 // Set default dimension for Alignment Frame window.
877 // The Alignment Frame window could be added from a number of places,
879 // I did this here in order not to miss out on any Alignment frame.
880 if (frame instanceof AlignFrame)
882 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
883 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
887 frame.setVisible(makeVisible);
888 frame.setClosable(true);
889 frame.setResizable(resizable);
890 frame.setMaximizable(resizable);
891 frame.setIconifiable(resizable);
892 frame.setOpaque(Platform.isJS());
894 if (frame.getX() < 1 && frame.getY() < 1)
896 frame.setLocation(xOffset * openFrameCount,
897 yOffset * ((openFrameCount - 1) % 10) + yOffset);
901 * add an entry for the new frame in the Window menu
902 * (and remove it when the frame is closed)
904 final JMenuItem menuItem = new JMenuItem(title);
905 frame.addInternalFrameListener(new InternalFrameAdapter()
908 public void internalFrameActivated(InternalFrameEvent evt)
910 JInternalFrame itf = desktop.getSelectedFrame();
913 if (itf instanceof AlignFrame)
915 Jalview.setCurrentAlignFrame((AlignFrame) itf);
922 public void internalFrameClosed(InternalFrameEvent evt)
924 PaintRefresher.RemoveComponent(frame);
927 * defensive check to prevent frames being
928 * added half off the window
930 if (openFrameCount > 0)
936 * ensure no reference to alignFrame retained by menu item listener
938 if (menuItem.getActionListeners().length > 0)
940 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
942 windowMenu.remove(menuItem);
946 menuItem.addActionListener(new ActionListener()
949 public void actionPerformed(ActionEvent e)
953 frame.setSelected(true);
954 frame.setIcon(false);
955 } catch (java.beans.PropertyVetoException ex)
957 // System.err.println(ex.toString());
962 setKeyBindings(frame);
966 windowMenu.add(menuItem);
971 frame.setSelected(true);
972 frame.requestFocus();
973 } catch (java.beans.PropertyVetoException ve)
975 } catch (java.lang.ClassCastException cex)
978 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
984 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
989 private static void setKeyBindings(JInternalFrame frame)
991 @SuppressWarnings("serial")
992 final Action closeAction = new AbstractAction()
995 public void actionPerformed(ActionEvent e)
1002 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1004 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1005 InputEvent.CTRL_DOWN_MASK);
1006 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1007 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1009 InputMap inputMap = frame
1010 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1011 String ctrlW = ctrlWKey.toString();
1012 inputMap.put(ctrlWKey, ctrlW);
1013 inputMap.put(cmdWKey, ctrlW);
1015 ActionMap actionMap = frame.getActionMap();
1016 actionMap.put(ctrlW, closeAction);
1020 public void lostOwnership(Clipboard clipboard, Transferable contents)
1024 Desktop.jalviewClipboard = null;
1027 internalCopy = false;
1031 public void dragEnter(DropTargetDragEvent evt)
1036 public void dragExit(DropTargetEvent evt)
1041 public void dragOver(DropTargetDragEvent evt)
1046 public void dropActionChanged(DropTargetDragEvent evt)
1057 public void drop(DropTargetDropEvent evt)
1059 boolean success = true;
1060 // JAL-1552 - acceptDrop required before getTransferable call for
1061 // Java's Transferable for native dnd
1062 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1063 Transferable t = evt.getTransferable();
1064 List<Object> files = new ArrayList<>();
1065 List<DataSourceType> protocols = new ArrayList<>();
1069 Desktop.transferFromDropTarget(files, protocols, evt, t);
1070 } catch (Exception e)
1072 e.printStackTrace();
1080 for (int i = 0; i < files.size(); i++)
1082 // BH 2018 File or String
1083 Object file = files.get(i);
1084 String fileName = file.toString();
1085 DataSourceType protocol = (protocols == null)
1086 ? DataSourceType.FILE
1088 FileFormatI format = null;
1090 if (fileName.endsWith(".jar"))
1092 format = FileFormat.Jalview;
1097 format = new IdentifyFile().identify(file, protocol);
1099 if (file instanceof File)
1101 Platform.cacheFileData((File) file);
1103 new FileLoader().LoadFile(null, file, protocol, format);
1106 } catch (Exception ex)
1111 evt.dropComplete(success); // need this to ensure input focus is properly
1112 // transfered to any new windows created
1122 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1124 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1125 JalviewFileChooser chooser = JalviewFileChooser
1126 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1128 chooser.setFileView(new JalviewFileView());
1129 chooser.setDialogTitle(
1130 MessageManager.getString("label.open_local_file"));
1131 chooser.setToolTipText(MessageManager.getString("action.open"));
1133 chooser.setResponseHandler(0, new Runnable()
1138 File selectedFile = chooser.getSelectedFile();
1139 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1141 FileFormatI format = chooser.getSelectedFormat();
1144 * Call IdentifyFile to verify the file contains what its extension implies.
1145 * Skip this step for dynamically added file formats, because
1146 * IdentifyFile does not know how to recognise them.
1148 if (FileFormats.getInstance().isIdentifiable(format))
1152 format = new IdentifyFile().identify(selectedFile,
1153 DataSourceType.FILE);
1154 } catch (FileFormatException e)
1156 // format = null; //??
1160 new FileLoader().LoadFile(viewport, selectedFile,
1161 DataSourceType.FILE, format);
1164 chooser.showOpenDialog(this);
1168 * Shows a dialog for input of a URL at which to retrieve alignment data
1173 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1175 // This construct allows us to have a wider textfield
1177 JLabel label = new JLabel(
1178 MessageManager.getString("label.input_file_url"));
1180 JPanel panel = new JPanel(new GridLayout(2, 1));
1184 * the URL to fetch is
1185 * Java: an editable combobox with history
1186 * JS: (pending JAL-3038) a plain text field
1189 String urlBase = "http://www.";
1190 if (Platform.isJS())
1192 history = new JTextField(urlBase, 35);
1201 JComboBox<String> asCombo = new JComboBox<>();
1202 asCombo.setPreferredSize(new Dimension(400, 20));
1203 asCombo.setEditable(true);
1204 asCombo.addItem(urlBase);
1205 String historyItems = Cache.getProperty("RECENT_URL");
1206 if (historyItems != null)
1208 for (String token : historyItems.split("\\t"))
1210 asCombo.addItem(token);
1217 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1218 MessageManager.getString("action.cancel") };
1219 Runnable action = new Runnable()
1224 @SuppressWarnings("unchecked")
1225 String url = (history instanceof JTextField
1226 ? ((JTextField) history).getText()
1227 : ((JComboBox<String>) history).getSelectedItem()
1230 if (url.toLowerCase().endsWith(".jar"))
1232 if (viewport != null)
1234 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1235 FileFormat.Jalview);
1239 new FileLoader().LoadFile(url, DataSourceType.URL,
1240 FileFormat.Jalview);
1245 FileFormatI format = null;
1248 format = new IdentifyFile().identify(url, DataSourceType.URL);
1249 } catch (FileFormatException e)
1251 // TODO revise error handling, distinguish between
1252 // URL not found and response not valid
1257 String msg = MessageManager
1258 .formatMessage("label.couldnt_locate", url);
1259 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1260 MessageManager.getString("label.url_not_found"),
1261 JvOptionPane.WARNING_MESSAGE);
1266 if (viewport != null)
1268 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1273 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1278 String dialogOption = MessageManager
1279 .getString("label.input_alignment_from_url");
1280 JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
1281 .showInternalDialog(panel, dialogOption,
1282 JvOptionPane.YES_NO_CANCEL_OPTION,
1283 JvOptionPane.PLAIN_MESSAGE, null, options,
1284 MessageManager.getString("action.ok"));
1288 * Opens the CutAndPaste window for the user to paste an alignment in to
1291 * - if not null, the pasted alignment is added to the current
1292 * alignment; if null, to a new alignment window
1295 public void inputTextboxMenuItem_actionPerformed(
1296 AlignmentViewPanel viewPanel)
1298 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1299 cap.setForInput(viewPanel);
1300 Desktop.addInternalFrame(cap,
1301 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1311 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1312 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1314 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1315 screen.height + "");
1316 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1317 getWidth(), getHeight()));
1319 if (jconsole != null)
1321 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1322 jconsole.stopConsole();
1326 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1329 if (dialogExecutor != null)
1331 dialogExecutor.shutdownNow();
1333 closeAll_actionPerformed(null);
1335 if (groovyConsole != null)
1337 // suppress a possible repeat prompt to save script
1338 groovyConsole.setDirty(false);
1339 groovyConsole.exit();
1344 private void storeLastKnownDimensions(String string, Rectangle jc)
1346 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1347 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1348 + " height:" + jc.height);
1350 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1351 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1352 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1353 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1363 public void aboutMenuItem_actionPerformed(ActionEvent e)
1365 // StringBuffer message = getAboutMessage(false);
1366 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1368 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1369 new Thread(new Runnable()
1374 new SplashScreen(true);
1379 public StringBuffer getAboutMessage(boolean shortv)
1381 StringBuffer message = new StringBuffer();
1382 message.append("<html>");
1385 message.append("<h1><strong>Version: "
1386 + jalview.bin.Cache.getProperty("VERSION")
1387 + "</strong></h1>");
1388 message.append("<strong>Last Updated: <em>"
1389 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1390 + "</em></strong>");
1396 message.append("<strong>Version "
1397 + jalview.bin.Cache.getProperty("VERSION")
1398 + "; last updated: "
1399 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1402 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1403 .equals("Checking"))
1405 message.append("<br>...Checking latest version...</br>");
1407 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1408 .equals(jalview.bin.Cache.getProperty("VERSION")))
1410 boolean red = false;
1411 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1412 .indexOf("automated build") == -1)
1415 // Displayed when code version and jnlp version do not match and code
1416 // version is not a development build
1417 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1420 message.append("<br>!! Version "
1421 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1423 + " is available for download from "
1424 + jalview.bin.Cache.getDefault("www.jalview.org",
1425 "http://www.jalview.org")
1429 message.append("</div>");
1432 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1434 "The Jalview Authors (See AUTHORS file for current list)")
1435 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1436 + "<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"
1437 + "<br><br>If you use Jalview, please cite:"
1438 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1439 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1440 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1446 * Action on requesting Help documentation
1449 public void documentationMenuItem_actionPerformed()
1453 if (Platform.isJS())
1455 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1464 Help.showHelpWindow();
1466 } catch (Exception ex)
1468 System.err.println("Error opening help: " + ex.getMessage());
1473 public void closeAll_actionPerformed(ActionEvent e)
1475 // TODO show a progress bar while closing?
1476 JInternalFrame[] frames = desktop.getAllFrames();
1477 for (int i = 0; i < frames.length; i++)
1481 frames[i].setClosed(true);
1482 } catch (java.beans.PropertyVetoException ex)
1486 Jalview.setCurrentAlignFrame(null);
1487 System.out.println("ALL CLOSED");
1488 if (v_client != null)
1490 // TODO clear binding to vamsas document objects on close_all
1494 * reset state of singleton objects as appropriate (clear down session state
1495 * when all windows are closed)
1497 StructureSelectionManager ssm = StructureSelectionManager
1498 .getStructureSelectionManager(this);
1506 public void raiseRelated_actionPerformed(ActionEvent e)
1508 reorderAssociatedWindows(false, false);
1512 public void minimizeAssociated_actionPerformed(ActionEvent e)
1514 reorderAssociatedWindows(true, false);
1517 void closeAssociatedWindows()
1519 reorderAssociatedWindows(false, true);
1525 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1529 protected void garbageCollect_actionPerformed(ActionEvent e)
1531 // We simply collect the garbage
1532 jalview.bin.Cache.log.debug("Collecting garbage...");
1534 jalview.bin.Cache.log.debug("Finished garbage collection.");
1541 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1545 protected void showMemusage_actionPerformed(ActionEvent e)
1547 desktop.showMemoryUsage(showMemusage.isSelected());
1554 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1558 protected void showConsole_actionPerformed(ActionEvent e)
1560 showConsole(showConsole.isSelected());
1563 Console jconsole = null;
1566 * control whether the java console is visible or not
1570 void showConsole(boolean selected)
1572 // TODO: decide if we should update properties file
1573 if (jconsole != null) // BH 2018
1575 showConsole.setSelected(selected);
1576 Cache.setProperty("SHOW_JAVA_CONSOLE",
1577 Boolean.valueOf(selected).toString());
1578 jconsole.setVisible(selected);
1582 void reorderAssociatedWindows(boolean minimize, boolean close)
1584 JInternalFrame[] frames = desktop.getAllFrames();
1585 if (frames == null || frames.length < 1)
1590 AlignmentViewport source = null, target = null;
1591 if (frames[0] instanceof AlignFrame)
1593 source = ((AlignFrame) frames[0]).getCurrentView();
1595 else if (frames[0] instanceof TreePanel)
1597 source = ((TreePanel) frames[0]).getViewPort();
1599 else if (frames[0] instanceof PCAPanel)
1601 source = ((PCAPanel) frames[0]).av;
1603 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1605 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1610 for (int i = 0; i < frames.length; i++)
1613 if (frames[i] == null)
1617 if (frames[i] instanceof AlignFrame)
1619 target = ((AlignFrame) frames[i]).getCurrentView();
1621 else if (frames[i] instanceof TreePanel)
1623 target = ((TreePanel) frames[i]).getViewPort();
1625 else if (frames[i] instanceof PCAPanel)
1627 target = ((PCAPanel) frames[i]).av;
1629 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1631 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1634 if (source == target)
1640 frames[i].setClosed(true);
1644 frames[i].setIcon(minimize);
1647 frames[i].toFront();
1651 } catch (java.beans.PropertyVetoException ex)
1666 protected void preferences_actionPerformed(ActionEvent e)
1672 * Prompts the user to choose a file and then saves the Jalview state as a
1673 * Jalview project file
1676 public void saveState_actionPerformed()
1678 saveState_actionPerformed(false);
1681 public void saveState_actionPerformed(boolean saveAs)
1683 java.io.File projectFile = getProjectFile();
1684 // autoSave indicates we already have a file and don't need to ask
1685 boolean autoSave = projectFile != null && !saveAs
1686 && BackupFiles.getEnabled();
1688 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1689 // saveAs="+saveAs+", Backups
1690 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1692 boolean approveSave = false;
1695 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1698 chooser.setFileView(new JalviewFileView());
1699 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1701 int value = chooser.showSaveDialog(this);
1703 if (value == JalviewFileChooser.APPROVE_OPTION)
1705 projectFile = chooser.getSelectedFile();
1706 setProjectFile(projectFile);
1711 if (approveSave || autoSave)
1713 final Desktop me = this;
1714 final java.io.File chosenFile = projectFile;
1715 new Thread(new Runnable()
1720 // TODO: refactor to Jalview desktop session controller action.
1721 setProgressBar(MessageManager.formatMessage(
1722 "label.saving_jalview_project", new Object[]
1723 { chosenFile.getName() }), chosenFile.hashCode());
1724 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1725 chosenFile.getParent());
1726 // TODO catch and handle errors for savestate
1727 // TODO prevent user from messing with the Desktop whilst we're saving
1730 boolean doBackup = BackupFiles.getEnabled();
1731 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1733 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1737 backupfiles.setWriteSuccess(true);
1738 backupfiles.rollBackupsAndRenameTempFile();
1740 } catch (OutOfMemoryError oom)
1742 new OOMWarning("Whilst saving current state to "
1743 + chosenFile.getName(), oom);
1744 } catch (Exception ex)
1746 Cache.log.error("Problems whilst trying to save to "
1747 + chosenFile.getName(), ex);
1748 JvOptionPane.showMessageDialog(me,
1749 MessageManager.formatMessage(
1750 "label.error_whilst_saving_current_state_to",
1752 { chosenFile.getName() }),
1753 MessageManager.getString("label.couldnt_save_project"),
1754 JvOptionPane.WARNING_MESSAGE);
1756 setProgressBar(null, chosenFile.hashCode());
1763 public void saveAsState_actionPerformed(ActionEvent e)
1765 saveState_actionPerformed(true);
1768 private void setProjectFile(File choice)
1770 this.projectFile = choice;
1773 public File getProjectFile()
1775 return this.projectFile;
1779 * Shows a file chooser dialog and tries to read in the selected file as a
1783 public void loadState_actionPerformed()
1785 final String[] suffix = new String[] { "jvp", "jar" };
1786 final String[] desc = new String[] { "Jalview Project",
1787 "Jalview Project (old)" };
1788 JalviewFileChooser chooser = new JalviewFileChooser(
1789 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1790 "Jalview Project", true, true); // last two booleans: allFiles,
1792 chooser.setFileView(new JalviewFileView());
1793 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1794 chooser.setResponseHandler(0, new Runnable()
1799 File selectedFile = chooser.getSelectedFile();
1800 setProjectFile(selectedFile);
1801 String choice = selectedFile.getAbsolutePath();
1802 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1803 new Thread(new Runnable()
1810 new Jalview2XML().loadJalviewAlign(choice);
1811 } catch (OutOfMemoryError oom)
1813 new OOMWarning("Whilst loading project from " + choice, oom);
1814 } catch (Exception ex)
1817 "Problems whilst loading project from " + choice, ex);
1818 JvOptionPane.showMessageDialog(Desktop.desktop,
1819 MessageManager.formatMessage(
1820 "label.error_whilst_loading_project_from",
1823 MessageManager.getString("label.couldnt_load_project"),
1824 JvOptionPane.WARNING_MESSAGE);
1831 chooser.showOpenDialog(this);
1835 public void inputSequence_actionPerformed(ActionEvent e)
1837 new SequenceFetcher(this);
1840 JPanel progressPanel;
1842 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1844 public void startLoading(final Object fileName)
1846 if (fileLoadingCount == 0)
1848 fileLoadingPanels.add(addProgressPanel(MessageManager
1849 .formatMessage("label.loading_file", new Object[]
1855 private JPanel addProgressPanel(String string)
1857 if (progressPanel == null)
1859 progressPanel = new JPanel(new GridLayout(1, 1));
1860 totalProgressCount = 0;
1861 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1863 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1864 JProgressBar progressBar = new JProgressBar();
1865 progressBar.setIndeterminate(true);
1867 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1869 thisprogress.add(progressBar, BorderLayout.CENTER);
1870 progressPanel.add(thisprogress);
1871 ((GridLayout) progressPanel.getLayout()).setRows(
1872 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1873 ++totalProgressCount;
1874 instance.validate();
1875 return thisprogress;
1878 int totalProgressCount = 0;
1880 private void removeProgressPanel(JPanel progbar)
1882 if (progressPanel != null)
1884 synchronized (progressPanel)
1886 progressPanel.remove(progbar);
1887 GridLayout gl = (GridLayout) progressPanel.getLayout();
1888 gl.setRows(gl.getRows() - 1);
1889 if (--totalProgressCount < 1)
1891 this.getContentPane().remove(progressPanel);
1892 progressPanel = null;
1899 public void stopLoading()
1902 if (fileLoadingCount < 1)
1904 while (fileLoadingPanels.size() > 0)
1906 removeProgressPanel(fileLoadingPanels.remove(0));
1908 fileLoadingPanels.clear();
1909 fileLoadingCount = 0;
1914 public static int getViewCount(String alignmentId)
1916 AlignmentViewport[] aps = getViewports(alignmentId);
1917 return (aps == null) ? 0 : aps.length;
1922 * @param alignmentId
1923 * - if null, all sets are returned
1924 * @return all AlignmentPanels concerning the alignmentId sequence set
1926 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1928 if (Desktop.desktop == null)
1930 // no frames created and in headless mode
1931 // TODO: verify that frames are recoverable when in headless mode
1934 List<AlignmentPanel> aps = new ArrayList<>();
1935 AlignFrame[] frames = getAlignFrames();
1940 for (AlignFrame af : frames)
1942 for (AlignmentPanel ap : af.alignPanels)
1944 if (alignmentId == null
1945 || alignmentId.equals(ap.av.getSequenceSetId()))
1951 if (aps.size() == 0)
1955 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1960 * get all the viewports on an alignment.
1962 * @param sequenceSetId
1963 * unique alignment id (may be null - all viewports returned in that
1965 * @return all viewports on the alignment bound to sequenceSetId
1967 public static AlignmentViewport[] getViewports(String sequenceSetId)
1969 List<AlignmentViewport> viewp = new ArrayList<>();
1970 if (desktop != null)
1972 AlignFrame[] frames = Desktop.getAlignFrames();
1974 for (AlignFrame afr : frames)
1976 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1977 .equals(sequenceSetId))
1979 if (afr.alignPanels != null)
1981 for (AlignmentPanel ap : afr.alignPanels)
1983 if (sequenceSetId == null
1984 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1992 viewp.add(afr.getViewport());
1996 if (viewp.size() > 0)
1998 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2005 * Explode the views in the given frame into separate AlignFrame
2009 public static void explodeViews(AlignFrame af)
2011 int size = af.alignPanels.size();
2017 for (int i = 0; i < size; i++)
2019 AlignmentPanel ap = af.alignPanels.get(i);
2020 AlignFrame newaf = new AlignFrame(ap);
2023 * Restore the view's last exploded frame geometry if known. Multiple
2024 * views from one exploded frame share and restore the same (frame)
2025 * position and size.
2027 Rectangle geometry = ap.av.getExplodedGeometry();
2028 if (geometry != null)
2030 newaf.setBounds(geometry);
2033 ap.av.setGatherViewsHere(false);
2035 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2036 AlignFrame.DEFAULT_HEIGHT);
2039 af.alignPanels.clear();
2040 af.closeMenuItem_actionPerformed(true);
2045 * Gather expanded views (separate AlignFrame's) with the same sequence set
2046 * identifier back in to this frame as additional views, and close the expanded
2047 * views. Note the expanded frames may themselves have multiple views. We take
2052 public void gatherViews(AlignFrame source)
2054 source.viewport.setGatherViewsHere(true);
2055 source.viewport.setExplodedGeometry(source.getBounds());
2056 JInternalFrame[] frames = desktop.getAllFrames();
2057 String viewId = source.viewport.getSequenceSetId();
2059 for (int t = 0; t < frames.length; t++)
2061 if (frames[t] instanceof AlignFrame && frames[t] != source)
2063 AlignFrame af = (AlignFrame) frames[t];
2064 boolean gatherThis = false;
2065 for (int a = 0; a < af.alignPanels.size(); a++)
2067 AlignmentPanel ap = af.alignPanels.get(a);
2068 if (viewId.equals(ap.av.getSequenceSetId()))
2071 ap.av.setGatherViewsHere(false);
2072 ap.av.setExplodedGeometry(af.getBounds());
2073 source.addAlignmentPanel(ap, false);
2079 af.alignPanels.clear();
2080 af.closeMenuItem_actionPerformed(true);
2087 jalview.gui.VamsasApplication v_client = null;
2090 public void vamsasImport_actionPerformed(ActionEvent e)
2092 // TODO: JAL-3048 not needed for Jalview-JS
2094 if (v_client == null)
2096 // Load and try to start a session.
2097 JalviewFileChooser chooser = new JalviewFileChooser(
2098 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2100 chooser.setFileView(new JalviewFileView());
2101 chooser.setDialogTitle(
2102 MessageManager.getString("label.open_saved_vamsas_session"));
2103 chooser.setToolTipText(MessageManager.getString(
2104 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2106 int value = chooser.showOpenDialog(this);
2108 if (value == JalviewFileChooser.APPROVE_OPTION)
2110 String fle = chooser.getSelectedFile().toString();
2111 if (!vamsasImport(chooser.getSelectedFile()))
2113 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2114 MessageManager.formatMessage(
2115 "label.couldnt_import_as_vamsas_session",
2119 .getString("label.vamsas_document_import_failed"),
2120 JvOptionPane.ERROR_MESSAGE);
2126 jalview.bin.Cache.log.error(
2127 "Implementation error - load session from a running session is not supported.");
2132 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2135 * @return true if import was a success and a session was started.
2137 public boolean vamsasImport(URL url)
2139 // TODO: create progress bar
2140 if (v_client != null)
2143 jalview.bin.Cache.log.error(
2144 "Implementation error - load session from a running session is not supported.");
2150 // copy the URL content to a temporary local file
2151 // TODO: be a bit cleverer here with nio (?!)
2152 File file = File.createTempFile("vdocfromurl", ".vdj");
2153 FileOutputStream fos = new FileOutputStream(file);
2154 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2155 byte[] buffer = new byte[2048];
2157 while ((ln = bis.read(buffer)) > -1)
2159 fos.write(buffer, 0, ln);
2163 v_client = new jalview.gui.VamsasApplication(this, file,
2164 url.toExternalForm());
2165 } catch (Exception ex)
2167 jalview.bin.Cache.log.error(
2168 "Failed to create new vamsas session from contents of URL "
2173 setupVamsasConnectedGui();
2174 v_client.initial_update(); // TODO: thread ?
2175 return v_client.inSession();
2179 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2182 * @return true if import was a success and a session was started.
2184 public boolean vamsasImport(File file)
2186 if (v_client != null)
2189 jalview.bin.Cache.log.error(
2190 "Implementation error - load session from a running session is not supported.");
2194 setProgressBar(MessageManager.formatMessage(
2195 "status.importing_vamsas_session_from", new Object[]
2196 { file.getName() }), file.hashCode());
2199 v_client = new jalview.gui.VamsasApplication(this, file, null);
2200 } catch (Exception ex)
2202 setProgressBar(MessageManager.formatMessage(
2203 "status.importing_vamsas_session_from", new Object[]
2204 { file.getName() }), file.hashCode());
2205 jalview.bin.Cache.log.error(
2206 "New vamsas session from existing session file failed:", ex);
2209 setupVamsasConnectedGui();
2210 v_client.initial_update(); // TODO: thread ?
2211 setProgressBar(MessageManager.formatMessage(
2212 "status.importing_vamsas_session_from", new Object[]
2213 { file.getName() }), file.hashCode());
2214 return v_client.inSession();
2217 public boolean joinVamsasSession(String mysesid)
2219 if (v_client != null)
2221 throw new Error(MessageManager
2222 .getString("error.try_join_vamsas_session_another"));
2224 if (mysesid == null)
2227 MessageManager.getString("error.invalid_vamsas_session_id"));
2229 v_client = new VamsasApplication(this, mysesid);
2230 setupVamsasConnectedGui();
2231 v_client.initial_update();
2232 return (v_client.inSession());
2236 public void vamsasStart_actionPerformed(ActionEvent e)
2238 if (v_client == null)
2241 // we just start a default session for moment.
2243 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2244 * getProperty("LAST_DIRECTORY"));
2246 * chooser.setFileView(new JalviewFileView());
2247 * chooser.setDialogTitle("Load Vamsas file");
2248 * chooser.setToolTipText("Import");
2250 * int value = chooser.showOpenDialog(this);
2252 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2253 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2255 v_client = new VamsasApplication(this);
2256 setupVamsasConnectedGui();
2257 v_client.initial_update(); // TODO: thread ?
2261 // store current data in session.
2262 v_client.push_update(); // TODO: thread
2266 protected void setupVamsasConnectedGui()
2268 vamsasStart.setText(MessageManager.getString("label.session_update"));
2269 vamsasSave.setVisible(true);
2270 vamsasStop.setVisible(true);
2271 vamsasImport.setVisible(false); // Document import to existing session is
2272 // not possible for vamsas-client-1.0.
2275 protected void setupVamsasDisconnectedGui()
2277 vamsasSave.setVisible(false);
2278 vamsasStop.setVisible(false);
2279 vamsasImport.setVisible(true);
2281 .setText(MessageManager.getString("label.new_vamsas_session"));
2285 public void vamsasStop_actionPerformed(ActionEvent e)
2287 if (v_client != null)
2289 v_client.end_session();
2291 setupVamsasDisconnectedGui();
2295 protected void buildVamsasStMenu()
2297 if (v_client == null)
2299 String[] sess = null;
2302 sess = VamsasApplication.getSessionList();
2303 } catch (Exception e)
2305 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2311 jalview.bin.Cache.log.debug(
2312 "Got current sessions list: " + sess.length + " entries.");
2313 VamsasStMenu.removeAll();
2314 for (int i = 0; i < sess.length; i++)
2316 JMenuItem sessit = new JMenuItem();
2317 sessit.setText(sess[i]);
2318 sessit.setToolTipText(MessageManager
2319 .formatMessage("label.connect_to_session", new Object[]
2321 final Desktop dsktp = this;
2322 final String mysesid = sess[i];
2323 sessit.addActionListener(new ActionListener()
2327 public void actionPerformed(ActionEvent e)
2329 if (dsktp.v_client == null)
2331 Thread rthr = new Thread(new Runnable()
2337 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2338 dsktp.setupVamsasConnectedGui();
2339 dsktp.v_client.initial_update();
2347 VamsasStMenu.add(sessit);
2349 // don't show an empty menu.
2350 VamsasStMenu.setVisible(sess.length > 0);
2355 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2356 VamsasStMenu.removeAll();
2357 VamsasStMenu.setVisible(false);
2362 // Not interested in the content. Just hide ourselves.
2363 VamsasStMenu.setVisible(false);
2368 public void vamsasSave_actionPerformed(ActionEvent e)
2370 // TODO: JAL-3048 not needed for Jalview-JS
2372 if (v_client != null)
2374 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2375 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2378 chooser.setFileView(new JalviewFileView());
2379 chooser.setDialogTitle(MessageManager
2380 .getString("label.save_vamsas_document_archive"));
2382 int value = chooser.showSaveDialog(this);
2384 if (value == JalviewFileChooser.APPROVE_OPTION)
2386 java.io.File choice = chooser.getSelectedFile();
2387 JPanel progpanel = addProgressPanel(MessageManager
2388 .formatMessage("label.saving_vamsas_doc", new Object[]
2389 { choice.getName() }));
2390 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2391 String warnmsg = null;
2392 String warnttl = null;
2395 v_client.vclient.storeDocument(choice);
2398 warnttl = "Serious Problem saving Vamsas Document";
2399 warnmsg = ex.toString();
2400 jalview.bin.Cache.log
2401 .error("Error Whilst saving document to " + choice, ex);
2403 } catch (Exception ex)
2405 warnttl = "Problem saving Vamsas Document.";
2406 warnmsg = ex.toString();
2407 jalview.bin.Cache.log.warn(
2408 "Exception Whilst saving document to " + choice, ex);
2411 removeProgressPanel(progpanel);
2412 if (warnmsg != null)
2414 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2416 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2422 JPanel vamUpdate = null;
2425 * hide vamsas user gui bits when a vamsas document event is being handled.
2428 * true to hide gui, false to reveal gui
2430 public void setVamsasUpdate(boolean b)
2432 Cache.log.debug("Setting gui for Vamsas update "
2433 + (b ? "in progress" : "finished"));
2435 if (vamUpdate != null)
2437 this.removeProgressPanel(vamUpdate);
2441 vamUpdate = this.addProgressPanel(
2442 MessageManager.getString("label.updating_vamsas_session"));
2444 vamsasStart.setVisible(!b);
2445 vamsasStop.setVisible(!b);
2446 vamsasSave.setVisible(!b);
2449 public JInternalFrame[] getAllFrames()
2451 return desktop.getAllFrames();
2455 * Checks the given url to see if it gives a response indicating that the user
2456 * should be informed of a new questionnaire.
2460 public void checkForQuestionnaire(String url)
2462 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2463 // javax.swing.SwingUtilities.invokeLater(jvq);
2464 new Thread(jvq).start();
2467 public void checkURLLinks()
2469 // Thread off the URL link checker
2470 addDialogThread(new Runnable()
2475 if (Cache.getDefault("CHECKURLLINKS", true))
2477 // check what the actual links are - if it's just the default don't
2478 // bother with the warning
2479 List<String> links = Preferences.sequenceUrlLinks
2482 // only need to check links if there is one with a
2483 // SEQUENCE_ID which is not the default EMBL_EBI link
2484 ListIterator<String> li = links.listIterator();
2485 boolean check = false;
2486 List<JLabel> urls = new ArrayList<>();
2487 while (li.hasNext())
2489 String link = li.next();
2490 if (link.contains(SEQUENCE_ID)
2491 && !UrlConstants.isDefaultString(link))
2494 int barPos = link.indexOf("|");
2495 String urlMsg = barPos == -1 ? link
2496 : link.substring(0, barPos) + ": "
2497 + link.substring(barPos + 1);
2498 urls.add(new JLabel(urlMsg));
2506 // ask user to check in case URL links use old style tokens
2507 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2508 JPanel msgPanel = new JPanel();
2509 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2510 msgPanel.add(Box.createVerticalGlue());
2511 JLabel msg = new JLabel(MessageManager
2512 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2513 JLabel msg2 = new JLabel(MessageManager
2514 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2516 for (JLabel url : urls)
2522 final JCheckBox jcb = new JCheckBox(
2523 MessageManager.getString("label.do_not_display_again"));
2524 jcb.addActionListener(new ActionListener()
2527 public void actionPerformed(ActionEvent e)
2529 // update Cache settings for "don't show this again"
2530 boolean showWarningAgain = !jcb.isSelected();
2531 Cache.setProperty("CHECKURLLINKS",
2532 Boolean.valueOf(showWarningAgain).toString());
2537 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2539 .getString("label.SEQUENCE_ID_no_longer_used"),
2540 JvOptionPane.WARNING_MESSAGE);
2547 * Proxy class for JDesktopPane which optionally displays the current memory
2548 * usage and highlights the desktop area with a red bar if free memory runs low.
2552 public class MyDesktopPane extends JDesktopPane
2555 private static final float ONE_MB = 1048576f;
2557 boolean showMemoryUsage = false;
2561 java.text.NumberFormat df;
2563 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2566 public MyDesktopPane(boolean showMemoryUsage)
2568 showMemoryUsage(showMemoryUsage);
2571 public void showMemoryUsage(boolean showMemory)
2573 this.showMemoryUsage = showMemory;
2576 Thread worker = new Thread(this);
2582 public boolean isShowMemoryUsage()
2584 return showMemoryUsage;
2590 df = java.text.NumberFormat.getNumberInstance();
2591 df.setMaximumFractionDigits(2);
2592 runtime = Runtime.getRuntime();
2594 while (showMemoryUsage)
2598 maxMemory = runtime.maxMemory() / ONE_MB;
2599 allocatedMemory = runtime.totalMemory() / ONE_MB;
2600 freeMemory = runtime.freeMemory() / ONE_MB;
2601 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2603 percentUsage = (totalFreeMemory / maxMemory) * 100;
2605 // if (percentUsage < 20)
2607 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2609 // instance.set.setBorder(border1);
2612 // sleep after showing usage
2614 } catch (Exception ex)
2616 ex.printStackTrace();
2622 public void paintComponent(Graphics g)
2624 if (showMemoryUsage && g != null && df != null)
2626 if (percentUsage < 20)
2628 g.setColor(Color.red);
2630 FontMetrics fm = g.getFontMetrics();
2633 g.drawString(MessageManager.formatMessage("label.memory_stats",
2635 { df.format(totalFreeMemory), df.format(maxMemory),
2636 df.format(percentUsage) }),
2637 10, getHeight() - fm.getHeight());
2644 * Accessor method to quickly get all the AlignmentFrames loaded.
2646 * @return an array of AlignFrame, or null if none found
2648 public static AlignFrame[] getAlignFrames()
2650 if (Jalview.isHeadlessMode())
2652 // Desktop.desktop is null in headless mode
2653 return new AlignFrame[] { Jalview.currentAlignFrame };
2656 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2662 List<AlignFrame> avp = new ArrayList<>();
2664 for (int i = frames.length - 1; i > -1; i--)
2666 if (frames[i] instanceof AlignFrame)
2668 avp.add((AlignFrame) frames[i]);
2670 else if (frames[i] instanceof SplitFrame)
2673 * Also check for a split frame containing an AlignFrame
2675 GSplitFrame sf = (GSplitFrame) frames[i];
2676 if (sf.getTopFrame() instanceof AlignFrame)
2678 avp.add((AlignFrame) sf.getTopFrame());
2680 if (sf.getBottomFrame() instanceof AlignFrame)
2682 avp.add((AlignFrame) sf.getBottomFrame());
2686 if (avp.size() == 0)
2690 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2695 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2699 public GStructureViewer[] getJmols()
2701 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2707 List<GStructureViewer> avp = new ArrayList<>();
2709 for (int i = frames.length - 1; i > -1; i--)
2711 if (frames[i] instanceof AppJmol)
2713 GStructureViewer af = (GStructureViewer) frames[i];
2717 if (avp.size() == 0)
2721 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2726 * Add Groovy Support to Jalview
2729 public void groovyShell_actionPerformed()
2733 openGroovyConsole();
2734 } catch (Exception ex)
2736 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2737 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2739 MessageManager.getString("label.couldnt_create_groovy_shell"),
2740 MessageManager.getString("label.groovy_support_failed"),
2741 JvOptionPane.ERROR_MESSAGE);
2746 * Open the Groovy console
2748 void openGroovyConsole()
2750 if (groovyConsole == null)
2752 groovyConsole = new groovy.ui.Console();
2753 groovyConsole.setVariable("Jalview", this);
2754 groovyConsole.run();
2757 * We allow only one console at a time, so that AlignFrame menu option
2758 * 'Calculate | Run Groovy script' is unambiguous.
2759 * Disable 'Groovy Console', and enable 'Run script', when the console is
2760 * opened, and the reverse when it is closed
2762 Window window = (Window) groovyConsole.getFrame();
2763 window.addWindowListener(new WindowAdapter()
2766 public void windowClosed(WindowEvent e)
2769 * rebind CMD-Q from Groovy Console to Jalview Quit
2772 enableExecuteGroovy(false);
2778 * show Groovy console window (after close and reopen)
2780 ((Window) groovyConsole.getFrame()).setVisible(true);
2783 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2784 * and disable opening a second console
2786 enableExecuteGroovy(true);
2790 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2793 protected void addQuitHandler()
2795 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2796 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2797 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2799 getRootPane().getActionMap().put("Quit", new AbstractAction()
2802 public void actionPerformed(ActionEvent e)
2810 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2813 * true if Groovy console is open
2815 public void enableExecuteGroovy(boolean enabled)
2818 * disable opening a second Groovy console
2819 * (or re-enable when the console is closed)
2821 groovyShell.setEnabled(!enabled);
2823 AlignFrame[] alignFrames = getAlignFrames();
2824 if (alignFrames != null)
2826 for (AlignFrame af : alignFrames)
2828 af.setGroovyEnabled(enabled);
2834 * Progress bars managed by the IProgressIndicator method.
2836 private Hashtable<Long, JPanel> progressBars;
2838 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2843 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2846 public void setProgressBar(String message, long id)
2848 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2850 if (progressBars == null)
2852 progressBars = new Hashtable<>();
2853 progressBarHandlers = new Hashtable<>();
2856 if (progressBars.get(new Long(id)) != null)
2858 JPanel panel = progressBars.remove(new Long(id));
2859 if (progressBarHandlers.contains(new Long(id)))
2861 progressBarHandlers.remove(new Long(id));
2863 removeProgressPanel(panel);
2867 progressBars.put(new Long(id), addProgressPanel(message));
2874 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2875 * jalview.gui.IProgressIndicatorHandler)
2878 public void registerHandler(final long id,
2879 final IProgressIndicatorHandler handler)
2881 if (progressBarHandlers == null
2882 || !progressBars.containsKey(new Long(id)))
2884 throw new Error(MessageManager.getString(
2885 "error.call_setprogressbar_before_registering_handler"));
2887 progressBarHandlers.put(new Long(id), handler);
2888 final JPanel progressPanel = progressBars.get(new Long(id));
2889 if (handler.canCancel())
2891 JButton cancel = new JButton(
2892 MessageManager.getString("action.cancel"));
2893 final IProgressIndicator us = this;
2894 cancel.addActionListener(new ActionListener()
2898 public void actionPerformed(ActionEvent e)
2900 handler.cancelActivity(id);
2901 us.setProgressBar(MessageManager
2902 .formatMessage("label.cancelled_params", new Object[]
2903 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2907 progressPanel.add(cancel, BorderLayout.EAST);
2913 * @return true if any progress bars are still active
2916 public boolean operationInProgress()
2918 if (progressBars != null && progressBars.size() > 0)
2926 * This will return the first AlignFrame holding the given viewport instance. It
2927 * will break if there are more than one AlignFrames viewing a particular av.
2930 * @return alignFrame for viewport
2932 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2934 if (desktop != null)
2936 AlignmentPanel[] aps = getAlignmentPanels(
2937 viewport.getSequenceSetId());
2938 for (int panel = 0; aps != null && panel < aps.length; panel++)
2940 if (aps[panel] != null && aps[panel].av == viewport)
2942 return aps[panel].alignFrame;
2949 public VamsasApplication getVamsasApplication()
2956 * flag set if jalview GUI is being operated programmatically
2958 private boolean inBatchMode = false;
2961 * check if jalview GUI is being operated programmatically
2963 * @return inBatchMode
2965 public boolean isInBatchMode()
2971 * set flag if jalview GUI is being operated programmatically
2973 * @param inBatchMode
2975 public void setInBatchMode(boolean inBatchMode)
2977 this.inBatchMode = inBatchMode;
2980 public void startServiceDiscovery()
2982 startServiceDiscovery(false);
2985 public void startServiceDiscovery(boolean blocking)
2987 boolean alive = true;
2988 Thread t0 = null, t1 = null, t2 = null;
2989 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2992 // todo: changesupport handlers need to be transferred
2993 if (discoverer == null)
2995 discoverer = new jalview.ws.jws1.Discoverer();
2996 // register PCS handler for desktop.
2997 discoverer.addPropertyChangeListener(changeSupport);
2999 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3000 // until we phase out completely
3001 (t0 = new Thread(discoverer)).start();
3004 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3006 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3007 .startDiscoverer(changeSupport);
3011 // TODO: do rest service discovery
3020 } catch (Exception e)
3023 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3024 || (t3 != null && t3.isAlive())
3025 || (t0 != null && t0.isAlive());
3031 * called to check if the service discovery process completed successfully.
3035 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3037 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3039 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3040 .getErrorMessages();
3043 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3045 if (serviceChangedDialog == null)
3047 // only run if we aren't already displaying one of these.
3048 addDialogThread(serviceChangedDialog = new Runnable()
3055 * JalviewDialog jd =new JalviewDialog() {
3057 * @Override protected void cancelPressed() { // TODO
3058 * Auto-generated method stub
3060 * }@Override protected void okPressed() { // TODO
3061 * Auto-generated method stub
3063 * }@Override protected void raiseClosed() { // TODO
3064 * Auto-generated method stub
3066 * } }; jd.initDialogFrame(new
3067 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3068 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3069 * + " or mis-configured HTTP proxy settings.<br/>" +
3070 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3072 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3073 * ), true, true, "Web Service Configuration Problem", 450,
3076 * jd.waitForInput();
3078 JvOptionPane.showConfirmDialog(Desktop.desktop,
3079 new JLabel("<html><table width=\"450\"><tr><td>"
3080 + ermsg + "</td></tr></table>"
3081 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3082 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3083 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3084 + " Tools->Preferences dialog box to change them.</p></html>"),
3085 "Web Service Configuration Problem",
3086 JvOptionPane.DEFAULT_OPTION,
3087 JvOptionPane.ERROR_MESSAGE);
3088 serviceChangedDialog = null;
3097 "Errors reported by JABA discovery service. Check web services preferences.\n"
3104 private Runnable serviceChangedDialog = null;
3107 * start a thread to open a URL in the configured browser. Pops up a warning
3108 * dialog to the user if there is an exception when calling out to the browser
3113 public static void showUrl(final String url)
3115 showUrl(url, Desktop.instance);
3119 * Like showUrl but allows progress handler to be specified
3123 * (null) or object implementing IProgressIndicator
3125 public static void showUrl(final String url,
3126 final IProgressIndicator progress)
3128 new Thread(new Runnable()
3135 if (progress != null)
3137 progress.setProgressBar(MessageManager
3138 .formatMessage("status.opening_params", new Object[]
3139 { url }), this.hashCode());
3141 jalview.util.BrowserLauncher.openURL(url);
3142 } catch (Exception ex)
3144 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3146 .getString("label.web_browser_not_found_unix"),
3147 MessageManager.getString("label.web_browser_not_found"),
3148 JvOptionPane.WARNING_MESSAGE);
3150 ex.printStackTrace();
3152 if (progress != null)
3154 progress.setProgressBar(null, this.hashCode());
3160 public static WsParamSetManager wsparamManager = null;
3162 public static ParamManager getUserParameterStore()
3164 if (wsparamManager == null)
3166 wsparamManager = new WsParamSetManager();
3168 return wsparamManager;
3172 * static hyperlink handler proxy method for use by Jalview's internal windows
3176 public static void hyperlinkUpdate(HyperlinkEvent e)
3178 if (e.getEventType() == EventType.ACTIVATED)
3183 url = e.getURL().toString();
3184 Desktop.showUrl(url);
3185 } catch (Exception x)
3189 if (Cache.log != null)
3191 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3196 "Couldn't handle string " + url + " as a URL.");
3199 // ignore any exceptions due to dud links.
3206 * single thread that handles display of dialogs to user.
3208 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3211 * flag indicating if dialogExecutor should try to acquire a permit
3213 private volatile boolean dialogPause = true;
3218 private java.util.concurrent.Semaphore block = new Semaphore(0);
3220 private static groovy.ui.Console groovyConsole;
3223 * add another dialog thread to the queue
3227 public void addDialogThread(final Runnable prompter)
3229 dialogExecutor.submit(new Runnable()
3239 } catch (InterruptedException x)
3244 if (instance == null)
3250 SwingUtilities.invokeAndWait(prompter);
3251 } catch (Exception q)
3253 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3259 public void startDialogQueue()
3261 // set the flag so we don't pause waiting for another permit and semaphore
3262 // the current task to begin
3263 dialogPause = false;
3268 * Outputs an image of the desktop to file in EPS format, after prompting the
3269 * user for choice of Text or Lineart character rendering (unless a preference
3270 * has been set). The file name is generated as
3273 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3277 protected void snapShotWindow_actionPerformed(ActionEvent e)
3279 // currently the menu option to do this is not shown
3282 int width = getWidth();
3283 int height = getHeight();
3285 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3286 ImageWriterI writer = new ImageWriterI()
3289 public void exportImage(Graphics g) throws Exception
3292 Cache.log.info("Successfully written snapshot to file "
3293 + of.getAbsolutePath());
3296 String title = "View of desktop";
3297 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3299 exporter.doExport(of, this, width, height, title);
3303 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3304 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3305 * location last time the view was expanded (if any). However it does not
3306 * remember the split pane divider location - this is set to match the
3307 * 'exploding' frame.
3311 public void explodeViews(SplitFrame sf)
3313 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3314 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3315 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3317 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3319 int viewCount = topPanels.size();
3326 * Processing in reverse order works, forwards order leaves the first panels
3327 * not visible. I don't know why!
3329 for (int i = viewCount - 1; i >= 0; i--)
3332 * Make new top and bottom frames. These take over the respective
3333 * AlignmentPanel objects, including their AlignmentViewports, so the
3334 * cdna/protein relationships between the viewports is carried over to the
3337 * explodedGeometry holds the (x, y) position of the previously exploded
3338 * SplitFrame, and the (width, height) of the AlignFrame component
3340 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3341 AlignFrame newTopFrame = new AlignFrame(topPanel);
3342 newTopFrame.setSize(oldTopFrame.getSize());
3343 newTopFrame.setVisible(true);
3344 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3345 .getExplodedGeometry();
3346 if (geometry != null)
3348 newTopFrame.setSize(geometry.getSize());
3351 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3352 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3353 newBottomFrame.setSize(oldBottomFrame.getSize());
3354 newBottomFrame.setVisible(true);
3355 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3356 .getExplodedGeometry();
3357 if (geometry != null)
3359 newBottomFrame.setSize(geometry.getSize());
3362 topPanel.av.setGatherViewsHere(false);
3363 bottomPanel.av.setGatherViewsHere(false);
3364 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3366 if (geometry != null)
3368 splitFrame.setLocation(geometry.getLocation());
3370 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3374 * Clear references to the panels (now relocated in the new SplitFrames)
3375 * before closing the old SplitFrame.
3378 bottomPanels.clear();
3383 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3384 * back into the given SplitFrame as additional views. Note that the gathered
3385 * frames may themselves have multiple views.
3389 public void gatherViews(GSplitFrame source)
3392 * special handling of explodedGeometry for a view within a SplitFrame: - it
3393 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3394 * height) of the AlignFrame component
3396 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3397 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3398 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3399 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3400 myBottomFrame.viewport
3401 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3402 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3403 myTopFrame.viewport.setGatherViewsHere(true);
3404 myBottomFrame.viewport.setGatherViewsHere(true);
3405 String topViewId = myTopFrame.viewport.getSequenceSetId();
3406 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3408 JInternalFrame[] frames = desktop.getAllFrames();
3409 for (JInternalFrame frame : frames)
3411 if (frame instanceof SplitFrame && frame != source)
3413 SplitFrame sf = (SplitFrame) frame;
3414 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3415 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3416 boolean gatherThis = false;
3417 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3419 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3420 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3421 if (topViewId.equals(topPanel.av.getSequenceSetId())
3422 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3425 topPanel.av.setGatherViewsHere(false);
3426 bottomPanel.av.setGatherViewsHere(false);
3427 topPanel.av.setExplodedGeometry(
3428 new Rectangle(sf.getLocation(), topFrame.getSize()));
3429 bottomPanel.av.setExplodedGeometry(
3430 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3431 myTopFrame.addAlignmentPanel(topPanel, false);
3432 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3438 topFrame.getAlignPanels().clear();
3439 bottomFrame.getAlignPanels().clear();
3446 * The dust settles...give focus to the tab we did this from.
3448 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3451 public static groovy.ui.Console getGroovyConsole()
3453 return groovyConsole;
3457 * handles the payload of a drag and drop event.
3459 * TODO refactor to desktop utilities class
3462 * - Data source strings extracted from the drop event
3464 * - protocol for each data source extracted from the drop event
3468 * - the payload from the drop event
3471 public static void transferFromDropTarget(List<Object> files,
3472 List<DataSourceType> protocols, DropTargetDropEvent evt,
3473 Transferable t) throws Exception
3476 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3478 // DataFlavor[] flavors = t.getTransferDataFlavors();
3479 // for (int i = 0; i < flavors.length; i++) {
3480 // if (flavors[i].isFlavorJavaFileListType()) {
3481 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3482 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3483 // for (int j = 0; j < list.size(); j++) {
3484 // File file = (File) list.get(j);
3485 // byte[] data = getDroppedFileBytes(file);
3486 // fileName.setText(file.getName() + " - " + data.length + " " +
3487 // evt.getLocation());
3488 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3489 // target.setText(new String(data));
3491 // dtde.dropComplete(true);
3496 DataFlavor uriListFlavor = new DataFlavor(
3497 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3500 urlFlavour = new DataFlavor(
3501 "application/x-java-url; class=java.net.URL");
3502 } catch (ClassNotFoundException cfe)
3504 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3507 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3512 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3513 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3514 // means url may be null.
3517 protocols.add(DataSourceType.URL);
3518 files.add(url.toString());
3519 Cache.log.debug("Drop handled as URL dataflavor "
3520 + files.get(files.size() - 1));
3525 if (Platform.isAMacAndNotJS())
3528 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3532 } catch (Throwable ex)
3534 Cache.log.debug("URL drop handler failed.", ex);
3537 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3539 // Works on Windows and MacOSX
3540 Cache.log.debug("Drop handled as javaFileListFlavor");
3541 for (Object file : (List) t
3542 .getTransferData(DataFlavor.javaFileListFlavor))
3545 protocols.add(DataSourceType.FILE);
3550 // Unix like behaviour
3551 boolean added = false;
3553 if (t.isDataFlavorSupported(uriListFlavor))
3555 Cache.log.debug("Drop handled as uriListFlavor");
3556 // This is used by Unix drag system
3557 data = (String) t.getTransferData(uriListFlavor);
3561 // fallback to text: workaround - on OSX where there's a JVM bug
3562 Cache.log.debug("standard URIListFlavor failed. Trying text");
3563 // try text fallback
3564 DataFlavor textDf = new DataFlavor(
3565 "text/plain;class=java.lang.String");
3566 if (t.isDataFlavorSupported(textDf))
3568 data = (String) t.getTransferData(textDf);
3571 Cache.log.debug("Plain text drop content returned "
3572 + (data == null ? "Null - failed" : data));
3577 while (protocols.size() < files.size())
3579 Cache.log.debug("Adding missing FILE protocol for "
3580 + files.get(protocols.size()));
3581 protocols.add(DataSourceType.FILE);
3583 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3584 data, "\r\n"); st.hasMoreTokens();)
3587 String s = st.nextToken();
3588 if (s.startsWith("#"))
3590 // the line is a comment (as per the RFC 2483)
3593 java.net.URI uri = new java.net.URI(s);
3594 if (uri.getScheme().toLowerCase().startsWith("http"))
3596 protocols.add(DataSourceType.URL);
3597 files.add(uri.toString());
3601 // otherwise preserve old behaviour: catch all for file objects
3602 java.io.File file = new java.io.File(uri);
3603 protocols.add(DataSourceType.FILE);
3604 files.add(file.toString());
3609 if (Cache.log.isDebugEnabled())
3611 if (data == null || !added)
3614 if (t.getTransferDataFlavors() != null
3615 && t.getTransferDataFlavors().length > 0)
3618 "Couldn't resolve drop data. Here are the supported flavors:");
3619 for (DataFlavor fl : t.getTransferDataFlavors())
3622 "Supported transfer dataflavor: " + fl.toString());
3623 Object df = t.getTransferData(fl);
3626 Cache.log.debug("Retrieves: " + df);
3630 Cache.log.debug("Retrieved nothing");
3636 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3642 if (Platform.isWindowsAndNotJS())
3644 Cache.log.debug("Scanning dropped content for Windows Link Files");
3646 // resolve any .lnk files in the file drop
3647 for (int f = 0; f < files.size(); f++)
3649 String source = files.get(f).toString().toLowerCase();
3650 if (protocols.get(f).equals(DataSourceType.FILE)
3651 && (source.endsWith(".lnk") || source.endsWith(".url")
3652 || source.endsWith(".site")))
3656 Object obj = files.get(f);
3657 File lf = (obj instanceof File ? (File) obj
3658 : new File((String) obj));
3659 // process link file to get a URL
3660 Cache.log.debug("Found potential link file: " + lf);
3661 WindowsShortcut wscfile = new WindowsShortcut(lf);
3662 String fullname = wscfile.getRealFilename();
3663 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3664 files.set(f, fullname);
3665 Cache.log.debug("Parsed real filename " + fullname
3666 + " to extract protocol: " + protocols.get(f));
3667 } catch (Exception ex)
3670 "Couldn't parse " + files.get(f) + " as a link file.",
3679 * Sets the Preferences property for experimental features to True or False
3680 * depending on the state of the controlling menu item
3683 protected void showExperimental_actionPerformed(boolean selected)
3685 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3689 * Answers a (possibly empty) list of any structure viewer frames (currently for
3690 * either Jmol or Chimera) which are currently open. This may optionally be
3691 * restricted to viewers of a specified class, or viewers linked to a specified
3695 * if not null, only return viewers linked to this panel
3696 * @param structureViewerClass
3697 * if not null, only return viewers of this class
3700 public List<StructureViewerBase> getStructureViewers(
3701 AlignmentPanel apanel,
3702 Class<? extends StructureViewerBase> structureViewerClass)
3704 List<StructureViewerBase> result = new ArrayList<>();
3705 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3707 for (JInternalFrame frame : frames)
3709 if (frame instanceof StructureViewerBase)
3711 if (structureViewerClass == null
3712 || structureViewerClass.isInstance(frame))
3715 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3717 result.add((StructureViewerBase) frame);