/*******************************************************************************
* 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.model.factory;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import abbot.tester.swt.CComboTester;
import abbot.tester.swt.ComboTester;
import abbot.tester.swt.MenuItemTester;
import abbot.tester.swt.MenuTester;
import abbot.tester.swt.ShellTester;
import abbot.tester.swt.TableItemTester;
import abbot.tester.swt.TreeItemTester;
import com.windowtester.internal.runtime.IWidgetIdentifier;
import com.windowtester.internal.runtime.locator.IdentifierAdapter;
import com.windowtester.recorder.event.IUISemanticEvent;
import com.windowtester.recorder.event.user.SemanticComboSelectionEvent;
import com.windowtester.recorder.event.user.SemanticDefaultSelectionEvent;
import com.windowtester.recorder.event.user.SemanticDragEvent;
import com.windowtester.recorder.event.user.SemanticDropEvent;
import com.windowtester.recorder.event.user.SemanticFocusEvent;
import com.windowtester.recorder.event.user.SemanticKeyDownEvent;
import com.windowtester.recorder.event.user.SemanticListSelectionEvent;
import com.windowtester.recorder.event.user.SemanticMenuSelectionEvent;
import com.windowtester.recorder.event.user.SemanticMoveEvent;
import com.windowtester.recorder.event.user.SemanticResizeEvent;
import com.windowtester.recorder.event.user.SemanticShellClosingEvent;
import com.windowtester.recorder.event.user.SemanticShellDisposedEvent;
import com.windowtester.recorder.event.user.SemanticShellShowingEvent;
import com.windowtester.recorder.event.user.SemanticTreeItemSelectionEvent;
import com.windowtester.recorder.event.user.SemanticWidgetSelectionEvent;
import com.windowtester.recorder.event.user.TreeEventType;
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.debug.LogHandler;
import com.windowtester.runtime.swt.internal.finder.WidgetLocatorService;
import com.windowtester.runtime.swt.internal.identifier.ContributedIdentifierManager;
import com.windowtester.runtime.swt.internal.locator.NoOpLocator;
import com.windowtester.runtime.swt.internal.selector.UIProxy;
import com.windowtester.runtime.swt.internal.util.TextUtils;
import com.windowtester.runtime.swt.locator.ListItemLocator;
import com.windowtester.runtime.swt.locator.SWTWidgetLocator;
import com.windowtester.swt.event.model.EventModelConstants;
import com.windowtester.swt.event.model.ISWTSemanticEventFactory;
/**
* A factory for building SWTSemanticEvents
*
* NOTE: this is a LEGACY class. Ultimately {@link SWTSemanticEventFactoryImplV2} will be preferred.
*/
public class SWTSemanticEventFactoryImplV1 implements ISWTSemanticEventFactory {
////////////////////////////////////////////////////////////////////////////
//
// Helpers
//
////////////////////////////////////////////////////////////////////////////
private final MenuItemTester _menuItemTester = new MenuItemTester();
private final MenuTester _menuTester = new MenuTester();
private final ComboTester _comboTester = new ComboTester();
private final CComboTester _cComboTester = new CComboTester();
private final TreeItemTester _treeItemTester = new TreeItemTester();
private final TableItemTester _tableItemTester = new TableItemTester();
private final ShellTester _shellTester = new ShellTester();
////////////////////////////////////////////////////////////////////////////
//
// Cached references
//
////////////////////////////////////////////////////////////////////////////
//the last seen widget --- whereby seen we mean has had info extracted...
private Widget _lastWidget;
//the last calculated widget locator
private IWidgetIdentifier _lastWidgetLocator;
////////////////////////////////////////////////////////////////////////////
//
// Public factory methods
//
////////////////////////////////////////////////////////////////////////////
public SemanticDropEvent createDragToEvent(Event event) {
return null; //unsupported
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createKeyDownEvent(org.eclipse.swt.widgets.Event)
*/
public SemanticKeyDownEvent createKeyDownEvent(Event event) {
EventInfo info = extractInfo(event);
SemanticKeyDownEvent keyDown = new SemanticKeyDownEvent(info);
keyDown.setKey(event.character);
keyDown.setKeyCode(event.keyCode);
return keyDown;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createKeyDownEvent(org.eclipse.swt.events.TraverseEvent)
*/
public SemanticKeyDownEvent createKeyDownEvent(TraverseEvent event) {
/*
* extractInfo does not work on TypedEvents... so, we replicate
* here (for now)
*/
EventInfo info = new EventInfo();
info.toString = "Traverse Event widget=" + event.widget + "char= " + event.character; //a quick hack
info.cls = event.widget.getClass().getName();
// info.parentShell = getParentShellInfo(event.widget);
info.button = 0; //not a mouse event
info.x = 0; //no x, y info associated
info.y = 0; //...
SemanticKeyDownEvent keyDown = new SemanticKeyDownEvent(info);
keyDown.setKey(event.character);
keyDown.setKeyCode(event.keyCode);
return keyDown;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createKeyDownEvent(org.eclipse.swt.events.KeyEvent)
*/
public SemanticKeyDownEvent createKeyDownEvent(KeyEvent event) {
/*
* extractInfo does not work on TypedEvents... so, we replicate
* here (for now)
*/
EventInfo info = new EventInfo();
info.toString = "Traverse Event widget=" + event.widget + "char= " + event.character; //a quick hack
info.cls = event.widget.getClass().getName();
// info.parentShell = getParentShellInfo(event.widget);
info.button = 0; //not a mouse event
info.x = 0; //no x, y info associated
info.y = 0; //...
SemanticKeyDownEvent keyDown = new SemanticKeyDownEvent(info);
keyDown.setKey(event.character);
keyDown.setKeyCode(event.keyCode);
return keyDown;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createWidgetSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createWidgetSelectionEvent(Event event) {
UISemanticEvent contributed = checkForContributedHandler(event);
if (contributed != null)
return contributed;
return parseSelectionEvent(event);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.ISWTSemanticEventFactory#createWidgetDisposedEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createWidgetClosedEvent(Widget widget) {
// TODO not supported in V1
return null;
}
private UISemanticEvent parseSelectionEvent(Event event) {
EventInfo info = extractInfo(event);
/*
* Some events are no-ops. Check for one of these first.
*/
if (info.hierarchyInfo instanceof NoOpLocator)
return null;
/*
* Texts in CCombos require special treatment:
*/
if (event.widget instanceof Text) {
WidgetLocatorService locator = new WidgetLocatorService();
Widget parent = locator.getParent(event.widget);
if (parent instanceof CCombo) {
info.hierarchyInfo = locator.inferIdentifyingInfo(parent);
info.toString = EventModelConstants.getEventName(event) + " widget=" + parent + " button= " + event.button;
SemanticWidgetSelectionEvent widgetSelect = new SemanticWidgetSelectionEvent(info);
widgetSelect.setItemLabel(parent.toString());
return widgetSelect;
}
} //TODO: cleanup and refactor this conditional logic
SemanticWidgetSelectionEvent widgetSelect = new SemanticWidgetSelectionEvent(info);
String label = extractWidgetLabel(event.widget);
widgetSelect.setItemLabel(label);
return widgetSelect;
}
private UISemanticEvent checkForContributedHandler(Event event) {
ILocator locator = getContributedLocator(event);
if (locator == null)
return null;
EventInfo info = extractInfo(event);
info.hierarchyInfo = adaptToIdentifier(locator);
SemanticWidgetSelectionEvent widgetSelect = new SemanticWidgetSelectionEvent(info);
String label = extractWidgetLabel(event.widget);
widgetSelect.setItemLabel(label);
return widgetSelect;
}
private ILocator getContributedLocator(Event target) {
return ContributedIdentifierManager.identify(target);
}
public static IWidgetIdentifier adaptToIdentifier(ILocator locator) {
IWidgetIdentifier identifier = null;
if (locator instanceof IWidgetIdentifier){
identifier = (IWidgetIdentifier)locator;
} else {
identifier = new IdentifierAdapter(locator);
}
return identifier;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createTabItemSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createTabItemSelectionEvent(Event event) {
Widget w = event.widget;
Widget item = null;
if (w instanceof TabFolder) {
//perhaps overly simplistic: taking first selection
item = ((TabFolder)w).getSelection()[0];
} else if (w instanceof CTabFolder) {
item = ((CTabFolder)w).getSelection();
}
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = item.getClass().getName();
// info.parentShell = getParentShellInfo(item);
info.hierarchyInfo = inferIdentifyingInfo(item);
/*
* Need to map x coords to coords relative to the widget
*/
Rectangle parentBounds = UIProxy.getBounds(event.widget);
Rectangle itemBounds = UIProxy.getBounds(item);
info.x = event.x - (itemBounds.x - parentBounds.x);
info.y = event.y;
SemanticWidgetSelectionEvent widgetSelect = new SemanticWidgetSelectionEvent(info);
String label = extractWidgetLabel(item);
widgetSelect.setItemLabel(label);
return widgetSelect;
}
private IWidgetIdentifier inferIdentifyingInfo(Widget widget) {
return new WidgetLocatorService().inferIdentifyingInfo(widget);
}
private IWidgetIdentifier inferIdentifyingInfo(Widget widget, Event event) {
return new WidgetLocatorService().inferIdentifyingInfo(widget, event);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createListItemSelectionEvent(org.eclipse.swt.widgets.List, java.lang.String, java.lang.String)
*/
public UISemanticEvent createListItemSelectionEvent(List list, String item, String mask) {
EventInfo info = new EventInfo();
info.toString = "List item selection (" + item + ") widget=" + list;
info.cls = list.getClass().getName();
info.hierarchyInfo = inferIdentifyingInfo(list);
//add item info to the locator (this isn't done by the service)
if (info.hierarchyInfo instanceof ListItemLocator) {
ListItemLocator loc = (ListItemLocator)info.hierarchyInfo;
loc.setPath(item);
}
SemanticListSelectionEvent listSelect = new SemanticListSelectionEvent(info);
listSelect.setItem(item);
listSelect.setMask(mask);
return listSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createComboSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createComboSelectionEvent(Event event) {
Combo combo = (Combo)event.widget;
EventInfo info = new EventInfo();
info.toString = "Combo item selection (" + combo + ") widget=" + combo;
info.cls = combo.getClass().getName();
// info.parentShell = getParentShellInfo(combo);
info.hierarchyInfo = inferIdentifyingInfo(combo);
info.x = event.x;
info.y = event.y;
SemanticComboSelectionEvent comboSelect = new SemanticComboSelectionEvent(info);
int index = _comboTester.getSelectionIndex(combo);
//TODO: the case where none is selected is an error and should be managed like one...
String item = (index == -1) ? "" /* none selected */ : _comboTester.getItem(combo, index);
comboSelect.setSelection(item);
return comboSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createCComboSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createCComboSelectionEvent(Event event) {
CCombo cCombo = (CCombo)event.widget;
EventInfo info = new EventInfo();
info.toString = "CCombo item selection (" + cCombo + ") widget=" + cCombo;
info.cls = cCombo.getClass().getName();
// info.parentShell = getParentShellInfo(cCombo);
info.hierarchyInfo = inferIdentifyingInfo(cCombo);
info.x = event.x;
info.y = event.y;
//N.B. reusing ComboSelection in the hopes we don't need a CCombo-specific one...
SemanticComboSelectionEvent comboSelect = new SemanticComboSelectionEvent(info);
int index = _cComboTester.getSelectionIndex(cCombo);
//TODO: the case where none is selected is an error and should be managed like one...
String item = (index == -1) ? "" /* none selected */ : _cComboTester.getItem(cCombo, index);
comboSelect.setSelection(item);
return comboSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createTableItemSelectionEvent(org.eclipse.swt.widgets.Table, org.eclipse.swt.widgets.TableItem, int, java.lang.String)
*/
public UISemanticEvent createTableItemSelectionEvent(Table table, TableItem item, int columnIndex, String mask) {
EventInfo info = new EventInfo();
info.toString = "Table item selection (" + item + ") widget=" + item;
info.cls = item.getClass().getName();
// info.parentShell = getParentShellInfo(table);
info.hierarchyInfo = inferIdentifyingInfo(item);
SemanticWidgetSelectionEvent tableItemSelect = new SemanticWidgetSelectionEvent(info);
// set the no of clicks
tableItemSelect.setClicks(1);
// tableItemSelect.setItem(item);
if (columnIndex != 0)
tableItemSelect.setIndex(columnIndex);
tableItemSelect.setMask(mask);
return tableItemSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createMenuSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public SemanticMenuSelectionEvent createMenuSelectionEvent(Event event) {
MenuItem item = (MenuItem)event.widget;
String pathString = _menuItemTester.getPathString(item);
//non context case
if (event.button != 3) {
int index = pathString.indexOf("/");
if (index != -1)
pathString = pathString.substring(index+1);
}
//need to find "root menu item"
MenuItem root = getRootMenuItem(item);
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = root.getClass().getName();
// info.parentShell = getParentShellInfo(event.widget);
info.hierarchyInfo = inferIdentifyingInfo(root);
info.button = event.button;
info.x = event.x;
info.y = event.y;
SemanticMenuSelectionEvent menuSelect = new SemanticMenuSelectionEvent(info);
String label = extractMenuItemLabel(event);
menuSelect.setItemLabel(label);
menuSelect.setPath(pathString);
return menuSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createContextMenuSelectionEvent(org.eclipse.swt.widgets.Widget, org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createContextMenuSelectionEvent(Widget target, Event event) {
/**
* there are pathological cases (where someone tries to get a context menu from within a
* context menu for example) where the target is null. In this case we just fast fail.
* TODO: handle this better!
*/
if (target == null)
return null;
MenuItem item = (MenuItem)event.widget;
String pathString = _menuItemTester.getPathString(item);
pathString = TextUtils.fixTabs(pathString);
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = target.getClass().getName();
ILocator locator = getContributedLocator(FakeEvent.forWidget(target).atCursorXY());
if (locator != null)
info.hierarchyInfo = adaptToIdentifier(locator);
else
info.hierarchyInfo = inferIdentifyingInfo(target);
info.button = 3;
info.x = event.x;
info.y = event.y;
SemanticMenuSelectionEvent menuSelect = new SemanticMenuSelectionEvent(info);
String label = extractMenuItemLabel(event);
menuSelect.setItemLabel(label);
menuSelect.setPath(pathString);
return menuSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createTreeItemContextMenuSelectionEvent(com.windowtester.recorder.event.user.SemanticTreeItemSelectionEvent, org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createTreeItemContextMenuSelectionEvent(SemanticTreeItemSelectionEvent treeItemSelectionEvent, Event event) {
String menuPath = _menuItemTester.getPathString((MenuItem)event.widget);
menuPath = TextUtils.fixTabs(menuPath);
treeItemSelectionEvent.setContextMenuSelectionPath(menuPath);
return treeItemSelectionEvent;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createContextMenuSelectionEvent(com.windowtester.recorder.event.user.UISemanticEvent, org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createContextMenuSelectionEvent(UISemanticEvent selection, Event event) {
MenuItem item = (MenuItem)event.widget;
String pathString = _menuItemTester.getPathString(item);
pathString = TextUtils.fixTabs(pathString);
IWidgetIdentifier loc = selection.getHierarchyInfo();
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = loc.getTargetClass().getName();
//info.parentShell = selection.getParentShellInfo();
info.hierarchyInfo = loc;
info.button = 3;
info.x = event.x;
info.y = event.y;
SemanticMenuSelectionEvent menuSelect = new SemanticMenuSelectionEvent(info);
menuSelect.setIndex(selection.getIndex());
String label = extractMenuItemLabel(event);
menuSelect.setItemLabel(label);
menuSelect.setPath(pathString);
return menuSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createTreeItemSelectionEvent(org.eclipse.swt.widgets.Event, com.windowtester.recorder.event.user.TreeEventType, int)
*/
public SemanticTreeItemSelectionEvent createTreeItemSelectionEvent(Event event, TreeEventType type, int button) {
EventInfo info = extractInfo(event);
info.button = button; //event's button info is incorrect
SemanticTreeItemSelectionEvent treeSelect = new SemanticTreeItemSelectionEvent(info, type);
String label = extractTreeItemLabel(event);
treeSelect.setItemLabel(label);
String path = extractPathString((TreeItem)event.item);
treeSelect.setItemPath(path);
return treeSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createTreeItemSelectionEvent(org.eclipse.swt.widgets.TreeItem, com.windowtester.recorder.event.user.TreeEventType, int)
*/
public UISemanticEvent createTreeItemSelectionEvent(TreeItem item, TreeEventType type, int button) {
//fetch parent tree
Tree tree = _treeItemTester.getParent(item);
EventInfo info = new EventInfo();
info.toString = "Tree Item Selection (" + type.getLabel() + ")";
info.cls = tree.getClass().getName();
// info.parentShell = getParentShellInfo(tree);
info.hierarchyInfo = inferIdentifyingInfo(tree);
info.button = button;
SemanticTreeItemSelectionEvent treeSelect = new SemanticTreeItemSelectionEvent(info, type);
String label = extractTreeItemLabel(item);
treeSelect.setItemLabel(label);
String path = extractPathString(item);
treeSelect.setItemPath(path);
return treeSelect;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createRawEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createRawEvent(Event event) {
EventInfo info = extractInfo(event);
return new UISemanticEvent(info);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createDefaultSelectionEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createDefaultSelectionEvent(Event event) {
EventInfo info = extractInfo(event);
return new SemanticDefaultSelectionEvent(info);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createShellShowingEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createShellShowingEvent(Event event) {
EventInfo info = extractInfo(event);
String text = null;
if (event.widget instanceof Shell)
text = _shellTester.getText((Shell)event.widget);
return new SemanticShellShowingEvent(info, text);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createShellClosingEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createShellClosingEvent(Event event) {
EventInfo info = extractInfo(event);
String text = null;
if (event.widget instanceof Shell)
text = _shellTester.getText((Shell)event.widget);
return new SemanticShellClosingEvent(info, text);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createShellDisposedEvent(org.eclipse.swt.widgets.Event)
*/
public UISemanticEvent createShellDisposedEvent(Event event) {
/*
* Rather than extract the info we build it manually
* (extraction can throw exceptions since widgets are getting disposed)
*/
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = event.widget.getClass().getName();
// info.parentShell = getParentShellInfo(event.widget);
info.button = event.button;
info.x = event.x;
info.y = event.y;
Shell shell = (Shell)event.widget;
// info.hierarchyInfo = new WidgetLocator(Shell.class, _shellTester.getText(shell));
info.hierarchyInfo = new SWTWidgetLocator(Shell.class, _shellTester.getText(shell));
return new SemanticShellDisposedEvent(info);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createMoveEvent(org.eclipse.swt.widgets.Event, org.eclipse.swt.widgets.Widget)
*/
public UISemanticEvent createMoveEvent(Event event, Widget widget) {
EventInfo info = extractInfo(event);
Rectangle bounds = UIProxy.getBounds(widget);
info.x = bounds.x;
info.y = bounds.y;
return new SemanticMoveEvent(info);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createResizeEvent(org.eclipse.swt.widgets.Event, org.eclipse.swt.widgets.Widget)
*/
public UISemanticEvent createResizeEvent(Event event, Widget widget) {
EventInfo info = extractInfo(event);
Rectangle bounds = UIProxy.getBounds(widget);
return new SemanticResizeEvent(info, bounds.width, bounds.height);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createFocusEvent(org.eclipse.swt.widgets.Event, org.eclipse.swt.widgets.Widget)
*/
public UISemanticEvent createFocusEvent(Event event, Widget widget) {
//System.out.println("creating focus event: " + widget);
UISemanticEvent focusEvent = null;
try {
EventInfo info = extractInfo(event);
focusEvent = new SemanticFocusEvent(info);
} catch(RuntimeException e) {
//the cause here is in a WidgetNotFoundException for the Text component of a CCombo
//we boldly ignore these as the CCombo's focus is set elsewhere
}
return focusEvent;
}
////////////////////////////////////////////////////////////////////////////
//
// Construction helpers
//
////////////////////////////////////////////////////////////////////////////
/**
* Find the topmost parent menu item.
* @param child
*/
protected MenuItem getRootMenuItem(MenuItem child) {
Menu parentMenu;
MenuItem parentItem = child, root = null;
do {
root = parentItem;
parentMenu = _menuItemTester.getParent(parentItem);
if (parentMenu != null)
parentItem = _menuTester.getParentItem(parentMenu);
} while (parentItem != null);
return root;
}
/**
* Create a path String that identifies this tree item with respect to its parent's (e.g. "Java/Project")
* @param item - the tree item
* @return a String representing its path
*/
protected String extractPathString(TreeItem item) {
//TODO[author=pq] use a StringBuffer or something better here (rub: *pre*pending) ...
String path = TextUtils.escapeSlashes(item.getText());
for (TreeItem parent = item.getParentItem(); parent != null; parent = parent.getParentItem()) {
//prepend
path = parent.getText() + '/' + path;
}
return path;
}
/**
* Extract the tree item label string.
* @param event - the underlying event
* @return the menu item label string
*/
protected String extractTreeItemLabel(Event event) {
Widget widget = event.item;
return extractTreeItemLabel(widget);
}
protected String extractTreeItemLabel(Widget widget) {
String label = null;
if (widget instanceof TreeItem) {
TreeItem item = (TreeItem)widget;
label = TextUtils.escapeSlashes(item.getText());
label = TextUtils.fixTabs(label);
} else //should really assert and fail if this is false
label = widget.toString();
return label;
}
/**
* Extract the menu item label string.
* @param event - the underlying event
* @return the menu item label string
*/
protected String extractMenuItemLabel(Event event) {
Widget widget = event.widget;
String label = null;
if (widget instanceof MenuItem) {
MenuItem item = (MenuItem)widget;
label = TextUtils.escapeSlashes(item.getText());
label = TextUtils.fixTabs(item.getText());
} else //should really assert and fail if this is false
label = widget.toString();
return label;
}
/**
* Extract the widget label info.
* @param event
*/
private String extractWidgetLabel(Widget widget) {
String label = null;
if (widget instanceof Button) {
Button button = (Button)widget;
label = button.getText();
} else if (widget instanceof Item) {
//TODO[author=pq] add ToolItem support here...
Item item = (Item)widget;
label = item.getText();
} else { //fall through...
label = widget.toString();
}
//finally, fix tabs that have been converted to spaces
label = TextUtils.fixTabs(label);
return label;
}
/**
* @return a short String description of this (raw) event
*/
protected String getTrimmedDescription(Event e) {
return EventModelConstants.getEventName(e) + " widget=" + e.widget + " button= " + e.button;
}
//
// /**
// * @param widget
// * @return
// */
// private ParentShellInfo getParentShellInfo(Widget widget) {
// Shell shell = getParentShell(widget);
// return createParentShellInfo(shell);
// }
// /**
// * Find this widget's parent shell. N.B. : Only valid on Control widgets.
// * @param widget - the widget in question
// * @return the parent shell (or null if there is none associated).
// */
// private Shell getParentShell(Widget widget) {
// if (widget == null || !(widget instanceof Control) || widget.isDisposed())
// return null;
// Control control = (Control)widget;
// Composite parent = control.getParent();
// while (parent != null && !(parent instanceof Shell)) {
// parent = parent.getParent();
// }
// return (Shell)parent;
// }
// /**
// * A factory helper.
// * @param shell
// * @return
// */
// private ParentShellInfo createParentShellInfo(Shell shell) {
// return shell == null ? UNAVAILABLE : new ParentShellInfo(shell);
// }
//
// /** An "empty/null" object instance */
// public final ParentShellInfo UNAVAILABLE = new ParentShellInfo(-1,"");
/**
* Extract relevant info from the given SWT event.
* @param event
* @return
*/
protected EventInfo extractInfo(Event event) {
EventInfo info = new EventInfo();
info.toString = getTrimmedDescription(event);
info.cls = event.widget.getClass().getName();
// info.parentShell = getParentShellInfo(event.widget);
info.button = event.button;
info.x = event.x;
info.y = event.y;
/*
* here we do a little caching to speed things up
*/
if (event.widget == _lastWidget && _lastWidgetLocator != null) {
info.hierarchyInfo = _lastWidgetLocator;
} else { //do it the hard way:
info.hierarchyInfo = inferIdentifyingInfo(event.widget, event);
//and update the cache
_lastWidgetLocator = info.hierarchyInfo;
_lastWidget = event.widget;
}
return info;
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createDragEvent(com.windowtester.recorder.event.IUISemanticEvent)
*/
public SemanticDragEvent createDragEvent(IUISemanticEvent event) {
return new SemanticDragEvent(event);
}
/* (non-Javadoc)
* @see com.windowtester.swt.event.model.factory.ISWTSemanticEventFactory#createDropEvent(org.eclipse.swt.dnd.DropTargetEvent, org.eclipse.swt.widgets.Control)
*/
public SemanticDropEvent createDropEvent(DropTargetEvent event, Control targetControl) {
//optionally we can set the target by passing an specifying param
Widget targetWidget = (targetControl != null) ? targetControl : event.widget;
EventInfo info = new EventInfo();
info.cls = targetWidget.getClass().getName();
// info.parentShell = getParentShellInfo(targetWidget);
info.button = 0;
//map this point from display coords to coords relative to target
Point mappedPoint = map(targetWidget, event.x, event.y);
info.x = mappedPoint.x;
info.y = mappedPoint.y;
Widget item = event.item;
UISemanticEvent target = null;
//trees and tables get special treatment
if (item instanceof TreeItem) {
target = createTreeItemSelectionEvent((TreeItem)item, TreeEventType.SELECT, 1);
//NOTE: we need to adjust x,y here
Point point = mapCoordinates((Tree)targetWidget, mappedPoint, (TreeItem)item);
target.setX(point.x);
target.setY(point.y);
}
if (item instanceof TableItem) {
TableItem tableItem = (TableItem)item;
Table table = _tableItemTester.getParent(tableItem);
//TODO: defaulting to 0 column index... will coordinates fix this?
target = createTableItemSelectionEvent(table, tableItem, 0, "SWT.BUTTON1");
// NOTE: we need to adjust x,y here
Point point = mapCoordinates(table, mappedPoint, tableItem);
target.setX(point.x);
target.setY(point.y);
}
//if we don't have a tree or table target, default to raw target
if (target == null) {
//note: we call this creation methods since it accepts contributions from extenders
target = createWidgetSelectionEvent(FakeEvent.forWidget(targetWidget).atXY(mappedPoint.x, mappedPoint.y));
}
return new SemanticDropEvent(target);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Coordinate mapping helpers
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Map these tree-relative offsets to tree-item-relative offsets
*/
private Point mapCoordinates(Tree tree, Point offset, TreeItem item) {
Rectangle bounds = _treeItemTester.getBounds(item);
int x = offset.x - bounds.x;
int y = offset.y - bounds.y;
return new Point(x,y);
}
/**
* Map these table offsets to table-item-relative offsets
*/
private Point mapCoordinates(Table table, Point offset, TableItem item) {
Rectangle bounds = _tableItemTester.getBounds(item, 0); //FIXME: using 0 column as default
int x = offset.x - bounds.x;
int y = offset.y - bounds.y;
return new Point(x,y);
}
/**
* Map this display relative coordinate to a point relative to this
* widget's control.
*/
private Point map(Widget target, int dx, int dy) {
Control control = UIProxy.getControl(target);
if (control == null)
LogHandler.log("unabled to find control for mapping target: " + target);
return target.getDisplay().map(null, control, dx, dy);
}
}