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

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