/*******************************************************************************
* Copyright (c) 2012 BREDEX GmbH.
* 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:
* BREDEX GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.jubula.rc.swing.tester.adapter;
import java.awt.AWTEvent;
import java.awt.Toolkit;
import javax.swing.JComponent;
import org.eclipse.jubula.rc.common.driver.ClickOptions;
import org.eclipse.jubula.rc.common.driver.DragAndDropHelper;
import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer;
import org.eclipse.jubula.rc.common.driver.IRobot;
import org.eclipse.jubula.rc.common.driver.IRunnable;
import org.eclipse.jubula.rc.common.driver.RobotTiming;
import org.eclipse.jubula.rc.common.exception.RobotException;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.listener.EventLock;
import org.eclipse.jubula.rc.common.tester.AbstractMenuTester;
import org.eclipse.jubula.rc.common.tester.adapter.interfaces.IWidgetComponent;
import org.eclipse.jubula.rc.swing.driver.KeyCodeConverter;
import org.eclipse.jubula.rc.swing.tester.JMenuBarTester;
import org.eclipse.jubula.rc.swing.tester.util.EventListener;
import org.eclipse.jubula.rc.swing.tester.util.TesterUtil;
import org.eclipse.jubula.rc.swing.tester.util.TesterUtil.PopupShownCondition;
import org.eclipse.jubula.toolkit.enums.ValueSets;
import org.eclipse.jubula.tools.internal.constants.TimeoutConstants;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
import org.eclipse.jubula.tools.internal.utils.TimeUtil;
/**
* Implements the interface for widgets and supports basic methods
* which are needed for nearly all Swing UI components.
* This is a basic adaption for <code>JComponent</code>.
*
* @author BREDEX GmbH
*/
public class JComponentAdapter extends AbstractComponentAdapter
implements IWidgetComponent {
/** the component */
private JComponent m_component;
/**
* Used to store the component into the adapter.
*
* @param objectToAdapt
* the object to adapt
*/
public JComponentAdapter(Object objectToAdapt) {
m_component = (JComponent) objectToAdapt;
}
/**
* {@inheritDoc}
*/
public Object getRealComponent() {
return m_component;
}
/**
* Gets the IEventThreadQueuer.
*
* @return The Robot
* @throws RobotException
* If the Robot cannot be created.
*/
protected IRobot getRobot() throws RobotException {
return getRobotFactory().getRobot();
}
/**
* @return The event thread queuer.
*/
public IEventThreadQueuer getEventThreadQueuer() {
return getRobotFactory().getEventThreadQueuer();
}
/**
* {@inheritDoc}
*/
public String getPropteryValue(final String propertyname) {
String prop = getEventThreadQueuer().invokeAndWait("getProperty", //$NON-NLS-1$
new IRunnable<String>() {
public String run() throws StepExecutionException {
try {
return getRobot().getPropertyValue(
getRealComponent(), propertyname);
} catch (RobotException e) {
throw new StepExecutionException(
e.getMessage(),
EventFactory.createActionError(
TestErrorEvent.PROPERTY_NOT_ACCESSABLE));
}
}
});
return String.valueOf(prop);
}
/**
* {@inheritDoc}
*/
public boolean isShowing() {
return getEventThreadQueuer().invokeAndWait(
"isShowing", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() {
return m_component.isShowing();
}
});
}
/**
* {@inheritDoc}
*/
public boolean hasFocus() {
return getEventThreadQueuer().invokeAndWait(
"hasFocus", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() {
return m_component.hasFocus();
}
});
}
/**
* {@inheritDoc}
*/
public boolean isEnabled() {
return getEventThreadQueuer().invokeAndWait(
"isEnabled", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() {
return m_component.isEnabled();
}
});
}
/**
* {@inheritDoc}
*/
public AbstractMenuTester showPopup(final int button) {
final Object component = m_component;
Runnable showPopup = new Runnable() {
public void run() {
RobotTiming.sleepPreShowPopupDelay();
ClassLoader oldCl = Thread.currentThread()
.getContextClassLoader();
Thread.currentThread().setContextClassLoader(component
.getClass().getClassLoader());
if ((getRobot()).isMouseInComponent(component)) {
getRobot().clickAtCurrentPosition(
component, 1, button);
} else {
getRobot().click(component, null,
ClickOptions.create()
.setClickCount(1)
.setMouseButton(button));
}
Thread.currentThread().setContextClassLoader(oldCl);
}
};
return showPopup(showPopup);
}
/**
* {@inheritDoc}
*/
public AbstractMenuTester showPopup(
final int xPos, final String xUnits,
final int yPos, final String yUnits, final int button)
throws StepExecutionException {
final Object component = m_component;
Runnable showPopup = new Runnable() {
public void run() {
RobotTiming.sleepPreShowPopupDelay();
boolean isAbsoluteCoordinatesX =
xUnits.equalsIgnoreCase(
ValueSets.Unit.pixel.rcValue());
boolean isAbsoluteCoordinatesY =
yUnits.equalsIgnoreCase(
ValueSets.Unit.pixel.rcValue());
getRobot().click(component, null,
ClickOptions.create().setMouseButton(button),
xPos, isAbsoluteCoordinatesX,
yPos, isAbsoluteCoordinatesY);
}
};
return showPopup(showPopup);
}
/**
* Shows a popup menu using the given runnable and waits for the popup
* menu to appear.
*
* @param showPopupOperation The implementation to use for opening the
* popup menu.
* @return the popup menu.
*/
public AbstractMenuTester showPopup(Runnable showPopupOperation) {
PopupShownCondition cond = new PopupShownCondition();
EventLock lock = new EventLock();
EventListener listener = new EventListener(lock, cond);
Toolkit.getDefaultToolkit().addAWTEventListener(listener,
AWTEvent.CONTAINER_EVENT_MASK);
// showPopupOperation must run in the current thread in order to
// avoid a race condition.
showPopupOperation.run();
synchronized (lock) {
try {
long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP;
long done = System.currentTimeMillis() + timeout;
long now;
while ((!lock.isReleased() || (cond.getPopup() == null)
|| !cond.getPopup().isShowing())
&& (timeout > 0)) {
lock.wait(timeout);
now = System.currentTimeMillis();
timeout = done - now;
}
} catch (InterruptedException e) {
// ignore
} finally {
Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
}
}
if (!lock.isReleased() || (cond.getPopup() == null)
|| !cond.getPopup().isShowing()) {
throw new StepExecutionException("popup not shown", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.POPUP_NOT_FOUND));
}
AbstractMenuTester menuCAPs = new JMenuBarTester();
menuCAPs.setComponent(cond.getPopup());
return menuCAPs;
}
/**
* {@inheritDoc}
*/
public void showToolTip(final String text, final int textSize,
final int timePerWord, final int windowWidth) {
StepExecutionException.throwUnsupportedAction();
}
/**
* {@inheritDoc}
*/
public void rcDrag(int mouseButton, String modifier, int xPos,
String xUnits, int yPos, String yUnits) {
final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
dndHelper.setMouseButton(mouseButton);
dndHelper.setModifier(modifier);
final IRobot robot = getRobot();
clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits);
TesterUtil.pressOrReleaseModifiers(modifier, true);
robot.mousePress(null, null, mouseButton);
}
/**
* {@inheritDoc}
*/
public void rcDrop(int xPos, String xUnits, int yPos, String yUnits,
int delayBeforeDrop) {
final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance();
final String modifier = dndHelper.getModifier();
final int mouseButton = dndHelper.getMouseButton();
try {
clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits);
TimeUtil.delay(delayBeforeDrop);
} finally {
getRobot().mouseRelease(null, null, mouseButton);
TesterUtil.pressOrReleaseModifiers(modifier, false);
}
}
/**
* clicks into the component.
*
* @param count amount of clicks
* @param button what mouse button should be used
* @param xPos what x position
* @param xUnits should x position be pixel or percent values
* @param yPos what y position
* @param yUnits should y position be pixel or percent values
* @throws StepExecutionException error
*/
private void clickDirect(int count, int button, int xPos, String xUnits,
int yPos, String yUnits) throws StepExecutionException {
getRobot().click(m_component, null,
ClickOptions.create()
.setClickCount(count)
.setMouseButton(button),
xPos, xUnits.equalsIgnoreCase(
ValueSets.Unit.pixel.rcValue()),
yPos, yUnits.equalsIgnoreCase(
ValueSets.Unit.pixel.rcValue()));
}
/**
* {@inheritDoc}
*/
public int getKeyCode(String mod) {
return KeyCodeConverter.getKeyCode(mod);
}
}