package abbot.script.swt;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.eclipse.swt.widgets.Widget;
import abbot.script.NoSuchReferenceException;
import abbot.swt.Resolver;
import abbot.tester.swt.WidgetTester;
/** Provide select non-static method access in addition to standard Call
* capabilities. Specifically, allows specification of a WidgetReference
* to be used as the method invocation target. If a WidgetReference is
* given, then the class of the widget reference is used as the target
* class.<p>
* This isn't a great name (and since it's a meta-class, it's easily
* changeable) but right now I can't think of one.
*/
public abstract class PropertyCall extends Call {
public static final String copyright = "Licensed Materials -- Property of IBM\n"+
"(c) Copyright International Business Machines Corporation, 2003\nUS Government "+
"Users Restricted Rights - Use, duplication or disclosure restricted by GSA "+
"ADP Schedule Contract with IBM Corp.";
private String widgetID = null;
/** Create a PropertyCall based on loaded XML attributes. */
public PropertyCall(Resolver resolver, HashMap attributes) {
super(resolver, patchAttributes(resolver, attributes));
widgetID = (String)attributes.get(TAG_COMPONENT);
}
/** Create a PropertyCall based on a static invocation. */
public PropertyCall(Resolver resolver, String description,
String className, String methodName, String[] args) {
super(resolver, description, className, methodName, args);
widgetID = null;
}
/** Create a PropertyCall with a widget target. */
public PropertyCall(Resolver resolver, String description,
String methodName, String[] args, String id) {
super(resolver, description, getRefClass(resolver, id),
methodName, args);
widgetID = id;
}
/** Return the widget reference ID used by this method invocation. */
public String getWidgetID() {
return widgetID;
}
/** Set the widget reference ID used by method invocation. The class
* of the widget referenced by the widget reference will replace the
* current target class.
*/
public void setWidgetID(String id) {
if (id == null) {
widgetID = null;
}
else {
WidgetReference ref = getResolver().getWidgetReference(id);
if (ref != null) {
widgetID = id;
setTargetClassName(ref.getRefClassName());
}
else
throw new NoSuchReferenceException(id);
}
}
/** Save attributes specific to this Step class. */
public HashMap getAttributes() {
HashMap map = super.getAttributes();
if (widgetID != null) {
map.remove(TAG_CLASS);
map.put(TAG_COMPONENT, widgetID);
}
return map;
}
/** Return the target of the method invocation. */
protected Object getTarget() throws Throwable {
if (widgetID != null) {
return ArgumentParser.eval(getResolver(), widgetID,
Widget.class);
}
return super.getTarget();
}
/** Insert default values if necessary. */
private static HashMap patchAttributes(Resolver resolver, HashMap map) {
String id = (String)map.get(TAG_COMPONENT);
if (id != null) {
map.put(TAG_CLASS, getRefClass(resolver, id));
}
return map;
}
private final static String[] prefixes = { "is", "get", "has" };
private final static Class[] returnTypes = {
boolean.class, null, boolean.class
};
/** Is the given method a property accessor? In addition to standard
* is/get/has property accessors, this includes pseudo-property methods on
* WidgetTester objects.
*/
public static boolean isPropertyMethod(Method m) {
String name = m.getName();
Class rt = m.getReturnType();
Class[] params = m.getParameterTypes();
Class dc = m.getDeclaringClass();
for (int i=0;i < prefixes.length;i++) {
if (name.startsWith(prefixes[i])
&& name.length() > prefixes[i].length()
&& Character.isUpperCase(name.charAt(prefixes[i].length()))
&& ((WidgetTester.class.isAssignableFrom(dc)
&& params.length == 1
&& Widget.class.isAssignableFrom(params[0]))
|| (Widget.class.isAssignableFrom(dc)
&& params.length == 0))
&& (returnTypes[i] == null
|| returnTypes[i].equals(rt))) {
return true;
}
}
return false;
}
protected String getDefaultDescription() {
String desc = super.getDefaultDescription();
if (getWidgetID() != null) {
desc = getWidgetID() + "." + desc;
}
return desc;
}
/** Obtain the class of the given reference's widget, or return
* org.eclipse.swt.widgets.Widget if not found.
*/
private static String getRefClass(Resolver r, String id) {
WidgetReference ref = r.getWidgetReference(id);
return ref == null ? "org.eclipse.swt.widgets.Widget" : ref.getRefClassName();
}
}