blob: 917d343e7ecc337a3e6ba81cf7715c945e431fa2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* 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:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.rc.swt.tester.tree;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.jubula.rc.common.driver.ClickOptions;
import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer;
import org.eclipse.jubula.rc.common.driver.IRobot;
import org.eclipse.jubula.rc.common.driver.IRunnable;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext;
import org.eclipse.jubula.rc.common.logger.AutServerLogger;
import org.eclipse.jubula.rc.common.util.Verifier;
import org.eclipse.jubula.rc.swt.tester.CAPUtil;
import org.eclipse.jubula.rc.swt.utils.SwtPointUtil;
import org.eclipse.jubula.rc.swt.utils.SwtUtils;
import org.eclipse.jubula.tools.constants.SwtAUTHierarchyConstants;
import org.eclipse.jubula.tools.objects.event.EventFactory;
import org.eclipse.jubula.tools.objects.event.TestErrorEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
/**
* This context holds the tree, the tree model and supports access to the Robot.
* It also implements some general operations on trees.
* @author BREDEX GmbH
* @created 09.08.2005
*/
public class TreeOperationContext extends AbstractTreeOperationContext {
/** The AUT Server logger. */
private static AutServerLogger log =
new AutServerLogger(TreeOperationContext.class);
/**
* Creates a new instance.
*
* @param queuer The queuer
* @param robot The Robot
* @param tree The tree
*/
public TreeOperationContext(IEventThreadQueuer queuer, IRobot robot,
Tree tree) {
super(queuer, robot, tree);
}
/**
* @param node
* The node.
* @param row
* The node row.
* @return The converted text
* @throws StepExecutionException
* If the method call fails.
*/
protected String convertValueToText(final Object node, final int row)
throws StepExecutionException {
return getRenderedText(node);
}
/**
* {@inheritDoc}
*/
public String getRenderedText(final Object node)
throws StepExecutionException {
final TreeItem treeNode = (TreeItem)node;
return (String)getQueuer().invokeAndWait(
"getText", new IRunnable() { //$NON-NLS-1$
public Object run() {
return CAPUtil.getWidgetText(treeNode, treeNode.getText());
}
});
}
/**
* {@inheritDoc}
*/
public boolean isVisible(final Object node) {
final TreeItem treeNode = (TreeItem)node;
Boolean visible = (Boolean)getQueuer().invokeAndWait("isVisible", //$NON-NLS-1$
new IRunnable() {
public Object run() {
TreeItem item = treeNode;
boolean vis = true;
while (item != null && item.getParentItem() != null) {
vis = item.getParentItem().getExpanded();
item = item.getParentItem();
}
return vis ? Boolean.TRUE : Boolean.FALSE;
}
});
return visible.booleanValue();
}
/**
* {@inheritDoc}
*/
public Rectangle getVisibleRowBounds(Rectangle rowBounds) {
org.eclipse.swt.graphics.Rectangle r =
(org.eclipse.swt.graphics.Rectangle)
getQueuer().invokeAndWait("getVisibleRowBounds: " + rowBounds, //$NON-NLS-1$
new IRunnable() {
public Object run() {
Tree tree = (Tree)getTree();
org.eclipse.swt.graphics.Rectangle visibleBounds =
tree.getClientArea();
return visibleBounds;
}
});
Rectangle visibleTreeBounds = new Rectangle(
r.x, r.y, r.width, r.height);
Rectangle visibleRowBounds = visibleTreeBounds.intersection(rowBounds);
return visibleRowBounds;
}
/**
* {@inheritDoc}
*/
public void collapseNode(Object node) {
final TreeItem item = castToTreeItem(node);
final Tree tree = (Tree)getTree();
boolean doAction = isExpanded(item);
if (doAction) {
if (log.isDebugEnabled()) {
log.debug("Collapsing node: " //$NON-NLS-1$
+ node);
}
getQueuer().invokeAndWait("collapse", new IRunnable() { //$NON-NLS-1$
public Object run() throws StepExecutionException {
Event collapseEvent = new Event();
collapseEvent.time = (int)System.currentTimeMillis();
collapseEvent.type = SWT.Collapse;
collapseEvent.widget = tree;
collapseEvent.item = item;
tree.notifyListeners(SWT.Collapse, collapseEvent);
item.setExpanded(false);
tree.update();
// Return value not used
return null;
}
});
}
}
/**
* {@inheritDoc}
*/
public void expandNode(Object node) {
final ClassLoader oldCl = Thread.currentThread()
.getContextClassLoader();
try {
final TreeItem item = castToTreeItem(node);
final Tree tree = (Tree)getTree();
boolean doAction = !isExpanded(item);
Thread.currentThread().setContextClassLoader(tree.getClass()
.getClassLoader());
getQueuer().invokeAndWait("Scroll Tree item: " + item //$NON-NLS-1$
+ " to visible", new IRunnable() { //$NON-NLS-1$
public Object run() {
tree.showItem(item);
// Return value not used
return null;
}
});
final Rectangle nodeBounds = getNodeBounds(node);
Rectangle visibleNodeBounds = getVisibleRowBounds(nodeBounds);
org.eclipse.swt.graphics.Rectangle swtVisibleNodeBounds =
new org.eclipse.swt.graphics.Rectangle(
visibleNodeBounds.x,
visibleNodeBounds.y,
visibleNodeBounds.width,
visibleNodeBounds.height);
getRobot().move(tree, swtVisibleNodeBounds);
if (doAction) {
if (log.isDebugEnabled()) {
log.debug("Expanding node: " + node); //$NON-NLS-1$
log.debug("Node bounds : " + visibleNodeBounds); //$NON-NLS-1$
}
getQueuer().invokeAndWait("expand", new IRunnable() { //$NON-NLS-1$
public Object run() throws StepExecutionException {
Event expandEvent = new Event();
expandEvent.time = (int)System.currentTimeMillis();
expandEvent.type = SWT.Expand;
expandEvent.widget = tree;
expandEvent.item = item;
tree.notifyListeners(SWT.Expand, expandEvent);
item.setExpanded(true);
tree.update();
// Return value not used
return null;
}
});
}
} finally {
Thread.currentThread().setContextClassLoader(oldCl);
}
}
/**
* {@inheritDoc}
*/
public Object[] getRootNodes() {
return (Object[])getQueuer().invokeAndWait("getRootNode", //$NON-NLS-1$
new IRunnable() {
public Object run() {
return ((Tree)getTree()).getItems();
}
});
}
/**
* {@inheritDoc}
*/
public boolean isExpanded(Object node) {
final TreeItem item = castToTreeItem(node);
// FIXME zeb: Verify that getExpanded() works like I think it does:
// It should return false if any of the parent nodes are
// collapsed.
return ((Boolean)getQueuer().invokeAndWait(
"isExpanded: " + item, //$NON-NLS-1$
new IRunnable() {
public Object run() {
return item.getExpanded() ? Boolean.TRUE : Boolean.FALSE;
}
})).booleanValue();
}
/**
* {@inheritDoc}
*/
public void clickNode(final Object node, final ClickOptions clickOps) {
final TreeItem item = castToTreeItem(node);
scrollNodeToVisible(item);
// Wait for all paint events resulting from the scroll to be processed
// before calculating bounds.
SwtUtils.waitForDisplayIdle(item.getDisplay());
org.eclipse.swt.graphics.Rectangle visibleRowBounds =
(org.eclipse.swt.graphics.Rectangle)getQueuer().invokeAndWait(
"getVisibleNodeBounds " + node, new IRunnable() { //$NON-NLS-1$
public Object run() {
final Rectangle nodeBounds = getNodeBounds(node);
return SwtPointUtil.toSwtRectangle(
getVisibleRowBounds(nodeBounds));
}
});
getRobot().click(getTree(), visibleRowBounds,
clickOps.setScrollToVisible(false));
}
/**
* {@inheritDoc}
*/
public void toggleNodeCheckbox(final Object node) {
final TreeItem item = castToTreeItem(node);
scrollNodeToVisible(item);
getQueuer().invokeAndWait(
"selectNodeCheckbox", new IRunnable() { //$NON-NLS-1$
public Object run() {
Tree tree = ((Tree)getTree());
boolean toggledValue = !item.getChecked();
item.setChecked(toggledValue);
Event toggleEvent = new Event();
toggleEvent.type = SWT.Selection;
toggleEvent.detail = SWT.CHECK;
toggleEvent.widget = tree;
toggleEvent.item = item;
toggleEvent.button = SWT.BUTTON1;
toggleEvent.count = 1;
toggleEvent.display = item.getDisplay();
tree.notifyListeners(SWT.Selection, toggleEvent);
return null;
}
});
}
/**
* {@inheritDoc}
*/
public void verifyCheckboxSelection(final Object node,
final boolean checked) {
final TreeItem item = castToTreeItem(node);
scrollNodeToVisible(item);
Boolean checkSelected = ((Boolean)getQueuer().invokeAndWait(
"verifyCheckboxSelection", new IRunnable() { //$NON-NLS-1$
public Object run() {
return new Boolean(item.getChecked());
}
}));
Verifier.equals(checked, checkSelected.booleanValue());
}
/**
* {@inheritDoc}
*/
public void scrollNodeToVisible(final Object node) {
getQueuer().invokeAndWait("showItem: " + node, //$NON-NLS-1$
new IRunnable() {
public Object run() {
((Tree)getTree()).showItem(castToTreeItem(node));
return null;
}
});
final Rectangle nodeBoundsRelativeToParent = getNodeBounds(node);
final Tree tree = (Tree)getTree();
getQueuer().invokeAndWait("getNodeBoundsRelativeToParent", //$NON-NLS-1$
new IRunnable() {
public Object run() {
org.eclipse.swt.graphics.Point cellOriginRelativeToParent =
tree.getDisplay().map(
tree, tree.getParent(),
new org.eclipse.swt.graphics.Point(
nodeBoundsRelativeToParent.x,
nodeBoundsRelativeToParent.y));
nodeBoundsRelativeToParent.x =
cellOriginRelativeToParent.x;
nodeBoundsRelativeToParent.y =
cellOriginRelativeToParent.y;
return null;
}
});
Control parent = (Control)getQueuer().invokeAndWait("getParent", //$NON-NLS-1$
new IRunnable() {
public Object run() {
tree.getParent();
return null;
}
});
getRobot().scrollToVisible(parent,
SwtPointUtil.toSwtRectangle(nodeBoundsRelativeToParent));
}
/**
* {@inheritDoc}
*/
public Object getChild(final Object parent, final int index) {
if (parent == null) {
Object [] rootNodes = getRootNodes();
if (index < 0 || index >= rootNodes.length) {
// FIXME zeb: Handle child not found
return null;
}
return rootNodes[index];
}
return getQueuer().invokeAndWait(
"getChild: " + parent + "; With index: " + index, //$NON-NLS-1$ //$NON-NLS-2$
new IRunnable() {
public Object run() {
TreeItem parentItem = castToTreeItem(parent);
try {
return parentItem.getItem(index);
} catch (IllegalArgumentException iae) {
// FIXME zeb: Handle child not found
return null;
}
}
});
}
/**
* {@inheritDoc}
*/
public Object getParent(final Object child) {
return getQueuer().invokeAndWait("getParent: " + child, //$NON-NLS-1$
new IRunnable() {
public Object run() {
TreeItem childItem = castToTreeItem(child);
return childItem.getParentItem();
}
});
}
/**
* Casts an Object to a TreeItem, handles ClassCastExceptions by throwing an
* IllegalArgumentException.
* @param toCast The object to cast
* @return The original object casted to a TreeItem
*/
private TreeItem castToTreeItem(Object toCast) {
try {
return (TreeItem)toCast;
} catch (ClassCastException cce) {
throw new IllegalArgumentException(
"Object must be of type TreeItem"); //$NON-NLS-1$
}
}
/**
* {@inheritDoc}
*/
public Object getSelectedNode() {
return getQueuer().invokeAndWait("getSelectedNode", //$NON-NLS-1$
new IRunnable() {
public Object run() {
TreeItem [] selectedItems =
((Tree)getTree()).getSelection();
if (selectedItems == null || selectedItems.length == 0) {
throw new StepExecutionException(
"No tree node(s) selected", //$NON-NLS-1$
EventFactory.createActionError(
TestErrorEvent.NO_SELECTION));
}
return selectedItems[0];
}
});
}
/**
* {@inheritDoc}
*/
public Object[] getChildren(Object parent) {
if (parent == null) {
return getRootNodes();
}
final TreeItem item = castToTreeItem(parent);
return (Object[])getQueuer().invokeAndWait("getChildren: " + item, //$NON-NLS-1$
new IRunnable() {
public Object run() {
return item.getItems();
}
});
}
/**
* {@inheritDoc}
*/
public int getNumberOfChildren(Object parent) {
if (parent == null) {
return getRootNodes().length;
}
final TreeItem item = castToTreeItem(parent);
return ((Integer)getQueuer().invokeAndWait("getChildren: " + item, //$NON-NLS-1$
new IRunnable() {
public Object run() {
return new Integer(item.getItemCount());
}
})).intValue();
}
/**
* {@inheritDoc}
*/
public Collection getNodeTextList(Object node) {
final Collection res = new ArrayList();
final TreeItem item = castToTreeItem(node);
getQueuer().invokeAndWait("getNodeText: " + item, //$NON-NLS-1$
new IRunnable() {
public Object run() {
int colCount = ((Tree)getTree()).getColumnCount();
for (int i = 0; i < colCount; i++) {
String textAtColumn = CAPUtil.getWidgetText(item,
SwtAUTHierarchyConstants.WIDGET_TEXT_KEY_PREFIX
+ i, item.getText(i));
if (textAtColumn != null) {
res.add(textAtColumn);
}
}
String text = CAPUtil.getWidgetText(item, item.getText());
if (text != null) {
res.add(text);
}
return null;
}
});
return res;
}
/**
* {@inheritDoc}
*/
public Rectangle getNodeBounds(final Object node) {
org.eclipse.swt.graphics.Rectangle r =
(org.eclipse.swt.graphics.Rectangle)
getQueuer().invokeAndWait("getNodeBounds: " + node, //$NON-NLS-1$
new IRunnable() {
public Object run() {
Tree tree = (Tree)getTree();
org.eclipse.swt.graphics.Rectangle bounds =
SwtUtils.getRelativeWidgetBounds(
(TreeItem)node, tree);
return bounds;
}
});
Rectangle nodeBounds = new Rectangle(
r.x, r.y, r.width, r.height);
return nodeBounds;
}
/**
* {@inheritDoc}
*/
public int getIndexOfChild(final Object parent, final Object child) {
if (parent != null) {
return ((Integer)(getQueuer().invokeAndWait(
"getIndexOfChild", //$NON-NLS-1$
new IRunnable() {
public Object run() throws StepExecutionException {
return new Integer(
((TreeItem)parent).indexOf((TreeItem)child));
}
}))).intValue();
}
Object [] rootNodes = getRootNodes();
for (int i = 0; i < rootNodes.length; i++) {
if (rootNodes[i] == child) {
return i;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
public boolean isLeaf(Object node) {
if (getNumberOfChildren(node) == 0) {
return true;
}
return false;
}
}