2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import static jalview.util.UrlConstants.SEQUENCE_ID;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.bin.Cache;
28 import jalview.bin.Jalview;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileFormats;
34 import jalview.io.FileLoader;
35 import jalview.io.FormatAdapter;
36 import jalview.io.IdentifyFile;
37 import jalview.io.JalviewFileChooser;
38 import jalview.io.JalviewFileView;
39 import jalview.jbgui.GSplitFrame;
40 import jalview.jbgui.GStructureViewer;
41 import jalview.structure.StructureSelectionManager;
42 import jalview.urls.IdOrgSettings;
43 import jalview.util.ImageMaker;
44 import jalview.util.MessageManager;
45 import jalview.util.Platform;
46 import jalview.util.UrlConstants;
47 import jalview.viewmodel.AlignmentViewport;
48 import jalview.ws.params.ParamManager;
49 import jalview.ws.utils.UrlDownloadClient;
51 import java.awt.BorderLayout;
52 import java.awt.Color;
53 import java.awt.Dimension;
54 import java.awt.FontMetrics;
55 import java.awt.Graphics;
56 import java.awt.GridLayout;
57 import java.awt.Point;
58 import java.awt.Rectangle;
59 import java.awt.Toolkit;
60 import java.awt.Window;
61 import java.awt.datatransfer.Clipboard;
62 import java.awt.datatransfer.ClipboardOwner;
63 import java.awt.datatransfer.DataFlavor;
64 import java.awt.datatransfer.Transferable;
65 import java.awt.dnd.DnDConstants;
66 import java.awt.dnd.DropTargetDragEvent;
67 import java.awt.dnd.DropTargetDropEvent;
68 import java.awt.dnd.DropTargetEvent;
69 import java.awt.dnd.DropTargetListener;
70 import java.awt.event.ActionEvent;
71 import java.awt.event.ActionListener;
72 import java.awt.event.InputEvent;
73 import java.awt.event.KeyEvent;
74 import java.awt.event.MouseAdapter;
75 import java.awt.event.MouseEvent;
76 import java.awt.event.WindowAdapter;
77 import java.awt.event.WindowEvent;
78 import java.beans.PropertyChangeEvent;
79 import java.beans.PropertyChangeListener;
80 import java.io.BufferedInputStream;
82 import java.io.FileOutputStream;
83 import java.io.IOException;
85 import java.util.ArrayList;
86 import java.util.Hashtable;
87 import java.util.List;
88 import java.util.ListIterator;
89 import java.util.StringTokenizer;
90 import java.util.Vector;
91 import java.util.concurrent.ExecutorService;
92 import java.util.concurrent.Executors;
93 import java.util.concurrent.Semaphore;
95 import javax.swing.AbstractAction;
96 import javax.swing.Action;
97 import javax.swing.ActionMap;
98 import javax.swing.Box;
99 import javax.swing.BoxLayout;
100 import javax.swing.DefaultDesktopManager;
101 import javax.swing.DesktopManager;
102 import javax.swing.InputMap;
103 import javax.swing.JButton;
104 import javax.swing.JCheckBox;
105 import javax.swing.JComboBox;
106 import javax.swing.JComponent;
107 import javax.swing.JDesktopPane;
108 import javax.swing.JFrame;
109 import javax.swing.JInternalFrame;
110 import javax.swing.JLabel;
111 import javax.swing.JMenuItem;
112 import javax.swing.JPanel;
113 import javax.swing.JPopupMenu;
114 import javax.swing.JProgressBar;
115 import javax.swing.KeyStroke;
116 import javax.swing.SwingUtilities;
117 import javax.swing.event.HyperlinkEvent;
118 import javax.swing.event.HyperlinkEvent.EventType;
119 import javax.swing.event.InternalFrameAdapter;
120 import javax.swing.event.InternalFrameEvent;
121 import javax.swing.event.MenuEvent;
122 import javax.swing.event.MenuListener;
124 import org.stackoverflowusers.file.WindowsShortcut;
131 * @version $Revision: 1.155 $
133 public class Desktop extends jalview.jbgui.GDesktop
134 implements DropTargetListener, ClipboardOwner, IProgressIndicator,
135 jalview.api.StructureSelectionManagerProvider
137 private static int DEFAULT_MIN_WIDTH = 300;
139 private static int DEFAULT_MIN_HEIGHT = 250;
141 private static int ALIGN_FRAME_DEFAULT_MIN_WIDTH = 600;
143 private static int ALIGN_FRAME_DEFAULT_MIN_HEIGHT = 70;
145 private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
147 private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
150 * news reader - null if it was never started.
152 private BlogReader jvnews = null;
154 private File projectFile;
158 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
160 public void addJalviewPropertyChangeListener(
161 PropertyChangeListener listener)
163 changeSupport.addJalviewPropertyChangeListener(listener);
167 * @param propertyName
169 * @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
170 * java.beans.PropertyChangeListener)
172 public void addJalviewPropertyChangeListener(String propertyName,
173 PropertyChangeListener listener)
175 changeSupport.addJalviewPropertyChangeListener(propertyName, listener);
179 * @param propertyName
181 * @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
182 * java.beans.PropertyChangeListener)
184 public void removeJalviewPropertyChangeListener(String propertyName,
185 PropertyChangeListener listener)
187 changeSupport.removeJalviewPropertyChangeListener(propertyName,
191 /** Singleton Desktop instance */
192 public static Desktop instance;
194 public static MyDesktopPane desktop;
196 static int openFrameCount = 0;
198 static final int xOffset = 30;
200 static final int yOffset = 30;
202 public static jalview.ws.jws1.Discoverer discoverer;
204 public static Object[] jalviewClipboard;
206 public static boolean internalCopy = false;
208 static int fileLoadingCount = 0;
210 class MyDesktopManager implements DesktopManager
213 private DesktopManager delegate;
215 public MyDesktopManager(DesktopManager delegate)
217 this.delegate = delegate;
221 public void activateFrame(JInternalFrame f)
225 delegate.activateFrame(f);
226 } catch (NullPointerException npe)
228 Point p = getMousePosition();
229 instance.showPasteMenu(p.x, p.y);
234 public void beginDraggingFrame(JComponent f)
236 delegate.beginDraggingFrame(f);
240 public void beginResizingFrame(JComponent f, int direction)
242 delegate.beginResizingFrame(f, direction);
246 public void closeFrame(JInternalFrame f)
248 delegate.closeFrame(f);
252 public void deactivateFrame(JInternalFrame f)
254 delegate.deactivateFrame(f);
258 public void deiconifyFrame(JInternalFrame f)
260 delegate.deiconifyFrame(f);
264 public void dragFrame(JComponent f, int newX, int newY)
270 delegate.dragFrame(f, newX, newY);
274 public void endDraggingFrame(JComponent f)
276 delegate.endDraggingFrame(f);
281 public void endResizingFrame(JComponent f)
283 delegate.endResizingFrame(f);
288 public void iconifyFrame(JInternalFrame f)
290 delegate.iconifyFrame(f);
294 public void maximizeFrame(JInternalFrame f)
296 delegate.maximizeFrame(f);
300 public void minimizeFrame(JInternalFrame f)
302 delegate.minimizeFrame(f);
306 public void openFrame(JInternalFrame f)
308 delegate.openFrame(f);
312 public void resizeFrame(JComponent f, int newX, int newY, int newWidth,
319 delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
323 public void setBoundsForFrame(JComponent f, int newX, int newY,
324 int newWidth, int newHeight)
326 delegate.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
329 // All other methods, simply delegate
334 * Creates a new Desktop object.
339 * A note to implementors. It is ESSENTIAL that any activities that might
340 * block are spawned off as threads rather than waited for during this
344 doVamsasClientCheck();
346 doConfigureStructurePrefs();
347 setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
348 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
349 boolean selmemusage = jalview.bin.Cache.getDefault("SHOW_MEMUSAGE",
351 boolean showjconsole = jalview.bin.Cache.getDefault("SHOW_JAVA_CONSOLE",
353 desktop = new MyDesktopPane(selmemusage);
354 showMemusage.setSelected(selmemusage);
355 desktop.setBackground(Color.white);
356 getContentPane().setLayout(new BorderLayout());
357 // alternate config - have scrollbars - see notes in JAL-153
358 // JScrollPane sp = new JScrollPane();
359 // sp.getViewport().setView(desktop);
360 // getContentPane().add(sp, BorderLayout.CENTER);
361 getContentPane().add(desktop, BorderLayout.CENTER);
362 desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
364 // This line prevents Windows Look&Feel resizing all new windows to maximum
365 // if previous window was maximised
366 desktop.setDesktopManager(
367 new MyDesktopManager(
368 (Platform.isWindows() ? new DefaultDesktopManager()
370 ? new AquaInternalFrameManager(
371 desktop.getDesktopManager())
372 : desktop.getDesktopManager())));
374 Rectangle dims = getLastKnownDimensions("");
381 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
382 setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
392 jconsole = new Console(this, showjconsole);
393 // add essential build information
394 jconsole.setHeader("Jalview Version: "
395 + jalview.bin.Cache.getProperty("VERSION") + "\n"
396 + "Jalview Installation: "
397 + jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
398 + "\n" + "Build Date: "
399 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
400 + "Java version: " + System.getProperty("java.version") + "\n"
401 + System.getProperty("os.arch") + " "
402 + System.getProperty("os.name") + " "
403 + System.getProperty("os.version"));
405 showConsole(showjconsole);
407 showNews.setVisible(false);
409 experimentalFeatures.setSelected(showExperimental());
411 getIdentifiersOrgData();
415 this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
416 // Spawn a thread that shows the splashscreen
418 SwingUtilities.invokeLater(new Runnable()
427 // Thread off a new instance of the file chooser - this reduces the time it
428 // takes to open it later on.
429 new Thread(new Runnable()
434 Cache.log.debug("Filechooser init thread started.");
435 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
436 JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
438 Cache.log.debug("Filechooser init thread finished.");
441 // Add the service change listener
442 changeSupport.addJalviewPropertyChangeListener("services",
443 new PropertyChangeListener()
447 public void propertyChange(PropertyChangeEvent evt)
449 Cache.log.debug("Firing service changed event for "
450 + evt.getNewValue());
451 JalviewServicesChanged(evt);
456 } // end BH 2018 ignore
458 this.addWindowListener(new WindowAdapter()
461 public void windowClosing(WindowEvent evt)
468 this.addMouseListener(ma = new MouseAdapter()
471 public void mousePressed(MouseEvent evt)
473 if (evt.isPopupTrigger()) // Mac
475 showPasteMenu(evt.getX(), evt.getY());
480 public void mouseReleased(MouseEvent evt)
482 if (evt.isPopupTrigger()) // Windows
484 showPasteMenu(evt.getX(), evt.getY());
488 desktop.addMouseListener(ma);
493 * Answers true if user preferences to enable experimental features is True
498 public boolean showExperimental()
500 String experimental = Cache.getDefault(EXPERIMENTAL_FEATURES,
501 Boolean.FALSE.toString());
502 return Boolean.valueOf(experimental).booleanValue();
505 public void doConfigureStructurePrefs()
507 // configure services
508 StructureSelectionManager ssm = StructureSelectionManager
509 .getStructureSelectionManager(this);
510 if (jalview.bin.Cache.getDefault(Preferences.ADD_SS_ANN, true))
512 ssm.setAddTempFacAnnot(jalview.bin.Cache
513 .getDefault(Preferences.ADD_TEMPFACT_ANN, true));
514 ssm.setProcessSecondaryStructure(jalview.bin.Cache
515 .getDefault(Preferences.STRUCT_FROM_PDB, true));
516 ssm.setSecStructServices(
517 jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW, true));
521 ssm.setAddTempFacAnnot(false);
522 ssm.setProcessSecondaryStructure(false);
523 ssm.setSecStructServices(false);
527 public void checkForNews()
536 final Desktop me = this;
537 // Thread off the news reader, in case there are connection problems.
538 addDialogThread(new Runnable()
543 Cache.log.debug("Starting news thread.");
545 jvnews = new BlogReader(me);
546 showNews.setVisible(true);
547 Cache.log.debug("Completed news thread.");
553 public void getIdentifiersOrgData()
555 // Thread off the identifiers fetcher
556 addDialogThread(new Runnable()
561 Cache.log.debug("Downloading data from identifiers.org");
562 UrlDownloadClient client = new UrlDownloadClient();
565 client.download(IdOrgSettings.getUrl(),
566 IdOrgSettings.getDownloadLocation());
567 } catch (IOException e)
569 Cache.log.debug("Exception downloading identifiers.org data"
577 protected void showNews_actionPerformed(ActionEvent e)
579 showNews(showNews.isSelected());
582 void showNews(boolean visible)
591 Cache.log.debug((visible ? "Showing" : "Hiding") + " news.");
592 showNews.setSelected(visible);
593 if (visible && !jvnews.isVisible())
595 new Thread(new Runnable()
600 long now = System.currentTimeMillis();
601 Desktop.instance.setProgressBar(
602 MessageManager.getString("status.refreshing_news"),
604 jvnews.refreshNews();
605 Desktop.instance.setProgressBar(null, now);
614 * recover the last known dimensions for a jalview window
617 * - empty string is desktop, all other windows have unique prefix
618 * @return null or last known dimensions scaled to current geometry (if last
619 * window geom was known)
621 Rectangle getLastKnownDimensions(String windowName)
623 // TODO: lock aspect ratio for scaling desktop Bug #0058199
624 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
625 String x = jalview.bin.Cache.getProperty(windowName + "SCREEN_X");
626 String y = jalview.bin.Cache.getProperty(windowName + "SCREEN_Y");
627 String width = jalview.bin.Cache
628 .getProperty(windowName + "SCREEN_WIDTH");
629 String height = jalview.bin.Cache
630 .getProperty(windowName + "SCREEN_HEIGHT");
631 if ((x != null) && (y != null) && (width != null) && (height != null))
633 int ix = Integer.parseInt(x), iy = Integer.parseInt(y),
634 iw = Integer.parseInt(width), ih = Integer.parseInt(height);
635 if (jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH") != null)
637 // attempt #1 - try to cope with change in screen geometry - this
638 // version doesn't preserve original jv aspect ratio.
639 // take ratio of current screen size vs original screen size.
640 double sw = ((1f * screenSize.width) / (1f * Integer.parseInt(
641 jalview.bin.Cache.getProperty("SCREENGEOMETRY_WIDTH"))));
642 double sh = ((1f * screenSize.height) / (1f * Integer.parseInt(
643 jalview.bin.Cache.getProperty("SCREENGEOMETRY_HEIGHT"))));
644 // rescale the bounds depending upon the current screen geometry.
645 ix = (int) (ix * sw);
646 iw = (int) (iw * sw);
647 iy = (int) (iy * sh);
648 ih = (int) (ih * sh);
649 while (ix >= screenSize.width)
651 jalview.bin.Cache.log.debug(
652 "Window geometry location recall error: shifting horizontal to within screenbounds.");
653 ix -= screenSize.width;
655 while (iy >= screenSize.height)
657 jalview.bin.Cache.log.debug(
658 "Window geometry location recall error: shifting vertical to within screenbounds.");
659 iy -= screenSize.height;
661 jalview.bin.Cache.log.debug(
662 "Got last known dimensions for " + windowName + ": x:" + ix
663 + " y:" + iy + " width:" + iw + " height:" + ih);
665 // return dimensions for new instance
666 return new Rectangle(ix, iy, iw, ih);
671 private void doVamsasClientCheck()
673 if (/** @j2sNative false && */ // BH 2018
674 jalview.bin.Cache.vamsasJarsPresent())
676 setupVamsasDisconnectedGui();
677 VamsasMenu.setVisible(true);
678 final Desktop us = this;
679 VamsasMenu.addMenuListener(new MenuListener()
681 // this listener remembers when the menu was first selected, and
682 // doesn't rebuild the session list until it has been cleared and
684 boolean refresh = true;
687 public void menuCanceled(MenuEvent e)
693 public void menuDeselected(MenuEvent e)
699 public void menuSelected(MenuEvent e)
703 us.buildVamsasStMenu();
708 vamsasStart.setVisible(true);
712 void showPasteMenu(int x, int y)
714 JPopupMenu popup = new JPopupMenu();
715 JMenuItem item = new JMenuItem(
716 MessageManager.getString("label.paste_new_window"));
717 item.addActionListener(new ActionListener()
720 public void actionPerformed(ActionEvent evt)
727 popup.show(this, x, y);
734 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
735 Transferable contents = c.getContents(this);
737 if (contents != null)
739 String file = (String) contents
740 .getTransferData(DataFlavor.stringFlavor);
742 FileFormatI format = new IdentifyFile().identify(file,
743 DataSourceType.PASTE);
745 new FileLoader().LoadFile(file, DataSourceType.PASTE, format);
748 } catch (Exception ex)
751 "Unable to paste alignment from system clipboard:\n" + ex);
756 * Adds and opens the given frame to the desktop
767 public static synchronized void addInternalFrame(
768 final JInternalFrame frame, String title, int w, int h)
770 addInternalFrame(frame, title, true, w, h, true, false);
774 * Add an internal frame to the Jalview desktop
781 * When true, display frame immediately, otherwise, caller must call
782 * setVisible themselves.
788 public static synchronized void addInternalFrame(
789 final JInternalFrame frame, String title, boolean makeVisible,
792 addInternalFrame(frame, title, makeVisible, w, h, true, false);
796 * Add an internal frame to the Jalview desktop and make it visible
809 public static synchronized void addInternalFrame(
810 final JInternalFrame frame, String title, int w, int h,
813 addInternalFrame(frame, title, true, w, h, resizable, false);
817 * Add an internal frame to the Jalview desktop
824 * When true, display frame immediately, otherwise, caller must call
825 * setVisible themselves.
832 * @param ignoreMinSize
833 * Do not set the default minimum size for frame
835 public static synchronized void addInternalFrame(
836 final JInternalFrame frame, String title, boolean makeVisible,
837 int w, int h, boolean resizable, boolean ignoreMinSize)
840 // TODO: allow callers to determine X and Y position of frame (eg. via
842 // TODO: consider fixing method to update entries in the window submenu with
843 // the current window title
845 frame.setTitle(title);
846 if (frame.getWidth() < 1 || frame.getHeight() < 1)
850 // THIS IS A PUBLIC STATIC METHOD, SO IT MAY BE CALLED EVEN IN
851 // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
852 // IF JALVIEW IS RUNNING HEADLESS
853 // ///////////////////////////////////////////////
854 if (instance == null || (System.getProperty("java.awt.headless") != null
855 && System.getProperty("java.awt.headless").equals("true")))
864 frame.setMinimumSize(
865 new Dimension(DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT));
867 // Set default dimension for Alignment Frame window.
868 // The Alignment Frame window could be added from a number of places,
870 // I did this here in order not to miss out on any Alignment frame.
871 if (frame instanceof AlignFrame)
873 frame.setMinimumSize(new Dimension(ALIGN_FRAME_DEFAULT_MIN_WIDTH,
874 ALIGN_FRAME_DEFAULT_MIN_HEIGHT));
878 frame.setVisible(makeVisible);
879 frame.setClosable(true);
880 frame.setResizable(resizable);
881 frame.setMaximizable(resizable);
882 frame.setIconifiable(resizable);
883 frame.setOpaque(/** @j2sNative true || */
886 if (frame.getX() < 1 && frame.getY() < 1)
888 frame.setLocation(xOffset * openFrameCount,
889 yOffset * ((openFrameCount - 1) % 10) + yOffset);
893 * add an entry for the new frame in the Window menu
894 * (and remove it when the frame is closed)
896 final JMenuItem menuItem = new JMenuItem(title);
897 frame.addInternalFrameListener(new InternalFrameAdapter()
900 public void internalFrameActivated(InternalFrameEvent evt)
902 JInternalFrame itf = desktop.getSelectedFrame();
905 if (itf instanceof AlignFrame)
907 Jalview.setCurrentAlignFrame((AlignFrame) itf);
914 public void internalFrameClosed(InternalFrameEvent evt)
916 PaintRefresher.RemoveComponent(frame);
919 * defensive check to prevent frames being
920 * added half off the window
922 if (openFrameCount > 0)
928 * ensure no reference to alignFrame retained by menu item listener
930 if (menuItem.getActionListeners().length > 0)
932 menuItem.removeActionListener(menuItem.getActionListeners()[0]);
934 windowMenu.remove(menuItem);
938 menuItem.addActionListener(new ActionListener()
941 public void actionPerformed(ActionEvent e)
945 frame.setSelected(true);
946 frame.setIcon(false);
947 } catch (java.beans.PropertyVetoException ex)
954 setKeyBindings(frame);
958 windowMenu.add(menuItem);
963 frame.setSelected(true);
964 frame.requestFocus();
965 } catch (java.beans.PropertyVetoException ve)
967 } catch (java.lang.ClassCastException cex)
970 "Squashed a possible GUI implementation error. If you can recreate this, please look at http://issues.jalview.org/browse/JAL-869",
976 * Add key bindings to a JInternalFrame so that Ctrl-W and Cmd-W will close
981 private static void setKeyBindings(JInternalFrame frame)
983 @SuppressWarnings("serial")
984 final Action closeAction = new AbstractAction()
987 public void actionPerformed(ActionEvent e)
994 * set up key bindings for Ctrl-W and Cmd-W, with the same (Close) action
996 KeyStroke ctrlWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
997 InputEvent.CTRL_DOWN_MASK);
998 KeyStroke cmdWKey = KeyStroke.getKeyStroke(KeyEvent.VK_W,
999 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
1001 InputMap inputMap = frame
1002 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
1003 String ctrlW = ctrlWKey.toString();
1004 inputMap.put(ctrlWKey, ctrlW);
1005 inputMap.put(cmdWKey, ctrlW);
1007 ActionMap actionMap = frame.getActionMap();
1008 actionMap.put(ctrlW, closeAction);
1012 public void lostOwnership(Clipboard clipboard, Transferable contents)
1016 Desktop.jalviewClipboard = null;
1019 internalCopy = false;
1023 public void dragEnter(DropTargetDragEvent evt)
1028 public void dragExit(DropTargetEvent evt)
1033 public void dragOver(DropTargetDragEvent evt)
1038 public void dropActionChanged(DropTargetDragEvent evt)
1049 public void drop(DropTargetDropEvent evt)
1051 boolean success = true;
1052 // JAL-1552 - acceptDrop required before getTransferable call for
1053 // Java's Transferable for native dnd
1054 evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
1055 Transferable t = evt.getTransferable();
1056 List<String> files = new ArrayList<>();
1057 List<DataSourceType> protocols = new ArrayList<>();
1061 Desktop.transferFromDropTarget(files, protocols, evt, t);
1062 } catch (Exception e)
1064 e.printStackTrace();
1072 for (int i = 0; i < files.size(); i++)
1074 String file = files.get(i).toString();
1075 DataSourceType protocol = (protocols == null)
1076 ? DataSourceType.FILE
1078 FileFormatI format = null;
1080 if (file.endsWith(".jar"))
1082 format = FileFormat.Jalview;
1087 format = new IdentifyFile().identify(file, protocol);
1090 new FileLoader().LoadFile(file, protocol, format);
1093 } catch (Exception ex)
1098 evt.dropComplete(success); // need this to ensure input focus is properly
1099 // transfered to any new windows created
1109 public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
1111 String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
1112 JalviewFileChooser chooser = JalviewFileChooser
1113 .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
1115 chooser.setFileView(new JalviewFileView());
1116 chooser.setDialogTitle(
1117 MessageManager.getString("label.open_local_file"));
1118 chooser.setToolTipText(MessageManager.getString("action.open"));
1120 int value = chooser.showOpenDialog(this);
1122 if (value == JalviewFileChooser.APPROVE_OPTION)
1124 String choice = chooser.getSelectedFile().getPath();
1125 Cache.setProperty("LAST_DIRECTORY",
1126 chooser.getSelectedFile().getParent());
1128 FileFormatI format = chooser.getSelectedFormat();
1131 * Call IdentifyFile to verify the file contains what its extension implies.
1132 * Skip this step for dynamically added file formats, because
1133 * IdentifyFile does not know how to recognise them.
1135 if (FileFormats.getInstance().isIdentifiable(format))
1139 format = new IdentifyFile().identify(choice, DataSourceType.FILE);
1140 } catch (FileFormatException e)
1142 // format = null; //??
1146 if (viewport != null)
1148 new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
1153 new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
1165 public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
1167 // This construct allows us to have a wider textfield
1169 JLabel label = new JLabel(
1170 MessageManager.getString("label.input_file_url"));
1172 JComboBox history = new JComboBox();
1173 JPanel panel = new JPanel(new GridLayout(2, 1));
1176 history.setPreferredSize(new Dimension(400, 20));
1177 history.setEditable(true);
1178 history.addItem("http://www.");
1180 String historyItems = jalview.bin.Cache.getProperty("RECENT_URL");
1184 if (historyItems != null)
1186 st = new StringTokenizer(historyItems, "\t");
1188 while (st.hasMoreTokens())
1190 history.addItem(st.nextElement());
1194 // BH 2018 -- providing a callback for SwingJS
1195 // dialogOption is just a simple way to provide
1196 // context for the modal-like response.
1197 // The only requirement is that desktop implement
1198 // PropertyChangeListener, which is used already in Java
1199 // for changes in input value and such within the dialogs.
1201 String dialogOption = "label.input_alignment_from_url";
1202 desktop.dialogData = new Object[] { dialogOption, viewport, history };
1203 desktop.onDialogReturn(
1204 JvOptionPane.showInternalConfirmDialog(desktop, panel,
1205 MessageManager.getString(dialogOption),
1206 JvOptionPane.OK_CANCEL_OPTION));
1208 // no code may follow this, as SwingJS will not block
1209 // callback in JavaScript comes via a property change event,
1210 // thus going into desktop.onDialogReturn(int) just the same as
1217 * Opens the CutAndPaste window for the user to paste an alignment in to
1220 * - if not null, the pasted alignment is added to the current
1221 * alignment; if null, to a new alignment window
1224 public void inputTextboxMenuItem_actionPerformed(
1225 AlignmentViewPanel viewPanel)
1227 CutAndPasteTransfer cap = new CutAndPasteTransfer();
1228 cap.setForInput(viewPanel);
1229 Desktop.addInternalFrame(cap,
1230 MessageManager.getString("label.cut_paste_alignmen_file"), true,
1240 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
1241 jalview.bin.Cache.setProperty("SCREENGEOMETRY_WIDTH",
1243 jalview.bin.Cache.setProperty("SCREENGEOMETRY_HEIGHT",
1244 screen.height + "");
1245 storeLastKnownDimensions("", new Rectangle(getBounds().x, getBounds().y,
1246 getWidth(), getHeight()));
1248 if (jconsole != null)
1250 storeLastKnownDimensions("JAVA_CONSOLE_", jconsole.getBounds());
1251 jconsole.stopConsole();
1255 storeLastKnownDimensions("JALVIEW_RSS_WINDOW_", jvnews.getBounds());
1258 if (dialogExecutor != null)
1260 dialogExecutor.shutdownNow();
1262 closeAll_actionPerformed(null);
1264 if (groovyConsole != null)
1266 // suppress a possible repeat prompt to save script
1267 groovyConsole.setDirty(false);
1268 groovyConsole.exit();
1273 private void storeLastKnownDimensions(String string, Rectangle jc)
1275 jalview.bin.Cache.log.debug("Storing last known dimensions for "
1276 + string + ": x:" + jc.x + " y:" + jc.y + " width:" + jc.width
1277 + " height:" + jc.height);
1279 jalview.bin.Cache.setProperty(string + "SCREEN_X", jc.x + "");
1280 jalview.bin.Cache.setProperty(string + "SCREEN_Y", jc.y + "");
1281 jalview.bin.Cache.setProperty(string + "SCREEN_WIDTH", jc.width + "");
1282 jalview.bin.Cache.setProperty(string + "SCREEN_HEIGHT", jc.height + "");
1292 public void aboutMenuItem_actionPerformed(ActionEvent e)
1294 // StringBuffer message = getAboutMessage(false);
1295 // JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1297 // message.toString(), "About Jalview", JvOptionPane.INFORMATION_MESSAGE);
1298 new Thread(new Runnable()
1303 new SplashScreen(true);
1308 public StringBuffer getAboutMessage(boolean shortv)
1310 StringBuffer message = new StringBuffer();
1311 message.append("<html>");
1314 message.append("<h1><strong>Version: "
1315 + jalview.bin.Cache.getProperty("VERSION")
1316 + "</strong></h1>");
1317 message.append("<strong>Last Updated: <em>"
1318 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
1319 + "</em></strong>");
1325 message.append("<strong>Version "
1326 + jalview.bin.Cache.getProperty("VERSION")
1327 + "; last updated: "
1328 + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
1331 if (jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1332 .equals("Checking"))
1334 message.append("<br>...Checking latest version...</br>");
1336 else if (!jalview.bin.Cache.getDefault("LATEST_VERSION", "Checking")
1337 .equals(jalview.bin.Cache.getProperty("VERSION")))
1339 boolean red = false;
1340 if (jalview.bin.Cache.getProperty("VERSION").toLowerCase()
1341 .indexOf("automated build") == -1)
1344 // Displayed when code version and jnlp version do not match and code
1345 // version is not a development build
1346 message.append("<div style=\"color: #FF0000;font-style: bold;\">");
1349 message.append("<br>!! Version "
1350 + jalview.bin.Cache.getDefault("LATEST_VERSION",
1352 + " is available for download from "
1353 + jalview.bin.Cache.getDefault("www.jalview.org",
1354 "http://www.jalview.org")
1358 message.append("</div>");
1361 message.append("<br>Authors: " + jalview.bin.Cache.getDefault(
1363 "The Jalview Authors (See AUTHORS file for current list)")
1364 + "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
1365 + "<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"
1366 + "<br><br>If you use Jalview, please cite:"
1367 + "<br>Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)"
1368 + "<br>Jalview Version 2 - a multiple sequence alignment editor and analysis workbench"
1369 + "<br>Bioinformatics doi: 10.1093/bioinformatics/btp033"
1381 public void documentationMenuItem_actionPerformed(ActionEvent e)
1385 Help.showHelpWindow();
1386 } catch (Exception ex)
1392 public void closeAll_actionPerformed(ActionEvent e)
1394 // TODO show a progress bar while closing?
1395 JInternalFrame[] frames = desktop.getAllFrames();
1396 for (int i = 0; i < frames.length; i++)
1400 frames[i].setClosed(true);
1401 } catch (java.beans.PropertyVetoException ex)
1405 Jalview.setCurrentAlignFrame(null);
1406 System.out.println("ALL CLOSED");
1407 if (v_client != null)
1409 // TODO clear binding to vamsas document objects on close_all
1413 * reset state of singleton objects as appropriate (clear down session state
1414 * when all windows are closed)
1416 StructureSelectionManager ssm = StructureSelectionManager
1417 .getStructureSelectionManager(this);
1425 public void raiseRelated_actionPerformed(ActionEvent e)
1427 reorderAssociatedWindows(false, false);
1431 public void minimizeAssociated_actionPerformed(ActionEvent e)
1433 reorderAssociatedWindows(true, false);
1436 void closeAssociatedWindows()
1438 reorderAssociatedWindows(false, true);
1444 * @seejalview.jbgui.GDesktop#garbageCollect_actionPerformed(java.awt.event.
1448 protected void garbageCollect_actionPerformed(ActionEvent e)
1450 // We simply collect the garbage
1451 jalview.bin.Cache.log.debug("Collecting garbage...");
1453 jalview.bin.Cache.log.debug("Finished garbage collection.");
1460 * jalview.jbgui.GDesktop#showMemusage_actionPerformed(java.awt.event.ActionEvent
1464 protected void showMemusage_actionPerformed(ActionEvent e)
1466 desktop.showMemoryUsage(showMemusage.isSelected());
1473 * jalview.jbgui.GDesktop#showConsole_actionPerformed(java.awt.event.ActionEvent
1477 protected void showConsole_actionPerformed(ActionEvent e)
1479 showConsole(showConsole.isSelected());
1482 Console jconsole = null;
1485 * control whether the java console is visible or not
1489 void showConsole(boolean selected)
1491 // TODO: decide if we should update properties file
1492 if (jconsole != null) // BH 2018
1494 showConsole.setSelected(selected);
1495 Cache.setProperty("SHOW_JAVA_CONSOLE",
1496 Boolean.valueOf(selected).toString());
1497 jconsole.setVisible(selected);
1501 void reorderAssociatedWindows(boolean minimize, boolean close)
1503 JInternalFrame[] frames = desktop.getAllFrames();
1504 if (frames == null || frames.length < 1)
1509 AlignmentViewport source = null, target = null;
1510 if (frames[0] instanceof AlignFrame)
1512 source = ((AlignFrame) frames[0]).getCurrentView();
1514 else if (frames[0] instanceof TreePanel)
1516 source = ((TreePanel) frames[0]).getViewPort();
1518 else if (frames[0] instanceof PCAPanel)
1520 source = ((PCAPanel) frames[0]).av;
1522 else if (frames[0].getContentPane() instanceof PairwiseAlignPanel)
1524 source = ((PairwiseAlignPanel) frames[0].getContentPane()).av;
1529 for (int i = 0; i < frames.length; i++)
1532 if (frames[i] == null)
1536 if (frames[i] instanceof AlignFrame)
1538 target = ((AlignFrame) frames[i]).getCurrentView();
1540 else if (frames[i] instanceof TreePanel)
1542 target = ((TreePanel) frames[i]).getViewPort();
1544 else if (frames[i] instanceof PCAPanel)
1546 target = ((PCAPanel) frames[i]).av;
1548 else if (frames[i].getContentPane() instanceof PairwiseAlignPanel)
1550 target = ((PairwiseAlignPanel) frames[i].getContentPane()).av;
1553 if (source == target)
1559 frames[i].setClosed(true);
1563 frames[i].setIcon(minimize);
1566 frames[i].toFront();
1570 } catch (java.beans.PropertyVetoException ex)
1585 protected void preferences_actionPerformed(ActionEvent e)
1597 public void saveState_actionPerformed(ActionEvent e)
1599 JalviewFileChooser chooser = new JalviewFileChooser("jvp",
1602 chooser.setFileView(new JalviewFileView());
1603 chooser.setDialogTitle(MessageManager.getString("label.save_state"));
1605 int value = chooser.showSaveDialog(this);
1607 if (value == JalviewFileChooser.APPROVE_OPTION)
1609 final Desktop me = this;
1610 final java.io.File choice = chooser.getSelectedFile();
1611 setProjectFile(choice);
1613 new Thread(new Runnable()
1618 // TODO: refactor to Jalview desktop session controller action.
1619 setProgressBar(MessageManager.formatMessage(
1620 "label.saving_jalview_project", new Object[]
1621 { choice.getName() }), choice.hashCode());
1622 jalview.bin.Cache.setProperty("LAST_DIRECTORY",
1623 choice.getParent());
1624 // TODO catch and handle errors for savestate
1625 // TODO prevent user from messing with the Desktop whilst we're saving
1628 new Jalview2XML().saveState(choice);
1629 } catch (OutOfMemoryError oom)
1632 "Whilst saving current state to " + choice.getName(),
1634 } catch (Exception ex)
1637 "Problems whilst trying to save to " + choice.getName(),
1639 JvOptionPane.showMessageDialog(me,
1640 MessageManager.formatMessage(
1641 "label.error_whilst_saving_current_state_to",
1643 { choice.getName() }),
1644 MessageManager.getString("label.couldnt_save_project"),
1645 JvOptionPane.WARNING_MESSAGE);
1647 setProgressBar(null, choice.hashCode());
1653 private void setProjectFile(File choice)
1655 this.projectFile = choice;
1658 public File getProjectFile()
1660 return this.projectFile;
1670 public void loadState_actionPerformed(ActionEvent e)
1672 JalviewFileChooser chooser = new JalviewFileChooser(
1673 Cache.getProperty("LAST_DIRECTORY"), new String[]
1676 { "Jalview Project", "Jalview Project (old)" },
1678 chooser.setFileView(new JalviewFileView());
1679 chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
1681 int value = chooser.showOpenDialog(this);
1683 if (value == JalviewFileChooser.APPROVE_OPTION)
1685 final File selectedFile = chooser.getSelectedFile();
1686 setProjectFile(selectedFile);
1687 final String choice = selectedFile.getAbsolutePath();
1688 Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
1689 new Thread(new Runnable()
1694 setProgressBar(MessageManager.formatMessage(
1695 "label.loading_jalview_project", new Object[]
1696 { choice }), choice.hashCode());
1699 new Jalview2XML().loadJalviewAlign(choice);
1700 } catch (OutOfMemoryError oom)
1702 new OOMWarning("Whilst loading project from " + choice, oom);
1703 } catch (Exception ex)
1706 "Problems whilst loading project from " + choice, ex);
1707 JvOptionPane.showMessageDialog(Desktop.desktop,
1708 MessageManager.formatMessage(
1709 "label.error_whilst_loading_project_from",
1712 MessageManager.getString("label.couldnt_load_project"),
1713 JvOptionPane.WARNING_MESSAGE);
1715 setProgressBar(null, choice.hashCode());
1722 public void inputSequence_actionPerformed(ActionEvent e)
1724 new SequenceFetcher(this);
1727 JPanel progressPanel;
1729 ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
1731 public void startLoading(final String fileName)
1733 if (fileLoadingCount == 0)
1735 fileLoadingPanels.add(addProgressPanel(MessageManager
1736 .formatMessage("label.loading_file", new Object[]
1742 private JPanel addProgressPanel(String string)
1744 if (progressPanel == null)
1746 progressPanel = new JPanel(new GridLayout(1, 1));
1747 totalProgressCount = 0;
1748 instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
1750 JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
1751 JProgressBar progressBar = new JProgressBar();
1752 progressBar.setIndeterminate(true);
1754 thisprogress.add(new JLabel(string), BorderLayout.WEST);
1756 thisprogress.add(progressBar, BorderLayout.CENTER);
1757 progressPanel.add(thisprogress);
1758 ((GridLayout) progressPanel.getLayout()).setRows(
1759 ((GridLayout) progressPanel.getLayout()).getRows() + 1);
1760 ++totalProgressCount;
1761 instance.validate();
1762 return thisprogress;
1765 int totalProgressCount = 0;
1767 private void removeProgressPanel(JPanel progbar)
1769 if (progressPanel != null)
1771 synchronized (progressPanel)
1773 progressPanel.remove(progbar);
1774 GridLayout gl = (GridLayout) progressPanel.getLayout();
1775 gl.setRows(gl.getRows() - 1);
1776 if (--totalProgressCount < 1)
1778 this.getContentPane().remove(progressPanel);
1779 progressPanel = null;
1786 public void stopLoading()
1789 if (fileLoadingCount < 1)
1791 while (fileLoadingPanels.size() > 0)
1793 removeProgressPanel(fileLoadingPanels.remove(0));
1795 fileLoadingPanels.clear();
1796 fileLoadingCount = 0;
1801 public static int getViewCount(String alignmentId)
1803 AlignmentViewport[] aps = getViewports(alignmentId);
1804 return (aps == null) ? 0 : aps.length;
1809 * @param alignmentId
1810 * - if null, all sets are returned
1811 * @return all AlignmentPanels concerning the alignmentId sequence set
1813 public static AlignmentPanel[] getAlignmentPanels(String alignmentId)
1815 if (Desktop.desktop == null)
1817 // no frames created and in headless mode
1818 // TODO: verify that frames are recoverable when in headless mode
1821 List<AlignmentPanel> aps = new ArrayList<>();
1822 AlignFrame[] frames = getAlignFrames();
1827 for (AlignFrame af : frames)
1829 for (AlignmentPanel ap : af.alignPanels)
1831 if (alignmentId == null
1832 || alignmentId.equals(ap.av.getSequenceSetId()))
1838 if (aps.size() == 0)
1842 AlignmentPanel[] vap = aps.toArray(new AlignmentPanel[aps.size()]);
1847 * get all the viewports on an alignment.
1849 * @param sequenceSetId
1850 * unique alignment id (may be null - all viewports returned in that
1852 * @return all viewports on the alignment bound to sequenceSetId
1854 public static AlignmentViewport[] getViewports(String sequenceSetId)
1856 List<AlignmentViewport> viewp = new ArrayList<>();
1857 if (desktop != null)
1859 AlignFrame[] frames = Desktop.getAlignFrames();
1861 for (AlignFrame afr : frames)
1863 if (sequenceSetId == null || afr.getViewport().getSequenceSetId()
1864 .equals(sequenceSetId))
1866 if (afr.alignPanels != null)
1868 for (AlignmentPanel ap : afr.alignPanels)
1870 if (sequenceSetId == null
1871 || sequenceSetId.equals(ap.av.getSequenceSetId()))
1879 viewp.add(afr.getViewport());
1883 if (viewp.size() > 0)
1885 return viewp.toArray(new AlignmentViewport[viewp.size()]);
1892 * Explode the views in the given frame into separate AlignFrame
1896 public static void explodeViews(AlignFrame af)
1898 int size = af.alignPanels.size();
1904 for (int i = 0; i < size; i++)
1906 AlignmentPanel ap = af.alignPanels.get(i);
1907 AlignFrame newaf = new AlignFrame(ap);
1910 * Restore the view's last exploded frame geometry if known. Multiple
1911 * views from one exploded frame share and restore the same (frame)
1912 * position and size.
1914 Rectangle geometry = ap.av.getExplodedGeometry();
1915 if (geometry != null)
1917 newaf.setBounds(geometry);
1920 ap.av.setGatherViewsHere(false);
1922 addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
1923 AlignFrame.DEFAULT_HEIGHT);
1926 af.alignPanels.clear();
1927 af.closeMenuItem_actionPerformed(true);
1932 * Gather expanded views (separate AlignFrame's) with the same sequence set
1933 * identifier back in to this frame as additional views, and close the
1934 * expanded views. Note the expanded frames may themselves have multiple
1935 * views. We take the lot.
1939 public void gatherViews(AlignFrame source)
1941 source.viewport.setGatherViewsHere(true);
1942 source.viewport.setExplodedGeometry(source.getBounds());
1943 JInternalFrame[] frames = desktop.getAllFrames();
1944 String viewId = source.viewport.getSequenceSetId();
1946 for (int t = 0; t < frames.length; t++)
1948 if (frames[t] instanceof AlignFrame && frames[t] != source)
1950 AlignFrame af = (AlignFrame) frames[t];
1951 boolean gatherThis = false;
1952 for (int a = 0; a < af.alignPanels.size(); a++)
1954 AlignmentPanel ap = af.alignPanels.get(a);
1955 if (viewId.equals(ap.av.getSequenceSetId()))
1958 ap.av.setGatherViewsHere(false);
1959 ap.av.setExplodedGeometry(af.getBounds());
1960 source.addAlignmentPanel(ap, false);
1966 af.alignPanels.clear();
1967 af.closeMenuItem_actionPerformed(true);
1974 jalview.gui.VamsasApplication v_client = null;
1977 public void vamsasImport_actionPerformed(ActionEvent e)
1979 if (v_client == null)
1981 // Load and try to start a session.
1982 JalviewFileChooser chooser = new JalviewFileChooser(
1983 jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1985 chooser.setFileView(new JalviewFileView());
1986 chooser.setDialogTitle(
1987 MessageManager.getString("label.open_saved_vamsas_session"));
1988 chooser.setToolTipText(MessageManager.getString(
1989 "label.select_vamsas_session_opened_as_new_vamsas_session"));
1991 int value = chooser.showOpenDialog(this);
1993 if (value == JalviewFileChooser.APPROVE_OPTION)
1995 String fle = chooser.getSelectedFile().toString();
1996 if (!vamsasImport(chooser.getSelectedFile()))
1998 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1999 MessageManager.formatMessage(
2000 "label.couldnt_import_as_vamsas_session",
2004 .getString("label.vamsas_document_import_failed"),
2005 JvOptionPane.ERROR_MESSAGE);
2011 jalview.bin.Cache.log.error(
2012 "Implementation error - load session from a running session is not supported.");
2017 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2020 * @return true if import was a success and a session was started.
2022 public boolean vamsasImport(URL url)
2024 // TODO: create progress bar
2025 if (v_client != null)
2028 jalview.bin.Cache.log.error(
2029 "Implementation error - load session from a running session is not supported.");
2035 // copy the URL content to a temporary local file
2036 // TODO: be a bit cleverer here with nio (?!)
2037 File file = File.createTempFile("vdocfromurl", ".vdj");
2038 FileOutputStream fos = new FileOutputStream(file);
2039 BufferedInputStream bis = new BufferedInputStream(url.openStream());
2040 byte[] buffer = new byte[2048];
2042 while ((ln = bis.read(buffer)) > -1)
2044 fos.write(buffer, 0, ln);
2048 v_client = new jalview.gui.VamsasApplication(this, file,
2049 url.toExternalForm());
2050 } catch (Exception ex)
2052 jalview.bin.Cache.log.error(
2053 "Failed to create new vamsas session from contents of URL "
2058 setupVamsasConnectedGui();
2059 v_client.initial_update(); // TODO: thread ?
2060 return v_client.inSession();
2064 * import file into a new vamsas session (uses jalview.gui.VamsasApplication)
2067 * @return true if import was a success and a session was started.
2069 public boolean vamsasImport(File file)
2071 if (v_client != null)
2074 jalview.bin.Cache.log.error(
2075 "Implementation error - load session from a running session is not supported.");
2079 setProgressBar(MessageManager.formatMessage(
2080 "status.importing_vamsas_session_from", new Object[]
2081 { file.getName() }), file.hashCode());
2084 v_client = new jalview.gui.VamsasApplication(this, file, null);
2085 } catch (Exception ex)
2087 setProgressBar(MessageManager.formatMessage(
2088 "status.importing_vamsas_session_from", new Object[]
2089 { file.getName() }), file.hashCode());
2090 jalview.bin.Cache.log.error(
2091 "New vamsas session from existing session file failed:", ex);
2094 setupVamsasConnectedGui();
2095 v_client.initial_update(); // TODO: thread ?
2096 setProgressBar(MessageManager.formatMessage(
2097 "status.importing_vamsas_session_from", new Object[]
2098 { file.getName() }), file.hashCode());
2099 return v_client.inSession();
2102 public boolean joinVamsasSession(String mysesid)
2104 if (v_client != null)
2106 throw new Error(MessageManager
2107 .getString("error.try_join_vamsas_session_another"));
2109 if (mysesid == null)
2112 MessageManager.getString("error.invalid_vamsas_session_id"));
2114 v_client = new VamsasApplication(this, mysesid);
2115 setupVamsasConnectedGui();
2116 v_client.initial_update();
2117 return (v_client.inSession());
2121 public void vamsasStart_actionPerformed(ActionEvent e)
2123 if (v_client == null)
2126 // we just start a default session for moment.
2128 * JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.
2129 * getProperty("LAST_DIRECTORY"));
2131 * chooser.setFileView(new JalviewFileView());
2132 * chooser.setDialogTitle("Load Vamsas file");
2133 * chooser.setToolTipText("Import");
2135 * int value = chooser.showOpenDialog(this);
2137 * if (value == JalviewFileChooser.APPROVE_OPTION) { v_client = new
2138 * jalview.gui.VamsasApplication(this, chooser.getSelectedFile());
2140 v_client = new VamsasApplication(this);
2141 setupVamsasConnectedGui();
2142 v_client.initial_update(); // TODO: thread ?
2146 // store current data in session.
2147 v_client.push_update(); // TODO: thread
2151 protected void setupVamsasConnectedGui()
2153 vamsasStart.setText(MessageManager.getString("label.session_update"));
2154 vamsasSave.setVisible(true);
2155 vamsasStop.setVisible(true);
2156 vamsasImport.setVisible(false); // Document import to existing session is
2157 // not possible for vamsas-client-1.0.
2160 protected void setupVamsasDisconnectedGui()
2162 vamsasSave.setVisible(false);
2163 vamsasStop.setVisible(false);
2164 vamsasImport.setVisible(true);
2166 .setText(MessageManager.getString("label.new_vamsas_session"));
2170 public void vamsasStop_actionPerformed(ActionEvent e)
2172 if (v_client != null)
2174 v_client.end_session();
2176 setupVamsasDisconnectedGui();
2180 protected void buildVamsasStMenu()
2182 if (v_client == null)
2184 String[] sess = null;
2187 sess = VamsasApplication.getSessionList();
2188 } catch (Exception e)
2190 jalview.bin.Cache.log.warn("Problem getting current sessions list.",
2196 jalview.bin.Cache.log.debug(
2197 "Got current sessions list: " + sess.length + " entries.");
2198 VamsasStMenu.removeAll();
2199 for (int i = 0; i < sess.length; i++)
2201 JMenuItem sessit = new JMenuItem();
2202 sessit.setText(sess[i]);
2203 sessit.setToolTipText(MessageManager
2204 .formatMessage("label.connect_to_session", new Object[]
2206 final Desktop dsktp = this;
2207 final String mysesid = sess[i];
2208 sessit.addActionListener(new ActionListener()
2212 public void actionPerformed(ActionEvent e)
2214 if (dsktp.v_client == null)
2216 Thread rthr = new Thread(new Runnable()
2222 dsktp.v_client = new VamsasApplication(dsktp, mysesid);
2223 dsktp.setupVamsasConnectedGui();
2224 dsktp.v_client.initial_update();
2232 VamsasStMenu.add(sessit);
2234 // don't show an empty menu.
2235 VamsasStMenu.setVisible(sess.length > 0);
2240 jalview.bin.Cache.log.debug("No current vamsas sessions.");
2241 VamsasStMenu.removeAll();
2242 VamsasStMenu.setVisible(false);
2247 // Not interested in the content. Just hide ourselves.
2248 VamsasStMenu.setVisible(false);
2253 public void vamsasSave_actionPerformed(ActionEvent e)
2255 if (v_client != null)
2257 // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
2258 JalviewFileChooser chooser = new JalviewFileChooser("vdj",
2261 chooser.setFileView(new JalviewFileView());
2262 chooser.setDialogTitle(MessageManager
2263 .getString("label.save_vamsas_document_archive"));
2265 int value = chooser.showSaveDialog(this);
2267 if (value == JalviewFileChooser.APPROVE_OPTION)
2269 java.io.File choice = chooser.getSelectedFile();
2270 JPanel progpanel = addProgressPanel(MessageManager
2271 .formatMessage("label.saving_vamsas_doc", new Object[]
2272 { choice.getName() }));
2273 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
2274 String warnmsg = null;
2275 String warnttl = null;
2278 v_client.vclient.storeDocument(choice);
2281 warnttl = "Serious Problem saving Vamsas Document";
2282 warnmsg = ex.toString();
2283 jalview.bin.Cache.log
2284 .error("Error Whilst saving document to " + choice, ex);
2286 } catch (Exception ex)
2288 warnttl = "Problem saving Vamsas Document.";
2289 warnmsg = ex.toString();
2290 jalview.bin.Cache.log.warn(
2291 "Exception Whilst saving document to " + choice, ex);
2294 removeProgressPanel(progpanel);
2295 if (warnmsg != null)
2297 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2299 warnmsg, warnttl, JvOptionPane.ERROR_MESSAGE);
2305 JPanel vamUpdate = null;
2308 * hide vamsas user gui bits when a vamsas document event is being handled.
2311 * true to hide gui, false to reveal gui
2313 public void setVamsasUpdate(boolean b)
2315 Cache.log.debug("Setting gui for Vamsas update "
2316 + (b ? "in progress" : "finished"));
2318 if (vamUpdate != null)
2320 this.removeProgressPanel(vamUpdate);
2324 vamUpdate = this.addProgressPanel(
2325 MessageManager.getString("label.updating_vamsas_session"));
2327 vamsasStart.setVisible(!b);
2328 vamsasStop.setVisible(!b);
2329 vamsasSave.setVisible(!b);
2332 public JInternalFrame[] getAllFrames()
2334 return desktop.getAllFrames();
2338 * Checks the given url to see if it gives a response indicating that the user
2339 * should be informed of a new questionnaire.
2343 public void checkForQuestionnaire(String url)
2345 UserQuestionnaireCheck jvq = new UserQuestionnaireCheck(url);
2346 // javax.swing.SwingUtilities.invokeLater(jvq);
2347 new Thread(jvq).start();
2350 public void checkURLLinks()
2352 // Thread off the URL link checker
2353 addDialogThread(new Runnable()
2358 if (/** @j2sNative false && */ // BH 2018
2359 Cache.getDefault("CHECKURLLINKS", true))
2361 // check what the actual links are - if it's just the default don't
2362 // bother with the warning
2363 List<String> links = Preferences.sequenceUrlLinks
2366 // only need to check links if there is one with a
2367 // SEQUENCE_ID which is not the default EMBL_EBI link
2368 ListIterator<String> li = links.listIterator();
2369 boolean check = false;
2370 List<JLabel> urls = new ArrayList<>();
2371 while (li.hasNext())
2373 String link = li.next();
2374 if (link.contains(SEQUENCE_ID)
2375 && !UrlConstants.isDefaultString(link))
2378 int barPos = link.indexOf("|");
2379 String urlMsg = barPos == -1 ? link
2380 : link.substring(0, barPos) + ": "
2381 + link.substring(barPos + 1);
2382 urls.add(new JLabel(urlMsg));
2390 // ask user to check in case URL links use old style tokens
2391 // ($SEQUENCE_ID$ for sequence id _or_ accession id)
2392 JPanel msgPanel = new JPanel();
2393 msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.PAGE_AXIS));
2394 msgPanel.add(Box.createVerticalGlue());
2395 JLabel msg = new JLabel(MessageManager
2396 .getString("label.SEQUENCE_ID_for_DB_ACCESSION1"));
2397 JLabel msg2 = new JLabel(MessageManager
2398 .getString("label.SEQUENCE_ID_for_DB_ACCESSION2"));
2400 for (JLabel url : urls)
2406 final JCheckBox jcb = new JCheckBox(
2407 MessageManager.getString("label.do_not_display_again"));
2408 jcb.addActionListener(new ActionListener()
2411 public void actionPerformed(ActionEvent e)
2413 // update Cache settings for "don't show this again"
2414 boolean showWarningAgain = !jcb.isSelected();
2415 Cache.setProperty("CHECKURLLINKS",
2416 Boolean.valueOf(showWarningAgain).toString());
2421 JvOptionPane.showMessageDialog(Desktop.desktop, msgPanel,
2423 .getString("label.SEQUENCE_ID_no_longer_used"),
2424 JvOptionPane.WARNING_MESSAGE);
2431 * Proxy class for JDesktopPane which optionally displays the current memory
2432 * usage and highlights the desktop area with a red bar if free memory runs
2437 public class MyDesktopPane extends JDesktopPane
2438 implements Runnable, PropertyChangeListener
2441 public Object[] dialogData;
2445 public void propertyChange(PropertyChangeEvent event)
2447 Object val = event.getNewValue();
2448 String name = event.getPropertyName();
2449 System.out.println(name);
2450 switch (event.getSource().getClass().getName())
2452 case "javax.swing.JOptionPane":
2456 onDialogReturn(val);
2459 if (val instanceof Integer)
2461 onDialogReturn(((Integer) val).intValue());
2465 onDialogReturn(val);
2470 case "javax.swing.ColorChooserDialog":
2473 case "SelectedColor":
2474 onDialogReturn(val);
2478 case "javax.swing.JFileChooser":
2481 case "SelectedFile":
2482 File file = (File) val;
2483 byte[] array = (val == null ? null
2484 : /** @j2sNative file._bytes || */
2486 onDialogReturn("fileName is '" + file.getName() + "'\n\n"
2487 + new String(array));
2492 System.out.println(event.getSource().getClass().getName() + " "
2493 + event.getPropertyName() + ": " + event.getNewValue());
2496 // JSCOmponent.DialogCaller interface
2497 private void onDialogReturn(Object value)
2499 System.out.println("not implemented");
2502 // JSCOmponent.DialogCaller interface
2503 void onDialogReturn(int value)
2505 if (value != Math.floor(value))
2507 // in JavaScript, this will be NaN, oddly enough
2511 switch ((String) dialogData[0])
2513 case "label.input_alignment_from_url":
2514 // reconstruct the parameter data
2516 AlignViewport viewport = (AlignViewport) dialogData[1];
2517 JComboBox history = (JComboBox) dialogData[2];
2518 // the rest of this is unchangaed
2519 if (reply != JvOptionPane.OK_OPTION)
2524 String url = history.getSelectedItem().toString();
2526 if (url.toLowerCase().endsWith(".jar"))
2528 if (viewport != null)
2530 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2531 FileFormat.Jalview);
2535 new FileLoader().LoadFile(url, DataSourceType.URL,
2536 FileFormat.Jalview);
2541 FileFormatI format = null;
2544 format = new IdentifyFile().identify(url, DataSourceType.URL);
2545 } catch (FileFormatException e)
2547 // TODO revise error handling, distinguish between
2548 // URL not found and response not valid
2553 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2554 MessageManager.formatMessage("label.couldnt_locate",
2557 MessageManager.getString("label.url_not_found"),
2558 JvOptionPane.WARNING_MESSAGE);
2563 if (viewport != null)
2565 new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
2570 new FileLoader().LoadFile(url, DataSourceType.URL, format);
2579 private static final float ONE_MB = 1048576f;
2581 boolean showMemoryUsage = false;
2585 java.text.NumberFormat df;
2587 float maxMemory, allocatedMemory, freeMemory, totalFreeMemory,
2590 public MyDesktopPane(boolean showMemoryUsage)
2592 showMemoryUsage(showMemoryUsage);
2595 public void showMemoryUsage(boolean showMemory)
2597 this.showMemoryUsage = showMemory;
2600 Thread worker = new Thread(this);
2606 public boolean isShowMemoryUsage()
2608 return showMemoryUsage;
2614 df = java.text.NumberFormat.getNumberInstance();
2615 df.setMaximumFractionDigits(2);
2616 runtime = Runtime.getRuntime();
2618 while (showMemoryUsage)
2622 maxMemory = runtime.maxMemory() / ONE_MB;
2623 allocatedMemory = runtime.totalMemory() / ONE_MB;
2624 freeMemory = runtime.freeMemory() / ONE_MB;
2625 totalFreeMemory = freeMemory + (maxMemory - allocatedMemory);
2627 percentUsage = (totalFreeMemory / maxMemory) * 100;
2629 // if (percentUsage < 20)
2631 // border1 = BorderFactory.createMatteBorder(12, 12, 12, 12,
2633 // instance.set.setBorder(border1);
2636 // sleep after showing usage
2638 } catch (Exception ex)
2640 ex.printStackTrace();
2646 public void paintComponent(Graphics g)
2648 if (showMemoryUsage && g != null && df != null)
2650 if (percentUsage < 20)
2652 g.setColor(Color.red);
2654 FontMetrics fm = g.getFontMetrics();
2657 g.drawString(MessageManager.formatMessage("label.memory_stats",
2659 { df.format(totalFreeMemory), df.format(maxMemory),
2660 df.format(percentUsage) }),
2661 10, getHeight() - fm.getHeight());
2669 * Accessor method to quickly get all the AlignmentFrames loaded.
2671 * @return an array of AlignFrame, or null if none found
2673 public static AlignFrame[] getAlignFrames()
2675 if (Jalview.isHeadlessMode())
2677 // Desktop.desktop is null in headless mode
2678 return new AlignFrame[] { Jalview.currentAlignFrame };
2681 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2687 List<AlignFrame> avp = new ArrayList<>();
2689 for (int i = frames.length - 1; i > -1; i--)
2691 if (frames[i] instanceof AlignFrame)
2693 avp.add((AlignFrame) frames[i]);
2695 else if (frames[i] instanceof SplitFrame)
2698 * Also check for a split frame containing an AlignFrame
2700 GSplitFrame sf = (GSplitFrame) frames[i];
2701 if (sf.getTopFrame() instanceof AlignFrame)
2703 avp.add((AlignFrame) sf.getTopFrame());
2705 if (sf.getBottomFrame() instanceof AlignFrame)
2707 avp.add((AlignFrame) sf.getBottomFrame());
2711 if (avp.size() == 0)
2715 AlignFrame afs[] = avp.toArray(new AlignFrame[avp.size()]);
2720 * Returns an array of any AppJmol frames in the Desktop (or null if none).
2724 public GStructureViewer[] getJmols()
2726 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
2732 List<GStructureViewer> avp = new ArrayList<>();
2734 for (int i = frames.length - 1; i > -1; i--)
2736 if (frames[i] instanceof AppJmol)
2738 GStructureViewer af = (GStructureViewer) frames[i];
2742 if (avp.size() == 0)
2746 GStructureViewer afs[] = avp.toArray(new GStructureViewer[avp.size()]);
2751 * Add Groovy Support to Jalview
2754 public void groovyShell_actionPerformed()
2758 openGroovyConsole();
2759 } catch (Exception ex)
2761 jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
2762 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
2764 MessageManager.getString("label.couldnt_create_groovy_shell"),
2765 MessageManager.getString("label.groovy_support_failed"),
2766 JvOptionPane.ERROR_MESSAGE);
2771 * Open the Groovy console
2773 void openGroovyConsole()
2775 if (groovyConsole == null)
2777 groovyConsole = new groovy.ui.Console();
2778 groovyConsole.setVariable("Jalview", this);
2779 groovyConsole.run();
2782 * We allow only one console at a time, so that AlignFrame menu option
2783 * 'Calculate | Run Groovy script' is unambiguous.
2784 * Disable 'Groovy Console', and enable 'Run script', when the console is
2785 * opened, and the reverse when it is closed
2787 Window window = (Window) groovyConsole.getFrame();
2788 window.addWindowListener(new WindowAdapter()
2791 public void windowClosed(WindowEvent e)
2794 * rebind CMD-Q from Groovy Console to Jalview Quit
2797 enableExecuteGroovy(false);
2803 * show Groovy console window (after close and reopen)
2805 ((Window) groovyConsole.getFrame()).setVisible(true);
2808 * if we got this far, enable 'Run Groovy' in AlignFrame menus
2809 * and disable opening a second console
2811 enableExecuteGroovy(true);
2815 * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
2816 * binding when opened
2818 protected void addQuitHandler()
2820 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
2821 .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
2822 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
2824 getRootPane().getActionMap().put("Quit", new AbstractAction()
2827 public void actionPerformed(ActionEvent e)
2835 * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
2838 * true if Groovy console is open
2840 public void enableExecuteGroovy(boolean enabled)
2843 * disable opening a second Groovy console
2844 * (or re-enable when the console is closed)
2846 groovyShell.setEnabled(!enabled);
2848 AlignFrame[] alignFrames = getAlignFrames();
2849 if (alignFrames != null)
2851 for (AlignFrame af : alignFrames)
2853 af.setGroovyEnabled(enabled);
2859 * Progress bars managed by the IProgressIndicator method.
2861 private Hashtable<Long, JPanel> progressBars;
2863 private Hashtable<Long, IProgressIndicatorHandler> progressBarHandlers;
2868 * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
2871 public void setProgressBar(String message, long id)
2873 if (progressBars == null)
2875 progressBars = new Hashtable<>();
2876 progressBarHandlers = new Hashtable<>();
2879 if (progressBars.get(new Long(id)) != null)
2881 JPanel panel = progressBars.remove(new Long(id));
2882 if (progressBarHandlers.contains(new Long(id)))
2884 progressBarHandlers.remove(new Long(id));
2886 removeProgressPanel(panel);
2890 progressBars.put(new Long(id), addProgressPanel(message));
2897 * @see jalview.gui.IProgressIndicator#registerHandler(long,
2898 * jalview.gui.IProgressIndicatorHandler)
2901 public void registerHandler(final long id,
2902 final IProgressIndicatorHandler handler)
2904 if (progressBarHandlers == null
2905 || !progressBars.containsKey(new Long(id)))
2907 throw new Error(MessageManager.getString(
2908 "error.call_setprogressbar_before_registering_handler"));
2910 progressBarHandlers.put(new Long(id), handler);
2911 final JPanel progressPanel = progressBars.get(new Long(id));
2912 if (handler.canCancel())
2914 JButton cancel = new JButton(
2915 MessageManager.getString("action.cancel"));
2916 final IProgressIndicator us = this;
2917 cancel.addActionListener(new ActionListener()
2921 public void actionPerformed(ActionEvent e)
2923 handler.cancelActivity(id);
2924 us.setProgressBar(MessageManager
2925 .formatMessage("label.cancelled_params", new Object[]
2926 { ((JLabel) progressPanel.getComponent(0)).getText() }),
2930 progressPanel.add(cancel, BorderLayout.EAST);
2936 * @return true if any progress bars are still active
2939 public boolean operationInProgress()
2941 if (progressBars != null && progressBars.size() > 0)
2949 * This will return the first AlignFrame holding the given viewport instance.
2950 * It will break if there are more than one AlignFrames viewing a particular
2954 * @return alignFrame for viewport
2956 public static AlignFrame getAlignFrameFor(AlignViewportI viewport)
2958 if (desktop != null)
2960 AlignmentPanel[] aps = getAlignmentPanels(
2961 viewport.getSequenceSetId());
2962 for (int panel = 0; aps != null && panel < aps.length; panel++)
2964 if (aps[panel] != null && aps[panel].av == viewport)
2966 return aps[panel].alignFrame;
2973 public VamsasApplication getVamsasApplication()
2980 * flag set if jalview GUI is being operated programmatically
2982 private boolean inBatchMode = false;
2985 * check if jalview GUI is being operated programmatically
2987 * @return inBatchMode
2989 public boolean isInBatchMode()
2995 * set flag if jalview GUI is being operated programmatically
2997 * @param inBatchMode
2999 public void setInBatchMode(boolean inBatchMode)
3001 this.inBatchMode = inBatchMode;
3004 public void startServiceDiscovery()
3006 startServiceDiscovery(false);
3009 public void startServiceDiscovery(boolean blocking)
3011 boolean alive = true;
3012 Thread t0 = null, t1 = null, t2 = null;
3013 // JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
3016 // todo: changesupport handlers need to be transferred
3017 if (discoverer == null)
3019 discoverer = new jalview.ws.jws1.Discoverer();
3020 // register PCS handler for desktop.
3021 discoverer.addPropertyChangeListener(changeSupport);
3023 // JAL-940 - disabled JWS1 service configuration - always start discoverer
3024 // until we phase out completely
3025 (t0 = new Thread(discoverer)).start();
3028 if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3030 t2 = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3031 .startDiscoverer(changeSupport);
3035 // TODO: do rest service discovery
3044 } catch (Exception e)
3047 alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
3048 || (t3 != null && t3.isAlive())
3049 || (t0 != null && t0.isAlive());
3055 * called to check if the service discovery process completed successfully.
3059 protected void JalviewServicesChanged(PropertyChangeEvent evt)
3061 if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
3063 final String ermsg = jalview.ws.jws2.Jws2Discoverer.getDiscoverer()
3064 .getErrorMessages();
3067 if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
3069 if (serviceChangedDialog == null)
3071 // only run if we aren't already displaying one of these.
3072 addDialogThread(serviceChangedDialog = new Runnable()
3079 * JalviewDialog jd =new JalviewDialog() {
3081 * @Override protected void cancelPressed() { // TODO
3082 * Auto-generated method stub
3084 * }@Override protected void okPressed() { // TODO
3085 * Auto-generated method stub
3087 * }@Override protected void raiseClosed() { // TODO
3088 * Auto-generated method stub
3090 * } }; jd.initDialogFrame(new
3091 * JLabel("<html><table width=\"450\"><tr><td>" + ermsg +
3092 * "<br/>It may be that you have invalid JABA URLs in your web service preferences,"
3093 * + " or mis-configured HTTP proxy settings.<br/>" +
3094 * "Check the <em>Connections</em> and <em>Web services</em> tab of the"
3096 * " Tools->Preferences dialog box to change them.</td></tr></table></html>"
3097 * ), true, true, "Web Service Configuration Problem", 450,
3100 * jd.waitForInput();
3102 JvOptionPane.showConfirmDialog(Desktop.desktop,
3103 new JLabel("<html><table width=\"450\"><tr><td>"
3104 + ermsg + "</td></tr></table>"
3105 + "<p>It may be that you have invalid JABA URLs<br/>in your web service preferences,"
3106 + "<br>or as a command-line argument, or mis-configured HTTP proxy settings.</p>"
3107 + "<p>Check the <em>Connections</em> and <em>Web services</em> tab<br/>of the"
3108 + " Tools->Preferences dialog box to change them.</p></html>"),
3109 "Web Service Configuration Problem",
3110 JvOptionPane.DEFAULT_OPTION,
3111 JvOptionPane.ERROR_MESSAGE);
3112 serviceChangedDialog = null;
3121 "Errors reported by JABA discovery service. Check web services preferences.\n"
3128 private Runnable serviceChangedDialog = null;
3131 * start a thread to open a URL in the configured browser. Pops up a warning
3132 * dialog to the user if there is an exception when calling out to the browser
3137 public static void showUrl(final String url)
3139 showUrl(url, Desktop.instance);
3143 * Like showUrl but allows progress handler to be specified
3147 * (null) or object implementing IProgressIndicator
3149 public static void showUrl(final String url,
3150 final IProgressIndicator progress)
3152 new Thread(new Runnable()
3159 if (progress != null)
3161 progress.setProgressBar(MessageManager
3162 .formatMessage("status.opening_params", new Object[]
3163 { url }), this.hashCode());
3165 jalview.util.BrowserLauncher.openURL(url);
3166 } catch (Exception ex)
3168 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
3170 .getString("label.web_browser_not_found_unix"),
3171 MessageManager.getString("label.web_browser_not_found"),
3172 JvOptionPane.WARNING_MESSAGE);
3174 ex.printStackTrace();
3176 if (progress != null)
3178 progress.setProgressBar(null, this.hashCode());
3184 public static WsParamSetManager wsparamManager = null;
3186 public static ParamManager getUserParameterStore()
3188 if (wsparamManager == null)
3190 wsparamManager = new WsParamSetManager();
3192 return wsparamManager;
3196 * static hyperlink handler proxy method for use by Jalview's internal windows
3200 public static void hyperlinkUpdate(HyperlinkEvent e)
3202 if (e.getEventType() == EventType.ACTIVATED)
3207 url = e.getURL().toString();
3208 Desktop.showUrl(url);
3209 } catch (Exception x)
3213 if (Cache.log != null)
3215 Cache.log.error("Couldn't handle string " + url + " as a URL.");
3220 "Couldn't handle string " + url + " as a URL.");
3223 // ignore any exceptions due to dud links.
3230 * single thread that handles display of dialogs to user.
3232 ExecutorService dialogExecutor = Executors.newSingleThreadExecutor();
3235 * flag indicating if dialogExecutor should try to acquire a permit
3237 private volatile boolean dialogPause = true;
3242 private java.util.concurrent.Semaphore block = new Semaphore(0);
3244 private static groovy.ui.Console groovyConsole;
3247 * add another dialog thread to the queue
3251 public void addDialogThread(final Runnable prompter)
3253 dialogExecutor.submit(new Runnable()
3263 } catch (InterruptedException x)
3268 if (instance == null)
3274 SwingUtilities.invokeAndWait(prompter);
3275 } catch (Exception q)
3277 Cache.log.warn("Unexpected Exception in dialog thread.", q);
3283 public void startDialogQueue()
3285 // set the flag so we don't pause waiting for another permit and semaphore
3286 // the current task to begin
3287 dialogPause = false;
3292 protected void snapShotWindow_actionPerformed(ActionEvent e)
3296 ImageMaker im = new jalview.util.ImageMaker(
3297 this, ImageMaker.TYPE.EPS, "View of Desktop", getWidth(),
3298 getHeight(), of = new File("Jalview_snapshot"
3299 + System.currentTimeMillis() + ".eps"),
3300 "View of desktop", null, 0, false);
3303 paintAll(im.getGraphics());
3305 } catch (Exception q)
3307 Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
3311 Cache.log.info("Successfully written snapshot to file "
3312 + of.getAbsolutePath());
3316 * Explode the views in the given SplitFrame into separate SplitFrame windows.
3317 * This respects (remembers) any previous 'exploded geometry' i.e. the size
3318 * and location last time the view was expanded (if any). However it does not
3319 * remember the split pane divider location - this is set to match the
3320 * 'exploding' frame.
3324 public void explodeViews(SplitFrame sf)
3326 AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
3327 AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
3328 List<? extends AlignmentViewPanel> topPanels = oldTopFrame
3330 List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
3332 int viewCount = topPanels.size();
3339 * Processing in reverse order works, forwards order leaves the first panels
3340 * not visible. I don't know why!
3342 for (int i = viewCount - 1; i >= 0; i--)
3345 * Make new top and bottom frames. These take over the respective
3346 * AlignmentPanel objects, including their AlignmentViewports, so the
3347 * cdna/protein relationships between the viewports is carried over to the
3350 * explodedGeometry holds the (x, y) position of the previously exploded
3351 * SplitFrame, and the (width, height) of the AlignFrame component
3353 AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
3354 AlignFrame newTopFrame = new AlignFrame(topPanel);
3355 newTopFrame.setSize(oldTopFrame.getSize());
3356 newTopFrame.setVisible(true);
3357 Rectangle geometry = ((AlignViewport) topPanel.getAlignViewport())
3358 .getExplodedGeometry();
3359 if (geometry != null)
3361 newTopFrame.setSize(geometry.getSize());
3364 AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
3365 AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
3366 newBottomFrame.setSize(oldBottomFrame.getSize());
3367 newBottomFrame.setVisible(true);
3368 geometry = ((AlignViewport) bottomPanel.getAlignViewport())
3369 .getExplodedGeometry();
3370 if (geometry != null)
3372 newBottomFrame.setSize(geometry.getSize());
3375 topPanel.av.setGatherViewsHere(false);
3376 bottomPanel.av.setGatherViewsHere(false);
3377 JInternalFrame splitFrame = new SplitFrame(newTopFrame,
3379 if (geometry != null)
3381 splitFrame.setLocation(geometry.getLocation());
3383 Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
3387 * Clear references to the panels (now relocated in the new SplitFrames)
3388 * before closing the old SplitFrame.
3391 bottomPanels.clear();
3396 * Gather expanded split frames, sharing the same pairs of sequence set ids,
3397 * back into the given SplitFrame as additional views. Note that the gathered
3398 * frames may themselves have multiple views.
3402 public void gatherViews(GSplitFrame source)
3405 * special handling of explodedGeometry for a view within a SplitFrame: - it
3406 * holds the (x, y) position of the enclosing SplitFrame, and the (width,
3407 * height) of the AlignFrame component
3409 AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
3410 AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
3411 myTopFrame.viewport.setExplodedGeometry(new Rectangle(source.getX(),
3412 source.getY(), myTopFrame.getWidth(), myTopFrame.getHeight()));
3413 myBottomFrame.viewport
3414 .setExplodedGeometry(new Rectangle(source.getX(), source.getY(),
3415 myBottomFrame.getWidth(), myBottomFrame.getHeight()));
3416 myTopFrame.viewport.setGatherViewsHere(true);
3417 myBottomFrame.viewport.setGatherViewsHere(true);
3418 String topViewId = myTopFrame.viewport.getSequenceSetId();
3419 String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
3421 JInternalFrame[] frames = desktop.getAllFrames();
3422 for (JInternalFrame frame : frames)
3424 if (frame instanceof SplitFrame && frame != source)
3426 SplitFrame sf = (SplitFrame) frame;
3427 AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
3428 AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
3429 boolean gatherThis = false;
3430 for (int a = 0; a < topFrame.alignPanels.size(); a++)
3432 AlignmentPanel topPanel = topFrame.alignPanels.get(a);
3433 AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
3434 if (topViewId.equals(topPanel.av.getSequenceSetId())
3435 && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
3438 topPanel.av.setGatherViewsHere(false);
3439 bottomPanel.av.setGatherViewsHere(false);
3440 topPanel.av.setExplodedGeometry(
3441 new Rectangle(sf.getLocation(), topFrame.getSize()));
3442 bottomPanel.av.setExplodedGeometry(
3443 new Rectangle(sf.getLocation(), bottomFrame.getSize()));
3444 myTopFrame.addAlignmentPanel(topPanel, false);
3445 myBottomFrame.addAlignmentPanel(bottomPanel, false);
3451 topFrame.getAlignPanels().clear();
3452 bottomFrame.getAlignPanels().clear();
3459 * The dust settles...give focus to the tab we did this from.
3461 myTopFrame.setDisplayedView(myTopFrame.alignPanel);
3464 public static groovy.ui.Console getGroovyConsole()
3466 return groovyConsole;
3470 * handles the payload of a drag and drop event.
3472 * TODO refactor to desktop utilities class
3475 * - Data source strings extracted from the drop event
3477 * - protocol for each data source extracted from the drop event
3481 * - the payload from the drop event
3484 public static void transferFromDropTarget(List<String> files,
3485 List<DataSourceType> protocols, DropTargetDropEvent evt,
3486 Transferable t) throws Exception
3489 DataFlavor uriListFlavor = new DataFlavor(
3490 "text/uri-list;class=java.lang.String"), urlFlavour = null;
3493 urlFlavour = new DataFlavor(
3494 "application/x-java-url; class=java.net.URL");
3495 } catch (ClassNotFoundException cfe)
3497 Cache.log.debug("Couldn't instantiate the URL dataflavor.", cfe);
3500 if (urlFlavour != null && t.isDataFlavorSupported(urlFlavour))
3505 java.net.URL url = (URL) t.getTransferData(urlFlavour);
3506 // nb: java 8 osx bug https://bugs.openjdk.java.net/browse/JDK-8156099
3507 // means url may be null.
3510 protocols.add(DataSourceType.URL);
3511 files.add(url.toString());
3512 Cache.log.debug("Drop handled as URL dataflavor "
3513 + files.get(files.size() - 1));
3518 if (Platform.isAMac())
3521 "Please ignore plist error - occurs due to problem with java 8 on OSX");
3525 } catch (Throwable ex)
3527 Cache.log.debug("URL drop handler failed.", ex);
3530 if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
3532 // Works on Windows and MacOSX
3533 Cache.log.debug("Drop handled as javaFileListFlavor");
3534 for (Object file : (List) t
3535 .getTransferData(DataFlavor.javaFileListFlavor))
3537 files.add(((File) file).toString());
3538 protocols.add(DataSourceType.FILE);
3543 // Unix like behaviour
3544 boolean added = false;
3546 if (t.isDataFlavorSupported(uriListFlavor))
3548 Cache.log.debug("Drop handled as uriListFlavor");
3549 // This is used by Unix drag system
3550 data = (String) t.getTransferData(uriListFlavor);
3554 // fallback to text: workaround - on OSX where there's a JVM bug
3555 Cache.log.debug("standard URIListFlavor failed. Trying text");
3556 // try text fallback
3557 DataFlavor textDf = new DataFlavor(
3558 "text/plain;class=java.lang.String");
3559 if (t.isDataFlavorSupported(textDf))
3561 data = (String) t.getTransferData(textDf);
3564 Cache.log.debug("Plain text drop content returned "
3565 + (data == null ? "Null - failed" : data));
3570 while (protocols.size() < files.size())
3572 Cache.log.debug("Adding missing FILE protocol for "
3573 + files.get(protocols.size()));
3574 protocols.add(DataSourceType.FILE);
3576 for (java.util.StringTokenizer st = new java.util.StringTokenizer(
3577 data, "\r\n"); st.hasMoreTokens();)
3580 String s = st.nextToken();
3581 if (s.startsWith("#"))
3583 // the line is a comment (as per the RFC 2483)
3586 java.net.URI uri = new java.net.URI(s);
3587 if (uri.getScheme().toLowerCase().startsWith("http"))
3589 protocols.add(DataSourceType.URL);
3590 files.add(uri.toString());
3594 // otherwise preserve old behaviour: catch all for file objects
3595 java.io.File file = new java.io.File(uri);
3596 protocols.add(DataSourceType.FILE);
3597 files.add(file.toString());
3602 if (Cache.log.isDebugEnabled())
3604 if (data == null || !added)
3607 if (t.getTransferDataFlavors() != null
3608 && t.getTransferDataFlavors().length > 0)
3611 "Couldn't resolve drop data. Here are the supported flavors:");
3612 for (DataFlavor fl : t.getTransferDataFlavors())
3615 "Supported transfer dataflavor: " + fl.toString());
3616 Object df = t.getTransferData(fl);
3619 Cache.log.debug("Retrieves: " + df);
3623 Cache.log.debug("Retrieved nothing");
3629 Cache.log.debug("Couldn't resolve dataflavor for drop: "
3635 if (Platform.isWindows())
3638 Cache.log.debug("Scanning dropped content for Windows Link Files");
3640 // resolve any .lnk files in the file drop
3641 for (int f = 0; f < files.size(); f++)
3643 String source = files.get(f).toLowerCase();
3644 if (protocols.get(f).equals(DataSourceType.FILE)
3645 && (source.endsWith(".lnk") || source.endsWith(".url")
3646 || source.endsWith(".site")))
3649 File lf = new File(files.get(f));
3650 // process link file to get a URL
3651 Cache.log.debug("Found potential link file: " + lf);
3652 WindowsShortcut wscfile = new WindowsShortcut(lf);
3653 String fullname = wscfile.getRealFilename();
3654 protocols.set(f, FormatAdapter.checkProtocol(fullname));
3655 files.set(f, fullname);
3656 Cache.log.debug("Parsed real filename " + fullname
3657 + " to extract protocol: " + protocols.get(f));
3659 catch (Exception ex)
3661 Cache.log.error("Couldn't parse "+files.get(f)+" as a link file.",ex);
3669 * Sets the Preferences property for experimental features to True or False
3670 * depending on the state of the controlling menu item
3673 protected void showExperimental_actionPerformed(boolean selected)
3675 Cache.setProperty(EXPERIMENTAL_FEATURES, Boolean.toString(selected));
3679 * Answers a (possibly empty) list of any structure viewer frames (currently
3680 * for either Jmol or Chimera) which are currently open. This may optionally
3681 * be restricted to viewers of a specified class, or viewers linked to a
3682 * specified alignment panel.
3685 * if not null, only return viewers linked to this panel
3686 * @param structureViewerClass
3687 * if not null, only return viewers of this class
3690 public List<StructureViewerBase> getStructureViewers(
3691 AlignmentPanel apanel,
3692 Class<? extends StructureViewerBase> structureViewerClass)
3694 List<StructureViewerBase> result = new ArrayList<>();
3695 JInternalFrame[] frames = Desktop.instance.getAllFrames();
3697 for (JInternalFrame frame : frames)
3699 if (frame instanceof StructureViewerBase)
3701 if (structureViewerClass == null
3702 || structureViewerClass.isInstance(frame))
3705 || ((StructureViewerBase) frame).isLinkedWith(apanel))
3707 result.add((StructureViewerBase) frame);