/*******************************************************************************
* 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.swt;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.windowtester.internal.runtime.finder.FinderFactory;
import com.windowtester.runtime.IUIContext;
import com.windowtester.runtime.locator.IWidgetLocator;
import com.windowtester.runtime.locator.IWidgetMatcher;
import com.windowtester.runtime.swt.internal.selector.WidgetSelectorAdapterFactory;
/**
* A class that captures hierarchy (containment) relationships between widgets for use
* in widget identification.
* <p>
* For example, a widget identified by class and position relative to its
* parent composite could be described so:
* <pre>
* new WidgetLocator(Text.class, 2,
* new WidgetLocator(Group.class, "addressGroup"));
* </pre>
*
* Effectively, this WidgetLocator instance describes the third Text widget in
* the Group labeled "addressGroup".
*
* @deprecated Replaced by the {@link IWidgetLocator} class hierarchy
*/
public class WidgetLocator implements Serializable, com.windowtester.swt.IWidgetLocator, com.windowtester.runtime.locator.IWidgetLocator {
/*
* NOTE: this class is serializable and uses the default serialization scheme.
* This should _not_ be a problem (hierarchies are not too deep); still, we
* could consider a custom serialization scheme.
*/
private static final long serialVersionUID = 7772528976750829834L;
/** A sentinel value, indicating an unassigned index */
public static final int UNASSIGNED = -1;
/** The target class */
private final Class _cls;
/** The target widget's name or label */
private final String _nameOrLabel;
/** The target's index relative to its parent */
private int _index;
/** The target's parent info */
private WidgetLocator _parentInfo;
/** A map for associated data key-value pairs */
private HashMap _map;
/*
* Used to implement new API IWidgetLocator.
* Notice that it's transient since Matchers are not necessarly serializable.
*/
private transient IWidgetMatcher _matcher;
/**
* Create an instance.
* @param cls - the target class
* @param nameOrLabel - the target's name or label
* @param index - the target's index relative to its parent
* @param parentInfo - the target's parent info
*/
public WidgetLocator(Class cls, String nameOrLabel, int index, WidgetLocator parentInfo) {
_cls = cls;
_nameOrLabel = nameOrLabel;
_index = index;
_parentInfo = parentInfo;
}
/**
* Create an instance.
* @param cls - the target class
* @param index - the target's index relative to its parent
* @param parentInfo - the target's parent info
*/
public WidgetLocator(Class cls, int index, WidgetLocator parentInfo) {
this(cls, null, index, parentInfo);
}
/**
* Create an instance.
* @param cls - the target class
* @param nameOrLabel - the target's name or label
* @param parentInfo - the target's parent info
*/
public WidgetLocator(Class cls, String nameOrLabel, WidgetLocator parentInfo) {
this(cls, nameOrLabel, UNASSIGNED, parentInfo);
}
/**
* Create an instance.
* @param cls - the target class
* @param parentInfo - the target's parent info
*/
public WidgetLocator(Class cls, WidgetLocator parentInfo) {
this(cls, null, UNASSIGNED, parentInfo);
}
/**
* Create an instance.
* @param cls - the target class
*/
public WidgetLocator(Class cls) {
this(cls, (WidgetLocator)null);
}
/**
* Create an instance.
* @param cls - the target class
* @param nameOrLabel - the target's name or label
*/
public WidgetLocator(Class cls, String nameOrLabel) {
this(cls, nameOrLabel, null);
}
/**
* Create an instance.
* @param cls - the target class
* @param nameOrLabel - the target's name or label
* @param index - the target's index relative to its parent
*/
public WidgetLocator(Class cls, String nameOrLabel, int index) {
this(cls, nameOrLabel, index, null);
}
/**
* Create an instance.
* @param cls - the target class
* @param index - the target's index relative to its parent
*/
public WidgetLocator(Class cls, int index) {
this(cls, null, index, null);
}
// /**
// * Accept this visitor.
// * @param visitor
// */
// public void accept(IWidgetLocatorVisitor visitor) {
// visitor.visit(this);
// if (_parentInfo != null)
// _parentInfo.accept(visitor);
// }
/**
* Get the <code>WidgetLocator</code> that describes this widget's parent.
* @return the parent's <code>WidgetLocator</code> object.
*/
public WidgetLocator getParentInfo() {
return _parentInfo;
}
/**
* Get the name or label String that helps identify this widget.
* @return the subject's name or label
*/
public String getNameOrLabel() {
return _nameOrLabel;
}
/**
* Get the subject widget's class.
* @return the subject's class
*/
public Class getTargetClass() {
return _cls;
}
/**
* Set the parent <code>WidgetLocator</code>.
* @param parentInfo - the new parent <code>WidgetLocator</code>
*/
public void setParentInfo(WidgetLocator parentInfo) {
_parentInfo = parentInfo;
}
/**
* Get this widget's index relative to its parent widget.
* @return a 0-based relative index or UNASSIGNED if it is not indexed.
*/
public int getIndex() {
return _index;
}
/**
* Set this widget's index relative to it's parent.
* @param index - the index.
*/
public void setIndex(int index) {
_index = index;
}
/**
* Get a String representation of this <code>WidgetLocator</code>.
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("WidgetLocator(").append(_cls.getName());
if (_nameOrLabel != null)
sb.append(", ").append(_nameOrLabel);
if (_index != UNASSIGNED)
sb.append(", ").append(_index);
if (_parentInfo != null)
sb.append(", ").append(_parentInfo);
sb.append(")");
return sb.toString();
}
/**
* Indicates whether some other object is "equal to" this one.
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o) {
//null check
if (o == null)
return false;
//type check
if (!(o instanceof WidgetLocator))
return false;
//self check
if (o == this)
return true;
WidgetLocator other = (WidgetLocator)o;
//check class
if (!_cls.equals(other._cls))
return false;
//check name
if (_nameOrLabel == null) {
if (other._nameOrLabel != null)
return false;
} else {
if (!_nameOrLabel.equals(other._nameOrLabel))
return false;
}
//check index
if (_index != other._index)
return false;
//check parent
if (_parentInfo == null) {
if (other._parentInfo != null)
return false;
} else {
if (!_parentInfo.equals(other._parentInfo))
return false;
}
//check data map
if (_map == null) {
if (other._map != null && !other._map.isEmpty())
return false;
} else {
if (!_map.equals(other._map))
return false;
}
//fall through
return true;
}
/**
* Returns a hash code value for this <code>WidgetLocator</code> object.
* @see java.lang.Object#hashCode()
*/
public int hashCode() {
int result = 13;
result = 37*result + _index;
result = 37*result + ((_cls == null) ? 0 : + _cls.hashCode());
result = 37*result + ((_nameOrLabel == null) ? 0 : + _nameOrLabel.hashCode());
result = 37*result + ((_parentInfo == null) ? 0 : + _parentInfo.hashCode());
result += (_map == null) ? 0 : _map.hashCode();
return result;
}
/**
* Returns the programmer defined property of the receiver
* with the specified name, or null if it has not been set.
* <p>
* Data mappings allow programmers to associate arbitrary key-value
* pairs with locator instances.
* </p>
*
* @param key the name of the property
*
* @exception IllegalArgumentException if the key is <code>null</code>
*
*
*/
public void setData(String key, String value) {
/*
* NOTE: keys and values are NOT objects (as in widgets)
* this is because locators need to be serializable.
* An alternative is to have the be ISerializables...
* we could widen the interface if need be.
*/
if (key == null)
throw new IllegalArgumentException("key must not be null");
getDataMap().put(key, value);
}
/**
* Returns the pogrammer defined property of the receiver
* with the specified name, or null if it has not been set.
* <p>
* Data mappings allow programmers to associate arbitrary key-value
* pairs with locator instances.
* </p>
*
*
* @param key the name of the property
* @return the value of the property or null if it has not been set
*
* @exception IllegalArgumentException if the key is null
*/
public String getData (String key) {
if (key == null)
throw new IllegalArgumentException("key must not be null");
return (String) getDataMap().get(key);
}
private Map getDataMap() {
if (_map == null)
_map = new HashMap();
return _map;
}
///////////////////////////////////////////////////////////////////////////////////////////
//
// New API Compatability
//
///////////////////////////////////////////////////////////////////////////////////////////
/* (non-Javadoc)
* @see com.windowtester.runtime.locator.IWidgetLocator#findAll(com.windowtester.runtime.IUIContext)
*/
public IWidgetLocator[] findAll(IUIContext ui) {
IWidgetLocator[] locators = FinderFactory.getFinder(ui).findAll(this);
//add UISelector behavior
for (int i = 0; i < locators.length; i++) {
locators[i] = WidgetSelectorAdapterFactory.create(locators[i]);
}
return locators;
}
/* (non-Javadoc)
* @see com.windowtester.runtime2.locator.IWidgetMatcher#matches(java.lang.Object)
*/
public boolean matches(Object widget) {
//in the process of refactoring out -- will fail if called at runtime
// if (_matcher == null)
// _matcher = new AdapterFactory().adapt(WidgetLocatorService.getMatcher(this));
return _matcher.matches(widget);
}
public String getTargetClassName() {
return _cls.getName();
}
}