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

Last change on this file since 1005 was 1005, checked in by fglaser, 12 years ago
  • remove of GUIElementTree now returns 0 if no element was removed.
  • GUIElementTree test added (unfortunately the test class needs some artificial mock objects, that were also added)
  • Property svn:mime-type set to text/plain
File size: 9.3 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.ArrayList;
18import java.util.HashMap;
19import java.util.List;
20import java.util.Map;
21
22import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementFactory;
23import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
24import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
25import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementFactory;
26
27/**
28 * <p>
29 * This class provides the interfaces for GUI element trees.
30 * </p>
31 * <p>
32 * The GUIElementTree represents the hierarchical structure of the GUI elements "as it is" currently during
33 * a session. It may change during the session due to creation and destruction of GUI elements.
34 * </p>
35 *
36 * @author Fabian Glaser
37 * @author Steffen Herbold
38 * @version 1.0
39 */
40public class GUIElementTree {
41        /* Note that in the current version the id of a GUI element is assumed to be a long. For future
42        versions it might be more suitable to change to some generic id type. */
43       
44         /**
45     * <p>
46     * Map of all GUI elements that are part of the tree for efficient searching. The keys of the
47     * map are the ids of the GUI elements.
48     * </p>
49     */
50    private Map<Long, IGUIElement> guiElements;
51
52    /**
53     * <p>
54     * Map of all GUI element specifications that are part of the tree for efficient searching. The
55     * keys of the map are the ids of the GUI elements.
56     * </p>
57     */
58    private Map<Long, IGUIElementSpec> guiElementSpecs;
59
60    /**
61     * <p>
62     * Map of all children of GUI elements that are part of the tree. The keys of the map are the
63     * ids of the parent GUI elements.
64     * </p>
65     */
66    private Map<Long, List<Long>> childRelations;
67
68    /**
69     * <p>
70     * Map of all parents of GUI elements that are part of the tree. The keys of the map are the
71     * ids of the child GUI elements.
72     * </p>
73     */
74    private Map<Long, Long> parentRelations;
75
76    /**
77     * <p>
78     * the internally created GUI model
79     * </p>
80     */
81    private GUIModel guiModel;
82
83    /**
84     * <p>
85     * the GUI element factory used in the model
86     * </p>
87     */
88    private IGUIElementFactory guiElementFactory = GUIElementFactory.getInstance();
89
90 
91
92    /**
93     * <p>
94     * Creates a new GUIElementTree.
95     * </p>
96     */
97    public GUIElementTree() {
98        guiElementSpecs = new HashMap<Long, IGUIElementSpec>();
99        childRelations = new HashMap<Long, List<Long>>();
100        parentRelations = new HashMap<Long, Long>();
101        guiElements = new HashMap<Long, IGUIElement>();
102        guiModel = new GUIModel();
103    }
104   
105    /**
106     * <p>
107     * Creates a GUIElementTree with an already existing guiModel
108     * @param guiModel
109     * </p>
110     */
111    public GUIElementTree(GUIModel guiModel){
112        guiElementSpecs = new HashMap<Long, IGUIElementSpec>();
113        childRelations = new HashMap<Long, List<Long>>();
114        parentRelations = new HashMap<Long, Long>();
115        guiElements = new HashMap<Long, IGUIElement>();
116        this.guiModel = guiModel;
117    }
118
119    /**
120     * <p>
121     * Adds a new GUI element to the tree.
122     * </p>
123     *
124     * @param guiElementID
125     *            id of the GUI element to be created
126     * @param parentID
127     *            id of the parent GUI element
128     * @param guiElementSpec
129     *                    the GUI element specification
130     */
131    public void add(Long guiElementID,
132                                Long parentID,
133                    IGUIElementSpec guiElementSpec)
134    {
135        IGUIElement guiElement = guiElements.get(guiElementID);
136       
137        if (guiElement == null) {
138                IGUIElementSpec parent = guiElementSpecs.get(parentID);
139            if (parent != null) {
140                List<Long> otherChildren = childRelations.get(parentID);
141
142                if (otherChildren == null) {
143                    otherChildren = new ArrayList<Long>();
144                    childRelations.put(parentID, otherChildren);
145                }
146
147                otherChildren.add(guiElementID);
148
149                parentRelations.put(guiElementID, parentID);
150            }
151            guiElementSpecs.put(guiElementID, guiElementSpec);
152           
153            List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
154
155            Long currentElementID = guiElementID;
156            while (guiElementSpec != null) {
157                guiElementPath.add(0, guiElementSpec);
158                currentElementID = parentRelations.get(currentElementID);
159                guiElementSpec = guiElementSpecs.get(currentElementID);
160            }
161
162            try {
163                guiElement = guiModel.integratePath(guiElementPath, guiElementFactory);
164            }
165            catch (GUIModelException e) {
166                throw new RuntimeException("could not instantiate GUI element with id " + guiElementID, e);
167            }
168            guiElements.put(guiElementID, guiElement);
169        }
170    }
171
172    /**
173     * <p>
174     * Searches the tree for a GUI element with the specified id and returns its
175     * {@link IGUIElementSpec} .
176     * </p>
177     *
178     * @param id
179     *            id that is looked for
180     * @return {@link IGUIElementSpec} of the GUI element with the given id if found, null otherwise
181     */
182    public IGUIElement find(long id) {
183        IGUIElement guiElement = guiElements.get(id);
184        if (guiElement == null) {
185            List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
186
187            IGUIElementSpec elementSpec = guiElementSpecs.get(id);
188
189            if (elementSpec == null) {
190                throw new RuntimeException("no GUI element found with hash " + id);
191            }
192
193            Long currentElementID = id;
194            while (elementSpec != null) {
195                guiElementPath.add(0, elementSpec);
196                currentElementID = parentRelations.get(currentElementID);
197                elementSpec = guiElementSpecs.get(currentElementID);
198            }
199
200            try {
201                guiElement = guiModel.integratePath(guiElementPath, guiElementFactory);
202            }
203            catch (GUIModelException e) {
204                throw new RuntimeException("could not instantiate GUI element with id " + id, e);
205            }
206            guiElements.put(id, guiElement);
207        }
208        return guiElement;
209    }
210
211    /**
212     * <p>
213     * Removes a GUI element (defined by its id) from the tree. All children of the GUI element will be
214     * removed recursively.
215     * </p>
216     *
217     * @param id
218     *            id of the GUI element to be removed
219     * @return number of GUI elements that were removed
220     */
221    public int remove(long id) {
222        int removedCounter = 0;
223        IGUIElementSpec node = guiElementSpecs.remove(id);
224
225        if (node != null) {
226                removedCounter++;
227            List<Long> nodesToBeRemoved = childRelations.remove(id);
228
229            // remove all children and sub-children, if any
230            if (nodesToBeRemoved != null) {
231                for (int i = 0; i < nodesToBeRemoved.size(); i++) {
232                    Long nodeToBeRemoved = nodesToBeRemoved.get(i);
233                    List<Long> children =
234                        childRelations.remove(nodeToBeRemoved);
235
236                    if (children != null) {
237                        nodesToBeRemoved.addAll(children);
238                    }
239
240                    guiElementSpecs.remove(nodeToBeRemoved);
241                    parentRelations.remove(nodeToBeRemoved);
242                    removedCounter++;
243                }
244            }
245
246            /* the node may be a child node of a parent. So search for it in the child relations
247            of the parent and remove it */
248            Long parent = parentRelations.remove(id);
249            if (parent != null) {
250                List<Long> children = childRelations.get(parent);
251
252                if (children != null) {
253                    for (int i = 0; i < children.size(); i++) {
254                        if (children.get(i) == id) {
255                            children.remove(i);
256                            break;
257                        }
258                    }
259
260                    if (children.size() <= 0) {
261                        childRelations.remove(parent);
262                    }
263                }
264            }
265        }
266        return removedCounter;
267    }
268
269    /**
270     * @return the guiModel
271     */
272    public GUIModel getGUIModel() {
273        return guiModel;
274    }
275
276    /**
277     * <p>
278     * Returns the number of nodes contained in the JFCComponentTree.
279     * </p>
280     *
281     * @return number of nodes
282     */
283    public int size() {
284        return guiElementSpecs.size();
285    }
286
287}
Note: See TracBrowser for help on using the repository browser.