/******************************************************************************* * 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.gef.internal.locator; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import com.windowtester.internal.runtime.locator.IAdaptableWidgetLocator; import com.windowtester.runtime.IUIContext; import com.windowtester.runtime.WidgetSearchException; import com.windowtester.runtime.gef.IFigureMatcher; import com.windowtester.runtime.gef.IFigureReference; import com.windowtester.runtime.gef.Position; import com.windowtester.runtime.gef.locator.FigureLocator; import com.windowtester.runtime.gef.locator.IFigureLocator; import com.windowtester.runtime.locator.IWidgetLocator; /** * Finds figure matched by a given matcher that is nearest to a given orientation * relative to a provided bounding box. */ public class ByOrientationLocator extends FigureLocatorDelegate implements PositionConstants { private static final long serialVersionUID = 39201753344418894L; public static interface IBoundsProvider { Rectangle getBounds(IUIContext ui) throws WidgetSearchException; } public static class PositionHelper { static class DistanceComparator implements Comparator { public int compare(Object arg0, Object arg1) { return ((Point)arg0).getDistance2((Point)arg1); } } static class Orientation implements Comparable { final int locationConstant; private final double distance; private final Point toCompare; public Orientation(Point anchor, Point toCompare, int locationConstant) { this.toCompare = toCompare; this.locationConstant = locationConstant; this.distance = anchor.getDistance(toCompare); //System.out.println("anchor: " + anchor + " toCompare: " + toCompare + " " + toString()); } public int compareTo(Object arg0) { return Double.compare(this.distance , ((Orientation)arg0).distance); } public String toString() { return "Orientation(" + getOrientationString() + ") - " + distance; } private String getOrientationString() { switch(locationConstant) { case NORTH : return "N"; case SOUTH : return "S"; case EAST : return "E"; case WEST : return "W"; case NORTH_EAST : return "NE"; case SOUTH_EAST : return "SE"; case NORTH_WEST : return "NW"; case SOUTH_WEST : return "SW"; } return "<NONE>"; } } public static Orientation[] buildOrientations(Point point, Rectangle rectangle) { return new Orientation[]{ new Orientation(rectangle.getTopRight(), point, NORTH_EAST), new Orientation(rectangle.getBottomRight(), point, SOUTH_EAST), new Orientation(rectangle.getTopLeft(), point, NORTH_WEST), new Orientation(rectangle.getBottomLeft(), point, SOUTH_WEST), new Orientation(rectangle.getTop(), point, NORTH), new Orientation(rectangle.getBottom(), point, SOUTH), new Orientation(rectangle.getRight(), point, EAST), new Orientation(rectangle.getLeft(), point, WEST) }; } public static int getNearestOrientationRelativeTo(Point point, Rectangle rectangle) { Orientation[] orientations = getRankedOrientations(point,rectangle); return firstOrientationConstant(orientations); } private static int firstOrientationConstant(Orientation[] orientations) { return orientations[0].locationConstant; } private static Orientation[] getRankedOrientations(Point point, Rectangle rectangle) { Orientation[] orientations = buildOrientations(point, rectangle); return sort(orientations); } private static Orientation[] sort(Orientation[] orientations) { Arrays.sort(orientations); return orientations; } public static Point getNearestPointToOrientation(Point[] points, Rectangle rectangle, int positionConstant) { Orientation[] closest = new Orientation[points.length]; for (int i=0; i < closest.length; ++i) { closest[i] = getRankedOrientations(points[i], rectangle)[0]; } return closestTo(closest, positionConstant); } private static Point closestTo(Orientation[] closest, int positionConstant) { List filtered = new ArrayList(); for (int i = 0; i < closest.length; i++) { if (closest[i].locationConstant == positionConstant) filtered.add(closest[i]); } if (filtered.size() == 0) return null; //TODO: an exception? return sort((Orientation[]) filtered.toArray(new Orientation[]{}))[0].toCompare; } } private final IBoundsProvider boundsProvider; private final int positionConstant; private final FigureLocator figureLocator; public ByOrientationLocator(IBoundsProvider boundsProvider, IFigureMatcher figureMatcher, int positionConstant) { super(figureMatcher); this.boundsProvider = boundsProvider; this.positionConstant = positionConstant; this.figureLocator = new FigureLocator(figureMatcher); } /* (non-Javadoc) * @see com.windowtester.runtime.locator.IWidgetLocator#findAll(com.windowtester.runtime.IUIContext) */ public IWidgetLocator[] findAll(IUIContext ui) { IWidgetLocator[] allMatches = figureLocator.findAll(ui); Point[] points = getPoints(allMatches); Rectangle bounds = null; try { bounds = boundsProvider.getBounds(ui); } catch (WidgetSearchException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (bounds == null) return new IWidgetLocator[0]; Point nearest = PositionHelper.getNearestPointToOrientation(points, bounds, positionConstant); if (nearest == null) return new IWidgetLocator[0]; return new IWidgetLocator[]{allMatches[indexOf(nearest, points)]}; } private int indexOf(Point nearest, Point[] points) { for (int i = 0; i < points.length; i++) { if (points[i].equals(nearest)) return i; } return -1; } private Point[] getPoints(IWidgetLocator[] locators) { Point[] points = new Point[locators.length]; for (int i=0; i < locators.length; ++i) { points[i] = getPoint(locators[i]); } return points; } public static Point getPoint(IWidgetLocator widgetLocator) { Rectangle bounds = getBounds(widgetLocator); if (bounds == null) return null; return bounds.getCenter(); } private static Rectangle getBounds(IWidgetLocator widgetLocator) { if (!(widgetLocator instanceof IFigureReference)) return null; IFigureReference ref = (IFigureReference)widgetLocator; IFigure figure = ref.getFigure(); if (figure == null) return null; Rectangle bounds = figure.getBounds(); return bounds; } public static IAdaptableWidgetLocator forPositionMatchInHost(int position, IFigureMatcher matcher, IFigureLocator hostFigure) { return new ByOrientationLocator(boundsFor(hostFigure), matcher, position); } public static IAdaptableWidgetLocator forPositionMatchInHost(Position position, IFigureMatcher matcher, IFigureLocator hostFigure) { return forPositionMatchInHost(com.windowtester.runtime.gef.internal.finder.position.PositionHelper.getPositionConstant(position), matcher, hostFigure); } private static IBoundsProvider boundsFor(final IFigureLocator hostFigure) { class BoundsProvider implements IBoundsProvider, Serializable { private static final long serialVersionUID = 1L; public Rectangle getBounds(IUIContext ui) throws WidgetSearchException { IWidgetLocator ref = ui.find(hostFigure); return ByOrientationLocator.getBounds(ref); } } return new BoundsProvider(); } /* (non-Javadoc) * @see com.windowtester.runtime.locator.IWidgetMatcher#matches(java.lang.Object) */ public boolean matches(Object widget) { return figureLocator.matches(widget); //TODO: this is not quite right <-- this will over-eagerly match (pruning happens relative to otehr matches) } /* (non-Javadoc) * @see com.windowtester.runtime.IAdaptable#getAdapter(java.lang.Class) */ public Object getAdapter(Class adapter) { return figureLocator.getAdapter(adapter); } }