blob: 31abdd52412d59cae3e2e7a2012264f878f5760c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2014 EclipseSource Muenchen GmbH 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:
* jfaltermeier - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.view.test.common.swt.spi;
import static org.junit.Assert.fail;
import java.util.NoSuchElementException;
import org.eclipse.emfforms.spi.swt.core.SWTDataElementIdHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
/**
* Util class for SWT Tests.
*
* @author jfaltermeier
*
*/
public final class SWTTestUtil {
private SWTTestUtil() {
// util
}
/**
* <p>
* Iterates over the hierarchy of the given {@link Control} and looks for a {@link Composite} with a
* {@link StackLayout}. The index specifies which composite with a stack layout should be returned.
* </p>
* <p>
* This method uses a depth-first-search.
* </p>
*
* @param control the parent control
* @param index the index of the layout
* @return the layout
* @throws NoSuchElementException if no layout with the index can be found
*/
public static StackLayout findStackLayout(Control control, int index) throws NoSuchElementException {
final Control result = find(control, index, new Counter(), new ControlTest() {
@Override
public boolean testCondition(Control control) {
if (!Composite.class.isInstance(control)) {
return false;
}
final Composite composite = Composite.class.cast(control);
final Layout layout = composite.getLayout();
if (layout == null) {
return false;
}
if (StackLayout.class != layout.getClass()) {
return false;
}
return true;
}
});
if (result == null) {
throw new NoSuchElementException("No composite with stack layout and index " + index + " found."); //$NON-NLS-1$//$NON-NLS-2$
}
final Composite composite = (Composite) result;
return (StackLayout) composite.getLayout();
}
/**
* <p>
* Iterates over the hierarchy of the given {@link Control} and looks for a control of the given class. The index
* specifies which control should be returned.
* </p>
* <p>
* This method uses a depth-first-search.
* </p>
*
* @param control the parent control
* @param index the index of the control to find
* @param <T> the type of the control to find
* @param clazz the class of the control to find
* @return the control
* @throws NoSuchElementException if no control with the index can be found
*/
public static <T extends Control> T findControl(Control control, int index, final Class<T> clazz)
throws NoSuchElementException {
final Control result = find(control, index, new Counter(), new ControlTest() {
@Override
public boolean testCondition(Control control) {
if (control.getClass() != clazz) {
return false;
}
return true;
}
});
if (result == null) {
throw new NoSuchElementException("No control of type " + clazz.getName() + " with index " + index //$NON-NLS-1$ //$NON-NLS-2$
+ " found."); //$NON-NLS-1$
}
return clazz.cast(result);
}
private static Control find(Control control, int index, Counter found, ControlTest test) {
final boolean success = test.testCondition(control);
if (success) {
found.inc();
}
if (index + 1 == found.count) {
return control;
}
if (!Composite.class.isInstance(control)) {
return null;
}
final Composite composite = Composite.class.cast(control);
for (final Control child : composite.getChildren()) {
final Control childResult = find(child, index, found, test);
if (childResult != null) {
return childResult;
}
}
return null;
}
/**
* Retrieves an element in the specified control by its unique Id, as defined in {@link SWTDataElementIdHelper}.
*
* @param control the parent control where the search control should be found.
* @param id the unique ID of the element to find
* @param clazz the class of control to find
* @param <T> the type of Control to find
* @return a optional referencing the control or an empty one if none was found.
*/
public static <T extends Control> T findControlById(Control control, final String id, final Class<T> clazz) {
// only get the first index, assuming id is unique
final Control result = find(control, 0, new Counter(), new ControlTest() {
@Override
public boolean testCondition(Control control) {
if (control.getClass() != clazz) {
return false;
}
final Object elementID = control.getData(SWTDataElementIdHelper.ELEMENT_ID_KEY);
if (elementID != null && id.equals(elementID)) {
return true;
}
return false;
}
});
return clazz.cast(result);
}
/**
* Waits for the ui thread to complete its work. Fails a testcase after 5 seconds.
*/
public static void waitForUIThread() {
final long maxTime = System.currentTimeMillis() + 5000;
while (Display.getDefault().readAndDispatch()) {
if (System.currentTimeMillis() > maxTime) {
fail("Timeout");
}
}
}
/**
* Simulates a click on the given {@link Button}.
*
* @param button the button to press
*/
public static void clickButton(Button button) {
selectWidget(button);
}
/**
* Selects the given widget.
*
* @param widget the control to select.
*/
public static void selectWidget(Widget widget) {
widget.notifyListeners(SWT.Selection, new Event());
}
/**
* Simulates a key down and key up event on the given {@link Control}.
*
* @param control the control
* @param keyCode the key code
*/
public static void pressAndReleaseKey(Control control, int keyCode) {
pressAndReleaseKey(control, 0, keyCode);
}
/**
* Simulates a key down and key up event on the given {@link Control}.
*
* @param control the control
* @param stateMask the state of the keyboard modifier keys (e.g. M1/ctrl)
* @param keyCode the key code
*/
public static void pressAndReleaseKey(Control control, int stateMask, int keyCode) {
final Event eventDown = new Event();
eventDown.stateMask = stateMask;
eventDown.keyCode = keyCode;
control.notifyListeners(SWT.KeyDown, eventDown);
final Event eventUp = new Event();
eventUp.keyCode = keyCode;
control.notifyListeners(SWT.KeyUp, eventDown);
}
/**
* Sets the given string on the {@link Text} and simulates a focus out event.
*
* @param text the text
* @param string the string to enter in the text
*/
public static void typeAndFocusOut(Text text, String string) {
text.setText(string);
text.notifyListeners(SWT.FocusOut, new Event());
}
/**
* Interface for a tester used by the {@link SWTTestUtil#find(Control, int, Counter, ControlTest)} method.
*
* @author jfaltermeier
*
*/
private interface ControlTest {
/**
* Tests a condition on the given control.
*
* @param control the control to test
* @return <code>true</code> if condition fulfilled, <code>false</code> otherwise
*/
boolean testCondition(Control control);
}
/**
* Simple counter class.
*
* @author jfaltermeier
*
*/
private static class Counter {
private int count;
/**
* Increases the counter.
*/
public void inc() {
count = count + 1;
}
}
}