/*******************************************************************************
* 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.swt.internal.selector;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import abbot.finder.matchers.swt.TextMatcher;
import abbot.script.Condition;
import abbot.tester.swt.TreeTester;
import com.windowtester.runtime.MultipleWidgetsFoundException;
import com.windowtester.runtime.WidgetNotFoundException;
import com.windowtester.runtime.swt.internal.abbot.TreeItemTester;
import com.windowtester.runtime.swt.internal.debug.LogHandler;
import com.windowtester.runtime.swt.internal.util.PathStringTokenizerUtil;
/**
* A Selector for Tree Items.
*
* This is a legacy class preserved for use in old UIContext calls.
*
* Moving forward, prefer {@link TreeItemSelector2}
*
* @deprecated
*
*/
public class TreeItemSelector extends BasicWidgetSelector {
private TreeTester _treeTester = new TreeTester();
private TreeItemTester _treeItemTester = new TreeItemTester();
/**
* @see com.windowtester.event.swt.ISWTWidgetSelectorDelegate#clickExpand(org.eclipse.swt.widgets.Widget)
*/
public Widget clickExpand(Widget w) {
TreeItem item = (TreeItem)w;
Rectangle bounds = UIProxy.getBounds(item);
boolean isExpanded = UIProxy.getExpanded(item);
//TODO: solve this more robustly
int x = Math.round(bounds.x/4);
int y = Math.round(bounds.y/2);
click(w,-x,y, SWT.BUTTON1);
UIDriver.wait(new TreeItemExpandedCondition(item, !isExpanded), 20000);
return w;
}
/**
* @throws MultipleWidgetsFoundException
* @throws WidgetNotFoundException
* @see com.windowtester.event.swt.ISWTWidgetSelectorDelegate#click(org.eclipse.swt.widgets.Widget, java.lang.String, int)
*/
public Widget click(Widget w, String path, int mask) throws WidgetNotFoundException, MultipleWidgetsFoundException {
if (w instanceof Tree)
return click((Tree)w, path, mask);
//other cases?
return null;
}
/**
* Click the Tree Item described by this path in the given tree/
* @param tree - the parent tree
* @param path - the path to the tree item in question
* @param mask - the mouse mask
* @return the clicked Tree Item
* @throws WidgetNotFoundException
* @throws MultipleWidgetsFoundException
*/
public Widget click(Tree tree, String path, int mask) throws WidgetNotFoundException, MultipleWidgetsFoundException {
Widget clicked = null;
try {
//find item
TreeItem item = find(tree, path);
//reveal item
_treeTester.showItem(tree, item);
// it make sense to dispatch system events at this point
waitForIdle(tree.getDisplay());
if(SWT.getPlatform().equals("gtk")) // no harmful for Windows
showItemExt(tree, item);
//and click it
Rectangle rect = UIProxy.getBounds(item);
clicked = click (item, 1, rect.height/2, mask);
} catch(IllegalStateException e) {
//in this case, fall back on abbot:
try {
clicked = _treeItemTester.actionClickTreeItem(path, tree, 1);
/*
* Extra provision to ensure checks happen.
* NOTE: This began as a fix for Linux but appears to be relevant in the win32 case
* as well (com.collab.wt.smoke.tests.TreeCheckTest was failing)
*/
if ((mask & SWT.CHECK) == SWT.CHECK) {
setChecked(clicked);
}
} catch (abbot.finder.swt.WidgetNotFoundException e1) {
throw new WidgetNotFoundException("Path: " + path + " not findable in tree " + UIProxy.getToString(tree));
} catch (abbot.finder.swt.MultipleWidgetsFoundException e1) {
throw new MultipleWidgetsFoundException("Path: " + path + " ambiguous in tree " + UIProxy.getToString(tree));
} catch(IllegalStateException e2) {
LogHandler.log(e2);
}
}
return clicked;
}
public Widget doubleClick(Widget w, String path, int mask) {
Tree tree = (Tree)w;
Widget clicked = null;
try {
//find item
TreeItem item = find(tree, path);
//reveal item
_treeTester.showItem(tree, item);
//it make sense to dispatch system events at this point
waitForIdle(tree.getDisplay());
if(SWT.getPlatform().equals("gtk")) // no harmful for Windows
showItemExt(tree, item);
//and click it
Rectangle rect = UIProxy.getBounds(item);
clicked = doubleClick (item, 1, rect.height/2, mask);
} catch(IllegalStateException e) {
//in this case, fall back on abbot:
try {
clicked = _treeItemTester.actionClickTreeItem(path, tree, 2);
} catch (abbot.finder.swt.WidgetNotFoundException e1) {
throw new IllegalStateException("Path: " + path + " not findable in tree " + UIProxy.getToString(tree));
} catch (abbot.finder.swt.MultipleWidgetsFoundException e1) {
throw new IllegalStateException("Path: " + path + " ambiguous in tree " + UIProxy.getToString(tree));
} catch(IllegalStateException e2) {
LogHandler.log(e2);
}
}
return clicked;
}
/**
* @throws WidgetNotFoundException
* @throws MultipleWidgetsFoundException
* @see com.windowtester.event.swt.ISWTWidgetSelectorDelegate#contextClick(org.eclipse.swt.widgets.Widget, java.lang.String, java.lang.String)
*/
// public Widget contextClick(Widget w, String itemPath, String menuPath) throws WidgetNotFoundException, MultipleWidgetsFoundException {
// Tree tree = (Tree)w;
// Widget clicked = null;
// if (itemPath == null || itemPath.length() == 0)
// clicked = tree;
// else
// {
// try {
// //find item
// TreeItem item = find(tree, itemPath);
// //reveal item
// _treeTester.showItem(tree, item);
// //it make sense to dispatch system events at this point
// waitForIdle(tree.getDisplay());
// clicked = item;
// } catch(IllegalStateException e) {
// //in this case, fall back on abbot:
// try {
// clicked = _treeItemTester.getTreeItemByPath(itemPath, tree);
// } catch (abbot.finder.swt.WidgetNotFoundException e1) {
// //close menu in case of failure
// handleMenuClose();
// //throw new WidgetNotFoundException("Tree Item: " + itemPath + " not findable in tree " + UIProxy.getToString(tree));
// clicked = tree;
// } catch (abbot.finder.swt.MultipleWidgetsFoundException e1) {
// //close menu in case of failure
// handleMenuClose();
// throw new MultipleWidgetsFoundException("Tree Item: " + itemPath + " ambiguous in tree " + UIProxy.getToString(tree));
// } catch(IllegalStateException e2) {
// LogHandler.log(e2);
// }
// }
// }
// return contextClick(clicked, menuPath);
// }
/**
* @see com.windowtester.event.swt.ISWTWidgetSelectorDelegate#selectAll(org.eclipse.swt.widgets.Widget)
*/
public void selectAll(final Widget w) {
w.getDisplay().syncExec(new Runnable() {
public void run() {
((Tree)w).selectAll();
}
});
}
/**
* Find the Tree Item described by this path String.
* @param tree - the containing tree
* @param path - the path describing the item in question
* @return the found Tree Item
*/
private TreeItem find(Tree tree, String path) {
//Fixing to handle escaped '\'s
//String[] nodeLabels = path.split(DELIM);
String[] nodeLabels = PathStringTokenizerUtil.tokenize(path);
TreeItem[] items;
TreeItem node = null, current = null;
items = _treeTester.getItems(tree);
//for each node label
for (int i = 0; i < nodeLabels.length; ++i) {
String nodeLabel = nodeLabels[i];
node = null;
//find the appropriate item
for (int j = 0; j < items.length && node == null; j++) {
current = items[j];
if (new TextMatcher(nodeLabel).matches(current)) {
node = current;
}
}
if (node == null)
throw new IllegalStateException("no matching node found"); //TODO: wrap this in a WidgetNotFoundException
//get its children
items = _treeItemTester.getItems(node);
}
return node;
}
////////////////////////////////////////////////////////////////////////////
//
// Wait condition helpers
//
////////////////////////////////////////////////////////////////////////////
/**
* A condition that waits for an expanded (true or false) condition.
*/
public class TreeItemExpandedCondition implements Condition {
private final TreeItem _treeNode;
private final boolean _isExpanded;
/**
* Create an instance.
* @param treeNode - the node to wait on
* @param isExpanded - whether the node should be expanded or not
*/
public TreeItemExpandedCondition(TreeItem treeNode, boolean isExpanded) {
_treeNode = treeNode;
_isExpanded = isExpanded;
}
/**
* @see abbot.script.Condition#test()
*/
public boolean test() {
return UIProxy.getExpanded(_treeNode) == _isExpanded;
}
}
public void showItemExt(final Tree t, final TreeItem item) {
if (t == null || item == null)
return;
Rectangle itemRect = _treeItemTester.getBounds(item);
setValueToScrollBar(_treeTester.getHorizontalBar(t), itemRect.x);
}
public void setValueToScrollBar(final ScrollBar bar, final int value)
{
bar.getDisplay().syncExec(new Runnable() {
public void run() {
bar.setSelection(value);
waitForIdle(bar.getDisplay());
}
});
}
}