// 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; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import de.ugoe.cs.autoquest.eventcore.EventTargetModelException; import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory; /** *

* This class provides the interfaces for hierarchical event target trees. *

*

* The HierarchicalEventTargetTree represents the hierarchical structure of the event targets * "as it is" currently during a session. It may change during the session due to creation and * destruction of event targets. The parameter ID represents the id type of the event targets * that are handled internally. The other type parameters specify the concrete target type. *

* * @author Fabian Glaser * @author Steffen Herbold * @version 1.0 */ public class HierarchicalEventTargetTree { /** *

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

*/ private Map eventTargets; /** *

* Map of all event target specifications that are part of the tree for efficient searching. The * keys of the map are the ids of the event targets. *

*/ private Map eventTargetSpecs; /** *

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

*/ private Map> childRelations; /** *

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

*/ private Map parentRelations; /** *

* the internally created GUI model *

*/ private HierarchicalEventTargetModel eventTargetModel; /** *

* the event target factory used in the model *

*/ private IEventTargetFactory eventTargetFactory; /** *

* Creates a new GUIElementTree. *

*/ public HierarchicalEventTargetTree(HierarchicalEventTargetModel eventTargetModel, IEventTargetFactory eventTargetFactory) { this.eventTargetSpecs = new HashMap(); this.childRelations = new HashMap>(); this.parentRelations = new HashMap(); this.eventTargets = new HashMap(); this.eventTargetModel = eventTargetModel; this.eventTargetFactory = eventTargetFactory; } /** *

* Adds a new event target to the tree. *

* * @param eventTargetID * id of the event target to be created * @param parentID * id of the parent event target * @param eventTargetSpec * the event target specification * * @throws EventTargetModelException if the event target can not be added to the underlying GUI model */ public void add(ID eventTargetID, ID parentID, TARGET_SPEC_TYPE eventTargetSpec) throws EventTargetModelException { TARGET_TYPE eventTarget = eventTargets.get(eventTargetID); if (eventTarget == null) { TARGET_SPEC_TYPE parent = eventTargetSpecs.get(parentID); if (parent != null) { List otherChildren = childRelations.get(parentID); if (otherChildren == null) { otherChildren = new ArrayList(); childRelations.put(parentID, otherChildren); } otherChildren.add(eventTargetID); parentRelations.put(eventTargetID, parentID); } eventTargetSpecs.put(eventTargetID, eventTargetSpec); List eventTargetPath = new ArrayList(); ID currentElementID = eventTargetID; while (eventTargetSpec != null) { eventTargetPath.add(0, eventTargetSpec); currentElementID = parentRelations.get(currentElementID); eventTargetSpec = eventTargetSpecs.get(currentElementID); } eventTarget = (TARGET_TYPE) eventTargetModel.integratePath(eventTargetPath, eventTargetFactory); eventTargets.put(eventTargetID, eventTarget); } } /** *

* Searches the tree for a event target with the specified id and returns its * {@link IGUIElement} . *

* * @param id * id that is looked for * @return {@link IEventTargetSpec} of the event target with the given id if found, null otherwise */ public TARGET_TYPE find(ID id) { return eventTargets.get(id); } /** *

* Returns the id of the provided {@link IHierachicalEventTarget}. The comparison is performed using the * equals method of the event target. *

* * @param eventTarget * guiElement that is looked for * @return the id of the event target, null if the event target can not be found */ public ID find(TARGET_TYPE eventTarget) { for (Map.Entry entry : eventTargets.entrySet()) { if (eventTarget.equals(entry.getValue())) { return entry.getKey(); } } return null; } /** *

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

* * @param id * id of the event target to be removed * @return number of event targets that were removed */ public int remove(ID id) { int removedCounter = 0; TARGET_SPEC_TYPE node = eventTargetSpecs.remove(id); if (node != null) { removedCounter++; List nodesToBeRemoved = childRelations.remove(id); // remove all children and sub-children, if any if (nodesToBeRemoved != null) { for (int i = 0; i < nodesToBeRemoved.size(); i++) { ID nodeToBeRemoved = nodesToBeRemoved.get(i); List children = childRelations.remove(nodeToBeRemoved); if (children != null) { nodesToBeRemoved.addAll(children); } eventTargetSpecs.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 */ ID 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 HierarchicalEventTargetModel getHierarchicalEventTargetModel() { return eventTargetModel; } /** *

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

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