source: trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElementSpec.java

Last change on this file was 2146, checked in by pharms, 7 years ago
  • refactored GUI model so that hierarchical event target structures can also be used and created by plugins not being strictly for GUIs
File size: 12.2 KB
RevLine 
[927]1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
[835]14
[922]15package de.ugoe.cs.autoquest.plugin.jfc.guimodel;
[573]16
[714]17import java.util.ArrayList;
[589]18import java.util.List;
19
20import org.apache.commons.collections15.CollectionUtils;
[1904]21import org.apache.commons.lang.mutable.MutableInt;
[589]22
[2146]23import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
[922]24import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
25import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
[573]26
27/**
28 * <p>
[835]29 * Implements the specification of {@link IGUIElement} for {@link JFCGUIElement}s.
[573]30 * </p>
31 *
[835]32 * @version 1.0
33 * @author Patrick Harms
[573]34 */
35public class JFCGUIElementSpec implements IGUIElementSpec {
36
[835]37    /**
38     * <p>
39     * Id for object serialization.
40     * </p>
41     */
[778]42    private static final long serialVersionUID = 1L;
43
[714]44    /**
45     * <p>
[835]46     * Current name of the GUI element
[714]47     * </p>
48     */
49    private String name;
50
51    /**
52     * <p>
[835]53     * Previous names of the GUI element as it may have changed over time.
[714]54     * </p>
55     */
56    private List<String> formerNames = new ArrayList<String>();
57
[835]58    /**
59     * <p>
60     * Type of the GUI element, i.e., its Java class.
61     * </p>
62     */
[588]63    private String type = null;
[835]64
65    /**
66     * <p>
67     * Icon associated with the GUI element.
68     * </p>
69     */
[588]70    private String icon = null;
[835]71
72    /**
73     * <p>
74     * Index of the GUI element in its parent element.
75     * </p>
76     */
[588]77    private int index = -1;
[835]78
[714]79    /**
80     * <p>
[1722]81     * An alternative index of the specified GUI element in its parent element. Each element type is
82     * counted separately. This index is used for replaying programs such as Jacareto.
83     * </p>
[1904]84     */   
85    private MutableInt altIndex = new MutableInt(-1);
[1722]86
87    /**
88     * <p>
[1009]89     * Hash code of the GUI element. Used as unique identifier during its existence.
[714]90     * </p>
91     */
[743]92    private int elementHash = -1;
[714]93
94    /**
95     * <p>
[1009]96     * Previous hashes of the GUI element as the GUI element may have been destroyed and recreated.
[714]97     * </p>
98     */
[743]99    private List<Integer> formerElementHashes = new ArrayList<Integer>();
[1722]100
[984]101    /**
102     * <p>
[990]103     * Type hierarchy of the class itself
[984]104     * </p>
105     */
[990]106    private List<String> typeHierarchy = null;
[714]107
[835]108    /*
109     * (non-Javadoc)
110     *
111     * @see
[922]112     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSecificationSimilarity(IGUIElementSpec
[835]113     * )
[573]114     */
115    @Override
[2146]116    public boolean getSimilarity(IEventTargetSpec other) {
[835]117        if (this == other) {
[589]118            return true;
[573]119        }
[835]120
121        if (!(other instanceof JFCGUIElementSpec)) {
[589]122            return false;
[573]123        }
[835]124
[573]125        JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other;
[835]126
[1080]127        if (type == null ? otherSpec.type != null : !type.equals(otherSpec.type)) {
[714]128            return false;
129        }
130
[1080]131        if (icon == null ? otherSpec.icon != null : !icon.equals(otherSpec.icon)) {
[714]132            return false;
133        }
134
135        // up to now, we compared, if the basics match. Now lets compare the id, the name and the
136        // index. All may change. The name may be reset (e.g. the title of a frame using the
137        // asterisk in the case data was changed). The id may change if e.g. a dialog is closed
138        // and reopend, i.e. a new instance is created. The index may change, if later in a panel
139        // a new element is added or another one is removed. If the element hash or the name stay
140        // the same, then similarity is given. Therefore these are the first two comparisons
[835]141
[743]142        if (elementHash == otherSpec.elementHash) {
[714]143            return true;
144        }
[835]145
[714]146        if ((name != null) && (name.equals(otherSpec.name))) {
147            return true;
[573]148        }
[835]149
150        if ((((name == null) && (otherSpec.name == null)) || (("".equals(name)) && (""
151            .equals(otherSpec.name)))) &&
152            (formerNames.size() == 0) &&
153            (otherSpec.formerNames.size() == 0))
[714]154        {
155            return true;
[600]156        }
[835]157
[714]158        // if the id and the name did not stay the same, then the name should be checked first.
159        // One of all known names of one of the specs must be equal to one of the known names of the
160        // respective other spec for similarity. Furthermore, if this is given, the index should
161        // have stayed the same.
162
163        if ((otherSpec.name != null) && formerNames.contains(otherSpec.name)) {
164            return index == otherSpec.index;
165        }
166
167        if ((name != null) && otherSpec.formerNames.contains(name)) {
168            return index == otherSpec.index;
169        }
[835]170
[714]171        if (CollectionUtils.containsAny(formerNames, otherSpec.formerNames)) {
172            return index == otherSpec.index;
173        }
[835]174
[714]175        // ok. Even the names do not match. This is usually a clear indication, that the elements
176        // are distinct. However, we check, if the former ids matched. This is very unlikely
177        // to happen. But it may occur, if a GUI element does not have a name or its name stays
178        // the empty string and if this GUI element is created, destroyed, and created again.
179        // Again we are restrictive and request the index to be equal as well.
180
181        if (formerElementHashes.contains(otherSpec.elementHash)) {
182            return index == otherSpec.index;
183        }
184
185        if (otherSpec.formerElementHashes.contains(elementHash)) {
186            return index == otherSpec.index;
187        }
[835]188
[714]189        if (CollectionUtils.containsAny(formerElementHashes, otherSpec.formerElementHashes)) {
190            return index == otherSpec.index;
191        }
[835]192
[714]193        // now we can be really sure, that the GUI elements differ
[835]194
[714]195        return false;
[573]196    }
197
[835]198    /*
199     * (non-Javadoc)
200     *
[922]201     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec)
[573]202     */
203    @Override
[832]204    public boolean equals(Object other) {
[835]205        if (this == other) {
[573]206            return true;
207        }
[835]208
209        if (!(other instanceof JFCGUIElementSpec)) {
[573]210            return false;
211        }
[835]212
[573]213        JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other;
[835]214
[1722]215        return (name == null ? otherSpec.name == null : name.equals(otherSpec.name)) &&
[1080]216            (type == null ? otherSpec.type == null : type.equals(otherSpec.type)) &&
217            (icon == null ? otherSpec.icon == null : icon.equals(otherSpec.icon)) &&
[743]218            (index == otherSpec.index) && (elementHash == otherSpec.elementHash);
[573]219    }
220
[835]221    /*
222     * (non-Javadoc)
223     *
[600]224     * @see java.lang.Object#hashCode()
225     */
226    @Override
227    public int hashCode() {
228        return (name + type + icon + index + elementHash).hashCode();
229    }
230
[573]231    /**
[835]232     * <p>
233     * Returns the name of the specified GUI element.
234     * </p>
235     *
[573]236     * @return the name
237     */
238    public String getName() {
[714]239        StringBuffer names = new StringBuffer();
[835]240
[714]241        if (name != null) {
242            names.append('"');
243            names.append(name);
244            names.append('"');
[589]245        }
[714]246        else {
247            names.append("NOT_SET");
248        }
[835]249
[714]250        if (formerNames.size() > 0) {
[835]251
[714]252            names.append(" (aka ");
[835]253
[714]254            for (int i = 0; i < formerNames.size(); i++) {
255                if (i > 0) {
256                    names.append("/");
257                }
258
259                names.append('"');
260                names.append(formerNames.get(i));
261                names.append('"');
262            }
[835]263
[714]264            names.append(")");
265        }
[835]266
[714]267        return names.toString();
[573]268    }
269
270    /**
[835]271     * <p>
272     * Returns the title of the specified GUI element.
273     * </p>
274     *
[573]275     * @return the title
276     */
277    public String getType() {
278        return type;
279    }
280
281    /**
[835]282     * <p>
283     * Returns the icon associated with the specified GUI element.
284     * </p>
285     *
[573]286     * @return the icon
287     */
288    public String getIcon() {
289        return icon;
290    }
291
292    /**
[835]293     * <p>
294     * Returns the index of the specified GUI element in its parent element.
295     * </p>
296     *
[573]297     * @return the index
298     */
299    public int getIndex() {
300        return index;
301    }
302
303    /**
[835]304     * <p>
[1722]305     * Returns an alternative index of the specified GUI element in its parent element. Each element
306     * type is counted separately.
307     * </p>
308     *
309     * @return the index
310     */
311    public int getAltIndex() {
[1904]312        return altIndex.intValue();
[1722]313    }
314
315    /**
316     * <p>
[835]317     * Returns the object hash of the specified GUI element.
318     * </p>
319     *
[573]320     * @return the elementHash
321     */
[743]322    public int getElementHash() {
[714]323        return elementHash;
[573]324    }
325
326    /**
[835]327     * <p>
[1722]328     * Sets the alternative index.
329     * </p>
330     *
331     * @param newAltIndex
332     *            the index
333     */
334    public void setAltIndex(int newAltIndex) {
[1904]335        altIndex.setValue(newAltIndex);
[1722]336    }
337
338    /**
339     * <p>
[835]340     * Sets the name of the specified GUI element.
341     * </p>
342     *
[849]343     * @param newName
[835]344     *            the name
[573]345     */
[714]346    public void setName(String newName) {
[835]347        if ((this.name != null) && (!this.name.equals(newName)) &&
[714]348            (!this.formerNames.contains(this.name)))
349        {
350            this.formerNames.add(this.name);
[589]351        }
[835]352
[714]353        this.name = newName;
[573]354    }
355
356    /**
[835]357     * <p>
358     * Sets the type of the specified GUI element.
359     * </p>
360     *
[849]361     * @param type
362     *            the type
[573]363     */
364    public void setType(String type) {
365        this.type = type;
366    }
367
368    /**
[835]369     * <p>
370     * Sets the icon associated with the specified GUI element.
371     * </p>
372     *
373     * @param icon
374     *            the icon
[573]375     */
376    public void setIcon(String icon) {
377        this.icon = icon;
378    }
379
380    /**
[835]381     * <p>
382     * Sets the index in its parent element of the specified GUI element.
383     * </p>
384     *
385     * @param index
386     *            the index
[573]387     */
388    public void setIndex(int index) {
389        this.index = index;
390    }
391
392    /**
[835]393     * <p>
394     * Sets the object hash of the specified GUI element.
395     * </p>
396     *
[849]397     * @param newElementHash
398     *            the element hash
[573]399     */
[743]400    public void setElementHash(int newElementHash) {
[835]401        if ((this.elementHash > -1) && !this.formerElementHashes.contains(this.elementHash)) {
[714]402            this.formerElementHashes.add(this.elementHash);
[589]403        }
[835]404
[714]405        this.elementHash = newElementHash;
[573]406    }
[1722]407
[984]408    /**
409     * <p>
[990]410     * Sets the type hierarchy of the specified GUI element.
[1722]411     *
[990]412     * @param typeHierarchy
[1722]413     *            </p>
[984]414     */
[1722]415    public void setTypeHierarchy(List<String> typeHierarchy) {
416        this.typeHierarchy = typeHierarchy;
[984]417    }
[835]418
[714]419    /**
420     * <p>
[835]421     * Updates the specification with another specification.
[714]422     * </p>
[835]423     *
[714]424     * @param furtherSpec
[835]425     *            specification used to update the current specification
[714]426     */
427    void update(JFCGUIElementSpec other) {
428        if (other != this) {
[743]429            for (int formerElementHash : other.formerElementHashes) {
[714]430                setElementHash(formerElementHash);
431            }
432
433            if (elementHash != other.elementHash) {
434                elementHash = other.elementHash;
435            }
436
437            for (String formerName : other.formerNames) {
438                setName(formerName);
439            }
440
[1080]441            if ((name == null) || (!name.equals(other.name))) {
[714]442                setName(other.name);
443            }
[1904]444            other.altIndex = this.altIndex;
[714]445        }
446    }
447
[835]448    /*
449     * (non-Javadoc)
450     *
451     * @see java.lang.Object#toString()
452     */
[607]453    public String toString() {
[835]454        return "[" + getName() + ";\"" + type + "\";\"" + icon + "\";" + index + ";" + elementHash +
455            "]";
[607]456    }
[573]457
[966]458    @Override
[990]459    public String[] getTypeHierarchy() {
[1722]460        if (typeHierarchy == null) {
461            return new String[]
462                { (getType()) };
463        }
464        else
465            return typeHierarchy.toArray(new String[typeHierarchy.size()]);
[966]466    }
467
[573]468}
Note: See TracBrowser for help on using the repository browser.