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 // boolean doFullLoad = /** @j2sNative ! */true;
410 if (!Platform.isJS())
418 jconsole = new Console(this, showjconsole);
419 // add essential build information
420 jconsole.setHeader("Jalview Version: "
421 + jalview.bin.Cache.getProperty("VERSION") + "\n"
422 + "Jalview Installation: "
423 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
424 + "\n" + "Build Date: "
425 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
426 + "Java version: " + System.getProperty("java.version") + "\n"
427 + System.getProperty("os.arch") + " "
428 + System.getProperty("os.name") + " "
429 + System.getProperty("os.version"));
431 showConsole(showjconsole);
433 showNews.setVisible(false);
435 experimentalFeatures.setSelected(showExperimental());
437 getIdentifiersOrgData();
441 // Spawn a thread that shows the splashscreen
443 SwingUtilities.invokeLater(new Runnable()
452 // Thread off a new instance of the file chooser - this reduces the time
454 // takes to open it later on.
455 new Thread(new Runnable()
460 Cache.log.debug("Filechooser init thread started.");
461 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
462 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
464 Cache.log.debug("Filechooser init thread finished.");
467 // Add the service change listener
468 changeSupport.addJalviewPropertyChangeListener("services",
469 new PropertyChangeListener()
473 public void propertyChange(PropertyChangeEvent evt)
475 Cache.log.debug("Firing service changed event for "
476 + evt.getNewValue());
477 JalviewServicesChanged(evt);
484 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
486 this.addWindowListener(new WindowAdapter()
489 public void windowClosing(WindowEvent evt)
496 this.addMouseListener(ma = new MouseAdapter()
499 public void mousePressed(MouseEvent evt)
501 if (evt.isPopupTrigger()) // Mac
503 showPasteMenu(evt.getX(), evt.getY());
508 public void mouseReleased(MouseEvent evt)
510 if (evt.isPopupTrigger()) // Windows
512 showPasteMenu(evt.getX(), evt.getY());
516 desktop.addMouseListener(ma);
521 * Answers true if user preferences to enable experimental features is True
526 public boolean showExperimental()
528 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
529 Boolean.FALSE.toString());
530 return Boolean.valueOf(experimental).booleanValue();
533 public void doConfigureStructurePrefs()
535 // configure services
536 StructureSelectionManager ssm = StructureSelectionManager
537 .getStructureSelectionManager(this);
538 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
540 ssm.setAddTempFacAnnot(jalview.bin.Cache
541 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
542 ssm.setProcessSecondaryStructure(jalview.bin.Cache
543 .getDefault(Preferences.STRUCT_FROM_PDB, true));
544 ssm.setSecStructServices(
545 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
549 ssm.setAddTempFacAnnot(false);
550 ssm.setProcessSecondaryStructure(false);
551 ssm.setSecStructServices(false);
555 public void checkForNews()
557 final Desktop me = this;
558 // Thread off the news reader, in case there are connection problems.
559 new Thread(new Runnable()
564 Cache.log.debug("Starting news thread.");
565 jvnews = new BlogReader(me);
566 showNews.setVisible(true);
567 Cache.log.debug("Completed news thread.");
572 public void getIdentifiersOrgData()
574 // Thread off the identifiers fetcher
575 new Thread(new Runnable()
580 Cache.log.debug("Downloading data from identifiers.org");
581 UrlDownloadClient client = new UrlDownloadClient();
584 client.download(IdOrgSettings.getUrl(),
585 IdOrgSettings.getDownloadLocation());
586 } catch (IOException e)
588 Cache.log.debug("Exception downloading identifiers.org data"
597 protected void showNews_actionPerformed(ActionEvent e)
599 showNews(showNews.isSelected());
602 void showNews(boolean visible)
604 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
605 showNews.setSelected(visible);
606 if (visible && !jvnews.isVisible())
608 new Thread(new Runnable()
613 long now = System.currentTimeMillis();
614 Desktop.instance.setProgressBar(
615 MessageManager.getString("status.refreshing_news"), now);
616 jvnews.refreshNews();
617 Desktop.instance.setProgressBar(null, now);
625 * recover the last known dimensions for a jalview window
628 * - empty string is desktop, all other windows have unique prefix
629 * @return null or last known dimensions scaled to current geometry (if last
630 * window geom was known)
632 Rectangle getLastKnownDimensions(String windowName)
634 // TODO: lock aspect ratio for scaling desktop Bug #0058199
635 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
636 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
637 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
638 String width = jalview.bin.Cache
639 .getProperty(windowName + "SCREEN_WIDTH");
640 String height = jalview.bin.Cache
641 .getProperty(windowName + "SCREEN_HEIGHT");
642 if ((x != null) && (y != null) && (width != null) && (height != null))
644 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
645 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
646 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
648 // attempt #1 - try to cope with change in screen geometry - this
649 // version doesn't preserve original jv aspect ratio.
650 // take ratio of current screen size vs original screen size.
651 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
652 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
653 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
654 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
655 // rescale the bounds depending upon the current screen geometry.
656 ix = (int) (ix * sw);
657 iw = (int) (iw * sw);
658 iy = (int) (iy * sh);
659 ih = (int) (ih * sh);
660 while (ix >= screenSize.width)
662 jalview.bin.Cache.log.debug(
663 "Window geometry location recall error: shifting horizontal to within screenbounds.");
664 ix -= screenSize.width;
666 while (iy >= screenSize.height)
668 jalview.bin.Cache.log.debug(
669 "Window geometry location recall error: shifting vertical to within screenbounds.");
670 iy -= screenSize.height;
672 jalview.bin.Cache.log.debug(
673 "Got last known dimensions for " + windowName + ": x:" + ix
674 + " y:" + iy + " width:" + iw + " height:" + ih);
676 // return dimensions for new instance
677 return new Rectangle(ix, iy, iw, ih);
682 private void doVamsasClientCheck()
684 if (Cache.vamsasJarsPresent())
686 setupVamsasDisconnectedGui();
687 VamsasMenu.setVisible(true);
688 final Desktop us = this;
689 VamsasMenu.addMenuListener(new MenuListener()
691 // this listener remembers when the menu was first selected, and
692 // doesn't rebuild the session list until it has been cleared and
694 boolean refresh = true;
697 public void menuCanceled(MenuEvent e)
703 public void menuDeselected(MenuEvent e)
709 public void menuSelected(MenuEvent e)
713 us.buildVamsasStMenu();
718 vamsasStart.setVisible(true);
722 void showPasteMenu(int x, int y)
724 JPopupMenu popup = new JPopupMenu();
725 JMenuItem item = new JMenuItem(
726 MessageManager.getString("label.paste_new_window"));
727 item.addActionListener(new ActionListener()
730 public void actionPerformed(ActionEvent evt)
737 popup.show(this, x, y);
744 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
745 Transferable contents = c.getContents(this);
747 if (contents != null)
749 String file = (String) contents
750 .getTransferData(DataFlavor.stringFlavor);
752 FileFormatI format = new IdentifyFile().identify(file,
753 DataSourceType.PASTE);
755 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
758 } catch (Exception ex)
761 "Unable to paste alignment from system clipboard:\n" + ex);
766 * Adds and opens the given frame to the desktop
777 public static synchronized void addInternalFrame(
778 final JInternalFrame frame, String title, int w, int h)
780 addInternalFrame(frame, title, true, w, h, true, false);
784 * Add an internal frame to the Jalview desktop
791 * When true, display frame immediately, otherwise, caller must call
792 * setVisible themselves.
798 public static synchronized void addInternalFrame(
799 final JInternalFrame frame, String title, boolean makeVisible,
802 addInternalFrame(frame, title, makeVisible, w, h, true, false);
806 * Add an internal frame to the Jalview desktop and make it visible
819 public static synchronized void addInternalFrame(
820 final JInternalFrame frame, String title, int w, int h,
823 addInternalFrame(frame, title, true, w, h, resizable, false);
827 * Add an internal frame to the Jalview desktop
834 * When true, display frame immediately, otherwise, caller must call
835 * setVisible themselves.
842 * @param ignoreMinSize
843 * Do not set the default minimum size for frame
845 public static synchronized void addInternalFrame(
846 final JInternalFrame frame, String title, boolean makeVisible,
847 int w, int h, boolean resizable, boolean ignoreMinSize)
850 // TODO: allow callers to determine X and Y position of frame (eg. via
852 // TODO: consider fixing method to update entries in the window submenu with
853 // the current window title
855 frame.setTitle(title);
856 if (frame.getWidth() < 1 || frame.getHeight() < 1)
860 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
861 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
862 // IF JALVIEW IS RUNNING HEADLESS
863 // ///////////////////////////////////////////////
864 if (instance == null || (System.getProperty("java.awt.headless") != null
865 && System.getProperty("java.awt.headless").equals("true")))
874 frame.setMinimumSize(
875 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
877 // Set default dimension for Alignment Frame window.
878 // The Alignment Frame window could be added from a number of places,
880 // I did this here in order not to miss out on any Alignment frame.
881 if (frame instanceof AlignFrame)
883 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
884 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
888 frame.setVisible(makeVisible);
889 frame.setClosable(true);
890 frame.setResizable(resizable);
891 frame.setMaximizable(resizable);
892 frame.setIconifiable(resizable);
893 frame.setOpaque(Platform.isJS());/// ** @j2sNative true || */false);
895 if (frame.getX() < 1 && frame.getY() < 1)
897 frame.setLocation(xOffset * openFrameCount,
898 yOffset * ((openFrameCount - 1) % 10) + yOffset);
902 * add an entry for the new frame in the Window menu
903 * (and remove it when the frame is closed)
905 final JMenuItem menuItem = new JMenuItem(title);
906 frame.addInternalFrameListener(new InternalFrameAdapter()
909 public void internalFrameActivated(InternalFrameEvent evt)
911 JInternalFrame itf = desktop.getSelectedFrame();
914 if (itf instanceof AlignFrame)
916 Jalview.setCurrentAlignFrame((AlignFrame) itf);
923 public void internalFrameClosed(InternalFrameEvent evt)
925 PaintRefresher.RemoveComponent(frame);
928 * defensive check to prevent frames being
929 * added half off the window
931 if (openFrameCount > 0)
937 * ensure no reference to alignFrame retained by menu item listener
939 if (menuItem.getActionListeners().length > 0)
941 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
943 windowMenu.remove(menuItem);
947 menuItem.addActionListener(new ActionListener()
950 public void actionPerformed(ActionEvent e)
954 frame.setSelected(true);
955 frame.setIcon(false);
956 } catch (java.beans.PropertyVetoException ex)
958 // System.err.println(ex.toString());
963 setKeyBindings(frame);
967 windowMenu.add(menuItem);
972 frame.setSelected(true);
973 frame.requestFocus();
974 } catch (java.beans.PropertyVetoException ve)
976 } catch (java.lang.ClassCastException cex)
979 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
985 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
990 private static void setKeyBindings(JInternalFrame frame)
992 @SuppressWarnings("serial")
993 final Action closeAction = new AbstractAction()
996 public void actionPerformed(ActionEvent e)
1003 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1005 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1006 InputEvent.CTRL_DOWN_MASK);
1007 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1008 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1010 InputMap inputMap = frame
1011 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1012 String ctrlW = ctrlWKey.toString();
1013 inputMap.put(ctrlWKey, ctrlW);
1014 inputMap.put(cmdWKey, ctrlW);
1016 ActionMap actionMap = frame.getActionMap();
1017 actionMap.put(ctrlW, closeAction);
1021 public void lostOwnership(Clipboard clipboard, Transferable contents)
1025 Desktop.jalviewClipboard = null;
1028 internalCopy = false;
1032 public void dragEnter(DropTargetDragEvent evt)
1037 public void dragExit(DropTargetEvent evt)
1042 public void dragOver(DropTargetDragEvent evt)
1047 public void dropActionChanged(DropTargetDragEvent evt)
1058 public void drop(DropTargetDropEvent evt)
1060 boolean success = true;
1061 // JAL-1552 - acceptDrop required before getTransferable call for
1062 // Java's Transferable for native dnd
1063 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1064 Transferable t = evt.getTransferable();
1065 List<Object> files = new ArrayList<>();
1066 List<DataSourceType> protocols = new ArrayList<>();
1070 Desktop.transferFromDropTarget(files, protocols, evt, t);
1071 } catch (Exception e)
1073 e.printStackTrace();
1081 for (int i = 0; i < files.size(); i++)
1083 // BH 2018 File or String
1084 Object file = files.get(i);
1085 String fileName = file.toString();
1086 DataSourceType protocol = (protocols == null)
1087 ? DataSourceType.FILE
1089 FileFormatI format = null;
1091 if (fileName.endsWith(".jar"))
1093 format = FileFormat.Jalview;
1098 format = new IdentifyFile().identify(file, protocol);
1101 new FileLoader().LoadFile(null, file, protocol, format);
1104 } catch (Exception ex)
1109 evt.dropComplete(success); // need this to ensure input focus is properly
1110 // transfered to any new windows created
1120 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1122 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1123 JalviewFileChooser chooser = JalviewFileChooser
1124 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1126 chooser.setFileView(new JalviewFileView());
1127 chooser.setDialogTitle(
1128 MessageManager.getString("label.open_local_file"));
1129 chooser.setToolTipText(MessageManager.getString("action.open"));
1131 chooser.setResponseHandler(0, new Runnable()
1136 File selectedFile = chooser.getSelectedFile();
1137 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1139 FileFormatI format = chooser.getSelectedFormat();
1142 * Call IdentifyFile to verify the file contains what its extension implies.
1143 * Skip this step for dynamically added file formats, because
1144 * IdentifyFile does not know how to recognise them.
1146 if (FileFormats.getInstance().isIdentifiable(format))
1150 format = new IdentifyFile().identify(selectedFile,
1151 DataSourceType.FILE);
1152 } catch (FileFormatException e)
1154 // format = null; //??
1158 new FileLoader().LoadFile(viewport, selectedFile,
1159 DataSourceType.FILE, format);
1162 chooser.showOpenDialog(this);
1166 * Shows a dialog for input of a URL at which to retrieve alignment data
1171 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1173 // This construct allows us to have a wider textfield
1175 JLabel label = new JLabel(
1176 MessageManager.getString("label.input_file_url"));
1178 JPanel panel = new JPanel(new GridLayout(2, 1));
1182 * the URL to fetch is
1183 * Java: an editable combobox with history
1184 * JS: (pending JAL-3038) a plain text field
1187 String urlBase = "http://www.";
1188 if (Platform.isJS())
1190 history = new JTextField(urlBase, 35);
1199 JComboBox<String> asCombo = new JComboBox<>();
1200 asCombo.setPreferredSize(new Dimension(400, 20));
1201 asCombo.setEditable(true);
1202 asCombo.addItem(urlBase);
1203 String historyItems = Cache.getProperty("RECENT_URL");
1204 if (historyItems != null)
1206 for (String token : historyItems.split("\\t"))
1208 asCombo.addItem(token);
1215 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1216 MessageManager.getString("action.cancel") };
1217 Runnable action = new Runnable()
1222 @SuppressWarnings("unchecked")
1223 String url = (history instanceof JTextField
1224 ? ((JTextField) history).getText()
1225 : ((JComboBox<String>) history).getSelectedItem()
1228 if (url.toLowerCase().endsWith(".jar"))
1230 if (viewport != null)
1232 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1233 FileFormat.Jalview);
1237 new FileLoader().LoadFile(url, DataSourceType.URL,
1238 FileFormat.Jalview);
1243 FileFormatI format = null;
1246 format = new IdentifyFile().identify(url, DataSourceType.URL);
1247 } catch (FileFormatException e)
1249 // TODO revise error handling, distinguish between
1250 // URL not found and response not valid
1255 String msg = MessageManager
1256 .formatMessage("label.couldnt_locate", url);
1257 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1258 MessageManager.getString("label.url_not_found"),
1259 JvOptionPane.WARNING_MESSAGE);
1264 if (viewport != null)
1266 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1271 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1276 String dialogOption = MessageManager
1277 .getString("label.input_alignment_from_url");
1278 JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
1279 .showInternalDialog(panel, dialogOption,
1280 JvOptionPane.YES_NO_CANCEL_OPTION,
1281 JvOptionPane.PLAIN_MESSAGE, null, options,
1282 MessageManager.getString("action.ok"));
1286 * Opens the CutAndPaste window for the user to paste an alignment in to
1289 * - if not null, the pasted alignment is added to the current
1290 * alignment; if null, to a new alignment window
1293 public void inputTextboxMenuItem_actionPerformed(
1294 AlignmentViewPanel viewPanel)
1296 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1297 cap.setForInput(viewPanel);
1298 Desktop.addInternalFrame(cap,
1299 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1309 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1310 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1312 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1313 screen.height + "");
1314 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1315 getWidth(), getHeight()));
1317 if (jconsole != null)
1319 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1320 jconsole.stopConsole();
1324 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1327 if (dialogExecutor != null)
1329 dialogExecutor.shutdownNow();
1331 closeAll_actionPerformed(null);
1333 if (groovyConsole != null)
1335 // suppress a possible repeat prompt to save script
1336 groovyConsole.setDirty(false);
1337 groovyConsole.exit();
1342 private void storeLastKnownDimensions(String string, Rectangle jc)
1344 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1345 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1346 + " height:" + jc.height);
1348 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1349 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1350 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1351 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1361 public void aboutMenuItem_actionPerformed(ActionEvent e)
1363 // StringBuffer message = getAboutMessage(false);
1364 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1366 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1367 new Thread(new Runnable()
1372 new SplashScreen(true);
1377 public StringBuffer getAboutMessage(boolean shortv)
1379 StringBuffer message = new StringBuffer();
1380 message.append("<html>");
1383 message.append("<h1><strong>Version: "
1384 + jalview.bin.Cache.getProperty("VERSION")
1385 + "</strong></h1>");
1386 message.append("<strong>Last Updated: <em>"
1387 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1388 + "</em></strong>");
1394 message.append("<strong>Version "
1395 + jalview.bin.Cache.getProperty("VERSION")
1396 + "; last updated: "
1397 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1400 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1401 .equals("Checking"))
1403 message.append("<br>...Checking latest version...</br>");
1405 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1406 .equals(jalview.bin.Cache.getProperty("VERSION")))
1408 boolean red = false;
1409 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1410 .indexOf("automated build") == -1)
1413 // Displayed when code version and jnlp version do not match and code
1414 // version is not a development build
1415 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1418 message.append("<br>!! Version "
1419 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1421 + " is available for download from "
1422 + jalview.bin.Cache.getDefault("www.jalview.org",
1423 "http://www.jalview.org")
1427 message.append("</div>");
1430 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1432 "The Jalview Authors (See AUTHORS file for current list)")
1433 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1434 + "<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"
1435 + "<br><br>If you use Jalview, please cite:"
1436 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1437 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1438 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1444 * Action on requesting Help documentation
1447 public void documentationMenuItem_actionPerformed()
1451 if (Platform.isJS())
1453 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1462 Help.showHelpWindow();
1464 } catch (Exception ex)
1466 System.err.println("Error opening help: " + ex.getMessage());
1471 public void closeAll_actionPerformed(ActionEvent e)
1473 // TODO show a progress bar while closing?
1474 JInternalFrame[] frames = desktop.getAllFrames();
1475 for (int i = 0; i < frames.length; i++)
1479 frames[i].setClosed(true);
1480 } catch (java.beans.PropertyVetoException ex)
1484 Jalview.setCurrentAlignFrame(null);
1485 System.out.println("ALL CLOSED");
1486 if (v_client != null)
1488 // TODO clear binding to vamsas document objects on close_all
1492 * reset state of singleton objects as appropriate (clear down session state
1493 * when all windows are closed)
1495 StructureSelectionManager ssm = StructureSelectionManager
1496 .getStructureSelectionManager(this);
1504 public void raiseRelated_actionPerformed(ActionEvent e)
1506 reorderAssociatedWindows(false, false);
1510 public void minimizeAssociated_actionPerformed(ActionEvent e)
1512 reorderAssociatedWindows(true, false);
1515 void closeAssociatedWindows()
1517 reorderAssociatedWindows(false, true);
1523 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1527 protected void garbageCollect_actionPerformed(ActionEvent e)
1529 // We simply collect the garbage
1530 jalview.bin.Cache.log.debug("Collecting garbage...");
1532 jalview.bin.Cache.log.debug("Finished garbage collection.");
1539 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1543 protected void showMemusage_actionPerformed(ActionEvent e)
1545 desktop.showMemoryUsage(showMemusage.isSelected());
1552 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1556 protected void showConsole_actionPerformed(ActionEvent e)
1558 showConsole(showConsole.isSelected());
1561 Console jconsole = null;
1564 * control whether the java console is visible or not
1568 void showConsole(boolean selected)
1570 // TODO: decide if we should update properties file
1571 if (jconsole != null) // BH 2018
1573 showConsole.setSelected(selected);
1574 Cache.setProperty("SHOW_JAVA_CONSOLE",
1575 Boolean.valueOf(selected).toString());
1576 jconsole.setVisible(selected);
1580 void reorderAssociatedWindows(boolean minimize, boolean close)
1582 JInternalFrame[] frames = desktop.getAllFrames();
1583 if (frames == null || frames.length < 1)
1588 AlignmentViewport source = null, target = null;
1589 if (frames[0] instanceof AlignFrame)
1591 source = ((AlignFrame) frames[0]).getCurrentView();
1593 else if (frames[0] instanceof TreePanel)
1595 source = ((TreePanel) frames[0]).getViewPort();
1597 else if (frames[0] instanceof PCAPanel)
1599 source = ((PCAPanel) frames[0]).av;
1601 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1603 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1608 for (int i = 0; i < frames.length; i++)
1611 if (frames[i] == null)
1615 if (frames[i] instanceof AlignFrame)
1617 target = ((AlignFrame) frames[i]).getCurrentView();
1619 else if (frames[i] instanceof TreePanel)
1621 target = ((TreePanel) frames[i]).getViewPort();
1623 else if (frames[i] instanceof PCAPanel)
1625 target = ((PCAPanel) frames[i]).av;
1627 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1629 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1632 if (source == target)
1638 frames[i].setClosed(true);
1642 frames[i].setIcon(minimize);
1645 frames[i].toFront();
1649 } catch (java.beans.PropertyVetoException ex)
1664 protected void preferences_actionPerformed(ActionEvent e)
1670 * Prompts the user to choose a file and then saves the Jalview state as a
1671 * Jalview project file
1674 public void saveState_actionPerformed()
1676 saveState_actionPerformed(false);
1679 public void saveState_actionPerformed(boolean saveAs)
1681 java.io.File projectFile = getProjectFile();
1682 // autoSave indicates we already have a file and don't need to ask
1683 boolean autoSave = projectFile != null && !saveAs
1684 && BackupFiles.getEnabled();
1686 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1687 // saveAs="+saveAs+", Backups
1688 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1690 boolean approveSave = false;
1693 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1696 chooser.setFileView(new JalviewFileView());
1697 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1699 int value = chooser.showSaveDialog(this);
1701 if (value == JalviewFileChooser.APPROVE_OPTION)
1703 projectFile = chooser.getSelectedFile();
1704 setProjectFile(projectFile);
1709 if (approveSave || autoSave)
1711 final Desktop me = this;
1712 final java.io.File chosenFile = projectFile;
1713 new Thread(new Runnable()
1718 // TODO: refactor to Jalview desktop session controller action.
1719 setProgressBar(MessageManager.formatMessage(
1720 "label.saving_jalview_project", new Object[]
1721 { chosenFile.getName() }), chosenFile.hashCode());
1722 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1723 chosenFile.getParent());
1724 // TODO catch and handle errors for savestate
1725 // TODO prevent user from messing with the Desktop whilst we're saving
1728 boolean doBackup = BackupFiles.getEnabled();
1729 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1731 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1735 backupfiles.setWriteSuccess(true);
1736 backupfiles.rollBackupsAndRenameTempFile();
1738 } catch (OutOfMemoryError oom)
1740 new OOMWarning("Whilst saving current state to "
1741 + chosenFile.getName(), oom);
1742 } catch (Exception ex)
1744 Cache.log.error("Problems whilst trying to save to "
1745 + chosenFile.getName(), ex);
1746 JvOptionPane.showMessageDialog(me,
1747 MessageManager.formatMessage(
1748 "label.error_whilst_saving_current_state_to",
1750 { chosenFile.getName() }),
1751 MessageManager.getString("label.couldnt_save_project"),
1752 JvOptionPane.WARNING_MESSAGE);
1754 setProgressBar(null, chosenFile.hashCode());
1761 public void saveAsState_actionPerformed(ActionEvent e)
1763 saveState_actionPerformed(true);
1766 private void setProjectFile(File choice)
1768 this.projectFile = choice;
1771 public File getProjectFile()
1773 return this.projectFile;
1777 * Shows a file chooser dialog and tries to read in the selected file as a
1781 public void loadState_actionPerformed()
1783 final String[] suffix = new String[] { "jvp", "jar" };
1784 final String[] desc = new String[] { "Jalview Project",
1785 "Jalview Project (old)" };
1786 JalviewFileChooser chooser = new JalviewFileChooser(
1787 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1788 "Jalview Project", true, true); // last two booleans: allFiles,
1790 chooser.setFileView(new JalviewFileView());
1791 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1792 chooser.setResponseHandler(0, new Runnable()
1797 File selectedFile = chooser.getSelectedFile();
1798 setProjectFile(selectedFile);
1799 String choice = selectedFile.getAbsolutePath();
1800 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1801 new Thread(new Runnable()
1808 new Jalview2XML().loadJalviewAlign(choice);
1809 } catch (OutOfMemoryError oom)
1811 new OOMWarning("Whilst loading project from " + choice, oom);
1812 } catch (Exception ex)
1815 "Problems whilst loading project from " + choice, ex);
1816 JvOptionPane.showMessageDialog(Desktop.desktop,
1817 MessageManager.formatMessage(
1818 "label.error_whilst_loading_project_from",
1821 MessageManager.getString("label.couldnt_load_project"),
1822 JvOptionPane.WARNING_MESSAGE);
1829 chooser.showOpenDialog(this);
1833 public void inputSequence_actionPerformed(ActionEvent e)
1835 new SequenceFetcher(this);
1838 JPanel progressPanel;
1840 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1842 public void startLoading(final Object fileName)
1844 if (fileLoadingCount == 0)
1846 fileLoadingPanels.add(addProgressPanel(MessageManager
1847 .formatMessage("label.loading_file", new Object[]
1853 private JPanel addProgressPanel(String string)
1855 if (progressPanel == null)
1857 progressPanel = new JPanel(new GridLayout(1, 1));
1858 totalProgressCount = 0;
1859 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1861 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1862 JProgressBar progressBar = new JProgressBar();
1863 progressBar.setIndeterminate(true);
1865 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1867 thisprogress.add(progressBar, BorderLayout.CENTER);
1868 progressPanel.add(thisprogress);
1869 ((GridLayout) progressPanel.getLayout()).setRows(
1870 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1871 ++totalProgressCount;
1872 instance.validate();
1873 return thisprogress;
1876 int totalProgressCount = 0;
1878 private void removeProgressPanel(JPanel progbar)
1880 if (progressPanel != null)
1882 synchronized (progressPanel)
1884 progressPanel.remove(progbar);
1885 GridLayout gl = (GridLayout) progressPanel.getLayout();
1886 gl.setRows(gl.getRows() - 1);
1887 if (--totalProgressCount < 1)
1889 this.getContentPane().remove(progressPanel);
1890 progressPanel = null;
1897 public void stopLoading()
1900 if (fileLoadingCount < 1)
1902 while (fileLoadingPanels.size() > 0)
1904 removeProgressPanel(fileLoadingPanels.remove(0));
1906 fileLoadingPanels.clear();
1907 fileLoadingCount = 0;
1912 public static int getViewCount(String alignmentId)
1914 AlignmentViewport[] aps = getViewports(alignmentId);
1915 return (aps == null) ? 0 : aps.length;
1920 * @param alignmentId
1921 * - if null, all sets are returned
1922 * @return all AlignmentPanels concerning the alignmentId sequence set
1924 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1926 if (Desktop.desktop == null)
1928 // no frames created and in headless mode
1929 // TODO: verify that frames are recoverable when in headless mode
1932 List<AlignmentPanel> aps = new ArrayList<>();
1933 AlignFrame[] frames = getAlignFrames();
1938 for (AlignFrame af : frames)
1940 for (AlignmentPanel ap : af.alignPanels)
1942 if (alignmentId == null
1943 || alignmentId.equals(ap.av.getSequenceSetId()))
1949 if (aps.size() == 0)
1953 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1958 * get all the viewports on an alignment.
1960 * @param sequenceSetId
1961 * unique alignment id (may be null - all viewports returned in that
1963 * @return all viewports on the alignment bound to sequenceSetId
1965 public static AlignmentViewport[] getViewports(String sequenceSetId)
1967 List<AlignmentViewport> viewp = new ArrayList<>();
1968 if (desktop != null)
1970 AlignFrame[] frames = Desktop.getAlignFrames();
1972 for (AlignFrame afr : frames)
1974 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1975 .equals(sequenceSetId))
1977 if (afr.alignPanels != null)
1979 for (AlignmentPanel ap : afr.alignPanels)
1981 if (sequenceSetId == null
1982 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1990 viewp.add(afr.getViewport());
1994 if (viewp.size() > 0)
1996 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2003 * Explode the views in the given frame into separate AlignFrame
2007 public static void explodeViews(AlignFrame af)
2009 int size = af.alignPanels.size();
2015 for (int i = 0; i < size; i++)
2017 AlignmentPanel ap = af.alignPanels.get(i);
2018 AlignFrame newaf = new AlignFrame(ap);
2021 * Restore the view's last exploded frame geometry if known. Multiple
2022 * views from one exploded frame share and restore the same (frame)
2023 * position and size.
2025 Rectangle geometry = ap.av.getExplodedGeometry();
2026 if (geometry != null)
2028 newaf.setBounds(geometry);
2031 ap.av.setGatherViewsHere(false);
2033 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2034 AlignFrame.DEFAULT_HEIGHT);
2037 af.alignPanels.clear();
2038 af.closeMenuItem_actionPerformed(true);
2043 * Gather expanded views (separate AlignFrame's) with the same sequence set
2044 * identifier back in to this frame as additional views, and close the expanded
2045 * views. Note the expanded frames may themselves have multiple views. We take
2050 public void gatherViews(AlignFrame source)
2052 source.viewport.setGatherViewsHere(true);
2053 source.viewport.setExplodedGeometry(source.getBounds());
2054 JInternalFrame[] frames = desktop.getAllFrames();
2055 String viewId = source.viewport.getSequenceSetId();
2057 for (int t = 0; t < frames.length; t++)
2059 if (frames[t] instanceof AlignFrame && frames[t] != source)
2061 AlignFrame af = (AlignFrame) frames[t];
2062 boolean gatherThis = false;
2063 for (int a = 0; a < af.alignPanels.size(); a++)
2065 AlignmentPanel ap = af.alignPanels.get(a);
2066 if (viewId.equals(ap.av.getSequenceSetId()))
2069 ap.av.setGatherViewsHere(false);
2070 ap.av.setExplodedGeometry(af.getBounds());
2071 source.addAlignmentPanel(ap, false);
2077 af.alignPanels.clear();
2078 af.closeMenuItem_actionPerformed(true);
2085 jalview.gui.VamsasApplication v_client = null;
2088 public void vamsasImport_actionPerformed(ActionEvent e)
2090 // TODO: JAL-3048 not needed for Jalview-JS
2092 if (v_client == null)
2094 // Load and try to start a session.
2095 JalviewFileChooser chooser = new JalviewFileChooser(
2096 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2098 chooser.setFileView(new JalviewFileView());
2099 chooser.setDialogTitle(
2100 MessageManager.getString("label.open_saved_vamsas_session"));
2101 chooser.setToolTipText(MessageManager.getString(
2102 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2104 int value = chooser.showOpenDialog(this);
2106 if (value == JalviewFileChooser.APPROVE_OPTION)
2108 String fle = chooser.getSelectedFile().toString();
2109 if (!vamsasImport(chooser.getSelectedFile()))
2111 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2112 MessageManager.formatMessage(
2113 "label.couldnt_import_as_vamsas_session",
2117 .getString("label.vamsas_document_import_failed"),
2118 JvOptionPane.ERROR_MESSAGE);
2124 jalview.bin.Cache.log.error(
2125 "Implementation error - load session from a running session is not supported.");
2130 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2133 * @return true if import was a success and a session was started.
2135 public boolean vamsasImport(URL url)
2137 // TODO: create progress bar
2138 if (v_client != null)
2141 jalview.bin.Cache.log.error(
2142 "Implementation error - load session from a running session is not supported.");
2148 // copy the URL content to a temporary local file
2149 // TODO: be a bit cleverer here with nio (?!)
2150 File file = File.createTempFile("vdocfromurl", ".vdj");
2151 FileOutputStream fos = new FileOutputStream(file);
2152 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2153 byte[] buffer = new byte[2048];
2155 while ((ln = bis.read(buffer)) > -1)
2157 fos.write(buffer, 0, ln);
2161 v_client = new jalview.gui.VamsasApplication(this, file,
2162 url.toExternalForm());
2163 } catch (Exception ex)
2165 jalview.bin.Cache.log.error(
2166 "Failed to create new vamsas session from contents of URL "
2171 setupVamsasConnectedGui();
2172 v_client.initial_update(); // TODO: thread ?
2173 return v_client.inSession();
2177 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2180 * @return true if import was a success and a session was started.
2182 public boolean vamsasImport(File file)
2184 if (v_client != null)
2187 jalview.bin.Cache.log.error(
2188 "Implementation error - load session from a running session is not supported.");
2192 setProgressBar(MessageManager.formatMessage(
2193 "status.importing_vamsas_session_from", new Object[]
2194 { file.getName() }), file.hashCode());
2197 v_client = new jalview.gui.VamsasApplication(this, file, null);
2198 } catch (Exception ex)
2200 setProgressBar(MessageManager.formatMessage(
2201 "status.importing_vamsas_session_from", new Object[]
2202 { file.getName() }), file.hashCode());
2203 jalview.bin.Cache.log.error(
2204 "New vamsas session from existing session file failed:", ex);
2207 setupVamsasConnectedGui();
2208 v_client.initial_update(); // TODO: thread ?
2209 setProgressBar(MessageManager.formatMessage(
2210 "status.importing_vamsas_session_from", new Object[]
2211 { file.getName() }), file.hashCode());
2212 return v_client.inSession();
2215 public boolean joinVamsasSession(String mysesid)
2217 if (v_client != null)
2219 throw new Error(MessageManager
2220 .getString("error.try_join_vamsas_session_another"));
2222 if (mysesid == null)
2225 MessageManager.getString("error.invalid_vamsas_session_id"));
2227 v_client = new VamsasApplication(this, mysesid);
2228 setupVamsasConnectedGui();
2229 v_client.initial_update();
2230 return (v_client.inSession());
2234 public void vamsasStart_actionPerformed(ActionEvent e)
2236 if (v_client == null)
2239 // we just start a default session for moment.
2241 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2242 * getProperty("LAST_DIRECTORY"));
2244 * chooser.setFileView(new JalviewFileView());
2245 * chooser.setDialogTitle("Load Vamsas file");
2246 * chooser.setToolTipText("Import");
2248 * int value = chooser.showOpenDialog(this);
2250 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2251 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2253 v_client = new VamsasApplication(this);
2254 setupVamsasConnectedGui();
2255 v_client.initial_update(); // TODO: thread ?
2259 // store current data in session.
2260 v_client.push_update(); // TODO: thread
2264 protected void setupVamsasConnectedGui()
2266 vamsasStart.setText(MessageManager.getString("label.session_update"));
2267 vamsasSave.setVisible(true);
2268 vamsasStop.setVisible(true);
2269 vamsasImport.setVisible(false); // Document import to existing session is
2270 // not possible for vamsas-client-1.0.
2273 protected void setupVamsasDisconnectedGui()
2275 vamsasSave.setVisible(false);
2276 vamsasStop.setVisible(false);
2277 vamsasImport.setVisible(true);
2279 .setText(MessageManager.getString("label.new_vamsas_session"));
2283 public void vamsasStop_actionPerformed(ActionEvent e)
2285 if (v_client != null)
2287 v_client.end_session();
2289 setupVamsasDisconnectedGui();
2293 protected void buildVamsasStMenu()
2295 if (v_client == null)
2297 String[] sess = null;
2300 sess = VamsasApplication.getSessionList();
2301 } catch (Exception e)
2303 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2309 jalview.bin.Cache.log.debug(
2310 "Got current sessions list: " + sess.length + " entries.");
2311 VamsasStMenu.removeAll();
2312 for (int i = 0; i < sess.length; i++)
2314 JMenuItem sessit = new JMenuItem();
2315 sessit.setText(sess[i]);
2316 sessit.setToolTipText(MessageManager
2317 .formatMessage("label.connect_to_session", new Object[]
2319 final Desktop dsktp = this;
2320 final String mysesid = sess[i];
2321 sessit.addActionListener(new ActionListener()
2325 public void actionPerformed(ActionEvent e)
2327 if (dsktp.v_client == null)
2329 Thread rthr = new Thread(new Runnable()
2335 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2336 dsktp.setupVamsasConnectedGui();
2337 dsktp.v_client.initial_update();
2345 VamsasStMenu.add(sessit);
2347 // don't show an empty menu.
2348 VamsasStMenu.setVisible(sess.length > 0);
2353 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2354 VamsasStMenu.removeAll();
2355 VamsasStMenu.setVisible(false);
2360 // Not interested in the content. Just hide ourselves.
2361 VamsasStMenu.setVisible(false);
2366 public void vamsasSave_actionPerformed(ActionEvent e)
2368 // TODO: JAL-3048 not needed for Jalview-JS
2370 if (v_client != null)
2372 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2373 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2376 chooser.setFileView(new JalviewFileView());
2377 chooser.setDialogTitle(MessageManager
2378 .getString("label.save_vamsas_document_archive"));
2380 int value = chooser.showSaveDialog(this);
2382 if (value == JalviewFileChooser.APPROVE_OPTION)
2384 java.io.File choice = chooser.getSelectedFile();
2385 JPanel progpanel = addProgressPanel(MessageManager
2386 .formatMessage("label.saving_vamsas_doc", new Object[]
2387 { choice.getName() }));
2388 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2389 String warnmsg = null;
2390 String warnttl = null;
2393 v_client.vclient.storeDocument(choice);
2396 warnttl = "Serious Problem saving Vamsas Document";
2397 warnmsg = ex.toString();
2398 jalview.bin.Cache.log
2399 .error("Error Whilst saving document to " + choice, ex);
2401 } catch (Exception ex)
2403 warnttl = "Problem saving Vamsas Document.";
2404 warnmsg = ex.toString();
2405 jalview.bin.Cache.log.warn(
2406 "Exception Whilst saving document to " + choice, ex);
2409 removeProgressPanel(progpanel);
2410 if (warnmsg != null)
2412 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2414 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2420 JPanel vamUpdate = null;
2423 * hide vamsas user gui bits when a vamsas document event is being handled.
2426 * true to hide gui, false to reveal gui
2428 public void setVamsasUpdate(boolean b)
2430 Cache.log.debug("Setting gui for Vamsas update "
2431 + (b ? "in progress" : "finished"));
2433 if (vamUpdate != null)
2435 this.removeProgressPanel(vamUpdate);
2439 vamUpdate = this.addProgressPanel(
2440 MessageManager.getString("label.updating_vamsas_session"));
2442 vamsasStart.setVisible(!b);
2443 vamsasStop.setVisible(!b);
2444 vamsasSave.setVisible(!b);
2447 public JInternalFrame[] getAllFrames()
2449 return desktop.getAllFrames();
2453 * Checks the given url to see if it gives a response indicating that the user
2454 * should be informed of a new questionnaire.
2458 public void checkForQuestionnaire(String url)
2460 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2461 // javax.swing.SwingUtilities.invokeLater(jvq);
2462 new Thread(jvq).start();
2465 public void checkURLLinks()
2467 // Thread off the URL link checker
2468 addDialogThread(new Runnable()
2473 if (Cache.getDefault("CHECKURLLINKS", true))
2475 // check what the actual links are - if it's just the default don't
2476 // bother with the warning
2477 List<String> links = Preferences.sequenceUrlLinks
2480 // only need to check links if there is one with a
2481 // SEQUENCE_ID which is not the default EMBL_EBI link
2482 ListIterator<String> li = links.listIterator();
2483 boolean check = false;
2484 List<JLabel> urls = new ArrayList<>();
2485 while (li.hasNext())
2487 String link = li.next();
2488 if (link.contains(SEQUENCE_ID)
2489 && !UrlConstants.isDefaultString(link))
2492 int barPos = link.indexOf("|");
2493 String urlMsg = barPos == -1 ? link
2494 : link.substring(0, barPos) + ": "
2495 + link.substring(barPos + 1);
2496 urls.add(new JLabel(urlMsg));
2504 // ask user to check in case URL links use old style tokens
2505 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2506 JPanel msgPanel = new JPanel();
2507 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2508 msgPanel.add(Box.createVerticalGlue());
2509 JLabel msg = new JLabel(MessageManager
2510 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2511 JLabel msg2 = new JLabel(MessageManager
2512 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2514 for (JLabel url : urls)
2520 final JCheckBox jcb = new JCheckBox(
2521 MessageManager.getString("label.do_not_display_again"));
2522 jcb.addActionListener(new ActionListener()
2525 public void actionPerformed(ActionEvent e)
2527 // update Cache settings for "don't show this again"
2528 boolean showWarningAgain = !jcb.isSelected();
2529 Cache.setProperty("CHECKURLLINKS",
2530 Boolean.valueOf(showWarningAgain).toString());
2535 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2537 .getString("label.SEQUENCE_ID_no_longer_used"),
2538 JvOptionPane.WARNING_MESSAGE);
2545 * Proxy class for JDesktopPane which optionally displays the current memory
2546 * usage and highlights the desktop area with a red bar if free memory runs low.
2550 public class MyDesktopPane extends JDesktopPane
2553 private static final float ONE_MB = 1048576f;
2555 boolean showMemoryUsage = false;
2559 java.text.NumberFormat df;
2561 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2564 public MyDesktopPane(boolean showMemoryUsage)
2566 showMemoryUsage(showMemoryUsage);
2569 public void showMemoryUsage(boolean showMemory)
2571 this.showMemoryUsage = showMemory;
2574 Thread worker = new Thread(this);
2580 public boolean isShowMemoryUsage()
2582 return showMemoryUsage;
2588 df = java.text.NumberFormat.getNumberInstance();
2589 df.setMaximumFractionDigits(2);
2590 runtime = Runtime.getRuntime();
2592 while (showMemoryUsage)
2596 maxMemory = runtime.maxMemory() / ONE_MB;
2597 allocatedMemory = runtime.totalMemory() / ONE_MB;
2598 freeMemory = runtime.freeMemory() / ONE_MB;
2599 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2601 percentUsage = (totalFreeMemory / maxMemory) * 100;
2603 // if (percentUsage < 20)
2605 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2607 // instance.set.setBorder(border1);
2610 // sleep after showing usage
2612 } catch (Exception ex)
2614 ex.printStackTrace();
2620 public void paintComponent(Graphics g)
2622 if (showMemoryUsage && g != null && df != null)
2624 if (percentUsage < 20)
2626 g.setColor(Color.red);
2628 FontMetrics fm = g.getFontMetrics();
2631 g.drawString(MessageManager.formatMessage("label.memory_stats",
2633 { df.format(totalFreeMemory), df.format(maxMemory),
2634 df.format(percentUsage) }),
2635 10, getHeight() - fm.getHeight());
2642 * Accessor method to quickly get all the AlignmentFrames loaded.
2644 * @return an array of AlignFrame, or null if none found
2646 public static AlignFrame[] getAlignFrames()
2648 if (Jalview.isHeadlessMode())
2650 // Desktop.desktop is null in headless mode
2651 return new AlignFrame[] { Jalview.currentAlignFrame };
2654 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2660 List<AlignFrame> avp = new ArrayList<>();
2662 for (int i = frames.length - 1; i > -1; i--)
2664 if (frames[i] instanceof AlignFrame)
2666 avp.add((AlignFrame) frames[i]);
2668 else if (frames[i] instanceof SplitFrame)
2671 * Also check for a split frame containing an AlignFrame
2673 GSplitFrame sf = (GSplitFrame) frames[i];
2674 if (sf.getTopFrame() instanceof AlignFrame)
2676 avp.add((AlignFrame) sf.getTopFrame());
2678 if (sf.getBottomFrame() instanceof AlignFrame)
2680 avp.add((AlignFrame) sf.getBottomFrame());
2684 if (avp.size() == 0)
2688 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2693 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2697 public GStructureViewer[] getJmols()
2699 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2705 List<GStructureViewer> avp = new ArrayList<>();
2707 for (int i = frames.length - 1; i > -1; i--)
2709 if (frames[i] instanceof AppJmol)
2711 GStructureViewer af = (GStructureViewer) frames[i];
2715 if (avp.size() == 0)
2719 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2724 * Add Groovy Support to Jalview
2727 public void groovyShell_actionPerformed()
2731 openGroovyConsole();
2732 } catch (Exception ex)
2734 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2735 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2737 MessageManager.getString("label.couldnt_create_groovy_shell"),
2738 MessageManager.getString("label.groovy_support_failed"),
2739 JvOptionPane.ERROR_MESSAGE);
2744 * Open the Groovy console
2746 void openGroovyConsole()
2748 if (groovyConsole == null)
2750 groovyConsole = new groovy.ui.Console();
2751 groovyConsole.setVariable("Jalview", this);
2752 groovyConsole.run();
2755 * We allow only one console at a time, so that AlignFrame menu option
2756 * 'Calculate | Run Groovy script' is unambiguous.
2757 * Disable 'Groovy Console', and enable 'Run script', when the console is
2758 * opened, and the reverse when it is closed
2760 Window window = (Window) groovyConsole.getFrame();
2761 window.addWindowListener(new WindowAdapter()
2764 public void windowClosed(WindowEvent e)
2767 * rebind CMD-Q from Groovy Console to Jalview Quit
2770 enableExecuteGroovy(false);
2776 * show Groovy console window (after close and reopen)
2778 ((Window) groovyConsole.getFrame()).setVisible(true);
2781 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2782 * and disable opening a second console
2784 enableExecuteGroovy(true);
2788 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2791 protected void addQuitHandler()
2793 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2794 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2795 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2797 getRootPane().getActionMap().put("Quit", new AbstractAction()
2800 public void actionPerformed(ActionEvent e)
2808 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2811 * true if Groovy console is open
2813 public void enableExecuteGroovy(boolean enabled)
2816 * disable opening a second Groovy console
2817 * (or re-enable when the console is closed)
2819 groovyShell.setEnabled(!enabled);
2821 AlignFrame[] alignFrames = getAlignFrames();
2822 if (alignFrames != null)
2824 for (AlignFrame af : alignFrames)
2826 af.setGroovyEnabled(enabled);
2832 * Progress bars managed by the IProgressIndicator method.
2834 private Hashtable<Long, JPanel> progressBars;
2836 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2841 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2844 public void setProgressBar(String message, long id)
2846 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2848 if (progressBars == null)
2850 progressBars = new Hashtable<>();
2851 progressBarHandlers = new Hashtable<>();
2854 if (progressBars.get(new Long(id)) != null)
2856 JPanel panel = progressBars.remove(new Long(id));
2857 if (progressBarHandlers.contains(new Long(id)))
2859 progressBarHandlers.remove(new Long(id));
2861 removeProgressPanel(panel);
2865 progressBars.put(new Long(id), addProgressPanel(message));
2872 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2873 * jalview.gui.IProgressIndicatorHandler)
2876 public void registerHandler(final long id,
2877 final IProgressIndicatorHandler handler)
2879 if (progressBarHandlers == null
2880 || !progressBars.containsKey(new Long(id)))
2882 throw new Error(MessageManager.getString(
2883 "error.call_setprogressbar_before_registering_handler"));
2885 progressBarHandlers.put(new Long(id), handler);
2886 final JPanel progressPanel = progressBars.get(new Long(id));
2887 if (handler.canCancel())
2889 JButton cancel = new JButton(
2890 MessageManager.getString("action.cancel"));
2891 final IProgressIndicator us = this;
2892 cancel.addActionListener(new ActionListener()
2896 public void actionPerformed(ActionEvent e)
2898 handler.cancelActivity(id);
2899 us.setProgressBar(MessageManager
2900 .formatMessage("label.cancelled_params", new Object[]
2901 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2905 progressPanel.add(cancel, BorderLayout.EAST);
2911 * @return true if any progress bars are still active
2914 public boolean operationInProgress()
2916 if (progressBars != null && progressBars.size() > 0)
2924 * This will return the first AlignFrame holding the given viewport instance. It
2925 * will break if there are more than one AlignFrames viewing a particular av.
2928 * @return alignFrame for viewport
2930 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2932 if (desktop != null)
2934 AlignmentPanel[] aps = getAlignmentPanels(
2935 viewport.getSequenceSetId());
2936 for (int panel = 0; aps != null && panel < aps.length; panel++)
2938 if (aps[panel] != null && aps[panel].av == viewport)
2940 return aps[panel].alignFrame;
2947 public VamsasApplication getVamsasApplication()
2954 * flag set if jalview GUI is being operated programmatically
2956 private boolean inBatchMode = false;
2959 * check if jalview GUI is being operated programmatically
2961 * @return inBatchMode
2963 public boolean isInBatchMode()
2969 * set flag if jalview GUI is being operated programmatically
2971 * @param inBatchMode
2973 public void setInBatchMode(boolean inBatchMode)
2975 this.inBatchMode = inBatchMode;
2978 public void startServiceDiscovery()
2980 startServiceDiscovery(false);
2983 public void startServiceDiscovery(boolean blocking)
2985 boolean alive = true;
2986 Thread t0 = null, t1 = null, t2 = null;
2987 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2990 // todo: changesupport handlers need to be transferred
2991 if (discoverer == null)
2993 discoverer = new jalview.ws.jws1.Discoverer();
2994 // register PCS handler for desktop.
2995 discoverer.addPropertyChangeListener(changeSupport);
2997 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2998 // until we phase out completely
2999 (t0 = new Thread(discoverer)).start();
3002 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3004 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3005 .startDiscoverer(changeSupport);
3009 // TODO: do rest service discovery
3018 } catch (Exception e)
3021 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3022 || (t3 != null && t3.isAlive())
3023 || (t0 != null && t0.isAlive());
3029 * called to check if the service discovery process completed successfully.
3033 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3035 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3037 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3038 .getErrorMessages();
3041 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3043 if (serviceChangedDialog == null)
3045 // only run if we aren't already displaying one of these.
3046 addDialogThread(serviceChangedDialog = new Runnable()
3053 * JalviewDialog jd =new JalviewDialog() {
3055 * @Override protected void cancelPressed() { // TODO
3056 * Auto-generated method stub
3058 * }@Override protected void okPressed() { // TODO
3059 * Auto-generated method stub
3061 * }@Override protected void raiseClosed() { // TODO
3062 * Auto-generated method stub
3064 * } }; jd.initDialogFrame(new
3065 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3066 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3067 * + " or mis-configured HTTP proxy settings.<br/>" +
3068 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3070 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3071 * ), true, true, "Web Service Configuration Problem", 450,
3074 * jd.waitForInput();
3076 JvOptionPane.showConfirmDialog(Desktop.desktop,
3077 new JLabel("<html><table width=\"450\"><tr><td>"
3078 + ermsg + "</td></tr></table>"
3079 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3080 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3081 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3082 + " Tools->Preferences dialog box to change them.</p></html>"),
3083 "Web Service Configuration Problem",
3084 JvOptionPane.DEFAULT_OPTION,
3085 JvOptionPane.ERROR_MESSAGE);
3086 serviceChangedDialog = null;
3095 "Errors reported by JABA discovery service. Check web services preferences.\n"
3102 private Runnable serviceChangedDialog = null;
3105 * start a thread to open a URL in the configured browser. Pops up a warning
3106 * dialog to the user if there is an exception when calling out to the browser
3111 public static void showUrl(final String url)
3113 showUrl(url, Desktop.instance);
3117 * Like showUrl but allows progress handler to be specified
3121 * (null) or object implementing IProgressIndicator
3123 public static void showUrl(final String url,
3124 final IProgressIndicator progress)
3126 new Thread(new Runnable()
3133 if (progress != null)
3135 progress.setProgressBar(MessageManager
3136 .formatMessage("status.opening_params", new Object[]
3137 { url }), this.hashCode());
3139 jalview.util.BrowserLauncher.openURL(url);
3140 } catch (Exception ex)
3142 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3144 .getString("label.web_browser_not_found_unix"),
3145 MessageManager.getString("label.web_browser_not_found"),
3146 JvOptionPane.WARNING_MESSAGE);
3148 ex.printStackTrace();
3150 if (progress != null)
3152 progress.setProgressBar(null, this.hashCode());
3158 public static WsParamSetManager wsparamManager = null;
3160 public static ParamManager getUserParameterStore()
3162 if (wsparamManager == null)
3164 wsparamManager = new WsParamSetManager();
3166 return wsparamManager;
3170 * static hyperlink handler proxy method for use by Jalview's internal windows
3174 public static void hyperlinkUpdate(HyperlinkEvent e)
3176 if (e.getEventType() == EventType.ACTIVATED)
3181 url = e.getURL().toString();
3182 Desktop.showUrl(url);
3183 } catch (Exception x)
3187 if (Cache.log != null)
3189 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3194 "Couldn't handle string " + url + " as a URL.");
3197 // ignore any exceptions due to dud links.
3204 * single thread that handles display of dialogs to user.
3206 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3209 * flag indicating if dialogExecutor should try to acquire a permit
3211 private volatile boolean dialogPause = true;
3216 private java.util.concurrent.Semaphore block = new Semaphore(0);
3218 private static groovy.ui.Console groovyConsole;
3221 * add another dialog thread to the queue
3225 public void addDialogThread(final Runnable prompter)
3227 dialogExecutor.submit(new Runnable()
3237 } catch (InterruptedException x)
3242 if (instance == null)
3248 SwingUtilities.invokeAndWait(prompter);
3249 } catch (Exception q)
3251 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3257 public void startDialogQueue()
3259 // set the flag so we don't pause waiting for another permit and semaphore
3260 // the current task to begin
3261 dialogPause = false;
3266 * Outputs an image of the desktop to file in EPS format, after prompting the
3267 * user for choice of Text or Lineart character rendering (unless a preference
3268 * has been set). The file name is generated as
3271 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3275 protected void snapShotWindow_actionPerformed(ActionEvent e)
3277 // currently the menu option to do this is not shown
3280 int width = getWidth();
3281 int height = getHeight();
3283 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3284 ImageWriterI writer = new ImageWriterI()
3287 public void exportImage(Graphics g) throws Exception
3290 Cache.log.info("Successfully written snapshot to file "
3291 + of.getAbsolutePath());
3294 String title = "View of desktop";
3295 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3297 exporter.doExport(of, this, width, height, title);
3301 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3302 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3303 * location last time the view was expanded (if any). However it does not
3304 * remember the split pane divider location - this is set to match the
3305 * 'exploding' frame.
3309 public void explodeViews(SplitFrame sf)
3311 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3312 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3313 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3315 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3317 int viewCount = topPanels.size();
3324 * Processing in reverse order works, forwards order leaves the first panels
3325 * not visible. I don't know why!
3327 for (int i = viewCount - 1; i >= 0; i--)
3330 * Make new top and bottom frames. These take over the respective
3331 * AlignmentPanel objects, including their AlignmentViewports, so the
3332 * cdna/protein relationships between the viewports is carried over to the
3335 * explodedGeometry holds the (x, y) position of the previously exploded
3336 * SplitFrame, and the (width, height) of the AlignFrame component
3338 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3339 AlignFrame newTopFrame = new AlignFrame(topPanel);
3340 newTopFrame.setSize(oldTopFrame.getSize());
3341 newTopFrame.setVisible(true);
3342 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3343 .getExplodedGeometry();
3344 if (geometry != null)
3346 newTopFrame.setSize(geometry.getSize());
3349 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3350 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3351 newBottomFrame.setSize(oldBottomFrame.getSize());
3352 newBottomFrame.setVisible(true);
3353 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3354 .getExplodedGeometry();
3355 if (geometry != null)
3357 newBottomFrame.setSize(geometry.getSize());
3360 topPanel.av.setGatherViewsHere(false);
3361 bottomPanel.av.setGatherViewsHere(false);
3362 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3364 if (geometry != null)
3366 splitFrame.setLocation(geometry.getLocation());
3368 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3372 * Clear references to the panels (now relocated in the new SplitFrames)
3373 * before closing the old SplitFrame.
3376 bottomPanels.clear();
3381 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3382 * back into the given SplitFrame as additional views. Note that the gathered
3383 * frames may themselves have multiple views.
3387 public void gatherViews(GSplitFrame source)
3390 * special handling of explodedGeometry for a view within a SplitFrame: - it
3391 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3392 * height) of the AlignFrame component
3394 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3395 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3396 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3397 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3398 myBottomFrame.viewport
3399 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3400 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3401 myTopFrame.viewport.setGatherViewsHere(true);
3402 myBottomFrame.viewport.setGatherViewsHere(true);
3403 String topViewId = myTopFrame.viewport.getSequenceSetId();
3404 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3406 JInternalFrame[] frames = desktop.getAllFrames();
3407 for (JInternalFrame frame : frames)
3409 if (frame instanceof SplitFrame && frame != source)
3411 SplitFrame sf = (SplitFrame) frame;
3412 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3413 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3414 boolean gatherThis = false;
3415 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3417 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3418 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3419 if (topViewId.equals(topPanel.av.getSequenceSetId())
3420 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3423 topPanel.av.setGatherViewsHere(false);
3424 bottomPanel.av.setGatherViewsHere(false);
3425 topPanel.av.setExplodedGeometry(
3426 new Rectangle(sf.getLocation(), topFrame.getSize()));
3427 bottomPanel.av.setExplodedGeometry(
3428 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3429 myTopFrame.addAlignmentPanel(topPanel, false);
3430 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3436 topFrame.getAlignPanels().clear();
3437 bottomFrame.getAlignPanels().clear();
3444 * The dust settles...give focus to the tab we did this from.
3446 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3449 public static groovy.ui.Console getGroovyConsole()
3451 return groovyConsole;
3455 * handles the payload of a drag and drop event.
3457 * TODO refactor to desktop utilities class
3460 * - Data source strings extracted from the drop event
3462 * - protocol for each data source extracted from the drop event
3466 * - the payload from the drop event
3469 public static void transferFromDropTarget(List<Object> files,
3470 List<DataSourceType> protocols, DropTargetDropEvent evt,
3471 Transferable t) throws Exception
3474 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3476 // DataFlavor[] flavors = t.getTransferDataFlavors();
3477 // for (int i = 0; i < flavors.length; i++) {
3478 // if (flavors[i].isFlavorJavaFileListType()) {
3479 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3480 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3481 // for (int j = 0; j < list.size(); j++) {
3482 // File file = (File) list.get(j);
3483 // byte[] data = getDroppedFileBytes(file);
3484 // fileName.setText(file.getName() + " - " + data.length + " " +
3485 // evt.getLocation());
3486 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3487 // target.setText(new String(data));
3489 // dtde.dropComplete(true);
3494 DataFlavor uriListFlavor = new DataFlavor(
3495 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3498 urlFlavour = new DataFlavor(
3499 "application/x-java-url; class=java.net.URL");
3500 } catch (ClassNotFoundException cfe)
3502 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3505 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3510 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3511 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3512 // means url may be null.
3515 protocols.add(DataSourceType.URL);
3516 files.add(url.toString());
3517 Cache.log.debug("Drop handled as URL dataflavor "
3518 + files.get(files.size() - 1));
3523 if (Platform.isAMacAndNotJS())
3526 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3530 } catch (Throwable ex)
3532 Cache.log.debug("URL drop handler failed.", ex);
3535 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3537 // Works on Windows and MacOSX
3538 Cache.log.debug("Drop handled as javaFileListFlavor");
3539 for (Object file : (List) t
3540 .getTransferData(DataFlavor.javaFileListFlavor))
3543 protocols.add(DataSourceType.FILE);
3548 // Unix like behaviour
3549 boolean added = false;
3551 if (t.isDataFlavorSupported(uriListFlavor))
3553 Cache.log.debug("Drop handled as uriListFlavor");
3554 // This is used by Unix drag system
3555 data = (String) t.getTransferData(uriListFlavor);
3559 // fallback to text: workaround - on OSX where there's a JVM bug
3560 Cache.log.debug("standard URIListFlavor failed. Trying text");
3561 // try text fallback
3562 DataFlavor textDf = new DataFlavor(
3563 "text/plain;class=java.lang.String");
3564 if (t.isDataFlavorSupported(textDf))
3566 data = (String) t.getTransferData(textDf);
3569 Cache.log.debug("Plain text drop content returned "
3570 + (data == null ? "Null - failed" : data));
3575 while (protocols.size() < files.size())
3577 Cache.log.debug("Adding missing FILE protocol for "
3578 + files.get(protocols.size()));
3579 protocols.add(DataSourceType.FILE);
3581 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3582 data, "\r\n"); st.hasMoreTokens();)
3585 String s = st.nextToken();
3586 if (s.startsWith("#"))
3588 // the line is a comment (as per the RFC 2483)
3591 java.net.URI uri = new java.net.URI(s);
3592 if (uri.getScheme().toLowerCase().startsWith("http"))
3594 protocols.add(DataSourceType.URL);
3595 files.add(uri.toString());
3599 // otherwise preserve old behaviour: catch all for file objects
3600 java.io.File file = new java.io.File(uri);
3601 protocols.add(DataSourceType.FILE);
3602 files.add(file.toString());
3607 if (Cache.log.isDebugEnabled())
3609 if (data == null || !added)
3612 if (t.getTransferDataFlavors() != null
3613 && t.getTransferDataFlavors().length > 0)
3616 "Couldn't resolve drop data. Here are the supported flavors:");
3617 for (DataFlavor fl : t.getTransferDataFlavors())
3620 "Supported transfer dataflavor: " + fl.toString());
3621 Object df = t.getTransferData(fl);
3624 Cache.log.debug("Retrieves: " + df);
3628 Cache.log.debug("Retrieved nothing");
3634 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3640 if (Platform.isWindowsAndNotJS())
3642 Cache.log.debug("Scanning dropped content for Windows Link Files");
3644 // resolve any .lnk files in the file drop
3645 for (int f = 0; f < files.size(); f++)
3647 String source = files.get(f).toString().toLowerCase();
3648 if (protocols.get(f).equals(DataSourceType.FILE)
3649 && (source.endsWith(".lnk") || source.endsWith(".url")
3650 || source.endsWith(".site")))
3654 Object obj = files.get(f);
3655 File lf = (obj instanceof File ? (File) obj
3656 : new File((String) obj));
3657 // process link file to get a URL
3658 Cache.log.debug("Found potential link file: " + lf);
3659 WindowsShortcut wscfile = new WindowsShortcut(lf);
3660 String fullname = wscfile.getRealFilename();
3661 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3662 files.set(f, fullname);
3663 Cache.log.debug("Parsed real filename " + fullname
3664 + " to extract protocol: " + protocols.get(f));
3665 } catch (Exception ex)
3668 "Couldn't parse " + files.get(f) + " as a link file.",
3677 * Sets the Preferences property for experimental features to True or False
3678 * depending on the state of the controlling menu item
3681 protected void showExperimental_actionPerformed(boolean selected)
3683 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3687 * Answers a (possibly empty) list of any structure viewer frames (currently for
3688 * either Jmol or Chimera) which are currently open. This may optionally be
3689 * restricted to viewers of a specified class, or viewers linked to a specified
3693 * if not null, only return viewers linked to this panel
3694 * @param structureViewerClass
3695 * if not null, only return viewers of this class
3698 public List<StructureViewerBase> getStructureViewers(
3699 AlignmentPanel apanel,
3700 Class<? extends StructureViewerBase> structureViewerClass)
3702 List<StructureViewerBase> result = new ArrayList<>();
3703 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3705 for (JInternalFrame frame : frames)
3707 if (frame instanceof StructureViewerBase)
3709 if (structureViewerClass == null
3710 || structureViewerClass.isInstance(frame))
3713 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3715 result.add((StructureViewerBase) frame);