Index: /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElementTest.java
===================================================================
--- /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElementTest.java	(revision 2145)
+++ /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElementTest.java	(revision 2146)
@@ -19,7 +19,7 @@
 import org.junit.Test;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
 /**
@@ -38,5 +38,5 @@
         assertCompletelyUnequal(guiElement1, guiElement2);
         
-        guiElement1.addEqualGUIElement(guiElement2);
+        guiElement1.addEqualEventTarget(guiElement2);
         assertCompletelyEqual(guiElement1, guiElement2);
         
@@ -47,5 +47,5 @@
         assertCompletelyUnequal(guiElement2, guiElement3);
         
-        guiElement1.addEqualGUIElement(guiElement3);
+        guiElement1.addEqualEventTarget(guiElement3);
         assertCompletelyEqual(guiElement1, guiElement2, guiElement3);
 
@@ -57,5 +57,5 @@
         assertCompletelyUnequal(guiElement3, guiElement4);
         
-        guiElement3.addEqualGUIElement(guiElement4);
+        guiElement3.addEqualEventTarget(guiElement4);
         assertCompletelyEqual(guiElement1, guiElement2, guiElement3, guiElement4);
     }
@@ -115,5 +115,5 @@
          */
         @Override
-        public void updateSpecification(IGUIElementSpec furtherSpec) {
+        public void updateSpecification(IEventTargetSpec furtherSpec) {
             throw new UnsupportedOperationException();
         }
Index: /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelTest.java
===================================================================
--- /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelTest.java	(revision 2145)
+++ /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelTest.java	(revision 2146)
@@ -23,4 +23,11 @@
 import org.junit.Test;
 
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelConfigurationException;
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetModel;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
+
 /**
  *
@@ -32,5 +39,5 @@
      * 
      */
-    private IGUIElementFactory guiElementFactory = new TestGUIElementFactory();
+    private IEventTargetFactory guiElementFactory = new TestGUIElementFactory();
 
     /**
@@ -399,5 +406,5 @@
         IGUIElement guiElem9 = model.getChildren(guiElem1).get(1);
         
-        model.groupGUIElements(Arrays.asList(guiElem2, guiElem9), "newGroup");
+        model.groupEventTargets(Arrays.asList(guiElem2, guiElem9), "newGroup", guiElementFactory);
         
         assertEquals(1, model.getChildren(guiElem1).size());
@@ -475,5 +482,5 @@
         IGUIElement guiElem5 = model.getChildren(guiElem2).get(1);
         
-        model.groupGUIElements(Arrays.asList(guiElem3, guiElem5), "newGroup");
+        model.groupEventTargets(Arrays.asList(guiElem3, guiElem5), "newGroup", guiElementFactory);
         
         assertEquals(1, model.getChildren(guiElem2).size());
@@ -551,5 +558,5 @@
         IGUIElement guiElem4 = model.getChildren(guiElem3).get(0);
         
-        model.groupGUIElements(Arrays.asList(guiElem4), "newGroup");
+        model.groupEventTargets(Arrays.asList(guiElem4), "newGroup", guiElementFactory);
         
         assertEquals(1, model.getChildren(guiElem3).size());
@@ -629,5 +636,5 @@
         IGUIElement guiElem6 = model.getChildren(guiElem5).get(0);
 
-        model.groupGUIElements(Arrays.asList(guiElem4, guiElem6), "newGroup");
+        model.groupEventTargets(Arrays.asList(guiElem4, guiElem6), "newGroup", guiElementFactory);
     }
 
@@ -685,5 +692,5 @@
         //         \-- guiElem10
         
-        GUIModel.Traverser traverser = model.getTraverser();
+        IHierarchicalEventTargetModel.Traverser<IGUIElement> traverser = model.getTraverser();
         assertNotNull(traverser);
         assertTrue(traverser.hasFirstChild());
@@ -890,5 +897,5 @@
         //         \-- guiElem10
         
-        GUIModel.Traverser traverser = model.getTraverser(target);
+        IHierarchicalEventTargetModel.Traverser<IGUIElement> traverser = model.getTraverser(target);
         assertNotNull(traverser);
         assertFalse(traverser.hasFirstChild());
@@ -985,16 +992,30 @@
      * @author Patrick Harms
      */
-    private class TestGUIElementFactory implements IGUIElementFactory {
+    private class TestGUIElementFactory implements IEventTargetFactory {
 
         /* (non-Javadoc)
          * @see IGUIElementFactory#instantiateGUIElement(IGUIElementSpec, IGUIElement)
          */
+        @SuppressWarnings("unchecked")
         @Override
-        public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent)
-            throws GUIModelConfigurationException
+        public <T extends IHierarchicalEventTarget> T instantiateEventTarget(IEventTargetSpec specification,
+                                                                             T                parent)
+            throws EventTargetModelConfigurationException
         {
             assertTrue(specification instanceof TestGUIElementSpec);
             
-            return new TestGUIElement((TestGUIElementSpec) specification, parent);
+            return (T) new TestGUIElement((TestGUIElementSpec) specification, (IGUIElement) parent);
+        }
+
+        /* (non-Javadoc)
+         * @see IEventTargetFactory#instantiateGroup(String, IHierarchicalEventTarget, HierarchicalEventTargetModel)
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T extends IHierarchicalEventTarget> T instantiateGroup(String                          groupName,
+                                                                       T                               parent,
+                                                                       HierarchicalEventTargetModel<T> hierarchicalEventTargetModel)
+        {
+            return (T) new GUIElementGroup(groupName, (IGUIElement) parent, (GUIModel) hierarchicalEventTargetModel);
         }
 
@@ -1053,5 +1074,5 @@
          */
         @Override
-        public boolean getSimilarity(IGUIElementSpec other) {
+        public boolean getSimilarity(IEventTargetSpec other) {
             return (other instanceof TestGUIElementSpec ?
                 ((TestGUIElementSpec) other).similarityId.equals(similarityId) : false);
@@ -1105,5 +1126,5 @@
          */
         @Override
-        public void updateSpecification(IGUIElementSpec furtherSpec) {
+        public void updateSpecification(IEventTargetSpec furtherSpec) {
             // do nothing
         }
Index: /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElement.java
===================================================================
--- /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElement.java	(revision 2145)
+++ /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElement.java	(revision 2146)
@@ -14,4 +14,8 @@
 
 package de.ugoe.cs.autoquest.eventcore.guimodel;
+
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 public class MockGUIElement implements IGUIElement {
@@ -55,8 +59,13 @@
 
     @Override
-    public void updateSpecification(IGUIElementSpec furtherSpec) { }
+    public void updateSpecification(IEventTargetSpec furtherSpec) { }
 
     @Override
-    public void addEqualGUIElement(IGUIElement equalElement) { }
+    public IHierarchicalEventTargetModel<?> getEventTargetModel() {
+        return null;
+    }
+
+    @Override
+    public void addEqualEventTarget(IHierarchicalEventTarget equalElement) { }
 
     @Override
Index: /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElementSpec.java
===================================================================
--- /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-core-events-test/src/test/java/de/ugoe/cs/autoquest/eventcore/guimodel/MockGUIElementSpec.java	(revision 2146)
@@ -14,4 +14,6 @@
 
 package de.ugoe.cs.autoquest.eventcore.guimodel;
+
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 
 public class MockGUIElementSpec implements IGUIElementSpec {
@@ -31,5 +33,5 @@
 
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         return false;
     }
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/AbstractDefaultHierarchicalEventTarget.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/AbstractDefaultHierarchicalEventTarget.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/AbstractDefaultHierarchicalEventTarget.java	(revision 2146)
@@ -0,0 +1,270 @@
+//   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.LinkedList;
+import java.util.List;
+
+/**
+ * <p>
+ * Skeletal implementation for hierarchical event targets.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public abstract class AbstractDefaultHierarchicalEventTarget
+    implements IHierarchicalEventTarget
+{
+
+    /**
+     * <p>
+     * Id for object serialization.
+     * </p>
+     */
+    public static final long serialVersionUID = 1L;
+
+    /**
+     * <p>
+     * Specification of the event target
+     * </p>
+     */
+    private final IEventTargetSpec specification;
+
+    /**
+     * <p>
+     * Reference to the parent event target
+     * </p>
+     */
+    private IHierarchicalEventTarget parent;
+    
+    /**
+     * <p>
+     * List of other event targets being equal to this
+     * </p>
+     */
+    private List<AbstractDefaultHierarchicalEventTarget> equalEventTargets = null;
+
+    /**
+     * <p>
+     * the reference to the event target model to which this event target belongs.
+     * </p>
+     */
+    private HierarchicalEventTargetModel<?> eventTargetModel;
+    
+    /**
+     * <p>
+     * the hash code of this object
+     * </p>
+     */
+    private int hashCode;
+
+    /**
+     * <p>
+     * Constructor. Creates a new AbstractDefaultEventTarget.
+     * </p>
+     * 
+     * @param specification
+     *            specification of the created event target
+     * @param parent
+     *            parent of the created event target; null means the target is at top-level
+     */
+    public AbstractDefaultHierarchicalEventTarget(IEventTargetSpec         specification,
+                                                  IHierarchicalEventTarget parent)
+    {
+        this.specification = specification;
+        setParent(parent);
+        
+        if (specification != null) {
+            this.hashCode = specification.hashCode();
+        }
+        else {
+            this.hashCode = 0;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getSpecification()
+     */
+    @Override
+    public IEventTargetSpec getSpecification() {
+        return specification;
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getParent()
+     */
+    @Override
+    public IHierarchicalEventTarget getParent() {
+        return parent;
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#getEventTargetModel()
+     */
+    @Override
+    public HierarchicalEventTargetModel<?> getEventTargetModel()
+    {
+       return eventTargetModel;
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget#addEqualEventTarget(IHierarchicalEventTarget)
+     */
+    @Override
+    public void addEqualEventTarget(IHierarchicalEventTarget equalElement) {
+        if (!(equalElement instanceof AbstractDefaultHierarchicalEventTarget)) {
+            throw new IllegalArgumentException
+                ("this implementation can only handle other AbstractDefaultHierarchicalEventTargets");
+        }
+        
+        AbstractDefaultHierarchicalEventTarget other =
+            (AbstractDefaultHierarchicalEventTarget) equalElement;
+        
+        synchronized (AbstractDefaultHierarchicalEventTarget.class) {
+            if (this.equalEventTargets == null) {
+                if (other.equalEventTargets == null) {
+                    this.equalEventTargets = new LinkedList<AbstractDefaultHierarchicalEventTarget>();
+                    this.equalEventTargets.add(this);
+                    this.equalEventTargets.add(other);
+                    other.equalEventTargets = this.equalEventTargets;
+                    other.hashCode = this.hashCode;
+                }
+                else {
+                    addIfNotContained(other.equalEventTargets, this);
+                    this.equalEventTargets = other.equalEventTargets;
+                    this.hashCode = other.hashCode;
+                }
+            }
+            else {
+                if (other.equalEventTargets == null) {
+                    addIfNotContained(this.equalEventTargets, other);
+                    other.equalEventTargets = this.equalEventTargets;
+                    other.hashCode = this.hashCode;
+                }
+                else if (this.equalEventTargets != other.equalEventTargets) {
+                    this.equalEventTargets.addAll(other.equalEventTargets);
+
+                    // we also have to set this new list for all other elements for which so
+                    // far list2 was registered
+                    for (AbstractDefaultHierarchicalEventTarget candidate : other.equalEventTargets) {
+                        candidate.equalEventTargets = this.equalEventTargets;
+                        candidate.hashCode = this.hashCode;
+                    }
+
+                    other.equalEventTargets = this.equalEventTargets;
+                    other.hashCode = this.hashCode;
+                }
+                // else
+                // in this case, both GUI elements should already be registered with the same
+                // lists.
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public final boolean equals(Object other) {
+        // implement final, as hierarchical event targets are all singletons and they equal only
+        // if they are the same object or if they are in the list of equal event targets
+        if (super.equals(other)) {
+            return true;
+        }
+        else if (other instanceof AbstractDefaultHierarchicalEventTarget) {
+            synchronized (AbstractDefaultHierarchicalEventTarget.class) {
+                if (equalEventTargets != null) {
+                    for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) {
+                        if (candidate == other) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public final int hashCode() {
+        // implement final, as event targets are all singletons and they equal only if they are the
+        // same object. If there are several event target objects that represent the same event target
+        // then they are stored in the list of equal event target. But at least their type is expected
+        // to be equal, so return the hash code of the type.
+        return hashCode;
+    }
+    
+    /**
+     * <p>
+     * updates the parent node of this node if required due to model restructuring
+     * </p>
+     */
+    void setParent(IHierarchicalEventTarget newParent)
+    {
+        synchronized (AbstractDefaultHierarchicalEventTarget.class) {
+            // all equal event targets must have the same parent. Otherwise, they are not equal
+            // anymore and we would have discrepancies on the return value of getParent() on
+            // equal event targets.
+            this.parent = newParent;
+            if (equalEventTargets != null) {
+                for (AbstractDefaultHierarchicalEventTarget candidate : equalEventTargets) {
+                    candidate.parent = newParent;
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * used to set the event target model to which this event target belongs. Will be set
+     * automatically, if used in combination with {@link HierarchicalEventTargetModel};
+     * </p>
+     *
+     * @param eventTargetModel
+     * 
+     */
+    void setEventTargetModel(HierarchicalEventTargetModel<?> eventTargetModel) {
+        this.eventTargetModel = eventTargetModel;
+    }
+
+    /**
+     * <p>
+     * Adds an {@link AbstractDefaultHierarchicalEventTarget} as equal to a list of
+     * {@link AbstractDefaultHierarchicalEventTarget}s if and only if it is not already contained.
+     * </p>
+     * 
+     * @param equalTargetsList
+     *            list of {@link AbstractDefaultHierarchicalEventTarget} to which the event target
+     *            is added
+     * @param eventTarget
+     *            event target to be added
+     */
+    private void addIfNotContained(List<AbstractDefaultHierarchicalEventTarget> equalTargetsList,
+                                   AbstractDefaultHierarchicalEventTarget       eventTarget)
+    {
+        for (AbstractDefaultHierarchicalEventTarget candidate : equalTargetsList) {
+            if (candidate == eventTarget) {
+                return;
+            }
+        }
+
+        equalTargetsList.add(eventTarget);
+    }
+
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelConfigurationException.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelConfigurationException.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelConfigurationException.java	(revision 2146)
@@ -0,0 +1,82 @@
+//   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;
+
+/**
+ * <p>
+ * Exception that is thrown if there is a failure during the creation of an
+ * {@link IHierarchicalEventTarget} by the {@link IEventTargetFactory}.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public class EventTargetModelConfigurationException extends EventTargetModelException {
+
+    /**
+     * <p>
+     * Id for object serialization.
+     * </p>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelConfigurationException.
+     * </p>
+     */
+    public EventTargetModelConfigurationException() {
+        super();
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelConfigurationException.
+     * </p>
+     * 
+     * @param message
+     *            message of the exception
+     */
+    public EventTargetModelConfigurationException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelConfigurationException.
+     * </p>
+     * 
+     * @param cause
+     *            cause of the exception
+     */
+    public EventTargetModelConfigurationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelConfigurationException.
+     * </p>
+     * 
+     * @param message
+     *            message of the exception
+     * @param cause
+     *            cause of the exception
+     */
+    public EventTargetModelConfigurationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelException.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelException.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/EventTargetModelException.java	(revision 2146)
@@ -0,0 +1,81 @@
+//   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;
+
+/**
+ * <p>
+ * Exception that is thrown if there are problems with the {@link IHierarchicalEventTargetModel}.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public class EventTargetModelException extends Exception {
+
+    /**
+     * <p>
+     * Id for object serialization.
+     * </p>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelException.
+     * </p>
+     */
+    public EventTargetModelException() {
+        super();
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelException.
+     * </p>
+     * 
+     * @param message
+     *            message of the exception
+     */
+    public EventTargetModelException(String message) {
+        super(message);
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelException.
+     * </p>
+     * 
+     * @param cause
+     *            cause of the exception
+     */
+    public EventTargetModelException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * <p>
+     * Constructor. Creates a new EventTargetModelException.
+     * </p>
+     * 
+     * @param message
+     *            message of the exception
+     * @param cause
+     *            cause of the exception
+     */
+    public EventTargetModelException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetGroup.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetGroup.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetGroup.java	(revision 2146)
@@ -0,0 +1,167 @@
+//   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.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * <p>
+ * This class is a dummy hierarchical event target to represent groups of event targets. A group of
+ * event targets can be integrated in any hierarchical event target model using the method
+ * {@link HierarchicalEventTargetModel#groupEventTargets(List, String, IEventTargetFactory)}. A
+ * group has the same behavior as any other parent hierarchical event target.
+ * </p>
+ * 
+ * @author Patrick Harms
+ */
+public class HierarchicalEventTargetGroup extends AbstractDefaultHierarchicalEventTarget {
+
+    /**
+     * <p>
+     * default serial version UID
+     * </p>
+     */
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * the list of grouped event targets
+     */
+    private List<IHierarchicalEventTarget> groupedEventTargets =
+        new LinkedList<IHierarchicalEventTarget>();
+
+    /**
+     * <p>
+     * instantiates an event target group with a name and its optional parent event target
+     * </p>
+     *
+     * @param groupName        the name of the event target group
+     * @param parent           the optional parent event target of the group
+     * @param eventTargetModel the event target model to which the group will belong
+     */
+    public HierarchicalEventTargetGroup(String                          groupName,
+                                        IHierarchicalEventTarget        parent,
+                                        HierarchicalEventTargetModel<?> eventTargetModel)
+    {
+        super(new GroupSpecification(groupName), parent);
+        super.setEventTargetModel(eventTargetModel);
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IEventTarget#getPlatform()
+     */
+    @Override
+    public String getPlatform() {
+        return "none";
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.IEventTarget#getStringIdentifier()
+     */
+    @Override
+    public String getStringIdentifier() {
+        return ((GroupSpecification) super.getSpecification()).name;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return getStringIdentifier();
+    }
+
+    /* (non-Javadoc)
+     * @see IHierarchicalEventTarget#updateSpecification(IEventTargetSpec)
+     */
+    @Override
+    public void updateSpecification(IEventTargetSpec furtherSpec) {
+        // do nothing
+    }
+
+    /**
+     * <p>
+     * returns the list of event targets belonging to this group.
+     * </p>
+     * 
+     * @return the event targets belonging to this group
+     * 
+     */
+    public List<IHierarchicalEventTarget> getGroupedEventTargets() {
+        return Collections.unmodifiableList(groupedEventTargets);
+    }
+    
+    /**
+     * <p>
+     * allows adding a new event target to the group
+     * </p>
+     *
+     * @param eventTarget the new member of the group
+     */
+    void addToGroup(IHierarchicalEventTarget eventTarget) {
+        this.groupedEventTargets.add(eventTarget);
+    }
+    
+    /**
+     * <p>
+     * internally required event target specification for an event target group. This is just a
+     * wrapper for a name of an event target group
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private static class GroupSpecification implements IEventTargetSpec {
+        
+        /**
+         * <p>
+         * default serial version UID
+         * </p>
+         */
+        private static final long serialVersionUID = 1L;
+        
+        /**
+         * <p>
+         * the name of the event target group represented by this specification
+         * </p>
+         */
+        private String name;
+
+        /**
+         * <p>
+         * instantiates the group specification with the given name. Two group specifications
+         * are only similar, if their names match.
+         * </p>
+         *
+         * @param name the name of the group
+         */
+        private GroupSpecification(String name) {
+            super();
+            this.name = name;
+        }
+
+        /* (non-Javadoc)
+         * @see IEventTargetSpec#getSimilarity(IEventTargetSpec)
+         */
+        @Override
+        public boolean getSimilarity(IEventTargetSpec other) {
+            return
+                (other instanceof GroupSpecification) &&
+                name.equals(((GroupSpecification) other).name);
+        }
+
+    }
+
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetModel.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetModel.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/HierarchicalEventTargetModel.java	(revision 2146)
@@ -0,0 +1,995 @@
+//   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.io.OutputStream;
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.logging.Level;
+
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * A hierarchical event target model is a tree of {@link IHierarchicalEventTarget}s and represents
+ * a complete user interface, e.g. GUI of a software. It is platform independent. It may have
+ * several root nodes, as some user interfaces are made up of several frames (GUI) or scenes (VR)
+ * being independent from each other. The event target model is filled using the
+ * {@link #integratePath(List, IEventTargetFactory)} method.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms, Steffen Herbold
+ */
+public class HierarchicalEventTargetModel<T extends IHierarchicalEventTarget>
+     implements Serializable, IHierarchicalEventTargetModel<T>
+{
+
+    /**  */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * <p>
+     * The root node of the tree not provided externally.
+     * </p>
+     */
+    private TreeNode root = new TreeNode();
+
+    /**
+     * <p>
+     * A map with all nodes currently known
+     * </p>
+     */
+    private Map<T, TreeNode> allNodes = new HashMap<T, TreeNode>();
+    
+    /**
+     * <p>
+     * true, if internal validation is switched on, false else
+     * </p>
+     */
+    private boolean validate = false;
+
+    /**
+     * <p>
+     * Default constructor to create a event target model without internal validation
+     * </p>
+     *
+     */
+    public HierarchicalEventTargetModel() {
+        this(false);
+    }
+
+    /**
+     * <p>
+     * creates an event target model, that internally validates itself by checking on access to
+     * nodes, if several event targets pretend to be equal or if several distinct event targets
+     * have the same child.
+     * </p>
+     *
+     * @param validate
+     *            true if internal validation shall be switched on (bad performance), false else
+     *
+     */
+    public HierarchicalEventTargetModel(boolean validate) {
+        this.validate = validate;
+    }
+
+    /**
+     * <p>
+     * Integrates a path of event targets into the event target model. The event target model
+     * itself is a tree and therefore a set of different paths through the tree that start with
+     * a root node and end with a leaf node. Such a path can be added to the tree. The method
+     * checks, if any of the event targets denoted by the path already exists. If so, it reuses it.
+     * It may therefore also return an existing event target being the leaf node of the provided
+     * path. If an event target of the path does not exist yet, it creates a new one using the
+     * provided event target factory.
+     * </p>
+     * <p>
+     * If an event target specification describes an existing event target or not is determined
+     * through comparing the event target specifications of the existing event targets with the
+     * ones provided in the path. The comparison is done using the
+     * {@link IEventTargetSpec#getSimilarity(IEventTargetSpec)} method. The comparison is only done
+     * on the correct levels. I.e. the currently known root elements of the tree are only compared
+     * to the first element in the path. If the correct one is found or created, its children are
+     * compared only to the second specification in the path, and so on.
+     * </p>
+     * <p>
+     * The returned event targets are singletons. I.e. it is tried to return always the identical
+     * object for the same denoted element. However, while creating the event target model, the
+     * similarity of event targets may change. Therefore, the method might determine, that two
+     * formerly different nodes are now similar. (This may happen, e.g. if event targets do not
+     * have initial names which are set afterwards. Therefore, first they are handled differently
+     * and later they can be identified as being the same.) In such a case, there are already
+     * several event target objects instantiated for the same event target. The singleton paradigm
+     * gets broken. Therefore, such event target objects are registered with each other, so that
+     * their equal method can determine equality again correctly, although the objects are no
+     * singletons anymore.
+     * </p>
+     * 
+     * @param eventTargetPath
+     *            the path to integrate into the model
+     * @param eventTargetFactory
+     *            the event target factory to be used for instantiating event target objects
+     * 
+     * @return The event target object representing the event target denoted by the provided path
+     * 
+     * @throws EventTargetModelException
+     *             thrown in cases such as the event target object could not be instantiated
+     * @throws IllegalArgumentException
+     *             if the provided path is invalid.
+     */
+    public T integratePath(List<? extends IEventTargetSpec> eventTargetPath,
+                           IEventTargetFactory              eventTargetFactory)
+        throws EventTargetModelException, IllegalArgumentException
+    {
+        if ((eventTargetPath == null) || (eventTargetPath.size() <= 0)) {
+            throw new IllegalArgumentException("event target path must contain at least one element");
+        }
+
+        List<IEventTargetSpec> remainingPath = new LinkedList<IEventTargetSpec>(eventTargetPath);
+
+        return (T) integratePath(root, remainingPath, eventTargetFactory);
+    }
+
+    /* (non-Javadoc)
+     * @see IEventTargetModel#getChildren(IEventTarget)
+     */
+    @Override
+    public List<T> getChildren(T eventTarget) {
+        TreeNode node = findNode(eventTarget);
+        
+        List<T> result = null;
+        if (node != null) {
+            result = new LinkedList<T>();
+            if (node.children != null) {
+                for (TreeNode child : node.children) {
+                    result.add((T) child.eventTarget);
+                }
+            }
+        }
+        else {
+            boolean found = false;
+            for (Map.Entry<T, TreeNode> entry : allNodes.entrySet()) {
+                if (entry.getKey().equals(eventTarget)) {
+                    if (!found) {
+                        System.out.println(eventTarget.hashCode() + "  " + entry.getKey().hashCode());
+                        found = true;
+                    }
+                    else {
+                        Console.traceln(Level.SEVERE, "Multiple nodes in the internal event " +
+                                        "target model match the same event target. This should " +
+                                        "not be the case and the event target model is probably " +
+                                        "invalid.");
+                    }
+                }
+            }
+            
+            if (!found) {
+                Console.traceln(Level.SEVERE, "event target belonging to model not found in model");
+            }
+        }
+ 
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see IEventTargetModel#getParent(IEventTarget)
+     */
+    @Override
+    public T getParent(T eventTarget) {
+        T parent = null;
+
+        for (Map.Entry<T, TreeNode> entry : allNodes.entrySet()) {
+            if (entry.getValue().children != null) {
+                for (TreeNode child : entry.getValue().children) {
+                    if (child.eventTarget.equals(eventTarget)) {
+                        if (parent == null) {
+                            parent = entry.getKey();
+                            if (!validate) {
+                                break;
+                            }
+                        }
+                        else {
+                            Console
+                            .traceln(Level.SEVERE,
+                                     "Multiple nodes in the internal event target model match " +
+                                     "the same event target. This should not be the case and the " +
+                                     "event target model is probably invalid.");
+                        }
+                    }
+                }
+            }
+        }
+
+        return parent;
+    }
+
+    /* (non-Javadoc)
+     * @see IEventTargetModel#getRootElements()
+     */
+    @Override
+    public List<T> getRootElements() {
+        List<T> roots = new ArrayList<T>();
+
+        if (root.children != null) {
+            for (TreeNode rootChild : root.children) {
+                roots.add(rootChild.eventTarget);
+            }
+        }
+
+        return roots;
+    }
+    
+    /**
+     * returns a traverser for the event target model to have efficient access to the tree of event
+     * targets without having direct access.
+     * 
+     * @return a traverser
+     */
+    @Override
+    public Traverser getTraverser() {
+        return new Traverser();
+    }
+
+    /**
+     * returns a traverser for the event target model starting at the given event target. Returns
+     * null, if the event target is not part of the model.
+     * 
+     * @return a traverser
+     */
+    @Override
+    public Traverser getTraverser(T startingAt) {
+        TreeNode node = findNode(startingAt);
+        
+        if (node != null) {
+            Traverser traverser = new Traverser();
+            traverser.navigateTo(node);
+            return traverser;
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * <p>
+     * dumps the event target model to the provided stream. Each node is represented through its
+     * toString() method. If a node has children, those are dumped indented and surrounded by
+     * braces.
+     * </p>
+     * 
+     * @param out
+     *            The stream to dump the textual representation of the model to
+     * @param encoding
+     *            The encoding to be used while dumping
+     */
+    public void dump(OutputStream out, String encoding) {
+        PrintStream stream;
+
+        if (out instanceof PrintStream) {
+            stream = (PrintStream) out;
+        }
+        else {
+            String enc = encoding == null ? "UTF-8" : encoding;
+            try {
+                stream = new PrintStream(out, true, enc);
+            }
+            catch (UnsupportedEncodingException e) {
+                throw new IllegalArgumentException("encodind " + enc + " not supported");
+            }
+        }
+
+        for (TreeNode node : root.children) {
+            dumpeventTarget(stream, node, "");
+        }
+    }
+
+    /**
+     * <p>
+     * This method groups the provided event targets under a common parent event target. The current
+     * parent event target of the event targets to group must be the same. If the event targets to
+     * be grouped are the whole list of children of the same parent, nothing is changed. 
+     * </p>
+     * 
+     * @param eventTargets       the list of event targets to be grouped
+     * @param groupName          the name of the event target group to be created
+     * @param eventTargetFactory the event target factory used for creating a group of the correct
+     *                           type (ensures, that all elements in the model can have T in their
+     *                           parent hierarchy)
+     * 
+     * @return the event target representing the group, or null, if the provided list of event
+     *         targets is empty
+     * 
+     * @throws IllegalArgumentException
+     *             if not all event targets to be merged share the same parent, if one of the
+     *             parameters is null, or if one of the provided event targets does not belong to
+     *             the model
+     */
+    public T groupEventTargets(List<T>             eventTargets,
+                               String              groupName,
+                               IEventTargetFactory eventTargetFactory)
+        throws IllegalArgumentException
+    {
+        if ((eventTargets == null) || (groupName == null) || (eventTargetFactory == null)) {
+            throw new IllegalArgumentException("parameters must not be null");
+        }
+        
+        if (eventTargets.size() <= 0) {
+            // do nothing
+            return null;
+        }
+        
+        TreeNode parent = findNode(eventTargets.get(0).getParent());
+        if (parent == null) {
+            throw new IllegalArgumentException("event targets to group must have a parent: " +
+                                               "parent of " + eventTargets.get(0) + " is " +
+                                               eventTargets.get(0).getParent() + " and not found " +
+                                               "in the model");
+        }
+        
+        List<TreeNode> nodesToGroup = new LinkedList<TreeNode>();
+        
+        for (IHierarchicalEventTarget element : eventTargets) {
+            if (!(element instanceof AbstractDefaultHierarchicalEventTarget)) {
+                throw new IllegalArgumentException
+                    ("can only group nodes of type AbstractDefaultHierarchicalEventTarget");
+            }
+            
+            TreeNode node = findNode(element);
+            if (node == null) {
+                throw new IllegalArgumentException
+                    ("event target " + element + " is not part of the model");
+            }
+            
+            if (!nodesToGroup.contains(node)) {
+                nodesToGroup.add(node);
+            }
+            
+            TreeNode parentNode = findNode(element.getParent());
+            
+            if (!parent.equals(parentNode)) {
+                throw new IllegalArgumentException("event targets do not share the same parent: " +
+                                                   parent + " (parent of " + eventTargets.get(0) +
+                                                   ") <> " + parentNode + " (parent of " +
+                                                   element + ")");
+            }
+        }
+        
+        TreeNode replacement = new TreeNode();
+        replacement.eventTarget =
+            eventTargetFactory.instantiateGroup(groupName, parent.eventTarget, this);
+        
+        if (!(replacement.eventTarget instanceof HierarchicalEventTargetGroup)) {
+            throw new IllegalArgumentException("factory does not instantiate an object of type " +
+                                               "HierarchicalEventTargetGroup which is required " +
+                                               "for performing the merge");
+        }
+        
+        for (TreeNode child : nodesToGroup) {
+            ((HierarchicalEventTargetGroup) replacement.eventTarget).addToGroup(child.eventTarget);
+            replacement.addChildNode(child);
+            ((AbstractDefaultHierarchicalEventTarget) child.eventTarget).setParent
+                (replacement.eventTarget);
+            parent.children.remove(child);
+        }
+
+        parent.children.add(replacement);
+
+        // finally, update the known nodes list
+        // if you don't do this getChildren will return wrong things and very bad things happen!
+        allNodes.put(replacement.eventTarget, replacement);
+        
+        return (T) replacement.eventTarget;
+    }
+    
+    /**
+     * <p>
+     * By calling this method, the event target model is traversed and similar nodes are merged.
+     * </p>
+     * 
+     */
+    public void condenseModel() {
+        mergeSubTree(root);
+    }
+    
+    /**
+     * <p>
+     * Merges the tree nodes of two event targets. The event targets need to have the same parent.
+     * They are merged recursively, i.e. also their children are merged. 
+     * </p>
+     * 
+     * @param eventTarget1
+     *            the first merge event target
+     * @param eventTarget2
+     *            the second merge event target
+     *            
+     * @return the result of the merge
+     *            
+     * @throws IllegalArgumentException
+     *             thrown if the two event targets do not have the same parent
+     */
+    public T mergeEventTargets(T eventTarget1, T eventTarget2) throws IllegalArgumentException
+    {
+        return mergeEventTargets(eventTarget1, eventTarget2, true);
+    }
+    
+    /**
+     * <p>
+     * Merges the tree nodes of two event targets. The event targets need to have the same parent.
+     * If the <code>recursively</code> parameter is set to true, the children of the event targets
+     * are merged, as well, as long as they are similar. If the parameter is false, the children
+     * are not merged. In this case the resulting event target has all children of both merged
+     * event targets.
+     * </p>
+     * 
+     * @param eventTarget1
+     *            the first merge event target
+     * @param eventTarget2
+     *            the second merge event target
+     * @param recursively
+     *            if true, the merge is done also for similar children, if false, not.
+     *            
+     * @return the result of the merge
+     *            
+     * @throws IllegalArgumentException
+     *             thrown if the two event targets do not have the same parent
+     */
+    public T mergeEventTargets(T eventTarget1, T eventTarget2, boolean recursively)
+        throws IllegalArgumentException
+    {
+        // check if both nodes have the same parent
+        T parentElement = getParent(eventTarget1);
+        boolean sameParent = (parentElement != null) ?
+            parentElement.equals(eventTarget2.getParent()) : (eventTarget2.getParent() == null);
+            
+        if (!sameParent) {
+            throw new IllegalArgumentException("can only merge nodes with the same parent");
+        }
+
+        // get the TreeNode of the parent of the event targets
+        TreeNode parent = findNode(parentElement);
+        
+        if ((parent == null) && (parentElement == null)) {
+            // merging root nodes. The parent is the root node of the event target tree
+            parent = root;
+        }
+
+        // get the TreeNodes for both event targets
+        TreeNode node1 = findNode(eventTarget1);
+        TreeNode node2 = findNode(eventTarget2);
+
+        if (node1 == null || node2 == null) {
+            throw new IllegalArgumentException
+                ("Error while merging nodes: one element is not part of the event target model!");
+        }
+
+        TreeNode replacement = mergeTreeNodes(node1, node2, recursively);
+
+        if (parent != null) {
+            // remove node1 and node2 from the parent's children and add the replacement instead
+            // assumes that there are no duplicates of node1 and node2
+            if (parent.children != null) {
+                parent.children.set(parent.children.indexOf(node1), replacement);
+                parent.children.remove(node2);
+            }
+        }
+
+        return replacement.eventTarget;
+    }
+
+    /**
+     * <p>
+     * internally integrates a path as the children of the provided parent node. This method is
+     * recursive and calls itself, for the child of the parent node, that matches the first element
+     * in the remaining path.
+     * </p>
+     * 
+     * @param parentNode
+     *            the parent node to add children for
+     * @param eventTargetPath
+     *            the path of children to be created starting with the parent node
+     * @param eventTargetFactory
+     *            the event target factory to be used for instantiating event target objects
+     * 
+     * @return The event target object representing the event target denoted by the provided path
+     * 
+     * @throws EventTargetModelException
+     *             thrown in cases such as the event target object could not be instantiated
+     */
+    private T integratePath(TreeNode               parentNode,
+                            List<IEventTargetSpec> remainingPath,
+                            IEventTargetFactory    eventTargetFactory)
+        throws EventTargetModelException
+    {
+        IEventTargetSpec specToIntegrateElementFor = remainingPath.remove(0);
+
+        TreeNode child = findEqualChild(parentNode, specToIntegrateElementFor);
+        if (child == null) {
+            T newElement = eventTargetFactory.instantiateEventTarget(specToIntegrateElementFor,
+                                                                     parentNode.eventTarget);
+
+            if (newElement instanceof AbstractDefaultHierarchicalEventTarget) {
+                ((AbstractDefaultHierarchicalEventTarget) newElement).setEventTargetModel(this);
+            }
+            
+            child = parentNode.addChild(newElement);
+            allNodes.put(child.eventTarget, child);
+        }
+
+        if (remainingPath.size() > 0) {
+            return integratePath(child, remainingPath, eventTargetFactory);
+        }
+        else {
+            return child.eventTarget;
+        }
+    }
+
+    /**
+     * <p>
+     * Searches the children of a tree node to see if the {@link IEventTargetSpec} equals the
+     * specification of the {@link TreeNode#eventTarget} of the child. If a match is found, the
+     * child is returned.
+     * </p>
+     * 
+     * @param parentNode
+     *            parent node whose children are searched
+     * @param specToMatch
+     *            specification that is searched for
+     * 
+     * @return matching child node or null if no child matches
+     */
+    private TreeNode findEqualChild(TreeNode parentNode, IEventTargetSpec specToMatch) {
+        if (parentNode.children != null) {
+            for (TreeNode child : parentNode.children) {
+                if (specToMatch.equals(child.eventTarget.getSpecification())) {
+                    return child;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * <p>
+     * Merges all similar nodes in the sub-tree of the event target model defined by the
+     * subTreeRoot.
+     * </p>
+     * <p>
+     * The merging order is a bottom-up. This means, that we first call mergeSubTree recursively for
+     * the grand children of the subTreeRoot, before we merge subTreeRoot.
+     * </p>
+     * <p>
+     * The merging strategy is top-down. This means, that every time we merge two child nodes, we
+     * call mergeSubTree recursively for all children of the merged nodes in order to check if we
+     * can merge the children, too.
+     * </p>
+     * 
+     * @param subTreeRoot
+     *            root node of the sub-tree that is merged
+     */
+    private void mergeSubTree(TreeNode subTreeRoot) {
+        if (subTreeRoot.children == null || subTreeRoot.children.isEmpty()) {
+            return;
+        }
+
+        // lets first merge the grand children of the parentNode
+        for (TreeNode child : subTreeRoot.children) {
+            mergeSubTree(child);
+        }
+
+        boolean performedMerge;
+
+        do {
+            performedMerge = false;
+            for (int i = 0; !performedMerge && i < subTreeRoot.children.size(); i++) {
+                IEventTargetSpec elemSpec1 =
+                    subTreeRoot.children.get(i).eventTarget.getSpecification();
+                for (int j = i + 1; !performedMerge && j < subTreeRoot.children.size(); j++) {
+                    IEventTargetSpec elemSpec2 =
+                        subTreeRoot.children.get(j).eventTarget.getSpecification();
+                    if (elemSpec1.getSimilarity(elemSpec2)) {
+                        TreeNode replacement = mergeTreeNodes
+                            (subTreeRoot.children.get(i), subTreeRoot.children.get(j), true);
+
+                        subTreeRoot.children.set(i, replacement);
+                        subTreeRoot.children.remove(j);
+                        performedMerge = true;
+                        i--;
+                        break;
+                    }
+                }
+            }
+        }
+        while (performedMerge);
+    }
+
+    /**
+     * <p>
+     * merges two nodes with each other. Merging means registering the event target objects with
+     * each other for equality checks. Further it adds all children of both nodes to a new
+     * replacing node. Afterwards, all similar nodes of the replacement node are merged as well as
+     * long the recursive parameter is set to true.
+     * </p>
+     * 
+     * @param treeNode1
+     *            the first of the two nodes to be merged
+     * @param treeNode2
+     *            the second of the two nodes to be merged
+     * @param recursively
+     *            if true, the merging also merges child nodes
+     *            
+     * @return a tree node being the merge of the two provided nodes.
+     */
+    private TreeNode mergeTreeNodes(TreeNode treeNode1, TreeNode treeNode2, boolean recursively) {
+        // and now a replacement node that is the merge of treeNode1 and treeNode2 is created
+        TreeNode replacement = new TreeNode();
+        replacement.eventTarget = treeNode1.eventTarget;
+        if (treeNode1.children != null) {
+            for (TreeNode child : treeNode1.children) {
+                replacement.addChildNode(child);
+            }
+        }
+        if (treeNode2.children != null) {
+            for (TreeNode child : treeNode2.children) {
+                replacement.addChildNode(child);
+            }
+        }
+
+        if (recursively) {
+            mergeSubTree(replacement);
+        }
+
+        replacement.eventTarget.updateSpecification(treeNode2.eventTarget.getSpecification());
+
+        // finally, update the known nodes list
+        // if you don't do this getChildren will return wrong things and very bad things happen!
+        allNodes.remove(treeNode1.eventTarget);
+        allNodes.remove(treeNode2.eventTarget);
+
+        // the following two lines are needed to preserve the references to the existing event
+        // targets. If two elements are the same, one should be deleted to make the elements
+        // singletons again. However, there may exist references to both objects. To preserve
+        // these, we simply register the equal event targets with each other so that an equals
+        // check can return true.
+        treeNode1.eventTarget.addEqualEventTarget(treeNode2.eventTarget);
+        treeNode2.eventTarget.addEqualEventTarget(treeNode1.eventTarget);
+        
+        allNodes.put(replacement.eventTarget, replacement);
+        
+        return replacement;
+    }
+
+    /**
+     * <p>
+     * dumps an event target to the stream. A dump contains the toString() representation of the
+     * event target as well as an indented list of its children surrounded by braces. Therefore,
+     * not the event target itself but its tree node is provided to have an efficient access to its
+     * children
+     * </p>
+     * 
+     * @param out
+     *            {@link PrintStream} where the eventTarget is dumped to
+     * @param node
+     *            the eventTarget's tree node of which the string representation is dumped
+     * @param indent
+     *            indent string of the dumping
+     */
+    private void dumpeventTarget(PrintStream out, TreeNode node, String indent) {
+        out.print(indent);
+        out.print(node.eventTarget);
+
+        if ((node.children != null) && (node.children.size() > 0)) {
+            out.println(" {");
+
+            for (TreeNode child : node.children) {
+                dumpeventTarget(out, child, indent + "  ");
+            }
+
+            out.print(indent);
+            out.print("}");
+        }
+
+        out.println();
+    }
+    
+    /**
+     * <p>
+     * Retrieves the TreeNode associated with an event target. Returns null if no such TreeNode is
+     * found.
+     * </p>
+     * 
+     * @param element
+     *            the event target
+     * 
+     * @return associated TreeNode; null if no such node exists
+     */
+    private TreeNode findNode(IEventTarget element) {
+        if (element == null) {
+            return null;
+        }
+
+        TreeNode result = null;
+        
+        if (!validate) {
+            result = allNodes.get(element);
+        }
+        else {
+            for (Map.Entry<T, TreeNode> entry : allNodes.entrySet()) {
+                if (entry.getKey().equals(element)) {
+                    if (result == null) {
+                        result = entry.getValue();
+                    }
+                    else {
+                        Console.traceln(Level.SEVERE, "Multiple nodes in the internal event " +
+                                        "target model match the same event target. This should " +
+                                        "not be the case and the event target model is probably " +
+                                        "invalid.");
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Used externally for tree traversal without providing direct access to the tree nodes
+     * </p>
+     * 
+     * @version 1.0
+     * @author Patrick Harms, Steffen Herbold
+     */
+    private class Traverser implements IHierarchicalEventTargetModel.Traverser<T> {
+        
+        /**
+         * <p>
+         * the stack of nodes on which the traverser currently works
+         * </p>
+         */
+        private Stack<StackEntry> nodeStack = new Stack<StackEntry>();
+        
+        /**
+         * <p>
+         * initializes the traverser by adding the root node of the event target model to the stack
+         * </p>
+         */
+        private Traverser() {
+            nodeStack.push(new StackEntry(root, 0));
+        }
+        
+        /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.guimodel.Traverser#firstChild()
+         */
+        @Override
+        public T firstChild() {
+            return pushChild(0);
+        }
+        
+        /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.guimodel.Traverser#hasFirstChild()
+         */
+        @Override
+        public boolean hasFirstChild() {
+            return
+                (nodeStack.peek().treeNode.children != null) &&
+                (nodeStack.peek().treeNode.children.size() > 0);
+        }
+        
+        /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.guimodel.Traverser#nextSibling()
+         */
+        @Override
+        public T nextSibling() {
+            int lastIndex = nodeStack.pop().index;
+            
+            T retval = pushChild(lastIndex + 1);
+            if (retval == null) {
+                pushChild(lastIndex);
+            }
+            
+            return retval;
+        }
+        
+        /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.guimodel.Traverser#hasNextSibling()
+         */
+        @Override
+        public boolean hasNextSibling() {
+            boolean result = false;
+            if (nodeStack.size() > 1) {
+                StackEntry entry = nodeStack.pop();
+                result = nodeStack.peek().treeNode.children.size() > (entry.index + 1);
+                pushChild(entry.index);
+            }
+            
+            return result;
+        }
+        
+        /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.guimodel.Traverser#parent()
+         */
+        @Override
+        public T parent() {
+            T retval = null;
+            
+            if (nodeStack.size() > 1) {
+                nodeStack.pop();
+                retval = nodeStack.peek().treeNode.eventTarget;
+            }
+            
+            return retval;
+        }
+        
+        /**
+         * <p>
+         * internal method used for changing the state of the traverser. I.e. to switch to a
+         * specific child event target of the current one.
+         * </p>
+         */
+        private T pushChild(int index) {
+            T retVal = null;
+            
+            if ((nodeStack.peek().treeNode.children != null) &&
+                (nodeStack.peek().treeNode.children.size() > index))
+            {
+                nodeStack.push
+                    (new StackEntry(nodeStack.peek().treeNode.children.get(index), index));
+                retVal = nodeStack.peek().treeNode.eventTarget;
+            }
+            
+            return retVal;
+        }
+        
+        /**
+         * <p>
+         * navigates the traverser to the given node in the event target model
+         * </p>
+         */
+        private boolean navigateTo(TreeNode node) {
+            if (hasFirstChild()) {
+                T childElement = firstChild();
+            
+                while (childElement != null) {
+                    if (childElement.equals(node.eventTarget)) {
+                        return true;
+                    }
+                    else if (navigateTo(node)) {
+                        return true;
+                    }
+                    else {
+                        childElement = nextSibling();
+                    }
+                }
+            
+                parent();
+            }
+            
+            return false;
+        }
+
+        /**
+         * <p>
+         * internal class needed to fill the stack with nodes of the event target models and their
+         * respective index in the children of the parent node.
+         * </p>
+         */
+        private class StackEntry {
+            
+            /** */
+            private TreeNode treeNode;
+            
+            /** */
+            private int index;
+            
+            /**
+             * <p>
+             * creates a new stack entry.
+             * </p>
+             */
+            private StackEntry(TreeNode treeNode, int index) {
+                this.treeNode = treeNode;
+                this.index = index;
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Used internally for building up the tree of event targets.
+     * </p>
+     * 
+     * @version 1.0
+     * @author Patrick Harms, Steffen Herbold
+     */
+    private class TreeNode implements Serializable {
+
+        /**  */
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * <p>
+         * event target associated with the TreeNode.
+         * </p>
+         */
+        private T eventTarget;
+
+        /**
+         * <p>
+         * Children of the TreeNode.
+         * </p>
+         */
+        private List<TreeNode> children;
+
+        /**
+         * <p>
+         * Adds a child to the current node while keeping all lists of nodes up to date
+         * </p>
+         * 
+         * @param eventTarget
+         *            event target that will be associated with the new child
+         *            
+         * @return the added child
+         */
+        private TreeNode addChild(T eventTarget) {
+            if (children == null) {
+                children = new ArrayList<TreeNode>();
+            }
+
+            TreeNode child = new TreeNode();
+            child.eventTarget = eventTarget;
+            children.add(child);
+
+            return child;
+        }
+
+        /**
+         * 
+         * <p>
+         * Adds a TreeNode as child to the current node. This way, the whole sub-tree is added.
+         * </p>
+         * 
+         * @param node
+         *            child node that is added
+         *            
+         * @return node that has been added
+         */
+        private TreeNode addChildNode(TreeNode node) {
+            if (children == null) {
+                children = new ArrayList<TreeNode>();
+            }
+            children.add(node);
+            return node;
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return eventTarget.toString();
+        }
+
+    }
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTarget.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTarget.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTarget.java	(revision 2146)
@@ -20,5 +20,5 @@
  * <p>
  * Common interface for event targets. An event target can, e.g., be an element of a GUI or Web
- * server. A concrete event-driven software platform can define its event targets through the
+ * server or VR. A concrete event-driven software platform can define its event targets through the
  * implementation of this interface.
  * </p>
@@ -47,3 +47,4 @@
      */
     public String getStringIdentifier();
+
 }
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetFactory.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetFactory.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetFactory.java	(revision 2146)
@@ -0,0 +1,64 @@
+//   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;
+
+/**
+ * <p>
+ * Common interface for event target factories. They are used while constructing hierarchical
+ * event target models.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public interface IEventTargetFactory {
+
+    /**
+     * <p>
+     * Instantiates a new {@link IHierarchicalEventTarget} from a given specification.
+     * </p>
+     * 
+     * @param specification
+     *            specification of the new event target
+     * @param parent
+     *            parent of the new event target
+     *            
+     * @return created event target
+     * 
+     * @throws EventTargetModelConfigurationException
+     *             thrown if there is a problem during the creation of the event target
+     */
+    public <T extends IHierarchicalEventTarget> T instantiateEventTarget(IEventTargetSpec specification,
+                                                                         T                parent)
+        throws EventTargetModelConfigurationException;
+
+    /**
+     * <p>
+     * Instantiates a new {@link IHierarchicalEventTarget} that represents a group of event targets.
+     * The returned object is defined to implement the interface but it must also derive from
+     * {@link HierarchicalEventTargetGroup}. This is to ensure type consistency in an event target
+     * model but to also allow simple group creations. 
+     * </p>
+     *
+     * @param groupName                    the name of the group to be created
+     * @param parent                       the parent element of the group
+     * @param hierarchicalEventTargetModel the model to which the group will belong
+     * @return
+     */
+    public <T extends IHierarchicalEventTarget> T instantiateGroup(String                          groupName,
+                                                                   T                               parent,
+                                                                   HierarchicalEventTargetModel<T> hierarchicalEventTargetModel);
+    
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetSpec.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetSpec.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IEventTargetSpec.java	(revision 2146)
@@ -0,0 +1,61 @@
+//   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.io.Serializable;
+
+/**
+ * <p>
+ * Common interface for event target specifications.
+ * </p>
+ * 
+ * @version 1.1
+ * @author Patrick Harms, Steffen Herbold
+ */
+public interface IEventTargetSpec extends Serializable {
+
+    /**
+     * <p>
+     * Evaluates if two event target specifications are similar. Similar means that a heuristic
+     * determines that the two event target specifications describe the same event target.
+     * </p>
+     * 
+     * @param other
+     *            specification whose similarity to this is evaluated
+     *            
+     * @return true if the specifications are similar; false otherwise
+     */
+    public boolean getSimilarity(IEventTargetSpec other);
+
+    /**
+     * <p>
+     * Defines that {@link IEventTargetSpec} implementations have to define equals.
+     * </p>
+     * 
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object other);
+
+    /**
+     * <p>
+     * Defines that {@link IEventTargetSpec} implementations have to define hashCode.
+     * </p>
+     * 
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode();
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTarget.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTarget.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTarget.java	(revision 2146)
@@ -0,0 +1,80 @@
+//   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.io.Serializable;
+
+/**
+ * <p>
+ * Common interface for event targets. An event target can, e.g., be an element of a GUI or Web
+ * server or a VR. A concrete event-driven software platform can define its event targets through
+ * the implementation of this interface. This type of event target differ from those of the parent
+ * type in that they can build tree structures such as a {@link IHierarchicalEventTargetModel}
+ * </p>
+ * 
+ * @version 1.0
+ * @author Steffen Herbold
+ */
+public interface IHierarchicalEventTarget extends IEventTarget, Serializable {
+    
+    /**
+     * <p>
+     * Returns the parent of the event target.
+     * </p>
+     * 
+     * @return the parent
+     */
+    public IHierarchicalEventTarget getParent();
+
+    /**
+     * <p>
+     * Returns the specification of the event target.
+     * </p>
+     * 
+     * @return the specification
+     */
+    public IEventTargetSpec getSpecification();
+
+    /**
+     * <p>
+     * Updates the specification of a event target with another specification, e.g., to add further
+     * known names of the event target.
+     * </p>
+     * 
+     * @param furtherSpec
+     *            additional specification
+     */
+    public void updateSpecification(IEventTargetSpec furtherSpec);
+
+    /**
+     * <p>
+     * returns the event target model to which this event target belongs (if any).
+     * </p>
+     *
+     * @return as described
+     */
+    public IHierarchicalEventTargetModel<? extends IHierarchicalEventTarget> getEventTargetModel();
+
+    /**
+     * <p>
+     * The {@link IHierarchicalEventTarget} that is passed by this function is equal to the current
+     * event target and will hereafter be treated as such.
+     * </p>
+     * 
+     * @param equalTarget
+     *            event target that is equal
+     */
+    public void addEqualEventTarget(IHierarchicalEventTarget equalTarget);
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTargetModel.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTargetModel.java	(revision 2146)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/IHierarchicalEventTargetModel.java	(revision 2146)
@@ -0,0 +1,150 @@
+//   Copyright 2015 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.List;
+
+/**
+ * <p>
+ * This interface can be used to wrap tree like event target structures. This allows rather
+ * flexible implementations of such structures and can either be rather concrete, e.g., for
+ * GUI models, or rather generic for any type of event target. The interface provides a way to
+ * traverse the target structure by retrieving a traverser.
+ * </p>
+ * 
+ * @author Patrick Harms
+ */
+public interface IHierarchicalEventTargetModel<T extends IHierarchicalEventTarget>  {
+
+    /**
+     * <p>
+     * Returns all children of the provided event target or null, if it does not have any or the
+     * node is unknown.
+     * </p>
+     * 
+     * @param eventTarget
+     *            the event target of which the children shall be returned
+     * 
+     * @return As described
+     */
+    List<T> getChildren(T eventTarget);
+
+    /**
+     * <p>
+     * Returns the parent event target of the provided one or null, if it does not have a
+     * parent (i.e. if it is a root node) or if the node is unknown.
+     * </p>
+     * 
+     * @param eventTarget
+     *            the event target of which the parent shall be returned
+     * 
+     * @return As described
+     */
+    T getParent(T eventTarget);
+
+    /**
+     * <p>
+     * Returns all root event targets of the model or an empty list, if the model is empty
+     * </p>
+     * 
+     * @return As described
+     */
+    List<T> getRootElements();
+
+    
+    /**
+     * returns a traverser for the event target model to have efficient access to the tree of
+     * event targets without having direct access.
+     * 
+     * @return a traverser
+     */
+    Traverser<T> getTraverser();
+
+    /**
+     * returns a traverser for the event target model starting at the given event target. Returns
+     * null, if the event target is not part of the model.
+     * 
+     * @return a traverser
+     */
+    Traverser<T> getTraverser(T startingAt);
+
+    
+    /**
+     * <p>
+     * This interface defines the methods to be provided by model traversers
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    public interface Traverser<T> {
+
+        /**
+         * <p>
+         * returns the first child of the current event target. On the first call of this method on
+         * the traverser the first of the root event targets of the event target model is returned.
+         * If the current event target does not have children, the method returns null. If the
+         * event target model is empty, then a call to this method will return null. The returned
+         * event target is the next one the traverser points to.
+         * </p>
+         *
+         * @return as described.
+         */
+        T firstChild();
+
+        /**
+         * <p>
+         * returns true, if the current event target has a first child, i.e. if the next call to the
+         * method {@link #firstChild()} would return an event target or null.
+         * </p>
+         *
+         * @return as described
+         */
+        boolean hasFirstChild();
+
+        /**
+         * <p>
+         * returns the next sibling of the current event target. If there is no further sibling,
+         * null is returned. If the current event target is one of the root nodes, the next root
+         * node of the event target model is returned. The returned event target is the next one
+         * the traverser points to.
+         * </p>
+         *
+         * @return as described
+         */
+        T nextSibling();
+
+        /**
+         * <p>
+         * returns true, if the current event target has a further sibling, i.e. if a call to the
+         * method {@link #nextSibling()} will return an event target
+         * </p>
+         *
+         * @return as described
+         */
+        boolean hasNextSibling();
+
+        /**
+         * <p>
+         * returns the parent event target of the current event target. If the current event target
+         * is a root node, null is returned. If there is no current event target yet as the method
+         * {@link #firstChild()} was not called yet, null is returned.
+         * </p>
+         *
+         * @return as described
+         */
+        T parent();
+
+    }
+}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElement.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElement.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/AbstractDefaultGUIElement.java	(revision 2146)
@@ -15,6 +15,5 @@
 package de.ugoe.cs.autoquest.eventcore.guimodel;
 
-import java.util.LinkedList;
-import java.util.List;
+import de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget;
 
 /**
@@ -26,5 +25,7 @@
  * @author Patrick Harms
  */
-public abstract class AbstractDefaultGUIElement implements IGUIElement {
+public abstract class AbstractDefaultGUIElement extends AbstractDefaultHierarchicalEventTarget
+    implements IGUIElement
+{
 
     /**
@@ -34,25 +35,4 @@
      */
     public static final long serialVersionUID = 1L;
-
-    /**
-     * <p>
-     * Specification of the GUI element
-     * </p>
-     */
-    private final IGUIElementSpec specification;
-
-    /**
-     * <p>
-     * Reference to the parent element
-     * </p>
-     */
-    private IGUIElement parent;
-    
-    /**
-     * <p>
-     * List of other GUI elements being equal to this
-     * </p>
-     */
-    private List<AbstractDefaultGUIElement> equalGUIElements = null;
     
     /**
@@ -62,18 +42,4 @@
      */
     private boolean usageObserved;
-
-    /**
-     * <p>
-     * the reference to the GUI model to which this GUI element belongs.
-     * </p>
-     */
-    private GUIModel guiModel;
-    
-    /**
-     * <p>
-     * the hash code of this object
-     * </p>
-     */
-    private int hashCode;
 
     /**
@@ -88,34 +54,5 @@
      */
     public AbstractDefaultGUIElement(IGUIElementSpec specification, IGUIElement parent) {
-        this.specification = specification;
-        this.usageObserved = false;
-        setParent(parent);
-        
-        if (specification != null) {
-            this.hashCode = specification.hashCode();
-        }
-        else {
-            this.hashCode = 0;
-        }
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see de.ugoe.cs.tasktree.guimodel.GUIElement#getSpecification()
-     */
-    @Override
-    public IGUIElementSpec getSpecification() {
-        return specification;
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#getParent()
-     */
-    @Override
-    public IGUIElement getParent() {
-        return parent;
+        super(specification, parent);
     }
 
@@ -125,60 +62,29 @@
     @Override
     public GUIModel getGUIModel() {
-       return guiModel;
+       return (GUIModel) super.getEventTargetModel();
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#addEqualGUIElement(IGUIElement)
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget#getParent()
      */
     @Override
-    public void addEqualGUIElement(IGUIElement equalElement) {
-        if (!(equalElement instanceof AbstractDefaultGUIElement)) {
-            throw new IllegalArgumentException
-                ("this implementation can only handle other AbstractDefaultGUIElements");
-        }
-        
-        AbstractDefaultGUIElement other = (AbstractDefaultGUIElement) equalElement;
-        
-        synchronized (AbstractDefaultGUIElement.class) {
-            if (this.equalGUIElements == null) {
-                if (other.equalGUIElements == null) {
-                    this.equalGUIElements = new LinkedList<AbstractDefaultGUIElement>();
-                    this.equalGUIElements.add(this);
-                    this.equalGUIElements.add(other);
-                    other.equalGUIElements = this.equalGUIElements;
-                    other.hashCode = this.hashCode;
-                }
-                else {
-                    addIfNotContained(other.equalGUIElements, this);
-                    this.equalGUIElements = other.equalGUIElements;
-                    this.hashCode = other.hashCode;
-                }
-            }
-            else {
-                if (other.equalGUIElements == null) {
-                    addIfNotContained(this.equalGUIElements, other);
-                    other.equalGUIElements = this.equalGUIElements;
-                    other.hashCode = this.hashCode;
-                }
-                else if (this.equalGUIElements != other.equalGUIElements) {
-                    this.equalGUIElements.addAll(other.equalGUIElements);
+    public IGUIElement getParent() {
+        return (IGUIElement) super.getParent();
+    }
 
-                    // we also have to set this new list for all other elements for which so
-                    // far list2 was registered
-                    for (AbstractDefaultGUIElement candidate : other.equalGUIElements) {
-                        candidate.equalGUIElements = this.equalGUIElements;
-                        candidate.hashCode = this.hashCode;
-                    }
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget#getSpecification()
+     */
+    @Override
+    public IGUIElementSpec getSpecification() {
+        return (IGUIElementSpec) super.getSpecification();
+    }
 
-                    other.equalGUIElements = this.equalGUIElements;
-                    other.hashCode = this.hashCode;
-                }
-                // else
-                // in this case, both GUI elements should already be registered with the same
-                // lists.
-            }
-        }
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget#getEventTargetModel()
+     */
+    @Override
+    public GUIModel getEventTargetModel() {
+        return (GUIModel) super.getEventTargetModel();
     }
 
@@ -203,97 +109,3 @@
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see GUIElement#equals(GUIElement)
-     */
-    public final boolean equals(Object other) {
-        // implement final, as GUI elements are all singletons and they equal only if they are the
-        // same object or if they are in the list of equal GUI elements
-        if (super.equals(other)) {
-            return true;
-        }
-        else if (other instanceof AbstractDefaultGUIElement) {
-            synchronized (AbstractDefaultGUIElement.class) {
-                if (equalGUIElements != null) {
-                    for (IGUIElement candidate : equalGUIElements) {
-                        if (candidate == other) {
-                            return true;
-                        }
-                    }
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see java.lang.Object#hashCode()
-     */
-    @Override
-    public final int hashCode() {
-        // implement final, as GUI elements are all singletons and they equal only if they are the
-        // same object. If there are several GUI element objects that represent the same GUI element
-        // then they are stored in the list of equal elements. But at least their type is expected
-        // to be equal, so return the hash code of the type.
-        return hashCode;
-    }
-    
-    /**
-     * <p>
-     * updates the parent node of this node if required due to model restructuring
-     * </p>
-     */
-    void setParent(IGUIElement newParent) {
-        synchronized (AbstractDefaultGUIElement.class) {
-            // all equal GUI elements must have the same parent. Otherwise, they are not equal
-            // anymore and we would have discrepancies on the return value of getParent() on
-            // equal GUI elements.
-            this.parent = newParent;
-            if (equalGUIElements != null) {
-                for (AbstractDefaultGUIElement candidate : equalGUIElements) {
-                    candidate.parent = newParent;
-                }
-            }
-        }
-    }
-
-    /**
-     * <p>
-     * used to set the GUI model to which this GUI element belongs. Will be set automatically, if
-     * used in combination with {@link GUIModel};
-     * </p>
-     *
-     * @param guiModel
-     */
-    void setGUIModel(GUIModel guiModel) {
-        this.guiModel = guiModel;
-    }
-
-    /**
-     * <p>
-     * Adds an {@link AbstractDefaultGUIElement} as equal to a list of
-     * {@link AbstractDefaultGUIElement}s if and only if it is not already contained.
-     * </p>
-     * 
-     * @param equalElementsList
-     *            list of {@link AbstractDefaultGUIElement} to which the GUI element is added
-     * @param guiElement
-     *            GUI element to be added
-     */
-    private void addIfNotContained(List<AbstractDefaultGUIElement> equalElementsList,
-                                   AbstractDefaultGUIElement       guiElement)
-    {
-        for (IGUIElement candidate : equalElementsList) {
-            if (candidate == guiElement) {
-                return;
-            }
-        }
-
-        equalElementsList.add(guiElement);
-    }
-
 }
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementFactory.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementFactory.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementFactory.java	(revision 2146)
@@ -25,4 +25,9 @@
 import java.util.logging.Level;
 
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelConfigurationException;
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetModel;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
 import de.ugoe.cs.util.console.Console;
 
@@ -35,5 +40,5 @@
  * @author Patrick Harms
  */
-public class GUIElementFactory implements IGUIElementFactory {
+public class GUIElementFactory implements IEventTargetFactory {
 
     /**
@@ -64,5 +69,5 @@
     /**
      * <p>
-     * A property mapping that defines to which Java class is created given the type of the GUI
+     * A property mapping that defines which Java class is created given the type of the GUI
      * element found in the specification.
      * </p>
@@ -71,14 +76,31 @@
 
     
-    /*
-     * (non-Javadoc)
-     * 
-     * @see
-     * de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementFactory#instantiateGUIElement(de.ugoe.cs.autoquest
-     * .eventcore.guimodel.IGUIElementSpec, de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement)
-     */
+    /* (non-Javadoc)
+     * @see IEventTargetFactory#instantiateEventTarget(IEventTargetSpec, IHierarchicalEventTarget)
+     */
+    @SuppressWarnings("unchecked")
     @Override
-    public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent)
-        throws GUIModelConfigurationException
+    public <T extends IHierarchicalEventTarget> T instantiateEventTarget(IEventTargetSpec specification,
+                                                                         T                parent)
+        throws EventTargetModelConfigurationException
+    {
+        if (!(specification instanceof IGUIElementSpec)) {
+            throw new IllegalArgumentException("can only handle IGUIElementSpecs as specification");
+        }
+        
+        if ((parent != null) && !(parent instanceof IGUIElement)) {
+            throw new IllegalArgumentException("can only handle IGUIElements as parent");
+        }
+        
+       return (T) instantiateEventTarget((IGUIElementSpec) specification, (IGUIElement) parent);
+    }
+        
+    
+    /**
+     * concrete implementation of {@link #instantiateEventTarget(IEventTargetSpec, IHierarchicalEventTarget)}
+     */
+    public IGUIElement instantiateEventTarget(IGUIElementSpec specification,
+                                              IGUIElement     parent)
+        throws EventTargetModelConfigurationException
     {
         Properties mappings = getMappingsFromConfiguration();
@@ -155,5 +177,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " can not be loaded.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " can not be loaded.", e);
@@ -162,5 +184,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " can not be instantiated due to security reasons.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " can not be instantiated due to security reasons.", e);
@@ -169,5 +191,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " does not provide an appropriate constructor.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " does not provide an appropriate constructor.", e);
@@ -177,5 +199,5 @@
                                 className + " does not provide an appropriate constructor " +
                                 "accepting the provided parameters.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className + " does not " +
                      "provide an appropriate constructor accepting the provided parameters.", e);
@@ -184,5 +206,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " can not be instantiated.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " can not be instantiated.", e);
@@ -191,5 +213,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " can not be instantiated.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " can not be instantiated.", e);
@@ -198,5 +220,5 @@
                 Console.traceln(Level.WARNING, "configured GUI element representing class " +
                                 className + " can not be instantiated.");
-                throw new GUIModelConfigurationException
+                throw new EventTargetModelConfigurationException
                     ("configured GUI element representing class " + className +
                      " can not be instantiated.", e);
@@ -208,5 +230,5 @@
                             specification.getType() + " found. Please extend GUI element " +
                             "mapping files.");
-            throw new GUIModelConfigurationException
+            throw new EventTargetModelConfigurationException
                 ("no class representing GUI elements of type " + specification.getType() +
                  " found. Please extend GUI element mapping files");
@@ -214,4 +236,25 @@
 
         return guiElement;
+    }
+
+    /* (non-Javadoc)
+     * @see IEventTargetFactory#instantiateGroup(String, IHierarchicalEventTarget, HierarchicalEventTargetModel)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends IHierarchicalEventTarget> T instantiateGroup(String                          groupName,
+                                                                   T                               parent,
+                                                                   HierarchicalEventTargetModel<T> hierarchicalEventTargetModel)
+    {
+        if (!(hierarchicalEventTargetModel instanceof GUIModel)) {
+            throw new IllegalArgumentException("can only handle GUI elements as event targets");
+        }
+        
+        if (!(parent instanceof IGUIElement)) {
+            throw new IllegalArgumentException("can only handle GUI elements as event targets");
+        }
+        
+        return (T) new GUIElementGroup
+              (groupName, (IGUIElement) parent, (GUIModel) hierarchicalEventTargetModel);
     }
 
@@ -226,5 +269,5 @@
      */
     private synchronized Properties getMappingsFromConfiguration()
-        throws GUIModelConfigurationException
+        throws EventTargetModelConfigurationException
     {
         if (mappingsFromConfiguration != null) {
@@ -249,12 +292,10 @@
                         }
                         catch (FileNotFoundException e) {
-                            throw new GUIModelConfigurationException(
-                                                                     "could not read mapping configuration file " +
-                                                                         mappingsFile, e);
+                            throw new EventTargetModelConfigurationException
+                                ("could not read mapping configuration file " + mappingsFile, e);
                         }
                         catch (IOException e) {
-                            throw new GUIModelConfigurationException(
-                                                                     "could not read mapping configuration file " +
-                                                                         mappingsFile, e);
+                            throw new EventTargetModelConfigurationException
+                                ("could not read mapping configuration file " + mappingsFile, e);
                         }
                         finally {
@@ -272,7 +313,6 @@
             }
             else {
-                throw new GUIModelConfigurationException(
-                                                         "no GUI mappings file provided in folder " +
-                                                             mappingsFolder);
+                throw new EventTargetModelConfigurationException
+                    ("no GUI mappings file provided in folder " + mappingsFolder);
             }
 
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementGroup.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementGroup.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementGroup.java	(revision 2146)
@@ -1,3 +1,3 @@
-//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//   Copyright 2015 Georg-August-Universität Göttingen, Germany
 //
 //   Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,31 +15,24 @@
 package de.ugoe.cs.autoquest.eventcore.guimodel;
 
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetGroup;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 
 /**
  * <p>
- * This class is a dummy GUI element to represent groups of GUI elements. A group of GUI elements
- * can be integrated in any GUI model using the method
- * {@link GUIModel#groupGUIElements(java.util.List, String)}. A group has the same behavior as
- * any other parent GUI element.
+ * implementation of event target groups for GUI elements
  * </p>
  * 
  * @author Patrick Harms
  */
-public class GUIElementGroup extends AbstractDefaultGUIElement {
+public class GUIElementGroup extends HierarchicalEventTargetGroup implements IGUIElement {
 
-    /**
-     * <p>
-     * default serial version UID
-     * </p>
-     */
+    /**  */
     private static final long serialVersionUID = 1L;
     
-    /**
-     * the list of grouped GUIElements
-     */
-    private List<IGUIElement> groupedGUIElements = new LinkedList<IGUIElement>();
+    /** the internal fake event target specification */
+    private GroupSpecification groupSpecification;
+    
+    /** stores if the usage of the group was observed (just to match the implemented interface */
+    private boolean usageObserved = false;
 
     /**
@@ -48,27 +41,22 @@
      * </p>
      *
-     * @param groupName the name of the GUI element group
-     * @param parent    the optional parent GUI element of the group
-     * @param guiModel  the GUI model to which the group will belong
+     * @param groupName        the name of the GUI element group
+     * @param parent           the optional parent GUI element of the group
+     * @param eventTargetModel the GUI model to which the group will belong
      */
-    public GUIElementGroup(String groupName, IGUIElement parent, GUIModel guiModel) {
-        super(new GroupSpecification(groupName), parent);
-        super.setGUIModel(guiModel);
+    public GUIElementGroup(String      groupName,
+                           IGUIElement parent,
+                           GUIModel    guiModel)
+    {
+        super(groupName, parent, guiModel);
+        groupSpecification = new GroupSpecification(groupName);
     }
 
     /* (non-Javadoc)
-     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#updateSpecification(IGUIElementSpec)
+     * @see de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget#getSpecification()
      */
     @Override
-    public final void updateSpecification(IGUIElementSpec furtherSpec) {
-        // do nothing
-    }
-
-    /* (non-Javadoc)
-     * @see de.ugoe.cs.autoquest.eventcore.IEventTarget#getPlatform()
-     */
-    @Override
-    public String getPlatform() {
-        return "none";
+    public IGUIElementSpec getSpecification() {
+        return groupSpecification;
     }
 
@@ -78,13 +66,13 @@
     @Override
     public String getStringIdentifier() {
-        return ((GroupSpecification) super.getSpecification()).name;
+        return groupSpecification.name;
     }
 
     /* (non-Javadoc)
-     * @see java.lang.Object#toString()
+     * @see de.ugoe.cs.autoquest.eventcore.AbstractDefaultHierarchicalEventTarget#getParent()
      */
     @Override
-    public String toString() {
-        return getStringIdentifier();
+    public IGUIElement getParent() {
+        return (IGUIElement) super.getParent();
     }
 
@@ -98,4 +86,28 @@
 
     /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#getGUIModel()
+     */
+    @Override
+    public GUIModel getGUIModel() {
+        return (GUIModel) super.getEventTargetModel();
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#isUsed()
+     */
+    @Override
+    public boolean isUsed() {
+        return usageObserved;
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#markUsed()
+     */
+    @Override
+    public void markUsed() {
+        usageObserved = true;
+    }
+
+    /* (non-Javadoc)
      * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#getDistanceTo(IGUIElement)
      */
@@ -105,33 +117,10 @@
             return 0.0;
         }
-        else if (super.getParent() != null) {
-            return super.getParent().getDistanceTo(otherElement);
+        else if (getParent() != null) {
+            return getParent().getDistanceTo(otherElement);
         }
         else {
             return 1.0;
         }
-    }
-
-    /**
-     * <p>
-     * returns the list of GUI elements belonging to this group.
-     * </p>
-     * 
-     * @return the GUI elements belonging to this group
-     * 
-     */
-    public List<IGUIElement> getGroupedElements() {
-        return Collections.unmodifiableList(groupedGUIElements);
-    }
-    
-    /**
-     * <p>
-     * allows adding a new GUI element to the group
-     * </p>
-     *
-     * @param guiElement the new member of the group
-     */
-    void addToGroup(IGUIElement guiElement) {
-        this.groupedGUIElements.add(guiElement);
     }
     
@@ -174,4 +163,14 @@
 
         /* (non-Javadoc)
+         * @see de.ugoe.cs.autoquest.eventcore.IEventTargetSpec#getSimilarity(IEventTargetSpec)
+         */
+        @Override
+        public boolean getSimilarity(IEventTargetSpec other) {
+            return
+                (other instanceof GroupSpecification) &&
+                name.equals(((GroupSpecification) other).name);
+        }
+
+        /* (non-Javadoc)
          * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getType()
          */
@@ -189,15 +188,4 @@
         }
 
-        /* (non-Javadoc)
-         * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getSimilarity(IGUIElementSpec)
-         */
-        @Override
-        public boolean getSimilarity(IGUIElementSpec other) {
-            return
-                (other instanceof GroupSpecification) &&
-                name.equals(((GroupSpecification) other).name);
-        }
-
     }
-
 }
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementTree.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementTree.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIElementTree.java	(revision 2146)
@@ -20,8 +20,8 @@
 import java.util.Map;
 
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory;
 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;
 
 /**
@@ -30,7 +30,8 @@
  * </p>
  * <p>
- * 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. The parameter
- * T represents the id type of the GUI elements that are handled internally.
+ * 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. The parameter T represents the id type of the GUI elements that are handled
+ * internally.
  * </p>
  * 
@@ -84,7 +85,5 @@
      * </p>
      */
-    private IGUIElementFactory guiElementFactory = GUIElementFactory.getInstance();
-
- 
+    private IEventTargetFactory guiElementFactory = GUIElementFactory.getInstance();
 
     /**
@@ -127,10 +126,10 @@
      *            the GUI element specification
      *            
-     * @throws GUIModelException if the GUI element can not be added to the underlying GUI model
+     * @throws EventTargetModelException if the GUI element can not be added to the underlying GUI model
      */
     public void add(T guiElementID,
                     T parentID,
                     IGUIElementSpec guiElementSpec)
-        throws GUIModelException
+        throws EventTargetModelException
     {
         IGUIElement guiElement = guiElements.get(guiElementID);
@@ -161,5 +160,5 @@
             }
 
-            guiElement = guiModel.integratePath(guiElementPath, guiElementFactory);
+            guiElement = (IGUIElement) guiModel.integratePath(guiElementPath, guiElementFactory);
             guiElements.put(guiElementID, guiElement);
         }
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModel.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModel.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModel.java	(revision 2146)
@@ -15,17 +15,8 @@
 package de.ugoe.cs.autoquest.eventcore.guimodel;
 
-import java.io.OutputStream;
-import java.io.PrintStream;
 import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-import java.util.logging.Level;
 
-import de.ugoe.cs.util.console.Console;
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetModel;
 
 /**
@@ -34,5 +25,5 @@
  * platform independent. It may have several root nodes, as some GUIs are made up of several Frames
  * being independent from each other. The GUI model is filled using the
- * {@link #integratePath(List, IGUIElementFactory)} method.
+ * {@link #integratePath(List, de.ugoe.cs.autoquest.eventcore.IEventTargetFactory)} method.
  * </p>
  * 
@@ -40,5 +31,7 @@
  * @author Patrick Harms, Steffen Herbold
  */
-public class GUIModel implements Serializable {
+public class GUIModel extends HierarchicalEventTargetModel<IGUIElement>
+    implements Serializable
+{
 
     /**  */
@@ -47,966 +40,21 @@
     /**
      * <p>
-     * The root node of the tree not provided externally.
-     * </p>
-     */
-    private TreeNode root = new TreeNode();
-
-    /**
-     * <p>
-     * A map with all nodes currently known
-     * </p>
-     */
-    private Map<IGUIElement, TreeNode> allNodes = new HashMap<IGUIElement, TreeNode>();
-    
-    /**
-     * <p>
-     * true, if internal validation is switched on, false else
-     * </p>
-     */
-    private boolean validate = false;
-
-    /**
-     * <p>
-     * Default constructor to create a GUI model without internal validation
+     * instantiate a default unvalidated model
      * </p>
      *
      */
     public GUIModel() {
-        this(false);
+        super();
     }
 
     /**
      * <p>
-     * creates a GUI model, that internally validates itself by checking on access to nodes,
-     * if several GUI elements pretend to be equal or if several distinct GUI elements have the
-     * same child.
+     * instantiate a model that will validate itself internally if the provided parameters is set
+     * to true. This is typically rather slow. 
      * </p>
-     *
-     * @param validate
-     *            true if internal validation shall be switched on (bad performance), false else
-     *
      */
     public GUIModel(boolean validate) {
-        this.validate = validate;
+        super(validate);
     }
 
-    /**
-     * <p>
-     * Integrates a path of GUI elements into the GUI model. The GUI model itself is a tree and
-     * therefore a set of different paths through the tree that start with a root node and end with
-     * a leaf node. Such a path can be added to the tree. The method checks, if any of the GUI
-     * elements denoted by the path already exists. If so, it reuses it. It may therefore also
-     * return an existing GUI element being the leaf node of the provided path. If a GUI element of
-     * the path does not exist yet, it creates a new one using the provided GUI element factory.
-     * </p>
-     * <p>
-     * If a GUI element specification describes an existing GUI element or not is determined through
-     * comparing the GUI element specifications of the existing GUI elements with the ones provided
-     * in the path. The comparison is done using the
-     * {@link IGUIElementSpec#getSimilarity(IGUIElementSpec)} method. The comparison is only done on
-     * the correct levels. I.e. the currently known root elements of the tree are only compared to
-     * the first element in the path. If the correct one is found or created, its children are
-     * compared only to the second specification in the path, and so on.
-     * </p>
-     * <p>
-     * The returned GUI elements are singletons. I.e. it is tried to return always the identical
-     * object for the same denoted element. However, while creating the GUI model, the similarity of
-     * GUI elements may change. Therefore, the method might determine, that two formerly different
-     * nodes are now similar. (This may happen, e.g. if GUI elements do not have initial names which
-     * are set afterwards. Therefore, first they are handled differently and later they can be
-     * identified as being the same.) In such a case, there are already several GUI element objects
-     * instantiated for the same GUI element. The singleton paradigm gets broken. Therefore, such
-     * GUI element objects are registered with each other, so that their equal method can determine
-     * equality again correctly, although the objects are no singletons anymore.
-     * </p>
-     * 
-     * @param guiElementPath
-     *            the path to integrate into the model
-     * @param guiElementFactory
-     *            the GUI element factory to be used for instantiating GUI element objects
-     * 
-     * @return The GUI element object representing the GUI element denoted by the provided path
-     * 
-     * @throws GUIModelException
-     *             thrown in cases such as the GUI element object could not be instantiated
-     * @throws IllegalArgumentException
-     *             if the provided path is invalid.
-     */
-    public IGUIElement integratePath(List<? extends IGUIElementSpec> guiElementPath,
-                                     IGUIElementFactory guiElementFactory)
-        throws GUIModelException, IllegalArgumentException
-    {
-        if ((guiElementPath == null) || (guiElementPath.size() <= 0)) {
-            throw new IllegalArgumentException("GUI element path must contain at least one element");
-        }
-
-        List<IGUIElementSpec> remainingPath = new LinkedList<IGUIElementSpec>(guiElementPath);
-
-        return integratePath(root, remainingPath, guiElementFactory);
-    }
-
-    /**
-     * <p>
-     * Returns all children of the provided GUI element or null, if it does not have any or the node
-     * is unknown.
-     * </p>
-     * 
-     * @param guiElement
-     *            the GUI element of which the children shall be returned
-     * 
-     * @return As described
-     */
-    public List<IGUIElement> getChildren(IGUIElement guiElement) {
-        TreeNode node = findNode(guiElement);
-        
-        List<IGUIElement> result = null;
-        if (node != null) {
-            result = new LinkedList<IGUIElement>();
-            if (node.children != null) {
-                for (TreeNode child : node.children) {
-                    result.add(child.guiElement);
-                }
-            }
-        }
-        else {
-            System.out.println("problem");
-            boolean found = false;
-            for (Map.Entry<IGUIElement, TreeNode> entry : allNodes.entrySet()) {
-                if (entry.getKey().equals(guiElement)) {
-                    if (!found) {
-                        System.out.println(guiElement.hashCode() + "  " + entry.getKey().hashCode());
-                        found = true;
-                    }
-                    else {
-                        Console.traceln(Level.SEVERE, "Multiple nodes in the internal GUI model " +
-                                        "match the same GUI element. This should not be the case " +
-                                        "and the GUI model is probably invalid.");
-                    }
-                }
-            }
-            
-            if (!found) {
-                Console.traceln(Level.SEVERE, "GUI element belonging to model not found in model");
-            }
-        }
- 
-        return result;
-    }
-
-    /**
-     * <p>
-     * Returns the parent GUI element of the provided GUI element or null, if it does not have a
-     * parent (i.e. if it is a root node) or if the node is unknown.
-     * </p>
-     * 
-     * @param guiElement
-     *            the GUI element of which the parent shall be returned
-     * 
-     * @return As described
-     */
-    public IGUIElement getParent(IGUIElement guiElement) {
-        IGUIElement parent = null;
-
-        for (Map.Entry<IGUIElement, TreeNode> entry : allNodes.entrySet()) {
-            if (entry.getValue().children != null) {
-                for (TreeNode child : entry.getValue().children) {
-                    if (child.guiElement.equals(guiElement)) {
-                        if (parent == null) {
-                            parent = entry.getKey();
-                            if (!validate) {
-                                break;
-                            }
-                        }
-                        else {
-                            Console
-                            .traceln(Level.SEVERE,
-                                     "Multiple nodes in the internal GUI model match the same GUI element. "
-                                             + "This should not be the case and the GUI model is probably invalid.");
-                        }
-                    }
-                }
-            }
-        }
-
-        return parent;
-    }
-
-    /**
-     * <p>
-     * Returns all root GUI elements of the model or an empty list, if the model is empty
-     * </p>
-     * 
-     * @return As described
-     */
-    public List<IGUIElement> getRootElements() {
-        List<IGUIElement> roots = new ArrayList<IGUIElement>();
-
-        if (root.children != null) {
-            for (TreeNode rootChild : root.children) {
-                roots.add(rootChild.guiElement);
-            }
-        }
-
-        return roots;
-    }
-    
-    /**
-     * returns a traverser for the GUI model to have efficient access to the tree of GUI elements
-     * without having direct access.
-     * 
-     * @return a traverser
-     */
-    public Traverser getTraverser() {
-        return new Traverser();
-    }
-
-    /**
-     * returns a traverser for the GUI model starting at the given GUI element. Returns null, if
-     * the GUI element is not part of the model.
-     * 
-     * @return a traverser
-     */
-    public Traverser getTraverser(IGUIElement startingAt) {
-        TreeNode node = findNode(startingAt);
-        
-        if (node != null) {
-            Traverser traverser = new Traverser();
-            traverser.navigateTo(node);
-            return traverser;
-        }
-        else {
-            return null;
-        }
-    }
-
-    /**
-     * <p>
-     * dumps the GUI model to the provided stream. Each node is represented through its toString()
-     * method. If a node has children, those are dumped indented and surrounded by braces.
-     * </p>
-     * 
-     * @param out
-     *            The stream to dump the textual representation of the model to
-     * @param encoding
-     *            The encoding to be used while dumping
-     */
-    public void dump(OutputStream out, String encoding) {
-        PrintStream stream;
-
-        if (out instanceof PrintStream) {
-            stream = (PrintStream) out;
-        }
-        else {
-            String enc = encoding == null ? "UTF-8" : encoding;
-            try {
-                stream = new PrintStream(out, true, enc);
-            }
-            catch (UnsupportedEncodingException e) {
-                throw new IllegalArgumentException("encodind " + enc + " not supported");
-            }
-        }
-
-        for (TreeNode node : root.children) {
-            dumpGUIElement(stream, node, "");
-        }
-    }
-
-    /**
-     * <p>
-     * This method groups the provided GUI elements under a common parent GUI element. The current
-     * parent GUI element of the GUI elements to group must be the same. If the GUI elements to
-     * be grouped are the whole list of children of the same parent, nothing is changed. 
-     * </p>
-     * 
-     * @param guiElements the list of GUI elements to be grouped
-     * @param groupName   the name of the GUI element group to be created
-     * 
-     * @return the GUI element representing the group, or null, if the provided list of GUI elements
-     *         is empty
-     * 
-     * @throws IllegalArgumentException
-     *             if not all GUI elements to be merged share the same parent, if one of the
-     *             parameters is null, or if one of the provided GUI elements does not belong to
-     *             the model
-     */
-    public IGUIElement groupGUIElements(List<IGUIElement> guiElements, String groupName)
-        throws IllegalArgumentException
-    {
-        if ((guiElements == null) || (groupName == null)) {
-            throw new IllegalArgumentException("parameters must not be null");
-        }
-        
-        if (guiElements.size() <= 0) {
-            // do nothing
-            return null;
-        }
-        
-        TreeNode parent = findNode(guiElements.get(0).getParent());
-        if (parent == null) {
-            throw new IllegalArgumentException("GUI elements to group must have a parent: parent " +
-                                               "of " + guiElements.get(0) + " is " +
-                                               guiElements.get(0).getParent() + " and not found " +
-                                               "in the model");
-        }
-        
-        List<TreeNode> nodesToGroup = new LinkedList<TreeNode>();
-        
-        for (IGUIElement element : guiElements) {
-            if (!(element instanceof AbstractDefaultGUIElement)) {
-                throw new IllegalArgumentException
-                    ("can only group nodes of type AbstractDefaultGUIElement");
-            }
-            
-            TreeNode node = findNode(element);
-            if (node == null) {
-                throw new IllegalArgumentException
-                    ("GUI element " + element + " is not part of the model");
-            }
-            
-            if (!nodesToGroup.contains(node)) {
-                nodesToGroup.add(node);
-            }
-            
-            TreeNode parentNode = findNode(element.getParent());
-            
-            if (!parent.equals(parentNode)) {
-                throw new IllegalArgumentException("GUI elements do not share the same parent: " +
-                                                   parent + " (parent of " + guiElements.get(0) +
-                                                   ") <> " + parentNode + " (parent of " +
-                                                   element + ")");
-            }
-        }
-        
-        TreeNode replacement = new TreeNode();
-        replacement.guiElement = new GUIElementGroup(groupName, parent.guiElement, this);
-        
-        for (TreeNode child : nodesToGroup) {
-            ((GUIElementGroup) replacement.guiElement).addToGroup(child.guiElement);
-            replacement.addChildNode(child);
-            ((AbstractDefaultGUIElement) child.guiElement).setParent(replacement.guiElement);
-            parent.children.remove(child);
-        }
-
-        parent.children.add(replacement);
-
-        // finally, update the known nodes list
-        // if you don't do this getChildren will return wrong things and very bad things happen!
-        allNodes.put(replacement.guiElement, replacement);
-        
-        return replacement.guiElement;
-    }
-    
-    /**
-     * <p>
-     * By calling this method, the GUIModel is traversed and similar nodes are merged.
-     * </p>
-     * 
-     */
-    public void condenseModel() {
-        mergeSubTree(root);
-    }
-    
-    /**
-     * <p>
-     * Merges the tree nodes of two GUI elements. The GUI elements need to have the same parent.
-     * They are merged recursively, i.e. also their children are merged. 
-     * </p>
-     * 
-     * @param guiElement1
-     *            the first merge GUI element
-     * @param guiElement2
-     *            the second merge GUI element
-     *            
-     * @return the result of the merge
-     *            
-     * @throws IllegalArgumentException
-     *             thrown if the two GUI elements do not have the same parent
-     */
-    public IGUIElement mergeGUIElements(IGUIElement guiElement1, IGUIElement guiElement2)
-        throws IllegalArgumentException
-    {
-        return mergeGUIElements(guiElement1, guiElement2, true);
-    }
-    
-    /**
-     * <p>
-     * Merges the tree nodes of two GUI elements. The GUI elements need to have the same parent.
-     * If the <code>recursively</code> parameter is set to true, the children of the GUI elements
-     * are merged, as well, as long as they are similar. If the parameter is false, the children
-     * are not merged. In this case the resulting GUI element has all children of both merged GUI
-     * elements.
-     * </p>
-     * 
-     * @param guiElement1
-     *            the first merge GUI element
-     * @param guiElement2
-     *            the second merge GUI element
-     * @param recursively
-     *            if true, the merge is done also for similar children, if false, not.
-     *            
-     * @return the result of the merge
-     *            
-     * @throws IllegalArgumentException
-     *             thrown if the two GUI elements do not have the same parent
-     */
-    public IGUIElement mergeGUIElements(IGUIElement guiElement1,
-                                        IGUIElement guiElement2,
-                                        boolean     recursively)
-        throws IllegalArgumentException
-    {
-        // check if both nodes have the same parent
-        IGUIElement parentElement = guiElement1.getParent();
-        boolean sameParent = (parentElement != null) ?
-            parentElement.equals(guiElement2.getParent()) : (guiElement2.getParent() == null);
-            
-        if (!sameParent) {
-            throw new IllegalArgumentException("can only merge nodes with the same parent");
-        }
-
-        // get the TreeNode of the parent of the GUI elements
-        TreeNode parent = findNode(parentElement);
-        
-        if ((parent == null) && (parentElement == null)) {
-            // merging root nodes. The parent is the root node of the GUI element tree
-            parent = root;
-        }
-
-        // get the TreeNodes for both GUI elements
-        TreeNode node1 = findNode(guiElement1);
-        TreeNode node2 = findNode(guiElement2);
-
-        if (node1 == null || node2 == null) {
-            throw new IllegalArgumentException
-                ("Error while merging nodes: one element is not part of the GUI model!");
-        }
-
-        TreeNode replacement = mergeTreeNodes(node1, node2, recursively);
-
-        if (parent != null) {
-            // remove node1 and node2 from the parent's children and add the replacement instead
-            // assumes that there are no duplicates of node1 and node2
-            if (parent.children != null) {
-                parent.children.set(parent.children.indexOf(node1), replacement);
-                parent.children.remove(node2);
-            }
-        }
-
-        return replacement.guiElement;
-    }
-
-    /**
-     * <p>
-     * internally integrates a path as the children of the provided parent node. This method is
-     * recursive and calls itself, for the child of the parent node, that matches the first element
-     * in the remaining path.
-     * </p>
-     * 
-     * @param parentNode
-     *            the parent node to add children for
-     * @param guiElementPath
-     *            the path of children to be created starting with the parent node
-     * @param guiElementFactory
-     *            the GUI element factory to be used for instantiating GUI element objects
-     * 
-     * @return The GUI element object representing the GUI element denoted by the provided path
-     * 
-     * @throws GUIModelException
-     *             thrown in cases such as the GUI element object could not be instantiated
-     */
-    private IGUIElement integratePath(TreeNode                        parentNode,
-                                      List<? extends IGUIElementSpec> remainingPath,
-                                      IGUIElementFactory              guiElementFactory)
-        throws GUIModelException
-    {
-        IGUIElementSpec specToIntegrateElementFor = remainingPath.remove(0);
-
-        TreeNode child = findEqualChild(parentNode, specToIntegrateElementFor);
-        if (child == null) {
-            IGUIElement newElement =
-                guiElementFactory.instantiateGUIElement(specToIntegrateElementFor,
-                                                        parentNode.guiElement);
-
-            if (newElement instanceof AbstractDefaultGUIElement) {
-                ((AbstractDefaultGUIElement) newElement).setGUIModel(this);
-            }
-            
-            child = parentNode.addChild(newElement);
-            allNodes.put(child.guiElement, child);
-        }
-
-        if (remainingPath.size() > 0) {
-            return integratePath(child, remainingPath, guiElementFactory);
-        }
-        else {
-            return child.guiElement;
-        }
-    }
-
-    /**
-     * <p>
-     * Searches the children of a tree node to see if the {@link IGUIElementSpec} of equals the
-     * specification of the {@link TreeNode#guiElement} of the child. If a match is found, the child
-     * is returned.
-     * </p>
-     * 
-     * @param parentNode
-     *            parent node whose children are searched
-     * @param specToMatch
-     *            specification that is searched for
-     * @return matching child node or null if no child matches
-     */
-    private TreeNode findEqualChild(TreeNode parentNode, IGUIElementSpec specToMatch) {
-        if (parentNode.children != null) {
-            for (TreeNode child : parentNode.children) {
-                if (specToMatch.equals(child.guiElement.getSpecification())) {
-                    return child;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * <p>
-     * Merges all similar nodes in the sub-tree of the GUI model defined by the subTreeRoot.
-     * </p>
-     * <p>
-     * The merging order is a bottom-up. This means, that we first call mergeSubTree recursively for
-     * the grand children of the subTreeRoot, before we merge subTreeRoot.
-     * </p>
-     * <p>
-     * The merging strategy is top-down. This means, that every time we merge two child nodes, we
-     * call mergeSubTree recursively for all children of the merged nodes in order to check if we
-     * can merge the children, too.
-     * </p>
-     * 
-     * @param subTreeRoot
-     *            root node of the sub-tree that is merged
-     */
-    private void mergeSubTree(TreeNode subTreeRoot) {
-        if (subTreeRoot.children == null || subTreeRoot.children.isEmpty()) {
-            return;
-        }
-
-        // lets first merge the grand children of the parentNode
-        for (TreeNode child : subTreeRoot.children) {
-            mergeSubTree(child);
-        }
-
-        boolean performedMerge;
-
-        do {
-            performedMerge = false;
-            for (int i = 0; !performedMerge && i < subTreeRoot.children.size(); i++) {
-                IGUIElementSpec elemSpec1 =
-                    subTreeRoot.children.get(i).guiElement.getSpecification();
-                for (int j = i + 1; !performedMerge && j < subTreeRoot.children.size(); j++) {
-                    IGUIElementSpec elemSpec2 =
-                        subTreeRoot.children.get(j).guiElement.getSpecification();
-                    if (elemSpec1.getSimilarity(elemSpec2)) {
-                        TreeNode replacement = mergeTreeNodes
-                            (subTreeRoot.children.get(i), subTreeRoot.children.get(j), true);
-
-                        subTreeRoot.children.set(i, replacement);
-                        subTreeRoot.children.remove(j);
-                        performedMerge = true;
-                        i--;
-                        break;
-                    }
-                }
-            }
-        }
-        while (performedMerge);
-    }
-
-    /**
-     * <p>
-     * merges two nodes with each other. Merging means registering the GUI element objects with each
-     * other for equality checks. Further it adds all children of both nodes to a new replacing
-     * node. Afterwards, all similar nodes of the replacement node are merged as well as long
-     * the recursive parameter is set to true.
-     * </p>
-     * 
-     * @param treeNode1
-     *            the first of the two nodes to be merged
-     * @param treeNode2
-     *            the second of the two nodes to be merged
-     * @param recursively
-     *            if true, the merging also merges child nodes
-     *            
-     * @return a tree node being the merge of the two provided nodes.
-     */
-    private TreeNode mergeTreeNodes(TreeNode treeNode1, TreeNode treeNode2, boolean recursively) {
-        // and now a replacement node that is the merge of treeNode1 and treeNode2 is created
-        TreeNode replacement = new TreeNode();
-        replacement.guiElement = treeNode1.guiElement;
-        if (treeNode1.children != null) {
-            for (TreeNode child : treeNode1.children) {
-                replacement.addChildNode(child);
-            }
-        }
-        if (treeNode2.children != null) {
-            for (TreeNode child : treeNode2.children) {
-                replacement.addChildNode(child);
-            }
-        }
-
-        if (recursively) {
-            mergeSubTree(replacement);
-        }
-
-        replacement.guiElement.updateSpecification(treeNode2.guiElement.getSpecification());
-
-        // finally, update the known nodes list
-        // if you don't do this getChildren will return wrong things and very bad things happen!
-        allNodes.remove(treeNode1.guiElement);
-        allNodes.remove(treeNode2.guiElement);
-
-        // the following two lines are needed to preserve the references to the existing GUI
-        // elements. If two elements are the same, one should be deleted to make the elements
-        // singletons again. However, there may exist references to both objects. To preserve
-        // these, we simply register the equal GUI elements with each other so that an equals
-        // check can return true.
-        treeNode1.guiElement.addEqualGUIElement(treeNode2.guiElement);
-        treeNode2.guiElement.addEqualGUIElement(treeNode1.guiElement);
-        
-        allNodes.put(replacement.guiElement, replacement);
-        
-        return replacement;
-    }
-
-    /**
-     * <p>
-     * dumps a GUI element to the stream. A dump contains the toString() representation of the GUI
-     * element as well as a indented list of its children surrounded by braces. Therefore, not the
-     * GUI element itself but its tree node is provided to have an efficient access to its children
-     * </p>
-     * 
-     * @param out
-     *            {@link PrintStream} where the guiElement is dumped to
-     * @param node
-     *            the guiElement's tree node of which the string representation is dumped
-     * @param indent
-     *            indent string of the dumping
-     */
-    private void dumpGUIElement(PrintStream out, TreeNode node, String indent) {
-        out.print(indent);
-        out.print(node.guiElement);
-
-        if ((node.children != null) && (node.children.size() > 0)) {
-            out.println(" {");
-
-            for (TreeNode child : node.children) {
-                dumpGUIElement(out, child, indent + "  ");
-            }
-
-            out.print(indent);
-            out.print("}");
-        }
-
-        out.println();
-    }
-    
-    /**
-     * <p>
-     * Retrieves the TreeNode associated with a GUI element. Returns null if no such TreeNode is
-     * found.
-     * </p>
-     * 
-     * @param element
-     *            the GUI element
-     * @return associated TreeNode; null if no such node exists
-     */
-    private TreeNode findNode(IGUIElement element) {
-        if (element == null) {
-            return null;
-        }
-
-        TreeNode result = null;
-        
-        if (!validate) {
-            result = allNodes.get(element);
-        }
-        else {
-            for (Map.Entry<IGUIElement, TreeNode> entry : allNodes.entrySet()) {
-                if (entry.getKey().equals(element)) {
-                    if (result == null) {
-                        result = entry.getValue();
-                    }
-                    else {
-                        Console.traceln(Level.SEVERE, "Multiple nodes in the internal GUI model " +
-                        		"match the same GUI element. This should not be the case " +
-                        		"and the GUI model is probably invalid.");
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * <p>
-     * Used externally for tree traversal without providing direct access to the tree nodes
-     * </p>
-     * 
-     * @version 1.0
-     * @author Patrick Harms, Steffen Herbold
-     */
-    public class Traverser {
-        
-        /**
-         * <p>
-         * the stack of nodes on which the traverser currently works
-         * </p>
-         */
-        private Stack<StackEntry> nodeStack = new Stack<StackEntry>();
-        
-        /**
-         * <p>
-         * initializes the traverser by adding the root node of the GUI model to the stack
-         * </p>
-         */
-        private Traverser() {
-            nodeStack.push(new StackEntry(root, 0));
-        }
-        
-        /**
-         * <p>
-         * returns the first child of the current GUI element. On the first call of this method on
-         * the traverser the first of the root GUI elements of the GUI model is returned. If the
-         * current GUI element does not have children, the method returns null. If the GUI model
-         * is empty, then a call to this method will return null. The returned GUI element is the
-         * next one the traverser points to.
-         * </p>
-         *
-         * @return as described.
-         */
-        public IGUIElement firstChild() {
-            return pushChild(0);
-        }
-        
-        /**
-         * <p>
-         * returns true, if the current GUI element has a first child, i.e. if the next call to the
-         * method {@link #firstChild()} would return a GUI element or null.
-         * </p>
-         *
-         * @return as described
-         */
-        public boolean hasFirstChild() {
-            return
-                (nodeStack.peek().treeNode.children != null) &&
-                (nodeStack.peek().treeNode.children.size() > 0);
-        }
-        
-        /**
-         * <p>
-         * returns the next sibling of the current GUI element. If there is no further sibling,
-         * null is returned. If the current GUI element is one of the root nodes, the next root
-         * node of the GUI model is returned. The returned GUI element is the next one the
-         * traverser points to.
-         * </p>
-         *
-         * @return as described
-         */
-        public IGUIElement nextSibling() {
-            int lastIndex = nodeStack.pop().index;
-            
-            IGUIElement retval = pushChild(lastIndex + 1);
-            if (retval == null) {
-                pushChild(lastIndex);
-            }
-            
-            return retval;
-        }
-        
-        /**
-         * <p>
-         * returns true, if the current GUI element has a further sibling, i.e. if a call to the
-         * method {@link #nextSibling()} will return a GUI element;
-         * </p>
-         *
-         * @return as described
-         */
-        public boolean hasNextSibling() {
-            boolean result = false;
-            if (nodeStack.size() > 1) {
-                StackEntry entry = nodeStack.pop();
-                result = nodeStack.peek().treeNode.children.size() > (entry.index + 1);
-                pushChild(entry.index);
-            }
-            
-            return result;
-        }
-        
-        /**
-         * <p>
-         * returns the parent GUI element of the current GUI element. If the current GUI element
-         * is a root node, null is returned. If there is no current GUI element yet as the method
-         * {@link #firstChild()} was not called yet, null is returned.
-         * </p>
-         *
-         * @return as described
-         */
-        public IGUIElement parent() {
-            IGUIElement retval = null;
-            
-            if (nodeStack.size() > 1) {
-                nodeStack.pop();
-                retval = nodeStack.peek().treeNode.guiElement;
-            }
-            
-            return retval;
-        }
-        
-        /**
-         * <p>
-         * internal method used for changing the state of the traverser. I.e. to switch to a
-         * specific child GUI element of the current one.
-         * </p>
-         */
-        private IGUIElement pushChild(int index) {
-            IGUIElement retVal = null;
-            
-            if ((nodeStack.peek().treeNode.children != null) &&
-                (nodeStack.peek().treeNode.children.size() > index))
-            {
-                nodeStack.push
-                    (new StackEntry(nodeStack.peek().treeNode.children.get(index), index));
-                retVal = nodeStack.peek().treeNode.guiElement;
-            }
-            
-            return retVal;
-        }
-        
-        /**
-         * <p>
-         * navigates the traverser to the given node in the GUI model
-         * </p>
-         */
-        private boolean navigateTo(TreeNode node) {
-            if (hasFirstChild()) {
-                IGUIElement childElement = firstChild();
-            
-                while (childElement != null) {
-                    if (childElement.equals(node.guiElement)) {
-                        return true;
-                    }
-                    else if (navigateTo(node)) {
-                        return true;
-                    }
-                    else {
-                        childElement = nextSibling();
-                    }
-                }
-            
-                parent();
-            }
-            
-            return false;
-        }
-
-        /**
-         * <p>
-         * internal class needed to fill the stack with nodes of the GUI models and their
-         * respective index in the children of the parent node.
-         * </p>
-         */
-        private class StackEntry {
-            
-            /** */
-            private TreeNode treeNode;
-            
-            /** */
-            private int index;
-            
-            /**
-             * <p>
-             * creates a new stack entry.
-             * </p>
-             */
-            private StackEntry(TreeNode treeNode, int index) {
-                this.treeNode = treeNode;
-                this.index = index;
-            }
-        }
-    }
-
-    /**
-     * <p>
-     * Used internally for building up the tree of GUI elements.
-     * </p>
-     * 
-     * @version 1.0
-     * @author Patrick Harms, Steffen Herbold
-     */
-    private static class TreeNode implements Serializable {
-
-        /**  */
-        private static final long serialVersionUID = 1L;
-
-        /**
-         * <p>
-         * GUI element associated with the TreeNode.
-         * </p>
-         */
-        private IGUIElement guiElement;
-
-        /**
-         * <p>
-         * Children of the TreeNode.
-         * </p>
-         */
-        private List<TreeNode> children;
-
-        /**
-         * <p>
-         * Adds a child to the current node while keeping all lists of nodes up to date
-         * </p>
-         * 
-         * @param guiElement
-         *            GUI element that will be associated with the new child
-         * @return the added child
-         */
-        private TreeNode addChild(IGUIElement guiElement) {
-            if (children == null) {
-                children = new ArrayList<TreeNode>();
-            }
-
-            TreeNode child = new TreeNode();
-            child.guiElement = guiElement;
-            children.add(child);
-
-            return child;
-        }
-
-        /**
-         * 
-         * <p>
-         * Adds a TreeNode as child to the current node. This way, the whole sub-tree is added.
-         * </p>
-         * 
-         * @param node
-         *            child node that is added
-         * @return node that has been added
-         */
-        private TreeNode addChildNode(TreeNode node) {
-            if (children == null) {
-                children = new ArrayList<TreeNode>();
-            }
-            children.add(node);
-            return node;
-        }
-
-        /*
-         * (non-Javadoc)
-         * 
-         * @see java.lang.Object#toString()
-         */
-        @Override
-        public String toString() {
-            return guiElement.toString();
-        }
-
-    }
 }
Index: unk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelConfigurationException.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelConfigurationException.java	(revision 2145)
+++ 	(revision )
@@ -1,82 +1,0 @@
-//   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;
-
-/**
- * <p>
- * Exception that is thrown if there is a failure during the creation of a {@link IGUIElement} by
- * the {@link GUIElementFactory}.
- * </p>
- * 
- * @version 1.0
- * @author Patrick Harms
- */
-public class GUIModelConfigurationException extends GUIModelException {
-
-    /**
-     * <p>
-     * Id for object serialization.
-     * </p>
-     */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelConfigurationException.
-     * </p>
-     */
-    public GUIModelConfigurationException() {
-        super();
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelConfigurationException.
-     * </p>
-     * 
-     * @param message
-     *            message of the exception
-     */
-    public GUIModelConfigurationException(String message) {
-        super(message);
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelConfigurationException.
-     * </p>
-     * 
-     * @param cause
-     *            cause of the exception
-     */
-    public GUIModelConfigurationException(Throwable cause) {
-        super(cause);
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelConfigurationException.
-     * </p>
-     * 
-     * @param message
-     *            message of the exception
-     * @param cause
-     *            cause of the exception
-     */
-    public GUIModelConfigurationException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-}
Index: unk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelException.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/GUIModelException.java	(revision 2145)
+++ 	(revision )
@@ -1,81 +1,0 @@
-//   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;
-
-/**
- * <p>
- * Exception that is thrown if there are problems with the {@link GUIModel}.
- * </p>
- * 
- * @version 1.0
- * @author Patrick Harms
- */
-public class GUIModelException extends Exception {
-
-    /**
-     * <p>
-     * Id for object serialization.
-     * </p>
-     */
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelException.
-     * </p>
-     */
-    public GUIModelException() {
-        super();
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelException.
-     * </p>
-     * 
-     * @param message
-     *            message of the exception
-     */
-    public GUIModelException(String message) {
-        super(message);
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelException.
-     * </p>
-     * 
-     * @param cause
-     *            cause of the exception
-     */
-    public GUIModelException(Throwable cause) {
-        super(cause);
-    }
-
-    /**
-     * <p>
-     * Constructor. Creates a new GUIModelException.
-     * </p>
-     * 
-     * @param message
-     *            message of the exception
-     * @param cause
-     *            cause of the exception
-     */
-    public GUIModelException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElement.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElement.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElement.java	(revision 2146)
@@ -15,5 +15,5 @@
 package de.ugoe.cs.autoquest.eventcore.guimodel;
 
-import de.ugoe.cs.autoquest.eventcore.IEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
 
 /**
@@ -25,6 +25,6 @@
  * @author Patrick Harms
  */
-public interface IGUIElement extends IEventTarget {
-    
+public interface IGUIElement extends IHierarchicalEventTarget {
+
     /**
      * <p>
@@ -99,26 +99,4 @@
     /**
      * <p>
-     * Updates the specification of a GUI element with another specification, e.g., to add further
-     * known names of the GUI element.
-     * </p>
-     * 
-     * @param furtherSpec
-     *            additional specification
-     */
-    public void updateSpecification(IGUIElementSpec furtherSpec);
-
-    /**
-     * <p>
-     * The {@link IGUIElement} that is passed by this function is equal to the current GUI element
-     * and will hereafter be treated as such.
-     * </p>
-     * 
-     * @param guiElement
-     *            GUI element that is equal
-     */
-    public void addEqualGUIElement(IGUIElement equalElement);
-
-    /**
-     * <p>
      * Returns a measure for the distance of this {@link IGUIElement} to the provided one. Distance
      * means a measure for the distance in display of the rendered GUI. The returned values must be
Index: unk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElementFactory.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElementFactory.java	(revision 2145)
+++ 	(revision )
@@ -1,43 +1,0 @@
-//   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;
-
-/**
- * <p>
- * Common interface for GUI element factories. 
- * </p>
- * 
- * @version 1.0
- * @author Patrick Harms
- */
-public interface IGUIElementFactory {
-
-    /**
-     * <p>
-     * Instantiates a new {@link IGUIElement} from a given specification.
-     * </p>
-     * 
-     * @param specification
-     *            specification of the new GUI element
-     * @param parent
-     *            parent of the new GUI element
-     * @return created GUI element
-     * @throws GUIModelConfigurationException
-     *             thrown if there is a problem during the creation of the GUI element
-     */
-    public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent)
-        throws GUIModelConfigurationException;
-    
-}
Index: /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElementSpec.java
===================================================================
--- /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-core-events/src/main/java/de/ugoe/cs/autoquest/eventcore/guimodel/IGUIElementSpec.java	(revision 2146)
@@ -17,4 +17,6 @@
 import java.io.Serializable;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
+
 /**
  * <p>
@@ -25,5 +27,5 @@
  * @author Patrick Harms, Steffen Herbold
  */
-public interface IGUIElementSpec extends Serializable {
+public interface IGUIElementSpec extends Serializable, IEventTargetSpec {
 
     /**
@@ -51,34 +53,3 @@
     public String[] getTypeHierarchy();
 
-    /**
-     * <p>
-     * Evaluates if two GUI specifications are similar. Similar means that a heuristic determines
-     * that the two GUI specifications describe the same GUI element.
-     * </p>
-     * 
-     * @param other
-     *            specification whose similarity to this is evaluated
-     * @return true if the specifications are similar; false otherwise
-     */
-    public boolean getSimilarity(IGUIElementSpec other);
-
-    /**
-     * <p>
-     * Defines that {@link IGUIElement} implementations have to define equals.
-     * </p>
-     * 
-     * @see Object#equals(Object)
-     */
-    @Override
-    public boolean equals(Object other);
-
-    /**
-     * <p>
-     * Defines that {@link IGUIElement} implementations have to define hashCode.
-     * </p>
-     * 
-     * @see Object#hashCode()
-     */
-    @Override
-    public int hashCode();
 }
Index: /trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java
===================================================================
--- /trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java	(revision 2145)
+++ /trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java	(revision 2146)
@@ -332,5 +332,9 @@
                 IIteration iteration = iterations.get(currentTask);
                 if (iteration != null) {
+                    // replacement required. Check if we already replaced a previous child, or if
+                    // we did, if the current child needs to be in the same iteration instance or
+                    // a new one.
                     if (!inReplacement || (iterationInstance.getTask() != iteration)) {
+                        // initiate a new replacement by creating the corresponding new instance
                         if (currentTask instanceof IOptional) {
                             IOptional optional = optionals.get(iteration);
@@ -347,4 +351,6 @@
                     }
                     
+                    // add the current task instance to the iteration instance that is going to
+                    // replace it
                     if (currentTask instanceof IOptional) {
                         ITaskInstance child = ((IOptionalInstance) session.get(index)).getChild();
@@ -363,7 +369,9 @@
                     }
                     
+                    // remove the task instance that was added to the replacing iteration instance
                     taskBuilder.removeTaskInstance(session, index);
                 }
                 else {
+                    // no replacement require. Finish previous replacements and continue
                     if (iterationInstance != null) {
                         iterationInstance = null;
@@ -384,5 +392,14 @@
     /**
      * <p>
-     * TODO clarify why this is done
+     * This may not be required anymore. The goal was the following. Consider two subsequent task
+     * instances which are detected to be repeating tasks on a level defined by the
+     * preparationTaskHandlingStrategy. Then the replacement of these iterated tasks by iteration
+     * instances would result in an iteration instance with two children, both of them having a
+     * different task assigned which does not match the child of the iteration model. This needs
+     * to be harmonized afterwards.
+     * </p>
+     * <p>
+     * <b>But, because we introduced the harmonization of event tasks directly at the beginning and
+     * afterwards, we compare only based on object identity, this may not be required anymore.</b>
      * </p>
      */
@@ -1217,9 +1234,4 @@
         List<Subsequence> potentialSuccessors = new LinkedList<Subsequence>();
         
-        appData.getStopWatch().start("determine locations");
-        Map<Subsequence, List<SubsequenceLocation>> allLocations =
-            getLocations(subsequences, appData);
-        appData.getStopWatch().stop("determine locations");
-        
         for (Subsequence subsequence : subsequences) {
             // Console.traceln
@@ -1240,8 +1252,8 @@
             
             List<Collision> precedingCollisions =
-                getPrecedingCollisions(subsequence, potentialPredecessors, allLocations, appData);
+                getPrecedingCollisions(subsequence, potentialPredecessors, appData);
             
             List<Collision> succeedingCollisions =
-                getSucceedingCollisions(subsequence, potentialSuccessors, allLocations, appData);
+                getSucceedingCollisions(subsequence, potentialSuccessors, appData);
             
             if ((precedingCollisions.size() <= 0) && (succeedingCollisions.size() <= 0)) {
@@ -1431,11 +1443,11 @@
      *
      */
-    private List<Collision> getPrecedingCollisions
-        (Subsequence                                 subsequence,
-         List<Subsequence>                           potentialPredecessors,
-         Map<Subsequence, List<SubsequenceLocation>> allLocations,
-         RuleApplicationData                         appData)
+    private List<Collision> getPrecedingCollisions(Subsequence         subsequence,
+                                                   List<Subsequence>   potentialPredecessors,
+                                                   RuleApplicationData appData)
     {
         List<Collision> precedingCollisions = new LinkedList<Collision>();
+        Map<Subsequence, List<SubsequenceLocation>> allLocations =
+            appData.getLastFoundSubsequenceLocations();
         
         for (SubsequenceLocation location : allLocations.get(subsequence)) {
@@ -1457,12 +1469,12 @@
      *
      */
-    private List<Collision> getSucceedingCollisions
-        (Subsequence                                 subsequence,
-         List<Subsequence>                           potentialSuccessors,
-         Map<Subsequence, List<SubsequenceLocation>> allLocations,
-         RuleApplicationData                         appData)
+    private List<Collision> getSucceedingCollisions(Subsequence         subsequence,
+                                                    List<Subsequence>   potentialSuccessors,
+                                                    RuleApplicationData appData)
     {
         List<Collision> succeedingCollisions = new LinkedList<Collision>();
-
+        Map<Subsequence, List<SubsequenceLocation>> allLocations =
+            appData.getLastFoundSubsequenceLocations();
+        
         for (SubsequenceLocation location : allLocations.get(subsequence)) {
             for (Subsequence successor : potentialSuccessors) {
@@ -1724,7 +1736,7 @@
      * @return
      */
-    private int getSubListIndex(ITaskInstanceList   list,
-                                Subsequence         subsequence,
-                                int                 startIndex)
+    private static int getSubListIndex(ITaskInstanceList   list,
+                                       Subsequence         subsequence,
+                                       int                 startIndex)
     {
         boolean matchFound;
@@ -2141,4 +2153,9 @@
          * 
          */
+        private Map<Subsequence, List<SubsequenceLocation>> lastFoundSubsequenceLocations;
+        
+        /**
+         * 
+         */
         private boolean detectedAndReplacedTasks;
         
@@ -2200,4 +2217,5 @@
         private void setLastFoundSubsequences(Subsequences lastFoundSequences) {
             this.lastFoundSubsequences = lastFoundSequences;
+            this.lastFoundSubsequenceLocations = null;
         }
 
@@ -2207,4 +2225,39 @@
         private Subsequences getLastFoundSubsequences() {
             return lastFoundSubsequences;
+        }
+
+        /**
+         * @return the lastFoundSequences
+         */
+        private Map<Subsequence, List<SubsequenceLocation>> getLastFoundSubsequenceLocations() {
+            if (lastFoundSubsequenceLocations != null) {
+                return lastFoundSubsequenceLocations;
+            }
+            
+            lastFoundSubsequenceLocations =
+                new IdentityHashMap<Subsequence, List<SubsequenceLocation>>();
+                
+            // fill the map with empty locations
+            for (Subsequence subsequence : lastFoundSubsequences) {
+                lastFoundSubsequenceLocations.put
+                    (subsequence, new LinkedList<SubsequenceLocation>());
+            }
+            
+            for (IUserSession session : sessions) {
+                for (Subsequence candidate : lastFoundSubsequences) {
+                    int index = -1;
+                    do {
+                        index = getSubListIndex(session, candidate, index + 1);
+                    
+                        if (index > -1) {
+                            lastFoundSubsequenceLocations.get
+                                (candidate).add(new SubsequenceLocation(session, index));
+                        }
+                    }
+                    while (index > -1);
+                }
+            }
+                
+            return lastFoundSubsequenceLocations;
         }
 
Index: /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/DefaultValueRule.java
===================================================================
--- /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/DefaultValueRule.java	(revision 2145)
+++ /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/DefaultValueRule.java	(revision 2146)
@@ -29,4 +29,7 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
 import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
@@ -609,4 +612,11 @@
 
         /**
+         * 
+         */
+        public IHierarchicalEventTargetModel<?> getEventTargetModel() {
+            return target.getEventTargetModel();
+        }
+
+        /**
          *
          */
@@ -653,5 +663,5 @@
          *
          */
-        public void updateSpecification(IGUIElementSpec furtherSpec) {
+        public void updateSpecification(IEventTargetSpec furtherSpec) {
             target.updateSpecification(furtherSpec);
         }
@@ -660,6 +670,6 @@
          * 
          */
-        public void addEqualGUIElement(IGUIElement equalElement) {
-            target.addEqualGUIElement(equalElement);
+        public void addEqualEventTarget(IHierarchicalEventTarget equalElement) {
+            target.addEqualEventTarget(equalElement);
         }
 
Index: /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RuleUtils.java
===================================================================
--- /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RuleUtils.java	(revision 2145)
+++ /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RuleUtils.java	(revision 2146)
@@ -23,5 +23,5 @@
 import java.util.Map;
 
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementGroup;
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetGroup;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 
@@ -123,5 +123,5 @@
         
         while (parent != null) {
-            if (!(parent instanceof GUIElementGroup)) {
+            if (!(parent instanceof HierarchicalEventTargetGroup)) {
                 result = parent.toString() + "/" + result;
             }
@@ -149,5 +149,5 @@
             IGUIElement parent = guiElement;
             while (parent != null) {
-                if (!(parent instanceof GUIElementGroup)) {
+                if (!(parent instanceof HierarchicalEventTargetGroup)) {
                     path.addFirst(parent);
                 }
Index: /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java
===================================================================
--- /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java	(revision 2145)
+++ /trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java	(revision 2146)
@@ -24,4 +24,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
@@ -175,5 +176,5 @@
         GUIModel model = result.values().iterator().next().iterator().next().getGUIModel();
         
-        GUIModel.Traverser traverser = model.getTraverser();
+        IHierarchicalEventTargetModel.Traverser<IGUIElement> traverser = model.getTraverser();
 
         IGUIElement currentGUIElement = null;
Index: /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/AndroidLogParser.java
===================================================================
--- /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/AndroidLogParser.java	(revision 2145)
+++ /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/AndroidLogParser.java	(revision 2146)
@@ -39,4 +39,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
 import de.ugoe.cs.autoquest.eventcore.gui.IInteraction;
 import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
@@ -44,5 +45,4 @@
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.plugin.android.guimodel.ANDROIDGUIElement;
@@ -374,5 +374,5 @@
                                           currentGUIElementSpec);
             }
-            catch (GUIModelException e) {
+            catch (EventTargetModelException e) {
                 throw new SAXException("could not handle GUI element with hash " +
                     currentGUIElementHash + ": " + e.getMessage(), e);
Index: /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElement.java
===================================================================
--- /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElement.java	(revision 2145)
+++ /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElement.java	(revision 2146)
@@ -15,7 +15,7 @@
 package de.ugoe.cs.autoquest.plugin.android.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
 
@@ -68,5 +68,5 @@
      */
     @Override
-    public void updateSpecification(IGUIElementSpec furtherSpec) {
+    public void updateSpecification(IEventTargetSpec furtherSpec) {
         // nothing do do here up to now.
     }
Index: /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElementSpec.java
===================================================================
--- /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-android/src/main/java/de/ugoe/cs/autoquest/plugin/android/guimodel/ANDROIDGUIElementSpec.java	(revision 2146)
@@ -17,4 +17,5 @@
 import java.util.List;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
@@ -106,5 +107,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (this == other) {
             return true;
Index: /trunk/autoquest-plugin-html-test/src/test/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModelTest.java
===================================================================
--- /trunk/autoquest-plugin-html-test/src/test/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModelTest.java	(revision 2145)
+++ /trunk/autoquest-plugin-html-test/src/test/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModelTest.java	(revision 2146)
@@ -26,9 +26,9 @@
 import org.junit.Test;
 
+import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetGroup;
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementFactory;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementGroup;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel.Traverser;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
@@ -343,5 +343,5 @@
      */
     private GUIModel generateGUIModel(String[] guiSpec)
-        throws IllegalArgumentException, GUIModelException
+        throws IllegalArgumentException, EventTargetModelException
     {
         GUIModel model = new GUIModel(true);
@@ -430,5 +430,5 @@
         }
         
-        GUIModel.Traverser traverser = guiModel.getTraverser();
+        IHierarchicalEventTargetModel.Traverser<IGUIElement> traverser = guiModel.getTraverser();
         
         assertPaths(traverser, "", paths);
@@ -440,5 +440,5 @@
      *
      */
-    private void assertPaths(Traverser traverser, String path, List<String> paths) {
+    private void assertPaths(IHierarchicalEventTargetModel.Traverser<IGUIElement> traverser, String path, List<String> paths) {
         if (traverser.hasFirstChild()) {
             IGUIElement childElement = traverser.firstChild();
@@ -481,6 +481,6 @@
             }
         }
-        else if (childElement instanceof GUIElementGroup) {
-            String tmp = ((GUIElementGroup) childElement).getStringIdentifier();
+        else if (childElement instanceof HierarchicalEventTargetGroup) {
+            String tmp = ((HierarchicalEventTargetGroup) childElement).getStringIdentifier();
             tmp = tmp.replaceAll("/", "");
             tmp = tmp.replaceAll("\\[", "");
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java	(revision 2146)
@@ -35,7 +35,7 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
 import de.ugoe.cs.autoquest.eventcore.IEventType;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.plugin.html.eventcore.HTMLEventTypeFactory;
@@ -273,5 +273,5 @@
                 super.getGUIElementTree().add(replacementId, parentId, specification);
             }
-            catch (GUIModelException e) {
+            catch (EventTargetModelException e) {
                 throw new SAXException("could not handle GUI element with id " +
                                        id + ": " + e.getMessage(), e);
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLGUIModel.java	(revision 2146)
@@ -25,4 +25,5 @@
 
 import de.ugoe.cs.autoquest.CommandHelpers;
+import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementFactory;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
@@ -445,5 +446,5 @@
                 //System.out.println(indent + "merging " + mergeResult + " and " +
                 //                   similarGUIElements.get(1).similarGUIElement);
-                mergeResult = model.mergeGUIElements
+                mergeResult = model.mergeEventTargets
                         (mergeResult, similarGUIElements.remove(1).similarGUIElement, false);
             }
@@ -492,5 +493,6 @@
         
         //System.out.println(indent + "grouping: " + guiElementsToGroup);
-        IGUIElement group = model.groupGUIElements(guiElementsToGroup, getGroupName(cluster));
+        IGUIElement group = model.groupEventTargets
+            (guiElementsToGroup, getGroupName(cluster), GUIElementFactory.getInstance());
         //System.out.println(indent + "  created group for " + cluster + ": " + group);
         
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLListStructures.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLListStructures.java	(revision 2146)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDcondenseHTMLListStructures.java	(revision 2146)
@@ -0,0 +1,278 @@
+//   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.plugin.html.commands;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import de.ugoe.cs.autoquest.CommandHelpers;
+import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLDocument;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLPageElement;
+import de.ugoe.cs.autoquest.plugin.html.guimodel.HTMLServer;
+import de.ugoe.cs.util.console.Command;
+import de.ugoe.cs.util.console.Console;
+import de.ugoe.cs.util.console.GlobalDataContainer;
+
+/**
+ * <p>
+ * TODO document
+ * </p>
+ * 
+ * @author Patrick Harms
+ * @version 1.0
+ */
+public class CMDcondenseHTMLListStructures implements Command {
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.util.console.Command#run(java.util.List)
+     */
+    @Override
+    public void run(List<Object> parameters) {
+        String sequencesName;
+
+        try {
+            sequencesName = (String) parameters.get(0);
+        }
+        catch (Exception e) {
+            throw new IllegalArgumentException("illegal parameters provided: " + e);
+        }
+
+        Object dataObject = GlobalDataContainer.getInstance().getData(sequencesName + "_targets");
+        if (dataObject == null) {
+            CommandHelpers.objectNotFoundMessage(sequencesName + "_targets");
+            return;
+        }
+        if (!(dataObject instanceof GUIModel)) {
+            CommandHelpers.objectNotType(sequencesName, "GUIModel");
+            return;
+        }
+
+        GUIModel model = (GUIModel) dataObject;
+        
+        for (IGUIElement root : model.getRootElements()) {
+            if (root instanceof HTMLServer) {
+                try {
+                    condenseListStructures((HTMLServer) root, model);
+                }
+                catch (Exception e) {
+                    Console.printerrln
+                        ("problems while condensing list structures on pages of server " + root);
+                    Console.logException(e);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * 
+     * </p>
+     *
+     * @param server the server of which all documents shall be condensed
+     * @param model  the GUI model in which the server is referenced
+     */
+    private void condenseListStructures(HTMLServer server, GUIModel model) {
+        Console.traceln(Level.INFO, "condensing list structures in documents of " + server);
+        
+        for (IGUIElement document : model.getChildren(server)) {
+            if (document instanceof HTMLDocument) {
+                condenseListStructures((HTMLDocument) document, model, "");
+            }
+            else {
+                Console.traceln(Level.WARNING, "child " + document + " of server " + server +
+                                " is no document");
+            }
+        }
+        
+        Console.traceln(Level.INFO, "condensed list structures in documents of " + server);
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param document
+     * @param model
+     * @param string
+     */
+    private void condenseListStructures(HTMLDocument document, GUIModel model, String indent) {
+        for (IGUIElement pageElement : model.getChildren(document)) {
+            if (pageElement instanceof HTMLPageElement) {
+                condenseListStructures((HTMLPageElement) pageElement, model, indent + "  ");
+            }
+            else {
+                Console.traceln(Level.WARNING, "child " + pageElement + " of document " + document +
+                                " is no page element");
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param pageElement
+     * @param model
+     * @param string
+     */
+    private List<List<HTMLPageElement>> condenseListStructures(HTMLPageElement pageElement,
+                                                               GUIModel        model,
+                                                               String          indent)
+    {
+        List<IGUIElement> children = model.getChildren(pageElement);
+        
+        if ((children == null) || (children.size() == 0)) {
+            // no children, return the element itself as the single entry of a list
+            List<List<HTMLPageElement>> result = new ArrayList<>();
+            result.add(new ArrayList<HTMLPageElement>());
+            result.get(0).add(pageElement);
+            return result;
+        }
+        
+        // traverse the children for structure information
+        @SuppressWarnings("unchecked")
+        List<List<HTMLPageElement>>[] childPaths = new List[children.size()];
+        int index = 0;
+        for (IGUIElement childElement : children) {
+            if (childElement instanceof HTMLPageElement) {
+                childPaths[index++] =
+                    condenseListStructures((HTMLPageElement) childElement, model, indent + "  ");
+            }
+            else {
+                Console.traceln(Level.WARNING, "child " + childElement + " of " + pageElement +
+                                " is no page element");
+            }
+        }
+        
+        // check for equally structured direct sibling children and group them. For this, their
+        // child paths need to be equal ignoring the HTML ids. So check for this.
+        Map<Integer, List<Integer>> equallyStructured = new HashMap<>();
+        int indexToCompareTo = 0;
+        equallyStructured.put(indexToCompareTo, new ArrayList<Integer>());
+        
+        SEARCH:
+        for (int i = 1; i < childPaths.length; i++) {
+            // compare any with the previous that needs to be compared with.
+            if (childPaths[indexToCompareTo].size() != childPaths[i].size()) {
+                // no equally structured children, try next.
+                indexToCompareTo = i;
+                equallyStructured.put(indexToCompareTo, new ArrayList<Integer>());
+                continue SEARCH;
+            }
+            
+            // compare individual child paths, first for their length
+            for (int j = 0; j < childPaths[indexToCompareTo].size(); j++) {
+                List<HTMLPageElement> firstPath = childPaths[indexToCompareTo].get(j);
+                List<HTMLPageElement> secondPath = childPaths[i].get(j);
+                if (firstPath.size() != secondPath.size()) {
+                    // no equally structured children, try next.
+                    indexToCompareTo = i;
+                    equallyStructured.put(indexToCompareTo, new ArrayList<Integer>());
+                    continue SEARCH;
+                }
+            
+                // compare individual path elements
+                for (int k = 0; k < firstPath.size(); k++) {
+                    if (!firstPath.get(k).getTagName().equals(secondPath.get(k).getTagName())) {
+                        // no equally structured children, try next.
+                        indexToCompareTo = i;
+                        equallyStructured.put(indexToCompareTo, new ArrayList<Integer>());
+                        continue SEARCH;
+                    }
+                }
+            }
+                
+            // found a match
+            equallyStructured.get(indexToCompareTo).add(i);
+        }
+        
+        for (Map.Entry<Integer, List<Integer>> entry : equallyStructured.entrySet()) {
+            if ((entry.getValue().size() > 1)) {
+                entry.getValue().add(0, entry.getKey());
+                
+                // check if the equal one have a minimum depth of 3
+                boolean hasMinDepth = false;
+                for (Integer indexesOfEqualChildren : entry.getValue()) {
+                    for (List<HTMLPageElement> path : childPaths[indexesOfEqualChildren]) {
+                        if (path.size() >= 3) {
+                            hasMinDepth = true;
+                            break;
+                        }
+                    }
+                }
+                
+                if (!hasMinDepth) {
+                    continue;
+                }
+                
+                // found equally structured children --> dump them
+                System.out.print("tata: " + pageElement.getView() + "  ");
+                String log = "";
+                
+                IGUIElement elem = pageElement;
+                while ((elem != null) && (elem instanceof HTMLPageElement)) {
+                    log = elem + "/" + log;
+                    elem = elem.getParent();
+                }
+                
+                System.out.println(log);
+                
+                for (int i = 0; i < entry.getValue().size(); i++) {
+                    System.out.println("  child " + (i + 1));
+                    for (int j = 0; j < childPaths[entry.getValue().get(i)].size(); j++) {
+                        System.out.print("    ");
+                        List<HTMLPageElement> path = childPaths[entry.getValue().get(i)].get(j);
+                        for (int k = 0; k < path.size(); k++) {
+                            System.out.print(path.get(k));
+                            System.out.print('/');
+                        }
+                        System.out.println();
+                    }
+                }
+            }
+        }
+        
+        List<List<HTMLPageElement>> result = new ArrayList<>();
+        for (List<List<HTMLPageElement>> childStructure : childPaths) {
+            for (List<HTMLPageElement> childPath : childStructure) {
+                childPath.add(0, pageElement);
+                result.add(childPath);
+            }
+        }
+        
+        return result;
+    }
+        
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.ugoe.cs.util.console.Command#help()
+     */
+    @Override
+    public String help() {
+        return "condenseHTMLListStructures <sequence>";
+    }
+}
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDgenerateSeleniumReplay.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDgenerateSeleniumReplay.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/commands/CMDgenerateSeleniumReplay.java	(revision 2146)
@@ -173,4 +173,7 @@
                             case TAB:
                                 value = "${KEY_TAB}";
+                                break;
+                            default:
+                                break;
                         }
                     }
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLDocumentSpec.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLDocumentSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLDocumentSpec.java	(revision 2146)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.plugin.html.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
@@ -99,5 +100,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (other instanceof HTMLDocumentSpec) {
             HTMLDocumentSpec otherSpec = (HTMLDocumentSpec) other;
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElement.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElement.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElement.java	(revision 2146)
@@ -15,6 +15,6 @@
 package de.ugoe.cs.autoquest.plugin.html.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
 /**
@@ -113,6 +113,6 @@
      */
     @Override
-    public void updateSpecification(IGUIElementSpec updateSpecification) {
-        // nothing to do. There is not need for handle things such as name changes, etc.
+    public void updateSpecification(IEventTargetSpec updateSpecification) {
+        // nothing to do. There is no need for handle things such as name changes, etc.
     }
 
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElementSpec.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLGUIElementSpec.java	(revision 2146)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.plugin.html.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
@@ -78,5 +79,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (other instanceof HTMLGUIElementSpec) {
             HTMLGUIElementSpec otherSpec = (HTMLGUIElementSpec) other;
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLPageElementSpec.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLPageElementSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLPageElementSpec.java	(revision 2146)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.plugin.html.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
@@ -108,5 +109,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (other instanceof HTMLPageElementSpec) {
             HTMLPageElementSpec otherSpec = (HTMLPageElementSpec) other;
Index: /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLServerSpec.java
===================================================================
--- /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLServerSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/guimodel/HTMLServerSpec.java	(revision 2146)
@@ -15,4 +15,5 @@
 package de.ugoe.cs.autoquest.plugin.html.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 
@@ -77,5 +78,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (other instanceof HTMLServerSpec) {
             HTMLServerSpec otherSpec = (HTMLServerSpec) other;
Index: /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCLogParser.java
===================================================================
--- /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCLogParser.java	(revision 2145)
+++ /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCLogParser.java	(revision 2146)
@@ -43,4 +43,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
 import de.ugoe.cs.autoquest.eventcore.gui.IInteraction;
 import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed;
@@ -53,5 +54,4 @@
 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.IGUIElement;
 import de.ugoe.cs.autoquest.keyboardmaps.VirtualKey;
@@ -407,5 +407,5 @@
                         (currentGuiElementPath, GUIElementFactory.getInstance());
                 }
-                catch (GUIModelException e) {
+                catch (EventTargetModelException e) {
                     throw new SAXException("error in the GUI model provided in the log", e);
                 }
Index: /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCSimplifiedLogParser.java
===================================================================
--- /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCSimplifiedLogParser.java	(revision 2145)
+++ /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/JFCSimplifiedLogParser.java	(revision 2146)
@@ -41,4 +41,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
 import de.ugoe.cs.autoquest.eventcore.gui.IInteraction;
 import de.ugoe.cs.autoquest.eventcore.gui.KeyPressed;
@@ -51,5 +52,4 @@
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.keyboardmaps.VirtualKey;
@@ -436,5 +436,5 @@
                 currentGUIElementTree.add(guiElementId, parentGuiElementId, currentGuiElementSpec);
             }
-            catch (GUIModelException e) {
+            catch (EventTargetModelException e) {
                 throw new SAXException("could not handle GUI element with hash " +
                                        currentGUIElementHash + ": " + e.getMessage(), e);
Index: /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElement.java
===================================================================
--- /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElement.java	(revision 2145)
+++ /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElement.java	(revision 2146)
@@ -15,7 +15,7 @@
 package de.ugoe.cs.autoquest.plugin.jfc.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
 
@@ -169,5 +169,5 @@
      */
     @Override
-    public void updateSpecification(IGUIElementSpec updateSpecification) {
+    public void updateSpecification(IEventTargetSpec updateSpecification) {
         if (updateSpecification instanceof JFCGUIElementSpec) {
             specification.update(((JFCGUIElementSpec) updateSpecification));
Index: /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElementSpec.java
===================================================================
--- /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-jfc/src/main/java/de/ugoe/cs/autoquest/plugin/jfc/guimodel/JFCGUIElementSpec.java	(revision 2146)
@@ -21,4 +21,5 @@
 import org.apache.commons.lang.mutable.MutableInt;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
@@ -113,5 +114,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
         if (this == other) {
             return true;
Index: /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/HandlerCreate.java
===================================================================
--- /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/HandlerCreate.java	(revision 2145)
+++ /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/HandlerCreate.java	(revision 2146)
@@ -17,6 +17,6 @@
 import org.xml.sax.SAXException;
 
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementTree;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModelException;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.plugin.mfc.guimodel.MFCGUIElementSpec;
@@ -98,5 +98,5 @@
                 super.getGUIElementTree().add(hwnd, parentHwnd, spec);
             }
-            catch (GUIModelException e) {
+            catch (EventTargetModelException e) {
                 throw new SAXException("could not handle GUI element with handle " +
                                        hwnd + ": " + e.getMessage(), e);
Index: /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElement.java
===================================================================
--- /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElement.java	(revision 2145)
+++ /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElement.java	(revision 2146)
@@ -15,7 +15,7 @@
 package de.ugoe.cs.autoquest.plugin.mfc.guimodel;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
 
@@ -125,6 +125,8 @@
      */
     @Override
-    public void updateSpecification(IGUIElementSpec furtherSpec) {
-        ((MFCGUIElementSpec) super.getSpecification()).update(furtherSpec);
+    public void updateSpecification(IEventTargetSpec furtherSpec) {
+        if (furtherSpec instanceof MFCGUIElementSpec) {
+            ((MFCGUIElementSpec) super.getSpecification()).update((MFCGUIElementSpec) furtherSpec);
+        }
     }
 
Index: /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElementSpec.java
===================================================================
--- /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElementSpec.java	(revision 2145)
+++ /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCGUIElementSpec.java	(revision 2146)
@@ -18,4 +18,5 @@
 import java.util.List;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.util.StringTools;
@@ -241,5 +242,5 @@
      */
     @Override
-    public boolean getSimilarity(IGUIElementSpec other) {
+    public boolean getSimilarity(IEventTargetSpec other) {
 
         if (this == other) {
Index: /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCWindowTree.java
===================================================================
--- /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCWindowTree.java	(revision 2145)
+++ /trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/guimodel/MFCWindowTree.java	(revision 2146)
@@ -22,8 +22,8 @@
 import java.util.Set;
 
+import de.ugoe.cs.autoquest.eventcore.EventTargetModelException;
+import de.ugoe.cs.autoquest.eventcore.IEventTargetFactory;
 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;
 
 /**
@@ -87,5 +87,5 @@
      * </p>
      */
-    private IGUIElementFactory guiElementFactory = GUIElementFactory.getInstance();
+    private IEventTargetFactory guiElementFactory = GUIElementFactory.getInstance();
 
     /**
@@ -188,5 +188,5 @@
                     (MFCGUIElement) guiModel.integratePath(guiElementPath, guiElementFactory);
             }
-            catch (GUIModelException e) {
+            catch (EventTargetModelException e) {
                 throw new RuntimeException("could not instantiate GUI element with id " + hwnd, e);
             }
Index: /trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/test/DummyGUIElement.java
===================================================================
--- /trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/test/DummyGUIElement.java	(revision 2145)
+++ /trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/test/DummyGUIElement.java	(revision 2146)
@@ -15,7 +15,7 @@
 package de.ugoe.cs.autoquest.test;
 
+import de.ugoe.cs.autoquest.eventcore.IEventTargetSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.AbstractDefaultGUIElement;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
 
@@ -89,5 +89,5 @@
 
     @Override
-    public void updateSpecification(IGUIElementSpec specToIntegrateElementFor) {
+    public void updateSpecification(IEventTargetSpec specToIntegrateElementFor) {
         // dummy
     }
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/AbstractInsertEventComposite.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/AbstractInsertEventComposite.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/AbstractInsertEventComposite.java	(revision 2146)
@@ -18,13 +18,13 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 abstract public class AbstractInsertEventComposite extends Composite {
 
-    protected GUIModel guiModel;
+    protected IHierarchicalEventTargetModel<?> eventTargetModel;
 
-    public AbstractInsertEventComposite(Composite parent, int style, GUIModel guiModel) {
+    public AbstractInsertEventComposite(Composite parent, int style, IHierarchicalEventTargetModel<?> eventTargetModel) {
         super(parent, style);
-        this.guiModel = guiModel;
+        this.eventTargetModel = eventTargetModel;
     }
 
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/EditSequenceDialog.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/EditSequenceDialog.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/EditSequenceDialog.java	(revision 2146)
@@ -32,5 +32,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 public class EditSequenceDialog extends Dialog {
@@ -43,5 +43,5 @@
 
     private java.util.List<Event> sequence;
-    private GUIModel guiModel;
+    private IHierarchicalEventTargetModel<?> eventTargetModel;
 
     /**
@@ -51,8 +51,8 @@
      * @param style
      */
-    public EditSequenceDialog(Shell parent, int style, GUIModel guiModel) {
+    public EditSequenceDialog(Shell parent, int style, IHierarchicalEventTargetModel<?> eventTargetModel) {
         super(parent, style);
         setText("SWT Dialog");
-        this.guiModel = guiModel;
+        this.eventTargetModel = eventTargetModel;
     }
 
@@ -206,5 +206,5 @@
 
     private void openInsertDialog(int position) {
-        if (guiModel == null) {
+        if (eventTargetModel == null) {
             MessageBox messageBox = new MessageBox(shell, SWT.ERROR);
             messageBox.setMessage("Operation not supported!\nOnly works for GUI sequences.");
@@ -212,5 +212,7 @@
             messageBox.open();
         } else {
-            InsertAssertionDialog insertDialog = new InsertAssertionDialog(shell, SWT.NONE, guiModel);
+            InsertAssertionDialog insertDialog =
+                new InsertAssertionDialog(shell, SWT.NONE, eventTargetModel);
+            
             Event event = insertDialog.open();
             if (event != null) {
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/GuiModelTabComposite.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/GuiModelTabComposite.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/GuiModelTabComposite.java	(revision 2146)
@@ -25,4 +25,6 @@
 import org.eclipse.swt.widgets.List;
 
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
 import de.ugoe.cs.util.console.GlobalDataContainer;
@@ -52,5 +54,5 @@
      * </p>
      */
-    private void createContents() {
+    private <T extends IHierarchicalEventTarget> void createContents() {
         setLayout(new GridLayout(5, false));
 
@@ -68,8 +70,12 @@
                 }
                 String modelName = selectedStrings[0];
-                GUIModel model = (GUIModel) GlobalDataContainer.getInstance().getData(modelName);
+                
+                @SuppressWarnings("unchecked")
+                IHierarchicalEventTargetModel<T> model =
+                    (IHierarchicalEventTargetModel<T>) GlobalDataContainer.getInstance().getData(modelName);
 
-                ShowGuiModelDialog showGuiModelDialog =
-                    new ShowGuiModelDialog(getShell(), SWT.NONE, model, modelName);
+                ShowGuiModelDialog<T> showGuiModelDialog =
+                    new ShowGuiModelDialog<T>(getShell(), SWT.NONE, model, modelName);
+                
                 showGuiModelDialog.open();
             }
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertAssertionDialog.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertAssertionDialog.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertAssertionDialog.java	(revision 2146)
@@ -31,5 +31,5 @@
 
 import de.ugoe.cs.autoquest.eventcore.Event;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 public class InsertAssertionDialog extends Dialog {
@@ -41,5 +41,5 @@
 
     List<AbstractInsertEventComposite> insertEventComposites;
-    GUIModel guiModel;
+    IHierarchicalEventTargetModel<?> eventTargetModel;
 
     /**
@@ -49,8 +49,8 @@
      * @param style
      */
-    public InsertAssertionDialog(Shell parent, int style, GUIModel guiModel) {
+    public InsertAssertionDialog(Shell parent, int style, IHierarchicalEventTargetModel<?> eventTargetModel) {
         super(parent, style);
         setText("SWT Dialog");
-        this.guiModel = guiModel;
+        this.eventTargetModel = eventTargetModel;
     }
 
@@ -90,5 +90,5 @@
         tbtmTextEquals.setText("TextEquals");
         AbstractInsertEventComposite compTextEquals =
-            new InsertTextEquals(tabFolder, SWT.NO_BACKGROUND, guiModel);
+            new InsertTextEquals(tabFolder, SWT.NO_BACKGROUND, eventTargetModel);
         tbtmTextEquals.setControl(compTextEquals);
         insertEventComposites.add(compTextEquals);
@@ -97,5 +97,5 @@
         tbtmFileEquals.setText("FileEquals");
         AbstractInsertEventComposite compFileEquals =
-            new InsertFileEquals(tabFolder, SWT.NO_BACKGROUND, guiModel);
+            new InsertFileEquals(tabFolder, SWT.NO_BACKGROUND, eventTargetModel);
         tbtmFileEquals.setControl(compFileEquals);
         insertEventComposites.add(compFileEquals);
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertFileEquals.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertFileEquals.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertFileEquals.java	(revision 2146)
@@ -27,5 +27,5 @@
 import de.ugoe.cs.autoquest.assertions.FileEqualsReplay;
 import de.ugoe.cs.autoquest.eventcore.Event;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 import org.eclipse.swt.events.SelectionAdapter;
@@ -46,6 +46,6 @@
      * @param style
      */
-    public InsertFileEquals(Composite parent, int style, GUIModel guiModel) {
-        super(parent, style, guiModel);
+    public InsertFileEquals(Composite parent, int style, IHierarchicalEventTargetModel<?> eventTargetModel) {
+        super(parent, style, eventTargetModel);
         setLayout(new GridLayout(3, false));
 
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertTextEquals.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertTextEquals.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/InsertTextEquals.java	(revision 2146)
@@ -31,6 +31,6 @@
 import de.ugoe.cs.autoquest.eventcore.Event;
 import de.ugoe.cs.autoquest.eventcore.IEventTarget;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
-import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 
 import org.eclipse.swt.events.SelectionAdapter;
@@ -47,6 +47,6 @@
      * @param style
      */
-    public InsertTextEquals(Composite parent, int style, GUIModel guiModel) {
-        super(parent, style, guiModel);
+    public InsertTextEquals(Composite parent, int style, IHierarchicalEventTargetModel<?> eventTargetModel) {
+        super(parent, style, eventTargetModel);
         setLayout(new GridLayout(3, false));
 
@@ -60,5 +60,5 @@
         guiTree = new Tree(this, SWT.BORDER);
         guiTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
-        buildGuiTree();
+        buildGuiTree(eventTargetModel);
         new Label(this, SWT.NONE);
 
@@ -109,19 +109,22 @@
     }
 
-    private void buildGuiTree() {
-        for (IGUIElement element : guiModel.getRootElements()) {
+    private <T extends IHierarchicalEventTarget> void buildGuiTree(IHierarchicalEventTargetModel<T> eventTargetModel) {
+        for (T element : eventTargetModel.getRootElements()) {
             TreeItem child = new TreeItem(guiTree, SWT.NULL);
             child.setText(element.toString());
             child.setData(element);
-            buildGuiTree(child, guiModel.getChildren(element));
+            buildGuiTree(child, eventTargetModel.getChildren(element), eventTargetModel);
         }
     }
 
-    private void buildGuiTree(TreeItem currentParent, List<IGUIElement> elements) {
-        for (IGUIElement element : elements) {
+    private <T extends IHierarchicalEventTarget> void buildGuiTree(TreeItem                         currentParent,
+                                                                   List<T>                          list,
+                                                                   IHierarchicalEventTargetModel<T> eventTargetModel)
+    {
+        for (T element : list) {
             TreeItem child = new TreeItem(currentParent, SWT.NULL);
             child.setText(element.toString());
             child.setData(element);
-            buildGuiTree(child, guiModel.getChildren(element));
+            buildGuiTree(child, eventTargetModel.getChildren(element), eventTargetModel);
         }
     }
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/SequencesDialog.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/SequencesDialog.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/SequencesDialog.java	(revision 2146)
@@ -29,5 +29,5 @@
 import de.ugoe.cs.autoquest.SequenceInstanceOf;
 import de.ugoe.cs.autoquest.eventcore.Event;
-import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.util.console.GlobalDataContainer;
 
@@ -41,5 +41,5 @@
     private List sequenceList;
     private Collection<java.util.List<Event>> sequences;
-    private GUIModel guiModel;
+    private IHierarchicalEventTargetModel<?> eventTargetModel;
 
     protected Shell shell;
@@ -99,5 +99,5 @@
                 else {
                     EditSequenceDialog editSequenceDialog =
-                        new EditSequenceDialog(shell, SWT.NONE, guiModel);
+                        new EditSequenceDialog(shell, SWT.NONE, eventTargetModel);
                     int counter = 0;
                     java.util.List<Event> selectedSequence = null;
@@ -143,7 +143,7 @@
             Object targetObject =
                 GlobalDataContainer.getInstance().getData(sequencesName + "_targets");
-            guiModel = null;
-            if (targetObject instanceof GUIModel) {
-                guiModel = (GUIModel) targetObject;
+            eventTargetModel = null;
+            if (targetObject instanceof IHierarchicalEventTargetModel) {
+                eventTargetModel = (IHierarchicalEventTargetModel<?>) targetObject;
             }
         }
Index: /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/ShowGuiModelDialog.java
===================================================================
--- /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/ShowGuiModelDialog.java	(revision 2145)
+++ /trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/ShowGuiModelDialog.java	(revision 2146)
@@ -28,4 +28,6 @@
 import org.eclipse.swt.widgets.TreeItem;
 
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
+import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
 import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
@@ -34,12 +36,12 @@
 import org.eclipse.swt.widgets.Label;
 
-public class ShowGuiModelDialog extends Dialog {
+public class ShowGuiModelDialog<T extends IHierarchicalEventTarget> extends Dialog {
 
     protected Shell shell;
-    private Tree guiTree;
-
-    protected GUIModel model;
-
-    public ShowGuiModelDialog(Shell parent, int style, GUIModel model, String modelName) {
+    private Tree targetTree;
+
+    protected IHierarchicalEventTargetModel<T> model;
+
+    public ShowGuiModelDialog(Shell parent, int style, IHierarchicalEventTargetModel<T> model, String modelName) {
         super(parent, style);
         setText("GUI Model " + modelName);
@@ -66,8 +68,8 @@
         shell.setLayout(new GridLayout(4, false));
 
-        guiTree = new Tree(shell, SWT.BORDER | SWT.MULTI);
-        guiTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
-
-        buildGuiTree();
+        targetTree = new Tree(shell, SWT.BORDER | SWT.MULTI);
+        targetTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
+
+        buildTargetTree();
 
         Button btnExpandAll = new Button(shell, SWT.NONE);
@@ -75,5 +77,5 @@
             @Override
             public void widgetSelected(SelectionEvent e) {
-                expandAll(guiTree, true);
+                expandAll(targetTree, true);
             }
         });
@@ -84,28 +86,30 @@
             @Override
             public void widgetSelected(SelectionEvent e) {
-                expandAll(guiTree, false);
+                expandAll(targetTree, false);
             }
         });
         btnCollapseAll.setText("Collapse all");
         
-        Button btnCondense = new Button(shell, SWT.NONE);
-        btnCondense.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                model.condenseModel();
-                guiTree.removeAll();
-                buildGuiTree();
-            }
-        });
-        btnCondense.setText("Condense");
-        
-        Button btnMerge = new Button(shell, SWT.NONE);
-        btnMerge.addSelectionListener(new SelectionAdapter() {
-            @Override
-            public void widgetSelected(SelectionEvent e) {
-                mergeSelectedNode(guiTree);
-            }
-        });
-        btnMerge.setText("Merge nodes");
+        if (model instanceof GUIModel) {
+            Button btnCondense = new Button(shell, SWT.NONE);
+            btnCondense.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    ((GUIModel) model).condenseModel();
+                    targetTree.removeAll();
+                    buildTargetTree();
+                }
+            });
+            btnCondense.setText("Condense");
+
+            Button btnMerge = new Button(shell, SWT.NONE);
+            btnMerge.addSelectionListener(new SelectionAdapter() {
+                @Override
+                public void widgetSelected(SelectionEvent e) {
+                    mergeSelectedNode(targetTree);
+                }
+            });
+            btnMerge.setText("Merge nodes");
+        }
         
         //new Label(shell, SWT.NONE);
@@ -116,21 +120,23 @@
     }
 
-    private void buildGuiTree() {
-        GUIModel.Traverser traverser = model.getTraverser();
-        
-        IGUIElement root = traverser.firstChild();
+    private void buildTargetTree() {
+        IHierarchicalEventTargetModel.Traverser<T> traverser =  model.getTraverser();
+        
+        IHierarchicalEventTarget root = traverser.firstChild();
         
         while (root != null) {
-            TreeItem child = new TreeItem(guiTree, SWT.NULL);
+            TreeItem child = new TreeItem(targetTree, SWT.NULL);
             child.setText(root.toString());
             child.setData(root);
-            buildGuiTree(child, traverser);
+            buildTargetTree(child, traverser);
             root = traverser.nextSibling();
         }
     }
 
-    private void buildGuiTree(TreeItem currentParent, GUIModel.Traverser traverser) {
+    private void buildTargetTree(TreeItem                                   currentParent,
+                                 IHierarchicalEventTargetModel.Traverser<T> traverser)
+    {
         if (traverser.hasFirstChild()) {
-            IGUIElement childElement = traverser.firstChild();
+            T childElement = traverser.firstChild();
         
             while (childElement != null) {
@@ -138,5 +144,5 @@
                 child.setText(childElement.toString());
                 child.setData(childElement);
-                buildGuiTree(child, traverser);
+                buildTargetTree(child, traverser);
                 childElement = traverser.nextSibling();
             }
@@ -159,4 +165,5 @@
     }
     
+    @SuppressWarnings("unchecked")
     private void mergeSelectedNode(Tree tree) {
         TreeItem[] selectedNodes = tree.getSelection();
@@ -184,7 +191,9 @@
             IGUIElement firstElement = (IGUIElement) selectedNodes[0].getData();
             for( int i=1 ; i<selectedNodes.length ; i++ ) {
-                model.mergeGUIElements(firstElement, (IGUIElement) selectedNodes[i].getData());
-            }
-        } catch( IllegalArgumentException e) {
+                ((GUIModel) model).mergeEventTargets
+                    (firstElement, (IGUIElement) selectedNodes[i].getData());
+            }
+        }
+        catch( IllegalArgumentException e) {
             Console.logException(e);
         }
@@ -193,10 +202,10 @@
         if (firstParent != null) {
             firstParent.removeAll();
-            buildGuiTree(firstParent, model.getTraverser((IGUIElement) firstParent.getData()));
+            buildTargetTree(firstParent, model.getTraverser((T) firstParent.getData()));
             firstParent.setExpanded(true);
         }
         else {
-            guiTree.removeAll();
-            buildGuiTree();
+            targetTree.removeAll();
+            buildTargetTree();
         }
     }
