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"));
357 // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
361 * change the line numbers
365 if (!Platform.isAMac())
367 // this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
372 // this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
373 java.awt.Desktop hdesktop = java.awt.Desktop.getDesktop();
375 hdesktop.setAboutHandler(new AboutHandler()
378 public void handleAbout(AboutEvent e)
380 aboutMenuItem_actionPerformed(null);
383 hdesktop.setPreferencesHandler(new PreferencesHandler()
386 public void handlePreferences(PreferencesEvent e)
388 preferences_actionPerformed(null);
391 hdesktop.setQuitHandler(new QuitHandler()
394 public void handleQuitRequestWith(QuitEvent e, QuitResponse r)
396 int n = JOptionPane.showConfirmDialog(null,
397 MessageManager.getString("label.quit_jalview"),
398 MessageManager.getString("action.quit"),
399 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
401 if (n == JOptionPane.OK_OPTION)
403 System.out.println("Shortcut Quit confirmed by user");
408 System.out.println("Shortcut Quit cancelled by user");
415 addWindowListener(new WindowAdapter()
419 public void windowClosing(WindowEvent ev)
425 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
428 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
430 desktop = new MyDesktopPane(selmemusage);
431 showMemusage.setSelected(selmemusage);
432 desktop.setBackground(Color.white);
434 getContentPane().setLayout(new BorderLayout());
435 // alternate config - have scrollbars - see notes in JAL-153
436 // JScrollPane sp = new JScrollPane();
437 // sp.getViewport().setView(desktop);
438 // getContentPane().add(sp, BorderLayout.CENTER);
439 getContentPane().add(desktop, BorderLayout.CENTER);
440 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
442 // This line prevents Windows Look&Feel resizing all new windows to maximum
443 // if previous window was maximised
444 desktop.setDesktopManager(new MyDesktopManager(
445 (Platform.isWindows() ? new DefaultDesktopManager()
447 ? new AquaInternalFrameManager(
448 desktop.getDesktopManager())
449 : desktop.getDesktopManager())));
451 Rectangle dims = getLastKnownDimensions("");
458 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
459 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
462 jconsole = new Console(this, showjconsole);
463 // add essential build information
465 "Jalview Version: " + jalview.bin.Cache.getProperty("VERSION")
466 + "\n" + "Jalview Installation: "
467 + jalview.bin.Cache.getDefault("INSTALLATION",
469 + "\n" + "Build Date: "
470 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
471 + "\n" + "Java version: "
472 + System.getProperty("java.version") + "\n"
473 + System.getProperty("os.arch") + " "
474 + System.getProperty("os.name") + " "
475 + System.getProperty("os.version"));
477 showConsole(showjconsole);
479 showNews.setVisible(false);
481 experimentalFeatures.setSelected(showExperimental());
483 getIdentifiersOrgData();
487 this.addWindowListener(new WindowAdapter()
490 public void windowClosing(WindowEvent evt)
497 this.addMouseListener(ma = new MouseAdapter()
500 public void mousePressed(MouseEvent evt)
502 if (evt.isPopupTrigger()) // Mac
504 showPasteMenu(evt.getX(), evt.getY());
509 public void mouseReleased(MouseEvent evt)
511 if (evt.isPopupTrigger()) // Windows
513 showPasteMenu(evt.getX(), evt.getY());
517 desktop.addMouseListener(ma);
519 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
520 // Spawn a thread that shows the splashscreen
521 SwingUtilities.invokeLater(new Runnable()
530 // Thread off a new instance of the file chooser - this reduces the time it
531 // takes to open it later on.
532 new Thread(new Runnable()
537 Cache.log.debug("Filechooser init thread started.");
538 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
539 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
541 Cache.log.debug("Filechooser init thread finished.");
544 // Add the service change listener
545 changeSupport.addJalviewPropertyChangeListener("services",
546 new PropertyChangeListener()
550 public void propertyChange(PropertyChangeEvent evt)
552 Cache.log.debug("Firing service changed event for "
553 + evt.getNewValue());
554 JalviewServicesChanged(evt);
561 * Answers true if user preferences to enable experimental features is True
566 public boolean showExperimental()
568 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
569 Boolean.FALSE.toString());
570 return Boolean.valueOf(experimental).booleanValue();
573 public void doConfigureStructurePrefs()
575 // configure services
576 StructureSelectionManager ssm = StructureSelectionManager
577 .getStructureSelectionManager(this);
578 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
580 ssm.setAddTempFacAnnot(jalview.bin.Cache
581 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
582 ssm.setProcessSecondaryStructure(jalview.bin.Cache
583 .getDefault(Preferences.STRUCT_FROM_PDB, true));
584 ssm.setSecStructServices(
585 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
589 ssm.setAddTempFacAnnot(false);
590 ssm.setProcessSecondaryStructure(false);
591 ssm.setSecStructServices(false);
595 public void checkForNews()
597 final Desktop me = this;
598 // Thread off the news reader, in case there are connection problems.
599 new Thread(new Runnable()
604 Cache.log.debug("Starting news thread.");
606 jvnews = new BlogReader(me);
607 showNews.setVisible(true);
608 Cache.log.debug("Completed news thread.");
613 public void getIdentifiersOrgData()
615 // Thread off the identifiers fetcher
616 new Thread(new Runnable()
621 Cache.log.debug("Downloading data from identifiers.org");
622 UrlDownloadClient client = new UrlDownloadClient();
625 client.download(IdOrgSettings.getUrl(),
626 IdOrgSettings.getDownloadLocation());
627 } catch (IOException e)
629 Cache.log.debug("Exception downloading identifiers.org data"
638 protected void showNews_actionPerformed(ActionEvent e)
640 showNews(showNews.isSelected());
643 void showNews(boolean visible)
646 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
647 showNews.setSelected(visible);
648 if (visible && !jvnews.isVisible())
650 new Thread(new Runnable()
655 long now = System.currentTimeMillis();
656 Desktop.instance.setProgressBar(
657 MessageManager.getString("status.refreshing_news"),
659 jvnews.refreshNews();
660 Desktop.instance.setProgressBar(null, now);
669 * recover the last known dimensions for a jalview window
672 * - empty string is desktop, all other windows have unique prefix
673 * @return null or last known dimensions scaled to current geometry (if last
674 * window geom was known)
676 Rectangle getLastKnownDimensions(String windowName)
678 // TODO: lock aspect ratio for scaling desktop Bug #0058199
679 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
680 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
681 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
682 String width = jalview.bin.Cache
683 .getProperty(windowName + "SCREEN_WIDTH");
684 String height = jalview.bin.Cache
685 .getProperty(windowName + "SCREEN_HEIGHT");
686 if ((x != null) && (y != null) && (width != null) && (height != null))
688 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
689 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
690 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
692 // attempt #1 - try to cope with change in screen geometry - this
693 // version doesn't preserve original jv aspect ratio.
694 // take ratio of current screen size vs original screen size.
695 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
696 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
697 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
698 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
699 // rescale the bounds depending upon the current screen geometry.
700 ix = (int) (ix * sw);
701 iw = (int) (iw * sw);
702 iy = (int) (iy * sh);
703 ih = (int) (ih * sh);
704 while (ix >= screenSize.width)
706 jalview.bin.Cache.log.debug(
707 "Window geometry location recall error: shifting horizontal to within screenbounds.");
708 ix -= screenSize.width;
710 while (iy >= screenSize.height)
712 jalview.bin.Cache.log.debug(
713 "Window geometry location recall error: shifting vertical to within screenbounds.");
714 iy -= screenSize.height;
716 jalview.bin.Cache.log.debug(
717 "Got last known dimensions for " + windowName + ": x:" + ix
718 + " y:" + iy + " width:" + iw + " height:" + ih);
720 // return dimensions for new instance
721 return new Rectangle(ix, iy, iw, ih);
726 private void doVamsasClientCheck()
728 if (jalview.bin.Cache.vamsasJarsPresent())
730 setupVamsasDisconnectedGui();
731 VamsasMenu.setVisible(true);
732 final Desktop us = this;
733 VamsasMenu.addMenuListener(new MenuListener()
735 // this listener remembers when the menu was first selected, and
736 // doesn't rebuild the session list until it has been cleared and
738 boolean refresh = true;
741 public void menuCanceled(MenuEvent e)
747 public void menuDeselected(MenuEvent e)
753 public void menuSelected(MenuEvent e)
757 us.buildVamsasStMenu();
762 vamsasStart.setVisible(true);
766 void showPasteMenu(int x, int y)
768 JPopupMenu popup = new JPopupMenu();
769 JMenuItem item = new JMenuItem(
770 MessageManager.getString("label.paste_new_window"));
771 item.addActionListener(new ActionListener()
774 public void actionPerformed(ActionEvent evt)
781 popup.show(this, x, y);
788 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
789 Transferable contents = c.getContents(this);
791 if (contents != null)
793 String file = (String) contents
794 .getTransferData(DataFlavor.stringFlavor);
796 FileFormatI format = new IdentifyFile().identify(file,
797 DataSourceType.PASTE);
799 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
802 } catch (Exception ex)
805 "Unable to paste alignment from system clipboard:\n" + ex);
810 * Adds and opens the given frame to the desktop
821 public static synchronized void addInternalFrame(
822 final JInternalFrame frame, String title, int w, int h)
824 addInternalFrame(frame, title, true, w, h, true, false);
828 * Add an internal frame to the Jalview desktop
835 * When true, display frame immediately, otherwise, caller must call
836 * setVisible themselves.
842 public static synchronized void addInternalFrame(
843 final JInternalFrame frame, String title, boolean makeVisible,
846 addInternalFrame(frame, title, makeVisible, w, h, true, false);
850 * Add an internal frame to the Jalview desktop and make it visible
863 public static synchronized void addInternalFrame(
864 final JInternalFrame frame, String title, int w, int h,
867 addInternalFrame(frame, title, true, w, h, resizable, false);
871 * Add an internal frame to the Jalview desktop
878 * When true, display frame immediately, otherwise, caller must call
879 * setVisible themselves.
886 * @param ignoreMinSize
887 * Do not set the default minimum size for frame
889 public static synchronized void addInternalFrame(
890 final JInternalFrame frame, String title, boolean makeVisible,
891 int w, int h, boolean resizable, boolean ignoreMinSize)
894 // TODO: allow callers to determine X and Y position of frame (eg. via
896 // TODO: consider fixing method to update entries in the window submenu with
897 // the current window title
899 frame.setTitle(title);
900 if (frame.getWidth() < 1 || frame.getHeight() < 1)
904 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
905 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
906 // IF JALVIEW IS RUNNING HEADLESS
907 // ///////////////////////////////////////////////
908 if (instance == null || (System.getProperty("java.awt.headless") != null
909 && System.getProperty("java.awt.headless").equals("true")))
918 frame.setMinimumSize(
919 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
921 // Set default dimension for Alignment Frame window.
922 // The Alignment Frame window could be added from a number of places,
924 // I did this here in order not to miss out on any Alignment frame.
925 if (frame instanceof AlignFrame)
927 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
928 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
932 frame.setVisible(makeVisible);
933 frame.setClosable(true);
934 frame.setResizable(resizable);
935 frame.setMaximizable(resizable);
936 frame.setIconifiable(resizable);
937 frame.setOpaque(false);
939 if (frame.getX() < 1 && frame.getY() < 1)
941 frame.setLocation(xOffset * openFrameCount,
942 yOffset * ((openFrameCount - 1) % 10) + yOffset);
946 * add an entry for the new frame in the Window menu
947 * (and remove it when the frame is closed)
949 final JMenuItem menuItem = new JMenuItem(title);
950 frame.addInternalFrameListener(new InternalFrameAdapter()
953 public void internalFrameActivated(InternalFrameEvent evt)
955 JInternalFrame itf = desktop.getSelectedFrame();
958 if (itf instanceof AlignFrame)
960 Jalview.setCurrentAlignFrame((AlignFrame) itf);
967 public void internalFrameClosed(InternalFrameEvent evt)
969 PaintRefresher.RemoveComponent(frame);
972 * defensive check to prevent frames being
973 * added half off the window
975 if (openFrameCount > 0)
981 * ensure no reference to alignFrame retained by menu item listener
983 if (menuItem.getActionListeners().length > 0)
985 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
987 windowMenu.remove(menuItem);
991 menuItem.addActionListener(new ActionListener()
994 public void actionPerformed(ActionEvent e)
998 frame.setSelected(true);
999 frame.setIcon(false);
1000 } catch (java.beans.PropertyVetoException ex)
1007 setKeyBindings(frame);
1011 windowMenu.add(menuItem);
1016 frame.setSelected(true);
1017 frame.requestFocus();
1018 } catch (java.beans.PropertyVetoException ve)
1020 } catch (java.lang.ClassCastException cex)
1023 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
1029 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
1034 private static void setKeyBindings(JInternalFrame frame)
1036 @SuppressWarnings("serial")
1037 final Action closeAction = new AbstractAction()
1040 public void actionPerformed(ActionEvent e)
1047 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
1049 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1050 InputEvent.CTRL_DOWN_MASK);
1051 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
1052 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1054 InputMap inputMap = frame
1055 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1056 String ctrlW = ctrlWKey.toString();
1057 inputMap.put(ctrlWKey, ctrlW);
1058 inputMap.put(cmdWKey, ctrlW);
1060 ActionMap actionMap = frame.getActionMap();
1061 actionMap.put(ctrlW, closeAction);
1065 public void lostOwnership(Clipboard clipboard, Transferable contents)
1069 Desktop.jalviewClipboard = null;
1072 internalCopy = false;
1076 public void dragEnter(DropTargetDragEvent evt)
1081 public void dragExit(DropTargetEvent evt)
1086 public void dragOver(DropTargetDragEvent evt)
1091 public void dropActionChanged(DropTargetDragEvent evt)
1102 public void drop(DropTargetDropEvent evt)
1104 boolean success = true;
1105 // JAL-1552 - acceptDrop required before getTransferable call for
1106 // Java's Transferable for native dnd
1107 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1108 Transferable t = evt.getTransferable();
1109 List<String> files = new ArrayList<>();
1110 List<DataSourceType> protocols = new ArrayList<>();
1114 Desktop.transferFromDropTarget(files, protocols, evt, t);
1115 } catch (Exception e)
1117 e.printStackTrace();
1125 for (int i = 0; i < files.size(); i++)
1127 String file = files.get(i).toString();
1128 DataSourceType protocol = (protocols == null)
1129 ? DataSourceType.FILE
1131 FileFormatI format = null;
1133 if (file.endsWith(".jar"))
1135 format = FileFormat.Jalview;
1140 format = new IdentifyFile().identify(file, protocol);
1143 new FileLoader().LoadFile(file, protocol, format);
1146 } catch (Exception ex)
1151 evt.dropComplete(success); // need this to ensure input focus is properly
1152 // transfered to any new windows created
1162 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1164 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1165 JalviewFileChooser chooser = JalviewFileChooser
1166 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1168 chooser.setFileView(new JalviewFileView());
1169 chooser.setDialogTitle(
1170 MessageManager.getString("label.open_local_file"));
1171 chooser.setToolTipText(MessageManager.getString("action.open"));
1173 int value = chooser.showOpenDialog(this);
1175 if (value == JalviewFileChooser.APPROVE_OPTION)
1177 String choice = chooser.getSelectedFile().getPath();
1178 Cache.setProperty("LAST_DIRECTORY",
1179 chooser.getSelectedFile().getParent());
1181 FileFormatI format = chooser.getSelectedFormat();
1184 * Call IdentifyFile to verify the file contains what its extension implies.
1185 * Skip this step for dynamically added file formats, because
1186 * IdentifyFile does not know how to recognise them.
1188 if (FileFormats.getInstance().isIdentifiable(format))
1192 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1193 } catch (FileFormatException e)
1195 // format = null; //??
1199 if (viewport != null)
1201 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1206 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1218 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1220 // This construct allows us to have a wider textfield
1222 JLabel label = new JLabel(
1223 MessageManager.getString("label.input_file_url"));
1224 final JComboBox history = new JComboBox();
1226 JPanel panel = new JPanel(new GridLayout(2, 1));
1229 history.setPreferredSize(new Dimension(400, 20));
1230 history.setEditable(true);
1231 history.addItem("http://www.");
1233 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1237 if (historyItems != null)
1239 st = new StringTokenizer(historyItems, "\t");
1241 while (st.hasMoreTokens())
1243 history.addItem(st.nextElement());
1247 int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
1248 MessageManager.getString("label.input_alignment_from_url"),
1249 JvOptionPane.OK_CANCEL_OPTION);
1251 if (reply != JvOptionPane.OK_OPTION)
1256 String url = history.getSelectedItem().toString();
1258 if (url.toLowerCase().endsWith(".jar"))
1260 if (viewport != null)
1262 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1263 FileFormat.Jalview);
1267 new FileLoader().LoadFile(url, DataSourceType.URL,
1268 FileFormat.Jalview);
1273 FileFormatI format = null;
1276 format = new IdentifyFile().identify(url, DataSourceType.URL);
1277 } catch (FileFormatException e)
1279 // TODO revise error handling, distinguish between
1280 // URL not found and response not valid
1285 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1286 MessageManager.formatMessage("label.couldnt_locate",
1289 MessageManager.getString("label.url_not_found"),
1290 JvOptionPane.WARNING_MESSAGE);
1295 if (viewport != null)
1297 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
1302 new FileLoader().LoadFile(url, DataSourceType.URL, format);
1308 * Opens the CutAndPaste window for the user to paste an alignment in to
1311 * - if not null, the pasted alignment is added to the current
1312 * alignment; if null, to a new alignment window
1315 public void inputTextboxMenuItem_actionPerformed(
1316 AlignmentViewPanel viewPanel)
1318 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1319 cap.setForInput(viewPanel);
1320 Desktop.addInternalFrame(cap,
1321 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1331 System.out.println("********** Desktop.quit()");
1332 System.out.println(savingFiles.toString());
1333 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1334 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1336 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1337 screen.height + "");
1338 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1339 getWidth(), getHeight()));
1341 if (jconsole != null)
1343 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1344 jconsole.stopConsole();
1348 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1351 if (dialogExecutor != null)
1353 dialogExecutor.shutdownNow();
1355 closeAll_actionPerformed(null);
1357 if (groovyConsole != null)
1359 // suppress a possible repeat prompt to save script
1360 groovyConsole.setDirty(false);
1361 groovyConsole.exit();
1366 private void storeLastKnownDimensions(String string, Rectangle jc)
1368 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1369 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1370 + " height:" + jc.height);
1372 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1373 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1374 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1375 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1385 public void aboutMenuItem_actionPerformed(ActionEvent e)
1387 // StringBuffer message = getAboutMessage(false);
1388 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1390 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1391 new Thread(new Runnable()
1396 new SplashScreen(true);
1401 public StringBuffer getAboutMessage(boolean shortv)
1403 StringBuffer message = new StringBuffer();
1404 message.append("<html>");
1407 message.append("<h1><strong>Version: "
1408 + jalview.bin.Cache.getProperty("VERSION")
1409 + "</strong></h1>");
1410 message.append("<strong>Last Updated: <em>"
1411 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1412 + "</em></strong>");
1418 message.append("<strong>Version "
1419 + jalview.bin.Cache.getProperty("VERSION")
1420 + "; last updated: "
1421 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1424 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1425 .equals("Checking"))
1427 message.append("<br>...Checking latest version...</br>");
1429 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1430 .equals(jalview.bin.Cache.getProperty("VERSION")))
1432 boolean red = false;
1433 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1434 .indexOf("automated build") == -1)
1437 // Displayed when code version and jnlp version do not match and code
1438 // version is not a development build
1439 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1442 message.append("<br>!! Version "
1443 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1445 + " is available for download from "
1446 + jalview.bin.Cache.getDefault("www.jalview.org",
1447 "http://www.jalview.org")
1451 message.append("</div>");
1454 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1456 "The Jalview Authors (See AUTHORS file for current list)")
1457 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1458 + "<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"
1459 + "<br><br>If you use Jalview, please cite:"
1460 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1461 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1462 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1474 public void documentationMenuItem_actionPerformed(ActionEvent e)
1478 Help.showHelpWindow();
1479 } catch (Exception ex)
1485 public void closeAll_actionPerformed(ActionEvent e)
1487 // TODO show a progress bar while closing?
1488 JInternalFrame[] frames = desktop.getAllFrames();
1489 for (int i = 0; i < frames.length; i++)
1493 frames[i].setClosed(true);
1494 } catch (java.beans.PropertyVetoException ex)
1498 Jalview.setCurrentAlignFrame(null);
1499 System.out.println("ALL CLOSED");
1500 if (v_client != null)
1502 // TODO clear binding to vamsas document objects on close_all
1506 * reset state of singleton objects as appropriate (clear down session state
1507 * when all windows are closed)
1509 StructureSelectionManager ssm = StructureSelectionManager
1510 .getStructureSelectionManager(this);
1518 public void raiseRelated_actionPerformed(ActionEvent e)
1520 reorderAssociatedWindows(false, false);
1524 public void minimizeAssociated_actionPerformed(ActionEvent e)
1526 reorderAssociatedWindows(true, false);
1529 void closeAssociatedWindows()
1531 reorderAssociatedWindows(false, true);
1537 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1541 protected void garbageCollect_actionPerformed(ActionEvent e)
1543 // We simply collect the garbage
1544 jalview.bin.Cache.log.debug("Collecting garbage...");
1546 jalview.bin.Cache.log.debug("Finished garbage collection.");
1553 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1557 protected void showMemusage_actionPerformed(ActionEvent e)
1559 desktop.showMemoryUsage(showMemusage.isSelected());
1566 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1570 protected void showConsole_actionPerformed(ActionEvent e)
1572 showConsole(showConsole.isSelected());
1575 Console jconsole = null;
1578 * control whether the java console is visible or not
1582 void showConsole(boolean selected)
1584 showConsole.setSelected(selected);
1585 // TODO: decide if we should update properties file
1586 Cache.setProperty("SHOW_JAVA_CONSOLE",
1587 Boolean.valueOf(selected).toString());
1588 jconsole.setVisible(selected);
1591 void reorderAssociatedWindows(boolean minimize, boolean close)
1593 JInternalFrame[] frames = desktop.getAllFrames();
1594 if (frames == null || frames.length < 1)
1599 AlignmentViewport source = null, target = null;
1600 if (frames[0] instanceof AlignFrame)
1602 source = ((AlignFrame) frames[0]).getCurrentView();
1604 else if (frames[0] instanceof TreePanel)
1606 source = ((TreePanel) frames[0]).getViewPort();
1608 else if (frames[0] instanceof PCAPanel)
1610 source = ((PCAPanel) frames[0]).av;
1612 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1614 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1619 for (int i = 0; i < frames.length; i++)
1622 if (frames[i] == null)
1626 if (frames[i] instanceof AlignFrame)
1628 target = ((AlignFrame) frames[i]).getCurrentView();
1630 else if (frames[i] instanceof TreePanel)
1632 target = ((TreePanel) frames[i]).getViewPort();
1634 else if (frames[i] instanceof PCAPanel)
1636 target = ((PCAPanel) frames[i]).av;
1638 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1640 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1643 if (source == target)
1649 frames[i].setClosed(true);
1653 frames[i].setIcon(minimize);
1656 frames[i].toFront();
1660 } catch (java.beans.PropertyVetoException ex)
1675 protected void preferences_actionPerformed(ActionEvent e)
1687 public void saveState_actionPerformed(ActionEvent e)
1689 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1692 chooser.setFileView(new JalviewFileView());
1693 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1695 int value = chooser.showSaveDialog(this);
1697 if (value == JalviewFileChooser.APPROVE_OPTION)
1699 final Desktop me = this;
1700 final java.io.File choice = chooser.getSelectedFile();
1701 setProjectFile(choice);
1703 new Thread(new Runnable()
1708 // TODO: refactor to Jalview desktop session controller action.
1709 setProgressBar(MessageManager.formatMessage(
1710 "label.saving_jalview_project", new Object[]
1711 { choice.getName() }), choice.hashCode());
1712 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1713 choice.getParent());
1714 // TODO catch and handle errors for savestate
1715 // TODO prevent user from messing with the Desktop whilst we're saving
1718 new Jalview2XML().saveState(choice);
1719 } catch (OutOfMemoryError oom)
1722 "Whilst saving current state to " + choice.getName(),
1724 } catch (Exception ex)
1727 "Problems whilst trying to save to " + choice.getName(),
1729 JvOptionPane.showMessageDialog(me,
1730 MessageManager.formatMessage(
1731 "label.error_whilst_saving_current_state_to",
1733 { choice.getName() }),
1734 MessageManager.getString("label.couldnt_save_project"),
1735 JvOptionPane.WARNING_MESSAGE);
1737 setProgressBar(null, choice.hashCode());
1743 private void setProjectFile(File choice)
1745 this.projectFile = choice;
1748 public File getProjectFile()
1750 return this.projectFile;
1760 public void loadState_actionPerformed(ActionEvent e)
1762 JalviewFileChooser chooser = new JalviewFileChooser(
1763 Cache.getProperty("LAST_DIRECTORY"), new String[]
1766 { "Jalview Project", "Jalview Project (old)" },
1768 chooser.setFileView(new JalviewFileView());
1769 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1771 int value = chooser.showOpenDialog(this);
1773 if (value == JalviewFileChooser.APPROVE_OPTION)
1775 final File selectedFile = chooser.getSelectedFile();
1776 setProjectFile(selectedFile);
1777 final String choice = selectedFile.getAbsolutePath();
1778 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1779 new Thread(new Runnable()
1784 setProgressBar(MessageManager.formatMessage(
1785 "label.loading_jalview_project", new Object[]
1786 { choice }), choice.hashCode());
1789 new Jalview2XML().loadJalviewAlign(choice);
1790 } catch (OutOfMemoryError oom)
1792 new OOMWarning("Whilst loading project from " + choice, oom);
1793 } catch (Exception ex)
1796 "Problems whilst loading project from " + choice, ex);
1797 JvOptionPane.showMessageDialog(Desktop.desktop,
1798 MessageManager.formatMessage(
1799 "label.error_whilst_loading_project_from",
1802 MessageManager.getString("label.couldnt_load_project"),
1803 JvOptionPane.WARNING_MESSAGE);
1805 setProgressBar(null, choice.hashCode());
1812 public void inputSequence_actionPerformed(ActionEvent e)
1814 new SequenceFetcher(this);
1817 JPanel progressPanel;
1819 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1821 public void startLoading(final String fileName)
1823 if (fileLoadingCount == 0)
1825 fileLoadingPanels.add(addProgressPanel(MessageManager
1826 .formatMessage("label.loading_file", new Object[]
1832 private JPanel addProgressPanel(String string)
1834 if (progressPanel == null)
1836 progressPanel = new JPanel(new GridLayout(1, 1));
1837 totalProgressCount = 0;
1838 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1840 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1841 JProgressBar progressBar = new JProgressBar();
1842 progressBar.setIndeterminate(true);
1844 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1846 thisprogress.add(progressBar, BorderLayout.CENTER);
1847 progressPanel.add(thisprogress);
1848 ((GridLayout) progressPanel.getLayout()).setRows(
1849 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1850 ++totalProgressCount;
1851 instance.validate();
1852 return thisprogress;
1855 int totalProgressCount = 0;
1857 private void removeProgressPanel(JPanel progbar)
1859 if (progressPanel != null)
1861 synchronized (progressPanel)
1863 progressPanel.remove(progbar);
1864 GridLayout gl = (GridLayout) progressPanel.getLayout();
1865 gl.setRows(gl.getRows() - 1);
1866 if (--totalProgressCount < 1)
1868 this.getContentPane().remove(progressPanel);
1869 progressPanel = null;
1876 public void stopLoading()
1879 if (fileLoadingCount < 1)
1881 while (fileLoadingPanels.size() > 0)
1883 removeProgressPanel(fileLoadingPanels.remove(0));
1885 fileLoadingPanels.clear();
1886 fileLoadingCount = 0;
1891 public static int getViewCount(String alignmentId)
1893 AlignmentViewport[] aps = getViewports(alignmentId);
1894 return (aps == null) ? 0 : aps.length;
1899 * @param alignmentId
1900 * - if null, all sets are returned
1901 * @return all AlignmentPanels concerning the alignmentId sequence set
1903 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1905 if (Desktop.desktop == null)
1907 // no frames created and in headless mode
1908 // TODO: verify that frames are recoverable when in headless mode
1911 List<AlignmentPanel> aps = new ArrayList<>();
1912 AlignFrame[] frames = getAlignFrames();
1917 for (AlignFrame af : frames)
1919 for (AlignmentPanel ap : af.alignPanels)
1921 if (alignmentId == null
1922 || alignmentId.equals(ap.av.getSequenceSetId()))
1928 if (aps.size() == 0)
1932 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1937 * get all the viewports on an alignment.
1939 * @param sequenceSetId
1940 * unique alignment id (may be null - all viewports returned in that
1942 * @return all viewports on the alignment bound to sequenceSetId
1944 public static AlignmentViewport[] getViewports(String sequenceSetId)
1946 List<AlignmentViewport> viewp = new ArrayList<>();
1947 if (desktop != null)
1949 AlignFrame[] frames = Desktop.getAlignFrames();
1951 for (AlignFrame afr : frames)
1953 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1954 .equals(sequenceSetId))
1956 if (afr.alignPanels != null)
1958 for (AlignmentPanel ap : afr.alignPanels)
1960 if (sequenceSetId == null
1961 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1969 viewp.add(afr.getViewport());
1973 if (viewp.size() > 0)
1975 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1982 * Explode the views in the given frame into separate AlignFrame
1986 public static void explodeViews(AlignFrame af)
1988 int size = af.alignPanels.size();
1994 for (int i = 0; i < size; i++)
1996 AlignmentPanel ap = af.alignPanels.get(i);
1997 AlignFrame newaf = new AlignFrame(ap);
2000 * Restore the view's last exploded frame geometry if known. Multiple
2001 * views from one exploded frame share and restore the same (frame)
2002 * position and size.
2004 Rectangle geometry = ap.av.getExplodedGeometry();
2005 if (geometry != null)
2007 newaf.setBounds(geometry);
2010 ap.av.setGatherViewsHere(false);
2012 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
2013 AlignFrame.DEFAULT_HEIGHT);
2016 af.alignPanels.clear();
2017 af.closeMenuItem_actionPerformed(true);
2022 * Gather expanded views (separate AlignFrame's) with the same sequence set
2023 * identifier back in to this frame as additional views, and close the
2024 * expanded views. Note the expanded frames may themselves have multiple
2025 * views. We take the lot.
2029 public void gatherViews(AlignFrame source)
2031 source.viewport.setGatherViewsHere(true);
2032 source.viewport.setExplodedGeometry(source.getBounds());
2033 JInternalFrame[] frames = desktop.getAllFrames();
2034 String viewId = source.viewport.getSequenceSetId();
2036 for (int t = 0; t < frames.length; t++)
2038 if (frames[t] instanceof AlignFrame && frames[t] != source)
2040 AlignFrame af = (AlignFrame) frames[t];
2041 boolean gatherThis = false;
2042 for (int a = 0; a < af.alignPanels.size(); a++)
2044 AlignmentPanel ap = af.alignPanels.get(a);
2045 if (viewId.equals(ap.av.getSequenceSetId()))
2048 ap.av.setGatherViewsHere(false);
2049 ap.av.setExplodedGeometry(af.getBounds());
2050 source.addAlignmentPanel(ap, false);
2056 af.alignPanels.clear();
2057 af.closeMenuItem_actionPerformed(true);
2064 jalview.gui.VamsasApplication v_client = null;
2067 public void vamsasImport_actionPerformed(ActionEvent e)
2069 if (v_client == null)
2071 // Load and try to start a session.
2072 JalviewFileChooser chooser = new JalviewFileChooser(
2073 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
2075 chooser.setFileView(new JalviewFileView());
2076 chooser.setDialogTitle(
2077 MessageManager.getString("label.open_saved_vamsas_session"));
2078 chooser.setToolTipText(MessageManager.getString(
2079 "label.select_vamsas_session_opened_as_new_vamsas_session"));
2081 int value = chooser.showOpenDialog(this);
2083 if (value == JalviewFileChooser.APPROVE_OPTION)
2085 String fle = chooser.getSelectedFile().toString();
2086 if (!vamsasImport(chooser.getSelectedFile()))
2088 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2089 MessageManager.formatMessage(
2090 "label.couldnt_import_as_vamsas_session",
2094 .getString("label.vamsas_document_import_failed"),
2095 JvOptionPane.ERROR_MESSAGE);
2101 jalview.bin.Cache.log.error(
2102 "Implementation error - load session from a running session is not supported.");
2107 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2110 * @return true if import was a success and a session was started.
2112 public boolean vamsasImport(URL url)
2114 // TODO: create progress bar
2115 if (v_client != null)
2118 jalview.bin.Cache.log.error(
2119 "Implementation error - load session from a running session is not supported.");
2125 // copy the URL content to a temporary local file
2126 // TODO: be a bit cleverer here with nio (?!)
2127 File file = File.createTempFile("vdocfromurl", ".vdj");
2128 FileOutputStream fos = new FileOutputStream(file);
2129 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2130 byte[] buffer = new byte[2048];
2132 while ((ln = bis.read(buffer)) > -1)
2134 fos.write(buffer, 0, ln);
2138 v_client = new jalview.gui.VamsasApplication(this, file,
2139 url.toExternalForm());
2140 } catch (Exception ex)
2142 jalview.bin.Cache.log.error(
2143 "Failed to create new vamsas session from contents of URL "
2148 setupVamsasConnectedGui();
2149 v_client.initial_update(); // TODO: thread ?
2150 return v_client.inSession();
2154 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2157 * @return true if import was a success and a session was started.
2159 public boolean vamsasImport(File file)
2161 if (v_client != null)
2164 jalview.bin.Cache.log.error(
2165 "Implementation error - load session from a running session is not supported.");
2169 setProgressBar(MessageManager.formatMessage(
2170 "status.importing_vamsas_session_from", new Object[]
2171 { file.getName() }), file.hashCode());
2174 v_client = new jalview.gui.VamsasApplication(this, file, null);
2175 } catch (Exception ex)
2177 setProgressBar(MessageManager.formatMessage(
2178 "status.importing_vamsas_session_from", new Object[]
2179 { file.getName() }), file.hashCode());
2180 jalview.bin.Cache.log.error(
2181 "New vamsas session from existing session file failed:", ex);
2184 setupVamsasConnectedGui();
2185 v_client.initial_update(); // TODO: thread ?
2186 setProgressBar(MessageManager.formatMessage(
2187 "status.importing_vamsas_session_from", new Object[]
2188 { file.getName() }), file.hashCode());
2189 return v_client.inSession();
2192 public boolean joinVamsasSession(String mysesid)
2194 if (v_client != null)
2196 throw new Error(MessageManager
2197 .getString("error.try_join_vamsas_session_another"));
2199 if (mysesid == null)
2202 MessageManager.getString("error.invalid_vamsas_session_id"));
2204 v_client = new VamsasApplication(this, mysesid);
2205 setupVamsasConnectedGui();
2206 v_client.initial_update();
2207 return (v_client.inSession());
2211 public void vamsasStart_actionPerformed(ActionEvent e)
2213 if (v_client == null)
2216 // we just start a default session for moment.
2218 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2219 * getProperty("LAST_DIRECTORY"));
2221 * chooser.setFileView(new JalviewFileView());
2222 * chooser.setDialogTitle("Load Vamsas file");
2223 * chooser.setToolTipText("Import");
2225 * int value = chooser.showOpenDialog(this);
2227 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2228 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2230 v_client = new VamsasApplication(this);
2231 setupVamsasConnectedGui();
2232 v_client.initial_update(); // TODO: thread ?
2236 // store current data in session.
2237 v_client.push_update(); // TODO: thread
2241 protected void setupVamsasConnectedGui()
2243 vamsasStart.setText(MessageManager.getString("label.session_update"));
2244 vamsasSave.setVisible(true);
2245 vamsasStop.setVisible(true);
2246 vamsasImport.setVisible(false); // Document import to existing session is
2247 // not possible for vamsas-client-1.0.
2250 protected void setupVamsasDisconnectedGui()
2252 vamsasSave.setVisible(false);
2253 vamsasStop.setVisible(false);
2254 vamsasImport.setVisible(true);
2256 .setText(MessageManager.getString("label.new_vamsas_session"));
2260 public void vamsasStop_actionPerformed(ActionEvent e)
2262 if (v_client != null)
2264 v_client.end_session();
2266 setupVamsasDisconnectedGui();
2270 protected void buildVamsasStMenu()
2272 if (v_client == null)
2274 String[] sess = null;
2277 sess = VamsasApplication.getSessionList();
2278 } catch (Exception e)
2280 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2286 jalview.bin.Cache.log.debug(
2287 "Got current sessions list: " + sess.length + " entries.");
2288 VamsasStMenu.removeAll();
2289 for (int i = 0; i < sess.length; i++)
2291 JMenuItem sessit = new JMenuItem();
2292 sessit.setText(sess[i]);
2293 sessit.setToolTipText(MessageManager
2294 .formatMessage("label.connect_to_session", new Object[]
2296 final Desktop dsktp = this;
2297 final String mysesid = sess[i];
2298 sessit.addActionListener(new ActionListener()
2302 public void actionPerformed(ActionEvent e)
2304 if (dsktp.v_client == null)
2306 Thread rthr = new Thread(new Runnable()
2312 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2313 dsktp.setupVamsasConnectedGui();
2314 dsktp.v_client.initial_update();
2322 VamsasStMenu.add(sessit);
2324 // don't show an empty menu.
2325 VamsasStMenu.setVisible(sess.length > 0);
2330 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2331 VamsasStMenu.removeAll();
2332 VamsasStMenu.setVisible(false);
2337 // Not interested in the content. Just hide ourselves.
2338 VamsasStMenu.setVisible(false);
2343 public void vamsasSave_actionPerformed(ActionEvent e)
2345 if (v_client != null)
2347 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2348 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2351 chooser.setFileView(new JalviewFileView());
2352 chooser.setDialogTitle(MessageManager
2353 .getString("label.save_vamsas_document_archive"));
2355 int value = chooser.showSaveDialog(this);
2357 if (value == JalviewFileChooser.APPROVE_OPTION)
2359 java.io.File choice = chooser.getSelectedFile();
2360 JPanel progpanel = addProgressPanel(MessageManager
2361 .formatMessage("label.saving_vamsas_doc", new Object[]
2362 { choice.getName() }));
2363 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2364 String warnmsg = null;
2365 String warnttl = null;
2368 v_client.vclient.storeDocument(choice);
2371 warnttl = "Serious Problem saving Vamsas Document";
2372 warnmsg = ex.toString();
2373 jalview.bin.Cache.log
2374 .error("Error Whilst saving document to " + choice, ex);
2376 } catch (Exception ex)
2378 warnttl = "Problem saving Vamsas Document.";
2379 warnmsg = ex.toString();
2380 jalview.bin.Cache.log.warn(
2381 "Exception Whilst saving document to " + choice, ex);
2384 removeProgressPanel(progpanel);
2385 if (warnmsg != null)
2387 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2389 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2395 JPanel vamUpdate = null;
2398 * hide vamsas user gui bits when a vamsas document event is being handled.
2401 * true to hide gui, false to reveal gui
2403 public void setVamsasUpdate(boolean b)
2405 Cache.log.debug("Setting gui for Vamsas update "
2406 + (b ? "in progress" : "finished"));
2408 if (vamUpdate != null)
2410 this.removeProgressPanel(vamUpdate);
2414 vamUpdate = this.addProgressPanel(
2415 MessageManager.getString("label.updating_vamsas_session"));
2417 vamsasStart.setVisible(!b);
2418 vamsasStop.setVisible(!b);
2419 vamsasSave.setVisible(!b);
2422 public JInternalFrame[] getAllFrames()
2424 return desktop.getAllFrames();
2428 * Checks the given url to see if it gives a response indicating that the user
2429 * should be informed of a new questionnaire.
2433 public void checkForQuestionnaire(String url)
2435 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2436 // javax.swing.SwingUtilities.invokeLater(jvq);
2437 new Thread(jvq).start();
2440 public void checkURLLinks()
2442 // Thread off the URL link checker
2443 addDialogThread(new Runnable()
2448 if (Cache.getDefault("CHECKURLLINKS", true))
2450 // check what the actual links are - if it's just the default don't
2451 // bother with the warning
2452 List<String> links = Preferences.sequenceUrlLinks
2455 // only need to check links if there is one with a
2456 // SEQUENCE_ID which is not the default EMBL_EBI link
2457 ListIterator<String> li = links.listIterator();
2458 boolean check = false;
2459 List<JLabel> urls = new ArrayList<>();
2460 while (li.hasNext())
2462 String link = li.next();
2463 if (link.contains(jalview.util.UrlConstants.SEQUENCE_ID)
2464 && !UrlConstants.isDefaultString(link))
2467 int barPos = link.indexOf("|");
2468 String urlMsg = barPos == -1 ? link
2469 : link.substring(0, barPos) + ": "
2470 + link.substring(barPos + 1);
2471 urls.add(new JLabel(urlMsg));
2479 // ask user to check in case URL links use old style tokens
2480 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2481 JPanel msgPanel = new JPanel();
2482 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2483 msgPanel.add(Box.createVerticalGlue());
2484 JLabel msg = new JLabel(MessageManager
2485 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2486 JLabel msg2 = new JLabel(MessageManager
2487 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2489 for (JLabel url : urls)
2495 final JCheckBox jcb = new JCheckBox(
2496 MessageManager.getString("label.do_not_display_again"));
2497 jcb.addActionListener(new ActionListener()
2500 public void actionPerformed(ActionEvent e)
2502 // update Cache settings for "don't show this again"
2503 boolean showWarningAgain = !jcb.isSelected();
2504 Cache.setProperty("CHECKURLLINKS",
2505 Boolean.valueOf(showWarningAgain).toString());
2510 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2512 .getString("label.SEQUENCE_ID_no_longer_used"),
2513 JvOptionPane.WARNING_MESSAGE);
2520 * Proxy class for JDesktopPane which optionally displays the current memory
2521 * usage and highlights the desktop area with a red bar if free memory runs
2526 public class MyDesktopPane extends JDesktopPane implements Runnable
2529 private static final float ONE_MB = 1048576f;
2531 boolean showMemoryUsage = false;
2535 java.text.NumberFormat df;
2537 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2540 public MyDesktopPane(boolean showMemoryUsage)
2542 showMemoryUsage(showMemoryUsage);
2545 public void showMemoryUsage(boolean showMemory)
2547 this.showMemoryUsage = showMemory;
2550 Thread worker = new Thread(this);
2556 public boolean isShowMemoryUsage()
2558 return showMemoryUsage;
2564 df = java.text.NumberFormat.getNumberInstance();
2565 df.setMaximumFractionDigits(2);
2566 runtime = Runtime.getRuntime();
2568 while (showMemoryUsage)
2572 maxMemory = runtime.maxMemory() / ONE_MB;
2573 allocatedMemory = runtime.totalMemory() / ONE_MB;
2574 freeMemory = runtime.freeMemory() / ONE_MB;
2575 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2577 percentUsage = (totalFreeMemory / maxMemory) * 100;
2579 // if (percentUsage < 20)
2581 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2583 // instance.set.setBorder(border1);
2586 // sleep after showing usage
2588 } catch (Exception ex)
2590 ex.printStackTrace();
2596 public void paintComponent(Graphics g)
2598 if (showMemoryUsage && g != null && df != null)
2600 if (percentUsage < 20)
2602 g.setColor(Color.red);
2604 FontMetrics fm = g.getFontMetrics();
2607 g.drawString(MessageManager.formatMessage("label.memory_stats",
2609 { df.format(totalFreeMemory), df.format(maxMemory),
2610 df.format(percentUsage) }),
2611 10, getHeight() - fm.getHeight());
2618 * Accessor method to quickly get all the AlignmentFrames loaded.
2620 * @return an array of AlignFrame, or null if none found
2622 public static AlignFrame[] getAlignFrames()
2624 if (Jalview.isHeadlessMode())
2626 // Desktop.desktop is null in headless mode
2627 return new AlignFrame[] { Jalview.currentAlignFrame };
2630 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2636 List<AlignFrame> avp = new ArrayList<>();
2638 for (int i = frames.length - 1; i > -1; i--)
2640 if (frames[i] instanceof AlignFrame)
2642 avp.add((AlignFrame) frames[i]);
2644 else if (frames[i] instanceof SplitFrame)
2647 * Also check for a split frame containing an AlignFrame
2649 GSplitFrame sf = (GSplitFrame) frames[i];
2650 if (sf.getTopFrame() instanceof AlignFrame)
2652 avp.add((AlignFrame) sf.getTopFrame());
2654 if (sf.getBottomFrame() instanceof AlignFrame)
2656 avp.add((AlignFrame) sf.getBottomFrame());
2660 if (avp.size() == 0)
2664 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2669 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2673 public GStructureViewer[] getJmols()
2675 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2681 List<GStructureViewer> avp = new ArrayList<>();
2683 for (int i = frames.length - 1; i > -1; i--)
2685 if (frames[i] instanceof AppJmol)
2687 GStructureViewer af = (GStructureViewer) frames[i];
2691 if (avp.size() == 0)
2695 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2700 * Add Groovy Support to Jalview
2703 public void groovyShell_actionPerformed()
2707 openGroovyConsole();
2708 } catch (Exception ex)
2710 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2711 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2713 MessageManager.getString("label.couldnt_create_groovy_shell"),
2714 MessageManager.getString("label.groovy_support_failed"),
2715 JvOptionPane.ERROR_MESSAGE);
2720 * Open the Groovy console
2722 void openGroovyConsole()
2724 if (groovyConsole == null)
2726 groovyConsole = new groovy.ui.Console();
2727 groovyConsole.setVariable("Jalview", this);
2728 groovyConsole.run();
2731 * We allow only one console at a time, so that AlignFrame menu option
2732 * 'Calculate | Run Groovy script' is unambiguous.
2733 * Disable 'Groovy Console', and enable 'Run script', when the console is
2734 * opened, and the reverse when it is closed
2736 Window window = (Window) groovyConsole.getFrame();
2737 window.addWindowListener(new WindowAdapter()
2740 public void windowClosed(WindowEvent e)
2743 * rebind CMD-Q from Groovy Console to Jalview Quit
2746 enableExecuteGroovy(false);
2752 * show Groovy console window (after close and reopen)
2754 ((Window) groovyConsole.getFrame()).setVisible(true);
2757 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2758 * and disable opening a second console
2760 enableExecuteGroovy(true);
2764 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2765 * binding when opened
2767 protected void addQuitHandler()
2769 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2770 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2771 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2773 getRootPane().getActionMap().put("Quit", new AbstractAction()
2776 public void actionPerformed(ActionEvent e)
2784 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2787 * true if Groovy console is open
2789 public void enableExecuteGroovy(boolean enabled)
2792 * disable opening a second Groovy console
2793 * (or re-enable when the console is closed)
2795 groovyShell.setEnabled(!enabled);
2797 AlignFrame[] alignFrames = getAlignFrames();
2798 if (alignFrames != null)
2800 for (AlignFrame af : alignFrames)
2802 af.setGroovyEnabled(enabled);
2808 * Progress bars managed by the IProgressIndicator method.
2810 private Hashtable<Long, JPanel> progressBars;
2812 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2817 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2820 public void setProgressBar(String message, long id)
2822 if (progressBars == null)
2824 progressBars = new Hashtable<>();
2825 progressBarHandlers = new Hashtable<>();
2828 if (progressBars.get(new Long(id)) != null)
2830 JPanel panel = progressBars.remove(new Long(id));
2831 if (progressBarHandlers.contains(new Long(id)))
2833 progressBarHandlers.remove(new Long(id));
2835 removeProgressPanel(panel);
2839 progressBars.put(new Long(id), addProgressPanel(message));
2846 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2847 * jalview.gui.IProgressIndicatorHandler)
2850 public void registerHandler(final long id,
2851 final IProgressIndicatorHandler handler)
2853 if (progressBarHandlers == null
2854 || !progressBars.containsKey(new Long(id)))
2856 throw new Error(MessageManager.getString(
2857 "error.call_setprogressbar_before_registering_handler"));
2859 progressBarHandlers.put(new Long(id), handler);
2860 final JPanel progressPanel = progressBars.get(new Long(id));
2861 if (handler.canCancel())
2863 JButton cancel = new JButton(
2864 MessageManager.getString("action.cancel"));
2865 final IProgressIndicator us = this;
2866 cancel.addActionListener(new ActionListener()
2870 public void actionPerformed(ActionEvent e)
2872 handler.cancelActivity(id);
2873 us.setProgressBar(MessageManager
2874 .formatMessage("label.cancelled_params", new Object[]
2875 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2879 progressPanel.add(cancel, BorderLayout.EAST);
2885 * @return true if any progress bars are still active
2888 public boolean operationInProgress()
2890 if (progressBars != null && progressBars.size() > 0)
2898 * This will return the first AlignFrame holding the given viewport instance.
2899 * It will break if there are more than one AlignFrames viewing a particular
2903 * @return alignFrame for viewport
2905 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2907 if (desktop != null)
2909 AlignmentPanel[] aps = getAlignmentPanels(
2910 viewport.getSequenceSetId());
2911 for (int panel = 0; aps != null && panel < aps.length; panel++)
2913 if (aps[panel] != null && aps[panel].av == viewport)
2915 return aps[panel].alignFrame;
2922 public VamsasApplication getVamsasApplication()
2929 * flag set if jalview GUI is being operated programmatically
2931 private boolean inBatchMode = false;
2934 * check if jalview GUI is being operated programmatically
2936 * @return inBatchMode
2938 public boolean isInBatchMode()
2944 * set flag if jalview GUI is being operated programmatically
2946 * @param inBatchMode
2948 public void setInBatchMode(boolean inBatchMode)
2950 this.inBatchMode = inBatchMode;
2953 public void startServiceDiscovery()
2955 startServiceDiscovery(false);
2958 public void startServiceDiscovery(boolean blocking)
2960 boolean alive = true;
2961 Thread t0 = null, t1 = null, t2 = null;
2962 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
2965 // todo: changesupport handlers need to be transferred
2966 if (discoverer == null)
2968 discoverer = new jalview.ws.jws1.Discoverer();
2969 // register PCS handler for desktop.
2970 discoverer.addPropertyChangeListener(changeSupport);
2972 // JAL-940 - disabled JWS1 service configuration - always start discoverer
2973 // until we phase out completely
2974 (t0 = new Thread(discoverer)).start();
2977 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
2979 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
2980 .startDiscoverer(changeSupport);
2984 // TODO: do rest service discovery
2993 } catch (Exception e)
2996 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
2997 || (t3 != null && t3.isAlive())
2998 || (t0 != null && t0.isAlive());
3004 * called to check if the service discovery process completed successfully.
3008 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3010 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3012 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3013 .getErrorMessages();
3016 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3018 if (serviceChangedDialog == null)
3020 // only run if we aren't already displaying one of these.
3021 addDialogThread(serviceChangedDialog = new Runnable()
3028 * JalviewDialog jd =new JalviewDialog() {
3030 * @Override protected void cancelPressed() { // TODO
3031 * Auto-generated method stub
3033 * }@Override protected void okPressed() { // TODO
3034 * Auto-generated method stub
3036 * }@Override protected void raiseClosed() { // TODO
3037 * Auto-generated method stub
3039 * } }; jd.initDialogFrame(new
3040 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3041 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3042 * + " or mis-configured HTTP proxy settings.<br/>" +
3043 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3045 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3046 * ), true, true, "Web Service Configuration Problem", 450,
3049 * jd.waitForInput();
3051 JvOptionPane.showConfirmDialog(Desktop.desktop,
3052 new JLabel("<html><table width=\"450\"><tr><td>"
3053 + ermsg + "</td></tr></table>"
3054 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3055 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3056 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3057 + " Tools->Preferences dialog box to change them.</p></html>"),
3058 "Web Service Configuration Problem",
3059 JvOptionPane.DEFAULT_OPTION,
3060 JvOptionPane.ERROR_MESSAGE);
3061 serviceChangedDialog = null;
3070 "Errors reported by JABA discovery service. Check web services preferences.\n"
3077 private Runnable serviceChangedDialog = null;
3080 * start a thread to open a URL in the configured browser. Pops up a warning
3081 * dialog to the user if there is an exception when calling out to the browser
3086 public static void showUrl(final String url)
3088 showUrl(url, Desktop.instance);
3092 * Like showUrl but allows progress handler to be specified
3096 * (null) or object implementing IProgressIndicator
3098 public static void showUrl(final String url,
3099 final IProgressIndicator progress)
3101 new Thread(new Runnable()
3108 if (progress != null)
3110 progress.setProgressBar(MessageManager
3111 .formatMessage("status.opening_params", new Object[]
3112 { url }), this.hashCode());
3114 jalview.util.BrowserLauncher.openURL(url);
3115 } catch (Exception ex)
3117 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3119 .getString("label.web_browser_not_found_unix"),
3120 MessageManager.getString("label.web_browser_not_found"),
3121 JvOptionPane.WARNING_MESSAGE);
3123 ex.printStackTrace();
3125 if (progress != null)
3127 progress.setProgressBar(null, this.hashCode());
3133 public static WsParamSetManager wsparamManager = null;
3135 public static ParamManager getUserParameterStore()
3137 if (wsparamManager == null)
3139 wsparamManager = new WsParamSetManager();
3141 return wsparamManager;
3145 * static hyperlink handler proxy method for use by Jalview's internal windows
3149 public static void hyperlinkUpdate(HyperlinkEvent e)
3151 if (e.getEventType() == EventType.ACTIVATED)
3156 url = e.getURL().toString();
3157 Desktop.showUrl(url);
3158 } catch (Exception x)
3162 if (Cache.log != null)
3164 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3169 "Couldn't handle string " + url + " as a URL.");
3172 // ignore any exceptions due to dud links.
3179 * single thread that handles display of dialogs to user.
3181 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3184 * flag indicating if dialogExecutor should try to acquire a permit
3186 private volatile boolean dialogPause = true;
3191 private java.util.concurrent.Semaphore block = new Semaphore(0);
3193 private static groovy.ui.Console groovyConsole;
3196 * add another dialog thread to the queue
3200 public void addDialogThread(final Runnable prompter)
3202 dialogExecutor.submit(new Runnable()
3212 } catch (InterruptedException x)
3217 if (instance == null)
3223 SwingUtilities.invokeAndWait(prompter);
3224 } catch (Exception q)
3226 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3232 public void startDialogQueue()
3234 // set the flag so we don't pause waiting for another permit and semaphore
3235 // the current task to begin
3236 dialogPause = false;
3241 protected void snapShotWindow_actionPerformed(ActionEvent e)
3245 ImageMaker im = new jalview.util.ImageMaker(
3246 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3247 getHeight(), of = new File("Jalview_snapshot"
3248 + System.currentTimeMillis() + ".eps"),
3249 "View of desktop", null, 0, false);
3252 paintAll(im.getGraphics());
3254 } catch (Exception q)
3256 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3260 Cache.log.info("Successfully written snapshot to file "
3261 + of.getAbsolutePath());
3265 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3266 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3267 * and location last time the view was expanded (if any). However it does not
3268 * remember the split pane divider location - this is set to match the
3269 * 'exploding' frame.
3273 public void explodeViews(SplitFrame sf)
3275 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3276 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3277 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3279 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3281 int viewCount = topPanels.size();
3288 * Processing in reverse order works, forwards order leaves the first panels
3289 * not visible. I don't know why!
3291 for (int i = viewCount - 1; i >= 0; i--)
3294 * Make new top and bottom frames. These take over the respective
3295 * AlignmentPanel objects, including their AlignmentViewports, so the
3296 * cdna/protein relationships between the viewports is carried over to the
3299 * explodedGeometry holds the (x, y) position of the previously exploded
3300 * SplitFrame, and the (width, height) of the AlignFrame component
3302 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3303 AlignFrame newTopFrame = new AlignFrame(topPanel);
3304 newTopFrame.setSize(oldTopFrame.getSize());
3305 newTopFrame.setVisible(true);
3306 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3307 .getExplodedGeometry();
3308 if (geometry != null)
3310 newTopFrame.setSize(geometry.getSize());
3313 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3314 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3315 newBottomFrame.setSize(oldBottomFrame.getSize());
3316 newBottomFrame.setVisible(true);
3317 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3318 .getExplodedGeometry();
3319 if (geometry != null)
3321 newBottomFrame.setSize(geometry.getSize());
3324 topPanel.av.setGatherViewsHere(false);
3325 bottomPanel.av.setGatherViewsHere(false);
3326 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3328 if (geometry != null)
3330 splitFrame.setLocation(geometry.getLocation());
3332 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3336 * Clear references to the panels (now relocated in the new SplitFrames)
3337 * before closing the old SplitFrame.
3340 bottomPanels.clear();
3345 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3346 * back into the given SplitFrame as additional views. Note that the gathered
3347 * frames may themselves have multiple views.
3351 public void gatherViews(GSplitFrame source)
3354 * special handling of explodedGeometry for a view within a SplitFrame: - it
3355 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3356 * height) of the AlignFrame component
3358 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3359 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3360 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3361 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3362 myBottomFrame.viewport
3363 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3364 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3365 myTopFrame.viewport.setGatherViewsHere(true);
3366 myBottomFrame.viewport.setGatherViewsHere(true);
3367 String topViewId = myTopFrame.viewport.getSequenceSetId();
3368 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3370 JInternalFrame[] frames = desktop.getAllFrames();
3371 for (JInternalFrame frame : frames)
3373 if (frame instanceof SplitFrame && frame != source)
3375 SplitFrame sf = (SplitFrame) frame;
3376 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3377 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3378 boolean gatherThis = false;
3379 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3381 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3382 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3383 if (topViewId.equals(topPanel.av.getSequenceSetId())
3384 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3387 topPanel.av.setGatherViewsHere(false);
3388 bottomPanel.av.setGatherViewsHere(false);
3389 topPanel.av.setExplodedGeometry(
3390 new Rectangle(sf.getLocation(), topFrame.getSize()));
3391 bottomPanel.av.setExplodedGeometry(
3392 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3393 myTopFrame.addAlignmentPanel(topPanel, false);
3394 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3400 topFrame.getAlignPanels().clear();
3401 bottomFrame.getAlignPanels().clear();
3408 * The dust settles...give focus to the tab we did this from.
3410 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3413 public static groovy.ui.Console getGroovyConsole()
3415 return groovyConsole;
3419 * handles the payload of a drag and drop event.
3421 * TODO refactor to desktop utilities class
3424 * - Data source strings extracted from the drop event
3426 * - protocol for each data source extracted from the drop event
3430 * - the payload from the drop event
3433 public static void transferFromDropTarget(List<String> files,
3434 List<DataSourceType> protocols, DropTargetDropEvent evt,
3435 Transferable t) throws Exception
3438 DataFlavor uriListFlavor = new DataFlavor(
3439 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3442 urlFlavour = new DataFlavor(
3443 "application/x-java-url; class=java.net.URL");
3444 } catch (ClassNotFoundException cfe)
3446 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3449 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3454 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3455 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3456 // means url may be null.
3459 protocols.add(DataSourceType.URL);
3460 files.add(url.toString());
3461 Cache.log.debug("Drop handled as URL dataflavor "
3462 + files.get(files.size() - 1));
3467 if (Platform.isAMac())
3470 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3474 } catch (Throwable ex)
3476 Cache.log.debug("URL drop handler failed.", ex);
3479 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3481 // Works on Windows and MacOSX
3482 Cache.log.debug("Drop handled as javaFileListFlavor");
3483 for (Object file : (List) t
3484 .getTransferData(DataFlavor.javaFileListFlavor))
3486 files.add(((File) file).toString());
3487 protocols.add(DataSourceType.FILE);
3492 // Unix like behaviour
3493 boolean added = false;
3495 if (t.isDataFlavorSupported(uriListFlavor))
3497 Cache.log.debug("Drop handled as uriListFlavor");
3498 // This is used by Unix drag system
3499 data = (String) t.getTransferData(uriListFlavor);
3503 // fallback to text: workaround - on OSX where there's a JVM bug
3504 Cache.log.debug("standard URIListFlavor failed. Trying text");
3505 // try text fallback
3506 DataFlavor textDf = new DataFlavor(
3507 "text/plain;class=java.lang.String");
3508 if (t.isDataFlavorSupported(textDf))
3510 data = (String) t.getTransferData(textDf);
3513 Cache.log.debug("Plain text drop content returned "
3514 + (data == null ? "Null - failed" : data));
3519 while (protocols.size() < files.size())
3521 Cache.log.debug("Adding missing FILE protocol for "
3522 + files.get(protocols.size()));
3523 protocols.add(DataSourceType.FILE);
3525 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3526 data, "\r\n"); st.hasMoreTokens();)
3529 String s = st.nextToken();
3530 if (s.startsWith("#"))
3532 // the line is a comment (as per the RFC 2483)
3535 java.net.URI uri = new java.net.URI(s);
3536 if (uri.getScheme().toLowerCase().startsWith("http"))
3538 protocols.add(DataSourceType.URL);
3539 files.add(uri.toString());
3543 // otherwise preserve old behaviour: catch all for file objects
3544 java.io.File file = new java.io.File(uri);
3545 protocols.add(DataSourceType.FILE);
3546 files.add(file.toString());
3551 if (Cache.log.isDebugEnabled())
3553 if (data == null || !added)
3556 if (t.getTransferDataFlavors() != null
3557 && t.getTransferDataFlavors().length > 0)
3560 "Couldn't resolve drop data. Here are the supported flavors:");
3561 for (DataFlavor fl : t.getTransferDataFlavors())
3564 "Supported transfer dataflavor: " + fl.toString());
3565 Object df = t.getTransferData(fl);
3568 Cache.log.debug("Retrieves: " + df);
3572 Cache.log.debug("Retrieved nothing");
3578 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3584 if (Platform.isWindows())
3587 Cache.log.debug("Scanning dropped content for Windows Link Files");
3589 // resolve any .lnk files in the file drop
3590 for (int f = 0; f < files.size(); f++)
3592 String source = files.get(f).toLowerCase();
3593 if (protocols.get(f).equals(DataSourceType.FILE)
3594 && (source.endsWith(".lnk") || source.endsWith(".url")
3595 || source.endsWith(".site")))
3599 File lf = new File(files.get(f));
3600 // process link file to get a URL
3601 Cache.log.debug("Found potential link file: " + lf);
3602 WindowsShortcut wscfile = new WindowsShortcut(lf);
3603 String fullname = wscfile.getRealFilename();
3604 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3605 files.set(f, fullname);
3606 Cache.log.debug("Parsed real filename " + fullname
3607 + " to extract protocol: " + protocols.get(f));
3608 } catch (Exception ex)
3611 "Couldn't parse " + files.get(f) + " as a link file.",
3620 * Sets the Preferences property for experimental features to True or False
3621 * depending on the state of the controlling menu item
3624 protected void showExperimental_actionPerformed(boolean selected)
3626 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3630 * Answers a (possibly empty) list of any structure viewer frames (currently
3631 * for either Jmol or Chimera) which are currently open. This may optionally
3632 * be restricted to viewers of a specified class, or viewers linked to a
3633 * specified alignment panel.
3636 * if not null, only return viewers linked to this panel
3637 * @param structureViewerClass
3638 * if not null, only return viewers of this class
3641 public List<StructureViewerBase> getStructureViewers(
3642 AlignmentPanel apanel,
3643 Class<? extends StructureViewerBase> structureViewerClass)
3645 List<StructureViewerBase> result = new ArrayList<>();
3646 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3648 for (JInternalFrame frame : frames)
3650 if (frame instanceof StructureViewerBase)
3652 if (structureViewerClass == null
3653 || structureViewerClass.isInstance(frame))
3656 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3658 result.add((StructureViewerBase) frame);