2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.AlignViewportI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.bin.Cache;
26 import jalview.bin.Jalview;
27 import jalview.io.DataSourceType;
28 import jalview.io.FileFormat;
29 import jalview.io.FileFormatException;
30 import jalview.io.FileFormatI;
31 import jalview.io.FileFormats;
32 import jalview.io.FileLoader;
33 import jalview.io.FormatAdapter;
34 import jalview.io.IdentifyFile;
35 import jalview.io.JalviewFileChooser;
36 import jalview.io.JalviewFileView;
37 import jalview.jbgui.GSplitFrame;
38 import jalview.jbgui.GStructureViewer;
39 import jalview.structure.StructureSelectionManager;
40 import jalview.urls.IdOrgSettings;
41 import jalview.util.ImageMaker;
42 import jalview.util.MessageManager;
43 import jalview.util.Platform;
44 import jalview.util.UrlConstants;
45 import jalview.viewmodel.AlignmentViewport;
46 import jalview.ws.params.ParamManager;
47 import jalview.ws.utils.UrlDownloadClient;
49 import java.awt.BorderLayout;
50 import java.awt.Color;
51 import java.awt.Dimension;
52 import java.awt.FontMetrics;
53 import java.awt.Graphics;
54 import java.awt.GridLayout;
55 import java.awt.Point;
56 import java.awt.Rectangle;
57 import java.awt.Toolkit;
58 import java.awt.Window;
59 import java.awt.datatransfer.Clipboard;
60 import java.awt.datatransfer.ClipboardOwner;
61 import java.awt.datatransfer.DataFlavor;
62 import java.awt.datatransfer.Transferable;
63 import java.awt.desktop.AboutEvent;
64 import java.awt.desktop.AboutHandler;
65 import java.awt.desktop.PreferencesEvent;
66 import java.awt.desktop.PreferencesHandler;
67 import java.awt.desktop.QuitEvent;
68 import java.awt.desktop.QuitHandler;
69 import java.awt.desktop.QuitResponse;
70 import java.awt.dnd.DnDConstants;
71 import java.awt.dnd.DropTargetDragEvent;
72 import java.awt.dnd.DropTargetDropEvent;
73 import java.awt.dnd.DropTargetEvent;
74 import java.awt.dnd.DropTargetListener;
75 import java.awt.event.ActionEvent;
76 import java.awt.event.ActionListener;
77 import java.awt.event.InputEvent;
78 import java.awt.event.KeyEvent;
79 import java.awt.event.MouseAdapter;
80 import java.awt.event.MouseEvent;
81 import java.awt.event.WindowAdapter;
82 import java.awt.event.WindowEvent;
83 import java.beans.PropertyChangeEvent;
84 import java.beans.PropertyChangeListener;
85 import java.io.BufferedInputStream;
87 import java.io.FileOutputStream;
88 import java.io.FileWriter;
89 import java.io.IOException;
91 import java.util.ArrayList;
92 import java.util.HashMap;
93 import java.util.Hashtable;
94 import java.util.List;
95 import java.util.ListIterator;
96 import java.util.StringTokenizer;
97 import java.util.Vector;
98 import java.util.concurrent.ExecutorService;
99 import java.util.concurrent.Executors;
100 import java.util.concurrent.Semaphore;
102 import javax.swing.AbstractAction;
103 import javax.swing.Action;
104 import javax.swing.ActionMap;
105 import javax.swing.Box;
106 import javax.swing.BoxLayout;
107 import javax.swing.DefaultDesktopManager;
108 import javax.swing.DesktopManager;
109 import javax.swing.InputMap;
110 import javax.swing.JButton;
111 import javax.swing.JCheckBox;
112 import javax.swing.JComboBox;
113 import javax.swing.JComponent;
114 import javax.swing.JDesktopPane;
115 import javax.swing.JInternalFrame;
116 import javax.swing.JLabel;
117 import javax.swing.JMenuItem;
118 import javax.swing.JOptionPane;
119 import javax.swing.JPanel;
120 import javax.swing.JPopupMenu;
121 import javax.swing.JProgressBar;
122 import javax.swing.KeyStroke;
123 import javax.swing.SwingUtilities;
124 import javax.swing.event.HyperlinkEvent;
125 import javax.swing.event.HyperlinkEvent.EventType;
126 import javax.swing.event.InternalFrameAdapter;
127 import javax.swing.event.InternalFrameEvent;
128 import javax.swing.event.MenuEvent;
129 import javax.swing.event.MenuListener;
131 import org.stackoverflowusers.file.WindowsShortcut;
138 * @version $Revision: 1.155 $
140 public class Desktop extends jalview.jbgui.GDesktop
141 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
142 jalview.api.StructureSelectionManagerProvider
144 private static int DEFAULT_MIN_WIDTH = 300;
146 private static int DEFAULT_MIN_HEIGHT = 250;
148 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
150 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
152 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
154 public static HashMap<String, FileWriter> savingFiles = new HashMap<>();
156 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
159 * news reader - null if it was never started.
161 private BlogReader jvnews = null;
163 private File projectFile;
167 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
169 public void addJalviewPropertyChangeListener(
170 PropertyChangeListener listener)
172 changeSupport.addJalviewPropertyChangeListener(listener);
176 * @param propertyName
178 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
179 * java.beans.PropertyChangeListener)
181 public void addJalviewPropertyChangeListener(String propertyName,
182 PropertyChangeListener listener)
184 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
188 * @param propertyName
190 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
191 * java.beans.PropertyChangeListener)
193 public void removeJalviewPropertyChangeListener(String propertyName,
194 PropertyChangeListener listener)
196 changeSupport.removeJalviewPropertyChangeListener(propertyName,
200 /** Singleton Desktop instance */
201 public static Desktop instance;
203 public static MyDesktopPane desktop;
205 static int openFrameCount = 0;
207 static final int xOffset = 30;
209 static final int yOffset = 30;
211 public static jalview.ws.jws1.Discoverer discoverer;
213 public static Object[] jalviewClipboard;
215 public static boolean internalCopy = false;
217 static int fileLoadingCount = 0;
219 class MyDesktopManager implements DesktopManager
222 private DesktopManager delegate;
224 public MyDesktopManager(DesktopManager delegate)
226 this.delegate = delegate;
230 public void activateFrame(JInternalFrame f)
234 delegate.activateFrame(f);
235 } catch (NullPointerException npe)
237 Point p = getMousePosition();
238 instance.showPasteMenu(p.x, p.y);
243 public void beginDraggingFrame(JComponent f)
245 delegate.beginDraggingFrame(f);
249 public void beginResizingFrame(JComponent f, int direction)
251 delegate.beginResizingFrame(f, direction);
255 public void closeFrame(JInternalFrame f)
257 delegate.closeFrame(f);
261 public void deactivateFrame(JInternalFrame f)
263 delegate.deactivateFrame(f);
267 public void deiconifyFrame(JInternalFrame f)
269 delegate.deiconifyFrame(f);
273 public void dragFrame(JComponent f, int newX, int newY)
279 delegate.dragFrame(f, newX, newY);
283 public void endDraggingFrame(JComponent f)
285 delegate.endDraggingFrame(f);
290 public void endResizingFrame(JComponent f)
292 delegate.endResizingFrame(f);
297 public void iconifyFrame(JInternalFrame f)
299 delegate.iconifyFrame(f);
303 public void maximizeFrame(JInternalFrame f)
305 delegate.maximizeFrame(f);
309 public void minimizeFrame(JInternalFrame f)
311 delegate.minimizeFrame(f);
315 public void openFrame(JInternalFrame f)
317 delegate.openFrame(f);
321 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
328 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
332 public void setBoundsForFrame(JComponent f, int newX, int newY,
333 int newWidth, int newHeight)
335 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
338 // All other methods, simply delegate
343 * Creates a new Desktop object.
348 * A note to implementors. It is ESSENTIAL that any activities that might
349 * block are spawned off as threads rather than waited for during this
353 doVamsasClientCheck();
355 doConfigureStructurePrefs();
356 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
358 if (!Platform.isAMac())
360 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
365 // this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
366 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
368 hdesktop.setAboutHandler(new AboutHandler()
371 public void handleAbout(AboutEvent e)
373 aboutMenuItem_actionPerformed(null);
376 hdesktop.setPreferencesHandler(new PreferencesHandler()
379 public void handlePreferences(PreferencesEvent e)
381 preferences_actionPerformed(null);
384 hdesktop.setQuitHandler(new QuitHandler()
387 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
389 int n = JOptionPane.showConfirmDialog(null,
390 MessageManager.getString("label.quit_jalview"),
391 MessageManager.getString("action.quit"),
392 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
394 if (n == JOptionPane.OK_OPTION)
396 System.out.println("Shortcut Quit confirmed by user");
401 System.out.println("Shortcut Quit cancelled by user");
408 addWindowListener(new WindowAdapter()
412 public void windowClosing(WindowEvent ev)
418 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
421 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
423 desktop = new MyDesktopPane(selmemusage);
424 showMemusage.setSelected(selmemusage);
425 desktop.setBackground(Color.white);
427 getContentPane().setLayout(new BorderLayout());
428 // alternate config - have scrollbars - see notes in JAL-153
429 // JScrollPane sp = new JScrollPane();
430 // sp.getViewport().setView(desktop);
431 // getContentPane().add(sp, BorderLayout.CENTER);
432 getContentPane().add(desktop, BorderLayout.CENTER);
433 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
435 // This line prevents Windows Look&Feel resizing all new windows to maximum
436 // if previous window was maximised
437 desktop.setDesktopManager(new MyDesktopManager(
438 (Platform.isWindows() ? new DefaultDesktopManager()
440 ? new AquaInternalFrameManager(
441 desktop.getDesktopManager())
442 : desktop.getDesktopManager())));
444 Rectangle dims = getLastKnownDimensions("");
451 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
452 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
455 jconsole = new Console(this, showjconsole);
456 // add essential build information
458 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
459 + "\n" + "Jalview Installation: "
460 + jalview.bin.Cache.getDefault("INSTALLATION",
462 + "\n" + "Build Date: "
463 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
464 + "\n" + "Java version: "
465 + System.getProperty("java.version") + "\n"
466 + System.getProperty("os.arch") + " "
467 + System.getProperty("os.name") + " "
468 + System.getProperty("os.version"));
470 showConsole(showjconsole);
472 showNews.setVisible(false);
474 experimentalFeatures.setSelected(showExperimental());
476 getIdentifiersOrgData();
480 this.addWindowListener(new WindowAdapter()
483 public void windowClosing(WindowEvent evt)
490 this.addMouseListener(ma = new MouseAdapter()
493 public void mousePressed(MouseEvent evt)
495 if (evt.isPopupTrigger()) // Mac
497 showPasteMenu(evt.getX(), evt.getY());
502 public void mouseReleased(MouseEvent evt)
504 if (evt.isPopupTrigger()) // Windows
506 showPasteMenu(evt.getX(), evt.getY());
510 desktop.addMouseListener(ma);
512 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
513 // Spawn a thread that shows the splashscreen
514 SwingUtilities.invokeLater(new Runnable()
523 // Thread off a new instance of the file chooser - this reduces the time it
524 // takes to open it later on.
525 new Thread(new Runnable()
530 Cache.log.debug("Filechooser init thread started.");
531 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
532 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
534 Cache.log.debug("Filechooser init thread finished.");
537 // Add the service change listener
538 changeSupport.addJalviewPropertyChangeListener("services",
539 new PropertyChangeListener()
543 public void propertyChange(PropertyChangeEvent evt)
545 Cache.log.debug("Firing service changed event for "
546 + evt.getNewValue());
547 JalviewServicesChanged(evt);
554 * Answers true if user preferences to enable experimental features is True
559 public boolean showExperimental()
561 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
562 Boolean.FALSE.toString());
563 return Boolean.valueOf(experimental).booleanValue();
566 public void doConfigureStructurePrefs()
568 // configure services
569 StructureSelectionManager ssm = StructureSelectionManager
570 .getStructureSelectionManager(this);
571 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
573 ssm.setAddTempFacAnnot(jalview.bin.Cache
574 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
575 ssm.setProcessSecondaryStructure(jalview.bin.Cache
576 .getDefault(Preferences.STRUCT_FROM_PDB, true));
577 ssm.setSecStructServices(
578 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
582 ssm.setAddTempFacAnnot(false);
583 ssm.setProcessSecondaryStructure(false);
584 ssm.setSecStructServices(false);
588 public void checkForNews()
590 final Desktop me = this;
591 // Thread off the news reader, in case there are connection problems.
592 new Thread(new Runnable()
597 Cache.log.debug("Starting news thread.");
599 jvnews = new BlogReader(me);
600 showNews.setVisible(true);
601 Cache.log.debug("Completed news thread.");
606 public void getIdentifiersOrgData()
608 // Thread off the identifiers fetcher
609 new Thread(new Runnable()
614 Cache.log.debug("Downloading data from identifiers.org");
615 UrlDownloadClient client = new UrlDownloadClient();
618 client.download(IdOrgSettings.getUrl(),
619 IdOrgSettings.getDownloadLocation());
620 } catch (IOException e)
622 Cache.log.debug("Exception downloading identifiers.org data"
631 protected void showNews_actionPerformed(ActionEvent e)
633 showNews(showNews.isSelected());
636 void showNews(boolean visible)
639 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
640 showNews.setSelected(visible);
641 if (visible && !jvnews.isVisible())
643 new Thread(new Runnable()
648 long now = System.currentTimeMillis();
649 Desktop.instance.setProgressBar(
650 MessageManager.getString("status.refreshing_news"),
652 jvnews.refreshNews();
653 Desktop.instance.setProgressBar(null, now);
662 * recover the last known dimensions for a jalview window
665 * - empty string is desktop, all other windows have unique prefix
666 * @return null or last known dimensions scaled to current geometry (if last
667 * window geom was known)
669 Rectangle getLastKnownDimensions(String windowName)
671 // TODO: lock aspect ratio for scaling desktop Bug #0058199
672 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
673 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
674 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
675 String width = jalview.bin.Cache
676 .getProperty(windowName + "SCREEN_WIDTH");
677 String height = jalview.bin.Cache
678 .getProperty(windowName + "SCREEN_HEIGHT");
679 if ((x != null) && (y != null) && (width != null) && (height != null))
681 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
682 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
683 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
685 // attempt #1 - try to cope with change in screen geometry - this
686 // version doesn't preserve original jv aspect ratio.
687 // take ratio of current screen size vs original screen size.
688 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
689 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
690 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
691 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
692 // rescale the bounds depending upon the current screen geometry.
693 ix = (int) (ix * sw);
694 iw = (int) (iw * sw);
695 iy = (int) (iy * sh);
696 ih = (int) (ih * sh);
697 while (ix >= screenSize.width)
699 jalview.bin.Cache.log.debug(
700 "Window geometry location recall error: shifting horizontal to within screenbounds.");
701 ix -= screenSize.width;
703 while (iy >= screenSize.height)
705 jalview.bin.Cache.log.debug(
706 "Window geometry location recall error: shifting vertical to within screenbounds.");
707 iy -= screenSize.height;
709 jalview.bin.Cache.log.debug(
710 "Got last known dimensions for " + windowName + ": x:" + ix
711 + " y:" + iy + " width:" + iw + " height:" + ih);
713 // return dimensions for new instance
714 return new Rectangle(ix, iy, iw, ih);
719 private void doVamsasClientCheck()
721 if (jalview.bin.Cache.vamsasJarsPresent())
723 setupVamsasDisconnectedGui();
724 VamsasMenu.setVisible(true);
725 final Desktop us = this;
726 VamsasMenu.addMenuListener(new MenuListener()
728 // this listener remembers when the menu was first selected, and
729 // doesn't rebuild the session list until it has been cleared and
731 boolean refresh = true;
734 public void menuCanceled(MenuEvent e)
740 public void menuDeselected(MenuEvent e)
746 public void menuSelected(MenuEvent e)
750 us.buildVamsasStMenu();
755 vamsasStart.setVisible(true);
759 void showPasteMenu(int x, int y)
761 JPopupMenu popup = new JPopupMenu();
762 JMenuItem item = new JMenuItem(
763 MessageManager.getString("label.paste_new_window"));
764 item.addActionListener(new ActionListener()
767 public void actionPerformed(ActionEvent evt)
774 popup.show(this, x, y);
781 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
782 Transferable contents = c.getContents(this);
784 if (contents != null)
786 String file = (String) contents
787 .getTransferData(DataFlavor.stringFlavor);
789 FileFormatI format = new IdentifyFile().identify(file,
790 DataSourceType.PASTE);
792 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
795 } catch (Exception ex)
798 "Unable to paste alignment from system clipboard:\n" + ex);
803 * Adds and opens the given frame to the desktop
814 public static synchronized void addInternalFrame(
815 final JInternalFrame frame, String title, int w, int h)
817 addInternalFrame(frame, title, true, w, h, true, false);
821 * Add an internal frame to the Jalview desktop
828 * When true, display frame immediately, otherwise, caller must call
829 * setVisible themselves.
835 public static synchronized void addInternalFrame(
836 final JInternalFrame frame, String title, boolean makeVisible,
839 addInternalFrame(frame, title, makeVisible, w, h, true, false);
843 * Add an internal frame to the Jalview desktop and make it visible
856 public static synchronized void addInternalFrame(
857 final JInternalFrame frame, String title, int w, int h,
860 addInternalFrame(frame, title, true, w, h, resizable, false);
864 * Add an internal frame to the Jalview desktop
871 * When true, display frame immediately, otherwise, caller must call
872 * setVisible themselves.
879 * @param ignoreMinSize
880 * Do not set the default minimum size for frame
882 public static synchronized void addInternalFrame(
883 final JInternalFrame frame, String title, boolean makeVisible,
884 int w, int h, boolean resizable, boolean ignoreMinSize)
887 // TODO: allow callers to determine X and Y position of frame (eg. via
889 // TODO: consider fixing method to update entries in the window submenu with
890 // the current window title
892 frame.setTitle(title);
893 if (frame.getWidth() < 1 || frame.getHeight() < 1)
897 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
898 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
899 // IF JALVIEW IS RUNNING HEADLESS
900 // ///////////////////////////////////////////////
901 if (instance == null || (System.getProperty("java.awt.headless") != null
902 && System.getProperty("java.awt.headless").equals("true")))
911 frame.setMinimumSize(
912 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
914 // Set default dimension for Alignment Frame window.
915 // The Alignment Frame window could be added from a number of places,
917 // I did this here in order not to miss out on any Alignment frame.
918 if (frame instanceof AlignFrame)
920 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
921 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
925 frame.setVisible(makeVisible);
926 frame.setClosable(true);
927 frame.setResizable(resizable);
928 frame.setMaximizable(resizable);
929 frame.setIconifiable(resizable);
930 frame.setOpaque(false);
932 if (frame.getX() < 1 && frame.getY() < 1)
934 frame.setLocation(xOffset * openFrameCount,
935 yOffset * ((openFrameCount - 1) % 10) + yOffset);
939 * add an entry for the new frame in the Window menu
940 * (and remove it when the frame is closed)
942 final JMenuItem menuItem = new JMenuItem(title);
943 frame.addInternalFrameListener(new InternalFrameAdapter()
946 public void internalFrameActivated(InternalFrameEvent evt)
948 JInternalFrame itf = desktop.getSelectedFrame();
951 if (itf instanceof AlignFrame)
953 Jalview.setCurrentAlignFrame((AlignFrame) itf);
960 public void internalFrameClosed(InternalFrameEvent evt)
962 PaintRefresher.RemoveComponent(frame);
965 * defensive check to prevent frames being
966 * added half off the window
968 if (openFrameCount > 0)
974 * ensure no reference to alignFrame retained by menu item listener
976 if (menuItem.getActionListeners().length > 0)
978 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
980 windowMenu.remove(menuItem);
984 menuItem.addActionListener(new ActionListener()
987 public void actionPerformed(ActionEvent e)
991 frame.setSelected(true);
992 frame.setIcon(false);
993 } catch (java.beans.PropertyVetoException ex)
1000 setKeyBindings(frame);
1004 windowMenu.add(menuItem);
1009 frame.setSelected(true);
1010 frame.requestFocus();
1011 } catch (java.beans.PropertyVetoException ve)
1013 } catch (java.lang.ClassCastException cex)
1016 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1022 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1027 private static void setKeyBindings(JInternalFrame frame)
1029 @SuppressWarnings("serial")
1030 final Action closeAction = new AbstractAction()
1033 public void actionPerformed(ActionEvent e)
1040 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1042 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1043 InputEvent.CTRL_DOWN_MASK);
1044 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1045 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1047 InputMap inputMap = frame
1048 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1049 String ctrlW = ctrlWKey.toString();
1050 inputMap.put(ctrlWKey, ctrlW);
1051 inputMap.put(cmdWKey, ctrlW);
1053 ActionMap actionMap = frame.getActionMap();
1054 actionMap.put(ctrlW, closeAction);
1058 public void lostOwnership(Clipboard clipboard, Transferable contents)
1062 Desktop.jalviewClipboard = null;
1065 internalCopy = false;
1069 public void dragEnter(DropTargetDragEvent evt)
1074 public void dragExit(DropTargetEvent evt)
1079 public void dragOver(DropTargetDragEvent evt)
1084 public void dropActionChanged(DropTargetDragEvent evt)
1095 public void drop(DropTargetDropEvent evt)
1097 boolean success = true;
1098 // JAL-1552 - acceptDrop required before getTransferable call for
1099 // Java's Transferable for native dnd
1100 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1101 Transferable t = evt.getTransferable();
1102 List<String> files = new ArrayList<>();
1103 List<DataSourceType> protocols = new ArrayList<>();
1107 Desktop.transferFromDropTarget(files, protocols, evt, t);
1108 } catch (Exception e)
1110 e.printStackTrace();
1118 for (int i = 0; i < files.size(); i++)
1120 String file = files.get(i).toString();
1121 DataSourceType protocol = (protocols == null)
1122 ? DataSourceType.FILE
1124 FileFormatI format = null;
1126 if (file.endsWith(".jar"))
1128 format = FileFormat.Jalview;
1133 format = new IdentifyFile().identify(file, protocol);
1136 new FileLoader().LoadFile(file, protocol, format);
1139 } catch (Exception ex)
1144 evt.dropComplete(success); // need this to ensure input focus is properly
1145 // transfered to any new windows created
1155 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1157 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1158 JalviewFileChooser chooser = JalviewFileChooser
1159 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1161 chooser.setFileView(new JalviewFileView());
1162 chooser.setDialogTitle(
1163 MessageManager.getString("label.open_local_file"));
1164 chooser.setToolTipText(MessageManager.getString("action.open"));
1166 int value = chooser.showOpenDialog(this);
1168 if (value == JalviewFileChooser.APPROVE_OPTION)
1170 String choice = chooser.getSelectedFile().getPath();
1171 Cache.setProperty("LAST_DIRECTORY",
1172 chooser.getSelectedFile().getParent());
1174 FileFormatI format = chooser.getSelectedFormat();
1177 * Call IdentifyFile to verify the file contains what its extension implies.
1178 * Skip this step for dynamically added file formats, because
1179 * IdentifyFile does not know how to recognise them.
1181 if (FileFormats.getInstance().isIdentifiable(format))
1185 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1186 } catch (FileFormatException e)
1188 // format = null; //??
1192 if (viewport != null)
1194 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1199 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1211 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1213 // This construct allows us to have a wider textfield
1215 JLabel label = new JLabel(
1216 MessageManager.getString("label.input_file_url"));
1217 final JComboBox history = new JComboBox();
1219 JPanel panel = new JPanel(new GridLayout(2, 1));
1222 history.setPreferredSize(new Dimension(400, 20));
1223 history.setEditable(true);
1224 history.addItem("http://www.");
1226 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1230 if (historyItems != null)
1232 st = new StringTokenizer(historyItems, "\t");
1234 while (st.hasMoreTokens())
1236 history.addItem(st.nextElement());
1240 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1241 MessageManager.getString("label.input_alignment_from_url"),
1242 JvOptionPane.OK_CANCEL_OPTION);
1244 if (reply != JvOptionPane.OK_OPTION)
1249 String url = history.getSelectedItem().toString();
1251 if (url.toLowerCase().endsWith(".jar"))
1253 if (viewport != null)
1255 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1256 FileFormat.Jalview);
1260 new FileLoader().LoadFile(url, DataSourceType.URL,
1261 FileFormat.Jalview);
1266 FileFormatI format = null;
1269 format = new IdentifyFile().identify(url, DataSourceType.URL);
1270 } catch (FileFormatException e)
1272 // TODO revise error handling, distinguish between
1273 // URL not found and response not valid
1278 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1279 MessageManager.formatMessage("label.couldnt_locate",
1282 MessageManager.getString("label.url_not_found"),
1283 JvOptionPane.WARNING_MESSAGE);
1288 if (viewport != null)
1290 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1295 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1301 * Opens the CutAndPaste window for the user to paste an alignment in to
1304 * - if not null, the pasted alignment is added to the current
1305 * alignment; if null, to a new alignment window
1308 public void inputTextboxMenuItem_actionPerformed(
1309 AlignmentViewPanel viewPanel)
1311 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1312 cap.setForInput(viewPanel);
1313 Desktop.addInternalFrame(cap,
1314 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1324 System.out.println("********** Desktop.quit()");
1325 System.out.println(savingFiles.toString());
1326 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1327 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1329 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1330 screen.height + "");
1331 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1332 getWidth(), getHeight()));
1334 if (jconsole != null)
1336 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1337 jconsole.stopConsole();
1341 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1344 if (dialogExecutor != null)
1346 dialogExecutor.shutdownNow();
1348 closeAll_actionPerformed(null);
1350 if (groovyConsole != null)
1352 // suppress a possible repeat prompt to save script
1353 groovyConsole.setDirty(false);
1354 groovyConsole.exit();
1359 private void storeLastKnownDimensions(String string, Rectangle jc)
1361 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1362 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1363 + " height:" + jc.height);
1365 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1366 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1367 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1368 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1378 public void aboutMenuItem_actionPerformed(ActionEvent e)
1380 // StringBuffer message = getAboutMessage(false);
1381 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1383 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1384 new Thread(new Runnable()
1389 new SplashScreen(true);
1394 public StringBuffer getAboutMessage(boolean shortv)
1396 StringBuffer message = new StringBuffer();
1397 message.append("<html>");
1400 message.append("<h1><strong>Version: "
1401 + jalview.bin.Cache.getProperty("VERSION")
1402 + "</strong></h1>");
1403 message.append("<strong>Last Updated: <em>"
1404 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1405 + "</em></strong>");
1411 message.append("<strong>Version "
1412 + jalview.bin.Cache.getProperty("VERSION")
1413 + "; last updated: "
1414 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1417 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1418 .equals("Checking"))
1420 message.append("<br>...Checking latest version...</br>");
1422 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1423 .equals(jalview.bin.Cache.getProperty("VERSION")))
1425 boolean red = false;
1426 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1427 .indexOf("automated build") == -1)
1430 // Displayed when code version and jnlp version do not match and code
1431 // version is not a development build
1432 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1435 message.append("<br>!! Version "
1436 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1438 + " is available for download from "
1439 + jalview.bin.Cache.getDefault("www.jalview.org",
1440 "http://www.jalview.org")
1444 message.append("</div>");
1447 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1449 "The Jalview Authors (See AUTHORS file for current list)")
1450 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1451 + "<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"
1452 + "<br><br>If you use Jalview, please cite:"
1453 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1454 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1455 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1467 public void documentationMenuItem_actionPerformed(ActionEvent e)
1471 Help.showHelpWindow();
1472 } catch (Exception ex)
1478 public void closeAll_actionPerformed(ActionEvent e)
1480 // TODO show a progress bar while closing?
1481 JInternalFrame[] frames = desktop.getAllFrames();
1482 for (int i = 0; i < frames.length; i++)
1486 frames[i].setClosed(true);
1487 } catch (java.beans.PropertyVetoException ex)
1491 Jalview.setCurrentAlignFrame(null);
1492 System.out.println("ALL CLOSED");
1493 if (v_client != null)
1495 // TODO clear binding to vamsas document objects on close_all
1499 * reset state of singleton objects as appropriate (clear down session state
1500 * when all windows are closed)
1502 StructureSelectionManager ssm = StructureSelectionManager
1503 .getStructureSelectionManager(this);
1511 public void raiseRelated_actionPerformed(ActionEvent e)
1513 reorderAssociatedWindows(false, false);
1517 public void minimizeAssociated_actionPerformed(ActionEvent e)
1519 reorderAssociatedWindows(true, false);
1522 void closeAssociatedWindows()
1524 reorderAssociatedWindows(false, true);
1530 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1534 protected void garbageCollect_actionPerformed(ActionEvent e)
1536 // We simply collect the garbage
1537 jalview.bin.Cache.log.debug("Collecting garbage...");
1539 jalview.bin.Cache.log.debug("Finished garbage collection.");
1546 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1550 protected void showMemusage_actionPerformed(ActionEvent e)
1552 desktop.showMemoryUsage(showMemusage.isSelected());
1559 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1563 protected void showConsole_actionPerformed(ActionEvent e)
1565 showConsole(showConsole.isSelected());
1568 Console jconsole = null;
1571 * control whether the java console is visible or not
1575 void showConsole(boolean selected)
1577 showConsole.setSelected(selected);
1578 // TODO: decide if we should update properties file
1579 Cache.setProperty("SHOW_JAVA_CONSOLE",
1580 Boolean.valueOf(selected).toString());
1581 jconsole.setVisible(selected);
1584 void reorderAssociatedWindows(boolean minimize, boolean close)
1586 JInternalFrame[] frames = desktop.getAllFrames();
1587 if (frames == null || frames.length < 1)
1592 AlignmentViewport source = null, target = null;
1593 if (frames[0] instanceof AlignFrame)
1595 source = ((AlignFrame) frames[0]).getCurrentView();
1597 else if (frames[0] instanceof TreePanel)
1599 source = ((TreePanel) frames[0]).getViewPort();
1601 else if (frames[0] instanceof PCAPanel)
1603 source = ((PCAPanel) frames[0]).av;
1605 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1607 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1612 for (int i = 0; i < frames.length; i++)
1615 if (frames[i] == null)
1619 if (frames[i] instanceof AlignFrame)
1621 target = ((AlignFrame) frames[i]).getCurrentView();
1623 else if (frames[i] instanceof TreePanel)
1625 target = ((TreePanel) frames[i]).getViewPort();
1627 else if (frames[i] instanceof PCAPanel)
1629 target = ((PCAPanel) frames[i]).av;
1631 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1633 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1636 if (source == target)
1642 frames[i].setClosed(true);
1646 frames[i].setIcon(minimize);
1649 frames[i].toFront();
1653 } catch (java.beans.PropertyVetoException ex)
1668 protected void preferences_actionPerformed(ActionEvent e)
1680 public void saveState_actionPerformed(ActionEvent e)
1682 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1685 chooser.setFileView(new JalviewFileView());
1686 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1688 int value = chooser.showSaveDialog(this);
1690 if (value == JalviewFileChooser.APPROVE_OPTION)
1692 final Desktop me = this;
1693 final java.io.File choice = chooser.getSelectedFile();
1694 setProjectFile(choice);
1696 new Thread(new Runnable()
1701 // TODO: refactor to Jalview desktop session controller action.
1702 setProgressBar(MessageManager.formatMessage(
1703 "label.saving_jalview_project", new Object[]
1704 { choice.getName() }), choice.hashCode());
1705 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1706 choice.getParent());
1707 // TODO catch and handle errors for savestate
1708 // TODO prevent user from messing with the Desktop whilst we're saving
1711 new Jalview2XML().saveState(choice);
1712 } catch (OutOfMemoryError oom)
1715 "Whilst saving current state to " + choice.getName(),
1717 } catch (Exception ex)
1720 "Problems whilst trying to save to " + choice.getName(),
1722 JvOptionPane.showMessageDialog(me,
1723 MessageManager.formatMessage(
1724 "label.error_whilst_saving_current_state_to",
1726 { choice.getName() }),
1727 MessageManager.getString("label.couldnt_save_project"),
1728 JvOptionPane.WARNING_MESSAGE);
1730 setProgressBar(null, choice.hashCode());
1736 private void setProjectFile(File choice)
1738 this.projectFile = choice;
1741 public File getProjectFile()
1743 return this.projectFile;
1753 public void loadState_actionPerformed(ActionEvent e)
1755 JalviewFileChooser chooser = new JalviewFileChooser(
1756 Cache.getProperty("LAST_DIRECTORY"), new String[]
1759 { "Jalview Project", "Jalview Project (old)" },
1761 chooser.setFileView(new JalviewFileView());
1762 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1764 int value = chooser.showOpenDialog(this);
1766 if (value == JalviewFileChooser.APPROVE_OPTION)
1768 final File selectedFile = chooser.getSelectedFile();
1769 setProjectFile(selectedFile);
1770 final String choice = selectedFile.getAbsolutePath();
1771 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1772 new Thread(new Runnable()
1777 setProgressBar(MessageManager.formatMessage(
1778 "label.loading_jalview_project", new Object[]
1779 { choice }), choice.hashCode());
1782 new Jalview2XML().loadJalviewAlign(choice);
1783 } catch (OutOfMemoryError oom)
1785 new OOMWarning("Whilst loading project from " + choice, oom);
1786 } catch (Exception ex)
1789 "Problems whilst loading project from " + choice, ex);
1790 JvOptionPane.showMessageDialog(Desktop.desktop,
1791 MessageManager.formatMessage(
1792 "label.error_whilst_loading_project_from",
1795 MessageManager.getString("label.couldnt_load_project"),
1796 JvOptionPane.WARNING_MESSAGE);
1798 setProgressBar(null, choice.hashCode());
1805 public void inputSequence_actionPerformed(ActionEvent e)
1807 new SequenceFetcher(this);
1810 JPanel progressPanel;
1812 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1814 public void startLoading(final String fileName)
1816 if (fileLoadingCount == 0)
1818 fileLoadingPanels.add(addProgressPanel(MessageManager
1819 .formatMessage("label.loading_file", new Object[]
1825 private JPanel addProgressPanel(String string)
1827 if (progressPanel == null)
1829 progressPanel = new JPanel(new GridLayout(1, 1));
1830 totalProgressCount = 0;
1831 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1833 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1834 JProgressBar progressBar = new JProgressBar();
1835 progressBar.setIndeterminate(true);
1837 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1839 thisprogress.add(progressBar, BorderLayout.CENTER);
1840 progressPanel.add(thisprogress);
1841 ((GridLayout) progressPanel.getLayout()).setRows(
1842 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1843 ++totalProgressCount;
1844 instance.validate();
1845 return thisprogress;
1848 int totalProgressCount = 0;
1850 private void removeProgressPanel(JPanel progbar)
1852 if (progressPanel != null)
1854 synchronized (progressPanel)
1856 progressPanel.remove(progbar);
1857 GridLayout gl = (GridLayout) progressPanel.getLayout();
1858 gl.setRows(gl.getRows() - 1);
1859 if (--totalProgressCount < 1)
1861 this.getContentPane().remove(progressPanel);
1862 progressPanel = null;
1869 public void stopLoading()
1872 if (fileLoadingCount < 1)
1874 while (fileLoadingPanels.size() > 0)
1876 removeProgressPanel(fileLoadingPanels.remove(0));
1878 fileLoadingPanels.clear();
1879 fileLoadingCount = 0;
1884 public static int getViewCount(String alignmentId)
1886 AlignmentViewport[] aps = getViewports(alignmentId);
1887 return (aps == null) ? 0 : aps.length;
1892 * @param alignmentId
1893 * - if null, all sets are returned
1894 * @return all AlignmentPanels concerning the alignmentId sequence set
1896 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1898 if (Desktop.desktop == null)
1900 // no frames created and in headless mode
1901 // TODO: verify that frames are recoverable when in headless mode
1904 List<AlignmentPanel> aps = new ArrayList<>();
1905 AlignFrame[] frames = getAlignFrames();
1910 for (AlignFrame af : frames)
1912 for (AlignmentPanel ap : af.alignPanels)
1914 if (alignmentId == null
1915 || alignmentId.equals(ap.av.getSequenceSetId()))
1921 if (aps.size() == 0)
1925 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1930 * get all the viewports on an alignment.
1932 * @param sequenceSetId
1933 * unique alignment id (may be null - all viewports returned in that
1935 * @return all viewports on the alignment bound to sequenceSetId
1937 public static AlignmentViewport[] getViewports(String sequenceSetId)
1939 List<AlignmentViewport> viewp = new ArrayList<>();
1940 if (desktop != null)
1942 AlignFrame[] frames = Desktop.getAlignFrames();
1944 for (AlignFrame afr : frames)
1946 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1947 .equals(sequenceSetId))
1949 if (afr.alignPanels != null)
1951 for (AlignmentPanel ap : afr.alignPanels)
1953 if (sequenceSetId == null
1954 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1962 viewp.add(afr.getViewport());
1966 if (viewp.size() > 0)
1968 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1975 * Explode the views in the given frame into separate AlignFrame
1979 public static void explodeViews(AlignFrame af)
1981 int size = af.alignPanels.size();
1987 for (int i = 0; i < size; i++)
1989 AlignmentPanel ap = af.alignPanels.get(i);
1990 AlignFrame newaf = new AlignFrame(ap);
1993 * Restore the view's last exploded frame geometry if known. Multiple
1994 * views from one exploded frame share and restore the same (frame)
1995 * position and size.
1997 Rectangle geometry = ap.av.getExplodedGeometry();
1998 if (geometry != null)
2000 newaf.setBounds(geometry);
2003 ap.av.setGatherViewsHere(false);
2005 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2006 AlignFrame.DEFAULT_HEIGHT);
2009 af.alignPanels.clear();
2010 af.closeMenuItem_actionPerformed(true);
2015 * Gather expanded views (separate AlignFrame's) with the same sequence set
2016 * identifier back in to this frame as additional views, and close the
2017 * expanded views. Note the expanded frames may themselves have multiple
2018 * views. We take the lot.
2022 public void gatherViews(AlignFrame source)
2024 source.viewport.setGatherViewsHere(true);
2025 source.viewport.setExplodedGeometry(source.getBounds());
2026 JInternalFrame[] frames = desktop.getAllFrames();
2027 String viewId = source.viewport.getSequenceSetId();
2029 for (int t = 0; t < frames.length; t++)
2031 if (frames[t] instanceof AlignFrame && frames[t] != source)
2033 AlignFrame af = (AlignFrame) frames[t];
2034 boolean gatherThis = false;
2035 for (int a = 0; a < af.alignPanels.size(); a++)
2037 AlignmentPanel ap = af.alignPanels.get(a);
2038 if (viewId.equals(ap.av.getSequenceSetId()))
2041 ap.av.setGatherViewsHere(false);
2042 ap.av.setExplodedGeometry(af.getBounds());
2043 source.addAlignmentPanel(ap, false);
2049 af.alignPanels.clear();
2050 af.closeMenuItem_actionPerformed(true);
2057 jalview.gui.VamsasApplication v_client = null;
2060 public void vamsasImport_actionPerformed(ActionEvent e)
2062 if (v_client == null)
2064 // Load and try to start a session.
2065 JalviewFileChooser chooser = new JalviewFileChooser(
2066 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2068 chooser.setFileView(new JalviewFileView());
2069 chooser.setDialogTitle(
2070 MessageManager.getString("label.open_saved_vamsas_session"));
2071 chooser.setToolTipText(MessageManager.getString(
2072 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2074 int value = chooser.showOpenDialog(this);
2076 if (value == JalviewFileChooser.APPROVE_OPTION)
2078 String fle = chooser.getSelectedFile().toString();
2079 if (!vamsasImport(chooser.getSelectedFile()))
2081 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2082 MessageManager.formatMessage(
2083 "label.couldnt_import_as_vamsas_session",
2087 .getString("label.vamsas_document_import_failed"),
2088 JvOptionPane.ERROR_MESSAGE);
2094 jalview.bin.Cache.log.error(
2095 "Implementation error - load session from a running session is not supported.");
2100 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2103 * @return true if import was a success and a session was started.
2105 public boolean vamsasImport(URL url)
2107 // TODO: create progress bar
2108 if (v_client != null)
2111 jalview.bin.Cache.log.error(
2112 "Implementation error - load session from a running session is not supported.");
2118 // copy the URL content to a temporary local file
2119 // TODO: be a bit cleverer here with nio (?!)
2120 File file = File.createTempFile("vdocfromurl", ".vdj");
2121 FileOutputStream fos = new FileOutputStream(file);
2122 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2123 byte[] buffer = new byte[2048];
2125 while ((ln = bis.read(buffer)) > -1)
2127 fos.write(buffer, 0, ln);
2131 v_client = new jalview.gui.VamsasApplication(this, file,
2132 url.toExternalForm());
2133 } catch (Exception ex)
2135 jalview.bin.Cache.log.error(
2136 "Failed to create new vamsas session from contents of URL "
2141 setupVamsasConnectedGui();
2142 v_client.initial_update(); // TODO: thread ?
2143 return v_client.inSession();
2147 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2150 * @return true if import was a success and a session was started.
2152 public boolean vamsasImport(File file)
2154 if (v_client != null)
2157 jalview.bin.Cache.log.error(
2158 "Implementation error - load session from a running session is not supported.");
2162 setProgressBar(MessageManager.formatMessage(
2163 "status.importing_vamsas_session_from", new Object[]
2164 { file.getName() }), file.hashCode());
2167 v_client = new jalview.gui.VamsasApplication(this, file, null);
2168 } catch (Exception ex)
2170 setProgressBar(MessageManager.formatMessage(
2171 "status.importing_vamsas_session_from", new Object[]
2172 { file.getName() }), file.hashCode());
2173 jalview.bin.Cache.log.error(
2174 "New vamsas session from existing session file failed:", ex);
2177 setupVamsasConnectedGui();
2178 v_client.initial_update(); // TODO: thread ?
2179 setProgressBar(MessageManager.formatMessage(
2180 "status.importing_vamsas_session_from", new Object[]
2181 { file.getName() }), file.hashCode());
2182 return v_client.inSession();
2185 public boolean joinVamsasSession(String mysesid)
2187 if (v_client != null)
2189 throw new Error(MessageManager
2190 .getString("error.try_join_vamsas_session_another"));
2192 if (mysesid == null)
2195 MessageManager.getString("error.invalid_vamsas_session_id"));
2197 v_client = new VamsasApplication(this, mysesid);
2198 setupVamsasConnectedGui();
2199 v_client.initial_update();
2200 return (v_client.inSession());
2204 public void vamsasStart_actionPerformed(ActionEvent e)
2206 if (v_client == null)
2209 // we just start a default session for moment.
2211 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2212 * getProperty("LAST_DIRECTORY"));
2214 * chooser.setFileView(new JalviewFileView());
2215 * chooser.setDialogTitle("Load Vamsas file");
2216 * chooser.setToolTipText("Import");
2218 * int value = chooser.showOpenDialog(this);
2220 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2221 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2223 v_client = new VamsasApplication(this);
2224 setupVamsasConnectedGui();
2225 v_client.initial_update(); // TODO: thread ?
2229 // store current data in session.
2230 v_client.push_update(); // TODO: thread
2234 protected void setupVamsasConnectedGui()
2236 vamsasStart.setText(MessageManager.getString("label.session_update"));
2237 vamsasSave.setVisible(true);
2238 vamsasStop.setVisible(true);
2239 vamsasImport.setVisible(false); // Document import to existing session is
2240 // not possible for vamsas-client-1.0.
2243 protected void setupVamsasDisconnectedGui()
2245 vamsasSave.setVisible(false);
2246 vamsasStop.setVisible(false);
2247 vamsasImport.setVisible(true);
2249 .setText(MessageManager.getString("label.new_vamsas_session"));
2253 public void vamsasStop_actionPerformed(ActionEvent e)
2255 if (v_client != null)
2257 v_client.end_session();
2259 setupVamsasDisconnectedGui();
2263 protected void buildVamsasStMenu()
2265 if (v_client == null)
2267 String[] sess = null;
2270 sess = VamsasApplication.getSessionList();
2271 } catch (Exception e)
2273 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2279 jalview.bin.Cache.log.debug(
2280 "Got current sessions list: " + sess.length + " entries.");
2281 VamsasStMenu.removeAll();
2282 for (int i = 0; i < sess.length; i++)
2284 JMenuItem sessit = new JMenuItem();
2285 sessit.setText(sess[i]);
2286 sessit.setToolTipText(MessageManager
2287 .formatMessage("label.connect_to_session", new Object[]
2289 final Desktop dsktp = this;
2290 final String mysesid = sess[i];
2291 sessit.addActionListener(new ActionListener()
2295 public void actionPerformed(ActionEvent e)
2297 if (dsktp.v_client == null)
2299 Thread rthr = new Thread(new Runnable()
2305 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2306 dsktp.setupVamsasConnectedGui();
2307 dsktp.v_client.initial_update();
2315 VamsasStMenu.add(sessit);
2317 // don't show an empty menu.
2318 VamsasStMenu.setVisible(sess.length > 0);
2323 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2324 VamsasStMenu.removeAll();
2325 VamsasStMenu.setVisible(false);
2330 // Not interested in the content. Just hide ourselves.
2331 VamsasStMenu.setVisible(false);
2336 public void vamsasSave_actionPerformed(ActionEvent e)
2338 if (v_client != null)
2340 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2341 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2344 chooser.setFileView(new JalviewFileView());
2345 chooser.setDialogTitle(MessageManager
2346 .getString("label.save_vamsas_document_archive"));
2348 int value = chooser.showSaveDialog(this);
2350 if (value == JalviewFileChooser.APPROVE_OPTION)
2352 java.io.File choice = chooser.getSelectedFile();
2353 JPanel progpanel = addProgressPanel(MessageManager
2354 .formatMessage("label.saving_vamsas_doc", new Object[]
2355 { choice.getName() }));
2356 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2357 String warnmsg = null;
2358 String warnttl = null;
2361 v_client.vclient.storeDocument(choice);
2364 warnttl = "Serious Problem saving Vamsas Document";
2365 warnmsg = ex.toString();
2366 jalview.bin.Cache.log
2367 .error("Error Whilst saving document to " + choice, ex);
2369 } catch (Exception ex)
2371 warnttl = "Problem saving Vamsas Document.";
2372 warnmsg = ex.toString();
2373 jalview.bin.Cache.log.warn(
2374 "Exception Whilst saving document to " + choice, ex);
2377 removeProgressPanel(progpanel);
2378 if (warnmsg != null)
2380 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2382 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2388 JPanel vamUpdate = null;
2391 * hide vamsas user gui bits when a vamsas document event is being handled.
2394 * true to hide gui, false to reveal gui
2396 public void setVamsasUpdate(boolean b)
2398 Cache.log.debug("Setting gui for Vamsas update "
2399 + (b ? "in progress" : "finished"));
2401 if (vamUpdate != null)
2403 this.removeProgressPanel(vamUpdate);
2407 vamUpdate = this.addProgressPanel(
2408 MessageManager.getString("label.updating_vamsas_session"));
2410 vamsasStart.setVisible(!b);
2411 vamsasStop.setVisible(!b);
2412 vamsasSave.setVisible(!b);
2415 public JInternalFrame[] getAllFrames()
2417 return desktop.getAllFrames();
2421 * Checks the given url to see if it gives a response indicating that the user
2422 * should be informed of a new questionnaire.
2426 public void checkForQuestionnaire(String url)
2428 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2429 // javax.swing.SwingUtilities.invokeLater(jvq);
2430 new Thread(jvq).start();
2433 public void checkURLLinks()
2435 // Thread off the URL link checker
2436 addDialogThread(new Runnable()
2441 if (Cache.getDefault("CHECKURLLINKS", true))
2443 // check what the actual links are - if it's just the default don't
2444 // bother with the warning
2445 List<String> links = Preferences.sequenceUrlLinks
2448 // only need to check links if there is one with a
2449 // SEQUENCE_ID which is not the default EMBL_EBI link
2450 ListIterator<String> li = links.listIterator();
2451 boolean check = false;
2452 List<JLabel> urls = new ArrayList<>();
2453 while (li.hasNext())
2455 String link = li.next();
2456 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2457 && !UrlConstants.isDefaultString(link))
2460 int barPos = link.indexOf("|");
2461 String urlMsg = barPos == -1 ? link
2462 : link.substring(0, barPos) + ": "
2463 + link.substring(barPos + 1);
2464 urls.add(new JLabel(urlMsg));
2472 // ask user to check in case URL links use old style tokens
2473 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2474 JPanel msgPanel = new JPanel();
2475 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2476 msgPanel.add(Box.createVerticalGlue());
2477 JLabel msg = new JLabel(MessageManager
2478 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2479 JLabel msg2 = new JLabel(MessageManager
2480 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2482 for (JLabel url : urls)
2488 final JCheckBox jcb = new JCheckBox(
2489 MessageManager.getString("label.do_not_display_again"));
2490 jcb.addActionListener(new ActionListener()
2493 public void actionPerformed(ActionEvent e)
2495 // update Cache settings for "don't show this again"
2496 boolean showWarningAgain = !jcb.isSelected();
2497 Cache.setProperty("CHECKURLLINKS",
2498 Boolean.valueOf(showWarningAgain).toString());
2503 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2505 .getString("label.SEQUENCE_ID_no_longer_used"),
2506 JvOptionPane.WARNING_MESSAGE);
2513 * Proxy class for JDesktopPane which optionally displays the current memory
2514 * usage and highlights the desktop area with a red bar if free memory runs
2519 public class MyDesktopPane extends JDesktopPane implements Runnable
2522 private static final float ONE_MB = 1048576f;
2524 boolean showMemoryUsage = false;
2528 java.text.NumberFormat df;
2530 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2533 public MyDesktopPane(boolean showMemoryUsage)
2535 showMemoryUsage(showMemoryUsage);
2538 public void showMemoryUsage(boolean showMemory)
2540 this.showMemoryUsage = showMemory;
2543 Thread worker = new Thread(this);
2549 public boolean isShowMemoryUsage()
2551 return showMemoryUsage;
2557 df = java.text.NumberFormat.getNumberInstance();
2558 df.setMaximumFractionDigits(2);
2559 runtime = Runtime.getRuntime();
2561 while (showMemoryUsage)
2565 maxMemory = runtime.maxMemory() / ONE_MB;
2566 allocatedMemory = runtime.totalMemory() / ONE_MB;
2567 freeMemory = runtime.freeMemory() / ONE_MB;
2568 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2570 percentUsage = (totalFreeMemory / maxMemory) * 100;
2572 // if (percentUsage < 20)
2574 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2576 // instance.set.setBorder(border1);
2579 // sleep after showing usage
2581 } catch (Exception ex)
2583 ex.printStackTrace();
2589 public void paintComponent(Graphics g)
2591 if (showMemoryUsage && g != null && df != null)
2593 if (percentUsage < 20)
2595 g.setColor(Color.red);
2597 FontMetrics fm = g.getFontMetrics();
2600 g.drawString(MessageManager.formatMessage("label.memory_stats",
2602 { df.format(totalFreeMemory), df.format(maxMemory),
2603 df.format(percentUsage) }),
2604 10, getHeight() - fm.getHeight());
2611 * Accessor method to quickly get all the AlignmentFrames loaded.
2613 * @return an array of AlignFrame, or null if none found
2615 public static AlignFrame[] getAlignFrames()
2617 if (Jalview.isHeadlessMode())
2619 // Desktop.desktop is null in headless mode
2620 return new AlignFrame[] { Jalview.currentAlignFrame };
2623 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2629 List<AlignFrame> avp = new ArrayList<>();
2631 for (int i = frames.length - 1; i > -1; i--)
2633 if (frames[i] instanceof AlignFrame)
2635 avp.add((AlignFrame) frames[i]);
2637 else if (frames[i] instanceof SplitFrame)
2640 * Also check for a split frame containing an AlignFrame
2642 GSplitFrame sf = (GSplitFrame) frames[i];
2643 if (sf.getTopFrame() instanceof AlignFrame)
2645 avp.add((AlignFrame) sf.getTopFrame());
2647 if (sf.getBottomFrame() instanceof AlignFrame)
2649 avp.add((AlignFrame) sf.getBottomFrame());
2653 if (avp.size() == 0)
2657 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2662 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2666 public GStructureViewer[] getJmols()
2668 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2674 List<GStructureViewer> avp = new ArrayList<>();
2676 for (int i = frames.length - 1; i > -1; i--)
2678 if (frames[i] instanceof AppJmol)
2680 GStructureViewer af = (GStructureViewer) frames[i];
2684 if (avp.size() == 0)
2688 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2693 * Add Groovy Support to Jalview
2696 public void groovyShell_actionPerformed()
2700 openGroovyConsole();
2701 } catch (Exception ex)
2703 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2704 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2706 MessageManager.getString("label.couldnt_create_groovy_shell"),
2707 MessageManager.getString("label.groovy_support_failed"),
2708 JvOptionPane.ERROR_MESSAGE);
2713 * Open the Groovy console
2715 void openGroovyConsole()
2717 if (groovyConsole == null)
2719 groovyConsole = new groovy.ui.Console();
2720 groovyConsole.setVariable("Jalview", this);
2721 groovyConsole.run();
2724 * We allow only one console at a time, so that AlignFrame menu option
2725 * 'Calculate | Run Groovy script' is unambiguous.
2726 * Disable 'Groovy Console', and enable 'Run script', when the console is
2727 * opened, and the reverse when it is closed
2729 Window window = (Window) groovyConsole.getFrame();
2730 window.addWindowListener(new WindowAdapter()
2733 public void windowClosed(WindowEvent e)
2736 * rebind CMD-Q from Groovy Console to Jalview Quit
2739 enableExecuteGroovy(false);
2745 * show Groovy console window (after close and reopen)
2747 ((Window) groovyConsole.getFrame()).setVisible(true);
2750 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2751 * and disable opening a second console
2753 enableExecuteGroovy(true);
2757 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2758 * binding when opened
2760 protected void addQuitHandler()
2762 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2763 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2764 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2766 getRootPane().getActionMap().put("Quit", new AbstractAction()
2769 public void actionPerformed(ActionEvent e)
2777 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2780 * true if Groovy console is open
2782 public void enableExecuteGroovy(boolean enabled)
2785 * disable opening a second Groovy console
2786 * (or re-enable when the console is closed)
2788 groovyShell.setEnabled(!enabled);
2790 AlignFrame[] alignFrames = getAlignFrames();
2791 if (alignFrames != null)
2793 for (AlignFrame af : alignFrames)
2795 af.setGroovyEnabled(enabled);
2801 * Progress bars managed by the IProgressIndicator method.
2803 private Hashtable<Long, JPanel> progressBars;
2805 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2810 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2813 public void setProgressBar(String message, long id)
2815 if (progressBars == null)
2817 progressBars = new Hashtable<>();
2818 progressBarHandlers = new Hashtable<>();
2821 if (progressBars.get(new Long(id)) != null)
2823 JPanel panel = progressBars.remove(new Long(id));
2824 if (progressBarHandlers.contains(new Long(id)))
2826 progressBarHandlers.remove(new Long(id));
2828 removeProgressPanel(panel);
2832 progressBars.put(new Long(id), addProgressPanel(message));
2839 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2840 * jalview.gui.IProgressIndicatorHandler)
2843 public void registerHandler(final long id,
2844 final IProgressIndicatorHandler handler)
2846 if (progressBarHandlers == null
2847 || !progressBars.containsKey(new Long(id)))
2849 throw new Error(MessageManager.getString(
2850 "error.call_setprogressbar_before_registering_handler"));
2852 progressBarHandlers.put(new Long(id), handler);
2853 final JPanel progressPanel = progressBars.get(new Long(id));
2854 if (handler.canCancel())
2856 JButton cancel = new JButton(
2857 MessageManager.getString("action.cancel"));
2858 final IProgressIndicator us = this;
2859 cancel.addActionListener(new ActionListener()
2863 public void actionPerformed(ActionEvent e)
2865 handler.cancelActivity(id);
2866 us.setProgressBar(MessageManager
2867 .formatMessage("label.cancelled_params", new Object[]
2868 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2872 progressPanel.add(cancel, BorderLayout.EAST);
2878 * @return true if any progress bars are still active
2881 public boolean operationInProgress()
2883 if (progressBars != null && progressBars.size() > 0)
2891 * This will return the first AlignFrame holding the given viewport instance.
2892 * It will break if there are more than one AlignFrames viewing a particular
2896 * @return alignFrame for viewport
2898 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2900 if (desktop != null)
2902 AlignmentPanel[] aps = getAlignmentPanels(
2903 viewport.getSequenceSetId());
2904 for (int panel = 0; aps != null && panel < aps.length; panel++)
2906 if (aps[panel] != null && aps[panel].av == viewport)
2908 return aps[panel].alignFrame;
2915 public VamsasApplication getVamsasApplication()
2922 * flag set if jalview GUI is being operated programmatically
2924 private boolean inBatchMode = false;
2927 * check if jalview GUI is being operated programmatically
2929 * @return inBatchMode
2931 public boolean isInBatchMode()
2937 * set flag if jalview GUI is being operated programmatically
2939 * @param inBatchMode
2941 public void setInBatchMode(boolean inBatchMode)
2943 this.inBatchMode = inBatchMode;
2946 public void startServiceDiscovery()
2948 startServiceDiscovery(false);
2951 public void startServiceDiscovery(boolean blocking)
2953 boolean alive = true;
2954 Thread t0 = null, t1 = null, t2 = null;
2955 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2958 // todo: changesupport handlers need to be transferred
2959 if (discoverer == null)
2961 discoverer = new jalview.ws.jws1.Discoverer();
2962 // register PCS handler for desktop.
2963 discoverer.addPropertyChangeListener(changeSupport);
2965 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2966 // until we phase out completely
2967 (t0 = new Thread(discoverer)).start();
2970 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2972 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2973 .startDiscoverer(changeSupport);
2977 // TODO: do rest service discovery
2986 } catch (Exception e)
2989 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2990 || (t3 != null && t3.isAlive())
2991 || (t0 != null && t0.isAlive());
2997 * called to check if the service discovery process completed successfully.
3001 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3003 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3005 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3006 .getErrorMessages();
3009 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3011 if (serviceChangedDialog == null)
3013 // only run if we aren't already displaying one of these.
3014 addDialogThread(serviceChangedDialog = new Runnable()
3021 * JalviewDialog jd =new JalviewDialog() {
3023 * @Override protected void cancelPressed() { // TODO
3024 * Auto-generated method stub
3026 * }@Override protected void okPressed() { // TODO
3027 * Auto-generated method stub
3029 * }@Override protected void raiseClosed() { // TODO
3030 * Auto-generated method stub
3032 * } }; jd.initDialogFrame(new
3033 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3034 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3035 * + " or mis-configured HTTP proxy settings.<br/>" +
3036 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3038 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3039 * ), true, true, "Web Service Configuration Problem", 450,
3042 * jd.waitForInput();
3044 JvOptionPane.showConfirmDialog(Desktop.desktop,
3045 new JLabel("<html><table width=\"450\"><tr><td>"
3046 + ermsg + "</td></tr></table>"
3047 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3048 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3049 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3050 + " Tools->Preferences dialog box to change them.</p></html>"),
3051 "Web Service Configuration Problem",
3052 JvOptionPane.DEFAULT_OPTION,
3053 JvOptionPane.ERROR_MESSAGE);
3054 serviceChangedDialog = null;
3063 "Errors reported by JABA discovery service. Check web services preferences.\n"
3070 private Runnable serviceChangedDialog = null;
3073 * start a thread to open a URL in the configured browser. Pops up a warning
3074 * dialog to the user if there is an exception when calling out to the browser
3079 public static void showUrl(final String url)
3081 showUrl(url, Desktop.instance);
3085 * Like showUrl but allows progress handler to be specified
3089 * (null) or object implementing IProgressIndicator
3091 public static void showUrl(final String url,
3092 final IProgressIndicator progress)
3094 new Thread(new Runnable()
3101 if (progress != null)
3103 progress.setProgressBar(MessageManager
3104 .formatMessage("status.opening_params", new Object[]
3105 { url }), this.hashCode());
3107 jalview.util.BrowserLauncher.openURL(url);
3108 } catch (Exception ex)
3110 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3112 .getString("label.web_browser_not_found_unix"),
3113 MessageManager.getString("label.web_browser_not_found"),
3114 JvOptionPane.WARNING_MESSAGE);
3116 ex.printStackTrace();
3118 if (progress != null)
3120 progress.setProgressBar(null, this.hashCode());
3126 public static WsParamSetManager wsparamManager = null;
3128 public static ParamManager getUserParameterStore()
3130 if (wsparamManager == null)
3132 wsparamManager = new WsParamSetManager();
3134 return wsparamManager;
3138 * static hyperlink handler proxy method for use by Jalview's internal windows
3142 public static void hyperlinkUpdate(HyperlinkEvent e)
3144 if (e.getEventType() == EventType.ACTIVATED)
3149 url = e.getURL().toString();
3150 Desktop.showUrl(url);
3151 } catch (Exception x)
3155 if (Cache.log != null)
3157 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3162 "Couldn't handle string " + url + " as a URL.");
3165 // ignore any exceptions due to dud links.
3172 * single thread that handles display of dialogs to user.
3174 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3177 * flag indicating if dialogExecutor should try to acquire a permit
3179 private volatile boolean dialogPause = true;
3184 private java.util.concurrent.Semaphore block = new Semaphore(0);
3186 private static groovy.ui.Console groovyConsole;
3189 * add another dialog thread to the queue
3193 public void addDialogThread(final Runnable prompter)
3195 dialogExecutor.submit(new Runnable()
3205 } catch (InterruptedException x)
3210 if (instance == null)
3216 SwingUtilities.invokeAndWait(prompter);
3217 } catch (Exception q)
3219 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3225 public void startDialogQueue()
3227 // set the flag so we don't pause waiting for another permit and semaphore
3228 // the current task to begin
3229 dialogPause = false;
3234 protected void snapShotWindow_actionPerformed(ActionEvent e)
3238 ImageMaker im = new jalview.util.ImageMaker(
3239 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3240 getHeight(), of = new File("Jalview_snapshot"
3241 + System.currentTimeMillis() + ".eps"),
3242 "View of desktop", null, 0, false);
3245 paintAll(im.getGraphics());
3247 } catch (Exception q)
3249 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3253 Cache.log.info("Successfully written snapshot to file "
3254 + of.getAbsolutePath());
3258 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3259 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3260 * and location last time the view was expanded (if any). However it does not
3261 * remember the split pane divider location - this is set to match the
3262 * 'exploding' frame.
3266 public void explodeViews(SplitFrame sf)
3268 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3269 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3270 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3272 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3274 int viewCount = topPanels.size();
3281 * Processing in reverse order works, forwards order leaves the first panels
3282 * not visible. I don't know why!
3284 for (int i = viewCount - 1; i >= 0; i--)
3287 * Make new top and bottom frames. These take over the respective
3288 * AlignmentPanel objects, including their AlignmentViewports, so the
3289 * cdna/protein relationships between the viewports is carried over to the
3292 * explodedGeometry holds the (x, y) position of the previously exploded
3293 * SplitFrame, and the (width, height) of the AlignFrame component
3295 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3296 AlignFrame newTopFrame = new AlignFrame(topPanel);
3297 newTopFrame.setSize(oldTopFrame.getSize());
3298 newTopFrame.setVisible(true);
3299 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3300 .getExplodedGeometry();
3301 if (geometry != null)
3303 newTopFrame.setSize(geometry.getSize());
3306 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3307 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3308 newBottomFrame.setSize(oldBottomFrame.getSize());
3309 newBottomFrame.setVisible(true);
3310 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3311 .getExplodedGeometry();
3312 if (geometry != null)
3314 newBottomFrame.setSize(geometry.getSize());
3317 topPanel.av.setGatherViewsHere(false);
3318 bottomPanel.av.setGatherViewsHere(false);
3319 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3321 if (geometry != null)
3323 splitFrame.setLocation(geometry.getLocation());
3325 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3329 * Clear references to the panels (now relocated in the new SplitFrames)
3330 * before closing the old SplitFrame.
3333 bottomPanels.clear();
3338 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3339 * back into the given SplitFrame as additional views. Note that the gathered
3340 * frames may themselves have multiple views.
3344 public void gatherViews(GSplitFrame source)
3347 * special handling of explodedGeometry for a view within a SplitFrame: - it
3348 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3349 * height) of the AlignFrame component
3351 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3352 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3353 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3354 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3355 myBottomFrame.viewport
3356 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3357 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3358 myTopFrame.viewport.setGatherViewsHere(true);
3359 myBottomFrame.viewport.setGatherViewsHere(true);
3360 String topViewId = myTopFrame.viewport.getSequenceSetId();
3361 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3363 JInternalFrame[] frames = desktop.getAllFrames();
3364 for (JInternalFrame frame : frames)
3366 if (frame instanceof SplitFrame && frame != source)
3368 SplitFrame sf = (SplitFrame) frame;
3369 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3370 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3371 boolean gatherThis = false;
3372 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3374 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3375 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3376 if (topViewId.equals(topPanel.av.getSequenceSetId())
3377 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3380 topPanel.av.setGatherViewsHere(false);
3381 bottomPanel.av.setGatherViewsHere(false);
3382 topPanel.av.setExplodedGeometry(
3383 new Rectangle(sf.getLocation(), topFrame.getSize()));
3384 bottomPanel.av.setExplodedGeometry(
3385 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3386 myTopFrame.addAlignmentPanel(topPanel, false);
3387 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3393 topFrame.getAlignPanels().clear();
3394 bottomFrame.getAlignPanels().clear();
3401 * The dust settles...give focus to the tab we did this from.
3403 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3406 public static groovy.ui.Console getGroovyConsole()
3408 return groovyConsole;
3412 * handles the payload of a drag and drop event.
3414 * TODO refactor to desktop utilities class
3417 * - Data source strings extracted from the drop event
3419 * - protocol for each data source extracted from the drop event
3423 * - the payload from the drop event
3426 public static void transferFromDropTarget(List<String> files,
3427 List<DataSourceType> protocols, DropTargetDropEvent evt,
3428 Transferable t) throws Exception
3431 DataFlavor uriListFlavor = new DataFlavor(
3432 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3435 urlFlavour = new DataFlavor(
3436 "application/x-java-url; class=java.net.URL");
3437 } catch (ClassNotFoundException cfe)
3439 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3442 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3447 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3448 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3449 // means url may be null.
3452 protocols.add(DataSourceType.URL);
3453 files.add(url.toString());
3454 Cache.log.debug("Drop handled as URL dataflavor "
3455 + files.get(files.size() - 1));
3460 if (Platform.isAMac())
3463 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3467 } catch (Throwable ex)
3469 Cache.log.debug("URL drop handler failed.", ex);
3472 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3474 // Works on Windows and MacOSX
3475 Cache.log.debug("Drop handled as javaFileListFlavor");
3476 for (Object file : (List) t
3477 .getTransferData(DataFlavor.javaFileListFlavor))
3479 files.add(((File) file).toString());
3480 protocols.add(DataSourceType.FILE);
3485 // Unix like behaviour
3486 boolean added = false;
3488 if (t.isDataFlavorSupported(uriListFlavor))
3490 Cache.log.debug("Drop handled as uriListFlavor");
3491 // This is used by Unix drag system
3492 data = (String) t.getTransferData(uriListFlavor);
3496 // fallback to text: workaround - on OSX where there's a JVM bug
3497 Cache.log.debug("standard URIListFlavor failed. Trying text");
3498 // try text fallback
3499 DataFlavor textDf = new DataFlavor(
3500 "text/plain;class=java.lang.String");
3501 if (t.isDataFlavorSupported(textDf))
3503 data = (String) t.getTransferData(textDf);
3506 Cache.log.debug("Plain text drop content returned "
3507 + (data == null ? "Null - failed" : data));
3512 while (protocols.size() < files.size())
3514 Cache.log.debug("Adding missing FILE protocol for "
3515 + files.get(protocols.size()));
3516 protocols.add(DataSourceType.FILE);
3518 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3519 data, "\r\n"); st.hasMoreTokens();)
3522 String s = st.nextToken();
3523 if (s.startsWith("#"))
3525 // the line is a comment (as per the RFC 2483)
3528 java.net.URI uri = new java.net.URI(s);
3529 if (uri.getScheme().toLowerCase().startsWith("http"))
3531 protocols.add(DataSourceType.URL);
3532 files.add(uri.toString());
3536 // otherwise preserve old behaviour: catch all for file objects
3537 java.io.File file = new java.io.File(uri);
3538 protocols.add(DataSourceType.FILE);
3539 files.add(file.toString());
3544 if (Cache.log.isDebugEnabled())
3546 if (data == null || !added)
3549 if (t.getTransferDataFlavors() != null
3550 && t.getTransferDataFlavors().length > 0)
3553 "Couldn't resolve drop data. Here are the supported flavors:");
3554 for (DataFlavor fl : t.getTransferDataFlavors())
3557 "Supported transfer dataflavor: " + fl.toString());
3558 Object df = t.getTransferData(fl);
3561 Cache.log.debug("Retrieves: " + df);
3565 Cache.log.debug("Retrieved nothing");
3571 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3577 if (Platform.isWindows())
3580 Cache.log.debug("Scanning dropped content for Windows Link Files");
3582 // resolve any .lnk files in the file drop
3583 for (int f = 0; f < files.size(); f++)
3585 String source = files.get(f).toLowerCase();
3586 if (protocols.get(f).equals(DataSourceType.FILE)
3587 && (source.endsWith(".lnk") || source.endsWith(".url")
3588 || source.endsWith(".site")))
3592 File lf = new File(files.get(f));
3593 // process link file to get a URL
3594 Cache.log.debug("Found potential link file: " + lf);
3595 WindowsShortcut wscfile = new WindowsShortcut(lf);
3596 String fullname = wscfile.getRealFilename();
3597 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3598 files.set(f, fullname);
3599 Cache.log.debug("Parsed real filename " + fullname
3600 + " to extract protocol: " + protocols.get(f));
3601 } catch (Exception ex)
3604 "Couldn't parse " + files.get(f) + " as a link file.",
3613 * Sets the Preferences property for experimental features to True or False
3614 * depending on the state of the controlling menu item
3617 protected void showExperimental_actionPerformed(boolean selected)
3619 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3623 * Answers a (possibly empty) list of any structure viewer frames (currently
3624 * for either Jmol or Chimera) which are currently open. This may optionally
3625 * be restricted to viewers of a specified class, or viewers linked to a
3626 * specified alignment panel.
3629 * if not null, only return viewers linked to this panel
3630 * @param structureViewerClass
3631 * if not null, only return viewers of this class
3634 public List<StructureViewerBase> getStructureViewers(
3635 AlignmentPanel apanel,
3636 Class<? extends StructureViewerBase> structureViewerClass)
3638 List<StructureViewerBase> result = new ArrayList<>();
3639 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3641 for (JInternalFrame frame : frames)
3643 if (frame instanceof StructureViewerBase)
3645 if (structureViewerClass == null
3646 || structureViewerClass.isInstance(frame))
3649 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3651 result.add((StructureViewerBase) frame);