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.BackupFiles;
30 import jalview.io.DataSourceType;
31 import jalview.io.FileFormat;
32 import jalview.io.FileFormatException;
33 import jalview.io.FileFormatI;
34 import jalview.io.FileFormats;
35 import jalview.io.FileLoader;
36 import jalview.io.FormatAdapter;
37 import jalview.io.IdentifyFile;
38 import jalview.io.JalviewFileChooser;
39 import jalview.io.JalviewFileView;
40 import jalview.jbgui.GSplitFrame;
41 import jalview.jbgui.GStructureViewer;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.urls.IdOrgSettings;
44 import jalview.util.ImageMaker;
45 import jalview.util.MessageManager;
46 import jalview.util.Platform;
47 import jalview.util.UrlConstants;
48 import jalview.viewmodel.AlignmentViewport;
49 import jalview.ws.params.ParamManager;
50 import jalview.ws.utils.UrlDownloadClient;
52 import java.awt.BorderLayout;
53 import java.awt.Color;
54 import java.awt.Dimension;
55 import java.awt.FontMetrics;
56 import java.awt.Graphics;
57 import java.awt.GridLayout;
58 import java.awt.Point;
59 import java.awt.Rectangle;
60 import java.awt.Toolkit;
61 import java.awt.Window;
62 import java.awt.datatransfer.Clipboard;
63 import java.awt.datatransfer.ClipboardOwner;
64 import java.awt.datatransfer.DataFlavor;
65 import java.awt.datatransfer.Transferable;
66 import java.awt.dnd.DnDConstants;
67 import java.awt.dnd.DropTargetDragEvent;
68 import java.awt.dnd.DropTargetDropEvent;
69 import java.awt.dnd.DropTargetEvent;
70 import java.awt.dnd.DropTargetListener;
71 import java.awt.event.ActionEvent;
72 import java.awt.event.ActionListener;
73 import java.awt.event.InputEvent;
74 import java.awt.event.KeyEvent;
75 import java.awt.event.MouseAdapter;
76 import java.awt.event.MouseEvent;
77 import java.awt.event.WindowAdapter;
78 import java.awt.event.WindowEvent;
79 import java.beans.PropertyChangeEvent;
80 import java.beans.PropertyChangeListener;
81 import java.io.BufferedInputStream;
83 import java.io.FileOutputStream;
84 import java.io.IOException;
86 import java.util.ArrayList;
87 import java.util.Hashtable;
88 import java.util.List;
89 import java.util.ListIterator;
90 import java.util.StringTokenizer;
91 import java.util.Vector;
92 import java.util.concurrent.ExecutorService;
93 import java.util.concurrent.Executors;
94 import java.util.concurrent.Semaphore;
96 import javax.swing.AbstractAction;
97 import javax.swing.Action;
98 import javax.swing.ActionMap;
99 import javax.swing.Box;
100 import javax.swing.BoxLayout;
101 import javax.swing.DefaultDesktopManager;
102 import javax.swing.DesktopManager;
103 import javax.swing.InputMap;
104 import javax.swing.JButton;
105 import javax.swing.JCheckBox;
106 import javax.swing.JComboBox;
107 import javax.swing.JComponent;
108 import javax.swing.JDesktopPane;
109 import javax.swing.JFrame;
110 import javax.swing.JInternalFrame;
111 import javax.swing.JLabel;
112 import javax.swing.JMenuItem;
113 import javax.swing.JPanel;
114 import javax.swing.JPopupMenu;
115 import javax.swing.JProgressBar;
116 import javax.swing.KeyStroke;
117 import javax.swing.SwingUtilities;
118 import javax.swing.event.HyperlinkEvent;
119 import javax.swing.event.HyperlinkEvent.EventType;
120 import javax.swing.event.InternalFrameAdapter;
121 import javax.swing.event.InternalFrameEvent;
122 import javax.swing.event.MenuEvent;
123 import javax.swing.event.MenuListener;
125 import org.stackoverflowusers.file.WindowsShortcut;
132 * @version $Revision: 1.155 $
134 public class Desktop extends jalview.jbgui.GDesktop
135 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
136 jalview.api.StructureSelectionManagerProvider
138 private static int DEFAULT_MIN_WIDTH = 300;
140 private static int DEFAULT_MIN_HEIGHT = 250;
142 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
144 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
146 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
148 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
151 * news reader - null if it was never started.
153 private BlogReader jvnews = null;
155 private File projectFile;
159 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
161 public void addJalviewPropertyChangeListener(
162 PropertyChangeListener listener)
164 changeSupport.addJalviewPropertyChangeListener(listener);
168 * @param propertyName
170 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
171 * java.beans.PropertyChangeListener)
173 public void addJalviewPropertyChangeListener(String propertyName,
174 PropertyChangeListener listener)
176 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
180 * @param propertyName
182 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
183 * java.beans.PropertyChangeListener)
185 public void removeJalviewPropertyChangeListener(String propertyName,
186 PropertyChangeListener listener)
188 changeSupport.removeJalviewPropertyChangeListener(propertyName,
192 /** Singleton Desktop instance */
193 public static Desktop instance;
195 public static MyDesktopPane desktop;
197 static int openFrameCount = 0;
199 static final int xOffset = 30;
201 static final int yOffset = 30;
203 public static jalview.ws.jws1.Discoverer discoverer;
205 public static Object[] jalviewClipboard;
207 public static boolean internalCopy = false;
209 static int fileLoadingCount = 0;
211 class MyDesktopManager implements DesktopManager
214 private DesktopManager delegate;
216 public MyDesktopManager(DesktopManager delegate)
218 this.delegate = delegate;
222 public void activateFrame(JInternalFrame f)
226 delegate.activateFrame(f);
227 } catch (NullPointerException npe)
229 Point p = getMousePosition();
230 instance.showPasteMenu(p.x, p.y);
235 public void beginDraggingFrame(JComponent f)
237 delegate.beginDraggingFrame(f);
241 public void beginResizingFrame(JComponent f, int direction)
243 delegate.beginResizingFrame(f, direction);
247 public void closeFrame(JInternalFrame f)
249 delegate.closeFrame(f);
253 public void deactivateFrame(JInternalFrame f)
255 delegate.deactivateFrame(f);
259 public void deiconifyFrame(JInternalFrame f)
261 delegate.deiconifyFrame(f);
265 public void dragFrame(JComponent f, int newX, int newY)
271 delegate.dragFrame(f, newX, newY);
275 public void endDraggingFrame(JComponent f)
277 delegate.endDraggingFrame(f);
282 public void endResizingFrame(JComponent f)
284 delegate.endResizingFrame(f);
289 public void iconifyFrame(JInternalFrame f)
291 delegate.iconifyFrame(f);
295 public void maximizeFrame(JInternalFrame f)
297 delegate.maximizeFrame(f);
301 public void minimizeFrame(JInternalFrame f)
303 delegate.minimizeFrame(f);
307 public void openFrame(JInternalFrame f)
309 delegate.openFrame(f);
313 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
320 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
324 public void setBoundsForFrame(JComponent f, int newX, int newY,
325 int newWidth, int newHeight)
327 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
330 // All other methods, simply delegate
335 * Creates a new Desktop object.
340 * A note to implementors. It is ESSENTIAL that any activities that might
341 * block are spawned off as threads rather than waited for during this
345 doVamsasClientCheck();
347 doConfigureStructurePrefs();
348 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
349 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
350 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
352 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
354 desktop = new MyDesktopPane(selmemusage);
355 showMemusage.setSelected(selmemusage);
356 desktop.setBackground(Color.white);
357 getContentPane().setLayout(new BorderLayout());
358 // alternate config - have scrollbars - see notes in JAL-153
359 // JScrollPane sp = new JScrollPane();
360 // sp.getViewport().setView(desktop);
361 // getContentPane().add(sp, BorderLayout.CENTER);
362 getContentPane().add(desktop, BorderLayout.CENTER);
363 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
365 // This line prevents Windows Look&Feel resizing all new windows to maximum
366 // if previous window was maximised
367 desktop.setDesktopManager(
368 new MyDesktopManager(
369 (Platform.isWindows() ? new DefaultDesktopManager()
371 ? new AquaInternalFrameManager(
372 desktop.getDesktopManager())
373 : desktop.getDesktopManager())));
375 Rectangle dims = getLastKnownDimensions("");
382 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
383 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
386 jconsole = new Console(this, showjconsole);
387 // add essential build information
389 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
390 + "\n" + "Jalview Installation: "
391 + jalview.bin.Cache.getDefault("INSTALLATION",
393 + "\n" + "Build Date: "
394 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
395 + "\n" + "Java version: "
396 + System.getProperty("java.version") + "\n"
397 + System.getProperty("os.arch") + " "
398 + System.getProperty("os.name") + " "
399 + System.getProperty("os.version"));
401 showConsole(showjconsole);
403 showNews.setVisible(false);
405 experimentalFeatures.setSelected(showExperimental());
407 getIdentifiersOrgData();
411 this.addWindowListener(new WindowAdapter()
414 public void windowClosing(WindowEvent evt)
421 this.addMouseListener(ma = new MouseAdapter()
424 public void mousePressed(MouseEvent evt)
426 if (evt.isPopupTrigger()) // Mac
428 showPasteMenu(evt.getX(), evt.getY());
433 public void mouseReleased(MouseEvent evt)
435 if (evt.isPopupTrigger()) // Windows
437 showPasteMenu(evt.getX(), evt.getY());
441 desktop.addMouseListener(ma);
443 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
444 // Spawn a thread that shows the splashscreen
445 SwingUtilities.invokeLater(new Runnable()
454 // Thread off a new instance of the file chooser - this reduces the time it
455 // takes to open it later on.
456 new Thread(new Runnable()
461 Cache.log.debug("Filechooser init thread started.");
462 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
463 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
465 Cache.log.debug("Filechooser init thread finished.");
468 // Add the service change listener
469 changeSupport.addJalviewPropertyChangeListener("services",
470 new PropertyChangeListener()
474 public void propertyChange(PropertyChangeEvent evt)
476 Cache.log.debug("Firing service changed event for "
477 + evt.getNewValue());
478 JalviewServicesChanged(evt);
485 * Answers true if user preferences to enable experimental features is True
490 public boolean showExperimental()
492 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
493 Boolean.FALSE.toString());
494 return Boolean.valueOf(experimental).booleanValue();
497 public void doConfigureStructurePrefs()
499 // configure services
500 StructureSelectionManager ssm = StructureSelectionManager
501 .getStructureSelectionManager(this);
502 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
504 ssm.setAddTempFacAnnot(jalview.bin.Cache
505 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
506 ssm.setProcessSecondaryStructure(jalview.bin.Cache
507 .getDefault(Preferences.STRUCT_FROM_PDB, true));
508 ssm.setSecStructServices(
509 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
513 ssm.setAddTempFacAnnot(false);
514 ssm.setProcessSecondaryStructure(false);
515 ssm.setSecStructServices(false);
519 public void checkForNews()
521 final Desktop me = this;
522 // Thread off the news reader, in case there are connection problems.
523 new Thread(new Runnable()
528 Cache.log.debug("Starting news thread.");
530 jvnews = new BlogReader(me);
531 showNews.setVisible(true);
532 Cache.log.debug("Completed news thread.");
537 public void getIdentifiersOrgData()
539 // Thread off the identifiers fetcher
540 new Thread(new Runnable()
545 Cache.log.debug("Downloading data from identifiers.org");
546 UrlDownloadClient client = new UrlDownloadClient();
549 client.download(IdOrgSettings.getUrl(),
550 IdOrgSettings.getDownloadLocation());
551 } catch (IOException e)
553 Cache.log.debug("Exception downloading identifiers.org data"
562 protected void showNews_actionPerformed(ActionEvent e)
564 showNews(showNews.isSelected());
567 void showNews(boolean visible)
570 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
571 showNews.setSelected(visible);
572 if (visible && !jvnews.isVisible())
574 new Thread(new Runnable()
579 long now = System.currentTimeMillis();
580 Desktop.instance.setProgressBar(
581 MessageManager.getString("status.refreshing_news"),
583 jvnews.refreshNews();
584 Desktop.instance.setProgressBar(null, now);
593 * recover the last known dimensions for a jalview window
596 * - empty string is desktop, all other windows have unique prefix
597 * @return null or last known dimensions scaled to current geometry (if last
598 * window geom was known)
600 Rectangle getLastKnownDimensions(String windowName)
602 // TODO: lock aspect ratio for scaling desktop Bug #0058199
603 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
604 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
605 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
606 String width = jalview.bin.Cache
607 .getProperty(windowName + "SCREEN_WIDTH");
608 String height = jalview.bin.Cache
609 .getProperty(windowName + "SCREEN_HEIGHT");
610 if ((x != null) && (y != null) && (width != null) && (height != null))
612 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
613 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
614 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
616 // attempt #1 - try to cope with change in screen geometry - this
617 // version doesn't preserve original jv aspect ratio.
618 // take ratio of current screen size vs original screen size.
619 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
620 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
621 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
622 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
623 // rescale the bounds depending upon the current screen geometry.
624 ix = (int) (ix * sw);
625 iw = (int) (iw * sw);
626 iy = (int) (iy * sh);
627 ih = (int) (ih * sh);
628 while (ix >= screenSize.width)
630 jalview.bin.Cache.log.debug(
631 "Window geometry location recall error: shifting horizontal to within screenbounds.");
632 ix -= screenSize.width;
634 while (iy >= screenSize.height)
636 jalview.bin.Cache.log.debug(
637 "Window geometry location recall error: shifting vertical to within screenbounds.");
638 iy -= screenSize.height;
640 jalview.bin.Cache.log.debug(
641 "Got last known dimensions for " + windowName + ": x:" + ix
642 + " y:" + iy + " width:" + iw + " height:" + ih);
644 // return dimensions for new instance
645 return new Rectangle(ix, iy, iw, ih);
650 private void doVamsasClientCheck()
652 if (jalview.bin.Cache.vamsasJarsPresent())
654 setupVamsasDisconnectedGui();
655 VamsasMenu.setVisible(true);
656 final Desktop us = this;
657 VamsasMenu.addMenuListener(new MenuListener()
659 // this listener remembers when the menu was first selected, and
660 // doesn't rebuild the session list until it has been cleared and
662 boolean refresh = true;
665 public void menuCanceled(MenuEvent e)
671 public void menuDeselected(MenuEvent e)
677 public void menuSelected(MenuEvent e)
681 us.buildVamsasStMenu();
686 vamsasStart.setVisible(true);
690 void showPasteMenu(int x, int y)
692 JPopupMenu popup = new JPopupMenu();
693 JMenuItem item = new JMenuItem(
694 MessageManager.getString("label.paste_new_window"));
695 item.addActionListener(new ActionListener()
698 public void actionPerformed(ActionEvent evt)
705 popup.show(this, x, y);
712 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
713 Transferable contents = c.getContents(this);
715 if (contents != null)
717 String file = (String) contents
718 .getTransferData(DataFlavor.stringFlavor);
720 FileFormatI format = new IdentifyFile().identify(file,
721 DataSourceType.PASTE);
723 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
726 } catch (Exception ex)
729 "Unable to paste alignment from system clipboard:\n" + ex);
734 * Adds and opens the given frame to the desktop
745 public static synchronized void addInternalFrame(
746 final JInternalFrame frame, String title, int w, int h)
748 addInternalFrame(frame, title, true, w, h, true, false);
752 * Add an internal frame to the Jalview desktop
759 * When true, display frame immediately, otherwise, caller must call
760 * setVisible themselves.
766 public static synchronized void addInternalFrame(
767 final JInternalFrame frame, String title, boolean makeVisible,
770 addInternalFrame(frame, title, makeVisible, w, h, true, false);
774 * Add an internal frame to the Jalview desktop and make it visible
787 public static synchronized void addInternalFrame(
788 final JInternalFrame frame, String title, int w, int h,
791 addInternalFrame(frame, title, true, w, h, resizable, false);
795 * Add an internal frame to the Jalview desktop
802 * When true, display frame immediately, otherwise, caller must call
803 * setVisible themselves.
810 * @param ignoreMinSize
811 * Do not set the default minimum size for frame
813 public static synchronized void addInternalFrame(
814 final JInternalFrame frame, String title, boolean makeVisible,
815 int w, int h, boolean resizable, boolean ignoreMinSize)
818 // TODO: allow callers to determine X and Y position of frame (eg. via
820 // TODO: consider fixing method to update entries in the window submenu with
821 // the current window title
823 frame.setTitle(title);
824 if (frame.getWidth() < 1 || frame.getHeight() < 1)
828 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
829 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
830 // IF JALVIEW IS RUNNING HEADLESS
831 // ///////////////////////////////////////////////
832 if (instance == null || (System.getProperty("java.awt.headless") != null
833 && System.getProperty("java.awt.headless").equals("true")))
842 frame.setMinimumSize(
843 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
845 // Set default dimension for Alignment Frame window.
846 // The Alignment Frame window could be added from a number of places,
848 // I did this here in order not to miss out on any Alignment frame.
849 if (frame instanceof AlignFrame)
851 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
852 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
856 frame.setVisible(makeVisible);
857 frame.setClosable(true);
858 frame.setResizable(resizable);
859 frame.setMaximizable(resizable);
860 frame.setIconifiable(resizable);
861 frame.setOpaque(false);
863 if (frame.getX() < 1 && frame.getY() < 1)
865 frame.setLocation(xOffset * openFrameCount,
866 yOffset * ((openFrameCount - 1) % 10) + yOffset);
870 * add an entry for the new frame in the Window menu
871 * (and remove it when the frame is closed)
873 final JMenuItem menuItem = new JMenuItem(title);
874 frame.addInternalFrameListener(new InternalFrameAdapter()
877 public void internalFrameActivated(InternalFrameEvent evt)
879 JInternalFrame itf = desktop.getSelectedFrame();
882 if (itf instanceof AlignFrame)
884 Jalview.setCurrentAlignFrame((AlignFrame) itf);
891 public void internalFrameClosed(InternalFrameEvent evt)
893 PaintRefresher.RemoveComponent(frame);
896 * defensive check to prevent frames being
897 * added half off the window
899 if (openFrameCount > 0)
905 * ensure no reference to alignFrame retained by menu item listener
907 if (menuItem.getActionListeners().length > 0)
909 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
911 windowMenu.remove(menuItem);
915 menuItem.addActionListener(new ActionListener()
918 public void actionPerformed(ActionEvent e)
922 frame.setSelected(true);
923 frame.setIcon(false);
924 } catch (java.beans.PropertyVetoException ex)
931 setKeyBindings(frame);
935 windowMenu.add(menuItem);
940 frame.setSelected(true);
941 frame.requestFocus();
942 } catch (java.beans.PropertyVetoException ve)
944 } catch (java.lang.ClassCastException cex)
947 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
953 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
958 private static void setKeyBindings(JInternalFrame frame)
960 @SuppressWarnings("serial")
961 final Action closeAction = new AbstractAction()
964 public void actionPerformed(ActionEvent e)
971 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
973 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
974 InputEvent.CTRL_DOWN_MASK);
975 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
976 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
978 InputMap inputMap = frame
979 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
980 String ctrlW = ctrlWKey.toString();
981 inputMap.put(ctrlWKey, ctrlW);
982 inputMap.put(cmdWKey, ctrlW);
984 ActionMap actionMap = frame.getActionMap();
985 actionMap.put(ctrlW, closeAction);
989 public void lostOwnership(Clipboard clipboard, Transferable contents)
993 Desktop.jalviewClipboard = null;
996 internalCopy = false;
1000 public void dragEnter(DropTargetDragEvent evt)
1005 public void dragExit(DropTargetEvent evt)
1010 public void dragOver(DropTargetDragEvent evt)
1015 public void dropActionChanged(DropTargetDragEvent evt)
1026 public void drop(DropTargetDropEvent evt)
1028 boolean success = true;
1029 // JAL-1552 - acceptDrop required before getTransferable call for
1030 // Java's Transferable for native dnd
1031 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1032 Transferable t = evt.getTransferable();
1033 List<String> files = new ArrayList<>();
1034 List<DataSourceType> protocols = new ArrayList<>();
1038 Desktop.transferFromDropTarget(files, protocols, evt, t);
1039 } catch (Exception e)
1041 e.printStackTrace();
1049 for (int i = 0; i < files.size(); i++)
1051 String file = files.get(i).toString();
1052 DataSourceType protocol = (protocols == null)
1053 ? DataSourceType.FILE
1055 FileFormatI format = null;
1057 if (file.endsWith(".jar"))
1059 format = FileFormat.Jalview;
1064 format = new IdentifyFile().identify(file, protocol);
1067 new FileLoader().LoadFile(file, protocol, format);
1070 } catch (Exception ex)
1075 evt.dropComplete(success); // need this to ensure input focus is properly
1076 // transfered to any new windows created
1086 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1088 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1089 JalviewFileChooser chooser = JalviewFileChooser
1090 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1092 chooser.setFileView(new JalviewFileView());
1093 chooser.setDialogTitle(
1094 MessageManager.getString("label.open_local_file"));
1095 chooser.setToolTipText(MessageManager.getString("action.open"));
1097 int value = chooser.showOpenDialog(this);
1099 if (value == JalviewFileChooser.APPROVE_OPTION)
1101 String choice = chooser.getSelectedFile().getPath();
1102 Cache.setProperty("LAST_DIRECTORY",
1103 chooser.getSelectedFile().getParent());
1105 FileFormatI format = chooser.getSelectedFormat();
1108 * Call IdentifyFile to verify the file contains what its extension implies.
1109 * Skip this step for dynamically added file formats, because
1110 * IdentifyFile does not know how to recognise them.
1112 if (FileFormats.getInstance().isIdentifiable(format))
1116 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1117 } catch (FileFormatException e)
1119 // format = null; //??
1123 if (viewport != null)
1125 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1130 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1142 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1144 // This construct allows us to have a wider textfield
1146 JLabel label = new JLabel(
1147 MessageManager.getString("label.input_file_url"));
1148 final JComboBox history = new JComboBox();
1150 JPanel panel = new JPanel(new GridLayout(2, 1));
1153 history.setPreferredSize(new Dimension(400, 20));
1154 history.setEditable(true);
1155 history.addItem("http://www.");
1157 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1161 if (historyItems != null)
1163 st = new StringTokenizer(historyItems, "\t");
1165 while (st.hasMoreTokens())
1167 history.addItem(st.nextElement());
1171 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1172 MessageManager.getString("label.input_alignment_from_url"),
1173 JvOptionPane.OK_CANCEL_OPTION);
1175 if (reply != JvOptionPane.OK_OPTION)
1180 String url = history.getSelectedItem().toString();
1182 if (url.toLowerCase().endsWith(".jar"))
1184 if (viewport != null)
1186 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1187 FileFormat.Jalview);
1191 new FileLoader().LoadFile(url, DataSourceType.URL,
1192 FileFormat.Jalview);
1197 FileFormatI format = null;
1200 format = new IdentifyFile().identify(url, DataSourceType.URL);
1201 } catch (FileFormatException e)
1203 // TODO revise error handling, distinguish between
1204 // URL not found and response not valid
1209 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1210 MessageManager.formatMessage("label.couldnt_locate",
1213 MessageManager.getString("label.url_not_found"),
1214 JvOptionPane.WARNING_MESSAGE);
1219 if (viewport != null)
1221 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1226 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1232 * Opens the CutAndPaste window for the user to paste an alignment in to
1235 * - if not null, the pasted alignment is added to the current
1236 * alignment; if null, to a new alignment window
1239 public void inputTextboxMenuItem_actionPerformed(
1240 AlignmentViewPanel viewPanel)
1242 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1243 cap.setForInput(viewPanel);
1244 Desktop.addInternalFrame(cap,
1245 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1255 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1256 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1258 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1259 screen.height + "");
1260 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1261 getWidth(), getHeight()));
1263 if (jconsole != null)
1265 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1266 jconsole.stopConsole();
1270 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1273 if (dialogExecutor != null)
1275 dialogExecutor.shutdownNow();
1277 closeAll_actionPerformed(null);
1279 if (groovyConsole != null)
1281 // suppress a possible repeat prompt to save script
1282 groovyConsole.setDirty(false);
1283 groovyConsole.exit();
1288 private void storeLastKnownDimensions(String string, Rectangle jc)
1290 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1291 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1292 + " height:" + jc.height);
1294 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1295 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1296 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1297 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1307 public void aboutMenuItem_actionPerformed(ActionEvent e)
1309 // StringBuffer message = getAboutMessage(false);
1310 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1312 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1313 new Thread(new Runnable()
1318 new SplashScreen(true);
1323 public StringBuffer getAboutMessage(boolean shortv)
1325 StringBuffer message = new StringBuffer();
1326 message.append("<html>");
1329 message.append("<h1><strong>Version: "
1330 + jalview.bin.Cache.getProperty("VERSION")
1331 + "</strong></h1>");
1332 message.append("<strong>Last Updated: <em>"
1333 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1334 + "</em></strong>");
1340 message.append("<strong>Version "
1341 + jalview.bin.Cache.getProperty("VERSION")
1342 + "; last updated: "
1343 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1346 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1347 .equals("Checking"))
1349 message.append("<br>...Checking latest version...</br>");
1351 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1352 .equals(jalview.bin.Cache.getProperty("VERSION")))
1354 boolean red = false;
1355 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1356 .indexOf("automated build") == -1)
1359 // Displayed when code version and jnlp version do not match and code
1360 // version is not a development build
1361 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1364 message.append("<br>!! Version "
1365 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1367 + " is available for download from "
1368 + jalview.bin.Cache.getDefault("www.jalview.org",
1369 "http://www.jalview.org")
1373 message.append("</div>");
1376 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1378 "The Jalview Authors (See AUTHORS file for current list)")
1379 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1380 + "<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"
1381 + "<br><br>If you use Jalview, please cite:"
1382 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1383 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1384 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1396 public void documentationMenuItem_actionPerformed(ActionEvent e)
1400 Help.showHelpWindow();
1401 } catch (Exception ex)
1407 public void closeAll_actionPerformed(ActionEvent e)
1409 // TODO show a progress bar while closing?
1410 JInternalFrame[] frames = desktop.getAllFrames();
1411 for (int i = 0; i < frames.length; i++)
1415 frames[i].setClosed(true);
1416 } catch (java.beans.PropertyVetoException ex)
1420 Jalview.setCurrentAlignFrame(null);
1421 System.out.println("ALL CLOSED");
1422 if (v_client != null)
1424 // TODO clear binding to vamsas document objects on close_all
1428 * reset state of singleton objects as appropriate (clear down session state
1429 * when all windows are closed)
1431 StructureSelectionManager ssm = StructureSelectionManager
1432 .getStructureSelectionManager(this);
1440 public void raiseRelated_actionPerformed(ActionEvent e)
1442 reorderAssociatedWindows(false, false);
1446 public void minimizeAssociated_actionPerformed(ActionEvent e)
1448 reorderAssociatedWindows(true, false);
1451 void closeAssociatedWindows()
1453 reorderAssociatedWindows(false, true);
1459 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1463 protected void garbageCollect_actionPerformed(ActionEvent e)
1465 // We simply collect the garbage
1466 jalview.bin.Cache.log.debug("Collecting garbage...");
1468 jalview.bin.Cache.log.debug("Finished garbage collection.");
1475 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1479 protected void showMemusage_actionPerformed(ActionEvent e)
1481 desktop.showMemoryUsage(showMemusage.isSelected());
1488 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1492 protected void showConsole_actionPerformed(ActionEvent e)
1494 showConsole(showConsole.isSelected());
1497 Console jconsole = null;
1500 * control whether the java console is visible or not
1504 void showConsole(boolean selected)
1506 showConsole.setSelected(selected);
1507 // TODO: decide if we should update properties file
1508 Cache.setProperty("SHOW_JAVA_CONSOLE",
1509 Boolean.valueOf(selected).toString());
1510 jconsole.setVisible(selected);
1513 void reorderAssociatedWindows(boolean minimize, boolean close)
1515 JInternalFrame[] frames = desktop.getAllFrames();
1516 if (frames == null || frames.length < 1)
1521 AlignmentViewport source = null, target = null;
1522 if (frames[0] instanceof AlignFrame)
1524 source = ((AlignFrame) frames[0]).getCurrentView();
1526 else if (frames[0] instanceof TreePanel)
1528 source = ((TreePanel) frames[0]).getViewPort();
1530 else if (frames[0] instanceof PCAPanel)
1532 source = ((PCAPanel) frames[0]).av;
1534 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1536 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1541 for (int i = 0; i < frames.length; i++)
1544 if (frames[i] == null)
1548 if (frames[i] instanceof AlignFrame)
1550 target = ((AlignFrame) frames[i]).getCurrentView();
1552 else if (frames[i] instanceof TreePanel)
1554 target = ((TreePanel) frames[i]).getViewPort();
1556 else if (frames[i] instanceof PCAPanel)
1558 target = ((PCAPanel) frames[i]).av;
1560 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1562 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1565 if (source == target)
1571 frames[i].setClosed(true);
1575 frames[i].setIcon(minimize);
1578 frames[i].toFront();
1582 } catch (java.beans.PropertyVetoException ex)
1597 protected void preferences_actionPerformed(ActionEvent e)
1609 public void saveState_actionPerformed(ActionEvent e)
1611 saveState_actionPerformed(e, false);
1614 public void saveState_actionPerformed(ActionEvent e, boolean saveAs)
1616 java.io.File projectFile = getProjectFile();
1617 // autoSave indicates we already have a file and don't need to ask
1618 boolean autoSave = projectFile != null && !saveAs && BackupFiles.getEnabled();
1620 System.out.println("autoSave="+autoSave+", projectFile='"+projectFile+"', saveAs="+saveAs+", Backups "+(BackupFiles.getEnabled()?"enabled":"disabled"));
1622 boolean approveSave = false;
1625 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1628 chooser.setFileView(new JalviewFileView());
1629 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1631 int value = chooser.showSaveDialog(this);
1633 if (value == JalviewFileChooser.APPROVE_OPTION)
1635 projectFile = chooser.getSelectedFile();
1636 setProjectFile(projectFile);
1641 if (approveSave || autoSave) {
1642 final Desktop me = this;
1643 final java.io.File chosenFile = projectFile;
1644 new Thread(new Runnable()
1649 // TODO: refactor to Jalview desktop session controller action.
1650 setProgressBar(MessageManager.formatMessage(
1651 "label.saving_jalview_project", new Object[]
1652 { chosenFile.getName() }), chosenFile.hashCode());
1653 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1654 chosenFile.getParent());
1655 // TODO catch and handle errors for savestate
1656 // TODO prevent user from messing with the Desktop whilst we're saving
1659 BackupFiles backupfiles = new BackupFiles(chosenFile);
1661 new Jalview2XML().saveState(backupfiles.getTempFile());
1663 backupfiles.setWriteSuccess(true);
1664 backupfiles.rollBackupsAndRenameTempFile();
1665 } catch (OutOfMemoryError oom)
1668 "Whilst saving current state to " + chosenFile.getName(),
1670 } catch (Exception ex)
1673 "Problems whilst trying to save to " + chosenFile.getName(),
1675 JvOptionPane.showMessageDialog(me,
1676 MessageManager.formatMessage(
1677 "label.error_whilst_saving_current_state_to",
1679 { chosenFile.getName() }),
1680 MessageManager.getString("label.couldnt_save_project"),
1681 JvOptionPane.WARNING_MESSAGE);
1683 setProgressBar(null, chosenFile.hashCode());
1690 public void saveAsState_actionPerformed(ActionEvent e)
1692 saveState_actionPerformed(e, true);
1695 private void setProjectFile(File choice)
1697 this.projectFile = choice;
1700 public File getProjectFile()
1702 return this.projectFile;
1712 public void loadState_actionPerformed(ActionEvent e)
1714 JalviewFileChooser chooser = new JalviewFileChooser(
1715 Cache.getProperty("LAST_DIRECTORY"), new String[]
1718 { "Jalview Project", "Jalview Project (old)" },
1720 chooser.setFileView(new JalviewFileView());
1721 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1723 int value = chooser.showOpenDialog(this);
1725 if (value == JalviewFileChooser.APPROVE_OPTION)
1727 final File selectedFile = chooser.getSelectedFile();
1728 setProjectFile(selectedFile);
1729 final String choice = selectedFile.getAbsolutePath();
1730 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1731 new Thread(new Runnable()
1736 setProgressBar(MessageManager.formatMessage(
1737 "label.loading_jalview_project", new Object[]
1738 { choice }), choice.hashCode());
1741 new Jalview2XML().loadJalviewAlign(choice);
1742 } catch (OutOfMemoryError oom)
1744 new OOMWarning("Whilst loading project from " + choice, oom);
1745 } catch (Exception ex)
1748 "Problems whilst loading project from " + choice, ex);
1749 JvOptionPane.showMessageDialog(Desktop.desktop,
1750 MessageManager.formatMessage(
1751 "label.error_whilst_loading_project_from",
1754 MessageManager.getString("label.couldnt_load_project"),
1755 JvOptionPane.WARNING_MESSAGE);
1757 setProgressBar(null, choice.hashCode());
1764 public void inputSequence_actionPerformed(ActionEvent e)
1766 new SequenceFetcher(this);
1769 JPanel progressPanel;
1771 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1773 public void startLoading(final String fileName)
1775 if (fileLoadingCount == 0)
1777 fileLoadingPanels.add(addProgressPanel(MessageManager
1778 .formatMessage("label.loading_file", new Object[]
1784 private JPanel addProgressPanel(String string)
1786 if (progressPanel == null)
1788 progressPanel = new JPanel(new GridLayout(1, 1));
1789 totalProgressCount = 0;
1790 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1792 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1793 JProgressBar progressBar = new JProgressBar();
1794 progressBar.setIndeterminate(true);
1796 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1798 thisprogress.add(progressBar, BorderLayout.CENTER);
1799 progressPanel.add(thisprogress);
1800 ((GridLayout) progressPanel.getLayout()).setRows(
1801 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1802 ++totalProgressCount;
1803 instance.validate();
1804 return thisprogress;
1807 int totalProgressCount = 0;
1809 private void removeProgressPanel(JPanel progbar)
1811 if (progressPanel != null)
1813 synchronized (progressPanel)
1815 progressPanel.remove(progbar);
1816 GridLayout gl = (GridLayout) progressPanel.getLayout();
1817 gl.setRows(gl.getRows() - 1);
1818 if (--totalProgressCount < 1)
1820 this.getContentPane().remove(progressPanel);
1821 progressPanel = null;
1828 public void stopLoading()
1831 if (fileLoadingCount < 1)
1833 while (fileLoadingPanels.size() > 0)
1835 removeProgressPanel(fileLoadingPanels.remove(0));
1837 fileLoadingPanels.clear();
1838 fileLoadingCount = 0;
1843 public static int getViewCount(String alignmentId)
1845 AlignmentViewport[] aps = getViewports(alignmentId);
1846 return (aps == null) ? 0 : aps.length;
1851 * @param alignmentId
1852 * - if null, all sets are returned
1853 * @return all AlignmentPanels concerning the alignmentId sequence set
1855 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1857 if (Desktop.desktop == null)
1859 // no frames created and in headless mode
1860 // TODO: verify that frames are recoverable when in headless mode
1863 List<AlignmentPanel> aps = new ArrayList<>();
1864 AlignFrame[] frames = getAlignFrames();
1869 for (AlignFrame af : frames)
1871 for (AlignmentPanel ap : af.alignPanels)
1873 if (alignmentId == null
1874 || alignmentId.equals(ap.av.getSequenceSetId()))
1880 if (aps.size() == 0)
1884 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1889 * get all the viewports on an alignment.
1891 * @param sequenceSetId
1892 * unique alignment id (may be null - all viewports returned in that
1894 * @return all viewports on the alignment bound to sequenceSetId
1896 public static AlignmentViewport[] getViewports(String sequenceSetId)
1898 List<AlignmentViewport> viewp = new ArrayList<>();
1899 if (desktop != null)
1901 AlignFrame[] frames = Desktop.getAlignFrames();
1903 for (AlignFrame afr : frames)
1905 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1906 .equals(sequenceSetId))
1908 if (afr.alignPanels != null)
1910 for (AlignmentPanel ap : afr.alignPanels)
1912 if (sequenceSetId == null
1913 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1921 viewp.add(afr.getViewport());
1925 if (viewp.size() > 0)
1927 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1934 * Explode the views in the given frame into separate AlignFrame
1938 public static void explodeViews(AlignFrame af)
1940 int size = af.alignPanels.size();
1946 for (int i = 0; i < size; i++)
1948 AlignmentPanel ap = af.alignPanels.get(i);
1949 AlignFrame newaf = new AlignFrame(ap);
1952 * Restore the view's last exploded frame geometry if known. Multiple
1953 * views from one exploded frame share and restore the same (frame)
1954 * position and size.
1956 Rectangle geometry = ap.av.getExplodedGeometry();
1957 if (geometry != null)
1959 newaf.setBounds(geometry);
1962 ap.av.setGatherViewsHere(false);
1964 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1965 AlignFrame.DEFAULT_HEIGHT);
1968 af.alignPanels.clear();
1969 af.closeMenuItem_actionPerformed(true);
1974 * Gather expanded views (separate AlignFrame's) with the same sequence set
1975 * identifier back in to this frame as additional views, and close the
1976 * expanded views. Note the expanded frames may themselves have multiple
1977 * views. We take the lot.
1981 public void gatherViews(AlignFrame source)
1983 source.viewport.setGatherViewsHere(true);
1984 source.viewport.setExplodedGeometry(source.getBounds());
1985 JInternalFrame[] frames = desktop.getAllFrames();
1986 String viewId = source.viewport.getSequenceSetId();
1988 for (int t = 0; t < frames.length; t++)
1990 if (frames[t] instanceof AlignFrame && frames[t] != source)
1992 AlignFrame af = (AlignFrame) frames[t];
1993 boolean gatherThis = false;
1994 for (int a = 0; a < af.alignPanels.size(); a++)
1996 AlignmentPanel ap = af.alignPanels.get(a);
1997 if (viewId.equals(ap.av.getSequenceSetId()))
2000 ap.av.setGatherViewsHere(false);
2001 ap.av.setExplodedGeometry(af.getBounds());
2002 source.addAlignmentPanel(ap, false);
2008 af.alignPanels.clear();
2009 af.closeMenuItem_actionPerformed(true);
2016 jalview.gui.VamsasApplication v_client = null;
2019 public void vamsasImport_actionPerformed(ActionEvent e)
2021 if (v_client == null)
2023 // Load and try to start a session.
2024 JalviewFileChooser chooser = new JalviewFileChooser(
2025 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2027 chooser.setFileView(new JalviewFileView());
2028 chooser.setDialogTitle(
2029 MessageManager.getString("label.open_saved_vamsas_session"));
2030 chooser.setToolTipText(MessageManager.getString(
2031 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2033 int value = chooser.showOpenDialog(this);
2035 if (value == JalviewFileChooser.APPROVE_OPTION)
2037 String fle = chooser.getSelectedFile().toString();
2038 if (!vamsasImport(chooser.getSelectedFile()))
2040 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2041 MessageManager.formatMessage(
2042 "label.couldnt_import_as_vamsas_session",
2046 .getString("label.vamsas_document_import_failed"),
2047 JvOptionPane.ERROR_MESSAGE);
2053 jalview.bin.Cache.log.error(
2054 "Implementation error - load session from a running session is not supported.");
2059 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2062 * @return true if import was a success and a session was started.
2064 public boolean vamsasImport(URL url)
2066 // TODO: create progress bar
2067 if (v_client != null)
2070 jalview.bin.Cache.log.error(
2071 "Implementation error - load session from a running session is not supported.");
2077 // copy the URL content to a temporary local file
2078 // TODO: be a bit cleverer here with nio (?!)
2079 File file = File.createTempFile("vdocfromurl", ".vdj");
2080 FileOutputStream fos = new FileOutputStream(file);
2081 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2082 byte[] buffer = new byte[2048];
2084 while ((ln = bis.read(buffer)) > -1)
2086 fos.write(buffer, 0, ln);
2090 v_client = new jalview.gui.VamsasApplication(this, file,
2091 url.toExternalForm());
2092 } catch (Exception ex)
2094 jalview.bin.Cache.log.error(
2095 "Failed to create new vamsas session from contents of URL "
2100 setupVamsasConnectedGui();
2101 v_client.initial_update(); // TODO: thread ?
2102 return v_client.inSession();
2106 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2109 * @return true if import was a success and a session was started.
2111 public boolean vamsasImport(File file)
2113 if (v_client != null)
2116 jalview.bin.Cache.log.error(
2117 "Implementation error - load session from a running session is not supported.");
2121 setProgressBar(MessageManager.formatMessage(
2122 "status.importing_vamsas_session_from", new Object[]
2123 { file.getName() }), file.hashCode());
2126 v_client = new jalview.gui.VamsasApplication(this, file, null);
2127 } catch (Exception ex)
2129 setProgressBar(MessageManager.formatMessage(
2130 "status.importing_vamsas_session_from", new Object[]
2131 { file.getName() }), file.hashCode());
2132 jalview.bin.Cache.log.error(
2133 "New vamsas session from existing session file failed:", ex);
2136 setupVamsasConnectedGui();
2137 v_client.initial_update(); // TODO: thread ?
2138 setProgressBar(MessageManager.formatMessage(
2139 "status.importing_vamsas_session_from", new Object[]
2140 { file.getName() }), file.hashCode());
2141 return v_client.inSession();
2144 public boolean joinVamsasSession(String mysesid)
2146 if (v_client != null)
2148 throw new Error(MessageManager
2149 .getString("error.try_join_vamsas_session_another"));
2151 if (mysesid == null)
2154 MessageManager.getString("error.invalid_vamsas_session_id"));
2156 v_client = new VamsasApplication(this, mysesid);
2157 setupVamsasConnectedGui();
2158 v_client.initial_update();
2159 return (v_client.inSession());
2163 public void vamsasStart_actionPerformed(ActionEvent e)
2165 if (v_client == null)
2168 // we just start a default session for moment.
2170 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2171 * getProperty("LAST_DIRECTORY"));
2173 * chooser.setFileView(new JalviewFileView());
2174 * chooser.setDialogTitle("Load Vamsas file");
2175 * chooser.setToolTipText("Import");
2177 * int value = chooser.showOpenDialog(this);
2179 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2180 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2182 v_client = new VamsasApplication(this);
2183 setupVamsasConnectedGui();
2184 v_client.initial_update(); // TODO: thread ?
2188 // store current data in session.
2189 v_client.push_update(); // TODO: thread
2193 protected void setupVamsasConnectedGui()
2195 vamsasStart.setText(MessageManager.getString("label.session_update"));
2196 vamsasSave.setVisible(true);
2197 vamsasStop.setVisible(true);
2198 vamsasImport.setVisible(false); // Document import to existing session is
2199 // not possible for vamsas-client-1.0.
2202 protected void setupVamsasDisconnectedGui()
2204 vamsasSave.setVisible(false);
2205 vamsasStop.setVisible(false);
2206 vamsasImport.setVisible(true);
2208 .setText(MessageManager.getString("label.new_vamsas_session"));
2212 public void vamsasStop_actionPerformed(ActionEvent e)
2214 if (v_client != null)
2216 v_client.end_session();
2218 setupVamsasDisconnectedGui();
2222 protected void buildVamsasStMenu()
2224 if (v_client == null)
2226 String[] sess = null;
2229 sess = VamsasApplication.getSessionList();
2230 } catch (Exception e)
2232 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2238 jalview.bin.Cache.log.debug(
2239 "Got current sessions list: " + sess.length + " entries.");
2240 VamsasStMenu.removeAll();
2241 for (int i = 0; i < sess.length; i++)
2243 JMenuItem sessit = new JMenuItem();
2244 sessit.setText(sess[i]);
2245 sessit.setToolTipText(MessageManager
2246 .formatMessage("label.connect_to_session", new Object[]
2248 final Desktop dsktp = this;
2249 final String mysesid = sess[i];
2250 sessit.addActionListener(new ActionListener()
2254 public void actionPerformed(ActionEvent e)
2256 if (dsktp.v_client == null)
2258 Thread rthr = new Thread(new Runnable()
2264 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2265 dsktp.setupVamsasConnectedGui();
2266 dsktp.v_client.initial_update();
2274 VamsasStMenu.add(sessit);
2276 // don't show an empty menu.
2277 VamsasStMenu.setVisible(sess.length > 0);
2282 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2283 VamsasStMenu.removeAll();
2284 VamsasStMenu.setVisible(false);
2289 // Not interested in the content. Just hide ourselves.
2290 VamsasStMenu.setVisible(false);
2295 public void vamsasSave_actionPerformed(ActionEvent e)
2297 if (v_client != null)
2299 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2300 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2303 chooser.setFileView(new JalviewFileView());
2304 chooser.setDialogTitle(MessageManager
2305 .getString("label.save_vamsas_document_archive"));
2307 int value = chooser.showSaveDialog(this);
2309 if (value == JalviewFileChooser.APPROVE_OPTION)
2311 java.io.File choice = chooser.getSelectedFile();
2312 JPanel progpanel = addProgressPanel(MessageManager
2313 .formatMessage("label.saving_vamsas_doc", new Object[]
2314 { choice.getName() }));
2315 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2316 String warnmsg = null;
2317 String warnttl = null;
2320 v_client.vclient.storeDocument(choice);
2323 warnttl = "Serious Problem saving Vamsas Document";
2324 warnmsg = ex.toString();
2325 jalview.bin.Cache.log
2326 .error("Error Whilst saving document to " + choice, ex);
2328 } catch (Exception ex)
2330 warnttl = "Problem saving Vamsas Document.";
2331 warnmsg = ex.toString();
2332 jalview.bin.Cache.log.warn(
2333 "Exception Whilst saving document to " + choice, ex);
2336 removeProgressPanel(progpanel);
2337 if (warnmsg != null)
2339 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2341 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2347 JPanel vamUpdate = null;
2350 * hide vamsas user gui bits when a vamsas document event is being handled.
2353 * true to hide gui, false to reveal gui
2355 public void setVamsasUpdate(boolean b)
2357 Cache.log.debug("Setting gui for Vamsas update "
2358 + (b ? "in progress" : "finished"));
2360 if (vamUpdate != null)
2362 this.removeProgressPanel(vamUpdate);
2366 vamUpdate = this.addProgressPanel(
2367 MessageManager.getString("label.updating_vamsas_session"));
2369 vamsasStart.setVisible(!b);
2370 vamsasStop.setVisible(!b);
2371 vamsasSave.setVisible(!b);
2374 public JInternalFrame[] getAllFrames()
2376 return desktop.getAllFrames();
2380 * Checks the given url to see if it gives a response indicating that the user
2381 * should be informed of a new questionnaire.
2385 public void checkForQuestionnaire(String url)
2387 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2388 // javax.swing.SwingUtilities.invokeLater(jvq);
2389 new Thread(jvq).start();
2392 public void checkURLLinks()
2394 // Thread off the URL link checker
2395 addDialogThread(new Runnable()
2400 if (Cache.getDefault("CHECKURLLINKS", true))
2402 // check what the actual links are - if it's just the default don't
2403 // bother with the warning
2404 List<String> links = Preferences.sequenceUrlLinks
2407 // only need to check links if there is one with a
2408 // SEQUENCE_ID which is not the default EMBL_EBI link
2409 ListIterator<String> li = links.listIterator();
2410 boolean check = false;
2411 List<JLabel> urls = new ArrayList<>();
2412 while (li.hasNext())
2414 String link = li.next();
2415 if (link.contains(SEQUENCE_ID)
2416 && !UrlConstants.isDefaultString(link))
2419 int barPos = link.indexOf("|");
2420 String urlMsg = barPos == -1 ? link
2421 : link.substring(0, barPos) + ": "
2422 + link.substring(barPos + 1);
2423 urls.add(new JLabel(urlMsg));
2431 // ask user to check in case URL links use old style tokens
2432 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2433 JPanel msgPanel = new JPanel();
2434 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2435 msgPanel.add(Box.createVerticalGlue());
2436 JLabel msg = new JLabel(MessageManager
2437 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2438 JLabel msg2 = new JLabel(MessageManager
2439 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2441 for (JLabel url : urls)
2447 final JCheckBox jcb = new JCheckBox(
2448 MessageManager.getString("label.do_not_display_again"));
2449 jcb.addActionListener(new ActionListener()
2452 public void actionPerformed(ActionEvent e)
2454 // update Cache settings for "don't show this again"
2455 boolean showWarningAgain = !jcb.isSelected();
2456 Cache.setProperty("CHECKURLLINKS",
2457 Boolean.valueOf(showWarningAgain).toString());
2462 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2464 .getString("label.SEQUENCE_ID_no_longer_used"),
2465 JvOptionPane.WARNING_MESSAGE);
2472 * Proxy class for JDesktopPane which optionally displays the current memory
2473 * usage and highlights the desktop area with a red bar if free memory runs
2478 public class MyDesktopPane extends JDesktopPane implements Runnable
2481 private static final float ONE_MB = 1048576f;
2483 boolean showMemoryUsage = false;
2487 java.text.NumberFormat df;
2489 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2492 public MyDesktopPane(boolean showMemoryUsage)
2494 showMemoryUsage(showMemoryUsage);
2497 public void showMemoryUsage(boolean showMemory)
2499 this.showMemoryUsage = showMemory;
2502 Thread worker = new Thread(this);
2508 public boolean isShowMemoryUsage()
2510 return showMemoryUsage;
2516 df = java.text.NumberFormat.getNumberInstance();
2517 df.setMaximumFractionDigits(2);
2518 runtime = Runtime.getRuntime();
2520 while (showMemoryUsage)
2524 maxMemory = runtime.maxMemory() / ONE_MB;
2525 allocatedMemory = runtime.totalMemory() / ONE_MB;
2526 freeMemory = runtime.freeMemory() / ONE_MB;
2527 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2529 percentUsage = (totalFreeMemory / maxMemory) * 100;
2531 // if (percentUsage < 20)
2533 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2535 // instance.set.setBorder(border1);
2538 // sleep after showing usage
2540 } catch (Exception ex)
2542 ex.printStackTrace();
2548 public void paintComponent(Graphics g)
2550 if (showMemoryUsage && g != null && df != null)
2552 if (percentUsage < 20)
2554 g.setColor(Color.red);
2556 FontMetrics fm = g.getFontMetrics();
2559 g.drawString(MessageManager.formatMessage("label.memory_stats",
2561 { df.format(totalFreeMemory), df.format(maxMemory),
2562 df.format(percentUsage) }),
2563 10, getHeight() - fm.getHeight());
2571 * Accessor method to quickly get all the AlignmentFrames loaded.
2573 * @return an array of AlignFrame, or null if none found
2575 public static AlignFrame[] getAlignFrames()
2577 if (Jalview.isHeadlessMode())
2579 // Desktop.desktop is null in headless mode
2580 return new AlignFrame[] { Jalview.currentAlignFrame };
2583 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2589 List<AlignFrame> avp = new ArrayList<>();
2591 for (int i = frames.length - 1; i > -1; i--)
2593 if (frames[i] instanceof AlignFrame)
2595 avp.add((AlignFrame) frames[i]);
2597 else if (frames[i] instanceof SplitFrame)
2600 * Also check for a split frame containing an AlignFrame
2602 GSplitFrame sf = (GSplitFrame) frames[i];
2603 if (sf.getTopFrame() instanceof AlignFrame)
2605 avp.add((AlignFrame) sf.getTopFrame());
2607 if (sf.getBottomFrame() instanceof AlignFrame)
2609 avp.add((AlignFrame) sf.getBottomFrame());
2613 if (avp.size() == 0)
2617 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2622 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2626 public GStructureViewer[] getJmols()
2628 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2634 List<GStructureViewer> avp = new ArrayList<>();
2636 for (int i = frames.length - 1; i > -1; i--)
2638 if (frames[i] instanceof AppJmol)
2640 GStructureViewer af = (GStructureViewer) frames[i];
2644 if (avp.size() == 0)
2648 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2653 * Add Groovy Support to Jalview
2656 public void groovyShell_actionPerformed()
2660 openGroovyConsole();
2661 } catch (Exception ex)
2663 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2664 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2666 MessageManager.getString("label.couldnt_create_groovy_shell"),
2667 MessageManager.getString("label.groovy_support_failed"),
2668 JvOptionPane.ERROR_MESSAGE);
2673 * Open the Groovy console
2675 void openGroovyConsole()
2677 if (groovyConsole == null)
2679 groovyConsole = new groovy.ui.Console();
2680 groovyConsole.setVariable("Jalview", this);
2681 groovyConsole.run();
2684 * We allow only one console at a time, so that AlignFrame menu option
2685 * 'Calculate | Run Groovy script' is unambiguous.
2686 * Disable 'Groovy Console', and enable 'Run script', when the console is
2687 * opened, and the reverse when it is closed
2689 Window window = (Window) groovyConsole.getFrame();
2690 window.addWindowListener(new WindowAdapter()
2693 public void windowClosed(WindowEvent e)
2696 * rebind CMD-Q from Groovy Console to Jalview Quit
2699 enableExecuteGroovy(false);
2705 * show Groovy console window (after close and reopen)
2707 ((Window) groovyConsole.getFrame()).setVisible(true);
2710 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2711 * and disable opening a second console
2713 enableExecuteGroovy(true);
2717 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2718 * binding when opened
2720 protected void addQuitHandler()
2722 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2723 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2724 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2726 getRootPane().getActionMap().put("Quit", new AbstractAction()
2729 public void actionPerformed(ActionEvent e)
2737 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2740 * true if Groovy console is open
2742 public void enableExecuteGroovy(boolean enabled)
2745 * disable opening a second Groovy console
2746 * (or re-enable when the console is closed)
2748 groovyShell.setEnabled(!enabled);
2750 AlignFrame[] alignFrames = getAlignFrames();
2751 if (alignFrames != null)
2753 for (AlignFrame af : alignFrames)
2755 af.setGroovyEnabled(enabled);
2761 * Progress bars managed by the IProgressIndicator method.
2763 private Hashtable<Long, JPanel> progressBars;
2765 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2770 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2773 public void setProgressBar(String message, long id)
2775 if (progressBars == null)
2777 progressBars = new Hashtable<>();
2778 progressBarHandlers = new Hashtable<>();
2781 if (progressBars.get(new Long(id)) != null)
2783 JPanel panel = progressBars.remove(new Long(id));
2784 if (progressBarHandlers.contains(new Long(id)))
2786 progressBarHandlers.remove(new Long(id));
2788 removeProgressPanel(panel);
2792 progressBars.put(new Long(id), addProgressPanel(message));
2799 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2800 * jalview.gui.IProgressIndicatorHandler)
2803 public void registerHandler(final long id,
2804 final IProgressIndicatorHandler handler)
2806 if (progressBarHandlers == null
2807 || !progressBars.containsKey(new Long(id)))
2809 throw new Error(MessageManager.getString(
2810 "error.call_setprogressbar_before_registering_handler"));
2812 progressBarHandlers.put(new Long(id), handler);
2813 final JPanel progressPanel = progressBars.get(new Long(id));
2814 if (handler.canCancel())
2816 JButton cancel = new JButton(
2817 MessageManager.getString("action.cancel"));
2818 final IProgressIndicator us = this;
2819 cancel.addActionListener(new ActionListener()
2823 public void actionPerformed(ActionEvent e)
2825 handler.cancelActivity(id);
2826 us.setProgressBar(MessageManager
2827 .formatMessage("label.cancelled_params", new Object[]
2828 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2832 progressPanel.add(cancel, BorderLayout.EAST);
2838 * @return true if any progress bars are still active
2841 public boolean operationInProgress()
2843 if (progressBars != null && progressBars.size() > 0)
2851 * This will return the first AlignFrame holding the given viewport instance.
2852 * It will break if there are more than one AlignFrames viewing a particular
2856 * @return alignFrame for viewport
2858 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2860 if (desktop != null)
2862 AlignmentPanel[] aps = getAlignmentPanels(
2863 viewport.getSequenceSetId());
2864 for (int panel = 0; aps != null && panel < aps.length; panel++)
2866 if (aps[panel] != null && aps[panel].av == viewport)
2868 return aps[panel].alignFrame;
2875 public VamsasApplication getVamsasApplication()
2882 * flag set if jalview GUI is being operated programmatically
2884 private boolean inBatchMode = false;
2887 * check if jalview GUI is being operated programmatically
2889 * @return inBatchMode
2891 public boolean isInBatchMode()
2897 * set flag if jalview GUI is being operated programmatically
2899 * @param inBatchMode
2901 public void setInBatchMode(boolean inBatchMode)
2903 this.inBatchMode = inBatchMode;
2906 public void startServiceDiscovery()
2908 startServiceDiscovery(false);
2911 public void startServiceDiscovery(boolean blocking)
2913 boolean alive = true;
2914 Thread t0 = null, t1 = null, t2 = null;
2915 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2918 // todo: changesupport handlers need to be transferred
2919 if (discoverer == null)
2921 discoverer = new jalview.ws.jws1.Discoverer();
2922 // register PCS handler for desktop.
2923 discoverer.addPropertyChangeListener(changeSupport);
2925 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2926 // until we phase out completely
2927 (t0 = new Thread(discoverer)).start();
2930 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2932 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2933 .startDiscoverer(changeSupport);
2937 // TODO: do rest service discovery
2946 } catch (Exception e)
2949 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2950 || (t3 != null && t3.isAlive())
2951 || (t0 != null && t0.isAlive());
2957 * called to check if the service discovery process completed successfully.
2961 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2963 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2965 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2966 .getErrorMessages();
2969 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2971 if (serviceChangedDialog == null)
2973 // only run if we aren't already displaying one of these.
2974 addDialogThread(serviceChangedDialog = new Runnable()
2981 * JalviewDialog jd =new JalviewDialog() {
2983 * @Override protected void cancelPressed() { // TODO
2984 * Auto-generated method stub
2986 * }@Override protected void okPressed() { // TODO
2987 * Auto-generated method stub
2989 * }@Override protected void raiseClosed() { // TODO
2990 * Auto-generated method stub
2992 * } }; jd.initDialogFrame(new
2993 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2994 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2995 * + " or mis-configured HTTP proxy settings.<br/>" +
2996 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2998 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2999 * ), true, true, "Web Service Configuration Problem", 450,
3002 * jd.waitForInput();
3004 JvOptionPane.showConfirmDialog(Desktop.desktop,
3005 new JLabel("<html><table width=\"450\"><tr><td>"
3006 + ermsg + "</td></tr></table>"
3007 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3008 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3009 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3010 + " Tools->Preferences dialog box to change them.</p></html>"),
3011 "Web Service Configuration Problem",
3012 JvOptionPane.DEFAULT_OPTION,
3013 JvOptionPane.ERROR_MESSAGE);
3014 serviceChangedDialog = null;
3023 "Errors reported by JABA discovery service. Check web services preferences.\n"
3030 private Runnable serviceChangedDialog = null;
3033 * start a thread to open a URL in the configured browser. Pops up a warning
3034 * dialog to the user if there is an exception when calling out to the browser
3039 public static void showUrl(final String url)
3041 showUrl(url, Desktop.instance);
3045 * Like showUrl but allows progress handler to be specified
3049 * (null) or object implementing IProgressIndicator
3051 public static void showUrl(final String url,
3052 final IProgressIndicator progress)
3054 new Thread(new Runnable()
3061 if (progress != null)
3063 progress.setProgressBar(MessageManager
3064 .formatMessage("status.opening_params", new Object[]
3065 { url }), this.hashCode());
3067 jalview.util.BrowserLauncher.openURL(url);
3068 } catch (Exception ex)
3070 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3072 .getString("label.web_browser_not_found_unix"),
3073 MessageManager.getString("label.web_browser_not_found"),
3074 JvOptionPane.WARNING_MESSAGE);
3076 ex.printStackTrace();
3078 if (progress != null)
3080 progress.setProgressBar(null, this.hashCode());
3086 public static WsParamSetManager wsparamManager = null;
3088 public static ParamManager getUserParameterStore()
3090 if (wsparamManager == null)
3092 wsparamManager = new WsParamSetManager();
3094 return wsparamManager;
3098 * static hyperlink handler proxy method for use by Jalview's internal windows
3102 public static void hyperlinkUpdate(HyperlinkEvent e)
3104 if (e.getEventType() == EventType.ACTIVATED)
3109 url = e.getURL().toString();
3110 Desktop.showUrl(url);
3111 } catch (Exception x)
3115 if (Cache.log != null)
3117 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3122 "Couldn't handle string " + url + " as a URL.");
3125 // ignore any exceptions due to dud links.
3132 * single thread that handles display of dialogs to user.
3134 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3137 * flag indicating if dialogExecutor should try to acquire a permit
3139 private volatile boolean dialogPause = true;
3144 private java.util.concurrent.Semaphore block = new Semaphore(0);
3146 private static groovy.ui.Console groovyConsole;
3149 * add another dialog thread to the queue
3153 public void addDialogThread(final Runnable prompter)
3155 dialogExecutor.submit(new Runnable()
3165 } catch (InterruptedException x)
3170 if (instance == null)
3176 SwingUtilities.invokeAndWait(prompter);
3177 } catch (Exception q)
3179 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3185 public void startDialogQueue()
3187 // set the flag so we don't pause waiting for another permit and semaphore
3188 // the current task to begin
3189 dialogPause = false;
3194 protected void snapShotWindow_actionPerformed(ActionEvent e)
3198 ImageMaker im = new jalview.util.ImageMaker(
3199 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3200 getHeight(), of = new File("Jalview_snapshot"
3201 + System.currentTimeMillis() + ".eps"),
3202 "View of desktop", null, 0, false);
3205 paintAll(im.getGraphics());
3207 } catch (Exception q)
3209 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3213 Cache.log.info("Successfully written snapshot to file "
3214 + of.getAbsolutePath());
3218 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3219 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3220 * and location last time the view was expanded (if any). However it does not
3221 * remember the split pane divider location - this is set to match the
3222 * 'exploding' frame.
3226 public void explodeViews(SplitFrame sf)
3228 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3229 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3230 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3232 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3234 int viewCount = topPanels.size();
3241 * Processing in reverse order works, forwards order leaves the first panels
3242 * not visible. I don't know why!
3244 for (int i = viewCount - 1; i >= 0; i--)
3247 * Make new top and bottom frames. These take over the respective
3248 * AlignmentPanel objects, including their AlignmentViewports, so the
3249 * cdna/protein relationships between the viewports is carried over to the
3252 * explodedGeometry holds the (x, y) position of the previously exploded
3253 * SplitFrame, and the (width, height) of the AlignFrame component
3255 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3256 AlignFrame newTopFrame = new AlignFrame(topPanel);
3257 newTopFrame.setSize(oldTopFrame.getSize());
3258 newTopFrame.setVisible(true);
3259 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3260 .getExplodedGeometry();
3261 if (geometry != null)
3263 newTopFrame.setSize(geometry.getSize());
3266 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3267 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3268 newBottomFrame.setSize(oldBottomFrame.getSize());
3269 newBottomFrame.setVisible(true);
3270 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3271 .getExplodedGeometry();
3272 if (geometry != null)
3274 newBottomFrame.setSize(geometry.getSize());
3277 topPanel.av.setGatherViewsHere(false);
3278 bottomPanel.av.setGatherViewsHere(false);
3279 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3281 if (geometry != null)
3283 splitFrame.setLocation(geometry.getLocation());
3285 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3289 * Clear references to the panels (now relocated in the new SplitFrames)
3290 * before closing the old SplitFrame.
3293 bottomPanels.clear();
3298 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3299 * back into the given SplitFrame as additional views. Note that the gathered
3300 * frames may themselves have multiple views.
3304 public void gatherViews(GSplitFrame source)
3307 * special handling of explodedGeometry for a view within a SplitFrame: - it
3308 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3309 * height) of the AlignFrame component
3311 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3312 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3313 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3314 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3315 myBottomFrame.viewport
3316 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3317 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3318 myTopFrame.viewport.setGatherViewsHere(true);
3319 myBottomFrame.viewport.setGatherViewsHere(true);
3320 String topViewId = myTopFrame.viewport.getSequenceSetId();
3321 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3323 JInternalFrame[] frames = desktop.getAllFrames();
3324 for (JInternalFrame frame : frames)
3326 if (frame instanceof SplitFrame && frame != source)
3328 SplitFrame sf = (SplitFrame) frame;
3329 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3330 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3331 boolean gatherThis = false;
3332 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3334 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3335 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3336 if (topViewId.equals(topPanel.av.getSequenceSetId())
3337 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3340 topPanel.av.setGatherViewsHere(false);
3341 bottomPanel.av.setGatherViewsHere(false);
3342 topPanel.av.setExplodedGeometry(
3343 new Rectangle(sf.getLocation(), topFrame.getSize()));
3344 bottomPanel.av.setExplodedGeometry(
3345 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3346 myTopFrame.addAlignmentPanel(topPanel, false);
3347 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3353 topFrame.getAlignPanels().clear();
3354 bottomFrame.getAlignPanels().clear();
3361 * The dust settles...give focus to the tab we did this from.
3363 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3366 public static groovy.ui.Console getGroovyConsole()
3368 return groovyConsole;
3372 * handles the payload of a drag and drop event.
3374 * TODO refactor to desktop utilities class
3377 * - Data source strings extracted from the drop event
3379 * - protocol for each data source extracted from the drop event
3383 * - the payload from the drop event
3386 public static void transferFromDropTarget(List<String> files,
3387 List<DataSourceType> protocols, DropTargetDropEvent evt,
3388 Transferable t) throws Exception
3391 DataFlavor uriListFlavor = new DataFlavor(
3392 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3395 urlFlavour = new DataFlavor(
3396 "application/x-java-url; class=java.net.URL");
3397 } catch (ClassNotFoundException cfe)
3399 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3402 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3407 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3408 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3409 // means url may be null.
3412 protocols.add(DataSourceType.URL);
3413 files.add(url.toString());
3414 Cache.log.debug("Drop handled as URL dataflavor "
3415 + files.get(files.size() - 1));
3420 if (Platform.isAMac())
3423 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3427 } catch (Throwable ex)
3429 Cache.log.debug("URL drop handler failed.", ex);
3432 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3434 // Works on Windows and MacOSX
3435 Cache.log.debug("Drop handled as javaFileListFlavor");
3436 for (Object file : (List) t
3437 .getTransferData(DataFlavor.javaFileListFlavor))
3439 files.add(((File) file).toString());
3440 protocols.add(DataSourceType.FILE);
3445 // Unix like behaviour
3446 boolean added = false;
3448 if (t.isDataFlavorSupported(uriListFlavor))
3450 Cache.log.debug("Drop handled as uriListFlavor");
3451 // This is used by Unix drag system
3452 data = (String) t.getTransferData(uriListFlavor);
3456 // fallback to text: workaround - on OSX where there's a JVM bug
3457 Cache.log.debug("standard URIListFlavor failed. Trying text");
3458 // try text fallback
3459 DataFlavor textDf = new DataFlavor(
3460 "text/plain;class=java.lang.String");
3461 if (t.isDataFlavorSupported(textDf))
3463 data = (String) t.getTransferData(textDf);
3466 Cache.log.debug("Plain text drop content returned "
3467 + (data == null ? "Null - failed" : data));
3472 while (protocols.size() < files.size())
3474 Cache.log.debug("Adding missing FILE protocol for "
3475 + files.get(protocols.size()));
3476 protocols.add(DataSourceType.FILE);
3478 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3479 data, "\r\n"); st.hasMoreTokens();)
3482 String s = st.nextToken();
3483 if (s.startsWith("#"))
3485 // the line is a comment (as per the RFC 2483)
3488 java.net.URI uri = new java.net.URI(s);
3489 if (uri.getScheme().toLowerCase().startsWith("http"))
3491 protocols.add(DataSourceType.URL);
3492 files.add(uri.toString());
3496 // otherwise preserve old behaviour: catch all for file objects
3497 java.io.File file = new java.io.File(uri);
3498 protocols.add(DataSourceType.FILE);
3499 files.add(file.toString());
3504 if (Cache.log.isDebugEnabled())
3506 if (data == null || !added)
3509 if (t.getTransferDataFlavors() != null
3510 && t.getTransferDataFlavors().length > 0)
3513 "Couldn't resolve drop data. Here are the supported flavors:");
3514 for (DataFlavor fl : t.getTransferDataFlavors())
3517 "Supported transfer dataflavor: " + fl.toString());
3518 Object df = t.getTransferData(fl);
3521 Cache.log.debug("Retrieves: " + df);
3525 Cache.log.debug("Retrieved nothing");
3531 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3537 if (Platform.isWindows())
3540 Cache.log.debug("Scanning dropped content for Windows Link Files");
3542 // resolve any .lnk files in the file drop
3543 for (int f = 0; f < files.size(); f++)
3545 String source = files.get(f).toLowerCase();
3546 if (protocols.get(f).equals(DataSourceType.FILE)
3547 && (source.endsWith(".lnk") || source.endsWith(".url")
3548 || source.endsWith(".site")))
3551 File lf = new File(files.get(f));
3552 // process link file to get a URL
3553 Cache.log.debug("Found potential link file: " + lf);
3554 WindowsShortcut wscfile = new WindowsShortcut(lf);
3555 String fullname = wscfile.getRealFilename();
3556 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3557 files.set(f, fullname);
3558 Cache.log.debug("Parsed real filename " + fullname
3559 + " to extract protocol: " + protocols.get(f));
3561 catch (Exception ex)
3563 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3571 * Sets the Preferences property for experimental features to True or False
3572 * depending on the state of the controlling menu item
3575 protected void showExperimental_actionPerformed(boolean selected)
3577 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3581 * Answers a (possibly empty) list of any structure viewer frames (currently
3582 * for either Jmol or Chimera) which are currently open. This may optionally
3583 * be restricted to viewers of a specified class, or viewers linked to a
3584 * specified alignment panel.
3587 * if not null, only return viewers linked to this panel
3588 * @param structureViewerClass
3589 * if not null, only return viewers of this class
3592 public List<StructureViewerBase> getStructureViewers(
3593 AlignmentPanel apanel,
3594 Class<? extends StructureViewerBase> structureViewerClass)
3596 List<StructureViewerBase> result = new ArrayList<>();
3597 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3599 for (JInternalFrame frame : frames)
3601 if (frame instanceof StructureViewerBase)
3603 if (structureViewerClass == null
3604 || structureViewerClass.isInstance(frame))
3607 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3609 result.add((StructureViewerBase) frame);