// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.eventcore.guimodel; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementFactory; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementFactory; /** *

* This class provides the interfaces for GUI element trees. *

*

* The GUIElementTree represents the hierarchical structure of the GUI elements "as it is" currently during * a session. It may change during the session due to creation and destruction of GUI elements. *

* * @author Fabian Glaser * @author Steffen Herbold * @version 1.0 */ public class GUIElementTree { /* Note that in the current version the id of a GUI element is assumed to be a long. For future versions it might be more suitable to change to some generic id type. */ /** *

* Map of all GUI elements that are part of the tree for efficient searching. The keys of the * map are the ids of the GUI elements. *

*/ private Map guiElements; /** *

* Map of all GUI element specifications that are part of the tree for efficient searching. The * keys of the map are the ids of the GUI elements. *

*/ private Map guiElementSpecs; /** *

* Map of all children of GUI elements that are part of the tree. The keys of the map are the * ids of the parent GUI elements. *

*/ private Map> childRelations; /** *

* Map of all parents of GUI elements that are part of the tree. The keys of the map are the * ids of the child GUI elements. *

*/ private Map parentRelations; /** *

* the internally created GUI model *

*/ private GUIModel guiModel; /** *

* the GUI element factory used in the model *

*/ private IGUIElementFactory guiElementFactory = GUIElementFactory.getInstance(); /** *

* Creates a new GUIElementTree. *

*/ public GUIElementTree() { guiElementSpecs = new HashMap(); childRelations = new HashMap>(); parentRelations = new HashMap(); guiElements = new HashMap(); guiModel = new GUIModel(); } /** *

* Creates a GUIElementTree with an already existing guiModel * @param guiModel *

*/ public GUIElementTree(GUIModel guiModel){ guiElementSpecs = new HashMap(); childRelations = new HashMap>(); parentRelations = new HashMap(); guiElements = new HashMap(); this.guiModel = guiModel; } /** *

* Adds a new GUI element to the tree. *

* * @param guiElementID * id of the GUI element to be created * @param parentID * id of the parent GUI element * @param guiElementSpec * the GUI element specification */ public void add(Long guiElementID, Long parentID, IGUIElementSpec guiElementSpec) { IGUIElement guiElement = guiElements.get(guiElementID); if (guiElement == null) { IGUIElementSpec parent = guiElementSpecs.get(parentID); if (parent != null) { List otherChildren = childRelations.get(parentID); if (otherChildren == null) { otherChildren = new ArrayList(); childRelations.put(parentID, otherChildren); } otherChildren.add(guiElementID); parentRelations.put(guiElementID, parentID); } guiElementSpecs.put(guiElementID, guiElementSpec); List guiElementPath = new ArrayList(); Long currentElementID = guiElementID; while (guiElementSpec != null) { guiElementPath.add(0, guiElementSpec); currentElementID = parentRelations.get(currentElementID); guiElementSpec = guiElementSpecs.get(currentElementID); } try { guiElement = guiModel.integratePath(guiElementPath, guiElementFactory); } catch (GUIModelException e) { throw new RuntimeException("could not instantiate GUI element with id " + guiElementID, e); } guiElements.put(guiElementID, guiElement); } } /** *

* Searches the tree for a GUI element with the specified id and returns its * {@link IGUIElementSpec} . *

* * @param id * id that is looked for * @return {@link IGUIElementSpec} of the GUI element with the given id if found, null otherwise */ public IGUIElement find(long id) { IGUIElement guiElement = guiElements.get(id); if (guiElement == null) { List guiElementPath = new ArrayList(); IGUIElementSpec elementSpec = guiElementSpecs.get(id); if (elementSpec == null) { throw new RuntimeException("no GUI element found with hash " + id); } Long currentElementID = id; while (elementSpec != null) { guiElementPath.add(0, elementSpec); currentElementID = parentRelations.get(currentElementID); elementSpec = guiElementSpecs.get(currentElementID); } try { guiElement = guiModel.integratePath(guiElementPath, guiElementFactory); } catch (GUIModelException e) { throw new RuntimeException("could not instantiate GUI element with id " + id, e); } guiElements.put(id, guiElement); } return guiElement; } /** *

* Removes a GUI element (defined by its id) from the tree. All children of the GUI element will be * removed recursively. *

* * @param id * id of the GUI element to be removed * @return number of GUI elements that were removed */ public int remove(long id) { IGUIElementSpec node = guiElementSpecs.remove(id); int removedCounter = 1; if (node != null) { List nodesToBeRemoved = childRelations.remove(id); // remove all children and sub-children, if any if (nodesToBeRemoved != null) { for (int i = 0; i < nodesToBeRemoved.size(); i++) { Long nodeToBeRemoved = nodesToBeRemoved.get(i); List children = childRelations.remove(nodeToBeRemoved); if (children != null) { nodesToBeRemoved.addAll(children); } guiElementSpecs.remove(nodeToBeRemoved); parentRelations.remove(nodeToBeRemoved); removedCounter++; } } /* the node may be a child node of a parent. So search for it in the child relations of the parent and remove it */ Long parent = parentRelations.remove(id); if (parent != null) { List children = childRelations.get(parent); if (children != null) { for (int i = 0; i < children.size(); i++) { if (children.get(i) == id) { children.remove(i); break; } } if (children.size() <= 0) { childRelations.remove(parent); } } } } return removedCounter; } /** * @return the guiModel */ public GUIModel getGUIModel() { return guiModel; } /** *

* Returns the number of nodes contained in the JFCComponentTree. *

* * @return number of nodes */ public int size() { return guiElementSpecs.size(); } }