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.Jalview;
27 import jalview.gui.ImageExporter.ImageWriterI;
28 import jalview.io.BackupFiles;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileFormats;
34 import jalview.io.FileLoader;
35 import jalview.io.FormatAdapter;
36 import jalview.io.IdentifyFile;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.jbgui.GSplitFrame;
40 import jalview.jbgui.GStructureViewer;
41 import jalview.project.Jalview2XML;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.urls.IdOrgSettings;
44 import jalview.util.BrowserLauncher;
45 import jalview.util.ImageMaker.TYPE;
46 import jalview.util.MessageManager;
47 import jalview.util.Platform;
48 import jalview.util.UrlConstants;
49 import jalview.viewmodel.AlignmentViewport;
50 import jalview.ws.params.ParamManager;
51 import jalview.ws.utils.UrlDownloadClient;
53 import java.awt.BorderLayout;
54 import java.awt.Color;
55 import java.awt.Dimension;
56 import java.awt.FontMetrics;
57 import java.awt.Graphics;
58 import java.awt.GridLayout;
59 import java.awt.Point;
60 import java.awt.Rectangle;
61 import java.awt.Toolkit;
62 import java.awt.Window;
63 import java.awt.datatransfer.Clipboard;
64 import java.awt.datatransfer.ClipboardOwner;
65 import java.awt.datatransfer.DataFlavor;
66 import java.awt.datatransfer.Transferable;
67 import java.awt.dnd.DnDConstants;
68 import java.awt.dnd.DropTargetDragEvent;
69 import java.awt.dnd.DropTargetDropEvent;
70 import java.awt.dnd.DropTargetEvent;
71 import java.awt.dnd.DropTargetListener;
72 import java.awt.event.ActionEvent;
73 import java.awt.event.ActionListener;
74 import java.awt.event.InputEvent;
75 import java.awt.event.KeyEvent;
76 import java.awt.event.MouseAdapter;
77 import java.awt.event.MouseEvent;
78 import java.awt.event.WindowAdapter;
79 import java.awt.event.WindowEvent;
80 import java.beans.PropertyChangeEvent;
81 import java.beans.PropertyChangeListener;
82 import java.io.BufferedInputStream;
84 import java.io.FileOutputStream;
85 import java.io.IOException;
87 import java.util.ArrayList;
88 import java.util.Hashtable;
89 import java.util.List;
90 import java.util.ListIterator;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFrame;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.JTextField;
117 import javax.swing.KeyStroke;
118 import javax.swing.SwingUtilities;
119 import javax.swing.event.HyperlinkEvent;
120 import javax.swing.event.HyperlinkEvent.EventType;
121 import javax.swing.event.InternalFrameAdapter;
122 import javax.swing.event.InternalFrameEvent;
123 import javax.swing.event.MenuEvent;
124 import javax.swing.event.MenuListener;
126 import org.stackoverflowusers.file.WindowsShortcut;
133 * @version $Revision: 1.155 $
135 @SuppressWarnings("serial")
136 public class Desktop extends jalview.jbgui.GDesktop
137 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
138 jalview.api.StructureSelectionManagerProvider
140 private final static int DEFAULT_MIN_WIDTH = 300;
142 private final static int DEFAULT_MIN_HEIGHT = 250;
144 private final static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
146 private final static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
148 private final static String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
150 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
153 * news reader - null if it was never started.
155 BlogReader jvnews = null;
157 private File projectFile;
161 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
163 public void addJalviewPropertyChangeListener(
164 PropertyChangeListener listener)
166 changeSupport.addJalviewPropertyChangeListener(listener);
170 * @param propertyName
172 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
173 * java.beans.PropertyChangeListener)
175 public void addJalviewPropertyChangeListener(String propertyName,
176 PropertyChangeListener listener)
178 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
182 * @param propertyName
184 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
185 * java.beans.PropertyChangeListener)
187 public void removeJalviewPropertyChangeListener(String propertyName,
188 PropertyChangeListener listener)
190 changeSupport.removeJalviewPropertyChangeListener(propertyName,
195 * Singleton Desktop instance only in Java;
197 private static Desktop instance;
199 public static Desktop getInstance()
202 @SuppressWarnings("unused")
203 ThreadGroup g = Thread.currentThread().getThreadGroup();
205 * @j2sNative d = g._jalviewDesktopInstance;
213 private static void setInstance(Desktop d)
215 @SuppressWarnings("unused")
216 ThreadGroup g = Thread.currentThread().getThreadGroup();
218 * @j2s g._jalviewDesktopInstance = d;
225 private MyDesktopPane desktopPane;
227 public static MyDesktopPane getDesktopPane()
229 return getInstance().desktopPane;
232 private void setDesktopPane(MyDesktopPane pane)
234 getInstance().desktopPane = pane;
237 static int openFrameCount = 0;
239 static final int xOffset = 30;
241 static final int yOffset = 30;
243 public static jalview.ws.jws1.Discoverer discoverer;
245 public static Object[] jalviewClipboard;
247 public static boolean internalCopy = false;
249 static int fileLoadingCount = 0;
251 class MyDesktopManager implements DesktopManager
254 private DesktopManager delegate;
256 public MyDesktopManager(DesktopManager delegate)
258 this.delegate = delegate;
262 public void activateFrame(JInternalFrame f)
266 delegate.activateFrame(f);
267 } catch (NullPointerException npe)
269 Point p = getMousePosition();
270 getInstance().showPasteMenu(p.x, p.y);
275 public void beginDraggingFrame(JComponent f)
277 delegate.beginDraggingFrame(f);
281 public void beginResizingFrame(JComponent f, int direction)
283 delegate.beginResizingFrame(f, direction);
287 public void closeFrame(JInternalFrame f)
289 delegate.closeFrame(f);
293 public void deactivateFrame(JInternalFrame f)
295 delegate.deactivateFrame(f);
299 public void deiconifyFrame(JInternalFrame f)
301 delegate.deiconifyFrame(f);
305 public void dragFrame(JComponent f, int newX, int newY)
311 delegate.dragFrame(f, newX, newY);
315 public void endDraggingFrame(JComponent f)
317 delegate.endDraggingFrame(f);
318 getDesktopPane().repaint();
322 public void endResizingFrame(JComponent f)
324 delegate.endResizingFrame(f);
325 getDesktopPane().repaint();
329 public void iconifyFrame(JInternalFrame f)
331 delegate.iconifyFrame(f);
335 public void maximizeFrame(JInternalFrame f)
337 delegate.maximizeFrame(f);
341 public void minimizeFrame(JInternalFrame f)
343 delegate.minimizeFrame(f);
347 public void openFrame(JInternalFrame f)
349 delegate.openFrame(f);
353 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
360 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
364 public void setBoundsForFrame(JComponent f, int newX, int newY,
365 int newWidth, int newHeight)
367 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
370 // All other methods, simply delegate
375 * Creates a new Desktop object.
381 * A note to implementors. It is ESSENTIAL that any activities that might
382 * block are spawned off as threads rather than waited for during this
386 if (!Platform.isJS())
388 doVamsasClientCheck();
391 doConfigureStructurePrefs();
392 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
393 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
394 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
396 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
398 setDesktopPane(new MyDesktopPane(selmemusage));
400 showMemusage.setSelected(selmemusage);
401 getDesktopPane().setBackground(Color.white);
402 getContentPane().setLayout(new BorderLayout());
403 // alternate config - have scrollbars - see notes in JAL-153
404 // JScrollPane sp = new JScrollPane();
405 // sp.getViewport().setView(desktop);
406 // getContentPane().add(sp, BorderLayout.CENTER);
408 // BH 2018 - just an experiment to try unclipped JInternalFrames.
411 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
414 getContentPane().add(getDesktopPane(), BorderLayout.CENTER);
415 getDesktopPane().setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
417 // This line prevents Windows Look&Feel resizing all new windows to maximum
418 // if previous window was maximised
419 getDesktopPane().setDesktopManager(new MyDesktopManager(
420 (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
421 : Platform.isAMacAndNotJS()
422 ? new AquaInternalFrameManager(
423 getDesktopPane().getDesktopManager())
424 : getDesktopPane().getDesktopManager())));
426 Rectangle dims = getLastKnownDimensions("");
433 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
434 int xPos = Math.max(5, (screenSize.width - 900) / 2);
435 int yPos = Math.max(5, (screenSize.height - 650) / 2);
436 setBounds(xPos, yPos, 900, 650);
439 if (!Platform.isJS())
447 jconsole = new Console(this, showjconsole);
448 // add essential build information
449 jconsole.setHeader("Jalview Version: "
450 + jalview.bin.Cache.getProperty("VERSION") + "\n"
451 + "Jalview Installation: "
452 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
453 + "\n" + "Build Date: "
454 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
455 + "Java version: " + System.getProperty("java.version") + "\n"
456 + System.getProperty("os.arch") + " "
457 + System.getProperty("os.name") + " "
458 + System.getProperty("os.version"));
460 showConsole(showjconsole);
462 showNews.setVisible(false);
464 experimentalFeatures.setSelected(showExperimental());
466 getIdentifiersOrgData();
470 // Spawn a thread that shows the splashscreen
472 SwingUtilities.invokeLater(new Runnable()
481 // Thread off a new instance of the file chooser - this reduces the time
483 // takes to open it later on.
484 new Thread(new Runnable()
489 Cache.log.debug("Filechooser init thread started.");
490 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
491 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
493 Cache.log.debug("Filechooser init thread finished.");
496 // Add the service change listener
497 changeSupport.addJalviewPropertyChangeListener("services",
498 new PropertyChangeListener()
502 public void propertyChange(PropertyChangeEvent evt)
504 Cache.log.debug("Firing service changed event for "
505 + evt.getNewValue());
506 JalviewServicesChanged(evt);
513 this.setDropTarget(new java.awt.dnd.DropTarget(getDesktopPane(), this));
515 this.addWindowListener(new WindowAdapter()
518 public void windowClosing(WindowEvent evt)
525 this.addMouseListener(ma = new MouseAdapter()
528 public void mousePressed(MouseEvent evt)
530 if (evt.isPopupTrigger()) // Mac
532 showPasteMenu(evt.getX(), evt.getY());
537 public void mouseReleased(MouseEvent evt)
539 if (evt.isPopupTrigger()) // Windows
541 showPasteMenu(evt.getX(), evt.getY());
545 getDesktopPane().addMouseListener(ma);
550 * Answers true if user preferences to enable experimental features is True
555 public boolean showExperimental()
557 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
558 Boolean.FALSE.toString());
559 return Boolean.valueOf(experimental).booleanValue();
562 public void doConfigureStructurePrefs()
564 // configure services
565 StructureSelectionManager ssm = StructureSelectionManager
566 .getStructureSelectionManager(this);
567 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
569 ssm.setAddTempFacAnnot(jalview.bin.Cache
570 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
571 ssm.setProcessSecondaryStructure(jalview.bin.Cache
572 .getDefault(Preferences.STRUCT_FROM_PDB, true));
573 ssm.setSecStructServices(
574 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
578 ssm.setAddTempFacAnnot(false);
579 ssm.setProcessSecondaryStructure(false);
580 ssm.setSecStructServices(false);
584 public void checkForNews()
586 final Desktop me = this;
587 // Thread off the news reader, in case there are connection problems.
588 new Thread(new Runnable()
593 Cache.log.debug("Starting news thread.");
594 jvnews = new BlogReader(me);
595 showNews.setVisible(true);
596 Cache.log.debug("Completed news thread.");
601 public void getIdentifiersOrgData()
603 // Thread off the identifiers fetcher
604 new Thread(new Runnable()
609 Cache.log.debug("Downloading data from identifiers.org");
610 // UrlDownloadClient client = new UrlDownloadClient();
613 UrlDownloadClient.download(IdOrgSettings.getUrl(),
614 IdOrgSettings.getDownloadLocation());
615 } catch (IOException e)
617 Cache.log.debug("Exception downloading identifiers.org data"
626 protected void showNews_actionPerformed(ActionEvent e)
628 showNews(showNews.isSelected());
631 protected void showNews(boolean visible)
633 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
634 showNews.setSelected(visible);
635 if (visible && !jvnews.isVisible())
637 new Thread(new Runnable()
642 long now = System.currentTimeMillis();
643 Desktop.getInstance().setProgressBar(
644 MessageManager.getString("status.refreshing_news"), now);
645 jvnews.refreshNews();
646 Desktop.getInstance().setProgressBar(null, now);
654 * recover the last known dimensions for a jalview window
657 * - empty string is desktop, all other windows have unique prefix
658 * @return null or last known dimensions scaled to current geometry (if last
659 * window geom was known)
661 Rectangle getLastKnownDimensions(String windowName)
663 // TODO: lock aspect ratio for scaling desktop Bug #0058199
664 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
665 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
666 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
667 String width = jalview.bin.Cache
668 .getProperty(windowName + "SCREEN_WIDTH");
669 String height = jalview.bin.Cache
670 .getProperty(windowName + "SCREEN_HEIGHT");
671 if ((x != null) && (y != null) && (width != null) && (height != null))
673 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
674 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
675 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
677 // attempt #1 - try to cope with change in screen geometry - this
678 // version doesn't preserve original jv aspect ratio.
679 // take ratio of current screen size vs original screen size.
680 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
681 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
682 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
683 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
684 // rescale the bounds depending upon the current screen geometry.
685 ix = (int) (ix * sw);
686 iw = (int) (iw * sw);
687 iy = (int) (iy * sh);
688 ih = (int) (ih * sh);
689 while (ix >= screenSize.width)
691 jalview.bin.Cache.log.debug(
692 "Window geometry location recall error: shifting horizontal to within screenbounds.");
693 ix -= screenSize.width;
695 while (iy >= screenSize.height)
697 jalview.bin.Cache.log.debug(
698 "Window geometry location recall error: shifting vertical to within screenbounds.");
699 iy -= screenSize.height;
701 jalview.bin.Cache.log.debug(
702 "Got last known dimensions for " + windowName + ": x:" + ix
703 + " y:" + iy + " width:" + iw + " height:" + ih);
705 // return dimensions for new instance
706 return new Rectangle(ix, iy, iw, ih);
711 private void doVamsasClientCheck()
713 if (Cache.vamsasJarsPresent())
715 setupVamsasDisconnectedGui();
716 VamsasMenu.setVisible(true);
717 final Desktop us = this;
718 VamsasMenu.addMenuListener(new MenuListener()
720 // this listener remembers when the menu was first selected, and
721 // doesn't rebuild the session list until it has been cleared and
723 boolean refresh = true;
726 public void menuCanceled(MenuEvent e)
732 public void menuDeselected(MenuEvent e)
738 public void menuSelected(MenuEvent e)
742 us.buildVamsasStMenu();
747 vamsasStart.setVisible(true);
751 protected void showPasteMenu(int x, int y)
753 JPopupMenu popup = new JPopupMenu();
754 JMenuItem item = new JMenuItem(
755 MessageManager.getString("label.paste_new_window"));
756 item.addActionListener(new ActionListener()
759 public void actionPerformed(ActionEvent evt)
766 popup.show(this, x, y);
773 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
774 Transferable contents = c.getContents(this);
776 if (contents != null)
778 String file = (String) contents
779 .getTransferData(DataFlavor.stringFlavor);
781 FileFormatI format = new IdentifyFile().identify(file,
782 DataSourceType.PASTE);
784 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
787 } catch (Exception ex)
790 "Unable to paste alignment from system clipboard:\n" + ex);
795 * Adds and opens the given frame to the desktop
806 public static synchronized void addInternalFrame(
807 final JInternalFrame frame, String title, int w, int h)
809 addInternalFrame(frame, title, true, w, h, true, false);
813 * Add an internal frame to the Jalview desktop
820 * When true, display frame immediately, otherwise, caller must call
821 * setVisible themselves.
827 public static synchronized void addInternalFrame(
828 final JInternalFrame frame, String title, boolean makeVisible,
831 addInternalFrame(frame, title, makeVisible, w, h, true, false);
835 * Add an internal frame to the Jalview desktop and make it visible
848 public static synchronized void addInternalFrame(
849 final JInternalFrame frame, String title, int w, int h,
852 addInternalFrame(frame, title, true, w, h, resizable, false);
856 * Add an internal frame to the Jalview desktop
863 * When true, display frame immediately, otherwise, caller must call
864 * setVisible themselves.
871 * @param ignoreMinSize
872 * Do not set the default minimum size for frame
874 public static synchronized void addInternalFrame(
875 final JInternalFrame frame, String title, boolean makeVisible,
876 int w, int h, boolean resizable, boolean ignoreMinSize)
879 // TODO: allow callers to determine X and Y position of frame (eg. via
881 // TODO: consider fixing method to update entries in the window submenu with
882 // the current window title
884 frame.setTitle(title);
885 if (frame.getWidth() < 1 || frame.getHeight() < 1)
889 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
890 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
891 // IF JALVIEW IS RUNNING HEADLESS
892 // ///////////////////////////////////////////////
893 if (instance == null || Jalview.isHeadlessMode())
902 frame.setMinimumSize(
903 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
905 // Set default dimension for Alignment Frame window.
906 // The Alignment Frame window could be added from a number of places,
908 // I did this here in order not to miss out on any Alignment frame.
909 if (frame instanceof AlignFrame)
911 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
912 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
916 frame.setVisible(makeVisible);
917 frame.setClosable(true);
918 frame.setResizable(resizable);
919 frame.setMaximizable(resizable);
920 frame.setIconifiable(resizable);
921 frame.setOpaque(Platform.isJS());
923 if (frame.getX() < 1 && frame.getY() < 1)
925 frame.setLocation(xOffset * openFrameCount,
926 yOffset * ((openFrameCount - 1) % 10) + yOffset);
930 * add an entry for the new frame in the Window menu
931 * (and remove it when the frame is closed)
933 JMenuItem menuItem = new JMenuItem(title);
934 frame.addInternalFrameListener(new InternalFrameAdapter()
937 public void internalFrameActivated(InternalFrameEvent evt)
939 JInternalFrame itf = getDesktopPane().getSelectedFrame();
942 if (itf instanceof AlignFrame)
944 Jalview.setCurrentAlignFrame((AlignFrame) itf);
951 public void internalFrameClosed(InternalFrameEvent evt)
953 PaintRefresher.RemoveComponent(frame);
956 * defensive check to prevent frames being
957 * added half off the window
959 if (openFrameCount > 0)
965 * ensure no reference to alignFrame retained by menu item listener
967 if (menuItem.getActionListeners().length > 0)
969 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
971 getInstance().windowMenu.remove(menuItem);
975 menuItem.addActionListener(new ActionListener()
978 public void actionPerformed(ActionEvent e)
982 frame.setSelected(true);
983 frame.setIcon(false);
984 } catch (java.beans.PropertyVetoException ex)
986 // System.err.println(ex.toString());
991 setKeyBindings(frame);
993 getDesktopPane().add(frame);
995 getInstance().windowMenu.add(menuItem);
1000 frame.setSelected(true);
1001 frame.requestFocus();
1002 } catch (java.beans.PropertyVetoException ve)
1004 } catch (java.lang.ClassCastException cex)
1007 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1013 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
1018 private static void setKeyBindings(JInternalFrame frame)
1020 final Action closeAction = new AbstractAction()
1023 public void actionPerformed(ActionEvent e)
1030 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1032 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1033 InputEvent.CTRL_DOWN_MASK);
1034 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1035 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1037 InputMap inputMap = frame
1038 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1039 String ctrlW = ctrlWKey.toString();
1040 inputMap.put(ctrlWKey, ctrlW);
1041 inputMap.put(cmdWKey, ctrlW);
1043 ActionMap actionMap = frame.getActionMap();
1044 actionMap.put(ctrlW, closeAction);
1048 public void lostOwnership(Clipboard clipboard, Transferable contents)
1052 Desktop.jalviewClipboard = null;
1055 internalCopy = false;
1059 public void dragEnter(DropTargetDragEvent evt)
1064 public void dragExit(DropTargetEvent evt)
1069 public void dragOver(DropTargetDragEvent evt)
1074 public void dropActionChanged(DropTargetDragEvent evt)
1085 public void drop(DropTargetDropEvent evt)
1087 boolean success = true;
1088 // JAL-1552 - acceptDrop required before getTransferable call for
1089 // Java's Transferable for native dnd
1090 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1091 Transferable t = evt.getTransferable();
1092 List<Object> files = new ArrayList<>();
1093 List<DataSourceType> protocols = new ArrayList<>();
1097 Desktop.transferFromDropTarget(files, protocols, evt, t);
1098 } catch (Exception e)
1100 e.printStackTrace();
1108 for (int i = 0; i < files.size(); i++)
1110 // BH 2018 File or String
1111 Object file = files.get(i);
1112 String fileName = file.toString();
1113 DataSourceType protocol = (protocols == null)
1114 ? DataSourceType.FILE
1116 FileFormatI format = null;
1118 if (fileName.endsWith(".jar"))
1120 format = FileFormat.Jalview;
1125 format = new IdentifyFile().identify(file, protocol);
1127 if (file instanceof File)
1129 Platform.cacheFileData((File) file);
1131 new FileLoader().LoadFile(null, file, protocol, format);
1134 } catch (Exception ex)
1139 evt.dropComplete(success); // need this to ensure input focus is properly
1140 // transfered to any new windows created
1150 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1152 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1153 JalviewFileChooser chooser = JalviewFileChooser
1154 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
1156 chooser.setFileView(new JalviewFileView());
1157 chooser.setDialogTitle(
1158 MessageManager.getString("label.open_local_file"));
1159 chooser.setToolTipText(MessageManager.getString("action.open"));
1161 chooser.setResponseHandler(0, new Runnable()
1166 File selectedFile = chooser.getSelectedFile();
1167 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1169 FileFormatI format = chooser.getSelectedFormat();
1172 * Call IdentifyFile to verify the file contains what its extension implies.
1173 * Skip this step for dynamically added file formats, because
1174 * IdentifyFile does not know how to recognise them.
1176 if (FileFormats.getInstance().isIdentifiable(format))
1180 format = new IdentifyFile().identify(selectedFile,
1181 DataSourceType.FILE);
1182 } catch (FileFormatException e)
1184 // format = null; //??
1188 new FileLoader().LoadFile(viewport, selectedFile,
1189 DataSourceType.FILE, format);
1192 chooser.showOpenDialog(this);
1196 * Shows a dialog for input of a URL at which to retrieve alignment data
1201 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1203 // This construct allows us to have a wider textfield
1205 JLabel label = new JLabel(
1206 MessageManager.getString("label.input_file_url"));
1208 JPanel panel = new JPanel(new GridLayout(2, 1));
1212 * the URL to fetch is
1213 * Java: an editable combobox with history
1214 * JS: (pending JAL-3038) a plain text field
1217 String urlBase = "http://www.";
1218 if (Platform.isJS())
1220 history = new JTextField(urlBase, 35);
1229 JComboBox<String> asCombo = new JComboBox<>();
1230 asCombo.setPreferredSize(new Dimension(400, 20));
1231 asCombo.setEditable(true);
1232 asCombo.addItem(urlBase);
1233 String historyItems = Cache.getProperty("RECENT_URL");
1234 if (historyItems != null)
1236 for (String token : historyItems.split("\\t"))
1238 asCombo.addItem(token);
1245 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1246 MessageManager.getString("action.cancel") };
1247 Runnable action = new Runnable()
1252 @SuppressWarnings("unchecked")
1253 String url = (history instanceof JTextField
1254 ? ((JTextField) history).getText()
1255 : ((JComboBox<String>) history).getSelectedItem()
1258 if (url.toLowerCase().endsWith(".jar"))
1260 if (viewport != null)
1262 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1263 FileFormat.Jalview);
1267 new FileLoader().LoadFile(url, DataSourceType.URL,
1268 FileFormat.Jalview);
1273 FileFormatI format = null;
1276 format = new IdentifyFile().identify(url, DataSourceType.URL);
1277 } catch (FileFormatException e)
1279 // TODO revise error handling, distinguish between
1280 // URL not found and response not valid
1285 String msg = MessageManager
1286 .formatMessage("label.couldnt_locate", url);
1287 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
1289 MessageManager.getString("label.url_not_found"),
1290 JvOptionPane.WARNING_MESSAGE);
1295 if (viewport != null)
1297 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1302 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1307 String dialogOption = MessageManager
1308 .getString("label.input_alignment_from_url");
1309 JvOptionPane.newOptionDialog(getDesktopPane())
1310 .setResponseHandler(0, action)
1311 .showInternalDialog(panel, dialogOption,
1312 JvOptionPane.YES_NO_CANCEL_OPTION,
1313 JvOptionPane.PLAIN_MESSAGE, null, options,
1314 MessageManager.getString("action.ok"));
1318 * Opens the CutAndPaste window for the user to paste an alignment in to
1321 * - if not null, the pasted alignment is added to the current
1322 * alignment; if null, to a new alignment window
1325 public void inputTextboxMenuItem_actionPerformed(
1326 AlignmentViewPanel viewPanel)
1328 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1329 cap.setForInput(viewPanel);
1330 Desktop.addInternalFrame(cap,
1331 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1341 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1342 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1344 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1345 screen.height + "");
1346 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1347 getWidth(), getHeight()));
1349 if (jconsole != null)
1351 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1352 jconsole.stopConsole();
1356 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1359 if (dialogExecutor != null)
1361 dialogExecutor.shutdownNow();
1363 closeAll_actionPerformed(null);
1365 if (groovyConsole != null)
1367 // suppress a possible repeat prompt to save script
1368 groovyConsole.setDirty(false);
1369 groovyConsole.exit();
1374 private void storeLastKnownDimensions(String string, Rectangle jc)
1376 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1377 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1378 + " height:" + jc.height);
1380 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1381 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1382 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1383 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1393 public void aboutMenuItem_actionPerformed(ActionEvent e)
1395 // StringBuffer message = getAboutMessage(false);
1396 // JvOptionPane.showInternalMessageDialog(Desktop.getDesktop(),
1398 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1399 new Thread(new Runnable()
1404 new SplashScreen(true);
1409 public StringBuffer getAboutMessage(boolean shortv)
1411 StringBuffer message = new StringBuffer();
1412 message.append("<html>");
1415 message.append("<h1><strong>Version: "
1416 + jalview.bin.Cache.getProperty("VERSION")
1417 + "</strong></h1>");
1418 message.append("<strong>Last Updated: <em>"
1419 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1420 + "</em></strong>");
1426 message.append("<strong>Version "
1427 + jalview.bin.Cache.getProperty("VERSION")
1428 + "; last updated: "
1429 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1432 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1433 .equals("Checking"))
1435 message.append("<br>...Checking latest version...</br>");
1437 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1438 .equals(jalview.bin.Cache.getProperty("VERSION")))
1440 boolean red = false;
1441 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1442 .indexOf("automated build") == -1)
1445 // Displayed when code version and jnlp version do not match and code
1446 // version is not a development build
1447 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1450 message.append("<br>!! Version "
1451 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1453 + " is available for download from "
1454 + jalview.bin.Cache.getDefault("www.jalview.org",
1455 "http://www.jalview.org")
1459 message.append("</div>");
1462 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1464 "The Jalview Authors (See AUTHORS file for current list)")
1465 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1466 + "<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"
1467 + "<br><br>If you use Jalview, please cite:"
1468 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1469 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1470 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1476 * Action on requesting Help documentation
1479 public void documentationMenuItem_actionPerformed()
1483 if (Platform.isJS())
1485 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1494 Help.showHelpWindow();
1496 } catch (Exception ex)
1498 System.err.println("Error opening help: " + ex.getMessage());
1503 public void closeAll_actionPerformed(ActionEvent e)
1505 // TODO show a progress bar while closing?
1506 JInternalFrame[] frames = getDesktopPane().getAllFrames();
1507 for (int i = 0; i < frames.length; i++)
1511 frames[i].setClosed(true);
1512 } catch (java.beans.PropertyVetoException ex)
1516 Jalview.setCurrentAlignFrame(null);
1517 System.out.println("ALL CLOSED");
1518 if (v_client != null)
1520 // TODO clear binding to vamsas document objects on close_all
1524 * reset state of singleton objects as appropriate (clear down session state
1525 * when all windows are closed)
1527 StructureSelectionManager ssm = StructureSelectionManager
1528 .getStructureSelectionManager(this);
1536 public void raiseRelated_actionPerformed(ActionEvent e)
1538 reorderAssociatedWindows(false, false);
1542 public void minimizeAssociated_actionPerformed(ActionEvent e)
1544 reorderAssociatedWindows(true, false);
1547 void closeAssociatedWindows()
1549 reorderAssociatedWindows(false, true);
1555 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1559 protected void garbageCollect_actionPerformed(ActionEvent e)
1561 // We simply collect the garbage
1562 jalview.bin.Cache.log.debug("Collecting garbage...");
1564 jalview.bin.Cache.log.debug("Finished garbage collection.");
1571 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1575 protected void showMemusage_actionPerformed(ActionEvent e)
1577 getDesktopPane().showMemoryUsage(showMemusage.isSelected());
1584 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1588 protected void showConsole_actionPerformed(ActionEvent e)
1590 showConsole(showConsole.isSelected());
1593 Console jconsole = null;
1596 * control whether the java console is visible or not
1600 void showConsole(boolean selected)
1602 // TODO: decide if we should update properties file
1603 if (jconsole != null) // BH 2018
1605 showConsole.setSelected(selected);
1606 Cache.setProperty("SHOW_JAVA_CONSOLE",
1607 Boolean.valueOf(selected).toString());
1608 jconsole.setVisible(selected);
1612 void reorderAssociatedWindows(boolean minimize, boolean close)
1614 JInternalFrame[] frames = getDesktopPane().getAllFrames();
1615 if (frames == null || frames.length < 1)
1620 AlignmentViewport source = null, target = null;
1621 if (frames[0] instanceof AlignFrame)
1623 source = ((AlignFrame) frames[0]).getCurrentView();
1625 else if (frames[0] instanceof TreePanel)
1627 source = ((TreePanel) frames[0]).getViewPort();
1629 else if (frames[0] instanceof PCAPanel)
1631 source = ((PCAPanel) frames[0]).av;
1633 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1635 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1640 for (int i = 0; i < frames.length; i++)
1643 if (frames[i] == null)
1647 if (frames[i] instanceof AlignFrame)
1649 target = ((AlignFrame) frames[i]).getCurrentView();
1651 else if (frames[i] instanceof TreePanel)
1653 target = ((TreePanel) frames[i]).getViewPort();
1655 else if (frames[i] instanceof PCAPanel)
1657 target = ((PCAPanel) frames[i]).av;
1659 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1661 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1664 if (source == target)
1670 frames[i].setClosed(true);
1674 frames[i].setIcon(minimize);
1677 frames[i].toFront();
1681 } catch (java.beans.PropertyVetoException ex)
1696 protected void preferences_actionPerformed(ActionEvent e)
1702 * Prompts the user to choose a file and then saves the Jalview state as a
1703 * Jalview project file
1706 public void saveState_actionPerformed()
1708 saveState_actionPerformed(false);
1711 public void saveState_actionPerformed(boolean saveAs)
1713 java.io.File projectFile = getProjectFile();
1714 // autoSave indicates we already have a file and don't need to ask
1715 boolean autoSave = projectFile != null && !saveAs
1716 && BackupFiles.getEnabled();
1718 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1719 // saveAs="+saveAs+", Backups
1720 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1722 boolean approveSave = false;
1725 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1728 chooser.setFileView(new JalviewFileView());
1729 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1731 int value = chooser.showSaveDialog(this);
1733 if (value == JalviewFileChooser.APPROVE_OPTION)
1735 projectFile = chooser.getSelectedFile();
1736 setProjectFile(projectFile);
1741 if (approveSave || autoSave)
1743 final Desktop me = this;
1744 final java.io.File chosenFile = projectFile;
1745 new Thread(new Runnable()
1750 // TODO: refactor to Jalview desktop session controller action.
1751 setProgressBar(MessageManager.formatMessage(
1752 "label.saving_jalview_project", new Object[]
1753 { chosenFile.getName() }), chosenFile.hashCode());
1754 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1755 chosenFile.getParent());
1756 // TODO catch and handle errors for savestate
1757 // TODO prevent user from messing with the Desktop whilst we're saving
1760 boolean doBackup = BackupFiles.getEnabled();
1761 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1763 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1767 backupfiles.setWriteSuccess(true);
1768 backupfiles.rollBackupsAndRenameTempFile();
1770 } catch (OutOfMemoryError oom)
1772 new OOMWarning("Whilst saving current state to "
1773 + chosenFile.getName(), oom);
1774 } catch (Exception ex)
1776 Cache.log.error("Problems whilst trying to save to "
1777 + chosenFile.getName(), ex);
1778 JvOptionPane.showMessageDialog(me,
1779 MessageManager.formatMessage(
1780 "label.error_whilst_saving_current_state_to",
1782 { chosenFile.getName() }),
1783 MessageManager.getString("label.couldnt_save_project"),
1784 JvOptionPane.WARNING_MESSAGE);
1786 setProgressBar(null, chosenFile.hashCode());
1793 public void saveAsState_actionPerformed(ActionEvent e)
1795 saveState_actionPerformed(true);
1798 protected void setProjectFile(File choice)
1800 this.projectFile = choice;
1803 public File getProjectFile()
1805 return this.projectFile;
1809 * Shows a file chooser dialog and tries to read in the selected file as a
1813 public void loadState_actionPerformed()
1815 final String[] suffix = new String[] { "jvp", "jar" };
1816 final String[] desc = new String[] { "Jalview Project",
1817 "Jalview Project (old)" };
1818 JalviewFileChooser chooser = new JalviewFileChooser(
1819 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1820 "Jalview Project", true, true); // last two booleans: allFiles,
1822 chooser.setFileView(new JalviewFileView());
1823 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1824 chooser.setResponseHandler(0, new Runnable()
1829 File selectedFile = chooser.getSelectedFile();
1830 setProjectFile(selectedFile);
1831 String choice = selectedFile.getAbsolutePath();
1832 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1833 new Thread(new Runnable()
1840 new Jalview2XML().loadJalviewAlign(choice);
1841 } catch (OutOfMemoryError oom)
1843 new OOMWarning("Whilst loading project from " + choice, oom);
1844 } catch (Exception ex)
1847 "Problems whilst loading project from " + choice, ex);
1848 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(),
1849 MessageManager.formatMessage(
1850 "label.error_whilst_loading_project_from",
1853 MessageManager.getString("label.couldnt_load_project"),
1854 JvOptionPane.WARNING_MESSAGE);
1861 chooser.showOpenDialog(this);
1865 public void inputSequence_actionPerformed(ActionEvent e)
1867 new SequenceFetcher(this);
1870 JPanel progressPanel;
1872 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1874 public void startLoading(final Object fileName)
1876 if (fileLoadingCount == 0)
1878 fileLoadingPanels.add(addProgressPanel(MessageManager
1879 .formatMessage("label.loading_file", new Object[]
1885 private JPanel addProgressPanel(String string)
1887 if (progressPanel == null)
1889 progressPanel = new JPanel(new GridLayout(1, 1));
1890 totalProgressCount = 0;
1891 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1893 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1894 JProgressBar progressBar = new JProgressBar();
1895 progressBar.setIndeterminate(true);
1897 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1899 thisprogress.add(progressBar, BorderLayout.CENTER);
1900 progressPanel.add(thisprogress);
1901 ((GridLayout) progressPanel.getLayout()).setRows(
1902 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1903 ++totalProgressCount;
1904 instance.validate();
1905 return thisprogress;
1908 int totalProgressCount = 0;
1910 private void removeProgressPanel(JPanel progbar)
1912 if (progressPanel != null)
1914 synchronized (progressPanel)
1916 progressPanel.remove(progbar);
1917 GridLayout gl = (GridLayout) progressPanel.getLayout();
1918 gl.setRows(gl.getRows() - 1);
1919 if (--totalProgressCount < 1)
1921 this.getContentPane().remove(progressPanel);
1922 progressPanel = null;
1929 public void stopLoading()
1932 if (fileLoadingCount < 1)
1934 while (fileLoadingPanels.size() > 0)
1936 removeProgressPanel(fileLoadingPanels.remove(0));
1938 fileLoadingPanels.clear();
1939 fileLoadingCount = 0;
1944 public static int getViewCount(String alignmentId)
1946 AlignmentViewport[] aps = getViewports(alignmentId);
1947 return (aps == null) ? 0 : aps.length;
1952 * @param alignmentId
1953 * - if null, all sets are returned
1954 * @return all AlignmentPanels concerning the alignmentId sequence set
1956 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1958 if (Desktop.getDesktopPane() == null)
1960 // no frames created and in headless mode
1961 // TODO: verify that frames are recoverable when in headless mode
1964 List<AlignmentPanel> aps = new ArrayList<>();
1965 AlignFrame[] frames = getAlignFrames();
1970 for (AlignFrame af : frames)
1972 for (AlignmentPanel ap : af.alignPanels)
1974 if (alignmentId == null
1975 || alignmentId.equals(ap.av.getSequenceSetId()))
1981 if (aps.size() == 0)
1985 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1990 * get all the viewports on an alignment.
1992 * @param sequenceSetId
1993 * unique alignment id (may be null - all viewports returned in that
1995 * @return all viewports on the alignment bound to sequenceSetId
1997 public static AlignmentViewport[] getViewports(String sequenceSetId)
1999 List<AlignmentViewport> viewp = new ArrayList<>();
2000 if (getDesktopPane() != null)
2002 AlignFrame[] frames = Desktop.getAlignFrames();
2004 for (AlignFrame afr : frames)
2006 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2007 .equals(sequenceSetId))
2009 if (afr.alignPanels != null)
2011 for (AlignmentPanel ap : afr.alignPanels)
2013 if (sequenceSetId == null
2014 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2022 viewp.add(afr.getViewport());
2026 if (viewp.size() > 0)
2028 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2035 * Explode the views in the given frame into separate AlignFrame
2039 public static void explodeViews(AlignFrame af)
2041 int size = af.alignPanels.size();
2047 for (int i = 0; i < size; i++)
2049 AlignmentPanel ap = af.alignPanels.get(i);
2050 AlignFrame newaf = new AlignFrame(ap);
2053 * Restore the view's last exploded frame geometry if known. Multiple
2054 * views from one exploded frame share and restore the same (frame)
2055 * position and size.
2057 Rectangle geometry = ap.av.getExplodedGeometry();
2058 if (geometry != null)
2060 newaf.setBounds(geometry);
2063 ap.av.setGatherViewsHere(false);
2065 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2066 AlignFrame.DEFAULT_HEIGHT);
2069 af.alignPanels.clear();
2070 af.closeMenuItem_actionPerformed(true);
2075 * Gather expanded views (separate AlignFrame's) with the same sequence set
2076 * identifier back in to this frame as additional views, and close the expanded
2077 * views. Note the expanded frames may themselves have multiple views. We take
2082 public void gatherViews(AlignFrame source)
2084 source.viewport.setGatherViewsHere(true);
2085 source.viewport.setExplodedGeometry(source.getBounds());
2086 JInternalFrame[] frames = getDesktopPane().getAllFrames();
2087 String viewId = source.viewport.getSequenceSetId();
2089 for (int t = 0; t < frames.length; t++)
2091 if (frames[t] instanceof AlignFrame && frames[t] != source)
2093 AlignFrame af = (AlignFrame) frames[t];
2094 boolean gatherThis = false;
2095 for (int a = 0; a < af.alignPanels.size(); a++)
2097 AlignmentPanel ap = af.alignPanels.get(a);
2098 if (viewId.equals(ap.av.getSequenceSetId()))
2101 ap.av.setGatherViewsHere(false);
2102 ap.av.setExplodedGeometry(af.getBounds());
2103 source.addAlignmentPanel(ap, false);
2109 af.alignPanels.clear();
2110 af.closeMenuItem_actionPerformed(true);
2117 jalview.gui.VamsasApplication v_client = null;
2120 public void vamsasImport_actionPerformed(ActionEvent e)
2122 // TODO: JAL-3048 not needed for Jalview-JS
2124 if (v_client == null)
2126 // Load and try to start a session.
2127 JalviewFileChooser chooser = new JalviewFileChooser(
2128 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2130 chooser.setFileView(new JalviewFileView());
2131 chooser.setDialogTitle(
2132 MessageManager.getString("label.open_saved_vamsas_session"));
2133 chooser.setToolTipText(MessageManager.getString(
2134 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2136 int value = chooser.showOpenDialog(this);
2138 if (value == JalviewFileChooser.APPROVE_OPTION)
2140 String fle = chooser.getSelectedFile().toString();
2141 if (!vamsasImport(chooser.getSelectedFile()))
2143 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2144 MessageManager.formatMessage(
2145 "label.couldnt_import_as_vamsas_session",
2149 .getString("label.vamsas_document_import_failed"),
2150 JvOptionPane.ERROR_MESSAGE);
2156 jalview.bin.Cache.log.error(
2157 "Implementation error - load session from a running session is not supported.");
2162 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2165 * @return true if import was a success and a session was started.
2167 public boolean vamsasImport(URL url)
2169 // TODO: create progress bar
2170 if (v_client != null)
2173 jalview.bin.Cache.log.error(
2174 "Implementation error - load session from a running session is not supported.");
2180 // copy the URL content to a temporary local file
2181 // TODO: be a bit cleverer here with nio (?!)
2182 File file = File.createTempFile("vdocfromurl", ".vdj");
2183 FileOutputStream fos = new FileOutputStream(file);
2184 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2185 byte[] buffer = new byte[2048];
2187 while ((ln = bis.read(buffer)) > -1)
2189 fos.write(buffer, 0, ln);
2193 v_client = new jalview.gui.VamsasApplication(this, file,
2194 url.toExternalForm());
2195 } catch (Exception ex)
2197 jalview.bin.Cache.log.error(
2198 "Failed to create new vamsas session from contents of URL "
2203 setupVamsasConnectedGui();
2204 v_client.initial_update(); // TODO: thread ?
2205 return v_client.inSession();
2209 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2212 * @return true if import was a success and a session was started.
2214 public boolean vamsasImport(File file)
2216 if (v_client != null)
2219 jalview.bin.Cache.log.error(
2220 "Implementation error - load session from a running session is not supported.");
2224 setProgressBar(MessageManager.formatMessage(
2225 "status.importing_vamsas_session_from", new Object[]
2226 { file.getName() }), file.hashCode());
2229 v_client = new jalview.gui.VamsasApplication(this, file, null);
2230 } catch (Exception ex)
2232 setProgressBar(MessageManager.formatMessage(
2233 "status.importing_vamsas_session_from", new Object[]
2234 { file.getName() }), file.hashCode());
2235 jalview.bin.Cache.log.error(
2236 "New vamsas session from existing session file failed:", ex);
2239 setupVamsasConnectedGui();
2240 v_client.initial_update(); // TODO: thread ?
2241 setProgressBar(MessageManager.formatMessage(
2242 "status.importing_vamsas_session_from", new Object[]
2243 { file.getName() }), file.hashCode());
2244 return v_client.inSession();
2247 public boolean joinVamsasSession(String mysesid)
2249 if (v_client != null)
2251 throw new Error(MessageManager
2252 .getString("error.try_join_vamsas_session_another"));
2254 if (mysesid == null)
2257 MessageManager.getString("error.invalid_vamsas_session_id"));
2259 v_client = new VamsasApplication(this, mysesid);
2260 setupVamsasConnectedGui();
2261 v_client.initial_update();
2262 return (v_client.inSession());
2266 public void vamsasStart_actionPerformed(ActionEvent e)
2268 if (v_client == null)
2271 // we just start a default session for moment.
2273 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2274 * getProperty("LAST_DIRECTORY"));
2276 * chooser.setFileView(new JalviewFileView());
2277 * chooser.setDialogTitle("Load Vamsas file");
2278 * chooser.setToolTipText("Import");
2280 * int value = chooser.showOpenDialog(this);
2282 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2283 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2285 v_client = new VamsasApplication(this);
2286 setupVamsasConnectedGui();
2287 v_client.initial_update(); // TODO: thread ?
2291 // store current data in session.
2292 v_client.push_update(); // TODO: thread
2296 protected void setupVamsasConnectedGui()
2298 vamsasStart.setText(MessageManager.getString("label.session_update"));
2299 vamsasSave.setVisible(true);
2300 vamsasStop.setVisible(true);
2301 vamsasImport.setVisible(false); // Document import to existing session is
2302 // not possible for vamsas-client-1.0.
2305 protected void setupVamsasDisconnectedGui()
2307 vamsasSave.setVisible(false);
2308 vamsasStop.setVisible(false);
2309 vamsasImport.setVisible(true);
2311 .setText(MessageManager.getString("label.new_vamsas_session"));
2315 public void vamsasStop_actionPerformed(ActionEvent e)
2317 if (v_client != null)
2319 v_client.end_session();
2321 setupVamsasDisconnectedGui();
2325 protected void buildVamsasStMenu()
2327 if (v_client == null)
2329 String[] sess = null;
2332 sess = VamsasApplication.getSessionList();
2333 } catch (Exception e)
2335 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2341 jalview.bin.Cache.log.debug(
2342 "Got current sessions list: " + sess.length + " entries.");
2343 VamsasStMenu.removeAll();
2344 for (int i = 0; i < sess.length; i++)
2346 JMenuItem sessit = new JMenuItem();
2347 sessit.setText(sess[i]);
2348 sessit.setToolTipText(MessageManager
2349 .formatMessage("label.connect_to_session", new Object[]
2351 final Desktop dsktp = this;
2352 final String mysesid = sess[i];
2353 sessit.addActionListener(new ActionListener()
2357 public void actionPerformed(ActionEvent e)
2359 if (dsktp.v_client == null)
2361 Thread rthr = new Thread(new Runnable()
2367 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2368 dsktp.setupVamsasConnectedGui();
2369 dsktp.v_client.initial_update();
2377 VamsasStMenu.add(sessit);
2379 // don't show an empty menu.
2380 VamsasStMenu.setVisible(sess.length > 0);
2385 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2386 VamsasStMenu.removeAll();
2387 VamsasStMenu.setVisible(false);
2392 // Not interested in the content. Just hide ourselves.
2393 VamsasStMenu.setVisible(false);
2398 public void vamsasSave_actionPerformed(ActionEvent e)
2400 // TODO: JAL-3048 not needed for Jalview-JS
2402 if (v_client != null)
2404 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2405 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2408 chooser.setFileView(new JalviewFileView());
2409 chooser.setDialogTitle(MessageManager
2410 .getString("label.save_vamsas_document_archive"));
2412 int value = chooser.showSaveDialog(this);
2414 if (value == JalviewFileChooser.APPROVE_OPTION)
2416 java.io.File choice = chooser.getSelectedFile();
2417 JPanel progpanel = addProgressPanel(MessageManager
2418 .formatMessage("label.saving_vamsas_doc", new Object[]
2419 { choice.getName() }));
2420 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2421 String warnmsg = null;
2422 String warnttl = null;
2425 v_client.vclient.storeDocument(choice);
2428 warnttl = "Serious Problem saving Vamsas Document";
2429 warnmsg = ex.toString();
2430 jalview.bin.Cache.log
2431 .error("Error Whilst saving document to " + choice, ex);
2433 } catch (Exception ex)
2435 warnttl = "Problem saving Vamsas Document.";
2436 warnmsg = ex.toString();
2437 jalview.bin.Cache.log.warn(
2438 "Exception Whilst saving document to " + choice, ex);
2441 removeProgressPanel(progpanel);
2442 if (warnmsg != null)
2444 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2446 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2452 JPanel vamUpdate = null;
2455 * hide vamsas user gui bits when a vamsas document event is being handled.
2458 * true to hide gui, false to reveal gui
2460 public void setVamsasUpdate(boolean b)
2462 Cache.log.debug("Setting gui for Vamsas update "
2463 + (b ? "in progress" : "finished"));
2465 if (vamUpdate != null)
2467 this.removeProgressPanel(vamUpdate);
2471 vamUpdate = this.addProgressPanel(
2472 MessageManager.getString("label.updating_vamsas_session"));
2474 vamsasStart.setVisible(!b);
2475 vamsasStop.setVisible(!b);
2476 vamsasSave.setVisible(!b);
2479 public JInternalFrame[] getAllFrames()
2481 return getDesktopPane().getAllFrames();
2485 * Checks the given url to see if it gives a response indicating that the user
2486 * should be informed of a new questionnaire.
2490 public void checkForQuestionnaire(String url)
2492 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2493 // javax.swing.SwingUtilities.invokeLater(jvq);
2494 new Thread(jvq).start();
2497 public void checkURLLinks()
2499 // Thread off the URL link checker
2500 addDialogThread(new Runnable()
2505 if (Cache.getDefault("CHECKURLLINKS", true))
2507 // check what the actual links are - if it's just the default don't
2508 // bother with the warning
2509 List<String> links = Preferences.sequenceUrlLinks
2512 // only need to check links if there is one with a
2513 // SEQUENCE_ID which is not the default EMBL_EBI link
2514 ListIterator<String> li = links.listIterator();
2515 boolean check = false;
2516 List<JLabel> urls = new ArrayList<>();
2517 while (li.hasNext())
2519 String link = li.next();
2520 if (link.contains(UrlConstants.SEQUENCE_ID)
2521 && !UrlConstants.isDefaultString(link))
2524 int barPos = link.indexOf("|");
2525 String urlMsg = barPos == -1 ? link
2526 : link.substring(0, barPos) + ": "
2527 + link.substring(barPos + 1);
2528 urls.add(new JLabel(urlMsg));
2536 // ask user to check in case URL links use old style tokens
2537 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2538 JPanel msgPanel = new JPanel();
2539 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2540 msgPanel.add(Box.createVerticalGlue());
2541 JLabel msg = new JLabel(MessageManager
2542 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2543 JLabel msg2 = new JLabel(MessageManager
2544 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2546 for (JLabel url : urls)
2552 final JCheckBox jcb = new JCheckBox(
2553 MessageManager.getString("label.do_not_display_again"));
2554 jcb.addActionListener(new ActionListener()
2557 public void actionPerformed(ActionEvent e)
2559 // update Cache settings for "don't show this again"
2560 boolean showWarningAgain = !jcb.isSelected();
2561 Cache.setProperty("CHECKURLLINKS",
2562 Boolean.valueOf(showWarningAgain).toString());
2567 JvOptionPane.showMessageDialog(Desktop.getDesktopPane(), msgPanel,
2569 .getString("label.SEQUENCE_ID_no_longer_used"),
2570 JvOptionPane.WARNING_MESSAGE);
2577 * Proxy class for JDesktopPane which optionally displays the current memory
2578 * usage and highlights the desktop area with a red bar if free memory runs low.
2582 public class MyDesktopPane extends JDesktopPane
2585 private static final float ONE_MB = 1048576f;
2587 boolean showMemoryUsage = false;
2591 java.text.NumberFormat df;
2593 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2596 public MyDesktopPane(boolean showMemoryUsage)
2598 showMemoryUsage(showMemoryUsage);
2601 public void showMemoryUsage(boolean showMemory)
2603 this.showMemoryUsage = showMemory;
2606 Thread worker = new Thread(this);
2612 public boolean isShowMemoryUsage()
2614 return showMemoryUsage;
2620 df = java.text.NumberFormat.getNumberInstance();
2621 df.setMaximumFractionDigits(2);
2622 runtime = Runtime.getRuntime();
2624 while (showMemoryUsage)
2628 maxMemory = runtime.maxMemory() / ONE_MB;
2629 allocatedMemory = runtime.totalMemory() / ONE_MB;
2630 freeMemory = runtime.freeMemory() / ONE_MB;
2631 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2633 percentUsage = (totalFreeMemory / maxMemory) * 100;
2635 // if (percentUsage < 20)
2637 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2639 // instance.set.setBorder(border1);
2642 // sleep after showing usage
2644 } catch (Exception ex)
2646 ex.printStackTrace();
2652 public void paintComponent(Graphics g)
2654 if (showMemoryUsage && g != null && df != null)
2656 if (percentUsage < 20)
2658 g.setColor(Color.red);
2660 FontMetrics fm = g.getFontMetrics();
2663 g.drawString(MessageManager.formatMessage("label.memory_stats",
2665 { df.format(totalFreeMemory), df.format(maxMemory),
2666 df.format(percentUsage) }),
2667 10, getHeight() - fm.getHeight());
2674 * Accessor method to quickly get all the AlignmentFrames loaded.
2676 * @return an array of AlignFrame, or null if none found
2678 public static AlignFrame[] getAlignFrames()
2680 if (Jalview.isHeadlessMode())
2682 // Desktop.getDesktop() is null in headless mode
2683 return new AlignFrame[] { Jalview.getCurrentAlignFrame() };
2686 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2692 List<AlignFrame> avp = new ArrayList<>();
2694 for (int i = frames.length - 1; i > -1; i--)
2696 if (frames[i] instanceof AlignFrame)
2698 avp.add((AlignFrame) frames[i]);
2700 else if (frames[i] instanceof SplitFrame)
2703 * Also check for a split frame containing an AlignFrame
2705 GSplitFrame sf = (GSplitFrame) frames[i];
2706 if (sf.getTopFrame() instanceof AlignFrame)
2708 avp.add((AlignFrame) sf.getTopFrame());
2710 if (sf.getBottomFrame() instanceof AlignFrame)
2712 avp.add((AlignFrame) sf.getBottomFrame());
2716 if (avp.size() == 0)
2720 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2725 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2729 public GStructureViewer[] getJmols()
2731 JInternalFrame[] frames = Desktop.getDesktopPane().getAllFrames();
2737 List<GStructureViewer> avp = new ArrayList<>();
2739 for (int i = frames.length - 1; i > -1; i--)
2741 if (frames[i] instanceof AppJmol)
2743 GStructureViewer af = (GStructureViewer) frames[i];
2747 if (avp.size() == 0)
2751 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2756 * Add Groovy Support to Jalview
2759 public void groovyShell_actionPerformed()
2763 openGroovyConsole();
2764 } catch (Exception ex)
2766 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2767 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
2769 MessageManager.getString("label.couldnt_create_groovy_shell"),
2770 MessageManager.getString("label.groovy_support_failed"),
2771 JvOptionPane.ERROR_MESSAGE);
2776 * Open the Groovy console
2778 private void openGroovyConsole()
2780 if (groovyConsole == null)
2782 groovyConsole = new groovy.ui.Console();
2783 groovyConsole.setVariable("Jalview", this);
2784 groovyConsole.run();
2787 * We allow only one console at a time, so that AlignFrame menu option
2788 * 'Calculate | Run Groovy script' is unambiguous.
2789 * Disable 'Groovy Console', and enable 'Run script', when the console is
2790 * opened, and the reverse when it is closed
2792 Window window = (Window) groovyConsole.getFrame();
2793 window.addWindowListener(new WindowAdapter()
2796 public void windowClosed(WindowEvent e)
2799 * rebind CMD-Q from Groovy Console to Jalview Quit
2802 enableExecuteGroovy(false);
2808 * show Groovy console window (after close and reopen)
2810 ((Window) groovyConsole.getFrame()).setVisible(true);
2813 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2814 * and disable opening a second console
2816 enableExecuteGroovy(true);
2820 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2823 protected void addQuitHandler()
2825 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2826 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2827 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2829 getRootPane().getActionMap().put("Quit", new AbstractAction()
2832 public void actionPerformed(ActionEvent e)
2840 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2843 * true if Groovy console is open
2845 public void enableExecuteGroovy(boolean enabled)
2848 * disable opening a second Groovy console
2849 * (or re-enable when the console is closed)
2851 groovyShell.setEnabled(!enabled);
2853 AlignFrame[] alignFrames = getAlignFrames();
2854 if (alignFrames != null)
2856 for (AlignFrame af : alignFrames)
2858 af.setGroovyEnabled(enabled);
2864 * Progress bars managed by the IProgressIndicator method.
2866 private Hashtable<Long, JPanel> progressBars;
2868 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2873 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2876 public void setProgressBar(String message, long id)
2878 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2880 if (progressBars == null)
2882 progressBars = new Hashtable<>();
2883 progressBarHandlers = new Hashtable<>();
2886 if (progressBars.get(new Long(id)) != null)
2888 JPanel panel = progressBars.remove(new Long(id));
2889 if (progressBarHandlers.contains(new Long(id)))
2891 progressBarHandlers.remove(new Long(id));
2893 removeProgressPanel(panel);
2897 progressBars.put(new Long(id), addProgressPanel(message));
2904 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2905 * jalview.gui.IProgressIndicatorHandler)
2908 public void registerHandler(final long id,
2909 final IProgressIndicatorHandler handler)
2911 if (progressBarHandlers == null
2912 || !progressBars.containsKey(new Long(id)))
2914 throw new Error(MessageManager.getString(
2915 "error.call_setprogressbar_before_registering_handler"));
2917 progressBarHandlers.put(new Long(id), handler);
2918 final JPanel progressPanel = progressBars.get(new Long(id));
2919 if (handler.canCancel())
2921 JButton cancel = new JButton(
2922 MessageManager.getString("action.cancel"));
2923 final IProgressIndicator us = this;
2924 cancel.addActionListener(new ActionListener()
2928 public void actionPerformed(ActionEvent e)
2930 handler.cancelActivity(id);
2931 us.setProgressBar(MessageManager
2932 .formatMessage("label.cancelled_params", new Object[]
2933 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2937 progressPanel.add(cancel, BorderLayout.EAST);
2943 * @return true if any progress bars are still active
2946 public boolean operationInProgress()
2948 if (progressBars != null && progressBars.size() > 0)
2956 * This will return the first AlignFrame holding the given viewport instance. It
2957 * will break if there are more than one AlignFrames viewing a particular av.
2960 * @return alignFrame for viewport
2962 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2964 if (getDesktopPane() != null)
2966 AlignmentPanel[] aps = getAlignmentPanels(
2967 viewport.getSequenceSetId());
2968 for (int panel = 0; aps != null && panel < aps.length; panel++)
2970 if (aps[panel] != null && aps[panel].av == viewport)
2972 return aps[panel].alignFrame;
2979 public VamsasApplication getVamsasApplication()
2986 * flag set if jalview GUI is being operated programmatically
2988 private boolean inBatchMode = false;
2991 * check if jalview GUI is being operated programmatically
2993 * @return inBatchMode
2995 public boolean isInBatchMode()
3001 * set flag if jalview GUI is being operated programmatically
3003 * @param inBatchMode
3005 public void setInBatchMode(boolean inBatchMode)
3007 this.inBatchMode = inBatchMode;
3010 public void startServiceDiscovery()
3012 startServiceDiscovery(false);
3015 public void startServiceDiscovery(boolean blocking)
3017 boolean alive = true;
3018 Thread t0 = null, t1 = null, t2 = null;
3019 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3022 // todo: changesupport handlers need to be transferred
3023 if (discoverer == null)
3025 discoverer = new jalview.ws.jws1.Discoverer();
3026 // register PCS handler for getDesktop().
3027 discoverer.addPropertyChangeListener(changeSupport);
3029 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3030 // until we phase out completely
3031 (t0 = new Thread(discoverer)).start();
3034 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3036 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3037 .startDiscoverer(changeSupport);
3041 // TODO: do rest service discovery
3050 } catch (Exception e)
3053 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3054 || (t3 != null && t3.isAlive())
3055 || (t0 != null && t0.isAlive());
3061 * called to check if the service discovery process completed successfully.
3065 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3067 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3069 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3070 .getErrorMessages();
3073 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3075 if (serviceChangedDialog == null)
3077 // only run if we aren't already displaying one of these.
3078 addDialogThread(serviceChangedDialog = new Runnable()
3085 * JalviewDialog jd =new JalviewDialog() {
3087 * @Override protected void cancelPressed() { // TODO
3088 * Auto-generated method stub
3090 * }@Override protected void okPressed() { // TODO
3091 * Auto-generated method stub
3093 * }@Override protected void raiseClosed() { // TODO
3094 * Auto-generated method stub
3096 * } }; jd.initDialogFrame(new
3097 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3098 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3099 * + " or mis-configured HTTP proxy settings.<br/>" +
3100 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3102 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3103 * ), true, true, "Web Service Configuration Problem", 450,
3106 * jd.waitForInput();
3108 JvOptionPane.showConfirmDialog(Desktop.getDesktopPane(),
3109 new JLabel("<html><table width=\"450\"><tr><td>"
3110 + ermsg + "</td></tr></table>"
3111 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3112 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3113 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3114 + " Tools->Preferences dialog box to change them.</p></html>"),
3115 "Web Service Configuration Problem",
3116 JvOptionPane.DEFAULT_OPTION,
3117 JvOptionPane.ERROR_MESSAGE);
3118 serviceChangedDialog = null;
3127 "Errors reported by JABA discovery service. Check web services preferences.\n"
3134 Runnable serviceChangedDialog = null;
3137 * start a thread to open a URL in the configured browser. Pops up a warning
3138 * dialog to the user if there is an exception when calling out to the browser
3143 public static void showUrl(final String url)
3145 showUrl(url, Desktop.getInstance());
3149 * Like showUrl but allows progress handler to be specified
3153 * (null) or object implementing IProgressIndicator
3155 public static void showUrl(final String url,
3156 final IProgressIndicator progress)
3158 new Thread(new Runnable()
3165 if (progress != null)
3167 progress.setProgressBar(MessageManager
3168 .formatMessage("status.opening_params", new Object[]
3169 { url }), this.hashCode());
3171 jalview.util.BrowserLauncher.openURL(url);
3172 } catch (Exception ex)
3174 JvOptionPane.showInternalMessageDialog(Desktop.getDesktopPane(),
3176 .getString("label.web_browser_not_found_unix"),
3177 MessageManager.getString("label.web_browser_not_found"),
3178 JvOptionPane.WARNING_MESSAGE);
3180 ex.printStackTrace();
3182 if (progress != null)
3184 progress.setProgressBar(null, this.hashCode());
3190 private WsParamSetManager wsparamManager = null;
3192 public static ParamManager getUserParameterStore()
3194 Desktop d = getInstance();
3195 if (d.wsparamManager == null)
3197 d.wsparamManager = new WsParamSetManager();
3199 return d.wsparamManager;
3203 * static hyperlink handler proxy method for use by Jalview's internal windows
3207 public static void hyperlinkUpdate(HyperlinkEvent e)
3209 if (e.getEventType() == EventType.ACTIVATED)
3214 url = e.getURL().toString();
3215 Desktop.showUrl(url);
3216 } catch (Exception x)
3220 if (Cache.log != null)
3222 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3227 "Couldn't handle string " + url + " as a URL.");
3230 // ignore any exceptions due to dud links.
3237 * single thread that handles display of dialogs to user.
3239 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3242 * flag indicating if dialogExecutor should try to acquire a permit
3244 volatile boolean dialogPause = true;
3249 java.util.concurrent.Semaphore block = new Semaphore(0);
3251 private static groovy.ui.Console groovyConsole;
3254 * add another dialog thread to the queue
3258 public void addDialogThread(final Runnable prompter)
3260 dialogExecutor.submit(new Runnable()
3270 } catch (InterruptedException x)
3275 if (getInstance() == null)
3281 SwingUtilities.invokeAndWait(prompter);
3282 } catch (Exception q)
3284 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3290 public void startDialogQueue()
3292 // set the flag so we don't pause waiting for another permit and semaphore
3293 // the current task to begin
3294 dialogPause = false;
3299 * Outputs an image of the desktop to file in EPS format, after prompting the
3300 * user for choice of Text or Lineart character rendering (unless a preference
3301 * has been set). The file name is generated as
3304 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3308 protected void snapShotWindow_actionPerformed(ActionEvent e)
3310 // currently the menu option to do this is not shown
3313 int width = getWidth();
3314 int height = getHeight();
3316 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3317 ImageWriterI writer = new ImageWriterI()
3320 public void exportImage(Graphics g) throws Exception
3323 Cache.log.info("Successfully written snapshot to file "
3324 + of.getAbsolutePath());
3327 String title = "View of desktop";
3328 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3330 exporter.doExport(of, this, width, height, title);
3334 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3335 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3336 * location last time the view was expanded (if any). However it does not
3337 * remember the split pane divider location - this is set to match the
3338 * 'exploding' frame.
3342 public void explodeViews(SplitFrame sf)
3344 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3345 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3346 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3348 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3350 int viewCount = topPanels.size();
3357 * Processing in reverse order works, forwards order leaves the first panels
3358 * not visible. I don't know why!
3360 for (int i = viewCount - 1; i >= 0; i--)
3363 * Make new top and bottom frames. These take over the respective
3364 * AlignmentPanel objects, including their AlignmentViewports, so the
3365 * cdna/protein relationships between the viewports is carried over to the
3368 * explodedGeometry holds the (x, y) position of the previously exploded
3369 * SplitFrame, and the (width, height) of the AlignFrame component
3371 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3372 AlignFrame newTopFrame = new AlignFrame(topPanel);
3373 newTopFrame.setSize(oldTopFrame.getSize());
3374 newTopFrame.setVisible(true);
3375 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3376 .getExplodedGeometry();
3377 if (geometry != null)
3379 newTopFrame.setSize(geometry.getSize());
3382 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3383 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3384 newBottomFrame.setSize(oldBottomFrame.getSize());
3385 newBottomFrame.setVisible(true);
3386 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3387 .getExplodedGeometry();
3388 if (geometry != null)
3390 newBottomFrame.setSize(geometry.getSize());
3393 topPanel.av.setGatherViewsHere(false);
3394 bottomPanel.av.setGatherViewsHere(false);
3395 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3397 if (geometry != null)
3399 splitFrame.setLocation(geometry.getLocation());
3401 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3405 * Clear references to the panels (now relocated in the new SplitFrames)
3406 * before closing the old SplitFrame.
3409 bottomPanels.clear();
3414 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3415 * back into the given SplitFrame as additional views. Note that the gathered
3416 * frames may themselves have multiple views.
3420 public void gatherViews(GSplitFrame source)
3423 * special handling of explodedGeometry for a view within a SplitFrame: - it
3424 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3425 * height) of the AlignFrame component
3427 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3428 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3429 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3430 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3431 myBottomFrame.viewport
3432 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3433 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3434 myTopFrame.viewport.setGatherViewsHere(true);
3435 myBottomFrame.viewport.setGatherViewsHere(true);
3436 String topViewId = myTopFrame.viewport.getSequenceSetId();
3437 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3439 JInternalFrame[] frames = getDesktopPane().getAllFrames();
3440 for (JInternalFrame frame : frames)
3442 if (frame instanceof SplitFrame && frame != source)
3444 SplitFrame sf = (SplitFrame) frame;
3445 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3446 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3447 boolean gatherThis = false;
3448 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3450 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3451 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3452 if (topViewId.equals(topPanel.av.getSequenceSetId())
3453 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3456 topPanel.av.setGatherViewsHere(false);
3457 bottomPanel.av.setGatherViewsHere(false);
3458 topPanel.av.setExplodedGeometry(
3459 new Rectangle(sf.getLocation(), topFrame.getSize()));
3460 bottomPanel.av.setExplodedGeometry(
3461 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3462 myTopFrame.addAlignmentPanel(topPanel, false);
3463 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3469 topFrame.getAlignPanels().clear();
3470 bottomFrame.getAlignPanels().clear();
3477 * The dust settles...give focus to the tab we did this from.
3479 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3482 public static groovy.ui.Console getGroovyConsole()
3484 return groovyConsole;
3488 * handles the payload of a drag and drop event.
3490 * TODO refactor to desktop utilities class
3493 * - Data source strings extracted from the drop event
3495 * - protocol for each data source extracted from the drop event
3499 * - the payload from the drop event
3502 @SuppressWarnings("unchecked")
3503 public static void transferFromDropTarget(List<Object> files,
3504 List<DataSourceType> protocols, DropTargetDropEvent evt,
3505 Transferable t) throws Exception
3508 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3510 // DataFlavor[] flavors = t.getTransferDataFlavors();
3511 // for (int i = 0; i < flavors.length; i++) {
3512 // if (flavors[i].isFlavorJavaFileListType()) {
3513 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3514 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3515 // for (int j = 0; j < list.size(); j++) {
3516 // File file = (File) list.get(j);
3517 // byte[] data = getDroppedFileBytes(file);
3518 // fileName.setText(file.getName() + " - " + data.length + " " +
3519 // evt.getLocation());
3520 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3521 // target.setText(new String(data));
3523 // dtde.dropComplete(true);
3528 DataFlavor uriListFlavor = new DataFlavor(
3529 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3532 urlFlavour = new DataFlavor(
3533 "application/x-java-url; class=java.net.URL");
3534 } catch (ClassNotFoundException cfe)
3536 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3539 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3544 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3545 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3546 // means url may be null.
3549 protocols.add(DataSourceType.URL);
3550 files.add(url.toString());
3551 Cache.log.debug("Drop handled as URL dataflavor "
3552 + files.get(files.size() - 1));
3557 if (Platform.isAMacAndNotJS())
3560 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3564 } catch (Throwable ex)
3566 Cache.log.debug("URL drop handler failed.", ex);
3569 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3571 // Works on Windows and MacOSX
3572 Cache.log.debug("Drop handled as javaFileListFlavor");
3573 for (Object file : (List<Object>) t
3574 .getTransferData(DataFlavor.javaFileListFlavor))
3577 protocols.add(DataSourceType.FILE);
3582 // Unix like behaviour
3583 boolean added = false;
3585 if (t.isDataFlavorSupported(uriListFlavor))
3587 Cache.log.debug("Drop handled as uriListFlavor");
3588 // This is used by Unix drag system
3589 data = (String) t.getTransferData(uriListFlavor);
3593 // fallback to text: workaround - on OSX where there's a JVM bug
3594 Cache.log.debug("standard URIListFlavor failed. Trying text");
3595 // try text fallback
3596 DataFlavor textDf = new DataFlavor(
3597 "text/plain;class=java.lang.String");
3598 if (t.isDataFlavorSupported(textDf))
3600 data = (String) t.getTransferData(textDf);
3603 Cache.log.debug("Plain text drop content returned "
3604 + (data == null ? "Null - failed" : data));
3609 while (protocols.size() < files.size())
3611 Cache.log.debug("Adding missing FILE protocol for "
3612 + files.get(protocols.size()));
3613 protocols.add(DataSourceType.FILE);
3615 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3616 data, "\r\n"); st.hasMoreTokens();)
3619 String s = st.nextToken();
3620 if (s.startsWith("#"))
3622 // the line is a comment (as per the RFC 2483)
3625 java.net.URI uri = new java.net.URI(s);
3626 if (uri.getScheme().toLowerCase().startsWith("http"))
3628 protocols.add(DataSourceType.URL);
3629 files.add(uri.toString());
3633 // otherwise preserve old behaviour: catch all for file objects
3634 java.io.File file = new java.io.File(uri);
3635 protocols.add(DataSourceType.FILE);
3636 files.add(file.toString());
3641 if (Cache.log.isDebugEnabled())
3643 if (data == null || !added)
3646 if (t.getTransferDataFlavors() != null
3647 && t.getTransferDataFlavors().length > 0)
3650 "Couldn't resolve drop data. Here are the supported flavors:");
3651 for (DataFlavor fl : t.getTransferDataFlavors())
3654 "Supported transfer dataflavor: " + fl.toString());
3655 Object df = t.getTransferData(fl);
3658 Cache.log.debug("Retrieves: " + df);
3662 Cache.log.debug("Retrieved nothing");
3668 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3674 if (Platform.isWindowsAndNotJS())
3676 Cache.log.debug("Scanning dropped content for Windows Link Files");
3678 // resolve any .lnk files in the file drop
3679 for (int f = 0; f < files.size(); f++)
3681 String source = files.get(f).toString().toLowerCase();
3682 if (protocols.get(f).equals(DataSourceType.FILE)
3683 && (source.endsWith(".lnk") || source.endsWith(".url")
3684 || source.endsWith(".site")))
3688 Object obj = files.get(f);
3689 File lf = (obj instanceof File ? (File) obj
3690 : new File((String) obj));
3691 // process link file to get a URL
3692 Cache.log.debug("Found potential link file: " + lf);
3693 WindowsShortcut wscfile = new WindowsShortcut(lf);
3694 String fullname = wscfile.getRealFilename();
3695 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3696 files.set(f, fullname);
3697 Cache.log.debug("Parsed real filename " + fullname
3698 + " to extract protocol: " + protocols.get(f));
3699 } catch (Exception ex)
3702 "Couldn't parse " + files.get(f) + " as a link file.",
3711 * Sets the Preferences property for experimental features to True or False
3712 * depending on the state of the controlling menu item
3715 protected void showExperimental_actionPerformed(boolean selected)
3717 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3721 * Answers a (possibly empty) list of any structure viewer frames (currently for
3722 * either Jmol or Chimera) which are currently open. This may optionally be
3723 * restricted to viewers of a specified class, or viewers linked to a specified
3727 * if not null, only return viewers linked to this panel
3728 * @param structureViewerClass
3729 * if not null, only return viewers of this class
3732 public List<StructureViewerBase> getStructureViewers(
3733 AlignmentPanel apanel,
3734 Class<? extends StructureViewerBase> structureViewerClass)
3736 List<StructureViewerBase> result = new ArrayList<>();
3737 JInternalFrame[] frames = Desktop.getInstance().getAllFrames();
3739 for (JInternalFrame frame : frames)
3741 if (frame instanceof StructureViewerBase)
3743 if (structureViewerClass == null
3744 || structureViewerClass.isInstance(frame))
3747 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3749 result.add((StructureViewerBase) frame);