/*******************************************************************************
* Copyright (c) 2012 University of Mannheim: Chair for Software Engineering
* 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:
* Ralph Gerbig - initial API and implementation and initial documentation
*******************************************************************************/
package de.uni_mannheim.informatik.swt.mlm.tests.core.ui;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable;
import org.eclipse.swtbot.swt.finder.results.ArrayResult;
import org.eclipse.swtbot.swt.finder.results.BoolResult;
import org.eclipse.swtbot.swt.finder.results.VoidResult;
import org.eclipse.swtbot.swt.finder.utils.MessageFormat;
import org.eclipse.swtbot.swt.finder.utils.SWTBotEvents;
import org.eclipse.swtbot.swt.finder.utils.SWTBotPreferences;
import org.eclipse.swtbot.swt.finder.utils.SWTUtils;
/**
* This class is the SWTUtils class extended by the click feature
* copied from AbstractSWTBotControl.
*/
public abstract class SWTUtilsEx extends SWTUtils {
/** The logger. */
private static Logger log = Logger.getLogger(SWTUtils.class);
/** With great power comes great responsibility, use carefully. */
private static Widget widget;
/** With great power comes great responsibility, use carefully. */
private static Display display;
/**
* Click on the table at given coordinates
*
* @param x the x co-ordinate of the click
* @param y the y co-ordinate of the click
* @since 2.0
*/
public static void clickXY(int x, int y, Widget w) {
widget = w;
display = w.getDisplay();
log.debug(MessageFormat.format("Clicking on {0}", widget.toString())); //$NON-NLS-1$
notify(SWT.MouseEnter);
notify(SWT.MouseMove);
notify(SWT.Activate);
notify(SWT.FocusIn);
notify(SWT.MouseDown, createMouseEvent(x, y, 1, SWT.NONE, 1));
notify(SWT.MouseUp, createMouseEvent(x, y, 1, SWT.BUTTON1, 1));
notify(SWT.Selection, createSelectionEvent(SWT.BUTTON1));
notify(SWT.MouseHover);
notify(SWT.MouseMove);
notify(SWT.MouseExit);
notify(SWT.Deactivate);
notify(SWT.FocusOut);
log.debug(MessageFormat.format("Clicked on {0}", widget.toString())); //$NON-NLS-1$
}
/**
* Sends a non-blocking notification of the specified type to the widget.
*
* @param eventType the event type.
* @see Widget#notifyListeners(int, Event)
*/
private static void notify(final int eventType) {
notify(eventType, createEvent());
}
/**
* Sends a non-blocking notification of the specified type to the {@link #widget}.
*
* @param eventType the type of event.
* @param createEvent the event to be sent to the {@link #widget}.
*/
private static void notify(final int eventType, final Event createEvent) {
notify(eventType, createEvent, widget);
}
/**
* Sends a non-blocking notification of the specified type to the widget.
*
* @param eventType the type of event.
* @param createEvent the event to be sent to the {@link #widget}.
* @param widget the widget to send the event to.
*/
private static void notify(final int eventType, final Event createEvent, final Widget widget) {
createEvent.type = eventType;
final Object[] result = syncExec(new ArrayResult<Object>() {
public Object[] run() {
return new Object[] { SWTBotEvents.toString(createEvent), widget.toString() };
}
});
log.trace(MessageFormat.format("Enquing event {0} on {1}", result)); //$NON-NLS-1$
asyncExec(new VoidResult() {
public void run() {
if ((widget == null) || widget.isDisposed()) {
log.trace(MessageFormat.format("Not notifying {0} is null or has been disposed", widget.toString())); //$NON-NLS-1$
return;
}
if (!isEnabledInternal()) {
log.warn(MessageFormat.format("Widget is not enabled: {0}", widget.toString())); //$NON-NLS-1$
return;
}
log.trace(MessageFormat.format("Sending event {0} to {1}", result)); //$NON-NLS-1$
widget.notifyListeners(eventType, createEvent);
log.debug(MessageFormat.format("Sent event {0} to {1}", result)); //$NON-NLS-1$
}
});
UIThreadRunnable.syncExec(new VoidResult() {
public void run() {
// do nothing, just wait for sync.
}
});
long playbackDelay = SWTBotPreferences.PLAYBACK_DELAY;
if (playbackDelay > 0)
sleep(playbackDelay);
}
/**
* Create a mouse event
*
* @param x the x co-ordinate of the mouse event.
* @param y the y co-ordinate of the mouse event.
* @param button the mouse button that was clicked.
* @param stateMask the state of the keyboard modifier keys.
* @param count the number of times the mouse was clicked.
* @return an event that encapsulates {@link #widget} and {@link #display}
* @since 1.2
*/
private static Event createMouseEvent(int x, int y, int button, int stateMask, int count) {
Event event = new Event();
event.time = (int) System.currentTimeMillis();
event.widget = widget;
event.display = display;
event.x = x;
event.y = y;
event.button = button;
event.stateMask = stateMask;
event.count = count;
return event;
}
/**
* Create a selection event with a particular state mask
*
* @param stateMask the state of the keyboard modifier keys.
*/
private static Event createSelectionEvent(int stateMask) {
Event event = createEvent();
event.stateMask = stateMask;
return event;
}
/**
* Creates an event.
*
* @return an event that encapsulates {@link #widget} and {@link #display}. Subclasses may override to set other
* event properties.
*/
private static Event createEvent() {
Event event = new Event();
event.time = (int) System.currentTimeMillis();
event.widget = widget;
event.display = display;
return event;
}
/**
* Invokes {@link ArrayResult#run()} on the UI thread.
*
* @param toExecute the object to be invoked in the UI thread.
* @return the array returned by toExecute.
*/
private static <T> T[] syncExec(ArrayResult<T> toExecute) {
return UIThreadRunnable.syncExec(display, toExecute);
}
/**
* Invokes {@link BoolResult#run()} asynchronously on the UI thread.
*
* @param toExecute the object to be invoked in the UI thread.
*/
private static void asyncExec(VoidResult toExecute) {
UIThreadRunnable.asyncExec(display, toExecute);
}
/**
* Gets if the widget is enabled.
* <p>
* This method is not thread safe, and must be called from the UI thread.
* </p>
*
* @return <code>true</code> if the widget is enabled.
* @since 1.0
*/
private static boolean isEnabledInternal() {
try {
return ((Boolean) SWTUtils.invokeMethod(widget, "isEnabled")).booleanValue(); //$NON-NLS-1$
} catch (Exception e) {
return true;
}
}
}