[831] | 1 |
|
---|
[545] | 2 | package de.ugoe.cs.quest.eventcore.guimodel;
|
---|
| 3 |
|
---|
[609] | 4 | import java.util.IdentityHashMap;
|
---|
| 5 | import java.util.LinkedList;
|
---|
| 6 | import 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 | */
|
---|
| 16 | public 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 | }
|
---|