/******************************************************************************* * 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.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.concurrent.Callable; import org.eclipse.draw2d.FigureCanvas; import org.eclipse.draw2d.IFigure; import org.eclipse.gef.handles.AbstractHandle; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.swt.widgets.Canvas; import com.windowtester.internal.debug.Logger; import com.windowtester.internal.runtime.finder.IIdentifierHintProvider; import com.windowtester.internal.runtime.finder.ISearchScope; import com.windowtester.internal.runtime.locator.IAdaptableWidgetLocator; import com.windowtester.internal.runtime.locator.IUISelector; import com.windowtester.runtime.IClickDescription; import com.windowtester.runtime.IUIContext; import com.windowtester.runtime.WT; import com.windowtester.runtime.WidgetSearchException; import com.windowtester.runtime.draw2d.internal.helpers.FigureSelectorHelper; import com.windowtester.runtime.gef.internal.FigureReference; import com.windowtester.runtime.gef.internal.commandstack.CommandStackTransaction; import com.windowtester.runtime.gef.internal.commandstack.UIRunnable; import com.windowtester.runtime.internal.finder.scope.IWidgetSearchScope; import com.windowtester.runtime.locator.IWidgetLocator; import com.windowtester.runtime.locator.IWidgetReference; import com.windowtester.runtime.locator.WidgetReference; import com.windowtester.runtime.swt.internal.drivers.MenuDriver; import com.windowtester.runtime.swt.internal.operation.SWTLocation; import com.windowtester.runtime.swt.internal.operation.SWTMenuOperation; import com.windowtester.runtime.swt.internal.operation.SWTShowMenuOperation; import com.windowtester.runtime.swt.internal.operation.SWTWidgetLocation; import com.windowtester.runtime.swt.internal.widgets.CanvasReference; import com.windowtester.runtime.swt.internal.widgets.MenuReference; import com.windowtester.runtime.swt.locator.SWTWidgetLocator; import com.windowtester.runtime.swt.locator.eclipse.IWorkbenchPartLocator; /** * A locator for the Figure Canvas in a GEF Graphical Editor. */ public class FigureCanvasLocatorDelegate extends SWTWidgetLocator implements IAdaptableWidgetLocator, IIdentifierHintProvider { private static final long serialVersionUID = -526717330328663732L; private static boolean canGetFigureOwner = true; private final IWidgetSearchScope _scope; public FigureCanvasLocatorDelegate() { this(ScopeFactory.unspecifedEditorLocator()); } public FigureCanvasLocatorDelegate(String editorName) { this(ScopeFactory.editorLocator(editorName)); } public FigureCanvasLocatorDelegate(IWorkbenchPartLocator partLocator) { super(FigureCanvas.class); _scope = ScopeFactory.widgetScopeForPart(partLocator); } /** * Get the search scope for this canvas. */ protected final IWidgetSearchScope getScope() { return _scope; } /* (non-Javadoc) * @see com.windowtester.runtime.WidgetLocator#findAll(com.windowtester.runtime.IUIContext) */ public final IWidgetLocator[] findAll(IUIContext ui) { return getScope().findAll(ui, getMatcher()); } /* (non-Javadoc) * @see com.windowtester.runtime.gef.locator.FigureLocator#getAdapter(java.lang.Class) */ public Object getAdapter(Class<?> adapter) { if (adapter == ILabelProvider.class) return new FigureLabelProvider(); if (adapter == IUISelector.class) return this; if (adapter == ISearchScope.class) return getScope(); return null; } /* (non-Javadoc) * @see com.windowtester.internal.runtime.finder.IIdentifierHintProvider#requiresXY() */ public boolean requiresXY() { // TODO Auto-generated method stub return false; } /** * Override the superclass implementation to return a {@link FigureReference} rather * than the canvas itself */ public IWidgetLocator click(final IUIContext ui, final IWidgetReference widget, final IClickDescription click) throws WidgetSearchException { return (IWidgetLocator) CommandStackTransaction.forActiveEditor().runInUI(new UIRunnable() { public Object runWithResult() throws WidgetSearchException { return doClick(ui, widget, click); } }, ui); } private IWidgetLocator doClick(IUIContext ui, IWidgetReference widget, IClickDescription click) throws WidgetSearchException { FigureCanvas canvas = (FigureCanvas) widget.getWidget(); //TODO: preClick and postClick need to use the adjusted x and y post scroll //preClick(canvas, new Point(click.x(), click.y()), ui); new FigureSelectorHelper(ui).clickPoint(canvas, click); //postClick(canvas, ui); //WidgetReference canvasRef = (WidgetReference) super.click(ui, widget, click); //FigureCanvas canvas = (FigureCanvas) canvasRef.getWidget(); return resolveReferenceForClick(click, canvas); } private IWidgetLocator doContextClick(IUIContext ui, final IWidgetReference widget, final IClickDescription click, String menuItemPath) throws WidgetSearchException { // //NOTE: preClick and postClick need to use the adjusted x and y post scroll // FigureCanvas canvas = (FigureCanvas) widget.getWidget(); // //preClick(canvas, new Point(click.x(), click.y()), ui); // new FigureSelectorHelper(ui).contextClickPoint(canvas, click, menuItemPath); // //postClick(canvas, ui); // return resolveReferenceForClick(click, canvas); /* * TODO: this should be pushed into a proper FigureReference class implementation. */ return new MenuDriver().resolveAndSelect(new Callable<MenuReference>() { public MenuReference call() throws Exception { FigureCanvas canvas = (FigureCanvas) widget.getWidget(); SWTLocation location = SWTWidgetLocation.withDefaultCenter(new CanvasReference<Canvas>(canvas), click); SWTMenuOperation op = new SWTShowMenuOperation(null).waitForIdle().click(WT.BUTTON3, location, false); op.execute(); return op.getMenu(); } }, menuItemPath); } private IWidgetLocator resolveReferenceForClick(IClickDescription click, final FigureCanvas canvas) { IFigure figure = determineFigureToClick(click, canvas); // If the figure is a handle, then determine the figure that owns it if (canGetFigureOwner && figure instanceof AbstractHandle) { Object result = null; try { result = getOwnerFigure(figure); } catch (Exception e) { canGetFigureOwner = false; Logger.log("Failed to access AbstractHandle.getOwnerFigure()", e); } if (result != null) figure = ((IFigure) result); } // If a figure was located, then return a reference to that figure if (figure != null) return FigureReference.lazy(figure); // If nothing else, return the canvas reference return WidgetReference.create(canvas, this); } private Object getOwnerFigure(IFigure figure) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method method = AbstractHandle.class.getDeclaredMethod("getOwnerFigure", new Class[] {}); method.setAccessible(true); return method.invoke(figure, new Object[] {}); } private IFigure determineFigureToClick(IClickDescription click, FigureCanvas canvas) { IFigure contents = canvas.getContents(); IFigure figure = contents.findFigureAt(click.x(), click.y()); return figure; } /* (non-Javadoc) * @see com.windowtester.runtime.swt.locator.SWTWidgetLocator#contextClick(com.windowtester.runtime.IUIContext, com.windowtester.runtime.locator.IWidgetReference, com.windowtester.runtime.IClickDescription, java.lang.String) */ public IWidgetLocator contextClick(final IUIContext ui, final IWidgetReference widget, final IClickDescription click, final String menuItemPath) throws WidgetSearchException { return (IWidgetLocator) CommandStackTransaction.forActiveEditor().runInUI(new UIRunnable() { public Object runWithResult() throws WidgetSearchException { return doContextClick(ui, widget, click, menuItemPath); } }, ui); } }