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

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