// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.plugin.jfc.guimodel; import java.util.ArrayList; import java.util.List; import org.apache.commons.collections15.CollectionUtils; import org.apache.commons.lang.mutable.MutableInt; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec; /** *

* Implements the specification of {@link IGUIElement} for {@link JFCGUIElement}s. *

* * @version 1.0 * @author Patrick Harms */ public class JFCGUIElementSpec implements IGUIElementSpec { /** *

* Id for object serialization. *

*/ private static final long serialVersionUID = 1L; /** *

* Current name of the GUI element *

*/ private String name; /** *

* Previous names of the GUI element as it may have changed over time. *

*/ private List formerNames = new ArrayList(); /** *

* Type of the GUI element, i.e., its Java class. *

*/ private String type = null; /** *

* Icon associated with the GUI element. *

*/ private String icon = null; /** *

* Index of the GUI element in its parent element. *

*/ private int index = -1; /** *

* An alternative index of the specified GUI element in its parent element. Each element type is * counted separately. This index is used for replaying programs such as Jacareto. *

*/ private MutableInt altIndex = new MutableInt(-1); /** *

* Hash code of the GUI element. Used as unique identifier during its existence. *

*/ private int elementHash = -1; /** *

* Previous hashes of the GUI element as the GUI element may have been destroyed and recreated. *

*/ private List formerElementHashes = new ArrayList(); /** *

* Type hierarchy of the class itself *

*/ private List typeHierarchy = null; /* * (non-Javadoc) * * @see * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSecificationSimilarity(IGUIElementSpec * ) */ @Override public boolean getSimilarity(IGUIElementSpec other) { if (this == other) { return true; } if (!(other instanceof JFCGUIElementSpec)) { return false; } JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other; if (type == null ? otherSpec.type != null : !type.equals(otherSpec.type)) { return false; } if (icon == null ? otherSpec.icon != null : !icon.equals(otherSpec.icon)) { return false; } // up to now, we compared, if the basics match. Now lets compare the id, the name and the // index. All may change. The name may be reset (e.g. the title of a frame using the // asterisk in the case data was changed). The id may change if e.g. a dialog is closed // and reopend, i.e. a new instance is created. The index may change, if later in a panel // a new element is added or another one is removed. If the element hash or the name stay // the same, then similarity is given. Therefore these are the first two comparisons if (elementHash == otherSpec.elementHash) { return true; } if ((name != null) && (name.equals(otherSpec.name))) { return true; } if ((((name == null) && (otherSpec.name == null)) || (("".equals(name)) && ("" .equals(otherSpec.name)))) && (formerNames.size() == 0) && (otherSpec.formerNames.size() == 0)) { return true; } // if the id and the name did not stay the same, then the name should be checked first. // One of all known names of one of the specs must be equal to one of the known names of the // respective other spec for similarity. Furthermore, if this is given, the index should // have stayed the same. if ((otherSpec.name != null) && formerNames.contains(otherSpec.name)) { return index == otherSpec.index; } if ((name != null) && otherSpec.formerNames.contains(name)) { return index == otherSpec.index; } if (CollectionUtils.containsAny(formerNames, otherSpec.formerNames)) { return index == otherSpec.index; } // ok. Even the names do not match. This is usually a clear indication, that the elements // are distinct. However, we check, if the former ids matched. This is very unlikely // to happen. But it may occur, if a GUI element does not have a name or its name stays // the empty string and if this GUI element is created, destroyed, and created again. // Again we are restrictive and request the index to be equal as well. if (formerElementHashes.contains(otherSpec.elementHash)) { return index == otherSpec.index; } if (otherSpec.formerElementHashes.contains(elementHash)) { return index == otherSpec.index; } if (CollectionUtils.containsAny(formerElementHashes, otherSpec.formerElementHashes)) { return index == otherSpec.index; } // now we can be really sure, that the GUI elements differ return false; } /* * (non-Javadoc) * * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec) */ @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof JFCGUIElementSpec)) { return false; } JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other; return (name == null ? otherSpec.name == null : name.equals(otherSpec.name)) && (type == null ? otherSpec.type == null : type.equals(otherSpec.type)) && (icon == null ? otherSpec.icon == null : icon.equals(otherSpec.icon)) && (index == otherSpec.index) && (elementHash == otherSpec.elementHash); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (name + type + icon + index + elementHash).hashCode(); } /** *

* Returns the name of the specified GUI element. *

* * @return the name */ public String getName() { StringBuffer names = new StringBuffer(); if (name != null) { names.append('"'); names.append(name); names.append('"'); } else { names.append("NOT_SET"); } if (formerNames.size() > 0) { names.append(" (aka "); for (int i = 0; i < formerNames.size(); i++) { if (i > 0) { names.append("/"); } names.append('"'); names.append(formerNames.get(i)); names.append('"'); } names.append(")"); } return names.toString(); } /** *

* Returns the title of the specified GUI element. *

* * @return the title */ public String getType() { return type; } /** *

* Returns the icon associated with the specified GUI element. *

* * @return the icon */ public String getIcon() { return icon; } /** *

* Returns the index of the specified GUI element in its parent element. *

* * @return the index */ public int getIndex() { return index; } /** *

* Returns an alternative index of the specified GUI element in its parent element. Each element * type is counted separately. *

* * @return the index */ public int getAltIndex() { return altIndex.intValue(); } /** *

* Returns the object hash of the specified GUI element. *

* * @return the elementHash */ public int getElementHash() { return elementHash; } /** *

* Sets the alternative index. *

* * @param newAltIndex * the index */ public void setAltIndex(int newAltIndex) { altIndex.setValue(newAltIndex); } /** *

* Sets the name of the specified GUI element. *

* * @param newName * the name */ public void setName(String newName) { if ((this.name != null) && (!this.name.equals(newName)) && (!this.formerNames.contains(this.name))) { this.formerNames.add(this.name); } this.name = newName; } /** *

* Sets the type of the specified GUI element. *

* * @param type * the type */ public void setType(String type) { this.type = type; } /** *

* Sets the icon associated with the specified GUI element. *

* * @param icon * the icon */ public void setIcon(String icon) { this.icon = icon; } /** *

* Sets the index in its parent element of the specified GUI element. *

* * @param index * the index */ public void setIndex(int index) { this.index = index; } /** *

* Sets the object hash of the specified GUI element. *

* * @param newElementHash * the element hash */ public void setElementHash(int newElementHash) { if ((this.elementHash > -1) && !this.formerElementHashes.contains(this.elementHash)) { this.formerElementHashes.add(this.elementHash); } this.elementHash = newElementHash; } /** *

* Sets the type hierarchy of the specified GUI element. * * @param typeHierarchy *

*/ public void setTypeHierarchy(List typeHierarchy) { this.typeHierarchy = typeHierarchy; } /** *

* Updates the specification with another specification. *

* * @param furtherSpec * specification used to update the current specification */ void update(JFCGUIElementSpec other) { if (other != this) { for (int formerElementHash : other.formerElementHashes) { setElementHash(formerElementHash); } if (elementHash != other.elementHash) { elementHash = other.elementHash; } for (String formerName : other.formerNames) { setName(formerName); } if ((name == null) || (!name.equals(other.name))) { setName(other.name); } other.altIndex = this.altIndex; } } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { return "[" + getName() + ";\"" + type + "\";\"" + icon + "\";" + index + ";" + elementHash + "]"; } @Override public String[] getTypeHierarchy() { if (typeHierarchy == null) { return new String[] { (getType()) }; } else return typeHierarchy.toArray(new String[typeHierarchy.size()]); } }