2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import static jalview.util.UrlConstants.SEQUENCE_ID;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.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.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
80 import java.io.BufferedInputStream;
82 import java.io.FileOutputStream;
83 import java.io.IOException;
85 import java.util.ArrayList;
86 import java.util.Hashtable;
87 import java.util.List;
88 import java.util.ListIterator;
89 import java.util.StringTokenizer;
90 import java.util.Vector;
91 import java.util.concurrent.ExecutorService;
92 import java.util.concurrent.Executors;
93 import java.util.concurrent.Semaphore;
95 import javax.swing.AbstractAction;
96 import javax.swing.Action;
97 import javax.swing.ActionMap;
98 import javax.swing.Box;
99 import javax.swing.BoxLayout;
100 import javax.swing.DefaultDesktopManager;
101 import javax.swing.DesktopManager;
102 import javax.swing.InputMap;
103 import javax.swing.JButton;
104 import javax.swing.JCheckBox;
105 import javax.swing.JComboBox;
106 import javax.swing.JComponent;
107 import javax.swing.JDesktopPane;
108 import javax.swing.JFrame;
109 import javax.swing.JInternalFrame;
110 import javax.swing.JLabel;
111 import javax.swing.JMenuItem;
112 import javax.swing.JPanel;
113 import javax.swing.JPopupMenu;
114 import javax.swing.JProgressBar;
115 import javax.swing.KeyStroke;
116 import javax.swing.SwingUtilities;
117 import javax.swing.event.HyperlinkEvent;
118 import javax.swing.event.HyperlinkEvent.EventType;
119 import javax.swing.event.InternalFrameAdapter;
120 import javax.swing.event.InternalFrameEvent;
121 import javax.swing.event.MenuEvent;
122 import javax.swing.event.MenuListener;
124 import org.stackoverflowusers.file.WindowsShortcut;
131 * @version $Revision: 1.155 $
133 public class Desktop extends jalview.jbgui.GDesktop
134 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
135 jalview.api.StructureSelectionManagerProvider
137 private static int DEFAULT_MIN_WIDTH = 300;
139 private static int DEFAULT_MIN_HEIGHT = 250;
141 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
143 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
145 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
147 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
150 * news reader - null if it was never started.
152 private BlogReader jvnews = null;
154 private File projectFile;
158 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
160 public void addJalviewPropertyChangeListener(
161 PropertyChangeListener listener)
163 changeSupport.addJalviewPropertyChangeListener(listener);
167 * @param propertyName
169 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
170 * java.beans.PropertyChangeListener)
172 public void addJalviewPropertyChangeListener(String propertyName,
173 PropertyChangeListener listener)
175 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
179 * @param propertyName
181 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
182 * java.beans.PropertyChangeListener)
184 public void removeJalviewPropertyChangeListener(String propertyName,
185 PropertyChangeListener listener)
187 changeSupport.removeJalviewPropertyChangeListener(propertyName,
191 /** Singleton Desktop instance */
192 public static Desktop instance;
194 public static MyDesktopPane desktop;
196 static int openFrameCount = 0;
198 static final int xOffset = 30;
200 static final int yOffset = 30;
202 public static jalview.ws.jws1.Discoverer discoverer;
204 public static Object[] jalviewClipboard;
206 public static boolean internalCopy = false;
208 static int fileLoadingCount = 0;
210 class MyDesktopManager implements DesktopManager
213 private DesktopManager delegate;
215 public MyDesktopManager(DesktopManager delegate)
217 this.delegate = delegate;
221 public void activateFrame(JInternalFrame f)
225 delegate.activateFrame(f);
226 } catch (NullPointerException npe)
228 Point p = getMousePosition();
229 instance.showPasteMenu(p.x, p.y);
234 public void beginDraggingFrame(JComponent f)
236 delegate.beginDraggingFrame(f);
240 public void beginResizingFrame(JComponent f, int direction)
242 delegate.beginResizingFrame(f, direction);
246 public void closeFrame(JInternalFrame f)
248 delegate.closeFrame(f);
252 public void deactivateFrame(JInternalFrame f)
254 delegate.deactivateFrame(f);
258 public void deiconifyFrame(JInternalFrame f)
260 delegate.deiconifyFrame(f);
264 public void dragFrame(JComponent f, int newX, int newY)
270 delegate.dragFrame(f, newX, newY);
274 public void endDraggingFrame(JComponent f)
276 delegate.endDraggingFrame(f);
281 public void endResizingFrame(JComponent f)
283 delegate.endResizingFrame(f);
288 public void iconifyFrame(JInternalFrame f)
290 delegate.iconifyFrame(f);
294 public void maximizeFrame(JInternalFrame f)
296 delegate.maximizeFrame(f);
300 public void minimizeFrame(JInternalFrame f)
302 delegate.minimizeFrame(f);
306 public void openFrame(JInternalFrame f)
308 delegate.openFrame(f);
312 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
319 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
323 public void setBoundsForFrame(JComponent f, int newX, int newY,
324 int newWidth, int newHeight)
326 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
329 // All other methods, simply delegate
334 * Creates a new Desktop object.
339 * A note to implementors. It is ESSENTIAL that any activities that might
340 * block are spawned off as threads rather than waited for during this
344 doVamsasClientCheck();
346 doConfigureStructurePrefs();
347 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
348 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
349 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
351 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
353 desktop = new MyDesktopPane(selmemusage);
354 showMemusage.setSelected(selmemusage);
355 desktop.setBackground(Color.white);
356 getContentPane().setLayout(new BorderLayout());
357 // alternate config - have scrollbars - see notes in JAL-153
358 // JScrollPane sp = new JScrollPane();
359 // sp.getViewport().setView(desktop);
360 // getContentPane().add(sp, BorderLayout.CENTER);
361 getContentPane().add(desktop, BorderLayout.CENTER);
362 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
364 // This line prevents Windows Look&Feel resizing all new windows to maximum
365 // if previous window was maximised
366 desktop.setDesktopManager(
367 new MyDesktopManager(
368 (Platform.isWindows() ? new DefaultDesktopManager()
370 ? new AquaInternalFrameManager(
371 desktop.getDesktopManager())
372 : desktop.getDesktopManager())));
374 Rectangle dims = getLastKnownDimensions("");
381 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
382 int xPos = Math.max(5, (screenSize.width - 900) / 2);
383 int yPos = Math.max(5, (screenSize.height - 650) / 2);
384 setBounds(xPos, yPos, 900, 650);
393 jconsole = new Console(this, showjconsole);
394 // add essential build information
395 jconsole.setHeader("Jalview Version: "
396 + jalview.bin.Cache.getProperty("VERSION") + "\n"
397 + "Jalview Installation: "
398 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
399 + "\n" + "Build Date: "
400 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
401 + "Java version: " + System.getProperty("java.version") + "\n"
402 + System.getProperty("os.arch") + " "
403 + System.getProperty("os.name") + " "
404 + System.getProperty("os.version"));
406 showConsole(showjconsole);
408 showNews.setVisible(false);
410 experimentalFeatures.setSelected(showExperimental());
412 getIdentifiersOrgData();
416 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
417 // Spawn a thread that shows the splashscreen
419 SwingUtilities.invokeLater(new Runnable()
428 // Thread off a new instance of the file chooser - this reduces the time it
429 // takes to open it later on.
430 new Thread(new Runnable()
435 Cache.log.debug("Filechooser init thread started.");
436 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
437 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
439 Cache.log.debug("Filechooser init thread finished.");
442 // Add the service change listener
443 changeSupport.addJalviewPropertyChangeListener("services",
444 new PropertyChangeListener()
448 public void propertyChange(PropertyChangeEvent evt)
450 Cache.log.debug("Firing service changed event for "
451 + evt.getNewValue());
452 JalviewServicesChanged(evt);
457 } // end BH 2018 ignore
459 this.addWindowListener(new WindowAdapter()
462 public void windowClosing(WindowEvent evt)
469 this.addMouseListener(ma = new MouseAdapter()
472 public void mousePressed(MouseEvent evt)
474 if (evt.isPopupTrigger()) // Mac
476 showPasteMenu(evt.getX(), evt.getY());
481 public void mouseReleased(MouseEvent evt)
483 if (evt.isPopupTrigger()) // Windows
485 showPasteMenu(evt.getX(), evt.getY());
489 desktop.addMouseListener(ma);
494 * Answers true if user preferences to enable experimental features is True
499 public boolean showExperimental()
501 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
502 Boolean.FALSE.toString());
503 return Boolean.valueOf(experimental).booleanValue();
506 public void doConfigureStructurePrefs()
508 // configure services
509 StructureSelectionManager ssm = StructureSelectionManager
510 .getStructureSelectionManager(this);
511 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
513 ssm.setAddTempFacAnnot(jalview.bin.Cache
514 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
515 ssm.setProcessSecondaryStructure(jalview.bin.Cache
516 .getDefault(Preferences.STRUCT_FROM_PDB, true));
517 ssm.setSecStructServices(
518 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
522 ssm.setAddTempFacAnnot(false);
523 ssm.setProcessSecondaryStructure(false);
524 ssm.setSecStructServices(false);
528 public void checkForNews()
537 final Desktop me = this;
538 // Thread off the news reader, in case there are connection problems.
539 addDialogThread(new Runnable()
544 Cache.log.debug("Starting news thread.");
546 jvnews = new BlogReader(me);
547 showNews.setVisible(true);
548 Cache.log.debug("Completed news thread.");
554 public void getIdentifiersOrgData()
556 // Thread off the identifiers fetcher
557 addDialogThread(new Runnable()
562 Cache.log.debug("Downloading data from identifiers.org");
563 UrlDownloadClient client = new UrlDownloadClient();
566 client.download(IdOrgSettings.getUrl(),
567 IdOrgSettings.getDownloadLocation());
568 } catch (IOException e)
570 Cache.log.debug("Exception downloading identifiers.org data"
578 protected void showNews_actionPerformed(ActionEvent e)
580 showNews(showNews.isSelected());
583 void showNews(boolean visible)
592 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
593 showNews.setSelected(visible);
594 if (visible && !jvnews.isVisible())
596 new Thread(new Runnable()
601 long now = System.currentTimeMillis();
602 Desktop.instance.setProgressBar(
603 MessageManager.getString("status.refreshing_news"),
605 jvnews.refreshNews();
606 Desktop.instance.setProgressBar(null, now);
615 * recover the last known dimensions for a jalview window
618 * - empty string is desktop, all other windows have unique prefix
619 * @return null or last known dimensions scaled to current geometry (if last
620 * window geom was known)
622 Rectangle getLastKnownDimensions(String windowName)
624 // TODO: lock aspect ratio for scaling desktop Bug #0058199
625 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
626 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
627 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
628 String width = jalview.bin.Cache
629 .getProperty(windowName + "SCREEN_WIDTH");
630 String height = jalview.bin.Cache
631 .getProperty(windowName + "SCREEN_HEIGHT");
632 if ((x != null) && (y != null) && (width != null) && (height != null))
634 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
635 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
636 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
638 // attempt #1 - try to cope with change in screen geometry - this
639 // version doesn't preserve original jv aspect ratio.
640 // take ratio of current screen size vs original screen size.
641 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
642 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
643 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
644 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
645 // rescale the bounds depending upon the current screen geometry.
646 ix = (int) (ix * sw);
647 iw = (int) (iw * sw);
648 iy = (int) (iy * sh);
649 ih = (int) (ih * sh);
650 while (ix >= screenSize.width)
652 jalview.bin.Cache.log.debug(
653 "Window geometry location recall error: shifting horizontal to within screenbounds.");
654 ix -= screenSize.width;
656 while (iy >= screenSize.height)
658 jalview.bin.Cache.log.debug(
659 "Window geometry location recall error: shifting vertical to within screenbounds.");
660 iy -= screenSize.height;
662 jalview.bin.Cache.log.debug(
663 "Got last known dimensions for " + windowName + ": x:" + ix
664 + " y:" + iy + " width:" + iw + " height:" + ih);
666 // return dimensions for new instance
667 return new Rectangle(ix, iy, iw, ih);
672 private void doVamsasClientCheck()
674 if (/** @j2sNative false && */ // BH 2018
675 jalview.bin.Cache.vamsasJarsPresent())
677 setupVamsasDisconnectedGui();
678 VamsasMenu.setVisible(true);
679 final Desktop us = this;
680 VamsasMenu.addMenuListener(new MenuListener()
682 // this listener remembers when the menu was first selected, and
683 // doesn't rebuild the session list until it has been cleared and
685 boolean refresh = true;
688 public void menuCanceled(MenuEvent e)
694 public void menuDeselected(MenuEvent e)
700 public void menuSelected(MenuEvent e)
704 us.buildVamsasStMenu();
709 vamsasStart.setVisible(true);
713 void showPasteMenu(int x, int y)
715 JPopupMenu popup = new JPopupMenu();
716 JMenuItem item = new JMenuItem(
717 MessageManager.getString("label.paste_new_window"));
718 item.addActionListener(new ActionListener()
721 public void actionPerformed(ActionEvent evt)
728 popup.show(this, x, y);
735 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
736 Transferable contents = c.getContents(this);
738 if (contents != null)
740 String file = (String) contents
741 .getTransferData(DataFlavor.stringFlavor);
743 FileFormatI format = new IdentifyFile().identify(file,
744 DataSourceType.PASTE);
746 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
749 } catch (Exception ex)
752 "Unable to paste alignment from system clipboard:\n" + ex);
757 * Adds and opens the given frame to the desktop
768 public static synchronized void addInternalFrame(
769 final JInternalFrame frame, String title, int w, int h)
771 addInternalFrame(frame, title, true, w, h, true, false);
775 * Add an internal frame to the Jalview desktop
782 * When true, display frame immediately, otherwise, caller must call
783 * setVisible themselves.
789 public static synchronized void addInternalFrame(
790 final JInternalFrame frame, String title, boolean makeVisible,
793 addInternalFrame(frame, title, makeVisible, w, h, true, false);
797 * Add an internal frame to the Jalview desktop and make it visible
810 public static synchronized void addInternalFrame(
811 final JInternalFrame frame, String title, int w, int h,
814 addInternalFrame(frame, title, true, w, h, resizable, false);
818 * Add an internal frame to the Jalview desktop
825 * When true, display frame immediately, otherwise, caller must call
826 * setVisible themselves.
833 * @param ignoreMinSize
834 * Do not set the default minimum size for frame
836 public static synchronized void addInternalFrame(
837 final JInternalFrame frame, String title, boolean makeVisible,
838 int w, int h, boolean resizable, boolean ignoreMinSize)
841 // TODO: allow callers to determine X and Y position of frame (eg. via
843 // TODO: consider fixing method to update entries in the window submenu with
844 // the current window title
846 frame.setTitle(title);
847 if (frame.getWidth() < 1 || frame.getHeight() < 1)
851 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
852 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
853 // IF JALVIEW IS RUNNING HEADLESS
854 // ///////////////////////////////////////////////
855 if (instance == null || (System.getProperty("java.awt.headless") != null
856 && System.getProperty("java.awt.headless").equals("true")))
865 frame.setMinimumSize(
866 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
868 // Set default dimension for Alignment Frame window.
869 // The Alignment Frame window could be added from a number of places,
871 // I did this here in order not to miss out on any Alignment frame.
872 if (frame instanceof AlignFrame)
874 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
875 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
879 frame.setVisible(makeVisible);
880 frame.setClosable(true);
881 frame.setResizable(resizable);
882 frame.setMaximizable(resizable);
883 frame.setIconifiable(resizable);
884 frame.setOpaque(/** @j2sNative true || */
887 if (frame.getX() < 1 && frame.getY() < 1)
889 frame.setLocation(xOffset * openFrameCount,
890 yOffset * ((openFrameCount - 1) % 10) + yOffset);
894 * add an entry for the new frame in the Window menu
895 * (and remove it when the frame is closed)
897 final JMenuItem menuItem = new JMenuItem(title);
898 frame.addInternalFrameListener(new InternalFrameAdapter()
901 public void internalFrameActivated(InternalFrameEvent evt)
903 JInternalFrame itf = desktop.getSelectedFrame();
906 if (itf instanceof AlignFrame)
908 Jalview.setCurrentAlignFrame((AlignFrame) itf);
915 public void internalFrameClosed(InternalFrameEvent evt)
917 PaintRefresher.RemoveComponent(frame);
920 * defensive check to prevent frames being
921 * added half off the window
923 if (openFrameCount > 0)
929 * ensure no reference to alignFrame retained by menu item listener
931 if (menuItem.getActionListeners().length > 0)
933 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
935 windowMenu.remove(menuItem);
939 menuItem.addActionListener(new ActionListener()
942 public void actionPerformed(ActionEvent e)
946 frame.setSelected(true);
947 frame.setIcon(false);
948 } catch (java.beans.PropertyVetoException ex)
955 setKeyBindings(frame);
959 windowMenu.add(menuItem);
964 frame.setSelected(true);
965 frame.requestFocus();
966 } catch (java.beans.PropertyVetoException ve)
968 } catch (java.lang.ClassCastException cex)
971 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
977 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
982 private static void setKeyBindings(JInternalFrame frame)
984 @SuppressWarnings("serial")
985 final Action closeAction = new AbstractAction()
988 public void actionPerformed(ActionEvent e)
995 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
997 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
998 InputEvent.CTRL_DOWN_MASK);
999 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1000 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1002 InputMap inputMap = frame
1003 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1004 String ctrlW = ctrlWKey.toString();
1005 inputMap.put(ctrlWKey, ctrlW);
1006 inputMap.put(cmdWKey, ctrlW);
1008 ActionMap actionMap = frame.getActionMap();
1009 actionMap.put(ctrlW, closeAction);
1013 public void lostOwnership(Clipboard clipboard, Transferable contents)
1017 Desktop.jalviewClipboard = null;
1020 internalCopy = false;
1024 public void dragEnter(DropTargetDragEvent evt)
1029 public void dragExit(DropTargetEvent evt)
1034 public void dragOver(DropTargetDragEvent evt)
1039 public void dropActionChanged(DropTargetDragEvent evt)
1050 public void drop(DropTargetDropEvent evt)
1052 boolean success = true;
1053 // JAL-1552 - acceptDrop required before getTransferable call for
1054 // Java's Transferable for native dnd
1055 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1056 Transferable t = evt.getTransferable();
1057 List<String> files = new ArrayList<>();
1058 List<DataSourceType> protocols = new ArrayList<>();
1062 Desktop.transferFromDropTarget(files, protocols, evt, t);
1063 } catch (Exception e)
1065 e.printStackTrace();
1073 for (int i = 0; i < files.size(); i++)
1075 String file = files.get(i).toString();
1076 DataSourceType protocol = (protocols == null)
1077 ? DataSourceType.FILE
1079 FileFormatI format = null;
1081 if (file.endsWith(".jar"))
1083 format = FileFormat.Jalview;
1088 format = new IdentifyFile().identify(file, protocol);
1091 new FileLoader().LoadFile(file, protocol, format);
1094 } catch (Exception ex)
1099 evt.dropComplete(success); // need this to ensure input focus is properly
1100 // transfered to any new windows created
1110 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1112 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1113 JalviewFileChooser chooser = JalviewFileChooser
1114 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1116 chooser.setFileView(new JalviewFileView());
1117 chooser.setDialogTitle(
1118 MessageManager.getString("label.open_local_file"));
1119 chooser.setToolTipText(MessageManager.getString("action.open"));
1121 int value = chooser.showOpenDialog(this);
1123 if (value == JalviewFileChooser.APPROVE_OPTION)
1125 String choice = chooser.getSelectedFile().getPath();
1126 Cache.setProperty("LAST_DIRECTORY",
1127 chooser.getSelectedFile().getParent());
1129 FileFormatI format = chooser.getSelectedFormat();
1132 * Call IdentifyFile to verify the file contains what its extension implies.
1133 * Skip this step for dynamically added file formats, because
1134 * IdentifyFile does not know how to recognise them.
1136 if (FileFormats.getInstance().isIdentifiable(format))
1140 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1141 } catch (FileFormatException e)
1143 // format = null; //??
1147 if (viewport != null)
1149 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1154 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1166 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1168 // This construct allows us to have a wider textfield
1170 JLabel label = new JLabel(
1171 MessageManager.getString("label.input_file_url"));
1173 JComboBox history = new JComboBox();
1174 JPanel panel = new JPanel(new GridLayout(2, 1));
1177 history.setPreferredSize(new Dimension(400, 20));
1178 history.setEditable(true);
1179 history.addItem("http://www.");
1181 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1185 if (historyItems != null)
1187 st = new StringTokenizer(historyItems, "\t");
1189 while (st.hasMoreTokens())
1191 history.addItem(st.nextElement());
1195 // BH 2018 -- providing a callback for SwingJS
1196 // dialogOption is just a simple way to provide
1197 // context for the modal-like response.
1198 // The only requirement is that desktop implement
1199 // PropertyChangeListener, which is used already in Java
1200 // for changes in input value and such within the dialogs.
1202 String dialogOption = "label.input_alignment_from_url";
1203 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1204 desktop.onDialogReturn(
1205 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1206 MessageManager.getString(dialogOption),
1207 JvOptionPane.OK_CANCEL_OPTION));
1209 // no code may follow this, as SwingJS will not block
1210 // callback in JavaScript comes via a property change event,
1211 // thus going into desktop.onDialogReturn(int) just the same as
1218 * Opens the CutAndPaste window for the user to paste an alignment in to
1221 * - if not null, the pasted alignment is added to the current
1222 * alignment; if null, to a new alignment window
1225 public void inputTextboxMenuItem_actionPerformed(
1226 AlignmentViewPanel viewPanel)
1228 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1229 cap.setForInput(viewPanel);
1230 Desktop.addInternalFrame(cap,
1231 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1241 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1242 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1244 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1245 screen.height + "");
1246 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1247 getWidth(), getHeight()));
1249 if (jconsole != null)
1251 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1252 jconsole.stopConsole();
1256 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1259 if (dialogExecutor != null)
1261 dialogExecutor.shutdownNow();
1263 closeAll_actionPerformed(null);
1265 if (groovyConsole != null)
1267 // suppress a possible repeat prompt to save script
1268 groovyConsole.setDirty(false);
1269 groovyConsole.exit();
1274 private void storeLastKnownDimensions(String string, Rectangle jc)
1276 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1277 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1278 + " height:" + jc.height);
1280 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1281 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1282 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1283 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1293 public void aboutMenuItem_actionPerformed(ActionEvent e)
1295 // StringBuffer message = getAboutMessage(false);
1296 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1298 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1299 new Thread(new Runnable()
1304 new SplashScreen(true);
1309 public StringBuffer getAboutMessage(boolean shortv)
1311 StringBuffer message = new StringBuffer();
1312 message.append("<html>");
1315 message.append("<h1><strong>Version: "
1316 + jalview.bin.Cache.getProperty("VERSION")
1317 + "</strong></h1>");
1318 message.append("<strong>Last Updated: <em>"
1319 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1320 + "</em></strong>");
1326 message.append("<strong>Version "
1327 + jalview.bin.Cache.getProperty("VERSION")
1328 + "; last updated: "
1329 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1332 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1333 .equals("Checking"))
1335 message.append("<br>...Checking latest version...</br>");
1337 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1338 .equals(jalview.bin.Cache.getProperty("VERSION")))
1340 boolean red = false;
1341 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1342 .indexOf("automated build") == -1)
1345 // Displayed when code version and jnlp version do not match and code
1346 // version is not a development build
1347 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1350 message.append("<br>!! Version "
1351 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1353 + " is available for download from "
1354 + jalview.bin.Cache.getDefault("www.jalview.org",
1355 "http://www.jalview.org")
1359 message.append("</div>");
1362 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1364 "The Jalview Authors (See AUTHORS file for current list)")
1365 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1366 + "<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"
1367 + "<br><br>If you use Jalview, please cite:"
1368 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1369 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1370 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1382 public void documentationMenuItem_actionPerformed(ActionEvent e)
1386 Help.showHelpWindow();
1387 } catch (Exception ex)
1393 public void closeAll_actionPerformed(ActionEvent e)
1395 // TODO show a progress bar while closing?
1396 JInternalFrame[] frames = desktop.getAllFrames();
1397 for (int i = 0; i < frames.length; i++)
1401 frames[i].setClosed(true);
1402 } catch (java.beans.PropertyVetoException ex)
1406 Jalview.setCurrentAlignFrame(null);
1407 System.out.println("ALL CLOSED");
1408 if (v_client != null)
1410 // TODO clear binding to vamsas document objects on close_all
1414 * reset state of singleton objects as appropriate (clear down session state
1415 * when all windows are closed)
1417 StructureSelectionManager ssm = StructureSelectionManager
1418 .getStructureSelectionManager(this);
1426 public void raiseRelated_actionPerformed(ActionEvent e)
1428 reorderAssociatedWindows(false, false);
1432 public void minimizeAssociated_actionPerformed(ActionEvent e)
1434 reorderAssociatedWindows(true, false);
1437 void closeAssociatedWindows()
1439 reorderAssociatedWindows(false, true);
1445 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1449 protected void garbageCollect_actionPerformed(ActionEvent e)
1451 // We simply collect the garbage
1452 jalview.bin.Cache.log.debug("Collecting garbage...");
1454 jalview.bin.Cache.log.debug("Finished garbage collection.");
1461 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1465 protected void showMemusage_actionPerformed(ActionEvent e)
1467 desktop.showMemoryUsage(showMemusage.isSelected());
1474 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1478 protected void showConsole_actionPerformed(ActionEvent e)
1480 showConsole(showConsole.isSelected());
1483 Console jconsole = null;
1486 * control whether the java console is visible or not
1490 void showConsole(boolean selected)
1492 // TODO: decide if we should update properties file
1493 if (jconsole != null) // BH 2018
1495 showConsole.setSelected(selected);
1496 Cache.setProperty("SHOW_JAVA_CONSOLE",
1497 Boolean.valueOf(selected).toString());
1498 jconsole.setVisible(selected);
1502 void reorderAssociatedWindows(boolean minimize, boolean close)
1504 JInternalFrame[] frames = desktop.getAllFrames();
1505 if (frames == null || frames.length < 1)
1510 AlignmentViewport source = null, target = null;
1511 if (frames[0] instanceof AlignFrame)
1513 source = ((AlignFrame) frames[0]).getCurrentView();
1515 else if (frames[0] instanceof TreePanel)
1517 source = ((TreePanel) frames[0]).getViewPort();
1519 else if (frames[0] instanceof PCAPanel)
1521 source = ((PCAPanel) frames[0]).av;
1523 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1525 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1530 for (int i = 0; i < frames.length; i++)
1533 if (frames[i] == null)
1537 if (frames[i] instanceof AlignFrame)
1539 target = ((AlignFrame) frames[i]).getCurrentView();
1541 else if (frames[i] instanceof TreePanel)
1543 target = ((TreePanel) frames[i]).getViewPort();
1545 else if (frames[i] instanceof PCAPanel)
1547 target = ((PCAPanel) frames[i]).av;
1549 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1551 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1554 if (source == target)
1560 frames[i].setClosed(true);
1564 frames[i].setIcon(minimize);
1567 frames[i].toFront();
1571 } catch (java.beans.PropertyVetoException ex)
1586 protected void preferences_actionPerformed(ActionEvent e)
1598 public void saveState_actionPerformed(ActionEvent e)
1600 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1603 chooser.setFileView(new JalviewFileView());
1604 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1606 int value = chooser.showSaveDialog(this);
1608 if (value == JalviewFileChooser.APPROVE_OPTION)
1610 final Desktop me = this;
1611 final java.io.File choice = chooser.getSelectedFile();
1612 setProjectFile(choice);
1614 new Thread(new Runnable()
1619 // TODO: refactor to Jalview desktop session controller action.
1620 setProgressBar(MessageManager.formatMessage(
1621 "label.saving_jalview_project", new Object[]
1622 { choice.getName() }), choice.hashCode());
1623 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1624 choice.getParent());
1625 // TODO catch and handle errors for savestate
1626 // TODO prevent user from messing with the Desktop whilst we're saving
1629 new Jalview2XML().saveState(choice);
1630 } catch (OutOfMemoryError oom)
1633 "Whilst saving current state to " + choice.getName(),
1635 } catch (Exception ex)
1638 "Problems whilst trying to save to " + choice.getName(),
1640 JvOptionPane.showMessageDialog(me,
1641 MessageManager.formatMessage(
1642 "label.error_whilst_saving_current_state_to",
1644 { choice.getName() }),
1645 MessageManager.getString("label.couldnt_save_project"),
1646 JvOptionPane.WARNING_MESSAGE);
1648 setProgressBar(null, choice.hashCode());
1654 private void setProjectFile(File choice)
1656 this.projectFile = choice;
1659 public File getProjectFile()
1661 return this.projectFile;
1671 public void loadState_actionPerformed(ActionEvent e)
1673 JalviewFileChooser chooser = new JalviewFileChooser(
1674 Cache.getProperty("LAST_DIRECTORY"), new String[]
1677 { "Jalview Project", "Jalview Project (old)" },
1679 chooser.setFileView(new JalviewFileView());
1680 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1682 int value = chooser.showOpenDialog(this);
1684 if (value == JalviewFileChooser.APPROVE_OPTION)
1686 final File selectedFile = chooser.getSelectedFile();
1687 setProjectFile(selectedFile);
1688 final String choice = selectedFile.getAbsolutePath();
1689 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1690 new Thread(new Runnable()
1695 setProgressBar(MessageManager.formatMessage(
1696 "label.loading_jalview_project", new Object[]
1697 { choice }), choice.hashCode());
1700 new Jalview2XML().loadJalviewAlign(choice);
1701 } catch (OutOfMemoryError oom)
1703 new OOMWarning("Whilst loading project from " + choice, oom);
1704 } catch (Exception ex)
1707 "Problems whilst loading project from " + choice, ex);
1708 JvOptionPane.showMessageDialog(Desktop.desktop,
1709 MessageManager.formatMessage(
1710 "label.error_whilst_loading_project_from",
1713 MessageManager.getString("label.couldnt_load_project"),
1714 JvOptionPane.WARNING_MESSAGE);
1716 setProgressBar(null, choice.hashCode());
1723 public void inputSequence_actionPerformed(ActionEvent e)
1725 new SequenceFetcher(this);
1728 JPanel progressPanel;
1730 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1732 public void startLoading(final String fileName)
1734 if (fileLoadingCount == 0)
1736 fileLoadingPanels.add(addProgressPanel(MessageManager
1737 .formatMessage("label.loading_file", new Object[]
1743 private JPanel addProgressPanel(String string)
1745 if (progressPanel == null)
1747 progressPanel = new JPanel(new GridLayout(1, 1));
1748 totalProgressCount = 0;
1749 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1751 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1752 JProgressBar progressBar = new JProgressBar();
1753 progressBar.setIndeterminate(true);
1755 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1757 thisprogress.add(progressBar, BorderLayout.CENTER);
1758 progressPanel.add(thisprogress);
1759 ((GridLayout) progressPanel.getLayout()).setRows(
1760 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1761 ++totalProgressCount;
1762 instance.validate();
1763 return thisprogress;
1766 int totalProgressCount = 0;
1768 private void removeProgressPanel(JPanel progbar)
1770 if (progressPanel != null)
1772 synchronized (progressPanel)
1774 progressPanel.remove(progbar);
1775 GridLayout gl = (GridLayout) progressPanel.getLayout();
1776 gl.setRows(gl.getRows() - 1);
1777 if (--totalProgressCount < 1)
1779 this.getContentPane().remove(progressPanel);
1780 progressPanel = null;
1787 public void stopLoading()
1790 if (fileLoadingCount < 1)
1792 while (fileLoadingPanels.size() > 0)
1794 removeProgressPanel(fileLoadingPanels.remove(0));
1796 fileLoadingPanels.clear();
1797 fileLoadingCount = 0;
1802 public static int getViewCount(String alignmentId)
1804 AlignmentViewport[] aps = getViewports(alignmentId);
1805 return (aps == null) ? 0 : aps.length;
1810 * @param alignmentId
1811 * - if null, all sets are returned
1812 * @return all AlignmentPanels concerning the alignmentId sequence set
1814 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1816 if (Desktop.desktop == null)
1818 // no frames created and in headless mode
1819 // TODO: verify that frames are recoverable when in headless mode
1822 List<AlignmentPanel> aps = new ArrayList<>();
1823 AlignFrame[] frames = getAlignFrames();
1828 for (AlignFrame af : frames)
1830 for (AlignmentPanel ap : af.alignPanels)
1832 if (alignmentId == null
1833 || alignmentId.equals(ap.av.getSequenceSetId()))
1839 if (aps.size() == 0)
1843 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1848 * get all the viewports on an alignment.
1850 * @param sequenceSetId
1851 * unique alignment id (may be null - all viewports returned in that
1853 * @return all viewports on the alignment bound to sequenceSetId
1855 public static AlignmentViewport[] getViewports(String sequenceSetId)
1857 List<AlignmentViewport> viewp = new ArrayList<>();
1858 if (desktop != null)
1860 AlignFrame[] frames = Desktop.getAlignFrames();
1862 for (AlignFrame afr : frames)
1864 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1865 .equals(sequenceSetId))
1867 if (afr.alignPanels != null)
1869 for (AlignmentPanel ap : afr.alignPanels)
1871 if (sequenceSetId == null
1872 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1880 viewp.add(afr.getViewport());
1884 if (viewp.size() > 0)
1886 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1893 * Explode the views in the given frame into separate AlignFrame
1897 public static void explodeViews(AlignFrame af)
1899 int size = af.alignPanels.size();
1905 for (int i = 0; i < size; i++)
1907 AlignmentPanel ap = af.alignPanels.get(i);
1908 AlignFrame newaf = new AlignFrame(ap);
1911 * Restore the view's last exploded frame geometry if known. Multiple
1912 * views from one exploded frame share and restore the same (frame)
1913 * position and size.
1915 Rectangle geometry = ap.av.getExplodedGeometry();
1916 if (geometry != null)
1918 newaf.setBounds(geometry);
1921 ap.av.setGatherViewsHere(false);
1923 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1924 AlignFrame.DEFAULT_HEIGHT);
1927 af.alignPanels.clear();
1928 af.closeMenuItem_actionPerformed(true);
1933 * Gather expanded views (separate AlignFrame's) with the same sequence set
1934 * identifier back in to this frame as additional views, and close the
1935 * expanded views. Note the expanded frames may themselves have multiple
1936 * views. We take the lot.
1940 public void gatherViews(AlignFrame source)
1942 source.viewport.setGatherViewsHere(true);
1943 source.viewport.setExplodedGeometry(source.getBounds());
1944 JInternalFrame[] frames = desktop.getAllFrames();
1945 String viewId = source.viewport.getSequenceSetId();
1947 for (int t = 0; t < frames.length; t++)
1949 if (frames[t] instanceof AlignFrame && frames[t] != source)
1951 AlignFrame af = (AlignFrame) frames[t];
1952 boolean gatherThis = false;
1953 for (int a = 0; a < af.alignPanels.size(); a++)
1955 AlignmentPanel ap = af.alignPanels.get(a);
1956 if (viewId.equals(ap.av.getSequenceSetId()))
1959 ap.av.setGatherViewsHere(false);
1960 ap.av.setExplodedGeometry(af.getBounds());
1961 source.addAlignmentPanel(ap, false);
1967 af.alignPanels.clear();
1968 af.closeMenuItem_actionPerformed(true);
1975 jalview.gui.VamsasApplication v_client = null;
1978 public void vamsasImport_actionPerformed(ActionEvent e)
1980 if (v_client == null)
1982 // Load and try to start a session.
1983 JalviewFileChooser chooser = new JalviewFileChooser(
1984 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1986 chooser.setFileView(new JalviewFileView());
1987 chooser.setDialogTitle(
1988 MessageManager.getString("label.open_saved_vamsas_session"));
1989 chooser.setToolTipText(MessageManager.getString(
1990 "label.select_vamsas_session_opened_as_new_vamsas_session"));
1992 int value = chooser.showOpenDialog(this);
1994 if (value == JalviewFileChooser.APPROVE_OPTION)
1996 String fle = chooser.getSelectedFile().toString();
1997 if (!vamsasImport(chooser.getSelectedFile()))
1999 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2000 MessageManager.formatMessage(
2001 "label.couldnt_import_as_vamsas_session",
2005 .getString("label.vamsas_document_import_failed"),
2006 JvOptionPane.ERROR_MESSAGE);
2012 jalview.bin.Cache.log.error(
2013 "Implementation error - load session from a running session is not supported.");
2018 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2021 * @return true if import was a success and a session was started.
2023 public boolean vamsasImport(URL url)
2025 // TODO: create progress bar
2026 if (v_client != null)
2029 jalview.bin.Cache.log.error(
2030 "Implementation error - load session from a running session is not supported.");
2036 // copy the URL content to a temporary local file
2037 // TODO: be a bit cleverer here with nio (?!)
2038 File file = File.createTempFile("vdocfromurl", ".vdj");
2039 FileOutputStream fos = new FileOutputStream(file);
2040 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2041 byte[] buffer = new byte[2048];
2043 while ((ln = bis.read(buffer)) > -1)
2045 fos.write(buffer, 0, ln);
2049 v_client = new jalview.gui.VamsasApplication(this, file,
2050 url.toExternalForm());
2051 } catch (Exception ex)
2053 jalview.bin.Cache.log.error(
2054 "Failed to create new vamsas session from contents of URL "
2059 setupVamsasConnectedGui();
2060 v_client.initial_update(); // TODO: thread ?
2061 return v_client.inSession();
2065 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2068 * @return true if import was a success and a session was started.
2070 public boolean vamsasImport(File file)
2072 if (v_client != null)
2075 jalview.bin.Cache.log.error(
2076 "Implementation error - load session from a running session is not supported.");
2080 setProgressBar(MessageManager.formatMessage(
2081 "status.importing_vamsas_session_from", new Object[]
2082 { file.getName() }), file.hashCode());
2085 v_client = new jalview.gui.VamsasApplication(this, file, null);
2086 } catch (Exception ex)
2088 setProgressBar(MessageManager.formatMessage(
2089 "status.importing_vamsas_session_from", new Object[]
2090 { file.getName() }), file.hashCode());
2091 jalview.bin.Cache.log.error(
2092 "New vamsas session from existing session file failed:", ex);
2095 setupVamsasConnectedGui();
2096 v_client.initial_update(); // TODO: thread ?
2097 setProgressBar(MessageManager.formatMessage(
2098 "status.importing_vamsas_session_from", new Object[]
2099 { file.getName() }), file.hashCode());
2100 return v_client.inSession();
2103 public boolean joinVamsasSession(String mysesid)
2105 if (v_client != null)
2107 throw new Error(MessageManager
2108 .getString("error.try_join_vamsas_session_another"));
2110 if (mysesid == null)
2113 MessageManager.getString("error.invalid_vamsas_session_id"));
2115 v_client = new VamsasApplication(this, mysesid);
2116 setupVamsasConnectedGui();
2117 v_client.initial_update();
2118 return (v_client.inSession());
2122 public void vamsasStart_actionPerformed(ActionEvent e)
2124 if (v_client == null)
2127 // we just start a default session for moment.
2129 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2130 * getProperty("LAST_DIRECTORY"));
2132 * chooser.setFileView(new JalviewFileView());
2133 * chooser.setDialogTitle("Load Vamsas file");
2134 * chooser.setToolTipText("Import");
2136 * int value = chooser.showOpenDialog(this);
2138 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2139 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2141 v_client = new VamsasApplication(this);
2142 setupVamsasConnectedGui();
2143 v_client.initial_update(); // TODO: thread ?
2147 // store current data in session.
2148 v_client.push_update(); // TODO: thread
2152 protected void setupVamsasConnectedGui()
2154 vamsasStart.setText(MessageManager.getString("label.session_update"));
2155 vamsasSave.setVisible(true);
2156 vamsasStop.setVisible(true);
2157 vamsasImport.setVisible(false); // Document import to existing session is
2158 // not possible for vamsas-client-1.0.
2161 protected void setupVamsasDisconnectedGui()
2163 vamsasSave.setVisible(false);
2164 vamsasStop.setVisible(false);
2165 vamsasImport.setVisible(true);
2167 .setText(MessageManager.getString("label.new_vamsas_session"));
2171 public void vamsasStop_actionPerformed(ActionEvent e)
2173 if (v_client != null)
2175 v_client.end_session();
2177 setupVamsasDisconnectedGui();
2181 protected void buildVamsasStMenu()
2183 if (v_client == null)
2185 String[] sess = null;
2188 sess = VamsasApplication.getSessionList();
2189 } catch (Exception e)
2191 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2197 jalview.bin.Cache.log.debug(
2198 "Got current sessions list: " + sess.length + " entries.");
2199 VamsasStMenu.removeAll();
2200 for (int i = 0; i < sess.length; i++)
2202 JMenuItem sessit = new JMenuItem();
2203 sessit.setText(sess[i]);
2204 sessit.setToolTipText(MessageManager
2205 .formatMessage("label.connect_to_session", new Object[]
2207 final Desktop dsktp = this;
2208 final String mysesid = sess[i];
2209 sessit.addActionListener(new ActionListener()
2213 public void actionPerformed(ActionEvent e)
2215 if (dsktp.v_client == null)
2217 Thread rthr = new Thread(new Runnable()
2223 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2224 dsktp.setupVamsasConnectedGui();
2225 dsktp.v_client.initial_update();
2233 VamsasStMenu.add(sessit);
2235 // don't show an empty menu.
2236 VamsasStMenu.setVisible(sess.length > 0);
2241 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2242 VamsasStMenu.removeAll();
2243 VamsasStMenu.setVisible(false);
2248 // Not interested in the content. Just hide ourselves.
2249 VamsasStMenu.setVisible(false);
2254 public void vamsasSave_actionPerformed(ActionEvent e)
2256 if (v_client != null)
2258 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2259 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2262 chooser.setFileView(new JalviewFileView());
2263 chooser.setDialogTitle(MessageManager
2264 .getString("label.save_vamsas_document_archive"));
2266 int value = chooser.showSaveDialog(this);
2268 if (value == JalviewFileChooser.APPROVE_OPTION)
2270 java.io.File choice = chooser.getSelectedFile();
2271 JPanel progpanel = addProgressPanel(MessageManager
2272 .formatMessage("label.saving_vamsas_doc", new Object[]
2273 { choice.getName() }));
2274 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2275 String warnmsg = null;
2276 String warnttl = null;
2279 v_client.vclient.storeDocument(choice);
2282 warnttl = "Serious Problem saving Vamsas Document";
2283 warnmsg = ex.toString();
2284 jalview.bin.Cache.log
2285 .error("Error Whilst saving document to " + choice, ex);
2287 } catch (Exception ex)
2289 warnttl = "Problem saving Vamsas Document.";
2290 warnmsg = ex.toString();
2291 jalview.bin.Cache.log.warn(
2292 "Exception Whilst saving document to " + choice, ex);
2295 removeProgressPanel(progpanel);
2296 if (warnmsg != null)
2298 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2300 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2306 JPanel vamUpdate = null;
2309 * hide vamsas user gui bits when a vamsas document event is being handled.
2312 * true to hide gui, false to reveal gui
2314 public void setVamsasUpdate(boolean b)
2316 Cache.log.debug("Setting gui for Vamsas update "
2317 + (b ? "in progress" : "finished"));
2319 if (vamUpdate != null)
2321 this.removeProgressPanel(vamUpdate);
2325 vamUpdate = this.addProgressPanel(
2326 MessageManager.getString("label.updating_vamsas_session"));
2328 vamsasStart.setVisible(!b);
2329 vamsasStop.setVisible(!b);
2330 vamsasSave.setVisible(!b);
2333 public JInternalFrame[] getAllFrames()
2335 return desktop.getAllFrames();
2339 * Checks the given url to see if it gives a response indicating that the user
2340 * should be informed of a new questionnaire.
2344 public void checkForQuestionnaire(String url)
2346 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2347 // javax.swing.SwingUtilities.invokeLater(jvq);
2348 new Thread(jvq).start();
2351 public void checkURLLinks()
2353 // Thread off the URL link checker
2354 addDialogThread(new Runnable()
2359 if (/** @j2sNative false && */ // BH 2018
2360 Cache.getDefault("CHECKURLLINKS", true))
2362 // check what the actual links are - if it's just the default don't
2363 // bother with the warning
2364 List<String> links = Preferences.sequenceUrlLinks
2367 // only need to check links if there is one with a
2368 // SEQUENCE_ID which is not the default EMBL_EBI link
2369 ListIterator<String> li = links.listIterator();
2370 boolean check = false;
2371 List<JLabel> urls = new ArrayList<>();
2372 while (li.hasNext())
2374 String link = li.next();
2375 if (link.contains(SEQUENCE_ID)
2376 && !UrlConstants.isDefaultString(link))
2379 int barPos = link.indexOf("|");
2380 String urlMsg = barPos == -1 ? link
2381 : link.substring(0, barPos) + ": "
2382 + link.substring(barPos + 1);
2383 urls.add(new JLabel(urlMsg));
2391 // ask user to check in case URL links use old style tokens
2392 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2393 JPanel msgPanel = new JPanel();
2394 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2395 msgPanel.add(Box.createVerticalGlue());
2396 JLabel msg = new JLabel(MessageManager
2397 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2398 JLabel msg2 = new JLabel(MessageManager
2399 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2401 for (JLabel url : urls)
2407 final JCheckBox jcb = new JCheckBox(
2408 MessageManager.getString("label.do_not_display_again"));
2409 jcb.addActionListener(new ActionListener()
2412 public void actionPerformed(ActionEvent e)
2414 // update Cache settings for "don't show this again"
2415 boolean showWarningAgain = !jcb.isSelected();
2416 Cache.setProperty("CHECKURLLINKS",
2417 Boolean.valueOf(showWarningAgain).toString());
2422 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2424 .getString("label.SEQUENCE_ID_no_longer_used"),
2425 JvOptionPane.WARNING_MESSAGE);
2432 * Proxy class for JDesktopPane which optionally displays the current memory
2433 * usage and highlights the desktop area with a red bar if free memory runs
2438 public class MyDesktopPane extends JDesktopPane
2439 implements Runnable, PropertyChangeListener
2442 public Object[] dialogData;
2446 public void propertyChange(PropertyChangeEvent event)
2448 Object val = event.getNewValue();
2449 String name = event.getPropertyName();
2450 System.out.println(name);
2451 switch (event.getSource().getClass().getName())
2453 case "javax.swing.JOptionPane":
2457 onDialogReturn(val);
2460 if (val instanceof Integer)
2462 onDialogReturn(((Integer) val).intValue());
2466 onDialogReturn(val);
2471 case "javax.swing.ColorChooserDialog":
2474 case "SelectedColor":
2475 onDialogReturn(val);
2479 case "javax.swing.JFileChooser":
2482 case "SelectedFile":
2483 File file = (File) val;
2484 byte[] array = (val == null ? null
2485 : /** @j2sNative file._bytes || */
2487 onDialogReturn("fileName is '" + file.getName() + "'\n\n"
2488 + new String(array));
2493 System.out.println(event.getSource().getClass().getName() + " "
2494 + event.getPropertyName() + ": " + event.getNewValue());
2497 // JSCOmponent.DialogCaller interface
2498 private void onDialogReturn(Object value)
2500 System.out.println("not implemented");
2503 // JSCOmponent.DialogCaller interface
2504 void onDialogReturn(int value)
2506 if (value != Math.floor(value))
2508 // in JavaScript, this will be NaN, oddly enough
2512 switch ((String) dialogData[0])
2514 case "label.input_alignment_from_url":
2515 // reconstruct the parameter data
2517 AlignViewport viewport = (AlignViewport) dialogData[1];
2518 JComboBox history = (JComboBox) dialogData[2];
2519 // the rest of this is unchangaed
2520 if (reply != JvOptionPane.OK_OPTION)
2525 String url = history.getSelectedItem().toString();
2527 if (url.toLowerCase().endsWith(".jar"))
2529 if (viewport != null)
2531 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2532 FileFormat.Jalview);
2536 new FileLoader().LoadFile(url, DataSourceType.URL,
2537 FileFormat.Jalview);
2542 FileFormatI format = null;
2545 format = new IdentifyFile().identify(url, DataSourceType.URL);
2546 } catch (FileFormatException e)
2548 // TODO revise error handling, distinguish between
2549 // URL not found and response not valid
2554 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2555 MessageManager.formatMessage("label.couldnt_locate",
2558 MessageManager.getString("label.url_not_found"),
2559 JvOptionPane.WARNING_MESSAGE);
2564 if (viewport != null)
2566 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2571 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2580 private static final float ONE_MB = 1048576f;
2582 boolean showMemoryUsage = false;
2586 java.text.NumberFormat df;
2588 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2591 public MyDesktopPane(boolean showMemoryUsage)
2593 showMemoryUsage(showMemoryUsage);
2596 public void showMemoryUsage(boolean showMemory)
2598 this.showMemoryUsage = showMemory;
2601 Thread worker = new Thread(this);
2607 public boolean isShowMemoryUsage()
2609 return showMemoryUsage;
2615 df = java.text.NumberFormat.getNumberInstance();
2616 df.setMaximumFractionDigits(2);
2617 runtime = Runtime.getRuntime();
2619 while (showMemoryUsage)
2623 maxMemory = runtime.maxMemory() / ONE_MB;
2624 allocatedMemory = runtime.totalMemory() / ONE_MB;
2625 freeMemory = runtime.freeMemory() / ONE_MB;
2626 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2628 percentUsage = (totalFreeMemory / maxMemory) * 100;
2630 // if (percentUsage < 20)
2632 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2634 // instance.set.setBorder(border1);
2637 // sleep after showing usage
2639 } catch (Exception ex)
2641 ex.printStackTrace();
2647 public void paintComponent(Graphics g)
2649 if (showMemoryUsage && g != null && df != null)
2651 if (percentUsage < 20)
2653 g.setColor(Color.red);
2655 FontMetrics fm = g.getFontMetrics();
2658 g.drawString(MessageManager.formatMessage("label.memory_stats",
2660 { df.format(totalFreeMemory), df.format(maxMemory),
2661 df.format(percentUsage) }),
2662 10, getHeight() - fm.getHeight());
2670 * Accessor method to quickly get all the AlignmentFrames loaded.
2672 * @return an array of AlignFrame, or null if none found
2674 public static AlignFrame[] getAlignFrames()
2676 if (Jalview.isHeadlessMode())
2678 // Desktop.desktop is null in headless mode
2679 return new AlignFrame[] { Jalview.currentAlignFrame };
2682 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2688 List<AlignFrame> avp = new ArrayList<>();
2690 for (int i = frames.length - 1; i > -1; i--)
2692 if (frames[i] instanceof AlignFrame)
2694 avp.add((AlignFrame) frames[i]);
2696 else if (frames[i] instanceof SplitFrame)
2699 * Also check for a split frame containing an AlignFrame
2701 GSplitFrame sf = (GSplitFrame) frames[i];
2702 if (sf.getTopFrame() instanceof AlignFrame)
2704 avp.add((AlignFrame) sf.getTopFrame());
2706 if (sf.getBottomFrame() instanceof AlignFrame)
2708 avp.add((AlignFrame) sf.getBottomFrame());
2712 if (avp.size() == 0)
2716 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2721 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2725 public GStructureViewer[] getJmols()
2727 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2733 List<GStructureViewer> avp = new ArrayList<>();
2735 for (int i = frames.length - 1; i > -1; i--)
2737 if (frames[i] instanceof AppJmol)
2739 GStructureViewer af = (GStructureViewer) frames[i];
2743 if (avp.size() == 0)
2747 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2752 * Add Groovy Support to Jalview
2755 public void groovyShell_actionPerformed()
2759 openGroovyConsole();
2760 } catch (Exception ex)
2762 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2763 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2765 MessageManager.getString("label.couldnt_create_groovy_shell"),
2766 MessageManager.getString("label.groovy_support_failed"),
2767 JvOptionPane.ERROR_MESSAGE);
2772 * Open the Groovy console
2774 void openGroovyConsole()
2776 if (groovyConsole == null)
2778 groovyConsole = new groovy.ui.Console();
2779 groovyConsole.setVariable("Jalview", this);
2780 groovyConsole.run();
2783 * We allow only one console at a time, so that AlignFrame menu option
2784 * 'Calculate | Run Groovy script' is unambiguous.
2785 * Disable 'Groovy Console', and enable 'Run script', when the console is
2786 * opened, and the reverse when it is closed
2788 Window window = (Window) groovyConsole.getFrame();
2789 window.addWindowListener(new WindowAdapter()
2792 public void windowClosed(WindowEvent e)
2795 * rebind CMD-Q from Groovy Console to Jalview Quit
2798 enableExecuteGroovy(false);
2804 * show Groovy console window (after close and reopen)
2806 ((Window) groovyConsole.getFrame()).setVisible(true);
2809 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2810 * and disable opening a second console
2812 enableExecuteGroovy(true);
2816 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2817 * binding when opened
2819 protected void addQuitHandler()
2821 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2822 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2823 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2825 getRootPane().getActionMap().put("Quit", new AbstractAction()
2828 public void actionPerformed(ActionEvent e)
2836 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2839 * true if Groovy console is open
2841 public void enableExecuteGroovy(boolean enabled)
2844 * disable opening a second Groovy console
2845 * (or re-enable when the console is closed)
2847 groovyShell.setEnabled(!enabled);
2849 AlignFrame[] alignFrames = getAlignFrames();
2850 if (alignFrames != null)
2852 for (AlignFrame af : alignFrames)
2854 af.setGroovyEnabled(enabled);
2860 * Progress bars managed by the IProgressIndicator method.
2862 private Hashtable<Long, JPanel> progressBars;
2864 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2869 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2872 public void setProgressBar(String message, long id)
2874 if (progressBars == null)
2876 progressBars = new Hashtable<>();
2877 progressBarHandlers = new Hashtable<>();
2880 if (progressBars.get(new Long(id)) != null)
2882 JPanel panel = progressBars.remove(new Long(id));
2883 if (progressBarHandlers.contains(new Long(id)))
2885 progressBarHandlers.remove(new Long(id));
2887 removeProgressPanel(panel);
2891 progressBars.put(new Long(id), addProgressPanel(message));
2898 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2899 * jalview.gui.IProgressIndicatorHandler)
2902 public void registerHandler(final long id,
2903 final IProgressIndicatorHandler handler)
2905 if (progressBarHandlers == null
2906 || !progressBars.containsKey(new Long(id)))
2908 throw new Error(MessageManager.getString(
2909 "error.call_setprogressbar_before_registering_handler"));
2911 progressBarHandlers.put(new Long(id), handler);
2912 final JPanel progressPanel = progressBars.get(new Long(id));
2913 if (handler.canCancel())
2915 JButton cancel = new JButton(
2916 MessageManager.getString("action.cancel"));
2917 final IProgressIndicator us = this;
2918 cancel.addActionListener(new ActionListener()
2922 public void actionPerformed(ActionEvent e)
2924 handler.cancelActivity(id);
2925 us.setProgressBar(MessageManager
2926 .formatMessage("label.cancelled_params", new Object[]
2927 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2931 progressPanel.add(cancel, BorderLayout.EAST);
2937 * @return true if any progress bars are still active
2940 public boolean operationInProgress()
2942 if (progressBars != null && progressBars.size() > 0)
2950 * This will return the first AlignFrame holding the given viewport instance.
2951 * It will break if there are more than one AlignFrames viewing a particular
2955 * @return alignFrame for viewport
2957 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2959 if (desktop != null)
2961 AlignmentPanel[] aps = getAlignmentPanels(
2962 viewport.getSequenceSetId());
2963 for (int panel = 0; aps != null && panel < aps.length; panel++)
2965 if (aps[panel] != null && aps[panel].av == viewport)
2967 return aps[panel].alignFrame;
2974 public VamsasApplication getVamsasApplication()
2981 * flag set if jalview GUI is being operated programmatically
2983 private boolean inBatchMode = false;
2986 * check if jalview GUI is being operated programmatically
2988 * @return inBatchMode
2990 public boolean isInBatchMode()
2996 * set flag if jalview GUI is being operated programmatically
2998 * @param inBatchMode
3000 public void setInBatchMode(boolean inBatchMode)
3002 this.inBatchMode = inBatchMode;
3005 public void startServiceDiscovery()
3007 startServiceDiscovery(false);
3010 public void startServiceDiscovery(boolean blocking)
3012 boolean alive = true;
3013 Thread t0 = null, t1 = null, t2 = null;
3014 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3017 // todo: changesupport handlers need to be transferred
3018 if (discoverer == null)
3020 discoverer = new jalview.ws.jws1.Discoverer();
3021 // register PCS handler for desktop.
3022 discoverer.addPropertyChangeListener(changeSupport);
3024 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3025 // until we phase out completely
3026 (t0 = new Thread(discoverer)).start();
3029 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3031 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3032 .startDiscoverer(changeSupport);
3036 // TODO: do rest service discovery
3045 } catch (Exception e)
3048 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3049 || (t3 != null && t3.isAlive())
3050 || (t0 != null && t0.isAlive());
3056 * called to check if the service discovery process completed successfully.
3060 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3062 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3064 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3065 .getErrorMessages();
3068 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3070 if (serviceChangedDialog == null)
3072 // only run if we aren't already displaying one of these.
3073 addDialogThread(serviceChangedDialog = new Runnable()
3080 * JalviewDialog jd =new JalviewDialog() {
3082 * @Override protected void cancelPressed() { // TODO
3083 * Auto-generated method stub
3085 * }@Override protected void okPressed() { // TODO
3086 * Auto-generated method stub
3088 * }@Override protected void raiseClosed() { // TODO
3089 * Auto-generated method stub
3091 * } }; jd.initDialogFrame(new
3092 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3093 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3094 * + " or mis-configured HTTP proxy settings.<br/>" +
3095 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3097 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3098 * ), true, true, "Web Service Configuration Problem", 450,
3101 * jd.waitForInput();
3103 JvOptionPane.showConfirmDialog(Desktop.desktop,
3104 new JLabel("<html><table width=\"450\"><tr><td>"
3105 + ermsg + "</td></tr></table>"
3106 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3107 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3108 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3109 + " Tools->Preferences dialog box to change them.</p></html>"),
3110 "Web Service Configuration Problem",
3111 JvOptionPane.DEFAULT_OPTION,
3112 JvOptionPane.ERROR_MESSAGE);
3113 serviceChangedDialog = null;
3122 "Errors reported by JABA discovery service. Check web services preferences.\n"
3129 private Runnable serviceChangedDialog = null;
3132 * start a thread to open a URL in the configured browser. Pops up a warning
3133 * dialog to the user if there is an exception when calling out to the browser
3138 public static void showUrl(final String url)
3140 showUrl(url, Desktop.instance);
3144 * Like showUrl but allows progress handler to be specified
3148 * (null) or object implementing IProgressIndicator
3150 public static void showUrl(final String url,
3151 final IProgressIndicator progress)
3153 new Thread(new Runnable()
3160 if (progress != null)
3162 progress.setProgressBar(MessageManager
3163 .formatMessage("status.opening_params", new Object[]
3164 { url }), this.hashCode());
3166 jalview.util.BrowserLauncher.openURL(url);
3167 } catch (Exception ex)
3169 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3171 .getString("label.web_browser_not_found_unix"),
3172 MessageManager.getString("label.web_browser_not_found"),
3173 JvOptionPane.WARNING_MESSAGE);
3175 ex.printStackTrace();
3177 if (progress != null)
3179 progress.setProgressBar(null, this.hashCode());
3185 public static WsParamSetManager wsparamManager = null;
3187 public static ParamManager getUserParameterStore()
3189 if (wsparamManager == null)
3191 wsparamManager = new WsParamSetManager();
3193 return wsparamManager;
3197 * static hyperlink handler proxy method for use by Jalview's internal windows
3201 public static void hyperlinkUpdate(HyperlinkEvent e)
3203 if (e.getEventType() == EventType.ACTIVATED)
3208 url = e.getURL().toString();
3209 Desktop.showUrl(url);
3210 } catch (Exception x)
3214 if (Cache.log != null)
3216 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3221 "Couldn't handle string " + url + " as a URL.");
3224 // ignore any exceptions due to dud links.
3231 * single thread that handles display of dialogs to user.
3233 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3236 * flag indicating if dialogExecutor should try to acquire a permit
3238 private volatile boolean dialogPause = true;
3243 private java.util.concurrent.Semaphore block = new Semaphore(0);
3245 private static groovy.ui.Console groovyConsole;
3248 * add another dialog thread to the queue
3252 public void addDialogThread(final Runnable prompter)
3254 dialogExecutor.submit(new Runnable()
3264 } catch (InterruptedException x)
3269 if (instance == null)
3275 SwingUtilities.invokeAndWait(prompter);
3276 } catch (Exception q)
3278 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3284 public void startDialogQueue()
3286 // set the flag so we don't pause waiting for another permit and semaphore
3287 // the current task to begin
3288 dialogPause = false;
3293 protected void snapShotWindow_actionPerformed(ActionEvent e)
3297 ImageMaker im = new jalview.util.ImageMaker(
3298 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3299 getHeight(), of = new File("Jalview_snapshot"
3300 + System.currentTimeMillis() + ".eps"),
3301 "View of desktop", null, 0, false);
3304 paintAll(im.getGraphics());
3306 } catch (Exception q)
3308 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3312 Cache.log.info("Successfully written snapshot to file "
3313 + of.getAbsolutePath());
3317 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3318 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3319 * and location last time the view was expanded (if any). However it does not
3320 * remember the split pane divider location - this is set to match the
3321 * 'exploding' frame.
3325 public void explodeViews(SplitFrame sf)
3327 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3328 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3329 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3331 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3333 int viewCount = topPanels.size();
3340 * Processing in reverse order works, forwards order leaves the first panels
3341 * not visible. I don't know why!
3343 for (int i = viewCount - 1; i >= 0; i--)
3346 * Make new top and bottom frames. These take over the respective
3347 * AlignmentPanel objects, including their AlignmentViewports, so the
3348 * cdna/protein relationships between the viewports is carried over to the
3351 * explodedGeometry holds the (x, y) position of the previously exploded
3352 * SplitFrame, and the (width, height) of the AlignFrame component
3354 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3355 AlignFrame newTopFrame = new AlignFrame(topPanel);
3356 newTopFrame.setSize(oldTopFrame.getSize());
3357 newTopFrame.setVisible(true);
3358 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3359 .getExplodedGeometry();
3360 if (geometry != null)
3362 newTopFrame.setSize(geometry.getSize());
3365 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3366 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3367 newBottomFrame.setSize(oldBottomFrame.getSize());
3368 newBottomFrame.setVisible(true);
3369 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3370 .getExplodedGeometry();
3371 if (geometry != null)
3373 newBottomFrame.setSize(geometry.getSize());
3376 topPanel.av.setGatherViewsHere(false);
3377 bottomPanel.av.setGatherViewsHere(false);
3378 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3380 if (geometry != null)
3382 splitFrame.setLocation(geometry.getLocation());
3384 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3388 * Clear references to the panels (now relocated in the new SplitFrames)
3389 * before closing the old SplitFrame.
3392 bottomPanels.clear();
3397 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3398 * back into the given SplitFrame as additional views. Note that the gathered
3399 * frames may themselves have multiple views.
3403 public void gatherViews(GSplitFrame source)
3406 * special handling of explodedGeometry for a view within a SplitFrame: - it
3407 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3408 * height) of the AlignFrame component
3410 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3411 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3412 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3413 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3414 myBottomFrame.viewport
3415 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3416 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3417 myTopFrame.viewport.setGatherViewsHere(true);
3418 myBottomFrame.viewport.setGatherViewsHere(true);
3419 String topViewId = myTopFrame.viewport.getSequenceSetId();
3420 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3422 JInternalFrame[] frames = desktop.getAllFrames();
3423 for (JInternalFrame frame : frames)
3425 if (frame instanceof SplitFrame && frame != source)
3427 SplitFrame sf = (SplitFrame) frame;
3428 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3429 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3430 boolean gatherThis = false;
3431 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3433 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3434 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3435 if (topViewId.equals(topPanel.av.getSequenceSetId())
3436 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3439 topPanel.av.setGatherViewsHere(false);
3440 bottomPanel.av.setGatherViewsHere(false);
3441 topPanel.av.setExplodedGeometry(
3442 new Rectangle(sf.getLocation(), topFrame.getSize()));
3443 bottomPanel.av.setExplodedGeometry(
3444 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3445 myTopFrame.addAlignmentPanel(topPanel, false);
3446 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3452 topFrame.getAlignPanels().clear();
3453 bottomFrame.getAlignPanels().clear();
3460 * The dust settles...give focus to the tab we did this from.
3462 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3465 public static groovy.ui.Console getGroovyConsole()
3467 return groovyConsole;
3471 * handles the payload of a drag and drop event.
3473 * TODO refactor to desktop utilities class
3476 * - Data source strings extracted from the drop event
3478 * - protocol for each data source extracted from the drop event
3482 * - the payload from the drop event
3485 public static void transferFromDropTarget(List<String> files,
3486 List<DataSourceType> protocols, DropTargetDropEvent evt,
3487 Transferable t) throws Exception
3490 DataFlavor uriListFlavor = new DataFlavor(
3491 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3494 urlFlavour = new DataFlavor(
3495 "application/x-java-url; class=java.net.URL");
3496 } catch (ClassNotFoundException cfe)
3498 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3501 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3506 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3507 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3508 // means url may be null.
3511 protocols.add(DataSourceType.URL);
3512 files.add(url.toString());
3513 Cache.log.debug("Drop handled as URL dataflavor "
3514 + files.get(files.size() - 1));
3519 if (Platform.isAMac())
3522 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3526 } catch (Throwable ex)
3528 Cache.log.debug("URL drop handler failed.", ex);
3531 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3533 // Works on Windows and MacOSX
3534 Cache.log.debug("Drop handled as javaFileListFlavor");
3535 for (Object file : (List) t
3536 .getTransferData(DataFlavor.javaFileListFlavor))
3538 files.add(((File) file).toString());
3539 protocols.add(DataSourceType.FILE);
3544 // Unix like behaviour
3545 boolean added = false;
3547 if (t.isDataFlavorSupported(uriListFlavor))
3549 Cache.log.debug("Drop handled as uriListFlavor");
3550 // This is used by Unix drag system
3551 data = (String) t.getTransferData(uriListFlavor);
3555 // fallback to text: workaround - on OSX where there's a JVM bug
3556 Cache.log.debug("standard URIListFlavor failed. Trying text");
3557 // try text fallback
3558 DataFlavor textDf = new DataFlavor(
3559 "text/plain;class=java.lang.String");
3560 if (t.isDataFlavorSupported(textDf))
3562 data = (String) t.getTransferData(textDf);
3565 Cache.log.debug("Plain text drop content returned "
3566 + (data == null ? "Null - failed" : data));
3571 while (protocols.size() < files.size())
3573 Cache.log.debug("Adding missing FILE protocol for "
3574 + files.get(protocols.size()));
3575 protocols.add(DataSourceType.FILE);
3577 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3578 data, "\r\n"); st.hasMoreTokens();)
3581 String s = st.nextToken();
3582 if (s.startsWith("#"))
3584 // the line is a comment (as per the RFC 2483)
3587 java.net.URI uri = new java.net.URI(s);
3588 if (uri.getScheme().toLowerCase().startsWith("http"))
3590 protocols.add(DataSourceType.URL);
3591 files.add(uri.toString());
3595 // otherwise preserve old behaviour: catch all for file objects
3596 java.io.File file = new java.io.File(uri);
3597 protocols.add(DataSourceType.FILE);
3598 files.add(file.toString());
3603 if (Cache.log.isDebugEnabled())
3605 if (data == null || !added)
3608 if (t.getTransferDataFlavors() != null
3609 && t.getTransferDataFlavors().length > 0)
3612 "Couldn't resolve drop data. Here are the supported flavors:");
3613 for (DataFlavor fl : t.getTransferDataFlavors())
3616 "Supported transfer dataflavor: " + fl.toString());
3617 Object df = t.getTransferData(fl);
3620 Cache.log.debug("Retrieves: " + df);
3624 Cache.log.debug("Retrieved nothing");
3630 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3636 if (Platform.isWindows())
3639 Cache.log.debug("Scanning dropped content for Windows Link Files");
3641 // resolve any .lnk files in the file drop
3642 for (int f = 0; f < files.size(); f++)
3644 String source = files.get(f).toLowerCase();
3645 if (protocols.get(f).equals(DataSourceType.FILE)
3646 && (source.endsWith(".lnk") || source.endsWith(".url")
3647 || source.endsWith(".site")))
3650 File lf = new File(files.get(f));
3651 // process link file to get a URL
3652 Cache.log.debug("Found potential link file: " + lf);
3653 WindowsShortcut wscfile = new WindowsShortcut(lf);
3654 String fullname = wscfile.getRealFilename();
3655 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3656 files.set(f, fullname);
3657 Cache.log.debug("Parsed real filename " + fullname
3658 + " to extract protocol: " + protocols.get(f));
3660 catch (Exception ex)
3662 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3670 * Sets the Preferences property for experimental features to True or False
3671 * depending on the state of the controlling menu item
3674 protected void showExperimental_actionPerformed(boolean selected)
3676 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3680 * Answers a (possibly empty) list of any structure viewer frames (currently
3681 * for either Jmol or Chimera) which are currently open. This may optionally
3682 * be restricted to viewers of a specified class, or viewers linked to a
3683 * specified alignment panel.
3686 * if not null, only return viewers linked to this panel
3687 * @param structureViewerClass
3688 * if not null, only return viewers of this class
3691 public List<StructureViewerBase> getStructureViewers(
3692 AlignmentPanel apanel,
3693 Class<? extends StructureViewerBase> structureViewerClass)
3695 List<StructureViewerBase> result = new ArrayList<>();
3696 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3698 for (JInternalFrame frame : frames)
3700 if (frame instanceof StructureViewerBase)
3702 if (structureViewerClass == null
3703 || structureViewerClass.isInstance(frame))
3706 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3708 result.add((StructureViewerBase) frame);