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 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
392 jconsole = new Console(this, showjconsole);
393 // add essential build information
394 jconsole.setHeader("Jalview Version: "
395 + jalview.bin.Cache.getProperty("VERSION") + "\n"
396 + "Jalview Installation: "
397 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
398 + "\n" + "Build Date: "
399 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
400 + "Java version: " + System.getProperty("java.version") + "\n"
401 + System.getProperty("os.arch") + " "
402 + System.getProperty("os.name") + " "
403 + System.getProperty("os.version"));
405 showConsole(showjconsole);
407 showNews.setVisible(false);
409 experimentalFeatures.setSelected(showExperimental());
411 getIdentifiersOrgData();
415 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
416 // Spawn a thread that shows the splashscreen
418 SwingUtilities.invokeLater(new Runnable()
427 // Thread off a new instance of the file chooser - this reduces the time it
428 // takes to open it later on.
429 new Thread(new Runnable()
434 Cache.log.debug("Filechooser init thread started.");
435 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
436 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
438 Cache.log.debug("Filechooser init thread finished.");
441 // Add the service change listener
442 changeSupport.addJalviewPropertyChangeListener("services",
443 new PropertyChangeListener()
447 public void propertyChange(PropertyChangeEvent evt)
449 Cache.log.debug("Firing service changed event for "
450 + evt.getNewValue());
451 JalviewServicesChanged(evt);
456 } // end BH 2018 ignore
458 this.addWindowListener(new WindowAdapter()
461 public void windowClosing(WindowEvent evt)
468 this.addMouseListener(ma = new MouseAdapter()
471 public void mousePressed(MouseEvent evt)
473 if (evt.isPopupTrigger()) // Mac
475 showPasteMenu(evt.getX(), evt.getY());
480 public void mouseReleased(MouseEvent evt)
482 if (evt.isPopupTrigger()) // Windows
484 showPasteMenu(evt.getX(), evt.getY());
488 desktop.addMouseListener(ma);
493 * Answers true if user preferences to enable experimental features is True
498 public boolean showExperimental()
500 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
501 Boolean.FALSE.toString());
502 return Boolean.valueOf(experimental).booleanValue();
505 public void doConfigureStructurePrefs()
507 // configure services
508 StructureSelectionManager ssm = StructureSelectionManager
509 .getStructureSelectionManager(this);
510 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
512 ssm.setAddTempFacAnnot(jalview.bin.Cache
513 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
514 ssm.setProcessSecondaryStructure(jalview.bin.Cache
515 .getDefault(Preferences.STRUCT_FROM_PDB, true));
516 ssm.setSecStructServices(
517 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
521 ssm.setAddTempFacAnnot(false);
522 ssm.setProcessSecondaryStructure(false);
523 ssm.setSecStructServices(false);
527 public void checkForNews()
536 final Desktop me = this;
537 // Thread off the news reader, in case there are connection problems.
538 addDialogThread(new Runnable()
543 Cache.log.debug("Starting news thread.");
545 jvnews = new BlogReader(me);
546 showNews.setVisible(true);
547 Cache.log.debug("Completed news thread.");
553 public void getIdentifiersOrgData()
555 // Thread off the identifiers fetcher
556 addDialogThread(new Runnable()
561 Cache.log.debug("Downloading data from identifiers.org");
562 UrlDownloadClient client = new UrlDownloadClient();
565 client.download(IdOrgSettings.getUrl(),
566 IdOrgSettings.getDownloadLocation());
567 } catch (IOException e)
569 Cache.log.debug("Exception downloading identifiers.org data"
577 protected void showNews_actionPerformed(ActionEvent e)
579 showNews(showNews.isSelected());
582 void showNews(boolean visible)
591 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
592 showNews.setSelected(visible);
593 if (visible && !jvnews.isVisible())
595 new Thread(new Runnable()
600 long now = System.currentTimeMillis();
601 Desktop.instance.setProgressBar(
602 MessageManager.getString("status.refreshing_news"),
604 jvnews.refreshNews();
605 Desktop.instance.setProgressBar(null, now);
614 * recover the last known dimensions for a jalview window
617 * - empty string is desktop, all other windows have unique prefix
618 * @return null or last known dimensions scaled to current geometry (if last
619 * window geom was known)
621 Rectangle getLastKnownDimensions(String windowName)
623 // TODO: lock aspect ratio for scaling desktop Bug #0058199
624 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
625 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
626 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
627 String width = jalview.bin.Cache
628 .getProperty(windowName + "SCREEN_WIDTH");
629 String height = jalview.bin.Cache
630 .getProperty(windowName + "SCREEN_HEIGHT");
631 if ((x != null) && (y != null) && (width != null) && (height != null))
633 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
634 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
635 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
637 // attempt #1 - try to cope with change in screen geometry - this
638 // version doesn't preserve original jv aspect ratio.
639 // take ratio of current screen size vs original screen size.
640 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
641 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
642 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
643 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
644 // rescale the bounds depending upon the current screen geometry.
645 ix = (int) (ix * sw);
646 iw = (int) (iw * sw);
647 iy = (int) (iy * sh);
648 ih = (int) (ih * sh);
649 while (ix >= screenSize.width)
651 jalview.bin.Cache.log.debug(
652 "Window geometry location recall error: shifting horizontal to within screenbounds.");
653 ix -= screenSize.width;
655 while (iy >= screenSize.height)
657 jalview.bin.Cache.log.debug(
658 "Window geometry location recall error: shifting vertical to within screenbounds.");
659 iy -= screenSize.height;
661 jalview.bin.Cache.log.debug(
662 "Got last known dimensions for " + windowName + ": x:" + ix
663 + " y:" + iy + " width:" + iw + " height:" + ih);
665 // return dimensions for new instance
666 return new Rectangle(ix, iy, iw, ih);
671 private void doVamsasClientCheck()
673 if (/** @j2sNative false && */ // BH 2018
674 jalview.bin.Cache.vamsasJarsPresent())
676 setupVamsasDisconnectedGui();
677 VamsasMenu.setVisible(true);
678 final Desktop us = this;
679 VamsasMenu.addMenuListener(new MenuListener()
681 // this listener remembers when the menu was first selected, and
682 // doesn't rebuild the session list until it has been cleared and
684 boolean refresh = true;
687 public void menuCanceled(MenuEvent e)
693 public void menuDeselected(MenuEvent e)
699 public void menuSelected(MenuEvent e)
703 us.buildVamsasStMenu();
708 vamsasStart.setVisible(true);
712 void showPasteMenu(int x, int y)
714 JPopupMenu popup = new JPopupMenu();
715 JMenuItem item = new JMenuItem(
716 MessageManager.getString("label.paste_new_window"));
717 item.addActionListener(new ActionListener()
720 public void actionPerformed(ActionEvent evt)
727 popup.show(this, x, y);
734 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
735 Transferable contents = c.getContents(this);
737 if (contents != null)
739 String file = (String) contents
740 .getTransferData(DataFlavor.stringFlavor);
742 FileFormatI format = new IdentifyFile().identify(file,
743 DataSourceType.PASTE);
745 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
748 } catch (Exception ex)
751 "Unable to paste alignment from system clipboard:\n" + ex);
756 * Adds and opens the given frame to the desktop
767 public static synchronized void addInternalFrame(
768 final JInternalFrame frame, String title, int w, int h)
770 addInternalFrame(frame, title, true, w, h, true, false);
774 * Add an internal frame to the Jalview desktop
781 * When true, display frame immediately, otherwise, caller must call
782 * setVisible themselves.
788 public static synchronized void addInternalFrame(
789 final JInternalFrame frame, String title, boolean makeVisible,
792 addInternalFrame(frame, title, makeVisible, w, h, true, false);
796 * Add an internal frame to the Jalview desktop and make it visible
809 public static synchronized void addInternalFrame(
810 final JInternalFrame frame, String title, int w, int h,
813 addInternalFrame(frame, title, true, w, h, resizable, false);
817 * Add an internal frame to the Jalview desktop
824 * When true, display frame immediately, otherwise, caller must call
825 * setVisible themselves.
832 * @param ignoreMinSize
833 * Do not set the default minimum size for frame
835 public static synchronized void addInternalFrame(
836 final JInternalFrame frame, String title, boolean makeVisible,
837 int w, int h, boolean resizable, boolean ignoreMinSize)
840 // TODO: allow callers to determine X and Y position of frame (eg. via
842 // TODO: consider fixing method to update entries in the window submenu with
843 // the current window title
845 frame.setTitle(title);
846 if (frame.getWidth() < 1 || frame.getHeight() < 1)
850 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
851 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
852 // IF JALVIEW IS RUNNING HEADLESS
853 // ///////////////////////////////////////////////
854 if (instance == null || (System.getProperty("java.awt.headless") != null
855 && System.getProperty("java.awt.headless").equals("true")))
864 frame.setMinimumSize(
865 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
867 // Set default dimension for Alignment Frame window.
868 // The Alignment Frame window could be added from a number of places,
870 // I did this here in order not to miss out on any Alignment frame.
871 if (frame instanceof AlignFrame)
873 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
874 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
878 frame.setVisible(makeVisible);
879 frame.setClosable(true);
880 frame.setResizable(resizable);
881 frame.setMaximizable(resizable);
882 frame.setIconifiable(resizable);
883 frame.setOpaque(/** @j2sNative true || */
886 if (frame.getX() < 1 && frame.getY() < 1)
888 frame.setLocation(xOffset * openFrameCount,
889 yOffset * ((openFrameCount - 1) % 10) + yOffset);
893 * add an entry for the new frame in the Window menu
894 * (and remove it when the frame is closed)
896 final JMenuItem menuItem = new JMenuItem(title);
897 frame.addInternalFrameListener(new InternalFrameAdapter()
900 public void internalFrameActivated(InternalFrameEvent evt)
902 JInternalFrame itf = desktop.getSelectedFrame();
905 if (itf instanceof AlignFrame)
907 Jalview.setCurrentAlignFrame((AlignFrame) itf);
914 public void internalFrameClosed(InternalFrameEvent evt)
916 PaintRefresher.RemoveComponent(frame);
919 * defensive check to prevent frames being
920 * added half off the window
922 if (openFrameCount > 0)
928 * ensure no reference to alignFrame retained by menu item listener
930 if (menuItem.getActionListeners().length > 0)
932 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
934 windowMenu.remove(menuItem);
938 menuItem.addActionListener(new ActionListener()
941 public void actionPerformed(ActionEvent e)
945 frame.setSelected(true);
946 frame.setIcon(false);
947 } catch (java.beans.PropertyVetoException ex)
954 setKeyBindings(frame);
958 windowMenu.add(menuItem);
963 frame.setSelected(true);
964 frame.requestFocus();
965 } catch (java.beans.PropertyVetoException ve)
967 } catch (java.lang.ClassCastException cex)
970 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
976 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
981 private static void setKeyBindings(JInternalFrame frame)
983 @SuppressWarnings("serial")
984 final Action closeAction = new AbstractAction()
987 public void actionPerformed(ActionEvent e)
994 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
996 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
997 InputEvent.CTRL_DOWN_MASK);
998 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
999 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1001 InputMap inputMap = frame
1002 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1003 String ctrlW = ctrlWKey.toString();
1004 inputMap.put(ctrlWKey, ctrlW);
1005 inputMap.put(cmdWKey, ctrlW);
1007 ActionMap actionMap = frame.getActionMap();
1008 actionMap.put(ctrlW, closeAction);
1012 public void lostOwnership(Clipboard clipboard, Transferable contents)
1016 Desktop.jalviewClipboard = null;
1019 internalCopy = false;
1023 public void dragEnter(DropTargetDragEvent evt)
1028 public void dragExit(DropTargetEvent evt)
1033 public void dragOver(DropTargetDragEvent evt)
1038 public void dropActionChanged(DropTargetDragEvent evt)
1049 public void drop(DropTargetDropEvent evt)
1051 boolean success = true;
1052 // JAL-1552 - acceptDrop required before getTransferable call for
1053 // Java's Transferable for native dnd
1054 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1055 Transferable t = evt.getTransferable();
1056 List<String> files = new ArrayList<>();
1057 List<DataSourceType> protocols = new ArrayList<>();
1061 Desktop.transferFromDropTarget(files, protocols, evt, t);
1062 } catch (Exception e)
1064 e.printStackTrace();
1072 for (int i = 0; i < files.size(); i++)
1074 String file = files.get(i).toString();
1075 DataSourceType protocol = (protocols == null)
1076 ? DataSourceType.FILE
1078 FileFormatI format = null;
1080 if (file.endsWith(".jar"))
1082 format = FileFormat.Jalview;
1087 format = new IdentifyFile().identify(file, protocol);
1090 new FileLoader().LoadFile(file, protocol, format);
1093 } catch (Exception ex)
1098 evt.dropComplete(success); // need this to ensure input focus is properly
1099 // transfered to any new windows created
1109 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1111 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1112 JalviewFileChooser chooser = JalviewFileChooser
1113 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1115 chooser.setFileView(new JalviewFileView());
1116 chooser.setDialogTitle(
1117 MessageManager.getString("label.open_local_file"));
1118 chooser.setToolTipText(MessageManager.getString("action.open"));
1120 int value = chooser.showOpenDialog(this);
1122 if (value == JalviewFileChooser.APPROVE_OPTION)
1124 String choice = chooser.getSelectedFile().getPath();
1125 Cache.setProperty("LAST_DIRECTORY",
1126 chooser.getSelectedFile().getParent());
1128 FileFormatI format = chooser.getSelectedFormat();
1131 * Call IdentifyFile to verify the file contains what its extension implies.
1132 * Skip this step for dynamically added file formats, because
1133 * IdentifyFile does not know how to recognise them.
1135 if (FileFormats.getInstance().isIdentifiable(format))
1139 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1140 } catch (FileFormatException e)
1142 // format = null; //??
1146 if (viewport != null)
1148 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1153 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1165 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1167 // This construct allows us to have a wider textfield
1169 JLabel label = new JLabel(
1170 MessageManager.getString("label.input_file_url"));
1171 final JComboBox history = new JComboBox();
1173 JPanel panel = new JPanel(new GridLayout(2, 1));
1176 history.setPreferredSize(new Dimension(400, 20));
1177 history.setEditable(true);
1178 history.addItem("http://www.");
1180 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1184 if (historyItems != null)
1186 st = new StringTokenizer(historyItems, "\t");
1188 while (st.hasMoreTokens())
1190 history.addItem(st.nextElement());
1194 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1195 MessageManager.getString("label.input_alignment_from_url"),
1196 JvOptionPane.OK_CANCEL_OPTION);
1198 if (reply != JvOptionPane.OK_OPTION)
1203 String url = history.getSelectedItem().toString();
1205 if (url.toLowerCase().endsWith(".jar"))
1207 if (viewport != null)
1209 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1210 FileFormat.Jalview);
1214 new FileLoader().LoadFile(url, DataSourceType.URL,
1215 FileFormat.Jalview);
1220 FileFormatI format = null;
1223 format = new IdentifyFile().identify(url, DataSourceType.URL);
1224 } catch (FileFormatException e)
1226 // TODO revise error handling, distinguish between
1227 // URL not found and response not valid
1232 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1233 MessageManager.formatMessage("label.couldnt_locate",
1236 MessageManager.getString("label.url_not_found"),
1237 JvOptionPane.WARNING_MESSAGE);
1242 if (viewport != null)
1244 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1249 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1255 * Opens the CutAndPaste window for the user to paste an alignment in to
1258 * - if not null, the pasted alignment is added to the current
1259 * alignment; if null, to a new alignment window
1262 public void inputTextboxMenuItem_actionPerformed(
1263 AlignmentViewPanel viewPanel)
1265 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1266 cap.setForInput(viewPanel);
1267 Desktop.addInternalFrame(cap,
1268 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1278 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1279 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1281 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1282 screen.height + "");
1283 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1284 getWidth(), getHeight()));
1286 if (jconsole != null)
1288 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1289 jconsole.stopConsole();
1293 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1296 if (dialogExecutor != null)
1298 dialogExecutor.shutdownNow();
1300 closeAll_actionPerformed(null);
1302 if (groovyConsole != null)
1304 // suppress a possible repeat prompt to save script
1305 groovyConsole.setDirty(false);
1306 groovyConsole.exit();
1311 private void storeLastKnownDimensions(String string, Rectangle jc)
1313 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1314 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1315 + " height:" + jc.height);
1317 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1318 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1319 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1320 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1330 public void aboutMenuItem_actionPerformed(ActionEvent e)
1332 // StringBuffer message = getAboutMessage(false);
1333 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1335 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1336 new Thread(new Runnable()
1341 new SplashScreen(true);
1346 public StringBuffer getAboutMessage(boolean shortv)
1348 StringBuffer message = new StringBuffer();
1349 message.append("<html>");
1352 message.append("<h1><strong>Version: "
1353 + jalview.bin.Cache.getProperty("VERSION")
1354 + "</strong></h1>");
1355 message.append("<strong>Last Updated: <em>"
1356 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1357 + "</em></strong>");
1363 message.append("<strong>Version "
1364 + jalview.bin.Cache.getProperty("VERSION")
1365 + "; last updated: "
1366 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1369 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1370 .equals("Checking"))
1372 message.append("<br>...Checking latest version...</br>");
1374 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1375 .equals(jalview.bin.Cache.getProperty("VERSION")))
1377 boolean red = false;
1378 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1379 .indexOf("automated build") == -1)
1382 // Displayed when code version and jnlp version do not match and code
1383 // version is not a development build
1384 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1387 message.append("<br>!! Version "
1388 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1390 + " is available for download from "
1391 + jalview.bin.Cache.getDefault("www.jalview.org",
1392 "http://www.jalview.org")
1396 message.append("</div>");
1399 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1401 "The Jalview Authors (See AUTHORS file for current list)")
1402 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1403 + "<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"
1404 + "<br><br>If you use Jalview, please cite:"
1405 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1406 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1407 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1419 public void documentationMenuItem_actionPerformed(ActionEvent e)
1423 Help.showHelpWindow();
1424 } catch (Exception ex)
1430 public void closeAll_actionPerformed(ActionEvent e)
1432 // TODO show a progress bar while closing?
1433 JInternalFrame[] frames = desktop.getAllFrames();
1434 for (int i = 0; i < frames.length; i++)
1438 frames[i].setClosed(true);
1439 } catch (java.beans.PropertyVetoException ex)
1443 Jalview.setCurrentAlignFrame(null);
1444 System.out.println("ALL CLOSED");
1445 if (v_client != null)
1447 // TODO clear binding to vamsas document objects on close_all
1451 * reset state of singleton objects as appropriate (clear down session state
1452 * when all windows are closed)
1454 StructureSelectionManager ssm = StructureSelectionManager
1455 .getStructureSelectionManager(this);
1463 public void raiseRelated_actionPerformed(ActionEvent e)
1465 reorderAssociatedWindows(false, false);
1469 public void minimizeAssociated_actionPerformed(ActionEvent e)
1471 reorderAssociatedWindows(true, false);
1474 void closeAssociatedWindows()
1476 reorderAssociatedWindows(false, true);
1482 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1486 protected void garbageCollect_actionPerformed(ActionEvent e)
1488 // We simply collect the garbage
1489 jalview.bin.Cache.log.debug("Collecting garbage...");
1491 jalview.bin.Cache.log.debug("Finished garbage collection.");
1498 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1502 protected void showMemusage_actionPerformed(ActionEvent e)
1504 desktop.showMemoryUsage(showMemusage.isSelected());
1511 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1515 protected void showConsole_actionPerformed(ActionEvent e)
1517 showConsole(showConsole.isSelected());
1520 Console jconsole = null;
1523 * control whether the java console is visible or not
1527 void showConsole(boolean selected)
1529 // TODO: decide if we should update properties file
1530 if (jconsole != null) // BH 2018
1532 showConsole.setSelected(selected);
1533 Cache.setProperty("SHOW_JAVA_CONSOLE",
1534 Boolean.valueOf(selected).toString());
1535 jconsole.setVisible(selected);
1539 void reorderAssociatedWindows(boolean minimize, boolean close)
1541 JInternalFrame[] frames = desktop.getAllFrames();
1542 if (frames == null || frames.length < 1)
1547 AlignmentViewport source = null, target = null;
1548 if (frames[0] instanceof AlignFrame)
1550 source = ((AlignFrame) frames[0]).getCurrentView();
1552 else if (frames[0] instanceof TreePanel)
1554 source = ((TreePanel) frames[0]).getViewPort();
1556 else if (frames[0] instanceof PCAPanel)
1558 source = ((PCAPanel) frames[0]).av;
1560 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1562 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1567 for (int i = 0; i < frames.length; i++)
1570 if (frames[i] == null)
1574 if (frames[i] instanceof AlignFrame)
1576 target = ((AlignFrame) frames[i]).getCurrentView();
1578 else if (frames[i] instanceof TreePanel)
1580 target = ((TreePanel) frames[i]).getViewPort();
1582 else if (frames[i] instanceof PCAPanel)
1584 target = ((PCAPanel) frames[i]).av;
1586 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1588 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1591 if (source == target)
1597 frames[i].setClosed(true);
1601 frames[i].setIcon(minimize);
1604 frames[i].toFront();
1608 } catch (java.beans.PropertyVetoException ex)
1623 protected void preferences_actionPerformed(ActionEvent e)
1635 public void saveState_actionPerformed(ActionEvent e)
1637 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1640 chooser.setFileView(new JalviewFileView());
1641 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1643 int value = chooser.showSaveDialog(this);
1645 if (value == JalviewFileChooser.APPROVE_OPTION)
1647 final Desktop me = this;
1648 final java.io.File choice = chooser.getSelectedFile();
1649 setProjectFile(choice);
1651 new Thread(new Runnable()
1656 // TODO: refactor to Jalview desktop session controller action.
1657 setProgressBar(MessageManager.formatMessage(
1658 "label.saving_jalview_project", new Object[]
1659 { choice.getName() }), choice.hashCode());
1660 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1661 choice.getParent());
1662 // TODO catch and handle errors for savestate
1663 // TODO prevent user from messing with the Desktop whilst we're saving
1666 new Jalview2XML().saveState(choice);
1667 } catch (OutOfMemoryError oom)
1670 "Whilst saving current state to " + choice.getName(),
1672 } catch (Exception ex)
1675 "Problems whilst trying to save to " + choice.getName(),
1677 JvOptionPane.showMessageDialog(me,
1678 MessageManager.formatMessage(
1679 "label.error_whilst_saving_current_state_to",
1681 { choice.getName() }),
1682 MessageManager.getString("label.couldnt_save_project"),
1683 JvOptionPane.WARNING_MESSAGE);
1685 setProgressBar(null, choice.hashCode());
1691 private void setProjectFile(File choice)
1693 this.projectFile = choice;
1696 public File getProjectFile()
1698 return this.projectFile;
1708 public void loadState_actionPerformed(ActionEvent e)
1710 JalviewFileChooser chooser = new JalviewFileChooser(
1711 Cache.getProperty("LAST_DIRECTORY"), new String[]
1714 { "Jalview Project", "Jalview Project (old)" },
1716 chooser.setFileView(new JalviewFileView());
1717 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1719 int value = chooser.showOpenDialog(this);
1721 if (value == JalviewFileChooser.APPROVE_OPTION)
1723 final File selectedFile = chooser.getSelectedFile();
1724 setProjectFile(selectedFile);
1725 final String choice = selectedFile.getAbsolutePath();
1726 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1727 new Thread(new Runnable()
1732 setProgressBar(MessageManager.formatMessage(
1733 "label.loading_jalview_project", new Object[]
1734 { choice }), choice.hashCode());
1737 new Jalview2XML().loadJalviewAlign(choice);
1738 } catch (OutOfMemoryError oom)
1740 new OOMWarning("Whilst loading project from " + choice, oom);
1741 } catch (Exception ex)
1744 "Problems whilst loading project from " + choice, ex);
1745 JvOptionPane.showMessageDialog(Desktop.desktop,
1746 MessageManager.formatMessage(
1747 "label.error_whilst_loading_project_from",
1750 MessageManager.getString("label.couldnt_load_project"),
1751 JvOptionPane.WARNING_MESSAGE);
1753 setProgressBar(null, choice.hashCode());
1760 public void inputSequence_actionPerformed(ActionEvent e)
1762 new SequenceFetcher(this);
1765 JPanel progressPanel;
1767 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1769 public void startLoading(final String fileName)
1771 if (fileLoadingCount == 0)
1773 fileLoadingPanels.add(addProgressPanel(MessageManager
1774 .formatMessage("label.loading_file", new Object[]
1780 private JPanel addProgressPanel(String string)
1782 if (progressPanel == null)
1784 progressPanel = new JPanel(new GridLayout(1, 1));
1785 totalProgressCount = 0;
1786 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1788 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1789 JProgressBar progressBar = new JProgressBar();
1790 progressBar.setIndeterminate(true);
1792 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1794 thisprogress.add(progressBar, BorderLayout.CENTER);
1795 progressPanel.add(thisprogress);
1796 ((GridLayout) progressPanel.getLayout()).setRows(
1797 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1798 ++totalProgressCount;
1799 instance.validate();
1800 return thisprogress;
1803 int totalProgressCount = 0;
1805 private void removeProgressPanel(JPanel progbar)
1807 if (progressPanel != null)
1809 synchronized (progressPanel)
1811 progressPanel.remove(progbar);
1812 GridLayout gl = (GridLayout) progressPanel.getLayout();
1813 gl.setRows(gl.getRows() - 1);
1814 if (--totalProgressCount < 1)
1816 this.getContentPane().remove(progressPanel);
1817 progressPanel = null;
1824 public void stopLoading()
1827 if (fileLoadingCount < 1)
1829 while (fileLoadingPanels.size() > 0)
1831 removeProgressPanel(fileLoadingPanels.remove(0));
1833 fileLoadingPanels.clear();
1834 fileLoadingCount = 0;
1839 public static int getViewCount(String alignmentId)
1841 AlignmentViewport[] aps = getViewports(alignmentId);
1842 return (aps == null) ? 0 : aps.length;
1847 * @param alignmentId
1848 * - if null, all sets are returned
1849 * @return all AlignmentPanels concerning the alignmentId sequence set
1851 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1853 if (Desktop.desktop == null)
1855 // no frames created and in headless mode
1856 // TODO: verify that frames are recoverable when in headless mode
1859 List<AlignmentPanel> aps = new ArrayList<>();
1860 AlignFrame[] frames = getAlignFrames();
1865 for (AlignFrame af : frames)
1867 for (AlignmentPanel ap : af.alignPanels)
1869 if (alignmentId == null
1870 || alignmentId.equals(ap.av.getSequenceSetId()))
1876 if (aps.size() == 0)
1880 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1885 * get all the viewports on an alignment.
1887 * @param sequenceSetId
1888 * unique alignment id (may be null - all viewports returned in that
1890 * @return all viewports on the alignment bound to sequenceSetId
1892 public static AlignmentViewport[] getViewports(String sequenceSetId)
1894 List<AlignmentViewport> viewp = new ArrayList<>();
1895 if (desktop != null)
1897 AlignFrame[] frames = Desktop.getAlignFrames();
1899 for (AlignFrame afr : frames)
1901 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1902 .equals(sequenceSetId))
1904 if (afr.alignPanels != null)
1906 for (AlignmentPanel ap : afr.alignPanels)
1908 if (sequenceSetId == null
1909 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1917 viewp.add(afr.getViewport());
1921 if (viewp.size() > 0)
1923 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1930 * Explode the views in the given frame into separate AlignFrame
1934 public static void explodeViews(AlignFrame af)
1936 int size = af.alignPanels.size();
1942 for (int i = 0; i < size; i++)
1944 AlignmentPanel ap = af.alignPanels.get(i);
1945 AlignFrame newaf = new AlignFrame(ap);
1948 * Restore the view's last exploded frame geometry if known. Multiple
1949 * views from one exploded frame share and restore the same (frame)
1950 * position and size.
1952 Rectangle geometry = ap.av.getExplodedGeometry();
1953 if (geometry != null)
1955 newaf.setBounds(geometry);
1958 ap.av.setGatherViewsHere(false);
1960 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1961 AlignFrame.DEFAULT_HEIGHT);
1964 af.alignPanels.clear();
1965 af.closeMenuItem_actionPerformed(true);
1970 * Gather expanded views (separate AlignFrame's) with the same sequence set
1971 * identifier back in to this frame as additional views, and close the
1972 * expanded views. Note the expanded frames may themselves have multiple
1973 * views. We take the lot.
1977 public void gatherViews(AlignFrame source)
1979 source.viewport.setGatherViewsHere(true);
1980 source.viewport.setExplodedGeometry(source.getBounds());
1981 JInternalFrame[] frames = desktop.getAllFrames();
1982 String viewId = source.viewport.getSequenceSetId();
1984 for (int t = 0; t < frames.length; t++)
1986 if (frames[t] instanceof AlignFrame && frames[t] != source)
1988 AlignFrame af = (AlignFrame) frames[t];
1989 boolean gatherThis = false;
1990 for (int a = 0; a < af.alignPanels.size(); a++)
1992 AlignmentPanel ap = af.alignPanels.get(a);
1993 if (viewId.equals(ap.av.getSequenceSetId()))
1996 ap.av.setGatherViewsHere(false);
1997 ap.av.setExplodedGeometry(af.getBounds());
1998 source.addAlignmentPanel(ap, false);
2004 af.alignPanels.clear();
2005 af.closeMenuItem_actionPerformed(true);
2012 jalview.gui.VamsasApplication v_client = null;
2015 public void vamsasImport_actionPerformed(ActionEvent e)
2017 if (v_client == null)
2019 // Load and try to start a session.
2020 JalviewFileChooser chooser = new JalviewFileChooser(
2021 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2023 chooser.setFileView(new JalviewFileView());
2024 chooser.setDialogTitle(
2025 MessageManager.getString("label.open_saved_vamsas_session"));
2026 chooser.setToolTipText(MessageManager.getString(
2027 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2029 int value = chooser.showOpenDialog(this);
2031 if (value == JalviewFileChooser.APPROVE_OPTION)
2033 String fle = chooser.getSelectedFile().toString();
2034 if (!vamsasImport(chooser.getSelectedFile()))
2036 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2037 MessageManager.formatMessage(
2038 "label.couldnt_import_as_vamsas_session",
2042 .getString("label.vamsas_document_import_failed"),
2043 JvOptionPane.ERROR_MESSAGE);
2049 jalview.bin.Cache.log.error(
2050 "Implementation error - load session from a running session is not supported.");
2055 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2058 * @return true if import was a success and a session was started.
2060 public boolean vamsasImport(URL url)
2062 // TODO: create progress bar
2063 if (v_client != null)
2066 jalview.bin.Cache.log.error(
2067 "Implementation error - load session from a running session is not supported.");
2073 // copy the URL content to a temporary local file
2074 // TODO: be a bit cleverer here with nio (?!)
2075 File file = File.createTempFile("vdocfromurl", ".vdj");
2076 FileOutputStream fos = new FileOutputStream(file);
2077 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2078 byte[] buffer = new byte[2048];
2080 while ((ln = bis.read(buffer)) > -1)
2082 fos.write(buffer, 0, ln);
2086 v_client = new jalview.gui.VamsasApplication(this, file,
2087 url.toExternalForm());
2088 } catch (Exception ex)
2090 jalview.bin.Cache.log.error(
2091 "Failed to create new vamsas session from contents of URL "
2096 setupVamsasConnectedGui();
2097 v_client.initial_update(); // TODO: thread ?
2098 return v_client.inSession();
2102 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2105 * @return true if import was a success and a session was started.
2107 public boolean vamsasImport(File file)
2109 if (v_client != null)
2112 jalview.bin.Cache.log.error(
2113 "Implementation error - load session from a running session is not supported.");
2117 setProgressBar(MessageManager.formatMessage(
2118 "status.importing_vamsas_session_from", new Object[]
2119 { file.getName() }), file.hashCode());
2122 v_client = new jalview.gui.VamsasApplication(this, file, null);
2123 } catch (Exception ex)
2125 setProgressBar(MessageManager.formatMessage(
2126 "status.importing_vamsas_session_from", new Object[]
2127 { file.getName() }), file.hashCode());
2128 jalview.bin.Cache.log.error(
2129 "New vamsas session from existing session file failed:", ex);
2132 setupVamsasConnectedGui();
2133 v_client.initial_update(); // TODO: thread ?
2134 setProgressBar(MessageManager.formatMessage(
2135 "status.importing_vamsas_session_from", new Object[]
2136 { file.getName() }), file.hashCode());
2137 return v_client.inSession();
2140 public boolean joinVamsasSession(String mysesid)
2142 if (v_client != null)
2144 throw new Error(MessageManager
2145 .getString("error.try_join_vamsas_session_another"));
2147 if (mysesid == null)
2150 MessageManager.getString("error.invalid_vamsas_session_id"));
2152 v_client = new VamsasApplication(this, mysesid);
2153 setupVamsasConnectedGui();
2154 v_client.initial_update();
2155 return (v_client.inSession());
2159 public void vamsasStart_actionPerformed(ActionEvent e)
2161 if (v_client == null)
2164 // we just start a default session for moment.
2166 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2167 * getProperty("LAST_DIRECTORY"));
2169 * chooser.setFileView(new JalviewFileView());
2170 * chooser.setDialogTitle("Load Vamsas file");
2171 * chooser.setToolTipText("Import");
2173 * int value = chooser.showOpenDialog(this);
2175 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2176 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2178 v_client = new VamsasApplication(this);
2179 setupVamsasConnectedGui();
2180 v_client.initial_update(); // TODO: thread ?
2184 // store current data in session.
2185 v_client.push_update(); // TODO: thread
2189 protected void setupVamsasConnectedGui()
2191 vamsasStart.setText(MessageManager.getString("label.session_update"));
2192 vamsasSave.setVisible(true);
2193 vamsasStop.setVisible(true);
2194 vamsasImport.setVisible(false); // Document import to existing session is
2195 // not possible for vamsas-client-1.0.
2198 protected void setupVamsasDisconnectedGui()
2200 vamsasSave.setVisible(false);
2201 vamsasStop.setVisible(false);
2202 vamsasImport.setVisible(true);
2204 .setText(MessageManager.getString("label.new_vamsas_session"));
2208 public void vamsasStop_actionPerformed(ActionEvent e)
2210 if (v_client != null)
2212 v_client.end_session();
2214 setupVamsasDisconnectedGui();
2218 protected void buildVamsasStMenu()
2220 if (v_client == null)
2222 String[] sess = null;
2225 sess = VamsasApplication.getSessionList();
2226 } catch (Exception e)
2228 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2234 jalview.bin.Cache.log.debug(
2235 "Got current sessions list: " + sess.length + " entries.");
2236 VamsasStMenu.removeAll();
2237 for (int i = 0; i < sess.length; i++)
2239 JMenuItem sessit = new JMenuItem();
2240 sessit.setText(sess[i]);
2241 sessit.setToolTipText(MessageManager
2242 .formatMessage("label.connect_to_session", new Object[]
2244 final Desktop dsktp = this;
2245 final String mysesid = sess[i];
2246 sessit.addActionListener(new ActionListener()
2250 public void actionPerformed(ActionEvent e)
2252 if (dsktp.v_client == null)
2254 Thread rthr = new Thread(new Runnable()
2260 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2261 dsktp.setupVamsasConnectedGui();
2262 dsktp.v_client.initial_update();
2270 VamsasStMenu.add(sessit);
2272 // don't show an empty menu.
2273 VamsasStMenu.setVisible(sess.length > 0);
2278 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2279 VamsasStMenu.removeAll();
2280 VamsasStMenu.setVisible(false);
2285 // Not interested in the content. Just hide ourselves.
2286 VamsasStMenu.setVisible(false);
2291 public void vamsasSave_actionPerformed(ActionEvent e)
2293 if (v_client != null)
2295 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2296 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2299 chooser.setFileView(new JalviewFileView());
2300 chooser.setDialogTitle(MessageManager
2301 .getString("label.save_vamsas_document_archive"));
2303 int value = chooser.showSaveDialog(this);
2305 if (value == JalviewFileChooser.APPROVE_OPTION)
2307 java.io.File choice = chooser.getSelectedFile();
2308 JPanel progpanel = addProgressPanel(MessageManager
2309 .formatMessage("label.saving_vamsas_doc", new Object[]
2310 { choice.getName() }));
2311 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2312 String warnmsg = null;
2313 String warnttl = null;
2316 v_client.vclient.storeDocument(choice);
2319 warnttl = "Serious Problem saving Vamsas Document";
2320 warnmsg = ex.toString();
2321 jalview.bin.Cache.log
2322 .error("Error Whilst saving document to " + choice, ex);
2324 } catch (Exception ex)
2326 warnttl = "Problem saving Vamsas Document.";
2327 warnmsg = ex.toString();
2328 jalview.bin.Cache.log.warn(
2329 "Exception Whilst saving document to " + choice, ex);
2332 removeProgressPanel(progpanel);
2333 if (warnmsg != null)
2335 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2337 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2343 JPanel vamUpdate = null;
2346 * hide vamsas user gui bits when a vamsas document event is being handled.
2349 * true to hide gui, false to reveal gui
2351 public void setVamsasUpdate(boolean b)
2353 Cache.log.debug("Setting gui for Vamsas update "
2354 + (b ? "in progress" : "finished"));
2356 if (vamUpdate != null)
2358 this.removeProgressPanel(vamUpdate);
2362 vamUpdate = this.addProgressPanel(
2363 MessageManager.getString("label.updating_vamsas_session"));
2365 vamsasStart.setVisible(!b);
2366 vamsasStop.setVisible(!b);
2367 vamsasSave.setVisible(!b);
2370 public JInternalFrame[] getAllFrames()
2372 return desktop.getAllFrames();
2376 * Checks the given url to see if it gives a response indicating that the user
2377 * should be informed of a new questionnaire.
2381 public void checkForQuestionnaire(String url)
2383 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2384 // javax.swing.SwingUtilities.invokeLater(jvq);
2385 new Thread(jvq).start();
2388 public void checkURLLinks()
2390 // Thread off the URL link checker
2391 addDialogThread(new Runnable()
2396 if (/** @j2sNative false && */ // BH 2018
2397 Cache.getDefault("CHECKURLLINKS", true))
2399 // check what the actual links are - if it's just the default don't
2400 // bother with the warning
2401 List<String> links = Preferences.sequenceUrlLinks
2404 // only need to check links if there is one with a
2405 // SEQUENCE_ID which is not the default EMBL_EBI link
2406 ListIterator<String> li = links.listIterator();
2407 boolean check = false;
2408 List<JLabel> urls = new ArrayList<>();
2409 while (li.hasNext())
2411 String link = li.next();
2412 if (link.contains(SEQUENCE_ID)
2413 && !UrlConstants.isDefaultString(link))
2416 int barPos = link.indexOf("|");
2417 String urlMsg = barPos == -1 ? link
2418 : link.substring(0, barPos) + ": "
2419 + link.substring(barPos + 1);
2420 urls.add(new JLabel(urlMsg));
2428 // ask user to check in case URL links use old style tokens
2429 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2430 JPanel msgPanel = new JPanel();
2431 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2432 msgPanel.add(Box.createVerticalGlue());
2433 JLabel msg = new JLabel(MessageManager
2434 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2435 JLabel msg2 = new JLabel(MessageManager
2436 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2438 for (JLabel url : urls)
2444 final JCheckBox jcb = new JCheckBox(
2445 MessageManager.getString("label.do_not_display_again"));
2446 jcb.addActionListener(new ActionListener()
2449 public void actionPerformed(ActionEvent e)
2451 // update Cache settings for "don't show this again"
2452 boolean showWarningAgain = !jcb.isSelected();
2453 Cache.setProperty("CHECKURLLINKS",
2454 Boolean.valueOf(showWarningAgain).toString());
2459 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2461 .getString("label.SEQUENCE_ID_no_longer_used"),
2462 JvOptionPane.WARNING_MESSAGE);
2469 * Proxy class for JDesktopPane which optionally displays the current memory
2470 * usage and highlights the desktop area with a red bar if free memory runs
2475 public class MyDesktopPane extends JDesktopPane implements Runnable
2478 private static final float ONE_MB = 1048576f;
2480 boolean showMemoryUsage = false;
2484 java.text.NumberFormat df;
2486 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2489 public MyDesktopPane(boolean showMemoryUsage)
2491 showMemoryUsage(showMemoryUsage);
2494 public void showMemoryUsage(boolean showMemory)
2496 this.showMemoryUsage = showMemory;
2499 Thread worker = new Thread(this);
2505 public boolean isShowMemoryUsage()
2507 return showMemoryUsage;
2513 df = java.text.NumberFormat.getNumberInstance();
2514 df.setMaximumFractionDigits(2);
2515 runtime = Runtime.getRuntime();
2517 while (showMemoryUsage)
2521 maxMemory = runtime.maxMemory() / ONE_MB;
2522 allocatedMemory = runtime.totalMemory() / ONE_MB;
2523 freeMemory = runtime.freeMemory() / ONE_MB;
2524 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2526 percentUsage = (totalFreeMemory / maxMemory) * 100;
2528 // if (percentUsage < 20)
2530 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2532 // instance.set.setBorder(border1);
2535 // sleep after showing usage
2537 } catch (Exception ex)
2539 ex.printStackTrace();
2545 public void paintComponent(Graphics g)
2547 if (showMemoryUsage && g != null && df != null)
2549 if (percentUsage < 20)
2551 g.setColor(Color.red);
2553 FontMetrics fm = g.getFontMetrics();
2556 g.drawString(MessageManager.formatMessage("label.memory_stats",
2558 { df.format(totalFreeMemory), df.format(maxMemory),
2559 df.format(percentUsage) }),
2560 10, getHeight() - fm.getHeight());
2568 * Accessor method to quickly get all the AlignmentFrames loaded.
2570 * @return an array of AlignFrame, or null if none found
2572 public static AlignFrame[] getAlignFrames()
2574 if (Jalview.isHeadlessMode())
2576 // Desktop.desktop is null in headless mode
2577 return new AlignFrame[] { Jalview.currentAlignFrame };
2580 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2586 List<AlignFrame> avp = new ArrayList<>();
2588 for (int i = frames.length - 1; i > -1; i--)
2590 if (frames[i] instanceof AlignFrame)
2592 avp.add((AlignFrame) frames[i]);
2594 else if (frames[i] instanceof SplitFrame)
2597 * Also check for a split frame containing an AlignFrame
2599 GSplitFrame sf = (GSplitFrame) frames[i];
2600 if (sf.getTopFrame() instanceof AlignFrame)
2602 avp.add((AlignFrame) sf.getTopFrame());
2604 if (sf.getBottomFrame() instanceof AlignFrame)
2606 avp.add((AlignFrame) sf.getBottomFrame());
2610 if (avp.size() == 0)
2614 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2619 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2623 public GStructureViewer[] getJmols()
2625 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2631 List<GStructureViewer> avp = new ArrayList<>();
2633 for (int i = frames.length - 1; i > -1; i--)
2635 if (frames[i] instanceof AppJmol)
2637 GStructureViewer af = (GStructureViewer) frames[i];
2641 if (avp.size() == 0)
2645 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2650 * Add Groovy Support to Jalview
2653 public void groovyShell_actionPerformed()
2657 openGroovyConsole();
2658 } catch (Exception ex)
2660 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2661 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2663 MessageManager.getString("label.couldnt_create_groovy_shell"),
2664 MessageManager.getString("label.groovy_support_failed"),
2665 JvOptionPane.ERROR_MESSAGE);
2670 * Open the Groovy console
2672 void openGroovyConsole()
2674 if (groovyConsole == null)
2676 groovyConsole = new groovy.ui.Console();
2677 groovyConsole.setVariable("Jalview", this);
2678 groovyConsole.run();
2681 * We allow only one console at a time, so that AlignFrame menu option
2682 * 'Calculate | Run Groovy script' is unambiguous.
2683 * Disable 'Groovy Console', and enable 'Run script', when the console is
2684 * opened, and the reverse when it is closed
2686 Window window = (Window) groovyConsole.getFrame();
2687 window.addWindowListener(new WindowAdapter()
2690 public void windowClosed(WindowEvent e)
2693 * rebind CMD-Q from Groovy Console to Jalview Quit
2696 enableExecuteGroovy(false);
2702 * show Groovy console window (after close and reopen)
2704 ((Window) groovyConsole.getFrame()).setVisible(true);
2707 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2708 * and disable opening a second console
2710 enableExecuteGroovy(true);
2714 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2715 * binding when opened
2717 protected void addQuitHandler()
2719 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2720 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2721 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2723 getRootPane().getActionMap().put("Quit", new AbstractAction()
2726 public void actionPerformed(ActionEvent e)
2734 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2737 * true if Groovy console is open
2739 public void enableExecuteGroovy(boolean enabled)
2742 * disable opening a second Groovy console
2743 * (or re-enable when the console is closed)
2745 groovyShell.setEnabled(!enabled);
2747 AlignFrame[] alignFrames = getAlignFrames();
2748 if (alignFrames != null)
2750 for (AlignFrame af : alignFrames)
2752 af.setGroovyEnabled(enabled);
2758 * Progress bars managed by the IProgressIndicator method.
2760 private Hashtable<Long, JPanel> progressBars;
2762 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2767 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2770 public void setProgressBar(String message, long id)
2772 if (progressBars == null)
2774 progressBars = new Hashtable<>();
2775 progressBarHandlers = new Hashtable<>();
2778 if (progressBars.get(new Long(id)) != null)
2780 JPanel panel = progressBars.remove(new Long(id));
2781 if (progressBarHandlers.contains(new Long(id)))
2783 progressBarHandlers.remove(new Long(id));
2785 removeProgressPanel(panel);
2789 progressBars.put(new Long(id), addProgressPanel(message));
2796 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2797 * jalview.gui.IProgressIndicatorHandler)
2800 public void registerHandler(final long id,
2801 final IProgressIndicatorHandler handler)
2803 if (progressBarHandlers == null
2804 || !progressBars.containsKey(new Long(id)))
2806 throw new Error(MessageManager.getString(
2807 "error.call_setprogressbar_before_registering_handler"));
2809 progressBarHandlers.put(new Long(id), handler);
2810 final JPanel progressPanel = progressBars.get(new Long(id));
2811 if (handler.canCancel())
2813 JButton cancel = new JButton(
2814 MessageManager.getString("action.cancel"));
2815 final IProgressIndicator us = this;
2816 cancel.addActionListener(new ActionListener()
2820 public void actionPerformed(ActionEvent e)
2822 handler.cancelActivity(id);
2823 us.setProgressBar(MessageManager
2824 .formatMessage("label.cancelled_params", new Object[]
2825 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2829 progressPanel.add(cancel, BorderLayout.EAST);
2835 * @return true if any progress bars are still active
2838 public boolean operationInProgress()
2840 if (progressBars != null && progressBars.size() > 0)
2848 * This will return the first AlignFrame holding the given viewport instance.
2849 * It will break if there are more than one AlignFrames viewing a particular
2853 * @return alignFrame for viewport
2855 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2857 if (desktop != null)
2859 AlignmentPanel[] aps = getAlignmentPanels(
2860 viewport.getSequenceSetId());
2861 for (int panel = 0; aps != null && panel < aps.length; panel++)
2863 if (aps[panel] != null && aps[panel].av == viewport)
2865 return aps[panel].alignFrame;
2872 public VamsasApplication getVamsasApplication()
2879 * flag set if jalview GUI is being operated programmatically
2881 private boolean inBatchMode = false;
2884 * check if jalview GUI is being operated programmatically
2886 * @return inBatchMode
2888 public boolean isInBatchMode()
2894 * set flag if jalview GUI is being operated programmatically
2896 * @param inBatchMode
2898 public void setInBatchMode(boolean inBatchMode)
2900 this.inBatchMode = inBatchMode;
2903 public void startServiceDiscovery()
2905 startServiceDiscovery(false);
2908 public void startServiceDiscovery(boolean blocking)
2910 boolean alive = true;
2911 Thread t0 = null, t1 = null, t2 = null;
2912 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2915 // todo: changesupport handlers need to be transferred
2916 if (discoverer == null)
2918 discoverer = new jalview.ws.jws1.Discoverer();
2919 // register PCS handler for desktop.
2920 discoverer.addPropertyChangeListener(changeSupport);
2922 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2923 // until we phase out completely
2924 (t0 = new Thread(discoverer)).start();
2927 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2929 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2930 .startDiscoverer(changeSupport);
2934 // TODO: do rest service discovery
2943 } catch (Exception e)
2946 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2947 || (t3 != null && t3.isAlive())
2948 || (t0 != null && t0.isAlive());
2954 * called to check if the service discovery process completed successfully.
2958 protected void JalviewServicesChanged(PropertyChangeEvent evt)
2960 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
2962 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2963 .getErrorMessages();
2966 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
2968 if (serviceChangedDialog == null)
2970 // only run if we aren't already displaying one of these.
2971 addDialogThread(serviceChangedDialog = new Runnable()
2978 * JalviewDialog jd =new JalviewDialog() {
2980 * @Override protected void cancelPressed() { // TODO
2981 * Auto-generated method stub
2983 * }@Override protected void okPressed() { // TODO
2984 * Auto-generated method stub
2986 * }@Override protected void raiseClosed() { // TODO
2987 * Auto-generated method stub
2989 * } }; jd.initDialogFrame(new
2990 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
2991 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
2992 * + " or mis-configured HTTP proxy settings.<br/>" +
2993 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
2995 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
2996 * ), true, true, "Web Service Configuration Problem", 450,
2999 * jd.waitForInput();
3001 JvOptionPane.showConfirmDialog(Desktop.desktop,
3002 new JLabel("<html><table width=\"450\"><tr><td>"
3003 + ermsg + "</td></tr></table>"
3004 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3005 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3006 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3007 + " Tools->Preferences dialog box to change them.</p></html>"),
3008 "Web Service Configuration Problem",
3009 JvOptionPane.DEFAULT_OPTION,
3010 JvOptionPane.ERROR_MESSAGE);
3011 serviceChangedDialog = null;
3020 "Errors reported by JABA discovery service. Check web services preferences.\n"
3027 private Runnable serviceChangedDialog = null;
3030 * start a thread to open a URL in the configured browser. Pops up a warning
3031 * dialog to the user if there is an exception when calling out to the browser
3036 public static void showUrl(final String url)
3038 showUrl(url, Desktop.instance);
3042 * Like showUrl but allows progress handler to be specified
3046 * (null) or object implementing IProgressIndicator
3048 public static void showUrl(final String url,
3049 final IProgressIndicator progress)
3051 new Thread(new Runnable()
3058 if (progress != null)
3060 progress.setProgressBar(MessageManager
3061 .formatMessage("status.opening_params", new Object[]
3062 { url }), this.hashCode());
3064 jalview.util.BrowserLauncher.openURL(url);
3065 } catch (Exception ex)
3067 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3069 .getString("label.web_browser_not_found_unix"),
3070 MessageManager.getString("label.web_browser_not_found"),
3071 JvOptionPane.WARNING_MESSAGE);
3073 ex.printStackTrace();
3075 if (progress != null)
3077 progress.setProgressBar(null, this.hashCode());
3083 public static WsParamSetManager wsparamManager = null;
3085 public static ParamManager getUserParameterStore()
3087 if (wsparamManager == null)
3089 wsparamManager = new WsParamSetManager();
3091 return wsparamManager;
3095 * static hyperlink handler proxy method for use by Jalview's internal windows
3099 public static void hyperlinkUpdate(HyperlinkEvent e)
3101 if (e.getEventType() == EventType.ACTIVATED)
3106 url = e.getURL().toString();
3107 Desktop.showUrl(url);
3108 } catch (Exception x)
3112 if (Cache.log != null)
3114 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3119 "Couldn't handle string " + url + " as a URL.");
3122 // ignore any exceptions due to dud links.
3129 * single thread that handles display of dialogs to user.
3131 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3134 * flag indicating if dialogExecutor should try to acquire a permit
3136 private volatile boolean dialogPause = true;
3141 private java.util.concurrent.Semaphore block = new Semaphore(0);
3143 private static groovy.ui.Console groovyConsole;
3146 * add another dialog thread to the queue
3150 public void addDialogThread(final Runnable prompter)
3152 dialogExecutor.submit(new Runnable()
3162 } catch (InterruptedException x)
3167 if (instance == null)
3173 SwingUtilities.invokeAndWait(prompter);
3174 } catch (Exception q)
3176 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3182 public void startDialogQueue()
3184 // set the flag so we don't pause waiting for another permit and semaphore
3185 // the current task to begin
3186 dialogPause = false;
3191 protected void snapShotWindow_actionPerformed(ActionEvent e)
3195 ImageMaker im = new jalview.util.ImageMaker(
3196 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3197 getHeight(), of = new File("Jalview_snapshot"
3198 + System.currentTimeMillis() + ".eps"),
3199 "View of desktop", null, 0, false);
3202 paintAll(im.getGraphics());
3204 } catch (Exception q)
3206 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3210 Cache.log.info("Successfully written snapshot to file "
3211 + of.getAbsolutePath());
3215 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3216 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3217 * and location last time the view was expanded (if any). However it does not
3218 * remember the split pane divider location - this is set to match the
3219 * 'exploding' frame.
3223 public void explodeViews(SplitFrame sf)
3225 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3226 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3227 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3229 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3231 int viewCount = topPanels.size();
3238 * Processing in reverse order works, forwards order leaves the first panels
3239 * not visible. I don't know why!
3241 for (int i = viewCount - 1; i >= 0; i--)
3244 * Make new top and bottom frames. These take over the respective
3245 * AlignmentPanel objects, including their AlignmentViewports, so the
3246 * cdna/protein relationships between the viewports is carried over to the
3249 * explodedGeometry holds the (x, y) position of the previously exploded
3250 * SplitFrame, and the (width, height) of the AlignFrame component
3252 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3253 AlignFrame newTopFrame = new AlignFrame(topPanel);
3254 newTopFrame.setSize(oldTopFrame.getSize());
3255 newTopFrame.setVisible(true);
3256 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3257 .getExplodedGeometry();
3258 if (geometry != null)
3260 newTopFrame.setSize(geometry.getSize());
3263 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3264 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3265 newBottomFrame.setSize(oldBottomFrame.getSize());
3266 newBottomFrame.setVisible(true);
3267 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3268 .getExplodedGeometry();
3269 if (geometry != null)
3271 newBottomFrame.setSize(geometry.getSize());
3274 topPanel.av.setGatherViewsHere(false);
3275 bottomPanel.av.setGatherViewsHere(false);
3276 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3278 if (geometry != null)
3280 splitFrame.setLocation(geometry.getLocation());
3282 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3286 * Clear references to the panels (now relocated in the new SplitFrames)
3287 * before closing the old SplitFrame.
3290 bottomPanels.clear();
3295 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3296 * back into the given SplitFrame as additional views. Note that the gathered
3297 * frames may themselves have multiple views.
3301 public void gatherViews(GSplitFrame source)
3304 * special handling of explodedGeometry for a view within a SplitFrame: - it
3305 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3306 * height) of the AlignFrame component
3308 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3309 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3310 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3311 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3312 myBottomFrame.viewport
3313 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3314 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3315 myTopFrame.viewport.setGatherViewsHere(true);
3316 myBottomFrame.viewport.setGatherViewsHere(true);
3317 String topViewId = myTopFrame.viewport.getSequenceSetId();
3318 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3320 JInternalFrame[] frames = desktop.getAllFrames();
3321 for (JInternalFrame frame : frames)
3323 if (frame instanceof SplitFrame && frame != source)
3325 SplitFrame sf = (SplitFrame) frame;
3326 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3327 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3328 boolean gatherThis = false;
3329 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3331 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3332 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3333 if (topViewId.equals(topPanel.av.getSequenceSetId())
3334 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3337 topPanel.av.setGatherViewsHere(false);
3338 bottomPanel.av.setGatherViewsHere(false);
3339 topPanel.av.setExplodedGeometry(
3340 new Rectangle(sf.getLocation(), topFrame.getSize()));
3341 bottomPanel.av.setExplodedGeometry(
3342 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3343 myTopFrame.addAlignmentPanel(topPanel, false);
3344 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3350 topFrame.getAlignPanels().clear();
3351 bottomFrame.getAlignPanels().clear();
3358 * The dust settles...give focus to the tab we did this from.
3360 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3363 public static groovy.ui.Console getGroovyConsole()
3365 return groovyConsole;
3369 * handles the payload of a drag and drop event.
3371 * TODO refactor to desktop utilities class
3374 * - Data source strings extracted from the drop event
3376 * - protocol for each data source extracted from the drop event
3380 * - the payload from the drop event
3383 public static void transferFromDropTarget(List<String> files,
3384 List<DataSourceType> protocols, DropTargetDropEvent evt,
3385 Transferable t) throws Exception
3388 DataFlavor uriListFlavor = new DataFlavor(
3389 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3392 urlFlavour = new DataFlavor(
3393 "application/x-java-url; class=java.net.URL");
3394 } catch (ClassNotFoundException cfe)
3396 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3399 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3404 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3405 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3406 // means url may be null.
3409 protocols.add(DataSourceType.URL);
3410 files.add(url.toString());
3411 Cache.log.debug("Drop handled as URL dataflavor "
3412 + files.get(files.size() - 1));
3417 if (Platform.isAMac())
3420 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3424 } catch (Throwable ex)
3426 Cache.log.debug("URL drop handler failed.", ex);
3429 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3431 // Works on Windows and MacOSX
3432 Cache.log.debug("Drop handled as javaFileListFlavor");
3433 for (Object file : (List) t
3434 .getTransferData(DataFlavor.javaFileListFlavor))
3436 files.add(((File) file).toString());
3437 protocols.add(DataSourceType.FILE);
3442 // Unix like behaviour
3443 boolean added = false;
3445 if (t.isDataFlavorSupported(uriListFlavor))
3447 Cache.log.debug("Drop handled as uriListFlavor");
3448 // This is used by Unix drag system
3449 data = (String) t.getTransferData(uriListFlavor);
3453 // fallback to text: workaround - on OSX where there's a JVM bug
3454 Cache.log.debug("standard URIListFlavor failed. Trying text");
3455 // try text fallback
3456 DataFlavor textDf = new DataFlavor(
3457 "text/plain;class=java.lang.String");
3458 if (t.isDataFlavorSupported(textDf))
3460 data = (String) t.getTransferData(textDf);
3463 Cache.log.debug("Plain text drop content returned "
3464 + (data == null ? "Null - failed" : data));
3469 while (protocols.size() < files.size())
3471 Cache.log.debug("Adding missing FILE protocol for "
3472 + files.get(protocols.size()));
3473 protocols.add(DataSourceType.FILE);
3475 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3476 data, "\r\n"); st.hasMoreTokens();)
3479 String s = st.nextToken();
3480 if (s.startsWith("#"))
3482 // the line is a comment (as per the RFC 2483)
3485 java.net.URI uri = new java.net.URI(s);
3486 if (uri.getScheme().toLowerCase().startsWith("http"))
3488 protocols.add(DataSourceType.URL);
3489 files.add(uri.toString());
3493 // otherwise preserve old behaviour: catch all for file objects
3494 java.io.File file = new java.io.File(uri);
3495 protocols.add(DataSourceType.FILE);
3496 files.add(file.toString());
3501 if (Cache.log.isDebugEnabled())
3503 if (data == null || !added)
3506 if (t.getTransferDataFlavors() != null
3507 && t.getTransferDataFlavors().length > 0)
3510 "Couldn't resolve drop data. Here are the supported flavors:");
3511 for (DataFlavor fl : t.getTransferDataFlavors())
3514 "Supported transfer dataflavor: " + fl.toString());
3515 Object df = t.getTransferData(fl);
3518 Cache.log.debug("Retrieves: " + df);
3522 Cache.log.debug("Retrieved nothing");
3528 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3534 if (Platform.isWindows())
3537 Cache.log.debug("Scanning dropped content for Windows Link Files");
3539 // resolve any .lnk files in the file drop
3540 for (int f = 0; f < files.size(); f++)
3542 String source = files.get(f).toLowerCase();
3543 if (protocols.get(f).equals(DataSourceType.FILE)
3544 && (source.endsWith(".lnk") || source.endsWith(".url")
3545 || source.endsWith(".site")))
3548 File lf = new File(files.get(f));
3549 // process link file to get a URL
3550 Cache.log.debug("Found potential link file: " + lf);
3551 WindowsShortcut wscfile = new WindowsShortcut(lf);
3552 String fullname = wscfile.getRealFilename();
3553 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3554 files.set(f, fullname);
3555 Cache.log.debug("Parsed real filename " + fullname
3556 + " to extract protocol: " + protocols.get(f));
3558 catch (Exception ex)
3560 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3568 * Sets the Preferences property for experimental features to True or False
3569 * depending on the state of the controlling menu item
3572 protected void showExperimental_actionPerformed(boolean selected)
3574 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3578 * Answers a (possibly empty) list of any structure viewer frames (currently
3579 * for either Jmol or Chimera) which are currently open. This may optionally
3580 * be restricted to viewers of a specified class, or viewers linked to a
3581 * specified alignment panel.
3584 * if not null, only return viewers linked to this panel
3585 * @param structureViewerClass
3586 * if not null, only return viewers of this class
3589 public List<StructureViewerBase> getStructureViewers(
3590 AlignmentPanel apanel,
3591 Class<? extends StructureViewerBase> structureViewerClass)
3593 List<StructureViewerBase> result = new ArrayList<>();
3594 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3596 for (JInternalFrame frame : frames)
3598 if (frame instanceof StructureViewerBase)
3600 if (structureViewerClass == null
3601 || structureViewerClass.isInstance(frame))
3604 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3606 result.add((StructureViewerBase) frame);