/******************************************************************************* * Copyright (c) 2013 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.swt.tester.adapter; 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.StepExecutionException; import org.eclipse.jubula.rc.common.listener.EventLock; import org.eclipse.jubula.rc.common.tester.AbstractMenuTester; import org.eclipse.jubula.rc.common.tester.WidgetTester; import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl; import org.eclipse.jubula.rc.swt.tester.MenuTester; import org.eclipse.jubula.rc.swt.tester.adapter.ControlAdapter.PopupShownCondition; import org.eclipse.jubula.rc.swt.tester.util.CAPUtil; import org.eclipse.jubula.rc.swt.tester.util.EventListener; import org.eclipse.jubula.rc.swt.tester.util.SimulatedTooltip; import org.eclipse.jubula.rc.swt.utils.SwtUtils; 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.swt.SWT; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Widget; /** * @author BREDEX GmbH * @created 18.02.2013 */ public class WidgetAdapter extends AbstractComponentAdapter { /** the widget */ private Widget m_component = null; /** * @param objectToAdapt the component */ public WidgetAdapter(Object objectToAdapt) { m_component = (Widget) objectToAdapt; } /** * {@inheritDoc} */ public Object getRealComponent() { return m_component; } /** * {@inheritDoc} */ public void rcDrop(final int xPos, final String xUnits, final int yPos, final String yUnits, int delayBeforeDrop) { final DragAndDropHelper dndHelper = DragAndDropHelper .getInstance(); final IRobot robot = getRobot(); final String modifier = dndHelper.getModifier(); final int mouseButton = dndHelper.getMouseButton(); // Note: This method performs the drag AND drop action in one runnable // in the GUI-Eventqueue because after the mousePress, the eventqueue // blocks! try { CAPUtil.pressOrReleaseModifiers(modifier, true); getEventThreadQueuer().invokeAndWait("startDrag", new IRunnable<Void>() { //$NON-NLS-1$ public Void run() throws StepExecutionException { // drag robot.mousePress(dndHelper.getDragComponent(), null, mouseButton); robot.shakeMouse(); // drop clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); return null; } }); WidgetTester.waitBeforeDrop(delayBeforeDrop); } finally { getRobot().mouseRelease(null, null, mouseButton); CAPUtil.pressOrReleaseModifiers(modifier, false); } } /** * {@inheritDoc} */ public void rcDrag(int mouseButton, String modifier, int xPos, String xUnits, int yPos, String yUnits) { // Only store the Drag-Information. Otherwise the GUI-Eventqueue // blocks after performed Drag! final DragAndDropHelper dndHelper = DragAndDropHelper .getInstance(); dndHelper.setMouseButton(mouseButton); dndHelper.setModifier(modifier); dndHelper.setDragComponent(null); clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); } /** * clicks into a component. * @param count amount of clicks * @param button what button should be clicked * @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 */ protected 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())); } /** * Shows and returns the popup menu * @param button MouseButton * @return the popup menu */ public AbstractMenuTester showPopup( final int button) { final Widget component = m_component; if (SwtUtils.isMouseCursorInWidget(component)) { return showPopup(component, new Runnable() { public void run() { RobotTiming.sleepPreShowPopupDelay(); getRobot().clickAtCurrentPosition(component, 1, button); } }); } return showPopup(50, ValueSets.Unit.percent.rcValue(), 50, ValueSets.Unit.percent.rcValue(), button); } /** * Shows and returns the popup menu * * @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 * @param button MouseButton * @return the popup menu * @throws StepExecutionException error */ public AbstractMenuTester showPopup( final int xPos, final String xUnits, final int yPos, final String yUnits, final int button) throws StepExecutionException { final Widget component = m_component; return showPopup(component, new Runnable() { public void run() { RobotTiming.sleepPreShowPopupDelay(); boolean isAbsoluteUnitsX = ValueSets.Unit.pixel.rcValue().equalsIgnoreCase( xUnits); boolean isAbsoluteUnitsY = ValueSets.Unit.pixel.rcValue().equalsIgnoreCase( yUnits); getRobot().click(component, null, ClickOptions.create().setClickCount(1) .setMouseButton(button), xPos, isAbsoluteUnitsX, yPos, isAbsoluteUnitsY); } }); } /** * Shows and returns the popup menu * * @param component The component for which to open the popup menu. * @param showPopup A <code>Runnable</code> that, when run, should display * a popup menu for the given component. * @return the popup menu * @throws StepExecutionException error */ private AbstractMenuTester showPopup(final Widget component, final Runnable showPopup) throws StepExecutionException { PopupShownCondition cond = new PopupShownCondition(); EventLock lock = new EventLock(); final EventListener listener = new EventListener(lock, cond); final Display d = component.getDisplay(); final IEventThreadQueuer queuer = new EventThreadQueuerSwtImpl(); queuer.invokeAndWait("addPopupShownListeners", new IRunnable<Void>() { //$NON-NLS-1$ public Void run() { d.addFilter(SWT.Show, listener); return null; } }); try { // showPopup must run in the current thread in order to // avoid a race condition. showPopup.run(); synchronized (lock) { long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP; long done = System.currentTimeMillis() + timeout; long now; while (!lock.isReleased() && (timeout > 0)) { lock.wait(timeout); now = System.currentTimeMillis(); timeout = done - now; } } } catch (InterruptedException e) { // ignore } finally { queuer.invokeAndWait("removePopupShownListeners", new IRunnable<Void>() { //$NON-NLS-1$ public Void run() { d.removeFilter(SWT.Show, listener); return null; } }); } if (!lock.isReleased()) { throw new StepExecutionException("popup not shown", //$NON-NLS-1$ EventFactory.createActionError( TestErrorEvent.POPUP_NOT_FOUND)); } MenuTester contextMenu = new MenuTester(); contextMenu.setComponent(cond.getPopup()); contextMenu.setContextMenu(true); return contextMenu; } /** * {@inheritDoc} */ public void showToolTip(final String text, final int textSize, final int timePerWord, final int windowWidth) { final Rectangle bounds = getEventThreadQueuer().invokeAndWait( "showToolTip.getBounds", new IRunnable<Rectangle>() { //$NON-NLS-1$ public Rectangle run() { return SwtUtils.getWidgetBounds(m_component); } }); SimulatedTooltip sp = getEventThreadQueuer().invokeAndWait("showToolTip.initToolTip", new IRunnable<SimulatedTooltip>() { //$NON-NLS-1$ public SimulatedTooltip run() throws StepExecutionException { return new SimulatedTooltip(timePerWord, text, windowWidth, textSize, bounds); } }); sp.start(); try { sp.join(); } catch (InterruptedException e) { throw new StepExecutionException(e); } } }