/******************************************************************************* * Copyright (c) 2012 Google, Inc. * 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: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runtime.draw2d.internal.helpers; import junit.framework.TestCase; import org.eclipse.draw2d.FigureCanvas; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.Polyline; import org.eclipse.draw2d.Viewport; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.swt.widgets.Widget; import abbot.tester.swt.ScrollBarTester; import abbot.tester.swt.ScrollableTester; import abbot.tester.swt.WidgetLocator; import com.windowtester.runtime.IClickDescription; import com.windowtester.runtime.IUIContext; import com.windowtester.runtime.WidgetSearchException; import com.windowtester.runtime.draw2d.internal.finder.Draw2DFinder; import com.windowtester.runtime.swt.internal.selector.BasicWidgetSelector; public class FigureSelectorHelper { private final IUIContext _ui; public FigureSelectorHelper(IUIContext ui) { _ui = ui; } protected final IUIContext getUI() { return _ui; } private final BasicWidgetSelector _selector = new BasicWidgetSelector(); public BasicWidgetSelector getSelector() { return _selector; } private void clickFigureAtPoint(final FigureCanvas parent, org.eclipse.draw2d.geometry.Rectangle bounds, int count) { TestCase.assertTrue((count > 0) && (count < 3)); Point p = scrollForClick(parent, bounds); //TODO: pass in button as param getSelector().click(parent, p.x, p.y, SWT.BUTTON1, count); } public void clickLabel(final FigureCanvas parent, Label target) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates org.eclipse.draw2d.geometry.Rectangle bounds = target.getTextBounds(); clickFigureAtPoint(parent, bounds, 1); } public void contextClickFigure( IFigure target, String menuText) { contextClickFigure(findParentCanvas(target), target, menuText); } public void contextClickFigure( IFigure target, int x, int y, String menuText) { contextClickFigure(findParentCanvas(target), target, x, y, menuText); } public void contextClickFigure(FigureCanvas parent, IFigure target, int x, int y, String menuText) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); TestCase.assertNotNull(menuText); //TODO: verify that this works! // Get the draw2d bounds and convert them to eclipse swt screen // coordinates org.eclipse.draw2d.geometry.Rectangle bounds = getBounds(target); final org.eclipse.draw2d.geometry.Point point = new org.eclipse.draw2d.geometry.Point(bounds.x + x, bounds.y + y); contextClickPoint(parent, point, menuText); } private org.eclipse.draw2d.geometry.Rectangle getBounds(IFigure target) { return Bounds.forFigure(target).asRectangle(); } public void contextClickFigure(final FigureCanvas parent, IFigure target, String menuText) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); TestCase.assertNotNull(menuText); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates org.eclipse.draw2d.geometry.Rectangle bounds = getBounds(target); final org.eclipse.draw2d.geometry.Point center = bounds.getCenter(); contextClickPoint(parent, center, menuText); } public void contextClickLabel(final FigureCanvas parent, Label target, String menuText) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); TestCase.assertNotNull(menuText); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates org.eclipse.draw2d.geometry.Rectangle bounds = target.getTextBounds(); final org.eclipse.draw2d.geometry.Point center = bounds.getCenter(); contextClickPoint(parent, center, menuText); } public void clickPolyline(final FigureCanvas parent, Polyline target) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates org.eclipse.draw2d.geometry.Point start = target.getStart(); org.eclipse.draw2d.geometry.Rectangle bounds = new org.eclipse.draw2d.geometry.Rectangle( start.x, start.y, 1, 1); clickFigureAtPoint(parent, bounds, 1); } public void contextClickPolyline(final FigureCanvas parent, Polyline target, String menuText) { TestCase.assertNotNull(parent); TestCase.assertNotNull(target); TestCase.assertNotNull(menuText); contextClickPoint(parent, target.getStart(), menuText); } private void contextClickPoint(final FigureCanvas parent, final org.eclipse.draw2d.geometry.Point clickPoint, final String menuText) { // adjust the point to click based upon the figure canvas viewport location final Point p = scrollForClick(parent, clickPoint); // Use the basic com.windowtester.runtime.gef.internal.selectors to perform the context click try { getBasicSelector().contextClick(parent, p.x, p.y, menuText); } catch (WidgetSearchException wse) { TestCase.fail(wse.getLocalizedMessage()); } } public Widget clickPoint(FigureCanvas canvas, IClickDescription click) { Point toClick = scrollForClick(canvas, new org.eclipse.draw2d.geometry.Point(click.x(), click.y())); return getBasicSelector().click(canvas, toClick.x, toClick.y, click.modifierMask(), click.clicks()); } public Widget contextClickPoint(FigureCanvas canvas, IClickDescription click, String menuItemPath) throws WidgetSearchException { Point toClick = scrollForClick(canvas, new org.eclipse.draw2d.geometry.Point(click.x(), click.y())); return getBasicSelector().contextClick(canvas, toClick.x, toClick.y, menuItemPath); } public Widget clickPoint(FigureCanvas canvas, Point point) { Point toClick = scrollForClick(canvas, new org.eclipse.draw2d.geometry.Point(point.x, point.y)); return getBasicSelector().click(canvas, toClick.x, toClick.y, SWT.BUTTON1); } private BasicWidgetSelector getBasicSelector() { return _selector; } public Rectangle getBounds(final FigureCanvas parent, IFigure figure) { TestCase.assertNotNull(parent); TestCase.assertNotNull(figure); // from the top of the canvas to the figure Rectangle figureBounds = toFigureCanvas(figure); // from top of canvas to top of scrollable viewport int scrolledOffsetY = getScrolledOffsetY(parent); int scrolledOffsetX = getScrolledOffsetX(parent); // from the top of viewport to top of item Rectangle adjustedFigureBounds = new Rectangle(figureBounds.x + scrolledOffsetX, figureBounds.y - scrolledOffsetY, figureBounds.width, figureBounds.height); // Place the parent canvas on the screen final Rectangle[] canvasBounds = new Rectangle[1]; Runnable r = new Runnable() { public void run() { canvasBounds[0] = WidgetLocator.getBounds(parent, false); } }; ensureRunOnUIThread(r); Rectangle resultingBounds = new Rectangle(canvasBounds[0].x + adjustedFigureBounds.x, canvasBounds[0].y + adjustedFigureBounds.y, adjustedFigureBounds.width, adjustedFigureBounds.height); return resultingBounds; } private void ensureRunOnUIThread(Runnable r) { Display.getDefault().syncExec(r); } public int getScrolledOffsetX(FigureCanvas canvas) { TestCase.assertNotNull(canvas); ScrollableTester scrollableTester = new ScrollableTester(); ScrollBar scrollBar = scrollableTester.getHorizontalBar(canvas); ScrollBarTester scrollBarTester = new ScrollBarTester(); return scrollBarTester.getSelection(scrollBar); } public int getScrolledOffsetY(FigureCanvas canvas) { TestCase.assertNotNull(canvas); ScrollableTester scrollableTester = new ScrollableTester(); scrollableTester.getClientArea(canvas); ScrollBar scrollBar = scrollableTester.getVerticalBar(canvas); ScrollBarTester scrollBarTester = new ScrollBarTester(); return scrollBarTester.getSelection(scrollBar); } public Point scrollForClick(final FigureCanvas parent, final org.eclipse.draw2d.geometry.Point clickPoint) { org.eclipse.draw2d.geometry.Rectangle bounds = new org.eclipse.draw2d.geometry.Rectangle( clickPoint.x, clickPoint.y, 1, 1); return scrollForClick(parent, bounds); } public Point scrollForClick(final FigureCanvas parent, final org.eclipse.draw2d.geometry.Rectangle bounds) { final org.eclipse.draw2d.geometry.Point clickPoint = bounds.getCenter(); // adjust the point to click based upon the figure canvas viewport location final Point[] p = new Point[1]; Runnable runner = new Runnable() { public void run() { Viewport viewport = parent.getViewport(); // before clicking, make sure the point we want to click is visible org.eclipse.draw2d.geometry.Point viewportLoc = viewport .getViewLocation().getCopy(); Dimension viewportSize = viewport.getSize().getCopy(); if (bounds.x < viewportLoc.x || bounds.x + bounds.width > viewportLoc.x + viewportSize.width || bounds.y < viewportLoc.y || bounds.y + bounds.height > viewportLoc.y + viewportSize.height) { // try to scroll so that the point is in the view - for each axis that // is not visible in the viewport, try to scroll so that the click // point is centered; if that is not possible, scroll as far as possible // based on the size of the viewport contents. Dimension contentsSize = viewport.getContents().getSize() .getCopy(); int vpx = viewportLoc.x; int vpy = viewportLoc.y; int vpHeight = viewportSize.height; int vpWidth = viewportSize.width; int dx = 0; if (bounds.x + bounds.width > vpx + vpWidth) { // click point is to the right of the viewport - scroll right // by the amount past the viewport plus half the viewport // width, or as far as possible int diff = (bounds.x + bounds.width) - (vpx + vpWidth) + (vpWidth / 2); dx = Math.min(contentsSize.width - (vpx + vpWidth), diff); } else if (bounds.x < vpx) { // click point is to the left of the viewport - scroll // left by the amount past the viewport plus half the // viewport width, or as far as possible int diff = (vpx - bounds.x) + (vpWidth / 2); dx = -1 * Math.min(vpx, diff); } int dy = 0; if (bounds.y + bounds.height > vpy + vpHeight) { // click point is below the viewport - scroll down // by the amount past the viewport plus half the viewport // height, or as far as possible int diff = (bounds.y + bounds.height) - (vpy + vpHeight) + (vpHeight / 2); dy = Math.min(contentsSize.height - (vpy + vpHeight), diff); } else if (bounds.y < vpy) { // click point is above the viewport - scroll up // by the amount past the viewport plus half the // viewport height, or as far as possible int diff = (vpy - bounds.y) + (vpHeight / 2); dy = -1 * Math.min(vpy, diff); } // TestCase // .assertTrue( // "click point was not in viewport, should have to scroll somewhere", // dx != 0 || dy != 0); viewportLoc.translate(dx, dy); viewport.setViewLocation(viewportLoc); // TestCase.assertEquals( // "viewport was not scrolled the expected amount", // viewportLoc, viewport.getViewLocation()); } p[0] = new Point(clickPoint.x - viewportLoc.x, clickPoint.y - viewportLoc.y); } }; ensureRunOnUIThread(runner); TestCase.assertNotNull(p[0]); return p[0]; } public Rectangle toFigureCanvas(IFigure figure) { TestCase.assertNotNull(figure); org.eclipse.draw2d.geometry.Rectangle draw2dBounds = getBounds(figure); Rectangle rectangleBounds = new Rectangle(draw2dBounds.x, draw2dBounds.y, draw2dBounds.width, draw2dBounds.height); IFigure parent = figure.getParent(); if ((draw2dBounds.x == 0) && (draw2dBounds.y == 0) && (parent != null)) { Rectangle parentBounds = toFigureCanvas(parent); rectangleBounds.x += parentBounds.x; rectangleBounds.y += parentBounds.y; } return rectangleBounds; } public Rectangle toFigureCanvas(Label label) { TestCase.assertNotNull(label); org.eclipse.draw2d.geometry.Rectangle draw2dBounds = label .getTextBounds(); Rectangle rectangleBounds = new Rectangle(draw2dBounds.x, draw2dBounds.y, draw2dBounds.width, draw2dBounds.height); return rectangleBounds; } /** * NOTE: x,y offset FROM CENTER! * @param target * @param x * @param y * @throws ParentCanvasNotFoundException */ public void clickFigure(IFigure target, int x, int y) throws ParentCanvasNotFoundException { clickFigure(1, target, x, y); } /** * NOTE: x,y offset FROM CENTER! * @param clicks * @param target * @param x * @param y * @throws ParentCanvasNotFoundException */ public void clickFigure(int clicks, IFigure target, int x, int y) throws ParentCanvasNotFoundException { TestCase.assertNotNull(target); FigureCanvas parent = findParentCanvas(target); if (parent == null) throw ParentCanvasNotFoundException.forFigure(target); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates Rectangle figureBounds = toFigureCanvas(target); org.eclipse.draw2d.geometry.Rectangle bounds = new org.eclipse.draw2d.geometry.Rectangle( figureBounds.x+x, figureBounds.y+y, figureBounds.width, figureBounds.height); clickFigureAtPoint(parent, bounds, clicks); } public void clickFigure(IFigure target) { clickFigure(1, target); } public void clickFigure(int clicks, IFigure target) { FigureCanvas parent = findParentCanvas(target); TestCase.assertNotNull(parent); TestCase.assertNotNull(target); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates Rectangle figureBounds = toFigureCanvas(target); org.eclipse.draw2d.geometry.Rectangle bounds = new org.eclipse.draw2d.geometry.Rectangle( figureBounds.x, figureBounds.y, figureBounds.width, figureBounds.height); clickFigureAtPoint(parent, bounds, clicks); } private FigureCanvas findParentCanvas(IFigure target) { return Draw2DFinder.getDefault().findParentCanvas(getUI(), target); } public void mouseMove(IFigure target, IClickDescription click) { FigureCanvas parent = findParentCanvas(target); TestCase.assertNotNull(parent); TestCase.assertNotNull(target); // Get the draw2d bounds and convert them to eclipse swt screen // coordinates Rectangle figureBounds = toFigureCanvas(target); org.eclipse.draw2d.geometry.Rectangle bounds = new org.eclipse.draw2d.geometry.Rectangle( figureBounds.x + click.x(), figureBounds.y + click.y(), figureBounds.width, figureBounds.height); Point p = scrollForClick(parent, bounds); getSelector().mouseMove(parent, p.x, p.y); } }