/*******************************************************************************
* 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.matchers;
import java.util.ArrayList;
import java.util.List;
import com.windowtester.runtime.swt.internal.widgets.ISWTWidgetMatcher;
import com.windowtester.runtime.swt.internal.widgets.ISWTWidgetReference;
/**
* Matches direct children. For containment tests, see {@link ComponentOfMatcher} or {@link ContainedInMatcher}.
*/
public class ChildOfMatcher extends WidgetMatcher {
public static final int UNSPECIFIED_INDEX = -1;
private final ISWTWidgetMatcher targetMatcher;
private final int index;
private final ISWTWidgetMatcher parentMatcher;
public ChildOfMatcher(ISWTWidgetMatcher target, ISWTWidgetMatcher parent) {
this(target, UNSPECIFIED_INDEX, parent);
}
public ChildOfMatcher(ISWTWidgetMatcher target, int index, ISWTWidgetMatcher parent) {
this.index = index;
this.targetMatcher = target;
this.parentMatcher = parent;
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.widgets.ISWTWidgetMatcher#matches(com.windowtester.runtime.swt.widgets.ISWTWidgetReference)
*/
public boolean matches(ISWTWidgetReference<?> widget) {
//is this log-worthy?
if (widget == null)
return false;
/*
* various fast-fail optimizations
*/
//check target matcher
if (!targetMatcher.matches(widget))
return false; //fast fail
//if target matches, turn to parent
//first, short-circuit if there is no parent matcher
// if (parentMatcher == null)
// return true;
//next, check parent matcher
// WidgetLocatorService infoService = new WidgetLocatorService();
// Widget parent = infoService.getParent(widget);
ISWTWidgetReference<?>parent = widget.getParent();
if (parent == null)
return false; //if there is no parent, but there is a matcher, return false
if (!parentMatcher.matches(parent))
return false; //fail if parent does not match
//lastly, check index
//return testIndex(widget, infoService, parent);
return testIndex(widget, parent);
}
// private boolean testIndex(Widget widget, WidgetLocatorService infoService, Widget parent) {
// //NOTE: some matchers override the infoService indexer...
// if (_parentMatcher instanceof IComponentIndexer) {
// //in case no index is assigned, any index match will do
// //this handles the case where a user wants ALL children of a widget
//
// //TODO: this logic might apply to the general case as well...
// if (_index == DEFAULT_INDEX)
// return true;
// return ((IComponentIndexer)_parentMatcher).getIndex(widget, _matcher) == _index;
// }
// // check if there is an index , only then do a match
// if (_index == DEFAULT_INDEX)
// return true;
// return infoService.getIndex(widget, parent) == _index;
// }
private boolean testIndex(ISWTWidgetReference<?> widget,
ISWTWidgetReference<?> parent) {
// check if there is an index , only then do a match
if (index == UNSPECIFIED_INDEX)
return true;
return getIndex(widget, parent) == index;
}
private int getIndex(ISWTWidgetReference<?> widget, ISWTWidgetReference<?> parent) {
ISWTWidgetReference<?>[] children = parent.getChildren();
int index = -1; //the index of our target widget
//only child case...
if (children.length == 1)
return index;
List<ISWTWidgetReference<?>> matchedChildren = pruneMatches(children);
for (ISWTWidgetReference<?> match : matchedChildren) {
++index;
Object w = match.getWidget();
if (w == widget.getWidget())
return index;
}
return -1;
}
private List<ISWTWidgetReference<?>> pruneMatches(
ISWTWidgetReference<?>[] children) {
List<ISWTWidgetReference<?>> matches = new ArrayList<ISWTWidgetReference<?>>();
for (int i = 0; i < children.length; i++) {
ISWTWidgetReference<?> child = children[i];
if (targetMatcher.matches(child))
matches.add(child);
}
return matches;
}
@Override
public String toString() {
return targetMatcher + " in " + parentMatcher;
}
}