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

Last change on this file since 2146 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
Line 
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.
14
15package de.ugoe.cs.autoquest.plugin.jfc.guimodel;
16
17import java.util.ArrayList;
18import java.util.List;
19
20import org.apache.commons.collections15.CollectionUtils;
21import org.apache.commons.lang.mutable.MutableInt;
22
23import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
24import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
25import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
26
27/**
28 * <p>
29 * Implements the specification of {@link IGUIElement} for {@link JFCGUIElement}s.
30 * </p>
31 *
32 * @version 1.0
33 * @author Patrick Harms
34 */
35public class JFCGUIElementSpec implements IGUIElementSpec {
36
37    /**
38     * <p>
39     * Id for object serialization.
40     * </p>
41     */
42    private static final long serialVersionUID = 1L;
43
44    /**
45     * <p>
46     * Current name of the GUI element
47     * </p>
48     */
49    private String name;
50
51    /**
52     * <p>
53     * Previous names of the GUI element as it may have changed over time.
54     * </p>
55     */
56    private List<String> formerNames = new ArrayList<String>();
57
58    /**
59     * <p>
60     * Type of the GUI element, i.e., its Java class.
61     * </p>
62     */
63    private String type = null;
64
65    /**
66     * <p>
67     * Icon associated with the GUI element.
68     * </p>
69     */
70    private String icon = null;
71
72    /**
73     * <p>
74     * Index of the GUI element in its parent element.
75     * </p>
76     */
77    private int index = -1;
78
79    /**
80     * <p>
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>
84     */   
85    private MutableInt altIndex = new MutableInt(-1);
86
87    /**
88     * <p>
89     * Hash code of the GUI element. Used as unique identifier during its existence.
90     * </p>
91     */
92    private int elementHash = -1;
93
94    /**
95     * <p>
96     * Previous hashes of the GUI element as the GUI element may have been destroyed and recreated.
97     * </p>
98     */
99    private List<Integer> formerElementHashes = new ArrayList<Integer>();
100
101    /**
102     * <p>
103     * Type hierarchy of the class itself
104     * </p>
105     */
106    private List<String> typeHierarchy = null;
107
108    /*
109     * (non-Javadoc)
110     *
111     * @see
112     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSecificationSimilarity(IGUIElementSpec
113     * )
114     */
115    @Override
116    public boolean getSimilarity(IEventTargetSpec other) {
117        if (this == other) {
118            return true;
119        }
120
121        if (!(other instanceof JFCGUIElementSpec)) {
122            return false;
123        }
124
125        JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other;
126
127        if (type == null ? otherSpec.type != null : !type.equals(otherSpec.type)) {
128            return false;
129        }
130
131        if (icon == null ? otherSpec.icon != null : !icon.equals(otherSpec.icon)) {
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
141
142        if (elementHash == otherSpec.elementHash) {
143            return true;
144        }
145
146        if ((name != null) && (name.equals(otherSpec.name))) {
147            return true;
148        }
149
150        if ((((name == null) && (otherSpec.name == null)) || (("".equals(name)) && (""
151            .equals(otherSpec.name)))) &&
152            (formerNames.size() == 0) &&
153            (otherSpec.formerNames.size() == 0))
154        {
155            return true;
156        }
157
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        }
170
171        if (CollectionUtils.containsAny(formerNames, otherSpec.formerNames)) {
172            return index == otherSpec.index;
173        }
174
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        }
188
189        if (CollectionUtils.containsAny(formerElementHashes, otherSpec.formerElementHashes)) {
190            return index == otherSpec.index;
191        }
192
193        // now we can be really sure, that the GUI elements differ
194
195        return false;
196    }
197
198    /*
199     * (non-Javadoc)
200     *
201     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#equals(IGUIElementSpec)
202     */
203    @Override
204    public boolean equals(Object other) {
205        if (this == other) {
206            return true;
207        }
208
209        if (!(other instanceof JFCGUIElementSpec)) {
210            return false;
211        }
212
213        JFCGUIElementSpec otherSpec = (JFCGUIElementSpec) other;
214
215        return (name == null ? otherSpec.name == null : name.equals(otherSpec.name)) &&
216            (type == null ? otherSpec.type == null : type.equals(otherSpec.type)) &&
217            (icon == null ? otherSpec.icon == null : icon.equals(otherSpec.icon)) &&
218            (index == otherSpec.index) && (elementHash == otherSpec.elementHash);
219    }
220
221    /*
222     * (non-Javadoc)
223     *
224     * @see java.lang.Object#hashCode()
225     */
226    @Override
227    public int hashCode() {
228        return (name + type + icon + index + elementHash).hashCode();
229    }
230
231    /**
232     * <p>
233     * Returns the name of the specified GUI element.
234     * </p>
235     *
236     * @return the name
237     */
238    public String getName() {
239        StringBuffer names = new StringBuffer();
240
241        if (name != null) {
242            names.append('"');
243            names.append(name);
244            names.append('"');
245        }
246        else {
247            names.append("NOT_SET");
248        }
249
250        if (formerNames.size() > 0) {
251
252            names.append(" (aka ");
253
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            }
263
264            names.append(")");
265        }
266
267        return names.toString();
268    }
269
270    /**
271     * <p>
272     * Returns the title of the specified GUI element.
273     * </p>
274     *
275     * @return the title
276     */
277    public String getType() {
278        return type;
279    }
280
281    /**
282     * <p>
283     * Returns the icon associated with the specified GUI element.
284     * </p>
285     *
286     * @return the icon
287     */
288    public String getIcon() {
289        return icon;
290    }
291
292    /**
293     * <p>
294     * Returns the index of the specified GUI element in its parent element.
295     * </p>
296     *
297     * @return the index
298     */
299    public int getIndex() {
300        return index;
301    }
302
303    /**
304     * <p>
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() {
312        return altIndex.intValue();
313    }
314
315    /**
316     * <p>
317     * Returns the object hash of the specified GUI element.
318     * </p>
319     *
320     * @return the elementHash
321     */
322    public int getElementHash() {
323        return elementHash;
324    }
325
326    /**
327     * <p>
328     * Sets the alternative index.
329     * </p>
330     *
331     * @param newAltIndex
332     *            the index
333     */
334    public void setAltIndex(int newAltIndex) {
335        altIndex.setValue(newAltIndex);
336    }
337
338    /**
339     * <p>
340     * Sets the name of the specified GUI element.
341     * </p>
342     *
343     * @param newName
344     *            the name
345     */
346    public void setName(String newName) {
347        if ((this.name != null) && (!this.name.equals(newName)) &&
348            (!this.formerNames.contains(this.name)))
349        {
350            this.formerNames.add(this.name);
351        }
352
353        this.name = newName;
354    }
355
356    /**
357     * <p>
358     * Sets the type of the specified GUI element.
359     * </p>
360     *
361     * @param type
362     *            the type
363     */
364    public void setType(String type) {
365        this.type = type;
366    }
367
368    /**
369     * <p>
370     * Sets the icon associated with the specified GUI element.
371     * </p>
372     *
373     * @param icon
374     *            the icon
375     */
376    public void setIcon(String icon) {
377        this.icon = icon;
378    }
379
380    /**
381     * <p>
382     * Sets the index in its parent element of the specified GUI element.
383     * </p>
384     *
385     * @param index
386     *            the index
387     */
388    public void setIndex(int index) {
389        this.index = index;
390    }
391
392    /**
393     * <p>
394     * Sets the object hash of the specified GUI element.
395     * </p>
396     *
397     * @param newElementHash
398     *            the element hash
399     */
400    public void setElementHash(int newElementHash) {
401        if ((this.elementHash > -1) && !this.formerElementHashes.contains(this.elementHash)) {
402            this.formerElementHashes.add(this.elementHash);
403        }
404
405        this.elementHash = newElementHash;
406    }
407
408    /**
409     * <p>
410     * Sets the type hierarchy of the specified GUI element.
411     *
412     * @param typeHierarchy
413     *            </p>
414     */
415    public void setTypeHierarchy(List<String> typeHierarchy) {
416        this.typeHierarchy = typeHierarchy;
417    }
418
419    /**
420     * <p>
421     * Updates the specification with another specification.
422     * </p>
423     *
424     * @param furtherSpec
425     *            specification used to update the current specification
426     */
427    void update(JFCGUIElementSpec other) {
428        if (other != this) {
429            for (int formerElementHash : other.formerElementHashes) {
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
441            if ((name == null) || (!name.equals(other.name))) {
442                setName(other.name);
443            }
444            other.altIndex = this.altIndex;
445        }
446    }
447
448    /*
449     * (non-Javadoc)
450     *
451     * @see java.lang.Object#toString()
452     */
453    public String toString() {
454        return "[" + getName() + ";\"" + type + "\";\"" + icon + "\";" + index + ";" + elementHash +
455            "]";
456    }
457
458    @Override
459    public String[] getTypeHierarchy() {
460        if (typeHierarchy == null) {
461            return new String[]
462                { (getType()) };
463        }
464        else
465            return typeHierarchy.toArray(new String[typeHierarchy.size()]);
466    }
467
468}
Note: See TracBrowser for help on using the repository browser.