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

Last change on this file since 846 was 831, checked in by sherbold, 12 years ago
  • code documentation and clean-up
  • Property svn:executable set to *
File size: 8.6 KB
RevLine 
[831]1
[545]2package de.ugoe.cs.quest.eventcore.guimodel;
3
[609]4import java.util.IdentityHashMap;
5import java.util.LinkedList;
6import java.util.List;
7
[545]8/**
[831]9 * <p>
10 * Skeletal implementation for GUI elements.
11 * </p>
[545]12 *
[831]13 * @version 1.0
14 * @author Patrick Harms
[545]15 */
16public abstract class AbstractDefaultGUIElement implements IGUIElement {
[831]17
18    /**
19     * <p>
20     * Id for object serialization.
21     * </p>
22     */
[545]23    public static final long serialVersionUID = 1L;
24
[831]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     */
[609]31    private static final EqualGUIElementManager equalGUIElementManager =
32        new EqualGUIElementManager();
33
[831]34    /**
35     * <p>
36     * Specification of the GUI element
37     * </p>
38     */
39    private final IGUIElementSpec specification;
[545]40
[831]41    /**
42     * <p>
43     * Reference to the parent element
44     * </p>
45     */
46    private final IGUIElement parent;
[603]47
[576]48    /**
49     * <p>
[831]50     * Constructor. Creates a new AbstractDefaultGUIElement.
[576]51     * </p>
[831]52     *
[576]53     * @param specification
[831]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
[565]57     */
[603]58    public AbstractDefaultGUIElement(IGUIElementSpec specification, IGUIElement parent) {
[576]59        this.specification = specification;
[603]60        this.parent = parent;
[565]61    }
62
[545]63    /*
64     * (non-Javadoc)
65     *
[576]66     * @see de.ugoe.cs.tasktree.guimodel.GUIElement#getSpecification()
[545]67     */
68    @Override
[576]69    public IGUIElementSpec getSpecification() {
70        return specification;
[545]71    }
72
[831]73    /*
74     * (non-Javadoc)
75     *
[603]76     * @see de.ugoe.cs.quest.eventcore.guimodel.IGUIElement#getParent()
77     */
78    @Override
79    public IGUIElement getParent() {
80        return parent;
81    }
82
[831]83    /*
84     * (non-Javadoc)
85     *
[609]86     * @see de.ugoe.cs.quest.eventcore.guimodel.IGUIElement#addEqualGUIElement(IGUIElement)
87     */
88    @Override
[831]89    public void addEqualGUIElement(IGUIElement equalElement) {
[609]90        equalGUIElementManager.addEqualGUIElements(this, equalElement);
91    }
92
[545]93    /*
94     * (non-Javadoc)
95     *
[576]96     * @see GUIElement#equals(GUIElement)
[545]97     */
[603]98    public final boolean equals(Object other) {
[609]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);
[545]102    }
103
[831]104    /*
105     * (non-Javadoc)
106     *
[603]107     * @see java.lang.Object#hashCode()
108     */
109    @Override
110    public final int hashCode() {
[609]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);
[603]116    }
117
[609]118    /**
119     * <p>
[831]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.
[609]124     * </p>
125     *
[831]126     * @version 1.0
127     * @author Patrick Harms
[609]128     */
129    private static class EqualGUIElementManager {
130
131        /**
132         * <p>
[831]133         * The internal map of GUI elements mapping each registered element to its equal variants.
[609]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>>();
[831]140
[609]141        /**
142         * <p>
[831]143         * Adds a new equals relationship between two {@link IGUIElement}s to the equality manager.
[609]144         * </p>
[831]145         *
146         * @param guiElement1
147         *            first equal GUI element
148         * @param guiElement2
149         *            second equal GUI element
[609]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);
[831]156
[609]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
[831]180                // in this case, both GUI elements should already be registered with the same
181                // lists.
[609]182            }
183        }
184
185        /**
186         * <p>
[831]187         * Returns the object hash of a {@link IGUIElement}.
[609]188         * </p>
[831]189         *
190         * @param guiElement
191         *            gui element whose object hash is determined
192         * @return the object hash
[609]193         */
194        private synchronized int hashCode(IGUIElement guiElement) {
195            return System.identityHashCode(getEqualElementsList(guiElement));
196        }
197
198        /**
199         * <p>
[831]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)}.
[609]203         * </p>
[831]204         *
205         * @param guiElement
206         *            GUI element to which the object is compared
[609]207         * @param other
[831]208         *            object that is compared to the GUI element
[609]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            }
[831]219
[609]220            return false;
221        }
222
223        /**
224         * <p>
[831]225         * Returns the equal {@link IGUIElement} of a given {@link IGUIElement}.
[609]226         * </p>
[831]227         *
[609]228         * @param guiElement
[831]229         *            GUI element of which the equal elements are returned
230         * @return the equal GUI elements
[609]231         */
232        private List<IGUIElement> getEqualElementsList(IGUIElement guiElement) {
233            List<IGUIElement> returnValue = identityHashMap.get(guiElement);
[831]234
[609]235            if (returnValue == null) {
236                returnValue = new LinkedList<IGUIElement>();
237                returnValue.add(guiElement);
238                identityHashMap.put(guiElement, returnValue);
239            }
[831]240
[609]241            return returnValue;
242        }
243
244        /**
245         * <p>
[831]246         * Adds {@link IGUIElement} as equal to a list of {@link IGUIElement} if and only if it is
247         * not already contained.
[609]248         * </p>
[831]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
[609]254         */
255        private void addIfNotContained(List<IGUIElement> equalElementsList, IGUIElement guiElement)
256        {
257            for (IGUIElement candidate : equalElementsList) {
258                if (candidate == guiElement) {
259                    return;
260                }
261            }
[831]262
[609]263            equalElementsList.add(guiElement);
264        }
265
266    }
267
[545]268}
Note: See TracBrowser for help on using the repository browser.