package abbot.script.swt; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Widget; import abbot.Log; import abbot.finder.swt.BasicFinder; import abbot.finder.swt.MultipleWidgetsFoundException; import abbot.finder.swt.WidgetFinder; import abbot.finder.swt.WidgetNotFoundException; import abbot.script.XMLConstants; import abbot.swt.SimpleResolver; import abbot.tester.swt.WidgetTester; /** * This class contains a subset of the functionality of * <code>abbot.script.ComponentReference</code>, omitting code that * is related to scripting/XML. */ public class WidgetReference implements XMLConstants /*, XMLifiable */{ // private static final String CR_USAGE = // "<widget id=\"<id>\" class=\"...\" .../>"; // // private SimpleResolver resolver; private WidgetFinder finder; // unique id for this reference private String id = null; // widget text, if any private String text = null; // widget name, if any private String name = null; // widget class name private String refClassName = null; // parent's ref id private String parentID = null; private WidgetReference parentReference = null; // index among parent's children private int index = -1; // parent window ref id private String windowID = null; private WidgetReference windowReference = null; // parent window title private String title = null; // tag specific to this widget private String tag = null; // for popup menus only, the invoking widget private String invokerID = null; private WidgetReference invokerReference = null; // for popup menus only, the location of invocation private Point point = new Point(-1,-1); /** For general widget lookup by class name. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) */ public WidgetReference(String id, Class widgetClass) { this(id, widgetClass, null, null, null, null, -1, null, null); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null */ public WidgetReference(String id, Class widgetClass, String name){ this(id, widgetClass, name, null, null, null, -1, null, null); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null * @param tag Tag as returned by WidgetTester.getTag(Widget) */ public WidgetReference(String id, Class widgetClass, String name, String tag) { this(id, widgetClass, name, tag, null, null, -1, null, null); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null * @param tag Tag as returned by WidgetTester.getTag(Widget) * @param title Owning Frame/Dialog title, or null */ public WidgetReference(String id, Class widgetClass, String name, String tag, String title) { this(id, widgetClass, name, tag, title, null, -1, null, null); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null * @param tag Tag as returned by WidgetTester.getTag(Widget) * @param title Owning Frame/Dialog title, or null * @param text The text of the widget as returned by widget.getText(), or null */ public WidgetReference(String id, Class widgetClass, String name, String tag, String title, String text){ this(id, widgetClass, name, tag, title, null, -1, null, text); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null * @param tag Tag as returned by WidgetTester.getTag(Widget) * @param title Owning Frame/Dialog title, or null * @param parent Reference to parent, or null * @param index Index within parent, or -1 */ public WidgetReference(String id, Class widgetClass, String name, String tag, String title, WidgetReference parent, int index) { this(id, widgetClass, name, tag, title, parent, index, null, null); } /** For general widget lookup. * @param id Desired ID for the reference. Only used if this reference is * to be passed as the parent, window, or invoker of another. * @param widgetClass Class of the widget (required) * @param name Name of the widget, or null * @param tag Tag as returned by WidgetTester.getTag(Widget) * @param title Owning Frame/Dialog title, or null * @param parent Reference to parent, or null * @param index Index within parent, or -1 * @param invokerOrWindow Window reference, invoker, or null * @param text widget's text */ public WidgetReference(String id, Class widgetClass, String name, String tag, String title, WidgetReference parent, int index, WidgetReference invokerOrWindow, String text) { // hack, kinda //resolver = parent != null ? parent.resolver : new Script(); this.id = id; this.refClassName = widgetClass.getName(); this.name = name; this.tag = tag; this.parentID = parent != null ? parent.getID() : null; this.index = index; this.text = text; //if (JPopupMenu.class.isAssignableFrom(widgetClass)) { // invokerID = invokerOrWindow != null // ? invokerOrWindow.getID() : null; //} //else { windowID = invokerOrWindow != null ? invokerOrWindow.getID() : null; //} this.title = title; } /** * Creates a WidgetReference object for the given Widget */ public WidgetReference(SimpleResolver resolver, Widget widget){ // this.resolver = resolver; this.finder = BasicFinder.getDefault(); //DefaultWidgetFinder.getFinder(); WidgetTester wt = new WidgetTester(); // TODO: fix this Class refClass = widget.getClass(); Widget parent = ((BasicFinder)finder).getWidgetParent(widget); // Widget win = null; refClass = WidgetTester.getCanonicalClass(refClass); refClassName = refClass.getName(); name = (String)wt.getData(widget, "name"); //finder.getWidgetName(widget); tag = WidgetTester.getTag(widget); // FIXME need to add this functionality // if (null != parent) { // Widget[] children = finder.getWidgetChildren(parent,false); // for (int i = 0; i < children.length; ++i) { // if (children[i] == widget) { // index = i; // break; // } // } // //if (tag == null) { // WidgetReference ref = resolver.addWidget(parent); // parentID = ref.getID(); // parentReference = ref; // //} // } // title = finder.getWidgetDecorationsTitle(widget); text = wt.getWidgetText(widget); // If no title is available, save the parent window id instead // if (title == null) { // win = finder.getWidgetDecorations(widget); // if (win != null && !(widget instanceof Decorations)) { // WidgetReference wref = resolver.addWidget(win); // this.windowID = wref != null ? wref.id : null; // this.windowReference = wref; // } // } try { // FIXME if the component has just become not visible, this lookup // will fail! Need a lookup flag for visible components? WidgetTester.findWidget(this); } catch (MultipleWidgetsFoundException e) { // More than one match found, so add more information if (parent != null && parentID == null) { WidgetReference ref = resolver.addWidget(parent); parentID = ref.getID(); parentReference = ref; // Try the lookup again to make sure it works this time try { WidgetTester.findWidget(this); } catch(Exception exc) { Log.warn(exc); exc.printStackTrace(); throw new Error("Reverse lookup failed for " + toString() + " trying to match " + /*WidgetTester.toString(*/widget); } } } catch (WidgetNotFoundException cnf) { // This indicates a failure in the reference recording mechanism, // and requires a fix. throw new Error("Reverse lookup failed for " + toString() + " trying to match " + /*ComponentTester.toString(*/widget); } // Finally, get a unique ID for this reference id = resolver.getUniqueID(this); Log.debug("Unique ID is " + id); } /** Unique identifier for this widget. */ public String getID() { return id; } /** This widget's name, null if no name was set. */ public String getName() { return name; } /** This widget's class name. */ public String getRefClassName() { return refClassName; } /** Return whether this reference has the same class or is a superclass of * the given widget's class. Simply compare class names to avoid class * loader conflicts. Note that this does not take into account interfaces * (which is okay, since with GUI widgets we're only concerned with * class inheritance). */ public boolean isAssignableFrom(Class cls) { return cls != null && (refClassName.equals(cls.getName()) || isAssignableFrom(cls.getSuperclass())); } /** Reference ID of this widget's parent (optional). */ public String getParentID() { return parentID; } public WidgetReference getParentReference() { //if (parentID != null && parentReference == null) { // parentReference = resolver.getWidgetReference(parentID); //} return parentReference; } /** Index among parent's children (optional). */ public int getIndex() { return index; } /** Reference ID of this widget's parent window (optional). */ public String getWindowID() { return windowID; } public WidgetReference getWindowReference() { //if (windowID != null && windowReference == null) { // windowReference = resolver.getWidgetReference(windowID); //} return windowReference; } /** Title string of this widget's parent frame (optional). */ public String getTitle() { return title; } /** Text of this widget */ public String getText() { return text; } /** Invoker of a JPopupMenu. */ public String getInvokerID() { return invokerID; } public WidgetReference getInvokerReference() { //if (invokerID != null && invokerReference == null) { // invokerReference = resolver.getWidgetReference(invokerID); //} return invokerReference; } public Point getInvocationLocation() { return point; } /** Returns a widget class-specific tag used to match this reference to a real widget. */ public String getTag() { return tag; } public String toString() { String str = id != null ? id : (refClassName + " (no id yet)"); if (str.indexOf("Instance") == -1) str += " (" + refClassName + ")"; return str; } }