2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.bin.Instance;
27 import jalview.bin.Jalview;
28 import jalview.gui.ImageExporter.ImageWriterI;
29 import jalview.io.BackupFiles;
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.project.Jalview2XML;
43 import jalview.structure.StructureSelectionManager;
44 import jalview.urls.IdOrgSettings;
45 import jalview.util.BrowserLauncher;
46 import jalview.util.ImageMaker.TYPE;
47 import jalview.util.MessageManager;
48 import jalview.util.Platform;
49 import jalview.util.UrlConstants;
50 import jalview.viewmodel.AlignmentViewport;
51 import jalview.ws.jws1.Discoverer;
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 @SuppressWarnings("serial")
138 public class Desktop extends jalview.jbgui.GDesktop
139 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
140 jalview.api.StructureSelectionManagerProvider
143 private final static int DEFAULT_MIN_WIDTH = 300;
145 private final static int DEFAULT_MIN_HEIGHT = 250;
147 private final static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
149 private final static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
151 private final static String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
153 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
156 * news reader - null if it was never started.
158 BlogReader jvnews = null;
160 private File projectFile;
164 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
166 public void addJalviewPropertyChangeListener(
167 PropertyChangeListener listener)
169 changeSupport.addJalviewPropertyChangeListener(listener);
173 * @param propertyName
175 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
176 * java.beans.PropertyChangeListener)
178 public void addJalviewPropertyChangeListener(String propertyName,
179 PropertyChangeListener listener)
181 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
185 * @param propertyName
187 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
188 * java.beans.PropertyChangeListener)
190 public void removeJalviewPropertyChangeListener(String propertyName,
191 PropertyChangeListener listener)
193 changeSupport.removeJalviewPropertyChangeListener(propertyName,
197 public static MyDesktopPane getDesktopPane()
199 return Desktop.getInstance().desktopPane;
202 public static StructureSelectionManager getStructureSelectionManager()
204 return StructureSelectionManager
205 .getStructureSelectionManager(Desktop.getInstance());
208 static int openFrameCount = 0;
210 static final int xOffset = 30;
212 static final int yOffset = 30;
214 public Discoverer discoverer;
216 public Object[] jalviewClipboard;
218 public boolean internalCopy = false;
220 private static int fileLoadingCount = 0;
222 public JInternalFrame conservationSlider, PIDSlider;
225 * just an instance (for testng, probably); no actual frames
227 private boolean instanceOnly;
229 class MyDesktopManager implements DesktopManager
232 private DesktopManager delegate;
234 public MyDesktopManager(DesktopManager delegate)
236 this.delegate = delegate;
240 public void activateFrame(JInternalFrame f)
244 delegate.activateFrame(f);
245 } catch (NullPointerException npe)
247 Point p = getMousePosition();
248 showPasteMenu(p.x, p.y);
253 public void beginDraggingFrame(JComponent f)
255 delegate.beginDraggingFrame(f);
259 public void beginResizingFrame(JComponent f, int direction)
261 delegate.beginResizingFrame(f, direction);
265 public void closeFrame(JInternalFrame f)
267 delegate.closeFrame(f);
271 public void deactivateFrame(JInternalFrame f)
273 delegate.deactivateFrame(f);
277 public void deiconifyFrame(JInternalFrame f)
279 delegate.deiconifyFrame(f);
283 public void dragFrame(JComponent f, int newX, int newY)
289 delegate.dragFrame(f, newX, newY);
293 public void endDraggingFrame(JComponent f)
295 delegate.endDraggingFrame(f);
296 desktopPane.repaint();
300 public void endResizingFrame(JComponent f)
302 delegate.endResizingFrame(f);
303 desktopPane.repaint();
307 public void iconifyFrame(JInternalFrame f)
309 delegate.iconifyFrame(f);
313 public void maximizeFrame(JInternalFrame f)
315 delegate.maximizeFrame(f);
319 public void minimizeFrame(JInternalFrame f)
321 delegate.minimizeFrame(f);
325 public void openFrame(JInternalFrame f)
327 delegate.openFrame(f);
331 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
338 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
342 public void setBoundsForFrame(JComponent f, int newX, int newY,
343 int newWidth, int newHeight)
345 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
348 // All other methods, simply delegate
352 public MyDesktopPane desktopPane;
354 public static Desktop getInstance()
356 Instance i = Instance.getInstance();
357 return (i.desktop == null ? (i.desktop = new Desktop(true))
366 public Desktop(boolean forInstance)
371 * Creates a new Desktop object.
376 * A note to implementors. It is ESSENTIAL that any activities that might
377 * block are spawned off as threads rather than waited for during this
380 Instance.getInstance().desktop = this;
382 if (!Platform.isJS())
384 doVamsasClientCheck();
387 doConfigureStructurePrefs();
388 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
389 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
390 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
392 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
394 desktopPane = new MyDesktopPane(selmemusage);
396 showMemusage.setSelected(selmemusage);
397 desktopPane.setBackground(Color.white);
398 getContentPane().setLayout(new BorderLayout());
399 // alternate config - have scrollbars - see notes in JAL-153
400 // JScrollPane sp = new JScrollPane();
401 // sp.getViewport().setView(desktop);
402 // getContentPane().add(sp, BorderLayout.CENTER);
404 // BH 2018 - just an experiment to try unclipped JInternalFrames.
407 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
410 getContentPane().add(desktopPane, BorderLayout.CENTER);
411 desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
413 // This line prevents Windows Look&Feel resizing all new windows to maximum
414 // if previous window was maximised
415 desktopPane.setDesktopManager(new MyDesktopManager(
416 (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
417 : Platform.isAMacAndNotJS()
418 ? new AquaInternalFrameManager(
419 desktopPane.getDesktopManager())
420 : desktopPane.getDesktopManager())));
422 Rectangle dims = getLastKnownDimensions("");
429 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
430 int xPos = Math.max(5, (screenSize.width - 900) / 2);
431 int yPos = Math.max(5, (screenSize.height - 650) / 2);
432 setBounds(xPos, yPos, 900, 650);
435 if (!Platform.isJS())
443 jconsole = new Console(this, showjconsole);
444 // add essential build information
445 jconsole.setHeader("Jalview Version: "
446 + jalview.bin.Cache.getProperty("VERSION") + "\n"
447 + "Jalview Installation: "
448 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
449 + "\n" + "Build Date: "
450 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
451 + "Java version: " + System.getProperty("java.version") + "\n"
452 + System.getProperty("os.arch") + " "
453 + System.getProperty("os.name") + " "
454 + System.getProperty("os.version"));
456 showConsole(showjconsole);
458 showNews.setVisible(false);
460 experimentalFeatures.setSelected(showExperimental());
462 getIdentifiersOrgData();
466 // Spawn a thread that shows the splashscreen
468 SwingUtilities.invokeLater(new Runnable()
477 // Thread off a new instance of the file chooser - this reduces the time
479 // takes to open it later on.
480 new Thread(new Runnable()
485 Cache.log.debug("Filechooser init thread started.");
486 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
487 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
489 Cache.log.debug("Filechooser init thread finished.");
492 // Add the service change listener
493 changeSupport.addJalviewPropertyChangeListener("services",
494 new PropertyChangeListener()
498 public void propertyChange(PropertyChangeEvent evt)
500 Cache.log.debug("Firing service changed event for "
501 + evt.getNewValue());
502 JalviewServicesChanged(evt);
509 this.setDropTarget(new java.awt.dnd.DropTarget(desktopPane, this));
511 this.addWindowListener(new WindowAdapter()
514 public void windowClosing(WindowEvent evt)
521 this.addMouseListener(ma = new MouseAdapter()
524 public void mousePressed(MouseEvent evt)
526 if (evt.isPopupTrigger()) // Mac
528 showPasteMenu(evt.getX(), evt.getY());
533 public void mouseReleased(MouseEvent evt)
535 if (evt.isPopupTrigger()) // Windows
537 showPasteMenu(evt.getX(), evt.getY());
541 desktopPane.addMouseListener(ma);
546 * Answers true if user preferences to enable experimental features is True
551 public boolean showExperimental()
553 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
554 Boolean.FALSE.toString());
555 return Boolean.valueOf(experimental).booleanValue();
558 public void doConfigureStructurePrefs()
560 // configure services
561 StructureSelectionManager ssm = getStructureSelectionManager();
562 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
564 ssm.setAddTempFacAnnot(jalview.bin.Cache
565 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
566 ssm.setProcessSecondaryStructure(jalview.bin.Cache
567 .getDefault(Preferences.STRUCT_FROM_PDB, true));
568 ssm.setSecStructServices(
569 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
573 ssm.setAddTempFacAnnot(false);
574 ssm.setProcessSecondaryStructure(false);
575 ssm.setSecStructServices(false);
579 public void checkForNews()
581 final Desktop me = this;
582 // Thread off the news reader, in case there are connection problems.
583 new Thread(new Runnable()
588 Cache.log.debug("Starting news thread.");
589 jvnews = new BlogReader(me);
590 showNews.setVisible(true);
591 Cache.log.debug("Completed news thread.");
596 public void getIdentifiersOrgData()
598 // Thread off the identifiers fetcher
599 new Thread(new Runnable()
604 Cache.log.debug("Downloading data from identifiers.org");
605 // UrlDownloadClient client = new UrlDownloadClient();
608 UrlDownloadClient.download(IdOrgSettings.getUrl(),
609 IdOrgSettings.getDownloadLocation());
610 } catch (IOException e)
612 Cache.log.debug("Exception downloading identifiers.org data"
621 protected void showNews_actionPerformed(ActionEvent e)
623 showNews(showNews.isSelected());
626 protected void showNews(boolean visible)
628 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
629 showNews.setSelected(visible);
630 if (visible && !jvnews.isVisible())
632 new Thread(new Runnable()
637 long now = System.currentTimeMillis();
639 MessageManager.getString("status.refreshing_news"), now);
640 jvnews.refreshNews();
641 setProgressBar(null, now);
649 * recover the last known dimensions for a jalview window
652 * - empty string is desktop, all other windows have unique prefix
653 * @return null or last known dimensions scaled to current geometry (if last
654 * window geom was known)
656 Rectangle getLastKnownDimensions(String windowName)
658 // TODO: lock aspect ratio for scaling desktop Bug #0058199
659 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
660 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
661 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
662 String width = jalview.bin.Cache
663 .getProperty(windowName + "SCREEN_WIDTH");
664 String height = jalview.bin.Cache
665 .getProperty(windowName + "SCREEN_HEIGHT");
666 if ((x != null) && (y != null) && (width != null) && (height != null))
668 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
669 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
670 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
672 // attempt #1 - try to cope with change in screen geometry - this
673 // version doesn't preserve original jv aspect ratio.
674 // take ratio of current screen size vs original screen size.
675 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
676 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
677 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
678 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
679 // rescale the bounds depending upon the current screen geometry.
680 ix = (int) (ix * sw);
681 iw = (int) (iw * sw);
682 iy = (int) (iy * sh);
683 ih = (int) (ih * sh);
684 while (ix >= screenSize.width)
686 jalview.bin.Cache.log.debug(
687 "Window geometry location recall error: shifting horizontal to within screenbounds.");
688 ix -= screenSize.width;
690 while (iy >= screenSize.height)
692 jalview.bin.Cache.log.debug(
693 "Window geometry location recall error: shifting vertical to within screenbounds.");
694 iy -= screenSize.height;
696 jalview.bin.Cache.log.debug(
697 "Got last known dimensions for " + windowName + ": x:" + ix
698 + " y:" + iy + " width:" + iw + " height:" + ih);
700 // return dimensions for new instance
701 return new Rectangle(ix, iy, iw, ih);
706 private void doVamsasClientCheck()
708 if (Cache.vamsasJarsPresent())
710 setupVamsasDisconnectedGui();
711 VamsasMenu.setVisible(true);
712 final Desktop us = this;
713 VamsasMenu.addMenuListener(new MenuListener()
715 // this listener remembers when the menu was first selected, and
716 // doesn't rebuild the session list until it has been cleared and
718 boolean refresh = true;
721 public void menuCanceled(MenuEvent e)
727 public void menuDeselected(MenuEvent e)
733 public void menuSelected(MenuEvent e)
737 us.buildVamsasStMenu();
742 vamsasStart.setVisible(true);
746 protected void showPasteMenu(int x, int y)
748 JPopupMenu popup = new JPopupMenu();
749 JMenuItem item = new JMenuItem(
750 MessageManager.getString("label.paste_new_window"));
751 item.addActionListener(new ActionListener()
754 public void actionPerformed(ActionEvent evt)
761 popup.show(this, x, y);
768 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
769 Transferable contents = c.getContents(this);
771 if (contents != null)
773 String file = (String) contents
774 .getTransferData(DataFlavor.stringFlavor);
776 FileFormatI format = new IdentifyFile().identify(file,
777 DataSourceType.PASTE);
779 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
782 } catch (Exception ex)
785 "Unable to paste alignment from system clipboard:\n" + ex);
790 * Adds and opens the given frame to the desktop
801 public static synchronized void addInternalFrame(
802 final JInternalFrame frame, String title, int w, int h)
804 addInternalFrame(frame, title, true, w, h, true, false);
808 * Add an internal frame to the Jalview desktop
815 * When true, display frame immediately, otherwise, caller must call
816 * setVisible themselves.
822 public static synchronized void addInternalFrame(
823 final JInternalFrame frame, String title, boolean makeVisible,
826 addInternalFrame(frame, title, makeVisible, w, h, true, false);
830 * Add an internal frame to the Jalview desktop and make it visible
843 public static synchronized void addInternalFrame(
844 final JInternalFrame frame, String title, int w, int h,
847 addInternalFrame(frame, title, true, w, h, resizable, false);
851 * Add an internal frame to the Jalview desktop
858 * When true, display frame immediately, otherwise, caller must call
859 * setVisible themselves.
866 * @param ignoreMinSize
867 * Do not set the default minimum size for frame
869 public static synchronized void addInternalFrame(
870 final JInternalFrame frame, String title, boolean makeVisible,
871 int w, int h, boolean resizable, boolean ignoreMinSize)
874 // TODO: allow callers to determine X and Y position of frame (eg. via
876 // TODO: consider fixing method to update entries in the window submenu with
877 // the current window title
879 frame.setTitle(title);
880 if (frame.getWidth() < 1 || frame.getHeight() < 1)
884 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
885 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
886 // IF JALVIEW IS RUNNING HEADLESS
887 // ///////////////////////////////////////////////
888 if (Desktop.getInstance().instanceOnly || Jalview.isHeadlessMode())
897 frame.setMinimumSize(
898 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
900 // Set default dimension for Alignment Frame window.
901 // The Alignment Frame window could be added from a number of places,
903 // I did this here in order not to miss out on any Alignment frame.
904 if (frame instanceof AlignFrame)
906 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
907 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
911 frame.setVisible(makeVisible);
912 frame.setClosable(true);
913 frame.setResizable(resizable);
914 frame.setMaximizable(resizable);
915 frame.setIconifiable(resizable);
916 frame.setOpaque(Platform.isJS());
918 if (frame.getX() < 1 && frame.getY() < 1)
920 frame.setLocation(xOffset * openFrameCount,
921 yOffset * ((openFrameCount - 1) % 10) + yOffset);
925 * add an entry for the new frame in the Window menu
926 * (and remove it when the frame is closed)
928 JMenuItem menuItem = new JMenuItem(title);
929 frame.addInternalFrameListener(new InternalFrameAdapter()
932 public void internalFrameActivated(InternalFrameEvent evt)
934 JInternalFrame itf = getDesktopPane().getSelectedFrame();
937 if (itf instanceof AlignFrame)
939 Jalview.setCurrentAlignFrame((AlignFrame) itf);
946 public void internalFrameClosed(InternalFrameEvent evt)
948 PaintRefresher.RemoveComponent(frame);
951 * defensive check to prevent frames being
952 * added half off the window
954 if (openFrameCount > 0)
960 * ensure no reference to alignFrame retained by menu item listener
962 if (menuItem.getActionListeners().length > 0)
964 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
966 Desktop.getInstance().windowMenu.remove(menuItem);
970 menuItem.addActionListener(new ActionListener()
973 public void actionPerformed(ActionEvent e)
977 frame.setSelected(true);
978 frame.setIcon(false);
979 } catch (java.beans.PropertyVetoException ex)
981 // System.err.println(ex.toString());
986 setKeyBindings(frame);
988 getDesktopPane().add(frame);
990 Desktop.getInstance().windowMenu.add(menuItem);
995 frame.setSelected(true);
996 frame.requestFocus();
997 } catch (java.beans.PropertyVetoException ve)
999 } catch (java.lang.ClassCastException cex)
1002 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1008 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
1013 private static void setKeyBindings(JInternalFrame frame)
1015 final Action closeAction = new AbstractAction()
1018 public void actionPerformed(ActionEvent e)
1025 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1027 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1028 InputEvent.CTRL_DOWN_MASK);
1029 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1030 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1032 InputMap inputMap = frame
1033 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1034 String ctrlW = ctrlWKey.toString();
1035 inputMap.put(ctrlWKey, ctrlW);
1036 inputMap.put(cmdWKey, ctrlW);
1038 ActionMap actionMap = frame.getActionMap();
1039 actionMap.put(ctrlW, closeAction);
1043 public void lostOwnership(Clipboard clipboard, Transferable contents)
1047 Desktop.getInstance().jalviewClipboard = null;
1050 internalCopy = false;
1054 public void dragEnter(DropTargetDragEvent evt)
1059 public void dragExit(DropTargetEvent evt)
1064 public void dragOver(DropTargetDragEvent evt)
1069 public void dropActionChanged(DropTargetDragEvent evt)
1080 public void drop(DropTargetDropEvent evt)
1082 boolean success = true;
1083 // JAL-1552 - acceptDrop required before getTransferable call for
1084 // Java's Transferable for native dnd
1085 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1086 Transferable t = evt.getTransferable();
1087 List<Object> files = new ArrayList<>();
1088 List<DataSourceType> protocols = new ArrayList<>();
1092 Desktop.transferFromDropTarget(files, protocols, evt, t);
1093 } catch (Exception e)
1095 e.printStackTrace();
1103 for (int i = 0; i < files.size(); i++)
1105 // BH 2018 File or String
1106 Object file = files.get(i);
1107 String fileName = file.toString();
1108 DataSourceType protocol = (protocols == null)
1109 ? DataSourceType.FILE
1111 FileFormatI format = null;
1113 if (fileName.endsWith(".jar"))
1115 format = FileFormat.Jalview;
1120 format = new IdentifyFile().identify(file, protocol);
1122 if (file instanceof File)
1124 Platform.cacheFileData((File) file);
1126 new FileLoader().LoadFile(null, file, protocol, format);
1129 } catch (Exception ex)
1134 evt.dropComplete(success); // need this to ensure input focus is properly
1135 // transfered to any new windows created
1145 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1147 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1148 JalviewFileChooser chooser = JalviewFileChooser
1149 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1151 chooser.setFileView(new JalviewFileView());
1152 chooser.setDialogTitle(
1153 MessageManager.getString("label.open_local_file"));
1154 chooser.setToolTipText(MessageManager.getString("action.open"));
1156 chooser.setResponseHandler(0, new Runnable()
1161 File selectedFile = chooser.getSelectedFile();
1162 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1164 FileFormatI format = chooser.getSelectedFormat();
1167 * Call IdentifyFile to verify the file contains what its extension implies.
1168 * Skip this step for dynamically added file formats, because
1169 * IdentifyFile does not know how to recognise them.
1171 if (FileFormats.getInstance().isIdentifiable(format))
1175 format = new IdentifyFile().identify(selectedFile,
1176 DataSourceType.FILE);
1177 } catch (FileFormatException e)
1179 // format = null; //??
1183 new FileLoader().LoadFile(viewport, selectedFile,
1184 DataSourceType.FILE, format);
1187 chooser.showOpenDialog(this);
1191 * Shows a dialog for input of a URL at which to retrieve alignment data
1196 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1198 // This construct allows us to have a wider textfield
1200 JLabel label = new JLabel(
1201 MessageManager.getString("label.input_file_url"));
1203 JPanel panel = new JPanel(new GridLayout(2, 1));
1207 * the URL to fetch is
1208 * Java: an editable combobox with history
1209 * JS: (pending JAL-3038) a plain text field
1212 String urlBase = "http://www.";
1213 if (Platform.isJS())
1215 history = new JTextField(urlBase, 35);
1224 JComboBox<String> asCombo = new JComboBox<>();
1225 asCombo.setPreferredSize(new Dimension(400, 20));
1226 asCombo.setEditable(true);
1227 asCombo.addItem(urlBase);
1228 String historyItems = Cache.getProperty("RECENT_URL");
1229 if (historyItems != null)
1231 for (String token : historyItems.split("\\t"))
1233 asCombo.addItem(token);
1240 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1241 MessageManager.getString("action.cancel") };
1242 Runnable action = new Runnable()
1247 @SuppressWarnings("unchecked")
1248 String url = (history instanceof JTextField
1249 ? ((JTextField) history).getText()
1250 : ((JComboBox<String>) history).getSelectedItem()
1253 if (url.toLowerCase().endsWith(".jar"))
1255 if (viewport != null)
1257 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1258 FileFormat.Jalview);
1262 new FileLoader().LoadFile(url, DataSourceType.URL,
1263 FileFormat.Jalview);
1268 FileFormatI format = null;
1271 format = new IdentifyFile().identify(url, DataSourceType.URL);
1272 } catch (FileFormatException e)
1274 // TODO revise error handling, distinguish between
1275 // URL not found and response not valid
1280 String msg = MessageManager
1281 .formatMessage("label.couldnt_locate", url);
1282 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
1284 MessageManager.getString("label.url_not_found"),
1285 JvOptionPane.WARNING_MESSAGE);
1290 if (viewport != null)
1292 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1297 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1302 String dialogOption = MessageManager
1303 .getString("label.input_alignment_from_url");
1304 JvOptionPane.newOptionDialog(getDesktopPane())
1305 .setResponseHandler(0, action)
1306 .showInternalDialog(panel, dialogOption,
1307 JvOptionPane.YES_NO_CANCEL_OPTION,
1308 JvOptionPane.PLAIN_MESSAGE, null, options,
1309 MessageManager.getString("action.ok"));
1313 * Opens the CutAndPaste window for the user to paste an alignment in to
1316 * - if not null, the pasted alignment is added to the current
1317 * alignment; if null, to a new alignment window
1320 public void inputTextboxMenuItem_actionPerformed(
1321 AlignmentViewPanel viewPanel)
1323 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1324 cap.setForInput(viewPanel);
1325 Desktop.addInternalFrame(cap,
1326 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1336 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1337 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1339 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1340 screen.height + "");
1341 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1342 getWidth(), getHeight()));
1344 if (jconsole != null)
1346 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1347 jconsole.stopConsole();
1351 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1354 if (dialogExecutor != null)
1356 dialogExecutor.shutdownNow();
1358 closeAll_actionPerformed(null);
1360 if (groovyConsole != null)
1362 // suppress a possible repeat prompt to save script
1363 groovyConsole.setDirty(false);
1364 groovyConsole.exit();
1369 private void storeLastKnownDimensions(String string, Rectangle jc)
1371 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1372 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1373 + " height:" + jc.height);
1375 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1376 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1377 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1378 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1388 public void aboutMenuItem_actionPerformed(ActionEvent e)
1390 // StringBuffer message = getAboutMessage(false);
1391 // JvOptionPane.showInternalMessageDialog(Desktop.getDesktop(),
1393 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1394 new Thread(new Runnable()
1399 new SplashScreen(true);
1404 public StringBuffer getAboutMessage(boolean shortv)
1406 StringBuffer message = new StringBuffer();
1407 message.append("<html>");
1410 message.append("<h1><strong>Version: "
1411 + jalview.bin.Cache.getProperty("VERSION")
1412 + "</strong></h1>");
1413 message.append("<strong>Last Updated: <em>"
1414 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1415 + "</em></strong>");
1421 message.append("<strong>Version "
1422 + jalview.bin.Cache.getProperty("VERSION")
1423 + "; last updated: "
1424 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1427 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1428 .equals("Checking"))
1430 message.append("<br>...Checking latest version...</br>");
1432 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1433 .equals(jalview.bin.Cache.getProperty("VERSION")))
1435 boolean red = false;
1436 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1437 .indexOf("automated build") == -1)
1440 // Displayed when code version and jnlp version do not match and code
1441 // version is not a development build
1442 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1445 message.append("<br>!! Version "
1446 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1448 + " is available for download from "
1449 + jalview.bin.Cache.getDefault("www.jalview.org",
1450 "http://www.jalview.org")
1454 message.append("</div>");
1457 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1459 "The Jalview Authors (See AUTHORS file for current list)")
1460 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1461 + "<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"
1462 + "<br><br>If you use Jalview, please cite:"
1463 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1464 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1465 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1471 * Action on requesting Help documentation
1474 public void documentationMenuItem_actionPerformed()
1478 if (Platform.isJS())
1480 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1489 Help.showHelpWindow();
1491 } catch (Exception ex)
1493 System.err.println("Error opening help: " + ex.getMessage());
1498 public void closeAll_actionPerformed(ActionEvent e)
1500 if (desktopPane == null)
1504 // TODO show a progress bar while closing?
1505 JInternalFrame[] frames = desktopPane.getAllFrames();
1506 for (int i = 0; i < frames.length; i++)
1510 frames[i].setClosed(true);
1511 } catch (java.beans.PropertyVetoException ex)
1515 Jalview.setCurrentAlignFrame(null);
1516 System.out.println("ALL CLOSED");
1517 if (v_client != null)
1519 // TODO clear binding to vamsas document objects on close_all
1523 * reset state of singleton objects as appropriate (clear down session state
1524 * when all windows are closed)
1526 getStructureSelectionManager().resetAll();
1530 public void raiseRelated_actionPerformed(ActionEvent e)
1532 reorderAssociatedWindows(false, false);
1536 public void minimizeAssociated_actionPerformed(ActionEvent e)
1538 reorderAssociatedWindows(true, false);
1541 void closeAssociatedWindows()
1543 reorderAssociatedWindows(false, true);
1549 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1553 protected void garbageCollect_actionPerformed(ActionEvent e)
1555 // We simply collect the garbage
1556 jalview.bin.Cache.log.debug("Collecting garbage...");
1558 jalview.bin.Cache.log.debug("Finished garbage collection.");
1565 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1569 protected void showMemusage_actionPerformed(ActionEvent e)
1571 getDesktopPane().showMemoryUsage(showMemusage.isSelected());
1578 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1582 protected void showConsole_actionPerformed(ActionEvent e)
1584 showConsole(showConsole.isSelected());
1587 Console jconsole = null;
1590 * control whether the java console is visible or not
1594 void showConsole(boolean selected)
1596 // TODO: decide if we should update properties file
1597 if (jconsole != null) // BH 2018
1599 showConsole.setSelected(selected);
1600 Cache.setProperty("SHOW_JAVA_CONSOLE",
1601 Boolean.valueOf(selected).toString());
1602 jconsole.setVisible(selected);
1606 void reorderAssociatedWindows(boolean minimize, boolean close)
1608 JInternalFrame[] frames = getDesktopPane().getAllFrames();
1609 if (frames == null || frames.length < 1)
1614 AlignmentViewport source = null, target = null;
1615 if (frames[0] instanceof AlignFrame)
1617 source = ((AlignFrame) frames[0]).getCurrentView();
1619 else if (frames[0] instanceof TreePanel)
1621 source = ((TreePanel) frames[0]).getViewPort();
1623 else if (frames[0] instanceof PCAPanel)
1625 source = ((PCAPanel) frames[0]).av;
1627 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1629 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1634 for (int i = 0; i < frames.length; i++)
1637 if (frames[i] == null)
1641 if (frames[i] instanceof AlignFrame)
1643 target = ((AlignFrame) frames[i]).getCurrentView();
1645 else if (frames[i] instanceof TreePanel)
1647 target = ((TreePanel) frames[i]).getViewPort();
1649 else if (frames[i] instanceof PCAPanel)
1651 target = ((PCAPanel) frames[i]).av;
1653 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1655 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1658 if (source == target)
1664 frames[i].setClosed(true);
1668 frames[i].setIcon(minimize);
1671 frames[i].toFront();
1675 } catch (java.beans.PropertyVetoException ex)
1690 protected void preferences_actionPerformed(ActionEvent e)
1696 * Prompts the user to choose a file and then saves the Jalview state as a
1697 * Jalview project file
1700 public void saveState_actionPerformed()
1702 saveState_actionPerformed(false);
1705 public void saveState_actionPerformed(boolean saveAs)
1707 java.io.File projectFile = getProjectFile();
1708 // autoSave indicates we already have a file and don't need to ask
1709 boolean autoSave = projectFile != null && !saveAs
1710 && BackupFiles.getEnabled();
1712 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1713 // saveAs="+saveAs+", Backups
1714 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1716 boolean approveSave = false;
1719 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1722 chooser.setFileView(new JalviewFileView());
1723 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1725 int value = chooser.showSaveDialog(this);
1727 if (value == JalviewFileChooser.APPROVE_OPTION)
1729 projectFile = chooser.getSelectedFile();
1730 setProjectFile(projectFile);
1735 if (approveSave || autoSave)
1737 final Desktop me = this;
1738 final java.io.File chosenFile = projectFile;
1739 new Thread(new Runnable()
1744 // TODO: refactor to Jalview desktop session controller action.
1745 setProgressBar(MessageManager.formatMessage(
1746 "label.saving_jalview_project", new Object[]
1747 { chosenFile.getName() }), chosenFile.hashCode());
1748 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1749 chosenFile.getParent());
1750 // TODO catch and handle errors for savestate
1751 // TODO prevent user from messing with the Desktop whilst we're saving
1754 boolean doBackup = BackupFiles.getEnabled();
1755 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1757 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1761 backupfiles.setWriteSuccess(true);
1762 backupfiles.rollBackupsAndRenameTempFile();
1764 } catch (OutOfMemoryError oom)
1766 new OOMWarning("Whilst saving current state to "
1767 + chosenFile.getName(), oom);
1768 } catch (Exception ex)
1770 Cache.log.error("Problems whilst trying to save to "
1771 + chosenFile.getName(), ex);
1772 JvOptionPane.showMessageDialog(me,
1773 MessageManager.formatMessage(
1774 "label.error_whilst_saving_current_state_to",
1776 { chosenFile.getName() }),
1777 MessageManager.getString("label.couldnt_save_project"),
1778 JvOptionPane.WARNING_MESSAGE);
1780 setProgressBar(null, chosenFile.hashCode());
1787 public void saveAsState_actionPerformed(ActionEvent e)
1789 saveState_actionPerformed(true);
1792 protected void setProjectFile(File choice)
1794 this.projectFile = choice;
1797 public File getProjectFile()
1799 return this.projectFile;
1803 * Shows a file chooser dialog and tries to read in the selected file as a
1807 public void loadState_actionPerformed()
1809 final String[] suffix = new String[] { "jvp", "jar" };
1810 final String[] desc = new String[] { "Jalview Project",
1811 "Jalview Project (old)" };
1812 JalviewFileChooser chooser = new JalviewFileChooser(
1813 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1814 "Jalview Project", true, true); // last two booleans: allFiles,
1816 chooser.setFileView(new JalviewFileView());
1817 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1818 chooser.setResponseHandler(0, new Runnable()
1823 File selectedFile = chooser.getSelectedFile();
1824 setProjectFile(selectedFile);
1825 String choice = selectedFile.getAbsolutePath();
1826 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1827 new Thread(new Runnable()
1834 new Jalview2XML().loadJalviewAlign(choice);
1835 } catch (OutOfMemoryError oom)
1837 new OOMWarning("Whilst loading project from " + choice, oom);
1838 } catch (Exception ex)
1841 "Problems whilst loading project from " + choice, ex);
1842 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
1843 MessageManager.formatMessage(
1844 "label.error_whilst_loading_project_from",
1847 MessageManager.getString("label.couldnt_load_project"),
1848 JvOptionPane.WARNING_MESSAGE);
1855 chooser.showOpenDialog(this);
1859 public void inputSequence_actionPerformed(ActionEvent e)
1861 new SequenceFetcher(this);
1864 JPanel progressPanel;
1866 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1868 public void startLoading(final Object fileName)
1870 if (fileLoadingCount == 0)
1872 fileLoadingPanels.add(addProgressPanel(MessageManager
1873 .formatMessage("label.loading_file", new Object[]
1879 private JPanel addProgressPanel(String string)
1881 if (progressPanel == null)
1883 progressPanel = new JPanel(new GridLayout(1, 1));
1884 totalProgressCount = 0;
1885 getContentPane().add(progressPanel, BorderLayout.SOUTH);
1887 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1888 JProgressBar progressBar = new JProgressBar();
1889 progressBar.setIndeterminate(true);
1891 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1893 thisprogress.add(progressBar, BorderLayout.CENTER);
1894 progressPanel.add(thisprogress);
1895 ((GridLayout) progressPanel.getLayout()).setRows(
1896 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1897 ++totalProgressCount;
1899 return thisprogress;
1902 int totalProgressCount = 0;
1904 private void removeProgressPanel(JPanel progbar)
1906 if (progressPanel != null)
1908 synchronized (progressPanel)
1910 progressPanel.remove(progbar);
1911 GridLayout gl = (GridLayout) progressPanel.getLayout();
1912 gl.setRows(gl.getRows() - 1);
1913 if (--totalProgressCount < 1)
1915 this.getContentPane().remove(progressPanel);
1916 progressPanel = null;
1923 public void stopLoading()
1926 if (fileLoadingCount < 1)
1928 while (fileLoadingPanels.size() > 0)
1930 removeProgressPanel(fileLoadingPanels.remove(0));
1932 fileLoadingPanels.clear();
1933 fileLoadingCount = 0;
1938 public static int getViewCount(String alignmentId)
1940 AlignmentViewport[] aps = getViewports(alignmentId);
1941 return (aps == null) ? 0 : aps.length;
1946 * @param alignmentId
1947 * - if null, all sets are returned
1948 * @return all AlignmentPanels concerning the alignmentId sequence set
1950 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1952 if (Desktop.getDesktopPane() == null)
1954 // no frames created and in headless mode
1955 // TODO: verify that frames are recoverable when in headless mode
1958 List<AlignmentPanel> aps = new ArrayList<>();
1959 AlignFrame[] frames = getAlignFrames();
1964 for (AlignFrame af : frames)
1966 for (AlignmentPanel ap : af.alignPanels)
1968 if (alignmentId == null
1969 || alignmentId.equals(ap.av.getSequenceSetId()))
1975 if (aps.size() == 0)
1979 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1984 * get all the viewports on an alignment.
1986 * @param sequenceSetId
1987 * unique alignment id (may be null - all viewports returned in that
1989 * @return all viewports on the alignment bound to sequenceSetId
1991 public static AlignmentViewport[] getViewports(String sequenceSetId)
1993 List<AlignmentViewport> viewp = new ArrayList<>();
1994 if (getDesktopPane() != null)
1996 AlignFrame[] frames = Desktop.getAlignFrames();
1998 for (AlignFrame afr : frames)
2000 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2001 .equals(sequenceSetId))
2003 if (afr.alignPanels != null)
2005 for (AlignmentPanel ap : afr.alignPanels)
2007 if (sequenceSetId == null
2008 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2016 viewp.add(afr.getViewport());
2020 if (viewp.size() > 0)
2022 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2029 * Explode the views in the given frame into separate AlignFrame
2033 public static void explodeViews(AlignFrame af)
2035 int size = af.alignPanels.size();
2041 for (int i = 0; i < size; i++)
2043 AlignmentPanel ap = af.alignPanels.get(i);
2044 AlignFrame newaf = new AlignFrame(ap);
2047 * Restore the view's last exploded frame geometry if known. Multiple
2048 * views from one exploded frame share and restore the same (frame)
2049 * position and size.
2051 Rectangle geometry = ap.av.getExplodedGeometry();
2052 if (geometry != null)
2054 newaf.setBounds(geometry);
2057 ap.av.setGatherViewsHere(false);
2059 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2060 AlignFrame.DEFAULT_HEIGHT);
2063 af.alignPanels.clear();
2064 af.closeMenuItem_actionPerformed(true);
2069 * Gather expanded views (separate AlignFrame's) with the same sequence set
2070 * identifier back in to this frame as additional views, and close the expanded
2071 * views. Note the expanded frames may themselves have multiple views. We take
2076 public void gatherViews(AlignFrame source)
2078 source.viewport.setGatherViewsHere(true);
2079 source.viewport.setExplodedGeometry(source.getBounds());
2080 JInternalFrame[] frames = getAllFrames();
2081 String viewId = source.viewport.getSequenceSetId();
2083 for (int t = 0; t < frames.length; t++)
2085 if (frames[t] instanceof AlignFrame && frames[t] != source)
2087 AlignFrame af = (AlignFrame) frames[t];
2088 boolean gatherThis = false;
2089 for (int a = 0; a < af.alignPanels.size(); a++)
2091 AlignmentPanel ap = af.alignPanels.get(a);
2092 if (viewId.equals(ap.av.getSequenceSetId()))
2095 ap.av.setGatherViewsHere(false);
2096 ap.av.setExplodedGeometry(af.getBounds());
2097 source.addAlignmentPanel(ap, false);
2103 af.alignPanels.clear();
2104 af.closeMenuItem_actionPerformed(true);
2111 jalview.gui.VamsasApplication v_client = null;
2114 public void vamsasImport_actionPerformed(ActionEvent e)
2116 // TODO: JAL-3048 not needed for Jalview-JS
2118 if (v_client == null)
2120 // Load and try to start a session.
2121 JalviewFileChooser chooser = new JalviewFileChooser(
2122 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2124 chooser.setFileView(new JalviewFileView());
2125 chooser.setDialogTitle(
2126 MessageManager.getString("label.open_saved_vamsas_session"));
2127 chooser.setToolTipText(MessageManager.getString(
2128 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2130 int value = chooser.showOpenDialog(this);
2132 if (value == JalviewFileChooser.APPROVE_OPTION)
2134 String fle = chooser.getSelectedFile().toString();
2135 if (!vamsasImport(chooser.getSelectedFile()))
2137 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2138 MessageManager.formatMessage(
2139 "label.couldnt_import_as_vamsas_session",
2143 .getString("label.vamsas_document_import_failed"),
2144 JvOptionPane.ERROR_MESSAGE);
2150 jalview.bin.Cache.log.error(
2151 "Implementation error - load session from a running session is not supported.");
2156 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2159 * @return true if import was a success and a session was started.
2161 public boolean vamsasImport(URL url)
2163 // TODO: create progress bar
2164 if (v_client != null)
2167 jalview.bin.Cache.log.error(
2168 "Implementation error - load session from a running session is not supported.");
2174 // copy the URL content to a temporary local file
2175 // TODO: be a bit cleverer here with nio (?!)
2176 File file = File.createTempFile("vdocfromurl", ".vdj");
2177 FileOutputStream fos = new FileOutputStream(file);
2178 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2179 byte[] buffer = new byte[2048];
2181 while ((ln = bis.read(buffer)) > -1)
2183 fos.write(buffer, 0, ln);
2187 v_client = new jalview.gui.VamsasApplication(this, file,
2188 url.toExternalForm());
2189 } catch (Exception ex)
2191 jalview.bin.Cache.log.error(
2192 "Failed to create new vamsas session from contents of URL "
2197 setupVamsasConnectedGui();
2198 v_client.initial_update(); // TODO: thread ?
2199 return v_client.inSession();
2203 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2206 * @return true if import was a success and a session was started.
2208 public boolean vamsasImport(File file)
2210 if (v_client != null)
2213 jalview.bin.Cache.log.error(
2214 "Implementation error - load session from a running session is not supported.");
2218 setProgressBar(MessageManager.formatMessage(
2219 "status.importing_vamsas_session_from", new Object[]
2220 { file.getName() }), file.hashCode());
2223 v_client = new jalview.gui.VamsasApplication(this, file, null);
2224 } catch (Exception ex)
2226 setProgressBar(MessageManager.formatMessage(
2227 "status.importing_vamsas_session_from", new Object[]
2228 { file.getName() }), file.hashCode());
2229 jalview.bin.Cache.log.error(
2230 "New vamsas session from existing session file failed:", ex);
2233 setupVamsasConnectedGui();
2234 v_client.initial_update(); // TODO: thread ?
2235 setProgressBar(MessageManager.formatMessage(
2236 "status.importing_vamsas_session_from", new Object[]
2237 { file.getName() }), file.hashCode());
2238 return v_client.inSession();
2241 public boolean joinVamsasSession(String mysesid)
2243 if (v_client != null)
2245 throw new Error(MessageManager
2246 .getString("error.try_join_vamsas_session_another"));
2248 if (mysesid == null)
2251 MessageManager.getString("error.invalid_vamsas_session_id"));
2253 v_client = new VamsasApplication(this, mysesid);
2254 setupVamsasConnectedGui();
2255 v_client.initial_update();
2256 return (v_client.inSession());
2260 public void vamsasStart_actionPerformed(ActionEvent e)
2262 if (v_client == null)
2265 // we just start a default session for moment.
2267 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2268 * getProperty("LAST_DIRECTORY"));
2270 * chooser.setFileView(new JalviewFileView());
2271 * chooser.setDialogTitle("Load Vamsas file");
2272 * chooser.setToolTipText("Import");
2274 * int value = chooser.showOpenDialog(this);
2276 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2277 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2279 v_client = new VamsasApplication(this);
2280 setupVamsasConnectedGui();
2281 v_client.initial_update(); // TODO: thread ?
2285 // store current data in session.
2286 v_client.push_update(); // TODO: thread
2290 protected void setupVamsasConnectedGui()
2292 vamsasStart.setText(MessageManager.getString("label.session_update"));
2293 vamsasSave.setVisible(true);
2294 vamsasStop.setVisible(true);
2295 vamsasImport.setVisible(false); // Document import to existing session is
2296 // not possible for vamsas-client-1.0.
2299 protected void setupVamsasDisconnectedGui()
2301 vamsasSave.setVisible(false);
2302 vamsasStop.setVisible(false);
2303 vamsasImport.setVisible(true);
2305 .setText(MessageManager.getString("label.new_vamsas_session"));
2309 public void vamsasStop_actionPerformed(ActionEvent e)
2311 if (v_client != null)
2313 v_client.end_session();
2315 setupVamsasDisconnectedGui();
2319 protected void buildVamsasStMenu()
2321 if (v_client == null)
2323 String[] sess = null;
2326 sess = VamsasApplication.getSessionList();
2327 } catch (Exception e)
2329 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2335 jalview.bin.Cache.log.debug(
2336 "Got current sessions list: " + sess.length + " entries.");
2337 VamsasStMenu.removeAll();
2338 for (int i = 0; i < sess.length; i++)
2340 JMenuItem sessit = new JMenuItem();
2341 sessit.setText(sess[i]);
2342 sessit.setToolTipText(MessageManager
2343 .formatMessage("label.connect_to_session", new Object[]
2345 final Desktop dsktp = this;
2346 final String mysesid = sess[i];
2347 sessit.addActionListener(new ActionListener()
2351 public void actionPerformed(ActionEvent e)
2353 if (dsktp.v_client == null)
2355 Thread rthr = new Thread(new Runnable()
2361 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2362 dsktp.setupVamsasConnectedGui();
2363 dsktp.v_client.initial_update();
2371 VamsasStMenu.add(sessit);
2373 // don't show an empty menu.
2374 VamsasStMenu.setVisible(sess.length > 0);
2379 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2380 VamsasStMenu.removeAll();
2381 VamsasStMenu.setVisible(false);
2386 // Not interested in the content. Just hide ourselves.
2387 VamsasStMenu.setVisible(false);
2392 public void vamsasSave_actionPerformed(ActionEvent e)
2394 // TODO: JAL-3048 not needed for Jalview-JS
2396 if (v_client != null)
2398 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2399 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2402 chooser.setFileView(new JalviewFileView());
2403 chooser.setDialogTitle(MessageManager
2404 .getString("label.save_vamsas_document_archive"));
2406 int value = chooser.showSaveDialog(this);
2408 if (value == JalviewFileChooser.APPROVE_OPTION)
2410 java.io.File choice = chooser.getSelectedFile();
2411 JPanel progpanel = addProgressPanel(MessageManager
2412 .formatMessage("label.saving_vamsas_doc", new Object[]
2413 { choice.getName() }));
2414 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2415 String warnmsg = null;
2416 String warnttl = null;
2419 v_client.vclient.storeDocument(choice);
2422 warnttl = "Serious Problem saving Vamsas Document";
2423 warnmsg = ex.toString();
2424 jalview.bin.Cache.log
2425 .error("Error Whilst saving document to " + choice, ex);
2427 } catch (Exception ex)
2429 warnttl = "Problem saving Vamsas Document.";
2430 warnmsg = ex.toString();
2431 jalview.bin.Cache.log.warn(
2432 "Exception Whilst saving document to " + choice, ex);
2435 removeProgressPanel(progpanel);
2436 if (warnmsg != null)
2438 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2440 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2446 JPanel vamUpdate = null;
2449 * hide vamsas user gui bits when a vamsas document event is being handled.
2452 * true to hide gui, false to reveal gui
2454 public void setVamsasUpdate(boolean b)
2456 Cache.log.debug("Setting gui for Vamsas update "
2457 + (b ? "in progress" : "finished"));
2459 if (vamUpdate != null)
2461 this.removeProgressPanel(vamUpdate);
2465 vamUpdate = this.addProgressPanel(
2466 MessageManager.getString("label.updating_vamsas_session"));
2468 vamsasStart.setVisible(!b);
2469 vamsasStop.setVisible(!b);
2470 vamsasSave.setVisible(!b);
2473 public JInternalFrame[] getAllFrames()
2475 return desktopPane.getAllFrames();
2479 * Checks the given url to see if it gives a response indicating that the user
2480 * should be informed of a new questionnaire.
2484 public void checkForQuestionnaire(String url)
2486 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2487 // javax.swing.SwingUtilities.invokeLater(jvq);
2488 new Thread(jvq).start();
2491 public void checkURLLinks()
2493 // Thread off the URL link checker
2494 addDialogThread(new Runnable()
2499 if (Cache.getDefault("CHECKURLLINKS", true))
2501 // check what the actual links are - if it's just the default don't
2502 // bother with the warning
2503 List<String> links = Preferences.sequenceUrlLinks
2506 // only need to check links if there is one with a
2507 // SEQUENCE_ID which is not the default EMBL_EBI link
2508 ListIterator<String> li = links.listIterator();
2509 boolean check = false;
2510 List<JLabel> urls = new ArrayList<>();
2511 while (li.hasNext())
2513 String link = li.next();
2514 if (link.contains(UrlConstants.SEQUENCE_ID)
2515 && !UrlConstants.isDefaultString(link))
2518 int barPos = link.indexOf("|");
2519 String urlMsg = barPos == -1 ? link
2520 : link.substring(0, barPos) + ": "
2521 + link.substring(barPos + 1);
2522 urls.add(new JLabel(urlMsg));
2530 // ask user to check in case URL links use old style tokens
2531 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2532 JPanel msgPanel = new JPanel();
2533 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2534 msgPanel.add(Box.createVerticalGlue());
2535 JLabel msg = new JLabel(MessageManager
2536 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2537 JLabel msg2 = new JLabel(MessageManager
2538 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2540 for (JLabel url : urls)
2546 final JCheckBox jcb = new JCheckBox(
2547 MessageManager.getString("label.do_not_display_again"));
2548 jcb.addActionListener(new ActionListener()
2551 public void actionPerformed(ActionEvent e)
2553 // update Cache settings for "don't show this again"
2554 boolean showWarningAgain = !jcb.isSelected();
2555 Cache.setProperty("CHECKURLLINKS",
2556 Boolean.valueOf(showWarningAgain).toString());
2561 JvOptionPane.showMessageDialog(desktopPane, msgPanel,
2563 .getString("label.SEQUENCE_ID_no_longer_used"),
2564 JvOptionPane.WARNING_MESSAGE);
2571 * Proxy class for JDesktopPane which optionally displays the current memory
2572 * usage and highlights the desktop area with a red bar if free memory runs low.
2576 public class MyDesktopPane extends JDesktopPane
2579 private static final float ONE_MB = 1048576f;
2581 boolean showMemoryUsage = false;
2585 java.text.NumberFormat df;
2587 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2590 public MyDesktopPane(boolean showMemoryUsage)
2592 showMemoryUsage(showMemoryUsage);
2595 public void showMemoryUsage(boolean showMemory)
2597 this.showMemoryUsage = showMemory;
2600 Thread worker = new Thread(this);
2606 public boolean isShowMemoryUsage()
2608 return showMemoryUsage;
2614 df = java.text.NumberFormat.getNumberInstance();
2615 df.setMaximumFractionDigits(2);
2616 runtime = Runtime.getRuntime();
2618 while (showMemoryUsage)
2622 maxMemory = runtime.maxMemory() / ONE_MB;
2623 allocatedMemory = runtime.totalMemory() / ONE_MB;
2624 freeMemory = runtime.freeMemory() / ONE_MB;
2625 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2627 percentUsage = (totalFreeMemory / maxMemory) * 100;
2629 // if (percentUsage < 20)
2631 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2633 // instance.set.setBorder(border1);
2636 // sleep after showing usage
2638 } catch (Exception ex)
2640 ex.printStackTrace();
2646 public void paintComponent(Graphics g)
2648 if (showMemoryUsage && g != null && df != null)
2650 if (percentUsage < 20)
2652 g.setColor(Color.red);
2654 FontMetrics fm = g.getFontMetrics();
2657 g.drawString(MessageManager.formatMessage("label.memory_stats",
2659 { df.format(totalFreeMemory), df.format(maxMemory),
2660 df.format(percentUsage) }),
2661 10, getHeight() - fm.getHeight());
2668 * Accessor method to quickly get all the AlignmentFrames loaded.
2670 * @return an array of AlignFrame, or null if none found
2672 public static AlignFrame[] getAlignFrames()
2674 if (Jalview.isHeadlessMode())
2676 // Desktop.getDesktop() is null in headless mode
2677 return new AlignFrame[] { Jalview.getCurrentAlignFrame() };
2680 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2686 List<AlignFrame> avp = new ArrayList<>();
2688 for (int i = frames.length - 1; i > -1; i--)
2690 if (frames[i] instanceof AlignFrame)
2692 avp.add((AlignFrame) frames[i]);
2694 else if (frames[i] instanceof SplitFrame)
2697 * Also check for a split frame containing an AlignFrame
2699 GSplitFrame sf = (GSplitFrame) frames[i];
2700 if (sf.getTopFrame() instanceof AlignFrame)
2702 avp.add((AlignFrame) sf.getTopFrame());
2704 if (sf.getBottomFrame() instanceof AlignFrame)
2706 avp.add((AlignFrame) sf.getBottomFrame());
2710 if (avp.size() == 0)
2714 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2719 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2723 public GStructureViewer[] getJmols()
2725 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2731 List<GStructureViewer> avp = new ArrayList<>();
2733 for (int i = frames.length - 1; i > -1; i--)
2735 if (frames[i] instanceof AppJmol)
2737 GStructureViewer af = (GStructureViewer) frames[i];
2741 if (avp.size() == 0)
2745 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2750 * Add Groovy Support to Jalview
2753 public void groovyShell_actionPerformed()
2757 openGroovyConsole();
2758 } catch (Exception ex)
2760 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2761 JvOptionPane.showInternalMessageDialog(desktopPane,
2763 MessageManager.getString("label.couldnt_create_groovy_shell"),
2764 MessageManager.getString("label.groovy_support_failed"),
2765 JvOptionPane.ERROR_MESSAGE);
2770 * Open the Groovy console
2772 private void openGroovyConsole()
2774 if (groovyConsole == null)
2776 groovyConsole = new groovy.ui.Console();
2777 groovyConsole.setVariable("Jalview", this);
2778 groovyConsole.run();
2781 * We allow only one console at a time, so that AlignFrame menu option
2782 * 'Calculate | Run Groovy script' is unambiguous.
2783 * Disable 'Groovy Console', and enable 'Run script', when the console is
2784 * opened, and the reverse when it is closed
2786 Window window = (Window) groovyConsole.getFrame();
2787 window.addWindowListener(new WindowAdapter()
2790 public void windowClosed(WindowEvent e)
2793 * rebind CMD-Q from Groovy Console to Jalview Quit
2796 enableExecuteGroovy(false);
2802 * show Groovy console window (after close and reopen)
2804 ((Window) groovyConsole.getFrame()).setVisible(true);
2807 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2808 * and disable opening a second console
2810 enableExecuteGroovy(true);
2814 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2817 protected void addQuitHandler()
2819 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2820 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2821 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2823 getRootPane().getActionMap().put("Quit", new AbstractAction()
2826 public void actionPerformed(ActionEvent e)
2834 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2837 * true if Groovy console is open
2839 public void enableExecuteGroovy(boolean enabled)
2842 * disable opening a second Groovy console
2843 * (or re-enable when the console is closed)
2845 groovyShell.setEnabled(!enabled);
2847 AlignFrame[] alignFrames = getAlignFrames();
2848 if (alignFrames != null)
2850 for (AlignFrame af : alignFrames)
2852 af.setGroovyEnabled(enabled);
2858 * Progress bars managed by the IProgressIndicator method.
2860 private Hashtable<Long, JPanel> progressBars;
2862 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2867 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2870 public void setProgressBar(String message, long id)
2872 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2874 if (progressBars == null)
2876 progressBars = new Hashtable<>();
2877 progressBarHandlers = new Hashtable<>();
2880 if (progressBars.get(new Long(id)) != null)
2882 JPanel panel = progressBars.remove(new Long(id));
2883 if (progressBarHandlers.contains(new Long(id)))
2885 progressBarHandlers.remove(new Long(id));
2887 removeProgressPanel(panel);
2891 progressBars.put(new Long(id), addProgressPanel(message));
2898 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2899 * jalview.gui.IProgressIndicatorHandler)
2902 public void registerHandler(final long id,
2903 final IProgressIndicatorHandler handler)
2905 if (progressBarHandlers == null
2906 || !progressBars.containsKey(new Long(id)))
2908 throw new Error(MessageManager.getString(
2909 "error.call_setprogressbar_before_registering_handler"));
2911 progressBarHandlers.put(new Long(id), handler);
2912 final JPanel progressPanel = progressBars.get(new Long(id));
2913 if (handler.canCancel())
2915 JButton cancel = new JButton(
2916 MessageManager.getString("action.cancel"));
2917 final IProgressIndicator us = this;
2918 cancel.addActionListener(new ActionListener()
2922 public void actionPerformed(ActionEvent e)
2924 handler.cancelActivity(id);
2925 us.setProgressBar(MessageManager
2926 .formatMessage("label.cancelled_params", new Object[]
2927 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2931 progressPanel.add(cancel, BorderLayout.EAST);
2937 * @return true if any progress bars are still active
2940 public boolean operationInProgress()
2942 if (progressBars != null && progressBars.size() > 0)
2950 * This will return the first AlignFrame holding the given viewport instance. It
2951 * will break if there are more than one AlignFrames viewing a particular av.
2954 * @return alignFrame for viewport
2956 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2958 if (getDesktopPane() != null)
2960 AlignmentPanel[] aps = getAlignmentPanels(
2961 viewport.getSequenceSetId());
2962 for (int panel = 0; aps != null && panel < aps.length; panel++)
2964 if (aps[panel] != null && aps[panel].av == viewport)
2966 return aps[panel].alignFrame;
2973 public VamsasApplication getVamsasApplication()
2980 * flag set if jalview GUI is being operated programmatically
2982 private boolean inBatchMode = false;
2985 * check if jalview GUI is being operated programmatically
2987 * @return inBatchMode
2989 public boolean isInBatchMode()
2995 * set flag if jalview GUI is being operated programmatically
2997 * @param inBatchMode
2999 public void setInBatchMode(boolean inBatchMode)
3001 this.inBatchMode = inBatchMode;
3004 public void startServiceDiscovery()
3006 startServiceDiscovery(false);
3009 public void startServiceDiscovery(boolean blocking)
3011 boolean alive = true;
3012 Thread t0 = null, t1 = null, t2 = null;
3013 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3016 // todo: changesupport handlers need to be transferred
3017 if (discoverer == null)
3019 discoverer = Discoverer.getInstance();
3020 // register PCS handler for getDesktop().
3021 discoverer.addPropertyChangeListener(changeSupport);
3023 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3024 // until we phase out completely
3025 (t0 = new Thread(discoverer)).start();
3028 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3030 t2 = jalview.ws.jws2.Jws2Discoverer.getInstance()
3031 .startDiscoverer(changeSupport);
3035 // TODO: do rest service discovery
3044 } catch (Exception e)
3047 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3048 || (t3 != null && t3.isAlive())
3049 || (t0 != null && t0.isAlive());
3055 * called to check if the service discovery process completed successfully.
3059 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3061 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3063 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
3064 .getErrorMessages();
3067 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3069 if (serviceChangedDialog == null)
3071 // only run if we aren't already displaying one of these.
3072 addDialogThread(serviceChangedDialog = new Runnable()
3079 * JalviewDialog jd =new JalviewDialog() {
3081 * @Override protected void cancelPressed() { // TODO
3082 * Auto-generated method stub
3084 * }@Override protected void okPressed() { // TODO
3085 * Auto-generated method stub
3087 * }@Override protected void raiseClosed() { // TODO
3088 * Auto-generated method stub
3090 * } }; jd.initDialogFrame(new
3091 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3092 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3093 * + " or mis-configured HTTP proxy settings.<br/>" +
3094 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3096 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3097 * ), true, true, "Web Service Configuration Problem", 450,
3100 * jd.waitForInput();
3102 JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(),
3103 new JLabel("<html><table width=\"450\"><tr><td>"
3104 + ermsg + "</td></tr></table>"
3105 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3106 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3107 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3108 + " Tools->Preferences dialog box to change them.</p></html>"),
3109 "Web Service Configuration Problem",
3110 JvOptionPane.DEFAULT_OPTION,
3111 JvOptionPane.ERROR_MESSAGE);
3112 serviceChangedDialog = null;
3121 "Errors reported by JABA discovery service. Check web services preferences.\n"
3128 Runnable serviceChangedDialog = null;
3131 * start a thread to open a URL in the configured browser. Pops up a warning
3132 * dialog to the user if there is an exception when calling out to the browser
3137 public static void showUrl(final String url)
3139 showUrl(url, Desktop.getInstance());
3143 * Like showUrl but allows progress handler to be specified
3147 * (null) or object implementing IProgressIndicator
3149 public static void showUrl(final String url,
3150 final IProgressIndicator progress)
3152 new Thread(new Runnable()
3159 if (progress != null)
3161 progress.setProgressBar(MessageManager
3162 .formatMessage("status.opening_params", new Object[]
3163 { url }), this.hashCode());
3165 BrowserLauncher.openURL(url);
3166 } catch (Exception ex)
3168 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3170 .getString("label.web_browser_not_found_unix"),
3171 MessageManager.getString("label.web_browser_not_found"),
3172 JvOptionPane.WARNING_MESSAGE);
3174 ex.printStackTrace();
3176 if (progress != null)
3178 progress.setProgressBar(null, this.hashCode());
3184 private WsParamSetManager wsparamManager = null;
3186 public static ParamManager getUserParameterStore()
3188 Desktop d = Desktop.getInstance();
3189 if (d.wsparamManager == null)
3191 d.wsparamManager = new WsParamSetManager();
3193 return d.wsparamManager;
3197 * static hyperlink handler proxy method for use by Jalview's internal windows
3201 public static void hyperlinkUpdate(HyperlinkEvent e)
3203 if (e.getEventType() == EventType.ACTIVATED)
3208 url = e.getURL().toString();
3209 Desktop.showUrl(url);
3210 } catch (Exception x)
3214 if (Cache.log != null)
3216 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3221 "Couldn't handle string " + url + " as a URL.");
3224 // ignore any exceptions due to dud links.
3231 * single thread that handles display of dialogs to user.
3233 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3236 * flag indicating if dialogExecutor should try to acquire a permit
3238 volatile boolean dialogPause = true;
3243 java.util.concurrent.Semaphore block = new Semaphore(0);
3245 private groovy.ui.Console groovyConsole;
3247 public StructureViewer lastTargetedView;
3250 * add another dialog thread to the queue
3254 public void addDialogThread(final Runnable prompter)
3256 dialogExecutor.submit(new Runnable()
3266 } catch (InterruptedException x)
3277 SwingUtilities.invokeAndWait(prompter);
3278 } catch (Exception q)
3280 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3286 public void startDialogQueue()
3288 // set the flag so we don't pause waiting for another permit and semaphore
3289 // the current task to begin
3290 dialogPause = false;
3295 * Outputs an image of the desktop to file in EPS format, after prompting the
3296 * user for choice of Text or Lineart character rendering (unless a preference
3297 * has been set). The file name is generated as
3300 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3304 protected void snapShotWindow_actionPerformed(ActionEvent e)
3306 // currently the menu option to do this is not shown
3309 int width = getWidth();
3310 int height = getHeight();
3312 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3313 ImageWriterI writer = new ImageWriterI()
3316 public void exportImage(Graphics g) throws Exception
3319 Cache.log.info("Successfully written snapshot to file "
3320 + of.getAbsolutePath());
3323 String title = "View of desktop";
3324 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3326 exporter.doExport(of, this, width, height, title);
3330 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3331 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3332 * location last time the view was expanded (if any). However it does not
3333 * remember the split pane divider location - this is set to match the
3334 * 'exploding' frame.
3338 public void explodeViews(SplitFrame sf)
3340 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3341 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3342 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3344 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3346 int viewCount = topPanels.size();
3353 * Processing in reverse order works, forwards order leaves the first panels
3354 * not visible. I don't know why!
3356 for (int i = viewCount - 1; i >= 0; i--)
3359 * Make new top and bottom frames. These take over the respective
3360 * AlignmentPanel objects, including their AlignmentViewports, so the
3361 * cdna/protein relationships between the viewports is carried over to the
3364 * explodedGeometry holds the (x, y) position of the previously exploded
3365 * SplitFrame, and the (width, height) of the AlignFrame component
3367 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3368 AlignFrame newTopFrame = new AlignFrame(topPanel);
3369 newTopFrame.setSize(oldTopFrame.getSize());
3370 newTopFrame.setVisible(true);
3371 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3372 .getExplodedGeometry();
3373 if (geometry != null)
3375 newTopFrame.setSize(geometry.getSize());
3378 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3379 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3380 newBottomFrame.setSize(oldBottomFrame.getSize());
3381 newBottomFrame.setVisible(true);
3382 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3383 .getExplodedGeometry();
3384 if (geometry != null)
3386 newBottomFrame.setSize(geometry.getSize());
3389 topPanel.av.setGatherViewsHere(false);
3390 bottomPanel.av.setGatherViewsHere(false);
3391 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3393 if (geometry != null)
3395 splitFrame.setLocation(geometry.getLocation());
3397 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3401 * Clear references to the panels (now relocated in the new SplitFrames)
3402 * before closing the old SplitFrame.
3405 bottomPanels.clear();
3410 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3411 * back into the given SplitFrame as additional views. Note that the gathered
3412 * frames may themselves have multiple views.
3416 public void gatherViews(GSplitFrame source)
3419 * special handling of explodedGeometry for a view within a SplitFrame: - it
3420 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3421 * height) of the AlignFrame component
3423 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3424 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3425 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3426 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3427 myBottomFrame.viewport
3428 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3429 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3430 myTopFrame.viewport.setGatherViewsHere(true);
3431 myBottomFrame.viewport.setGatherViewsHere(true);
3432 String topViewId = myTopFrame.viewport.getSequenceSetId();
3433 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3435 JInternalFrame[] frames = desktopPane.getAllFrames();
3436 for (JInternalFrame frame : frames)
3438 if (frame instanceof SplitFrame && frame != source)
3440 SplitFrame sf = (SplitFrame) frame;
3441 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3442 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3443 boolean gatherThis = false;
3444 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3446 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3447 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3448 if (topViewId.equals(topPanel.av.getSequenceSetId())
3449 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3452 topPanel.av.setGatherViewsHere(false);
3453 bottomPanel.av.setGatherViewsHere(false);
3454 topPanel.av.setExplodedGeometry(
3455 new Rectangle(sf.getLocation(), topFrame.getSize()));
3456 bottomPanel.av.setExplodedGeometry(
3457 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3458 myTopFrame.addAlignmentPanel(topPanel, false);
3459 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3465 topFrame.getAlignPanels().clear();
3466 bottomFrame.getAlignPanels().clear();
3473 * The dust settles...give focus to the tab we did this from.
3475 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3478 public static groovy.ui.Console getGroovyConsole()
3480 return Desktop.getInstance().groovyConsole;
3484 * handles the payload of a drag and drop event.
3486 * TODO refactor to desktop utilities class
3489 * - Data source strings extracted from the drop event
3491 * - protocol for each data source extracted from the drop event
3495 * - the payload from the drop event
3498 @SuppressWarnings("unchecked")
3499 public static void transferFromDropTarget(List<Object> files,
3500 List<DataSourceType> protocols, DropTargetDropEvent evt,
3501 Transferable t) throws Exception
3504 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3506 // DataFlavor[] flavors = t.getTransferDataFlavors();
3507 // for (int i = 0; i < flavors.length; i++) {
3508 // if (flavors[i].isFlavorJavaFileListType()) {
3509 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3510 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3511 // for (int j = 0; j < list.size(); j++) {
3512 // File file = (File) list.get(j);
3513 // byte[] data = getDroppedFileBytes(file);
3514 // fileName.setText(file.getName() + " - " + data.length + " " +
3515 // evt.getLocation());
3516 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3517 // target.setText(new String(data));
3519 // dtde.dropComplete(true);
3524 DataFlavor uriListFlavor = new DataFlavor(
3525 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3528 urlFlavour = new DataFlavor(
3529 "application/x-java-url; class=java.net.URL");
3530 } catch (ClassNotFoundException cfe)
3532 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3535 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3540 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3541 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3542 // means url may be null.
3545 protocols.add(DataSourceType.URL);
3546 files.add(url.toString());
3547 Cache.log.debug("Drop handled as URL dataflavor "
3548 + files.get(files.size() - 1));
3553 if (Platform.isAMacAndNotJS())
3556 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3560 } catch (Throwable ex)
3562 Cache.log.debug("URL drop handler failed.", ex);
3565 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3567 // Works on Windows and MacOSX
3568 Cache.log.debug("Drop handled as javaFileListFlavor");
3569 for (Object file : (List<Object>) t
3570 .getTransferData(DataFlavor.javaFileListFlavor))
3573 protocols.add(DataSourceType.FILE);
3578 // Unix like behaviour
3579 boolean added = false;
3581 if (t.isDataFlavorSupported(uriListFlavor))
3583 Cache.log.debug("Drop handled as uriListFlavor");
3584 // This is used by Unix drag system
3585 data = (String) t.getTransferData(uriListFlavor);
3589 // fallback to text: workaround - on OSX where there's a JVM bug
3590 Cache.log.debug("standard URIListFlavor failed. Trying text");
3591 // try text fallback
3592 DataFlavor textDf = new DataFlavor(
3593 "text/plain;class=java.lang.String");
3594 if (t.isDataFlavorSupported(textDf))
3596 data = (String) t.getTransferData(textDf);
3599 Cache.log.debug("Plain text drop content returned "
3600 + (data == null ? "Null - failed" : data));
3605 while (protocols.size() < files.size())
3607 Cache.log.debug("Adding missing FILE protocol for "
3608 + files.get(protocols.size()));
3609 protocols.add(DataSourceType.FILE);
3611 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3612 data, "\r\n"); st.hasMoreTokens();)
3615 String s = st.nextToken();
3616 if (s.startsWith("#"))
3618 // the line is a comment (as per the RFC 2483)
3621 java.net.URI uri = new java.net.URI(s);
3622 if (uri.getScheme().toLowerCase().startsWith("http"))
3624 protocols.add(DataSourceType.URL);
3625 files.add(uri.toString());
3629 // otherwise preserve old behaviour: catch all for file objects
3630 java.io.File file = new java.io.File(uri);
3631 protocols.add(DataSourceType.FILE);
3632 files.add(file.toString());
3637 if (Cache.log.isDebugEnabled())
3639 if (data == null || !added)
3642 if (t.getTransferDataFlavors() != null
3643 && t.getTransferDataFlavors().length > 0)
3646 "Couldn't resolve drop data. Here are the supported flavors:");
3647 for (DataFlavor fl : t.getTransferDataFlavors())
3650 "Supported transfer dataflavor: " + fl.toString());
3651 Object df = t.getTransferData(fl);
3654 Cache.log.debug("Retrieves: " + df);
3658 Cache.log.debug("Retrieved nothing");
3664 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3670 if (Platform.isWindowsAndNotJS())
3672 Cache.log.debug("Scanning dropped content for Windows Link Files");
3674 // resolve any .lnk files in the file drop
3675 for (int f = 0; f < files.size(); f++)
3677 String source = files.get(f).toString().toLowerCase();
3678 if (protocols.get(f).equals(DataSourceType.FILE)
3679 && (source.endsWith(".lnk") || source.endsWith(".url")
3680 || source.endsWith(".site")))
3684 Object obj = files.get(f);
3685 File lf = (obj instanceof File ? (File) obj
3686 : new File((String) obj));
3687 // process link file to get a URL
3688 Cache.log.debug("Found potential link file: " + lf);
3689 WindowsShortcut wscfile = new WindowsShortcut(lf);
3690 String fullname = wscfile.getRealFilename();
3691 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3692 files.set(f, fullname);
3693 Cache.log.debug("Parsed real filename " + fullname
3694 + " to extract protocol: " + protocols.get(f));
3695 } catch (Exception ex)
3698 "Couldn't parse " + files.get(f) + " as a link file.",
3707 * Sets the Preferences property for experimental features to True or False
3708 * depending on the state of the controlling menu item
3711 protected void showExperimental_actionPerformed(boolean selected)
3713 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3717 * Answers a (possibly empty) list of any structure viewer frames (currently for
3718 * either Jmol or Chimera) which are currently open. This may optionally be
3719 * restricted to viewers of a specified class, or viewers linked to a specified
3723 * if not null, only return viewers linked to this panel
3724 * @param structureViewerClass
3725 * if not null, only return viewers of this class
3728 public List<StructureViewerBase> getStructureViewers(
3729 AlignmentPanel apanel,
3730 Class<? extends StructureViewerBase> structureViewerClass)
3732 List<StructureViewerBase> result = new ArrayList<>();
3733 JInternalFrame[] frames = getAllFrames();
3735 for (JInternalFrame frame : frames)
3737 if (frame instanceof StructureViewerBase)
3739 if (structureViewerClass == null
3740 || structureViewerClass.isInstance(frame))
3743 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3745 result.add((StructureViewerBase) frame);