/*******************************************************************************
* Copyright (c) 2008 Cedric Chabanois and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cedric Chabanois - initial API and implementation
*******************************************************************************/
package org.eclipse.swtbot.swt.finder.finders;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swtbot.swt.finder.results.VoidResult;
import org.eclipse.swtbot.swt.finder.utils.SWTUtils;
import org.eclipse.swtbot.swt.finder.utils.internal.Assert;
/**
* Context menu finder that uses events to get the current context menu. It must be used instead of ContextMenuFinder
* when the context menu is not associated with a Widget. It must be registered before the context menu appears.
* <p>
* Here is a sample usage:
* </p>
*
* <pre>
* EventContextMenuFinder eventContextMenuFinder = new EventContextMenuFinder();
* try {
* eventContextMenuFinder.register();
* button.click(); // a popup menu appears below the button
* SWTBotMenu menu = new SWTBotMenu(new Finder(new ControlFinder(), eventContextMenuFinder), "Menu Text");
* menu.click();
* } finally {
* eventContextMenuFinder.unregister();
* }
* </pre>
*
* This is not convenient to use but the need for this is not so frequent. In case you have better idea on the
* implementation or usage please add a comment to <a href="http://swtbot.org/bugzilla/show_bug.cgi?id=19">this bug</a>.
*
* @author Cedric Chabanois <cchabanois [at] no-log [dot] org>
* @version $Id$
* @since 1.0
*/
public class EventContextMenuFinder extends MenuFinder {
/**
* The current context menu.
*/
private Menu currentContextMenu = null;
/**
* The listener to be used.
*/
private final ShowHideListener showHideListener;
/**
* The display to use.
*/
private final Display display;
/**
* Creates an event based context menu finder.
*
* @param display the display
* @throws NullPointerException Thrown if the display is <code>null</code>.
*/
public EventContextMenuFinder(Display display) {
Assert.isNotNull(display, "The display can not be null"); //$NON-NLS-1$
this.display = display;
showHideListener = new ShowHideListener();
}
/**
* Creates an event based context menu finder.
*/
public EventContextMenuFinder() {
this(SWTUtils.display());
}
/**
* Registers this finder so that it may start 'looking for' controls. It does so by listening for {@link SWT#Show}
* and {@link SWT#Hide} events on menus.
*/
public void register() {
UIThreadRunnable.syncExec(display, new VoidResult() {
public void run() {
display.addFilter(SWT.Show, showHideListener);
display.addFilter(SWT.Hide, showHideListener);
}
});
}
/**
* Unregisters this finder so that it may stop 'looking for' controls. It does so by listening for {@link SWT#Show}
* and {@link SWT#Hide} events on menus.
*/
public void unregister() {
UIThreadRunnable.syncExec(display, new VoidResult() {
public void run() {
display.removeFilter(SWT.Show, showHideListener);
display.removeFilter(SWT.Hide, showHideListener);
}
});
}
/**
* Gets the menu bar that has been found. This may be <code>null</code> if one had not been found yet.
*
* @see org.eclipse.swtbot.swt.finder.finders.MenuFinder#menuBar(org.eclipse.swt.widgets.Shell)
* @param shell This is not used.
* @return The menu or <code>null</code> if not yet found.
*/
@Override
protected Menu menuBar(final Shell shell) {
return currentContextMenu;
}
/**
* A private class to listen for the show/hide events.
*/
private class ShowHideListener implements Listener {
/**
* Handles the event by checking if it is the proper event. If it is a show, then the current context menu is
* set. Otherwise it will be set to <code>null</code> if it is a hide event.
*
* @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)
* @param event the event to check.
*/
public void handleEvent(Event event) {
if (!(event.widget instanceof Menu))
return;
Menu menu = (Menu) event.widget;
if (SWTUtils.hasStyle(menu, SWT.POP_UP)) {
if (event.type == SWT.Show)
currentContextMenu = menu;
if (event.type == SWT.Hide)
currentContextMenu = null;
}
}
}
}