source: trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElement.java @ 1051

Last change on this file since 1051 was 1051, checked in by pharms, 11 years ago
  • renamed usageObserved to isUsed
  • renamed markAsUsed to markUsed
  • added markUsed to default GUI element interface
  • Property svn:executable set to *
File size: 9.8 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.eventcore.guimodel;
16
17import java.util.IdentityHashMap;
18import java.util.LinkedList;
19import java.util.List;
20
21/**
22 * <p>
23 * Skeletal implementation for GUI elements.
24 * </p>
25 *
26 * @version 1.0
27 * @author Patrick Harms
28 */
29public abstract class AbstractDefaultGUIElement implements IGUIElement {
30
31    /**
32     * <p>
33     * Id for object serialization.
34     * </p>
35     */
36    public static final long serialVersionUID = 1L;
37
38    /**
39     * <p>
40     * The reference to equal GUI element manager (needed to preserve singleton behavior, even
41     * though the objects are not singleton).
42     * </p>
43     */
44    private static final EqualGUIElementManager equalGUIElementManager =
45        new EqualGUIElementManager();
46
47    /**
48     * <p>
49     * Specification of the GUI element
50     * </p>
51     */
52    private final IGUIElementSpec specification;
53
54    /**
55     * <p>
56     * Reference to the parent element
57     * </p>
58     */
59    private final IGUIElement parent;
60   
61    /**
62     * <p>
63     * Boolean that indicates if a GUIElement was used during a session.
64     * </p>
65     */
66    boolean usageObserved;
67
68    /**
69     * <p>
70     * Constructor. Creates a new AbstractDefaultGUIElement.
71     * </p>
72     *
73     * @param specification
74     *            specification of the created GUI element
75     * @param parent
76     *            parent of the created GUI element; null means the element is a top-level window
77     */
78    public AbstractDefaultGUIElement(IGUIElementSpec specification, IGUIElement parent) {
79        this.specification = specification;
80        this.parent = parent;
81        this.usageObserved = false;
82    }
83
84    /*
85     * (non-Javadoc)
86     *
87     * @see de.ugoe.cs.tasktree.guimodel.GUIElement#getSpecification()
88     */
89    @Override
90    public IGUIElementSpec getSpecification() {
91        return specification;
92    }
93
94    /*
95     * (non-Javadoc)
96     *
97     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#getParent()
98     */
99    @Override
100    public IGUIElement getParent() {
101        return parent;
102    }
103
104    /*
105     * (non-Javadoc)
106     *
107     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#addEqualGUIElement(IGUIElement)
108     */
109    @Override
110    public void addEqualGUIElement(IGUIElement equalElement) {
111        equalGUIElementManager.addEqualGUIElements(this, equalElement);
112    }
113
114    /*
115     * (non-Javadoc)
116     *
117     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#isUsed()
118     */
119    @Override
120    public boolean isUsed() {
121        return usageObserved;
122    }
123
124    /*
125     * (non-Javadoc)
126     *
127     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#markUsed()
128     */
129    @Override
130    public void markUsed() {
131        this.usageObserved = true;
132    }
133
134    /*
135     * (non-Javadoc)
136     *
137     * @see GUIElement#equals(GUIElement)
138     */
139    public final boolean equals(Object other) {
140        // implement final, as GUI elements are all singletons and they equal only if they are the
141        // same object or if they are in the list of equal GUI elements
142        return super.equals(other) || equalGUIElementManager.equals(this, other);
143    }
144
145    /*
146     * (non-Javadoc)
147     *
148     * @see java.lang.Object#hashCode()
149     */
150    @Override
151    public final int hashCode() {
152        // implement final, as GUI elements are all singletons and they equal only if they are the
153        // same object. If there are several GUI element objects that represent the same GUI element
154        // then they are stored in the list of equal elements. In this case, the hash code of the
155        // list is unique within the system
156        return equalGUIElementManager.hashCode(this);
157    }
158   
159    /**
160     * <p>
161     * This internal helper class manages equal GUI elements. This is necessary, as we often first
162     * identify many GUI elements as different and later use a heuristic to determine that they are
163     * the same. This class provides the means to preserve the singleton behavior of the GUI
164     * elements after we merge two GUI elements.
165     * </p>
166     *
167     * @version 1.0
168     * @author Patrick Harms
169     */
170    private static class EqualGUIElementManager {
171
172        /**
173         * <p>
174         * The internal map of GUI elements mapping each registered element to its equal variants.
175         * We use the {@link IdentityHashMap} as a normal hash map would not work because of the
176         * changing of the hash code of GUI elements at runtime.
177         * </p>
178         */
179        private IdentityHashMap<IGUIElement, List<IGUIElement>> identityHashMap =
180            new IdentityHashMap<IGUIElement, List<IGUIElement>>();
181
182        /**
183         * <p>
184         * Adds a new equals relationship between two {@link IGUIElement}s to the equality manager.
185         * </p>
186         *
187         * @param guiElement1
188         *            first equal GUI element
189         * @param guiElement2
190         *            second equal GUI element
191         */
192        private synchronized void addEqualGUIElements(IGUIElement guiElement1,
193                                                      IGUIElement guiElement2)
194        {
195            List<IGUIElement> list1 = identityHashMap.get(guiElement1);
196            List<IGUIElement> list2 = identityHashMap.get(guiElement2);
197
198            if (list1 == null) {
199                if (list2 == null) {
200                    list2 = new LinkedList<IGUIElement>();
201                    list2.add(guiElement1);
202                    list2.add(guiElement2);
203                    identityHashMap.put(guiElement1, list2);
204                    identityHashMap.put(guiElement2, list2);
205                }
206                else {
207                    addIfNotContained(list2, guiElement1);
208                    identityHashMap.put(guiElement1, list2);
209                }
210            }
211            else {
212                if (list2 == null) {
213                    addIfNotContained(list1, guiElement2);
214                    identityHashMap.put(guiElement2, list1);
215                }
216                else if (list1 != list2) {
217                    list1.addAll(list2);
218                    identityHashMap.put(guiElement2, list1);
219                }
220                // else
221                // in this case, both GUI elements should already be registered with the same
222                // lists.
223            }
224        }
225
226        /**
227         * <p>
228         * Returns the object hash of a {@link IGUIElement}.
229         * </p>
230         *
231         * @param guiElement
232         *            gui element whose object hash is determined
233         * @return the object hash
234         */
235        private synchronized int hashCode(IGUIElement guiElement) {
236            return System.identityHashCode(getEqualElementsList(guiElement));
237        }
238
239        /**
240         * <p>
241         * Determines the equality of two {@link IGUIElement}s based on the information of the
242         * identify manager. Two elements are equal, if they have been added as equal using
243         * {@link #addEqualGUIElements(IGUIElement, IGUIElement)}.
244         * </p>
245         *
246         * @param guiElement
247         *            GUI element to which the object is compared
248         * @param other
249         *            object that is compared to the GUI element
250         * @return
251         */
252        private synchronized boolean equals(IGUIElement guiElement, Object other) {
253            if (other instanceof IGUIElement) {
254                for (IGUIElement candidate : getEqualElementsList(guiElement)) {
255                    if (candidate == other) {
256                        return true;
257                    }
258                }
259            }
260
261            return false;
262        }
263
264        /**
265         * <p>
266         * Returns the equal {@link IGUIElement} of a given {@link IGUIElement}.
267         * </p>
268         *
269         * @param guiElement
270         *            GUI element of which the equal elements are returned
271         * @return the equal GUI elements
272         */
273        private List<IGUIElement> getEqualElementsList(IGUIElement guiElement) {
274            List<IGUIElement> returnValue = identityHashMap.get(guiElement);
275
276            if (returnValue == null) {
277                returnValue = new LinkedList<IGUIElement>();
278                returnValue.add(guiElement);
279                identityHashMap.put(guiElement, returnValue);
280            }
281
282            return returnValue;
283        }
284
285        /**
286         * <p>
287         * Adds {@link IGUIElement} as equal to a list of {@link IGUIElement} if and only if it is
288         * not already contained.
289         * </p>
290         *
291         * @param equalElementsList
292         *            list of {@link IGUIElement} to which the GUI element is added
293         * @param guiElement
294         *            GUI element to be added
295         */
296        private void addIfNotContained(List<IGUIElement> equalElementsList, IGUIElement guiElement)
297        {
298            for (IGUIElement candidate : equalElementsList) {
299                if (candidate == guiElement) {
300                    return;
301                }
302            }
303
304            equalElementsList.add(guiElement);
305        }
306
307    }
308
309}
Note: See TracBrowser for help on using the repository browser.