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.FileWriter;
86 import java.io.IOException;
88 import java.util.ArrayList;
89 import java.util.HashMap;
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.JInternalFrame;
112 import javax.swing.JLabel;
113 import javax.swing.JMenuItem;
114 import javax.swing.JPanel;
115 import javax.swing.JPopupMenu;
116 import javax.swing.JProgressBar;
117 import javax.swing.JTextField;
118 import javax.swing.KeyStroke;
119 import javax.swing.SwingUtilities;
120 import javax.swing.event.HyperlinkEvent;
121 import javax.swing.event.HyperlinkEvent.EventType;
122 import javax.swing.event.InternalFrameAdapter;
123 import javax.swing.event.InternalFrameEvent;
124 import javax.swing.event.MenuEvent;
125 import javax.swing.event.MenuListener;
127 import org.stackoverflowusers.file.WindowsShortcut;
134 * @version $Revision: 1.155 $
136 public class Desktop extends jalview.jbgui.GDesktop
137 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
138 jalview.api.StructureSelectionManagerProvider
140 private static int DEFAULT_MIN_WIDTH = 300;
142 private static int DEFAULT_MIN_HEIGHT = 250;
144 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
146 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
148 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
150 protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
152 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
154 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
157 * news reader - null if it was never started.
159 private BlogReader jvnews = null;
161 private File projectFile;
165 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
167 public void addJalviewPropertyChangeListener(
168 PropertyChangeListener listener)
170 changeSupport.addJalviewPropertyChangeListener(listener);
174 * @param propertyName
176 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
177 * java.beans.PropertyChangeListener)
179 public void addJalviewPropertyChangeListener(String propertyName,
180 PropertyChangeListener listener)
182 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
186 * @param propertyName
188 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
189 * java.beans.PropertyChangeListener)
191 public void removeJalviewPropertyChangeListener(String propertyName,
192 PropertyChangeListener listener)
194 changeSupport.removeJalviewPropertyChangeListener(propertyName,
198 /** Singleton Desktop instance */
199 public static Desktop instance;
201 public static MyDesktopPane desktop;
203 public static MyDesktopPane getDesktop()
205 // BH 2018 could use currentThread() here as a reference to a
206 // Hashtable<Thread, MyDesktopPane> in JavaScript
210 static int openFrameCount = 0;
212 static final int xOffset = 30;
214 static final int yOffset = 30;
216 public static jalview.ws.jws1.Discoverer discoverer;
218 public static Object[] jalviewClipboard;
220 public static boolean internalCopy = false;
222 static int fileLoadingCount = 0;
224 class MyDesktopManager implements DesktopManager
227 private DesktopManager delegate;
229 public MyDesktopManager(DesktopManager delegate)
231 this.delegate = delegate;
235 public void activateFrame(JInternalFrame f)
239 delegate.activateFrame(f);
240 } catch (NullPointerException npe)
242 Point p = getMousePosition();
243 instance.showPasteMenu(p.x, p.y);
248 public void beginDraggingFrame(JComponent f)
250 delegate.beginDraggingFrame(f);
254 public void beginResizingFrame(JComponent f, int direction)
256 delegate.beginResizingFrame(f, direction);
260 public void closeFrame(JInternalFrame f)
262 delegate.closeFrame(f);
266 public void deactivateFrame(JInternalFrame f)
268 delegate.deactivateFrame(f);
272 public void deiconifyFrame(JInternalFrame f)
274 delegate.deiconifyFrame(f);
278 public void dragFrame(JComponent f, int newX, int newY)
284 delegate.dragFrame(f, newX, newY);
288 public void endDraggingFrame(JComponent f)
290 delegate.endDraggingFrame(f);
295 public void endResizingFrame(JComponent f)
297 delegate.endResizingFrame(f);
302 public void iconifyFrame(JInternalFrame f)
304 delegate.iconifyFrame(f);
308 public void maximizeFrame(JInternalFrame f)
310 delegate.maximizeFrame(f);
314 public void minimizeFrame(JInternalFrame f)
316 delegate.minimizeFrame(f);
320 public void openFrame(JInternalFrame f)
322 delegate.openFrame(f);
326 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
333 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
337 public void setBoundsForFrame(JComponent f, int newX, int newY,
338 int newWidth, int newHeight)
340 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
343 // All other methods, simply delegate
348 * Creates a new Desktop object.
354 * A note to implementors. It is ESSENTIAL that any activities that might
355 * block are spawned off as threads rather than waited for during this
359 if (!Platform.isJS())
361 doVamsasClientCheck();
364 doConfigureStructurePrefs();
365 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
367 if (!Platform.isAMac())
369 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
373 this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
379 APQHandlers.setAPQHandlers(this);
380 } catch (Exception e)
382 System.out.println("Cannot set APQHandlers");
383 // e.printStackTrace();
384 } catch (Throwable t)
386 System.out.println("Cannot set APQHandlers");
387 // t.printStackTrace();
391 addWindowListener(new WindowAdapter()
395 public void windowClosing(WindowEvent ev)
401 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
404 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
406 desktop = new MyDesktopPane(selmemusage);
408 showMemusage.setSelected(selmemusage);
409 desktop.setBackground(Color.white);
411 getContentPane().setLayout(new BorderLayout());
412 // alternate config - have scrollbars - see notes in JAL-153
413 // JScrollPane sp = new JScrollPane();
414 // sp.getViewport().setView(desktop);
415 // getContentPane().add(sp, BorderLayout.CENTER);
417 // BH 2018 - just an experiment to try unclipped JInternalFrames.
420 getRootPane().putClientProperty("swingjs.overflow.hidden", "false");
423 getContentPane().add(desktop, BorderLayout.CENTER);
424 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
426 // This line prevents Windows Look&Feel resizing all new windows to maximum
427 // if previous window was maximised
428 desktop.setDesktopManager(new MyDesktopManager(
429 (Platform.isWindowsAndNotJS() ? new DefaultDesktopManager()
430 : Platform.isAMacAndNotJS()
431 ? new AquaInternalFrameManager(
432 desktop.getDesktopManager())
433 : desktop.getDesktopManager())));
435 Rectangle dims = getLastKnownDimensions("");
442 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
443 int xPos = Math.max(5, (screenSize.width - 900) / 2);
444 int yPos = Math.max(5, (screenSize.height - 650) / 2);
445 setBounds(xPos, yPos, 900, 650);
448 if (!Platform.isJS())
456 jconsole = new Console(this, showjconsole);
457 // add essential build information
458 jconsole.setHeader("Jalview Version: "
459 + jalview.bin.Cache.getProperty("VERSION") + "\n"
460 + "Jalview Installation: "
461 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
462 + "\n" + "Build Date: "
463 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
464 + "Java version: " + System.getProperty("java.version") + "\n"
465 + System.getProperty("os.arch") + " "
466 + System.getProperty("os.name") + " "
467 + System.getProperty("os.version")
468 + (jalview.bin.Cache.getProperty("VERSION").equals("DEVELOPMENT")
470 + System.getProperty(
472 + File.separator + "bin"
473 + File.separator + "java"
476 showConsole(showjconsole);
478 showNews.setVisible(false);
480 experimentalFeatures.setSelected(showExperimental());
482 getIdentifiersOrgData();
486 // Spawn a thread that shows the splashscreen
488 SwingUtilities.invokeLater(new Runnable()
497 // Thread off a new instance of the file chooser - this reduces the time
498 // it takes to open it later on.
499 new Thread(new Runnable()
504 Cache.log.debug("Filechooser init thread started.");
505 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
506 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
508 Cache.log.debug("Filechooser init thread finished.");
511 // Add the service change listener
512 changeSupport.addJalviewPropertyChangeListener("services",
513 new PropertyChangeListener()
517 public void propertyChange(PropertyChangeEvent evt)
519 Cache.log.debug("Firing service changed event for "
520 + evt.getNewValue());
521 JalviewServicesChanged(evt);
528 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
530 this.addWindowListener(new WindowAdapter()
533 public void windowClosing(WindowEvent evt)
540 this.addMouseListener(ma = new MouseAdapter()
543 public void mousePressed(MouseEvent evt)
545 if (evt.isPopupTrigger()) // Mac
547 showPasteMenu(evt.getX(), evt.getY());
552 public void mouseReleased(MouseEvent evt)
554 if (evt.isPopupTrigger()) // Windows
556 showPasteMenu(evt.getX(), evt.getY());
560 desktop.addMouseListener(ma);
565 * Answers true if user preferences to enable experimental features is True
570 public boolean showExperimental()
572 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
573 Boolean.FALSE.toString());
574 return Boolean.valueOf(experimental).booleanValue();
577 public void doConfigureStructurePrefs()
579 // configure services
580 StructureSelectionManager ssm = StructureSelectionManager
581 .getStructureSelectionManager(this);
582 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
584 ssm.setAddTempFacAnnot(jalview.bin.Cache
585 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
586 ssm.setProcessSecondaryStructure(jalview.bin.Cache
587 .getDefault(Preferences.STRUCT_FROM_PDB, true));
588 ssm.setSecStructServices(
589 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
593 ssm.setAddTempFacAnnot(false);
594 ssm.setProcessSecondaryStructure(false);
595 ssm.setSecStructServices(false);
599 public void checkForNews()
601 final Desktop me = this;
602 // Thread off the news reader, in case there are connection problems.
603 new Thread(new Runnable()
608 Cache.log.debug("Starting news thread.");
609 jvnews = new BlogReader(me);
610 showNews.setVisible(true);
611 Cache.log.debug("Completed news thread.");
616 public void getIdentifiersOrgData()
618 // Thread off the identifiers fetcher
619 new Thread(new Runnable()
624 Cache.log.debug("Downloading data from identifiers.org");
625 UrlDownloadClient client = new UrlDownloadClient();
628 client.download(IdOrgSettings.getUrl(),
629 IdOrgSettings.getDownloadLocation());
630 } catch (IOException e)
632 Cache.log.debug("Exception downloading identifiers.org data"
641 protected void showNews_actionPerformed(ActionEvent e)
643 showNews(showNews.isSelected());
646 void showNews(boolean visible)
648 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
649 showNews.setSelected(visible);
650 if (visible && !jvnews.isVisible())
652 new Thread(new Runnable()
657 long now = System.currentTimeMillis();
658 Desktop.instance.setProgressBar(
659 MessageManager.getString("status.refreshing_news"), now);
660 jvnews.refreshNews();
661 Desktop.instance.setProgressBar(null, now);
669 * recover the last known dimensions for a jalview window
672 * - empty string is desktop, all other windows have unique prefix
673 * @return null or last known dimensions scaled to current geometry (if last
674 * window geom was known)
676 Rectangle getLastKnownDimensions(String windowName)
678 // TODO: lock aspect ratio for scaling desktop Bug #0058199
679 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
680 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
681 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
682 String width = jalview.bin.Cache
683 .getProperty(windowName + "SCREEN_WIDTH");
684 String height = jalview.bin.Cache
685 .getProperty(windowName + "SCREEN_HEIGHT");
686 if ((x != null) && (y != null) && (width != null) && (height != null))
688 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
689 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
690 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
692 // attempt #1 - try to cope with change in screen geometry - this
693 // version doesn't preserve original jv aspect ratio.
694 // take ratio of current screen size vs original screen size.
695 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
696 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
697 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
698 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
699 // rescale the bounds depending upon the current screen geometry.
700 ix = (int) (ix * sw);
701 iw = (int) (iw * sw);
702 iy = (int) (iy * sh);
703 ih = (int) (ih * sh);
704 while (ix >= screenSize.width)
706 jalview.bin.Cache.log.debug(
707 "Window geometry location recall error: shifting horizontal to within screenbounds.");
708 ix -= screenSize.width;
710 while (iy >= screenSize.height)
712 jalview.bin.Cache.log.debug(
713 "Window geometry location recall error: shifting vertical to within screenbounds.");
714 iy -= screenSize.height;
716 jalview.bin.Cache.log.debug(
717 "Got last known dimensions for " + windowName + ": x:" + ix
718 + " y:" + iy + " width:" + iw + " height:" + ih);
720 // return dimensions for new instance
721 return new Rectangle(ix, iy, iw, ih);
726 private void doVamsasClientCheck()
728 if (Cache.vamsasJarsPresent())
730 setupVamsasDisconnectedGui();
731 VamsasMenu.setVisible(true);
732 final Desktop us = this;
733 VamsasMenu.addMenuListener(new MenuListener()
735 // this listener remembers when the menu was first selected, and
736 // doesn't rebuild the session list until it has been cleared and
738 boolean refresh = true;
741 public void menuCanceled(MenuEvent e)
747 public void menuDeselected(MenuEvent e)
753 public void menuSelected(MenuEvent e)
757 us.buildVamsasStMenu();
762 vamsasStart.setVisible(true);
766 void showPasteMenu(int x, int y)
768 JPopupMenu popup = new JPopupMenu();
769 JMenuItem item = new JMenuItem(
770 MessageManager.getString("label.paste_new_window"));
771 item.addActionListener(new ActionListener()
774 public void actionPerformed(ActionEvent evt)
781 popup.show(this, x, y);
788 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
789 Transferable contents = c.getContents(this);
791 if (contents != null)
793 String file = (String) contents
794 .getTransferData(DataFlavor.stringFlavor);
796 FileFormatI format = new IdentifyFile().identify(file,
797 DataSourceType.PASTE);
799 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
802 } catch (Exception ex)
805 "Unable to paste alignment from system clipboard:\n" + ex);
810 * Adds and opens the given frame to the desktop
821 public static synchronized void addInternalFrame(
822 final JInternalFrame frame, String title, int w, int h)
824 addInternalFrame(frame, title, true, w, h, true, false);
828 * Add an internal frame to the Jalview desktop
835 * When true, display frame immediately, otherwise, caller must call
836 * setVisible themselves.
842 public static synchronized void addInternalFrame(
843 final JInternalFrame frame, String title, boolean makeVisible,
846 addInternalFrame(frame, title, makeVisible, w, h, true, false);
850 * Add an internal frame to the Jalview desktop and make it visible
863 public static synchronized void addInternalFrame(
864 final JInternalFrame frame, String title, int w, int h,
867 addInternalFrame(frame, title, true, w, h, resizable, false);
871 * Add an internal frame to the Jalview desktop
878 * When true, display frame immediately, otherwise, caller must call
879 * setVisible themselves.
886 * @param ignoreMinSize
887 * Do not set the default minimum size for frame
889 public static synchronized void addInternalFrame(
890 final JInternalFrame frame, String title, boolean makeVisible,
891 int w, int h, boolean resizable, boolean ignoreMinSize)
894 // TODO: allow callers to determine X and Y position of frame (eg. via
896 // TODO: consider fixing method to update entries in the window submenu with
897 // the current window title
899 frame.setTitle(title);
900 if (frame.getWidth() < 1 || frame.getHeight() < 1)
904 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
905 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
906 // IF JALVIEW IS RUNNING HEADLESS
907 // ///////////////////////////////////////////////
908 if (instance == null || (System.getProperty("java.awt.headless") != null
909 && System.getProperty("java.awt.headless").equals("true")))
918 frame.setMinimumSize(
919 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
921 // Set default dimension for Alignment Frame window.
922 // The Alignment Frame window could be added from a number of places,
924 // I did this here in order not to miss out on any Alignment frame.
925 if (frame instanceof AlignFrame)
927 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
928 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
932 frame.setVisible(makeVisible);
933 frame.setClosable(true);
934 frame.setResizable(resizable);
935 frame.setMaximizable(resizable);
936 frame.setIconifiable(resizable);
937 frame.setOpaque(Platform.isJS());
939 if (frame.getX() < 1 && frame.getY() < 1)
941 frame.setLocation(xOffset * openFrameCount,
942 yOffset * ((openFrameCount - 1) % 10) + yOffset);
946 * add an entry for the new frame in the Window menu
947 * (and remove it when the frame is closed)
949 final JMenuItem menuItem = new JMenuItem(title);
950 frame.addInternalFrameListener(new InternalFrameAdapter()
953 public void internalFrameActivated(InternalFrameEvent evt)
955 JInternalFrame itf = desktop.getSelectedFrame();
958 if (itf instanceof AlignFrame)
960 Jalview.setCurrentAlignFrame((AlignFrame) itf);
967 public void internalFrameClosed(InternalFrameEvent evt)
969 PaintRefresher.RemoveComponent(frame);
972 * defensive check to prevent frames being
973 * added half off the window
975 if (openFrameCount > 0)
981 * ensure no reference to alignFrame retained by menu item listener
983 if (menuItem.getActionListeners().length > 0)
985 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
987 windowMenu.remove(menuItem);
991 menuItem.addActionListener(new ActionListener()
994 public void actionPerformed(ActionEvent e)
998 frame.setSelected(true);
999 frame.setIcon(false);
1000 } catch (java.beans.PropertyVetoException ex)
1002 // System.err.println(ex.toString());
1007 setKeyBindings(frame);
1011 windowMenu.add(menuItem);
1016 frame.setSelected(true);
1017 frame.requestFocus();
1018 } catch (java.beans.PropertyVetoException ve)
1020 } catch (java.lang.ClassCastException cex)
1023 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1029 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close the
1034 private static void setKeyBindings(JInternalFrame frame)
1036 @SuppressWarnings("serial")
1037 final Action closeAction = new AbstractAction()
1040 public void actionPerformed(ActionEvent e)
1047 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1049 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1050 InputEvent.CTRL_DOWN_MASK);
1051 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1052 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx());
1054 InputMap inputMap = frame
1055 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1056 String ctrlW = ctrlWKey.toString();
1057 inputMap.put(ctrlWKey, ctrlW);
1058 inputMap.put(cmdWKey, ctrlW);
1060 ActionMap actionMap = frame.getActionMap();
1061 actionMap.put(ctrlW, closeAction);
1065 public void lostOwnership(Clipboard clipboard, Transferable contents)
1069 Desktop.jalviewClipboard = null;
1072 internalCopy = false;
1076 public void dragEnter(DropTargetDragEvent evt)
1081 public void dragExit(DropTargetEvent evt)
1086 public void dragOver(DropTargetDragEvent evt)
1091 public void dropActionChanged(DropTargetDragEvent evt)
1102 public void drop(DropTargetDropEvent evt)
1104 boolean success = true;
1105 // JAL-1552 - acceptDrop required before getTransferable call for
1106 // Java's Transferable for native dnd
1107 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1108 Transferable t = evt.getTransferable();
1109 List<Object> files = new ArrayList<>();
1110 List<DataSourceType> protocols = new ArrayList<>();
1114 Desktop.transferFromDropTarget(files, protocols, evt, t);
1115 } catch (Exception e)
1117 e.printStackTrace();
1125 for (int i = 0; i < files.size(); i++)
1127 // BH 2018 File or String
1128 Object file = files.get(i);
1129 String fileName = file.toString();
1130 DataSourceType protocol = (protocols == null)
1131 ? DataSourceType.FILE
1133 FileFormatI format = null;
1135 if (fileName.endsWith(".jar"))
1137 format = FileFormat.Jalview;
1142 format = new IdentifyFile().identify(file, protocol);
1144 if (file instanceof File)
1146 Platform.cacheFileData((File) file);
1148 new FileLoader().LoadFile(null, file, protocol, format);
1151 } catch (Exception ex)
1156 evt.dropComplete(success); // need this to ensure input focus is properly
1157 // transfered to any new windows created
1167 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1169 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1170 JalviewFileChooser chooser = JalviewFileChooser
1171 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat, BackupFiles.getEnabled());
1173 chooser.setFileView(new JalviewFileView());
1174 chooser.setDialogTitle(
1175 MessageManager.getString("label.open_local_file"));
1176 chooser.setToolTipText(MessageManager.getString("action.open"));
1178 chooser.setResponseHandler(0, new Runnable()
1183 File selectedFile = chooser.getSelectedFile();
1184 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1186 FileFormatI format = chooser.getSelectedFormat();
1189 * Call IdentifyFile to verify the file contains what its extension implies.
1190 * Skip this step for dynamically added file formats, because
1191 * IdentifyFile does not know how to recognise them.
1193 if (FileFormats.getInstance().isIdentifiable(format))
1197 format = new IdentifyFile().identify(selectedFile,
1198 DataSourceType.FILE);
1199 } catch (FileFormatException e)
1201 // format = null; //??
1205 new FileLoader().LoadFile(viewport, selectedFile,
1206 DataSourceType.FILE, format);
1209 chooser.showOpenDialog(this);
1213 * Shows a dialog for input of a URL at which to retrieve alignment data
1218 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1220 // This construct allows us to have a wider textfield
1222 JLabel label = new JLabel(
1223 MessageManager.getString("label.input_file_url"));
1225 JPanel panel = new JPanel(new GridLayout(2, 1));
1229 * the URL to fetch is
1230 * Java: an editable combobox with history
1231 * JS: (pending JAL-3038) a plain text field
1234 String urlBase = "http://www.";
1235 if (Platform.isJS())
1237 history = new JTextField(urlBase, 35);
1246 JComboBox<String> asCombo = new JComboBox<>();
1247 asCombo.setPreferredSize(new Dimension(400, 20));
1248 asCombo.setEditable(true);
1249 asCombo.addItem(urlBase);
1250 String historyItems = Cache.getProperty("RECENT_URL");
1251 if (historyItems != null)
1253 for (String token : historyItems.split("\\t"))
1255 asCombo.addItem(token);
1262 Object[] options = new Object[] { MessageManager.getString("action.ok"),
1263 MessageManager.getString("action.cancel") };
1264 Runnable action = new Runnable()
1269 @SuppressWarnings("unchecked")
1270 String url = (history instanceof JTextField
1271 ? ((JTextField) history).getText()
1272 : ((JComboBox<String>) history).getSelectedItem()
1275 if (url.toLowerCase().endsWith(".jar"))
1277 if (viewport != null)
1279 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1280 FileFormat.Jalview);
1284 new FileLoader().LoadFile(url, DataSourceType.URL,
1285 FileFormat.Jalview);
1290 FileFormatI format = null;
1293 format = new IdentifyFile().identify(url, DataSourceType.URL);
1294 } catch (FileFormatException e)
1296 // TODO revise error handling, distinguish between
1297 // URL not found and response not valid
1302 String msg = MessageManager
1303 .formatMessage("label.couldnt_locate", url);
1304 JvOptionPane.showInternalMessageDialog(Desktop.desktop, msg,
1305 MessageManager.getString("label.url_not_found"),
1306 JvOptionPane.WARNING_MESSAGE);
1311 if (viewport != null)
1313 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1318 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1323 String dialogOption = MessageManager
1324 .getString("label.input_alignment_from_url");
1325 JvOptionPane.newOptionDialog(desktop).setResponseHandler(0, action)
1326 .showInternalDialog(panel, dialogOption,
1327 JvOptionPane.YES_NO_CANCEL_OPTION,
1328 JvOptionPane.PLAIN_MESSAGE, null, options,
1329 MessageManager.getString("action.ok"));
1333 * Opens the CutAndPaste window for the user to paste an alignment in to
1336 * - if not null, the pasted alignment is added to the current
1337 * alignment; if null, to a new alignment window
1340 public void inputTextboxMenuItem_actionPerformed(
1341 AlignmentViewPanel viewPanel)
1343 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1344 cap.setForInput(viewPanel);
1345 Desktop.addInternalFrame(cap,
1346 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1356 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1357 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1359 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1360 screen.height + "");
1361 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1362 getWidth(), getHeight()));
1364 if (jconsole != null)
1366 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1367 jconsole.stopConsole();
1371 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1374 if (dialogExecutor != null)
1376 dialogExecutor.shutdownNow();
1378 closeAll_actionPerformed(null);
1380 if (groovyConsole != null)
1382 // suppress a possible repeat prompt to save script
1383 groovyConsole.setDirty(false);
1384 groovyConsole.exit();
1389 private void storeLastKnownDimensions(String string, Rectangle jc)
1391 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1392 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1393 + " height:" + jc.height);
1395 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1396 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1397 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1398 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1408 public void aboutMenuItem_actionPerformed(ActionEvent e)
1410 // StringBuffer message = getAboutMessage(false);
1411 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1413 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1414 new Thread(new Runnable()
1419 new SplashScreen(true);
1424 public StringBuffer getAboutMessage(boolean shortv)
1426 StringBuffer message = new StringBuffer();
1427 message.append("<html>");
1430 message.append("<h1><strong>Version: "
1431 + jalview.bin.Cache.getProperty("VERSION")
1432 + "</strong></h1>");
1433 message.append("<strong>Last Updated: <em>"
1434 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1435 + "</em></strong>");
1441 message.append("<strong>Version "
1442 + jalview.bin.Cache.getProperty("VERSION")
1443 + "; last updated: "
1444 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1447 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1448 .equals("Checking"))
1450 message.append("<br>...Checking latest version...</br>");
1452 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1453 .equals(jalview.bin.Cache.getProperty("VERSION")))
1455 boolean red = false;
1456 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1457 .indexOf("automated build") == -1)
1460 // Displayed when code version and jnlp version do not match and code
1461 // version is not a development build
1462 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1465 message.append("<br>!! Version "
1466 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1468 + " is available for download from "
1469 + jalview.bin.Cache.getDefault("www.jalview.org",
1470 "http://www.jalview.org")
1474 message.append("</div>");
1477 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1479 "The Jalview Authors (See AUTHORS file for current list)")
1480 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1481 + "<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"
1482 + "<br><br>If you use Jalview, please cite:"
1483 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1484 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1485 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1491 * Action on requesting Help documentation
1494 public void documentationMenuItem_actionPerformed()
1498 if (Platform.isJS())
1500 BrowserLauncher.openURL("http://www.jalview.org/help.html");
1509 Help.showHelpWindow();
1511 } catch (Exception ex)
1513 System.err.println("Error opening help: " + ex.getMessage());
1518 public void closeAll_actionPerformed(ActionEvent e)
1520 // TODO show a progress bar while closing?
1521 JInternalFrame[] frames = desktop.getAllFrames();
1522 for (int i = 0; i < frames.length; i++)
1526 frames[i].setClosed(true);
1527 } catch (java.beans.PropertyVetoException ex)
1531 Jalview.setCurrentAlignFrame(null);
1532 System.out.println("ALL CLOSED");
1533 if (v_client != null)
1535 // TODO clear binding to vamsas document objects on close_all
1539 * reset state of singleton objects as appropriate (clear down session state
1540 * when all windows are closed)
1542 StructureSelectionManager ssm = StructureSelectionManager
1543 .getStructureSelectionManager(this);
1551 public void raiseRelated_actionPerformed(ActionEvent e)
1553 reorderAssociatedWindows(false, false);
1557 public void minimizeAssociated_actionPerformed(ActionEvent e)
1559 reorderAssociatedWindows(true, false);
1562 void closeAssociatedWindows()
1564 reorderAssociatedWindows(false, true);
1570 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1574 protected void garbageCollect_actionPerformed(ActionEvent e)
1576 // We simply collect the garbage
1577 jalview.bin.Cache.log.debug("Collecting garbage...");
1579 jalview.bin.Cache.log.debug("Finished garbage collection.");
1586 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1590 protected void showMemusage_actionPerformed(ActionEvent e)
1592 desktop.showMemoryUsage(showMemusage.isSelected());
1599 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1603 protected void showConsole_actionPerformed(ActionEvent e)
1605 showConsole(showConsole.isSelected());
1608 Console jconsole = null;
1611 * control whether the java console is visible or not
1615 void showConsole(boolean selected)
1617 // TODO: decide if we should update properties file
1618 if (jconsole != null) // BH 2018
1620 showConsole.setSelected(selected);
1621 Cache.setProperty("SHOW_JAVA_CONSOLE",
1622 Boolean.valueOf(selected).toString());
1623 jconsole.setVisible(selected);
1627 void reorderAssociatedWindows(boolean minimize, boolean close)
1629 JInternalFrame[] frames = desktop.getAllFrames();
1630 if (frames == null || frames.length < 1)
1635 AlignmentViewport source = null, target = null;
1636 if (frames[0] instanceof AlignFrame)
1638 source = ((AlignFrame) frames[0]).getCurrentView();
1640 else if (frames[0] instanceof TreePanel)
1642 source = ((TreePanel) frames[0]).getViewPort();
1644 else if (frames[0] instanceof PCAPanel)
1646 source = ((PCAPanel) frames[0]).av;
1648 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1650 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1655 for (int i = 0; i < frames.length; i++)
1658 if (frames[i] == null)
1662 if (frames[i] instanceof AlignFrame)
1664 target = ((AlignFrame) frames[i]).getCurrentView();
1666 else if (frames[i] instanceof TreePanel)
1668 target = ((TreePanel) frames[i]).getViewPort();
1670 else if (frames[i] instanceof PCAPanel)
1672 target = ((PCAPanel) frames[i]).av;
1674 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1676 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1679 if (source == target)
1685 frames[i].setClosed(true);
1689 frames[i].setIcon(minimize);
1692 frames[i].toFront();
1696 } catch (java.beans.PropertyVetoException ex)
1711 protected void preferences_actionPerformed(ActionEvent e)
1717 * Prompts the user to choose a file and then saves the Jalview state as a
1718 * Jalview project file
1721 public void saveState_actionPerformed()
1723 saveState_actionPerformed(false);
1726 public void saveState_actionPerformed(boolean saveAs)
1728 java.io.File projectFile = getProjectFile();
1729 // autoSave indicates we already have a file and don't need to ask
1730 boolean autoSave = projectFile != null && !saveAs
1731 && BackupFiles.getEnabled();
1733 // System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"',
1734 // saveAs="+saveAs+", Backups
1735 // "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1737 boolean approveSave = false;
1740 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1743 chooser.setFileView(new JalviewFileView());
1744 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1746 int value = chooser.showSaveDialog(this);
1748 if (value == JalviewFileChooser.APPROVE_OPTION)
1750 projectFile = chooser.getSelectedFile();
1751 setProjectFile(projectFile);
1756 if (approveSave || autoSave)
1758 final Desktop me = this;
1759 final java.io.File chosenFile = projectFile;
1760 new Thread(new Runnable()
1765 // TODO: refactor to Jalview desktop session controller action.
1766 setProgressBar(MessageManager.formatMessage(
1767 "label.saving_jalview_project", new Object[]
1768 { chosenFile.getName() }), chosenFile.hashCode());
1769 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1770 chosenFile.getParent());
1771 // TODO catch and handle errors for savestate
1772 // TODO prevent user from messing with the Desktop whilst we're saving
1775 boolean doBackup = BackupFiles.getEnabled();
1776 BackupFiles backupfiles = doBackup ? new BackupFiles(chosenFile) : null;
1778 new Jalview2XML().saveState(doBackup ? backupfiles.getTempFile() : chosenFile);
1782 backupfiles.setWriteSuccess(true);
1783 backupfiles.rollBackupsAndRenameTempFile();
1785 } catch (OutOfMemoryError oom)
1787 new OOMWarning("Whilst saving current state to "
1788 + chosenFile.getName(), oom);
1789 } catch (Exception ex)
1791 Cache.log.error("Problems whilst trying to save to "
1792 + chosenFile.getName(), ex);
1793 JvOptionPane.showMessageDialog(me,
1794 MessageManager.formatMessage(
1795 "label.error_whilst_saving_current_state_to",
1797 { chosenFile.getName() }),
1798 MessageManager.getString("label.couldnt_save_project"),
1799 JvOptionPane.WARNING_MESSAGE);
1801 setProgressBar(null, chosenFile.hashCode());
1808 public void saveAsState_actionPerformed(ActionEvent e)
1810 saveState_actionPerformed(true);
1813 private void setProjectFile(File choice)
1815 this.projectFile = choice;
1818 public File getProjectFile()
1820 return this.projectFile;
1824 * Shows a file chooser dialog and tries to read in the selected file as a
1828 public void loadState_actionPerformed()
1830 final String[] suffix = new String[] { "jvp", "jar" };
1831 final String[] desc = new String[] { "Jalview Project",
1832 "Jalview Project (old)" };
1833 JalviewFileChooser chooser = new JalviewFileChooser(
1834 Cache.getProperty("LAST_DIRECTORY"), suffix, desc,
1835 "Jalview Project", true, BackupFiles.getEnabled()); // last two booleans: allFiles,
1837 chooser.setFileView(new JalviewFileView());
1838 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1839 chooser.setResponseHandler(0, new Runnable()
1844 File selectedFile = chooser.getSelectedFile();
1845 setProjectFile(selectedFile);
1846 String choice = selectedFile.getAbsolutePath();
1847 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1848 new Thread(new Runnable()
1855 new Jalview2XML().loadJalviewAlign(choice);
1856 } catch (OutOfMemoryError oom)
1858 new OOMWarning("Whilst loading project from " + choice, oom);
1859 } catch (Exception ex)
1862 "Problems whilst loading project from " + choice, ex);
1863 JvOptionPane.showMessageDialog(Desktop.desktop,
1864 MessageManager.formatMessage(
1865 "label.error_whilst_loading_project_from",
1868 MessageManager.getString("label.couldnt_load_project"),
1869 JvOptionPane.WARNING_MESSAGE);
1876 chooser.showOpenDialog(this);
1880 public void inputSequence_actionPerformed(ActionEvent e)
1882 new SequenceFetcher(this);
1885 JPanel progressPanel;
1887 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1889 public void startLoading(final Object fileName)
1891 if (fileLoadingCount == 0)
1893 fileLoadingPanels.add(addProgressPanel(MessageManager
1894 .formatMessage("label.loading_file", new Object[]
1900 private JPanel addProgressPanel(String string)
1902 if (progressPanel == null)
1904 progressPanel = new JPanel(new GridLayout(1, 1));
1905 totalProgressCount = 0;
1906 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1908 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1909 JProgressBar progressBar = new JProgressBar();
1910 progressBar.setIndeterminate(true);
1912 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1914 thisprogress.add(progressBar, BorderLayout.CENTER);
1915 progressPanel.add(thisprogress);
1916 ((GridLayout) progressPanel.getLayout()).setRows(
1917 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1918 ++totalProgressCount;
1919 instance.validate();
1920 return thisprogress;
1923 int totalProgressCount = 0;
1925 private void removeProgressPanel(JPanel progbar)
1927 if (progressPanel != null)
1929 synchronized (progressPanel)
1931 progressPanel.remove(progbar);
1932 GridLayout gl = (GridLayout) progressPanel.getLayout();
1933 gl.setRows(gl.getRows() - 1);
1934 if (--totalProgressCount < 1)
1936 this.getContentPane().remove(progressPanel);
1937 progressPanel = null;
1944 public void stopLoading()
1947 if (fileLoadingCount < 1)
1949 while (fileLoadingPanels.size() > 0)
1951 removeProgressPanel(fileLoadingPanels.remove(0));
1953 fileLoadingPanels.clear();
1954 fileLoadingCount = 0;
1959 public static int getViewCount(String alignmentId)
1961 AlignmentViewport[] aps = getViewports(alignmentId);
1962 return (aps == null) ? 0 : aps.length;
1967 * @param alignmentId
1968 * - if null, all sets are returned
1969 * @return all AlignmentPanels concerning the alignmentId sequence set
1971 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1973 if (Desktop.desktop == null)
1975 // no frames created and in headless mode
1976 // TODO: verify that frames are recoverable when in headless mode
1979 List<AlignmentPanel> aps = new ArrayList<>();
1980 AlignFrame[] frames = getAlignFrames();
1985 for (AlignFrame af : frames)
1987 for (AlignmentPanel ap : af.alignPanels)
1989 if (alignmentId == null
1990 || alignmentId.equals(ap.av.getSequenceSetId()))
1996 if (aps.size() == 0)
2000 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
2005 * get all the viewports on an alignment.
2007 * @param sequenceSetId
2008 * unique alignment id (may be null - all viewports returned in that
2010 * @return all viewports on the alignment bound to sequenceSetId
2012 public static AlignmentViewport[] getViewports(String sequenceSetId)
2014 List<AlignmentViewport> viewp = new ArrayList<>();
2015 if (desktop != null)
2017 AlignFrame[] frames = Desktop.getAlignFrames();
2019 for (AlignFrame afr : frames)
2021 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
2022 .equals(sequenceSetId))
2024 if (afr.alignPanels != null)
2026 for (AlignmentPanel ap : afr.alignPanels)
2028 if (sequenceSetId == null
2029 || sequenceSetId.equals(ap.av.getSequenceSetId()))
2037 viewp.add(afr.getViewport());
2041 if (viewp.size() > 0)
2043 return viewp.toArray(new AlignmentViewport[viewp.size()]);
2050 * Explode the views in the given frame into separate AlignFrame
2054 public static void explodeViews(AlignFrame af)
2056 int size = af.alignPanels.size();
2062 for (int i = 0; i < size; i++)
2064 AlignmentPanel ap = af.alignPanels.get(i);
2065 AlignFrame newaf = new AlignFrame(ap);
2068 * Restore the view's last exploded frame geometry if known. Multiple
2069 * views from one exploded frame share and restore the same (frame)
2070 * position and size.
2072 Rectangle geometry = ap.av.getExplodedGeometry();
2073 if (geometry != null)
2075 newaf.setBounds(geometry);
2078 ap.av.setGatherViewsHere(false);
2080 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2081 AlignFrame.DEFAULT_HEIGHT);
2084 af.alignPanels.clear();
2085 af.closeMenuItem_actionPerformed(true);
2090 * Gather expanded views (separate AlignFrame's) with the same sequence set
2091 * identifier back in to this frame as additional views, and close the expanded
2092 * views. Note the expanded frames may themselves have multiple views. We take
2097 public void gatherViews(AlignFrame source)
2099 source.viewport.setGatherViewsHere(true);
2100 source.viewport.setExplodedGeometry(source.getBounds());
2101 JInternalFrame[] frames = desktop.getAllFrames();
2102 String viewId = source.viewport.getSequenceSetId();
2104 for (int t = 0; t < frames.length; t++)
2106 if (frames[t] instanceof AlignFrame && frames[t] != source)
2108 AlignFrame af = (AlignFrame) frames[t];
2109 boolean gatherThis = false;
2110 for (int a = 0; a < af.alignPanels.size(); a++)
2112 AlignmentPanel ap = af.alignPanels.get(a);
2113 if (viewId.equals(ap.av.getSequenceSetId()))
2116 ap.av.setGatherViewsHere(false);
2117 ap.av.setExplodedGeometry(af.getBounds());
2118 source.addAlignmentPanel(ap, false);
2124 af.alignPanels.clear();
2125 af.closeMenuItem_actionPerformed(true);
2132 jalview.gui.VamsasApplication v_client = null;
2135 public void vamsasImport_actionPerformed(ActionEvent e)
2137 // TODO: JAL-3048 not needed for Jalview-JS
2139 if (v_client == null)
2141 // Load and try to start a session.
2142 JalviewFileChooser chooser = new JalviewFileChooser(
2143 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2145 chooser.setFileView(new JalviewFileView());
2146 chooser.setDialogTitle(
2147 MessageManager.getString("label.open_saved_vamsas_session"));
2148 chooser.setToolTipText(MessageManager.getString(
2149 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2151 int value = chooser.showOpenDialog(this);
2153 if (value == JalviewFileChooser.APPROVE_OPTION)
2155 String fle = chooser.getSelectedFile().toString();
2156 if (!vamsasImport(chooser.getSelectedFile()))
2158 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2159 MessageManager.formatMessage(
2160 "label.couldnt_import_as_vamsas_session",
2164 .getString("label.vamsas_document_import_failed"),
2165 JvOptionPane.ERROR_MESSAGE);
2171 jalview.bin.Cache.log.error(
2172 "Implementation error - load session from a running session is not supported.");
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(URL url)
2184 // TODO: create progress bar
2185 if (v_client != null)
2188 jalview.bin.Cache.log.error(
2189 "Implementation error - load session from a running session is not supported.");
2195 // copy the URL content to a temporary local file
2196 // TODO: be a bit cleverer here with nio (?!)
2197 File file = File.createTempFile("vdocfromurl", ".vdj");
2198 FileOutputStream fos = new FileOutputStream(file);
2199 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2200 byte[] buffer = new byte[2048];
2202 while ((ln = bis.read(buffer)) > -1)
2204 fos.write(buffer, 0, ln);
2208 v_client = new jalview.gui.VamsasApplication(this, file,
2209 url.toExternalForm());
2210 } catch (Exception ex)
2212 jalview.bin.Cache.log.error(
2213 "Failed to create new vamsas session from contents of URL "
2218 setupVamsasConnectedGui();
2219 v_client.initial_update(); // TODO: thread ?
2220 return v_client.inSession();
2224 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2227 * @return true if import was a success and a session was started.
2229 public boolean vamsasImport(File file)
2231 if (v_client != null)
2234 jalview.bin.Cache.log.error(
2235 "Implementation error - load session from a running session is not supported.");
2239 setProgressBar(MessageManager.formatMessage(
2240 "status.importing_vamsas_session_from", new Object[]
2241 { file.getName() }), file.hashCode());
2244 v_client = new jalview.gui.VamsasApplication(this, file, null);
2245 } catch (Exception ex)
2247 setProgressBar(MessageManager.formatMessage(
2248 "status.importing_vamsas_session_from", new Object[]
2249 { file.getName() }), file.hashCode());
2250 jalview.bin.Cache.log.error(
2251 "New vamsas session from existing session file failed:", ex);
2254 setupVamsasConnectedGui();
2255 v_client.initial_update(); // TODO: thread ?
2256 setProgressBar(MessageManager.formatMessage(
2257 "status.importing_vamsas_session_from", new Object[]
2258 { file.getName() }), file.hashCode());
2259 return v_client.inSession();
2262 public boolean joinVamsasSession(String mysesid)
2264 if (v_client != null)
2266 throw new Error(MessageManager
2267 .getString("error.try_join_vamsas_session_another"));
2269 if (mysesid == null)
2272 MessageManager.getString("error.invalid_vamsas_session_id"));
2274 v_client = new VamsasApplication(this, mysesid);
2275 setupVamsasConnectedGui();
2276 v_client.initial_update();
2277 return (v_client.inSession());
2281 public void vamsasStart_actionPerformed(ActionEvent e)
2283 if (v_client == null)
2286 // we just start a default session for moment.
2288 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2289 * getProperty("LAST_DIRECTORY"));
2291 * chooser.setFileView(new JalviewFileView());
2292 * chooser.setDialogTitle("Load Vamsas file");
2293 * chooser.setToolTipText("Import");
2295 * int value = chooser.showOpenDialog(this);
2297 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2298 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2300 v_client = new VamsasApplication(this);
2301 setupVamsasConnectedGui();
2302 v_client.initial_update(); // TODO: thread ?
2306 // store current data in session.
2307 v_client.push_update(); // TODO: thread
2311 protected void setupVamsasConnectedGui()
2313 vamsasStart.setText(MessageManager.getString("label.session_update"));
2314 vamsasSave.setVisible(true);
2315 vamsasStop.setVisible(true);
2316 vamsasImport.setVisible(false); // Document import to existing session is
2317 // not possible for vamsas-client-1.0.
2320 protected void setupVamsasDisconnectedGui()
2322 vamsasSave.setVisible(false);
2323 vamsasStop.setVisible(false);
2324 vamsasImport.setVisible(true);
2326 .setText(MessageManager.getString("label.new_vamsas_session"));
2330 public void vamsasStop_actionPerformed(ActionEvent e)
2332 if (v_client != null)
2334 v_client.end_session();
2336 setupVamsasDisconnectedGui();
2340 protected void buildVamsasStMenu()
2342 if (v_client == null)
2344 String[] sess = null;
2347 sess = VamsasApplication.getSessionList();
2348 } catch (Exception e)
2350 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2356 jalview.bin.Cache.log.debug(
2357 "Got current sessions list: " + sess.length + " entries.");
2358 VamsasStMenu.removeAll();
2359 for (int i = 0; i < sess.length; i++)
2361 JMenuItem sessit = new JMenuItem();
2362 sessit.setText(sess[i]);
2363 sessit.setToolTipText(MessageManager
2364 .formatMessage("label.connect_to_session", new Object[]
2366 final Desktop dsktp = this;
2367 final String mysesid = sess[i];
2368 sessit.addActionListener(new ActionListener()
2372 public void actionPerformed(ActionEvent e)
2374 if (dsktp.v_client == null)
2376 Thread rthr = new Thread(new Runnable()
2382 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2383 dsktp.setupVamsasConnectedGui();
2384 dsktp.v_client.initial_update();
2392 VamsasStMenu.add(sessit);
2394 // don't show an empty menu.
2395 VamsasStMenu.setVisible(sess.length > 0);
2400 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2401 VamsasStMenu.removeAll();
2402 VamsasStMenu.setVisible(false);
2407 // Not interested in the content. Just hide ourselves.
2408 VamsasStMenu.setVisible(false);
2413 public void vamsasSave_actionPerformed(ActionEvent e)
2415 // TODO: JAL-3048 not needed for Jalview-JS
2417 if (v_client != null)
2419 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2420 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2423 chooser.setFileView(new JalviewFileView());
2424 chooser.setDialogTitle(MessageManager
2425 .getString("label.save_vamsas_document_archive"));
2427 int value = chooser.showSaveDialog(this);
2429 if (value == JalviewFileChooser.APPROVE_OPTION)
2431 java.io.File choice = chooser.getSelectedFile();
2432 JPanel progpanel = addProgressPanel(MessageManager
2433 .formatMessage("label.saving_vamsas_doc", new Object[]
2434 { choice.getName() }));
2435 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2436 String warnmsg = null;
2437 String warnttl = null;
2440 v_client.vclient.storeDocument(choice);
2443 warnttl = "Serious Problem saving Vamsas Document";
2444 warnmsg = ex.toString();
2445 jalview.bin.Cache.log
2446 .error("Error Whilst saving document to " + choice, ex);
2448 } catch (Exception ex)
2450 warnttl = "Problem saving Vamsas Document.";
2451 warnmsg = ex.toString();
2452 jalview.bin.Cache.log.warn(
2453 "Exception Whilst saving document to " + choice, ex);
2456 removeProgressPanel(progpanel);
2457 if (warnmsg != null)
2459 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2461 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2467 JPanel vamUpdate = null;
2470 * hide vamsas user gui bits when a vamsas document event is being handled.
2473 * true to hide gui, false to reveal gui
2475 public void setVamsasUpdate(boolean b)
2477 Cache.log.debug("Setting gui for Vamsas update "
2478 + (b ? "in progress" : "finished"));
2480 if (vamUpdate != null)
2482 this.removeProgressPanel(vamUpdate);
2486 vamUpdate = this.addProgressPanel(
2487 MessageManager.getString("label.updating_vamsas_session"));
2489 vamsasStart.setVisible(!b);
2490 vamsasStop.setVisible(!b);
2491 vamsasSave.setVisible(!b);
2494 public JInternalFrame[] getAllFrames()
2496 return desktop.getAllFrames();
2500 * Checks the given url to see if it gives a response indicating that the user
2501 * should be informed of a new questionnaire.
2505 public void checkForQuestionnaire(String url)
2507 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2508 // javax.swing.SwingUtilities.invokeLater(jvq);
2509 new Thread(jvq).start();
2512 public void checkURLLinks()
2514 // Thread off the URL link checker
2515 addDialogThread(new Runnable()
2520 if (Cache.getDefault("CHECKURLLINKS", true))
2522 // check what the actual links are - if it's just the default don't
2523 // bother with the warning
2524 List<String> links = Preferences.sequenceUrlLinks
2527 // only need to check links if there is one with a
2528 // SEQUENCE_ID which is not the default EMBL_EBI link
2529 ListIterator<String> li = links.listIterator();
2530 boolean check = false;
2531 List<JLabel> urls = new ArrayList<>();
2532 while (li.hasNext())
2534 String link = li.next();
2535 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2536 && !UrlConstants.isDefaultString(link))
2539 int barPos = link.indexOf("|");
2540 String urlMsg = barPos == -1 ? link
2541 : link.substring(0, barPos) + ": "
2542 + link.substring(barPos + 1);
2543 urls.add(new JLabel(urlMsg));
2551 // ask user to check in case URL links use old style tokens
2552 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2553 JPanel msgPanel = new JPanel();
2554 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2555 msgPanel.add(Box.createVerticalGlue());
2556 JLabel msg = new JLabel(MessageManager
2557 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2558 JLabel msg2 = new JLabel(MessageManager
2559 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2561 for (JLabel url : urls)
2567 final JCheckBox jcb = new JCheckBox(
2568 MessageManager.getString("label.do_not_display_again"));
2569 jcb.addActionListener(new ActionListener()
2572 public void actionPerformed(ActionEvent e)
2574 // update Cache settings for "don't show this again"
2575 boolean showWarningAgain = !jcb.isSelected();
2576 Cache.setProperty("CHECKURLLINKS",
2577 Boolean.valueOf(showWarningAgain).toString());
2582 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2584 .getString("label.SEQUENCE_ID_no_longer_used"),
2585 JvOptionPane.WARNING_MESSAGE);
2592 * Proxy class for JDesktopPane which optionally displays the current memory
2593 * usage and highlights the desktop area with a red bar if free memory runs low.
2597 public class MyDesktopPane extends JDesktopPane
2600 private static final float ONE_MB = 1048576f;
2602 boolean showMemoryUsage = false;
2606 java.text.NumberFormat df;
2608 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2611 public MyDesktopPane(boolean showMemoryUsage)
2613 showMemoryUsage(showMemoryUsage);
2616 public void showMemoryUsage(boolean showMemory)
2618 this.showMemoryUsage = showMemory;
2621 Thread worker = new Thread(this);
2627 public boolean isShowMemoryUsage()
2629 return showMemoryUsage;
2635 df = java.text.NumberFormat.getNumberInstance();
2636 df.setMaximumFractionDigits(2);
2637 runtime = Runtime.getRuntime();
2639 while (showMemoryUsage)
2643 maxMemory = runtime.maxMemory() / ONE_MB;
2644 allocatedMemory = runtime.totalMemory() / ONE_MB;
2645 freeMemory = runtime.freeMemory() / ONE_MB;
2646 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2648 percentUsage = (totalFreeMemory / maxMemory) * 100;
2650 // if (percentUsage < 20)
2652 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2654 // instance.set.setBorder(border1);
2657 // sleep after showing usage
2659 } catch (Exception ex)
2661 ex.printStackTrace();
2667 public void paintComponent(Graphics g)
2669 if (showMemoryUsage && g != null && df != null)
2671 if (percentUsage < 20)
2673 g.setColor(Color.red);
2675 FontMetrics fm = g.getFontMetrics();
2678 g.drawString(MessageManager.formatMessage("label.memory_stats",
2680 { df.format(totalFreeMemory), df.format(maxMemory),
2681 df.format(percentUsage) }),
2682 10, getHeight() - fm.getHeight());
2689 * Accessor method to quickly get all the AlignmentFrames loaded.
2691 * @return an array of AlignFrame, or null if none found
2693 public static AlignFrame[] getAlignFrames()
2695 if (Jalview.isHeadlessMode())
2697 // Desktop.desktop is null in headless mode
2698 return new AlignFrame[] { Jalview.currentAlignFrame };
2701 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2707 List<AlignFrame> avp = new ArrayList<>();
2709 for (int i = frames.length - 1; i > -1; i--)
2711 if (frames[i] instanceof AlignFrame)
2713 avp.add((AlignFrame) frames[i]);
2715 else if (frames[i] instanceof SplitFrame)
2718 * Also check for a split frame containing an AlignFrame
2720 GSplitFrame sf = (GSplitFrame) frames[i];
2721 if (sf.getTopFrame() instanceof AlignFrame)
2723 avp.add((AlignFrame) sf.getTopFrame());
2725 if (sf.getBottomFrame() instanceof AlignFrame)
2727 avp.add((AlignFrame) sf.getBottomFrame());
2731 if (avp.size() == 0)
2735 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2740 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2744 public GStructureViewer[] getJmols()
2746 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2752 List<GStructureViewer> avp = new ArrayList<>();
2754 for (int i = frames.length - 1; i > -1; i--)
2756 if (frames[i] instanceof AppJmol)
2758 GStructureViewer af = (GStructureViewer) frames[i];
2762 if (avp.size() == 0)
2766 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2771 * Add Groovy Support to Jalview
2774 public void groovyShell_actionPerformed()
2778 openGroovyConsole();
2779 } catch (Exception ex)
2781 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2782 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2784 MessageManager.getString("label.couldnt_create_groovy_shell"),
2785 MessageManager.getString("label.groovy_support_failed"),
2786 JvOptionPane.ERROR_MESSAGE);
2791 * Open the Groovy console
2793 void openGroovyConsole()
2795 if (groovyConsole == null)
2797 groovyConsole = new groovy.ui.Console();
2798 groovyConsole.setVariable("Jalview", this);
2799 groovyConsole.run();
2802 * We allow only one console at a time, so that AlignFrame menu option
2803 * 'Calculate | Run Groovy script' is unambiguous.
2804 * Disable 'Groovy Console', and enable 'Run script', when the console is
2805 * opened, and the reverse when it is closed
2807 Window window = (Window) groovyConsole.getFrame();
2808 window.addWindowListener(new WindowAdapter()
2811 public void windowClosed(WindowEvent e)
2814 * rebind CMD-Q from Groovy Console to Jalview Quit
2817 enableExecuteGroovy(false);
2823 * show Groovy console window (after close and reopen)
2825 ((Window) groovyConsole.getFrame()).setVisible(true);
2828 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2829 * and disable opening a second console
2831 enableExecuteGroovy(true);
2835 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this binding
2838 protected void addQuitHandler()
2840 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2841 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2842 jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx()),
2844 getRootPane().getActionMap().put("Quit", new AbstractAction()
2847 public void actionPerformed(ActionEvent e)
2855 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2858 * true if Groovy console is open
2860 public void enableExecuteGroovy(boolean enabled)
2863 * disable opening a second Groovy console
2864 * (or re-enable when the console is closed)
2866 groovyShell.setEnabled(!enabled);
2868 AlignFrame[] alignFrames = getAlignFrames();
2869 if (alignFrames != null)
2871 for (AlignFrame af : alignFrames)
2873 af.setGroovyEnabled(enabled);
2879 * Progress bars managed by the IProgressIndicator method.
2881 private Hashtable<Long, JPanel> progressBars;
2883 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2888 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2891 public void setProgressBar(String message, long id)
2893 Platform.timeCheck("Desktop " + message, Platform.TIME_MARK);
2895 if (progressBars == null)
2897 progressBars = new Hashtable<>();
2898 progressBarHandlers = new Hashtable<>();
2901 if (progressBars.get(Long.valueOf(id)) != null)
2903 JPanel panel = progressBars.remove(Long.valueOf(id));
2904 if (progressBarHandlers.contains(Long.valueOf(id)))
2906 progressBarHandlers.remove(Long.valueOf(id));
2908 removeProgressPanel(panel);
2912 progressBars.put(Long.valueOf(id), addProgressPanel(message));
2919 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2920 * jalview.gui.IProgressIndicatorHandler)
2923 public void registerHandler(final long id,
2924 final IProgressIndicatorHandler handler)
2926 if (progressBarHandlers == null
2927 || !progressBars.containsKey(Long.valueOf(id)))
2929 throw new Error(MessageManager.getString(
2930 "error.call_setprogressbar_before_registering_handler"));
2932 progressBarHandlers.put(Long.valueOf(id), handler);
2933 final JPanel progressPanel = progressBars.get(Long.valueOf(id));
2934 if (handler.canCancel())
2936 JButton cancel = new JButton(
2937 MessageManager.getString("action.cancel"));
2938 final IProgressIndicator us = this;
2939 cancel.addActionListener(new ActionListener()
2943 public void actionPerformed(ActionEvent e)
2945 handler.cancelActivity(id);
2946 us.setProgressBar(MessageManager
2947 .formatMessage("label.cancelled_params", new Object[]
2948 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2952 progressPanel.add(cancel, BorderLayout.EAST);
2958 * @return true if any progress bars are still active
2961 public boolean operationInProgress()
2963 if (progressBars != null && progressBars.size() > 0)
2971 * This will return the first AlignFrame holding the given viewport instance. It
2972 * will break if there are more than one AlignFrames viewing a particular av.
2975 * @return alignFrame for viewport
2977 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2979 if (desktop != null)
2981 AlignmentPanel[] aps = getAlignmentPanels(
2982 viewport.getSequenceSetId());
2983 for (int panel = 0; aps != null && panel < aps.length; panel++)
2985 if (aps[panel] != null && aps[panel].av == viewport)
2987 return aps[panel].alignFrame;
2994 public VamsasApplication getVamsasApplication()
3001 * flag set if jalview GUI is being operated programmatically
3003 private boolean inBatchMode = false;
3006 * check if jalview GUI is being operated programmatically
3008 * @return inBatchMode
3010 public boolean isInBatchMode()
3016 * set flag if jalview GUI is being operated programmatically
3018 * @param inBatchMode
3020 public void setInBatchMode(boolean inBatchMode)
3022 this.inBatchMode = inBatchMode;
3025 public void startServiceDiscovery()
3027 startServiceDiscovery(false);
3030 public void startServiceDiscovery(boolean blocking)
3032 boolean alive = true;
3033 Thread t0 = null, t1 = null, t2 = null;
3034 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3037 // todo: changesupport handlers need to be transferred
3038 if (discoverer == null)
3040 discoverer = new jalview.ws.jws1.Discoverer();
3041 // register PCS handler for desktop.
3042 discoverer.addPropertyChangeListener(changeSupport);
3044 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3045 // until we phase out completely
3046 (t0 = new Thread(discoverer)).start();
3049 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3051 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3052 .startDiscoverer(changeSupport);
3056 // TODO: do rest service discovery
3065 } catch (Exception e)
3068 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3069 || (t3 != null && t3.isAlive())
3070 || (t0 != null && t0.isAlive());
3076 * called to check if the service discovery process completed successfully.
3080 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3082 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3084 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3085 .getErrorMessages();
3088 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3090 if (serviceChangedDialog == null)
3092 // only run if we aren't already displaying one of these.
3093 addDialogThread(serviceChangedDialog = new Runnable()
3100 * JalviewDialog jd =new JalviewDialog() {
3102 * @Override protected void cancelPressed() { // TODO
3103 * Auto-generated method stub
3105 * }@Override protected void okPressed() { // TODO
3106 * Auto-generated method stub
3108 * }@Override protected void raiseClosed() { // TODO
3109 * Auto-generated method stub
3111 * } }; jd.initDialogFrame(new
3112 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3113 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3114 * + " or mis-configured HTTP proxy settings.<br/>" +
3115 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3117 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3118 * ), true, true, "Web Service Configuration Problem", 450,
3121 * jd.waitForInput();
3123 JvOptionPane.showConfirmDialog(Desktop.desktop,
3124 new JLabel("<html><table width=\"450\"><tr><td>"
3125 + ermsg + "</td></tr></table>"
3126 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3127 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3128 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3129 + " Tools->Preferences dialog box to change them.</p></html>"),
3130 "Web Service Configuration Problem",
3131 JvOptionPane.DEFAULT_OPTION,
3132 JvOptionPane.ERROR_MESSAGE);
3133 serviceChangedDialog = null;
3142 "Errors reported by JABA discovery service. Check web services preferences.\n"
3149 private Runnable serviceChangedDialog = null;
3152 * start a thread to open a URL in the configured browser. Pops up a warning
3153 * dialog to the user if there is an exception when calling out to the browser
3158 public static void showUrl(final String url)
3160 showUrl(url, Desktop.instance);
3164 * Like showUrl but allows progress handler to be specified
3168 * (null) or object implementing IProgressIndicator
3170 public static void showUrl(final String url,
3171 final IProgressIndicator progress)
3173 new Thread(new Runnable()
3180 if (progress != null)
3182 progress.setProgressBar(MessageManager
3183 .formatMessage("status.opening_params", new Object[]
3184 { url }), this.hashCode());
3186 jalview.util.BrowserLauncher.openURL(url);
3187 } catch (Exception ex)
3189 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3191 .getString("label.web_browser_not_found_unix"),
3192 MessageManager.getString("label.web_browser_not_found"),
3193 JvOptionPane.WARNING_MESSAGE);
3195 ex.printStackTrace();
3197 if (progress != null)
3199 progress.setProgressBar(null, this.hashCode());
3205 public static WsParamSetManager wsparamManager = null;
3207 public static ParamManager getUserParameterStore()
3209 if (wsparamManager == null)
3211 wsparamManager = new WsParamSetManager();
3213 return wsparamManager;
3217 * static hyperlink handler proxy method for use by Jalview's internal windows
3221 public static void hyperlinkUpdate(HyperlinkEvent e)
3223 if (e.getEventType() == EventType.ACTIVATED)
3228 url = e.getURL().toString();
3229 Desktop.showUrl(url);
3230 } catch (Exception x)
3234 if (Cache.log != null)
3236 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3241 "Couldn't handle string " + url + " as a URL.");
3244 // ignore any exceptions due to dud links.
3251 * single thread that handles display of dialogs to user.
3253 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3256 * flag indicating if dialogExecutor should try to acquire a permit
3258 private volatile boolean dialogPause = true;
3263 private java.util.concurrent.Semaphore block = new Semaphore(0);
3265 private static groovy.ui.Console groovyConsole;
3268 * add another dialog thread to the queue
3272 public void addDialogThread(final Runnable prompter)
3274 dialogExecutor.submit(new Runnable()
3284 } catch (InterruptedException x)
3288 if (instance == null)
3294 SwingUtilities.invokeAndWait(prompter);
3295 } catch (Exception q)
3297 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3303 public void startDialogQueue()
3305 // set the flag so we don't pause waiting for another permit and semaphore
3306 // the current task to begin
3307 dialogPause = false;
3312 * Outputs an image of the desktop to file in EPS format, after prompting the
3313 * user for choice of Text or Lineart character rendering (unless a preference
3314 * has been set). The file name is generated as
3317 * Jalview_snapshot_nnnnn.eps where nnnnn is the current timestamp in milliseconds
3321 protected void snapShotWindow_actionPerformed(ActionEvent e)
3323 // currently the menu option to do this is not shown
3326 int width = getWidth();
3327 int height = getHeight();
3329 "Jalview_snapshot_" + System.currentTimeMillis() + ".eps");
3330 ImageWriterI writer = new ImageWriterI()
3333 public void exportImage(Graphics g) throws Exception
3336 Cache.log.info("Successfully written snapshot to file "
3337 + of.getAbsolutePath());
3340 String title = "View of desktop";
3341 ImageExporter exporter = new ImageExporter(writer, null, TYPE.EPS,
3343 exporter.doExport(of, this, width, height, title);
3347 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3348 * This respects (remembers) any previous 'exploded geometry' i.e. the size and
3349 * location last time the view was expanded (if any). However it does not
3350 * remember the split pane divider location - this is set to match the
3351 * 'exploding' frame.
3355 public void explodeViews(SplitFrame sf)
3357 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3358 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3359 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3361 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3363 int viewCount = topPanels.size();
3370 * Processing in reverse order works, forwards order leaves the first panels
3371 * not visible. I don't know why!
3373 for (int i = viewCount - 1; i >= 0; i--)
3376 * Make new top and bottom frames. These take over the respective
3377 * AlignmentPanel objects, including their AlignmentViewports, so the
3378 * cdna/protein relationships between the viewports is carried over to the
3381 * explodedGeometry holds the (x, y) position of the previously exploded
3382 * SplitFrame, and the (width, height) of the AlignFrame component
3384 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3385 AlignFrame newTopFrame = new AlignFrame(topPanel);
3386 newTopFrame.setSize(oldTopFrame.getSize());
3387 newTopFrame.setVisible(true);
3388 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3389 .getExplodedGeometry();
3390 if (geometry != null)
3392 newTopFrame.setSize(geometry.getSize());
3395 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3396 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3397 newBottomFrame.setSize(oldBottomFrame.getSize());
3398 newBottomFrame.setVisible(true);
3399 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3400 .getExplodedGeometry();
3401 if (geometry != null)
3403 newBottomFrame.setSize(geometry.getSize());
3406 topPanel.av.setGatherViewsHere(false);
3407 bottomPanel.av.setGatherViewsHere(false);
3408 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3410 if (geometry != null)
3412 splitFrame.setLocation(geometry.getLocation());
3414 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3418 * Clear references to the panels (now relocated in the new SplitFrames)
3419 * before closing the old SplitFrame.
3422 bottomPanels.clear();
3427 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3428 * back into the given SplitFrame as additional views. Note that the gathered
3429 * frames may themselves have multiple views.
3433 public void gatherViews(GSplitFrame source)
3436 * special handling of explodedGeometry for a view within a SplitFrame: - it
3437 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3438 * height) of the AlignFrame component
3440 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3441 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3442 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3443 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3444 myBottomFrame.viewport
3445 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3446 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3447 myTopFrame.viewport.setGatherViewsHere(true);
3448 myBottomFrame.viewport.setGatherViewsHere(true);
3449 String topViewId = myTopFrame.viewport.getSequenceSetId();
3450 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3452 JInternalFrame[] frames = desktop.getAllFrames();
3453 for (JInternalFrame frame : frames)
3455 if (frame instanceof SplitFrame && frame != source)
3457 SplitFrame sf = (SplitFrame) frame;
3458 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3459 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3460 boolean gatherThis = false;
3461 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3463 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3464 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3465 if (topViewId.equals(topPanel.av.getSequenceSetId())
3466 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3469 topPanel.av.setGatherViewsHere(false);
3470 bottomPanel.av.setGatherViewsHere(false);
3471 topPanel.av.setExplodedGeometry(
3472 new Rectangle(sf.getLocation(), topFrame.getSize()));
3473 bottomPanel.av.setExplodedGeometry(
3474 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3475 myTopFrame.addAlignmentPanel(topPanel, false);
3476 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3482 topFrame.getAlignPanels().clear();
3483 bottomFrame.getAlignPanels().clear();
3490 * The dust settles...give focus to the tab we did this from.
3492 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3495 public static groovy.ui.Console getGroovyConsole()
3497 return groovyConsole;
3501 * handles the payload of a drag and drop event.
3503 * TODO refactor to desktop utilities class
3506 * - Data source strings extracted from the drop event
3508 * - protocol for each data source extracted from the drop event
3512 * - the payload from the drop event
3515 public static void transferFromDropTarget(List<Object> files,
3516 List<DataSourceType> protocols, DropTargetDropEvent evt,
3517 Transferable t) throws Exception
3520 // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
3522 // DataFlavor[] flavors = t.getTransferDataFlavors();
3523 // for (int i = 0; i < flavors.length; i++) {
3524 // if (flavors[i].isFlavorJavaFileListType()) {
3525 // evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
3526 // List<File> list = (List<File>) t.getTransferData(flavors[i]);
3527 // for (int j = 0; j < list.size(); j++) {
3528 // File file = (File) list.get(j);
3529 // byte[] data = getDroppedFileBytes(file);
3530 // fileName.setText(file.getName() + " - " + data.length + " " +
3531 // evt.getLocation());
3532 // JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
3533 // target.setText(new String(data));
3535 // dtde.dropComplete(true);
3540 DataFlavor uriListFlavor = new DataFlavor(
3541 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3544 urlFlavour = new DataFlavor(
3545 "application/x-java-url; class=java.net.URL");
3546 } catch (ClassNotFoundException cfe)
3548 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3551 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3556 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3557 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3558 // means url may be null.
3561 protocols.add(DataSourceType.URL);
3562 files.add(url.toString());
3563 Cache.log.debug("Drop handled as URL dataflavor "
3564 + files.get(files.size() - 1));
3569 if (Platform.isAMacAndNotJS())
3572 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3575 } catch (Throwable ex)
3577 Cache.log.debug("URL drop handler failed.", ex);
3580 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3582 // Works on Windows and MacOSX
3583 Cache.log.debug("Drop handled as javaFileListFlavor");
3584 for (Object file : (List) t
3585 .getTransferData(DataFlavor.javaFileListFlavor))
3588 protocols.add(DataSourceType.FILE);
3593 // Unix like behaviour
3594 boolean added = false;
3596 if (t.isDataFlavorSupported(uriListFlavor))
3598 Cache.log.debug("Drop handled as uriListFlavor");
3599 // This is used by Unix drag system
3600 data = (String) t.getTransferData(uriListFlavor);
3604 // fallback to text: workaround - on OSX where there's a JVM bug
3605 Cache.log.debug("standard URIListFlavor failed. Trying text");
3606 // try text fallback
3607 DataFlavor textDf = new DataFlavor(
3608 "text/plain;class=java.lang.String");
3609 if (t.isDataFlavorSupported(textDf))
3611 data = (String) t.getTransferData(textDf);
3614 Cache.log.debug("Plain text drop content returned "
3615 + (data == null ? "Null - failed" : data));
3620 while (protocols.size() < files.size())
3622 Cache.log.debug("Adding missing FILE protocol for "
3623 + files.get(protocols.size()));
3624 protocols.add(DataSourceType.FILE);
3626 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3627 data, "\r\n"); st.hasMoreTokens();)
3630 String s = st.nextToken();
3631 if (s.startsWith("#"))
3633 // the line is a comment (as per the RFC 2483)
3636 java.net.URI uri = new java.net.URI(s);
3637 if (uri.getScheme().toLowerCase().startsWith("http"))
3639 protocols.add(DataSourceType.URL);
3640 files.add(uri.toString());
3644 // otherwise preserve old behaviour: catch all for file objects
3645 java.io.File file = new java.io.File(uri);
3646 protocols.add(DataSourceType.FILE);
3647 files.add(file.toString());
3652 if (Cache.log.isDebugEnabled())
3654 if (data == null || !added)
3657 if (t.getTransferDataFlavors() != null
3658 && t.getTransferDataFlavors().length > 0)
3661 "Couldn't resolve drop data. Here are the supported flavors:");
3662 for (DataFlavor fl : t.getTransferDataFlavors())
3665 "Supported transfer dataflavor: " + fl.toString());
3666 Object df = t.getTransferData(fl);
3669 Cache.log.debug("Retrieves: " + df);
3673 Cache.log.debug("Retrieved nothing");
3679 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3685 if (Platform.isWindowsAndNotJS())
3687 Cache.log.debug("Scanning dropped content for Windows Link Files");
3689 // resolve any .lnk files in the file drop
3690 for (int f = 0; f < files.size(); f++)
3692 String source = files.get(f).toString().toLowerCase();
3693 if (protocols.get(f).equals(DataSourceType.FILE)
3694 && (source.endsWith(".lnk") || source.endsWith(".url")
3695 || source.endsWith(".site")))
3699 Object obj = files.get(f);
3700 File lf = (obj instanceof File ? (File) obj
3701 : new File((String) obj));
3702 // process link file to get a URL
3703 Cache.log.debug("Found potential link file: " + lf);
3704 WindowsShortcut wscfile = new WindowsShortcut(lf);
3705 String fullname = wscfile.getRealFilename();
3706 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3707 files.set(f, fullname);
3708 Cache.log.debug("Parsed real filename " + fullname
3709 + " to extract protocol: " + protocols.get(f));
3710 } catch (Exception ex)
3713 "Couldn't parse " + files.get(f) + " as a link file.",
3722 * Sets the Preferences property for experimental features to True or False
3723 * depending on the state of the controlling menu item
3726 protected void showExperimental_actionPerformed(boolean selected)
3728 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3732 * Answers a (possibly empty) list of any structure viewer frames (currently for
3733 * either Jmol or Chimera) which are currently open. This may optionally be
3734 * restricted to viewers of a specified class, or viewers linked to a specified
3738 * if not null, only return viewers linked to this panel
3739 * @param structureViewerClass
3740 * if not null, only return viewers of this class
3743 public List<StructureViewerBase> getStructureViewers(
3744 AlignmentPanel apanel,
3745 Class<? extends StructureViewerBase> structureViewerClass)
3747 List<StructureViewerBase> result = new ArrayList<>();
3748 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3750 for (JInternalFrame frame : frames)
3752 if (frame instanceof StructureViewerBase)
3754 if (structureViewerClass == null
3755 || structureViewerClass.isInstance(frame))
3758 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3760 result.add((StructureViewerBase) frame);