/******************************************************************************* * 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.swt.event.spy; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.CoolBar; import org.eclipse.swt.widgets.CoolItem; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.Widget; import com.windowtester.internal.debug.Tracer; import com.windowtester.internal.runtime.IWidgetIdentifier; import com.windowtester.recorder.event.user.SemanticWidgetInspectionEvent; import com.windowtester.recorder.event.user.UISemanticEvent; import com.windowtester.recorder.event.user.UISemanticEvent.EventInfo; import com.windowtester.runtime.locator.ILocator; import com.windowtester.runtime.swt.internal.Context; import com.windowtester.runtime.swt.internal.abbot.SWTWorkarounds; import com.windowtester.runtime.swt.internal.finder.SWTHierarchyHelper; import com.windowtester.runtime.swt.internal.finder.ShellFinder; import com.windowtester.runtime.swt.internal.finder.WidgetLocatorService; import com.windowtester.runtime.swt.internal.identifier.ContributedIdentifierManager; import com.windowtester.runtime.swt.locator.ListItemLocator; import com.windowtester.runtime.swt.locator.SWTWidgetLocator; import com.windowtester.swt.event.model.factory.SWTSemanticEventFactoryImplV1; import com.windowtester.swt.event.recorder.IEventRecorderPluginTraceOptions; public class SpyEventHandler { public static boolean FORCE_ENABLE = false; //FOR TESTING private boolean inSpyMode = FORCE_ENABLE; public UISemanticEvent interepretHover(Event event) { if (!inSpyMode) return null; return createInspectionEvent(event); } public void spyModeToggled() { this.inSpyMode = !inSpyMode; Tracer.trace(IEventRecorderPluginTraceOptions.SWT_EVENTS, "spy mode toggled to: " + inSpyMode); } private UISemanticEvent createInspectionEvent(Event event) { Widget w = event.widget; if (w == null) return null; // int stateMask = event.stateMask; // if ((stateMask & SWT.CTRL) != 0) // return null; // System.out.println("--->spy handling: " + event); Shell currentShell = getShell(w); /* * UGLY, UGLY, UGLY * Seed to ensure scope is properly set (rub: need to * override active shell which may be null) */ ShellFinder.CURRENT_SHELL_HINT = currentShell; w = getMostSpecificWidgetForEvent(w, event); if (w == null) return null; SemanticWidgetInspectionEvent containerInspection = SemanticContainerDescription.forWidgetInShell(w, currentShell); if (containerInspection != null) return containerInspection; EventInfo info = extractInfo(event, w); return new SemanticWidgetInspectionEvent(info, Context.GLOBAL.getUI()).withWidgetHash(w.hashCode()).atHoverPoint(getCursorPosition()); } private Shell getShell(Widget w) { try { SWTHierarchyHelper helper = new SWTHierarchyHelper(w.getDisplay()); do { w = helper.getParent(w); if (w instanceof Shell) { return (Shell) w; } } while (w != null); } catch (Throwable th) { // being safe } return null; } private Point getCursorPosition() { return Display.getDefault().getCursorLocation(); } private EventInfo extractInfo(Event event, Widget w) { EventInfo info = new EventInfo(); info.toString = "inspection request for: " + w; info.cls = w.getClass().getName(); info.hierarchyInfo = identifyWidget(w, event); info.x = event.x; info.y = event.y; return info; } private IWidgetIdentifier identifyWidget(Widget w, Event event) { ILocator contributed = ContributedIdentifierManager.identify(event); if (contributed != null) return SWTSemanticEventFactoryImplV1.adaptToIdentifier(contributed); IWidgetIdentifier id = new WidgetLocatorService().inferIdentifyingInfo(w, event); return sanityCheck(id, event); } private IWidgetIdentifier sanityCheck(IWidgetIdentifier id, Event event) { if (id instanceof ListItemLocator) { ListItemLocator listItem = (ListItemLocator)id; /* * Since there is no way to map hover location to an associated list item, we pop up and only surface details on the List */ SWTWidgetLocator list = new SWTWidgetLocator(List.class); list.setParentInfo(listItem.getParentInfo()); return list; } return id; } static Widget getMostSpecificWidgetForEvent(Widget w, Event event) { if (w instanceof Tree) { Tree tree = (Tree)w; return tree.getItem(pointFor(event)); } if (w instanceof Table) { Table table = (Table)w; return table.getItem(pointFor(event)); } if (w instanceof ToolBar) { ToolBar bar = (ToolBar)w; return bar.getItem(pointFor(event)); } if (w instanceof CoolBar) { CoolBar bar = (CoolBar)w; CoolItem[] items = bar.getItems(); for (int i = 0; i < items.length; i++) { CoolItem item = items[i]; Rectangle bounds = SWTWorkarounds.getBounds(item); if (bounds != null && bounds.contains(pointFor(event))) return item; } } if (w instanceof TabFolder) { TabFolder folder = (TabFolder)w; TabItem[] items = folder.getItems(); for (int i = 0; i < items.length; i++) { TabItem item = items[i]; Rectangle bounds = SWTWorkarounds.getBounds(item); if (bounds != null && bounds.contains(pointFor(event))) return item; } } if (w instanceof CTabFolder) { CTabFolder folder = (CTabFolder)w; return folder.getItem(pointFor(event)); } if (w instanceof Composite) { Composite composite = (Composite)w; Control[] children = composite.getChildren(); for (int i = 0; i < children.length; i++) { Control control = children[i]; Rectangle bounds = SWTWorkarounds.getBounds(control); if (bounds != null && bounds.contains(pointFor(event))) return control; } } //TODO: are there more cases? return w; } private static Point pointFor(Event event) { return new Point(event.x, event.y); } }