Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2010 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 and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.rc.rcp.e3.gef.tester; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.Validate; import org.eclipse.draw2d.Connection; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.FigureCanvas; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Point; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditDomain; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.GraphicalViewer; import org.eclipse.gef.RootEditPart; import org.eclipse.gef.palette.PaletteEntry; import org.eclipse.gef.ui.palette.PaletteViewer; import org.eclipse.jubula.rc.common.CompSystemConstants; import org.eclipse.jubula.rc.common.driver.ClickOptions; import org.eclipse.jubula.rc.common.driver.IRobot; import org.eclipse.jubula.rc.common.driver.IRunnable; import org.eclipse.jubula.rc.common.exception.StepExecutionException; import org.eclipse.jubula.rc.common.tester.WidgetTester; import org.eclipse.jubula.rc.common.util.MatchUtil; import org.eclipse.jubula.rc.common.util.MenuUtilBase; import org.eclipse.jubula.rc.common.util.Verifier; import org.eclipse.jubula.rc.rcp.e3.gef.factory.DefaultEditPartAdapterFactory; import org.eclipse.jubula.rc.rcp.e3.gef.identifier.IEditPartIdentifier; import org.eclipse.jubula.rc.rcp.e3.gef.listener.GefPartListener; import org.eclipse.jubula.rc.swt.driver.DragAndDropHelperSwt; import org.eclipse.jubula.rc.swt.driver.RobotFactoryConfig; import org.eclipse.jubula.rc.swt.tester.CAPUtil; import org.eclipse.jubula.rc.swt.tester.adapter.ControlAdapter; import org.eclipse.jubula.tools.objects.event.EventFactory; import org.eclipse.jubula.tools.objects.event.TestErrorEvent; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; /** * Implementation class for Figure Canvas (Eclipse GEF). * * @author BREDEX GmbH * @created May 13, 2009 */ public class FigureCanvasTester extends WidgetTester { /** * the viewer that contains the EditParts corresponding to the FigureCanvas */ private GraphicalViewer m_viewer = null; /** * * @return the viewer associated with the canvas to test. */ private GraphicalViewer getViewer() { return m_viewer; } /** * * @return the control for the canvas to test. */ private Control getViewerControl() { return getViewer().getControl(); } /** * * @return the root edit part of the viewer. */ private RootEditPart getRootEditPart() { return getViewer().getRootEditPart(); } /** * * @return the root of the palette viewer (tool palette). */ private RootEditPart getPaletteRoot() { return getViewer().getEditDomain().getPaletteViewer().getRootEditPart(); } /** * * @param textPath The path to the tool. * @param operator The operator used for matching. * @return the EditPart found at the end of the given path. Returns * <code>null</code> if no EditPart can be found for the given path * or if the EditPart found is not a GraphicalEditPart. */ private GraphicalEditPart findPaletteEditPart(String textPath, String operator) { final String[] pathItems = MenuUtilBase.splitPath(textPath); boolean isExisting = true; EditPart currentEditPart = getPaletteRoot().getContents(); for (int i = 0; i < pathItems.length && currentEditPart != null; i++) { List effectiveChildren = currentEditPart.getChildren(); EditPart[] children = (EditPart[]) effectiveChildren.toArray(new EditPart[effectiveChildren.size()]); boolean itemFound = false; for (int j = 0; j < children.length && !itemFound; j++) { Object model = children[j].getModel(); if (model instanceof PaletteEntry) { String entryLabel = ((PaletteEntry) model).getLabel(); if (entryLabel != null && MatchUtil.getInstance().match(entryLabel, pathItems[i], operator)) { itemFound = true; currentEditPart = children[j]; } } } if (!itemFound) { isExisting = false; break; } } return isExisting && currentEditPart instanceof GraphicalEditPart ? (GraphicalEditPart) currentEditPart : null; } /** * {@inheritDoc} */ public void setComponent(final Object graphicsComponent) { Composite composite = (Composite) new RobotFactoryConfig().getRobotFactory().getEventThreadQueuer() .invokeAndWait(getClass().getName() + ".setComponent", new IRunnable() { //$NON-NLS-1$ public Object run() throws StepExecutionException { FigureCanvas figureCanvas = (FigureCanvas) graphicsComponent; Composite parent = figureCanvas; while (parent != null && !(parent .getData(GefPartListener.TEST_GEF_VIEWER_DATA_KEY) instanceof GraphicalViewer)) { parent = parent.getParent(); } if (parent != null) { m_viewer = (GraphicalViewer) parent.getData(GefPartListener.TEST_GEF_VIEWER_DATA_KEY); return parent; } return null; } }); setAdapter(new ControlAdapter(composite)); } /** * Checks whether the figure for the EditPart for the given path exists and * is visible. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @param exists Whether the figure is expected to exist. */ public void rcCheckFigureExists(String textPath, String operator, boolean exists) { boolean isExisting = findFigure(findEditPart(textPath, operator)) != null; if (!isExisting) { // See if there's a connection anchor at the given path isExisting = findConnectionAnchor(textPath, operator) != null; } Verifier.equals(exists, isExisting); } /** * Checks the given property of the figure at the given path. * * @param textPath The path to the figure. * @param textPathOperator The operator used for matching the text path. * @param propertyName The name of the property * @param expectedPropValue The value of the property as a string * @param valueOperator The operator used to verify */ public void rcVerifyFigureProperty(String textPath, String textPathOperator, final String propertyName, String expectedPropValue, String valueOperator) { final IFigure figure = findFigure(findEditPart(textPath, textPathOperator)); if (figure == null) { throw new StepExecutionException("No figure could be found for the given text path.", //$NON-NLS-1$ EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); } Object prop = getEventThreadQueuer().invokeAndWait("getProperty", //$NON-NLS-1$ new IRunnable() { public Object run() throws StepExecutionException { try { return PropertyUtils.getProperty(figure, propertyName); } catch (IllegalAccessException e) { throw new StepExecutionException(e.getMessage(), EventFactory.createActionError(TestErrorEvent.PROPERTY_NOT_ACCESSABLE)); } catch (InvocationTargetException e) { throw new StepExecutionException(e.getMessage(), EventFactory.createActionError(TestErrorEvent.PROPERTY_NOT_ACCESSABLE)); } catch (NoSuchMethodException e) { throw new StepExecutionException(e.getMessage(), EventFactory.createActionError(TestErrorEvent.PROPERTY_NOT_ACCESSABLE)); } } }); final String propToStr = String.valueOf(prop); Verifier.match(propToStr, expectedPropValue, valueOperator); } /** * Checks whether the tool for the given path exists and * is visible. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @param exists Whether the figure is expected to exist. */ public void rcCheckToolExists(String textPath, String operator, boolean exists) { boolean isExisting = findPaletteFigure(textPath, operator) != null; Verifier.equals(exists, isExisting); } /** * Finds and clicks the figure for the given path. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @param count The number of times to click. * @param button The mouse button to use for the click. */ public void rcClickFigure(String textPath, String operator, int count, int button) { getRobot().click(getViewerControl(), getFigureBoundsChecked(textPath, operator), ClickOptions.create().setScrollToVisible(false).setClickCount(count).setMouseButton(button)); } /** * Finds and clicks on a connection between a source figure and a * target figure. * * @param sourceTextPath The path to the source figure. * @param sourceOperator The operator to use for matching the source * figure path. * @param targetTextPath The path to the target figure. * @param targetOperator The operator to use for matching the target * figure path. * @param count The number of times to click. * @param button The mouse button to use for the click. */ public void rcClickConnection(String sourceTextPath, String sourceOperator, String targetTextPath, String targetOperator, int count, int button) { GraphicalEditPart sourceEditPart = findEditPart(sourceTextPath, sourceOperator); GraphicalEditPart targetEditPart = findEditPart(targetTextPath, targetOperator); ConnectionEditPart connectionEditPart = null; if (sourceEditPart != null) { List sourceConnectionList = sourceEditPart.getSourceConnections(); ConnectionEditPart[] sourceConnections = (ConnectionEditPart[]) sourceConnectionList .toArray(new ConnectionEditPart[sourceConnectionList.size()]); for (int i = 0; i < sourceConnections.length && connectionEditPart == null; i++) { if (sourceConnections[i].getTarget() == targetEditPart) { connectionEditPart = sourceConnections[i]; } } } else if (targetEditPart != null) { List targetConnectionList = targetEditPart.getTargetConnections(); ConnectionEditPart[] targetConnections = (ConnectionEditPart[]) targetConnectionList .toArray(new ConnectionEditPart[targetConnectionList.size()]); for (int i = 0; i < targetConnections.length && connectionEditPart == null; i++) { if (targetConnections[i].getSource() == targetEditPart) { connectionEditPart = targetConnections[i]; } } } else { throw new StepExecutionException("No figures could be found for the given text paths.", //$NON-NLS-1$ EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); } IFigure connectionFigure = findFigure(connectionEditPart); if (connectionFigure == null) { String missingEnd = sourceEditPart == null ? "source" : "target"; //$NON-NLS-1$ //$NON-NLS-2$ throw new StepExecutionException( "No connection could be found for the given " + missingEnd + " figure.", //$NON-NLS-1$ //$NON-NLS-2$ EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); } // Scrolling revealEditPart(connectionEditPart); if (connectionFigure instanceof Connection) { Point midpoint = ((Connection) connectionFigure).getPoints().getMidpoint(); connectionFigure.translateToAbsolute(midpoint); getRobot().click(getViewerControl(), null, ClickOptions.create().setScrollToVisible(false).setClickCount(count).setMouseButton(button), midpoint.x, true, midpoint.y, true); } else { getRobot().click(getViewerControl(), getBounds(connectionFigure), ClickOptions.create().setScrollToVisible(false).setClickCount(count).setMouseButton(button)); } } /** * Clicks the specified position within the given figure. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @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 if step execution fails. */ public void rcClickInFigure(String textPath, String operator, int count, int button, int xPos, String xUnits, int yPos, String yUnits) throws StepExecutionException { getRobot().click(getViewerControl(), getFigureBoundsChecked(textPath, operator), ClickOptions.create().setScrollToVisible(false).setClickCount(count).setMouseButton(button), xPos, xUnits.equalsIgnoreCase(CompSystemConstants.POS_UNIT_PIXEL), yPos, yUnits.equalsIgnoreCase(CompSystemConstants.POS_UNIT_PIXEL)); } /** * Simulates the beginning of a Drag. Moves to the specified position * within the given figure and stores information related to the drag to * be used later by a Drop operation. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @param mouseButton the mouse button. * @param modifier the modifier, e.g. shift, ctrl, etc. * @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 */ public void rcDragFigure(String textPath, String operator, 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 DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt.getInstance(); dndHelper.setMouseButton(mouseButton); dndHelper.setModifier(modifier); dndHelper.setDragComponent(null); rcClickInFigure(textPath, operator, 0, mouseButton, xPos, xUnits, yPos, yUnits); } /** * Performs a Drop. Moves to the specified location within the given figure * and releases the modifier and mouse button pressed by the previous drag * operation. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @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 delayBeforeDrop the amount of time (in milliseconds) to wait * between moving the mouse to the drop point and * releasing the mouse button */ public void rcDropOnFigure(final String textPath, final String operator, final int xPos, final String xUnits, final int yPos, final String yUnits, int delayBeforeDrop) { final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt.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 { pressOrReleaseModifiers(modifier, true); getEventThreadQueuer().invokeAndWait("gdStartDragFigure", new IRunnable() { //$NON-NLS-1$ public Object run() throws StepExecutionException { // drag robot.mousePress(dndHelper.getDragComponent(), null, mouseButton); CAPUtil.shakeMouse(); // drop rcClickInFigure(textPath, operator, 0, mouseButton, xPos, xUnits, yPos, yUnits); return null; } }); waitBeforeDrop(delayBeforeDrop); } finally { getRobot().mouseRelease(null, null, mouseButton); pressOrReleaseModifiers(modifier, false); } } /** * Returns the bounds for the figure for the given path. If no such * figure can be found, a {@link StepExecutionException} will be thrown. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @return the bounds of the figure for the given path. */ private Rectangle getFigureBoundsChecked(String textPath, String operator) { GraphicalEditPart editPart = findEditPart(textPath, operator); IFigure figure = findFigure(editPart); ConnectionAnchor anchor = null; if (figure == null) { // Try to find a connection anchor instead anchor = findConnectionAnchor(textPath, operator); if (anchor != null) { final String[] pathItems = MenuUtilBase.splitPath(textPath); final String[] editPartPathItems = new String[pathItems.length - 1]; System.arraycopy(pathItems, 0, editPartPathItems, 0, editPartPathItems.length); editPart = findEditPart(operator, editPartPathItems); } if (anchor == null || findFigure(editPart) == null) { throw new StepExecutionException("No figure could be found for the given text path.", //$NON-NLS-1$ EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); } } // Scrolling revealEditPart(editPart); return figure != null ? getBounds(figure) : getBounds(anchor); } /** * Clicks the tool found at the given path. * * @param textPath The path to the tool. * @param operator The operator used for matching. * @param count The number of times to click. */ public void rcSelectTool(String textPath, String operator, int count) { Control paletteControl = getPaletteControl(); IFigure figure = findPaletteFigureChecked(textPath, operator); getRobot().click(paletteControl, getBounds(figure), ClickOptions.create().setScrollToVisible(false).setClickCount(count)); } /** * @return the control associated with the palette viewer. */ private Control getPaletteControl() { EditDomain editDomain = getViewer().getEditDomain(); if (editDomain == null) { return null; } PaletteViewer paletteViewer = editDomain.getPaletteViewer(); if (paletteViewer == null) { return null; } return paletteViewer.getControl(); } /** * * @param figure The figure for which to find the bounds. * @return the bounds of the given figure. */ private Rectangle getBounds(IFigure figure) { org.eclipse.draw2d.geometry.Rectangle figureBounds = new org.eclipse.draw2d.geometry.Rectangle( figure.getBounds()); // Take scrolling and zooming into account figure.translateToAbsolute(figureBounds); return new Rectangle(figureBounds.x, figureBounds.y, figureBounds.width, figureBounds.height); } /** * * @param anchor The anchor for which to find the bounds. * @return the "bounds" of the given anchor. Since the location of an * anchor is defined as a single point, the bounds are a small * rectangle with that point at the center. */ private Rectangle getBounds(ConnectionAnchor anchor) { Validate.notNull(anchor); Point refPoint = anchor.getReferencePoint(); return new Rectangle(refPoint.x - 1, refPoint.y - 1, 3, 3); } /** * * @param textPath The path to the GraphicalEditPart. * @param operator The operator used for matching. * @return the GraphicalEditPart for the given path. Returns * <code>null</code> if no EditPart exists for the given path or if * the found EditPart is not a GraphicalEditPart. */ private GraphicalEditPart findEditPart(String textPath, String operator) { final String[] pathItems = MenuUtilBase.splitPath(textPath); return findEditPart(operator, pathItems); } /** * @param operator The operator used for matching. * @param pathItems The path to the GraphicalEditPart. Each element in the * array represents a single segment of the path. * @return the GraphicalEditPart for the given path. Returns * <code>null</code> if no EditPart exists for the given path or if * the found EditPart is not a GraphicalEditPart. */ private GraphicalEditPart findEditPart(String operator, final String[] pathItems) { boolean isExisting = true; EditPart currentEditPart = getRootEditPart().getContents(); for (int i = 0; i < pathItems.length && currentEditPart != null; i++) { List effectiveChildren = currentEditPart.getChildren(); EditPart[] children = (EditPart[]) effectiveChildren.toArray(new EditPart[effectiveChildren.size()]); boolean itemFound = false; for (int j = 0; j < children.length && !itemFound; j++) { IEditPartIdentifier childFigureIdentifier = DefaultEditPartAdapterFactory .loadFigureIdentifier(children[j]); if (childFigureIdentifier != null) { String figureId = childFigureIdentifier.getIdentifier(); if (figureId != null && MatchUtil.getInstance().match(figureId, pathItems[i], operator)) { itemFound = true; currentEditPart = children[j]; } } } if (!itemFound) { isExisting = false; break; } } return isExisting && currentEditPart instanceof GraphicalEditPart ? (GraphicalEditPart) currentEditPart : null; } /** * * @param textPath The path to the figure. * @param operator The operator used for matching. * @return the figure for the GraphicalEditPart for the given path within * the palette. Returns <code>null</code> if no EditPart exists * for the given path or if the found EditPart does not have a * figure. */ private IFigure findPaletteFigure(String textPath, String operator) { GraphicalEditPart editPart = findPaletteEditPart(textPath, operator); // Scrolling revealEditPart(editPart); return findFigure(editPart); } /** * Finds and returns the palette figure for the given path. If no such * figure can be found, a {@link StepExecutionException} will be thrown. * * @param textPath The path to the figure. * @param operator The operator used for matching. * @return the figure for the GraphicalEditPart for the given path within * the palette. */ private IFigure findPaletteFigureChecked(String textPath, String operator) { IFigure figure = findPaletteFigure(textPath, operator); if (figure == null) { throw new StepExecutionException("No palette figure could be found for the given text path.", //$NON-NLS-1$ EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); } return figure; } /** * * @param editPart The EditPart for which to find the corresponding figure. * @return the (visible) figure corresponding to the given EditPart, or * <code>null</code> if no visible figure corresponds to the given * EditPart. */ private IFigure findFigure(GraphicalEditPart editPart) { if (editPart != null) { IFigure figure = editPart.getFigure(); if (figure.isShowing()) { return figure; } } return null; } /** * Attempts to find a connection anchor at the given textpath. * * @param textPath The path to the anchor. * @param operator The operator used for matching. * @return the anchor found at the given text path, or <code>null</code> * if no such anchor exists. */ private ConnectionAnchor findConnectionAnchor(String textPath, String operator) { final String[] pathItems = MenuUtilBase.splitPath(textPath); final String[] editPartPathItems = new String[pathItems.length - 1]; System.arraycopy(pathItems, 0, editPartPathItems, 0, editPartPathItems.length); GraphicalEditPart editPart = findEditPart(operator, editPartPathItems); if (editPart != null) { String anchorPathItem = pathItems[pathItems.length - 1]; IEditPartIdentifier editPartIdentifier = DefaultEditPartAdapterFactory.loadFigureIdentifier(editPart); if (editPartIdentifier != null) { Map anchorMap = editPartIdentifier.getConnectionAnchors(); if (anchorMap != null) { Iterator anchorMapIter = anchorMap.keySet().iterator(); while (anchorMapIter.hasNext()) { Object anchorMapKey = anchorMapIter.next(); Object anchorMapValue = anchorMap.get(anchorMapKey); if (anchorMapKey instanceof String && anchorMapValue instanceof ConnectionAnchor && MatchUtil.getInstance().match((String) anchorMapKey, anchorPathItem, operator)) { return (ConnectionAnchor) anchorMapValue; } } } } } return null; } /** * Reveals the given {@link EditPart} within its viewer. * * @param editPart the {@link EditPart} to reveal. */ private void revealEditPart(final EditPart editPart) { if (editPart != null) { getEventThreadQueuer().invokeAndWait(getClass().getName() + ".revealEditPart", new IRunnable() { //$NON-NLS-1$ public Object run() throws StepExecutionException { editPart.getViewer().reveal(editPart); return null; } }); } } }