source: trunk/quest-core-tasktrees/src/main/java/de/ugoe/cs/quest/tasktrees/temporalrelation/DefaultGuiElementSequenceDetectionRule.java @ 799

Last change on this file since 799 was 799, checked in by pharms, 12 years ago
  • improved grouping of tasks that are executed in the same parent GUI element
File size: 11.9 KB
Line 
1package de.ugoe.cs.quest.tasktrees.temporalrelation;
2
3import java.util.ArrayList;
4import java.util.List;
5
6import de.ugoe.cs.quest.eventcore.guimodel.IGUIElement;
7import de.ugoe.cs.quest.tasktrees.treeifc.IEventTask;
8import de.ugoe.cs.quest.tasktrees.treeifc.ISequence;
9import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeBuilder;
10import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNode;
11import de.ugoe.cs.quest.tasktrees.treeifc.ITaskTreeNodeFactory;
12
13/**
14 * TODO comment
15 *
16 * @version $Revision: $ $Date: 18.03.2012$
17 * @author 2012, last modified by $Author: patrick$
18 */
19public class DefaultGuiElementSequenceDetectionRule implements TemporalRelationshipRule {
20
21    /*
22     * (non-Javadoc)
23     *
24     * @see de.ugoe.cs.tasktree.temporalrelation.TemporalRelationshipRule#apply(TaskTreeNode,
25     * TaskTreeBuilder, TaskTreeNodeFactory)
26     */
27    @Override
28    public RuleApplicationResult apply(ITaskTreeNode        parent,
29                                       ITaskTreeBuilder     builder,
30                                       ITaskTreeNodeFactory nodeFactory,
31                                       boolean              finalize)
32    {
33        if (!(parent instanceof ISequence)) {
34            return null;
35        }
36
37        RuleApplicationResult result = new RuleApplicationResult();
38       
39        IGUIElement lastGuiElement = null;
40        int index = 0;
41        while (index < parent.getChildren().size()) {
42            ITaskTreeNode child = parent.getChildren().get(index);
43            IGUIElement currentGuiElement = getGUIElement(child);
44            if ((index > 0) && (!lastGuiElement.equals(currentGuiElement))) {
45                ReducableCommonDenominator commonDenominator =
46                    getNextReducableCommonDenominator(parent, index - 1);
47                   
48                if (commonDenominator != null) {
49                    // condense only if not all children would be condensed or if we can be sure,
50                    // that there will be no further child that should be included in the condensed
51                    // sequence
52                    if ((commonDenominator.noOfTasks < parent.getChildren().size()) &&
53                        (!isOnGuiElementPath(commonDenominator.commonGuiElement, currentGuiElement)))
54                    {
55                        condenseTasksToSequence(parent, index, commonDenominator.noOfTasks,
56                                                builder, nodeFactory, result);
57
58                        result.setRuleApplicationStatus
59                            (RuleApplicationStatus.RULE_APPLICATION_FINISHED);
60                        return result;
61                    }
62                    else {
63                        // the common denominator is on the parent path of the next GUI element.
64                        // Therefore, the current sequences is not finished yet. So break up.
65                        result.setRuleApplicationStatus
66                            (RuleApplicationStatus.RULE_APPLICATION_FEASIBLE);
67                    }
68                }
69            }
70
71            lastGuiElement = currentGuiElement;
72            index++;
73        }
74
75        ReducableCommonDenominator commonDenominator =
76            getNextReducableCommonDenominator(parent, parent.getChildren().size() - 1);
77       
78        if ((commonDenominator != null) &&
79            (commonDenominator.noOfTasks < parent.getChildren().size()))
80        {
81            if (finalize) {
82                condenseTasksToSequence
83                    (parent, index, commonDenominator.noOfTasks, builder, nodeFactory, result);
84               
85                result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FINISHED);
86               
87                return result;
88            }
89            else {
90                result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FEASIBLE);
91            }
92        }
93
94        return result;
95    }
96
97    /**
98     * <p>
99     * TODO: comment
100     * </p>
101     *
102     * @param guiElement
103     * @param detectedTasks
104     * @param parent
105     * @param index
106     * @param builder
107     * @param nodeFactory
108     * @return
109     */
110    private void condenseTasksToSequence(ITaskTreeNode         parent,
111                                         int                   parentIndex,
112                                         int                   noOfTasks,
113                                         ITaskTreeBuilder      builder,
114                                         ITaskTreeNodeFactory  nodeFactory,
115                                         RuleApplicationResult result)
116    {
117        ISequence newSequence = nodeFactory.createNewSequence();
118        for (int i = 0; i < noOfTasks; i++) {
119            builder.addChild(newSequence, parent.getChildren().get(parentIndex - noOfTasks));
120            // remove exactly the same number of children from the parent.
121            builder.removeChild((ISequence) parent, parentIndex - noOfTasks);
122        }
123               
124        builder.addChild((ISequence) parent, parentIndex - noOfTasks, newSequence);
125        result.addNewlyCreatedParentNode(newSequence);
126    }
127
128    /**
129     * <p>
130     * TODO: comment
131     * </p>
132     *
133     * @param detectedTasks
134     * @return
135     */
136    private ReducableCommonDenominator getNextReducableCommonDenominator(ITaskTreeNode parent,
137                                                                         int           childIndex)
138    {
139        ReducableCommonDenominator commonDenominator = null;
140       
141        // a common denominator can only exist for at least two task tree nodes
142        if (childIndex > 0) {
143            // start with the last one
144            int pos = childIndex;
145
146            commonDenominator = new ReducableCommonDenominator();
147           
148            // check for further predecessors, if they match the same common denominator
149            IGUIElement currentCommonDenominator = null;
150            do {
151                if (--pos < 0) {
152                    currentCommonDenominator = null;
153                }
154                else {
155                    currentCommonDenominator = getCommonDenominator
156                        (getGUIElement(parent.getChildren().get(pos)),
157                         getGUIElement(parent.getChildren().get(pos + 1)));
158                }
159               
160                if (commonDenominator.commonGuiElement == null) {
161                    commonDenominator.commonGuiElement = currentCommonDenominator;
162                }
163            }
164            while ((commonDenominator.commonGuiElement != null) &&
165                   (commonDenominator.commonGuiElement.equals(currentCommonDenominator)));
166           
167            if (commonDenominator.commonGuiElement != null) {
168                // pos points to the last element, that has not the same common denominator.
169                // This one must be subtracted from the task number as well
170                commonDenominator.noOfTasks = childIndex - pos;
171            }
172            else {
173                commonDenominator = null;
174            }
175        }
176       
177        return commonDenominator;
178    }
179
180    /**
181     * <p>
182     * TODO: comment
183     * </p>
184     *
185     * @param child
186     * @return
187     */
188    private IGUIElement getGUIElement(ITaskTreeNode node) {
189        List<IGUIElement> terminalGUIElements = new ArrayList<IGUIElement>();
190        getTerminalGUIElements(node, terminalGUIElements);
191        return getCommonDenominator(terminalGUIElements);
192    }
193       
194    /**
195     * <p>
196     * TODO: comment
197     * </p>
198     *
199     * @param detectedTaskGroups
200     * @return
201     */
202    /*private IGUIElement getCommonDenominator(Stack<Task> detectedTasks, int start) {
203        List<IGUIElement> allGUIElements = new ArrayList<IGUIElement>();
204       
205        for (int i = start; i < detectedTasks.size(); i++) {
206            allGUIElements.add(detectedTasks.get(i).commonGuiElement);
207        }
208       
209        return getCommonDenominator(allGUIElements);
210    }*/
211
212    /**
213     * <p>
214     * TODO: comment
215     * </p>
216     *
217     * @param child
218     * @return
219     */
220    private IGUIElement getCommonDenominator(IGUIElement guiElement1, IGUIElement guiElement2) {
221        List<IGUIElement> allGUIElements = new ArrayList<IGUIElement>();
222        allGUIElements.add(guiElement1);
223        allGUIElements.add(guiElement2);
224        return getCommonDenominator(allGUIElements);
225    }
226
227    /**
228     * <p>
229     * TODO: comment
230     * </p>
231     *
232     * @param child
233     * @return
234     */
235    private IGUIElement getCommonDenominator(List<IGUIElement> guiElements) {
236        IGUIElement commonDenominator = null;
237       
238        if (guiElements.size() > 0) {
239            List<IGUIElement> commonDenominatorPath = new ArrayList<IGUIElement>();
240           
241            // create a reference list using the first GUI element
242            IGUIElement guiElement = guiElements.get(0);
243            while (guiElement != null) {
244                commonDenominatorPath.add(0, guiElement);
245                guiElement = guiElement.getParent();
246            }
247           
248            // for each other GUI element, check the reference list for the first element in the
249            // path, that is not common to the current one, and delete it as well as it subsequent
250            // siblings
251            List<IGUIElement> currentPath = new ArrayList<IGUIElement>();
252            for (int i = 1; i < guiElements.size(); i++) {
253                currentPath.clear();
254                guiElement = guiElements.get(i);
255                while (guiElement != null) {
256                    currentPath.add(0, guiElement);
257                    guiElement = guiElement.getParent();
258                }
259               
260                // determine the index of the first unequal path element
261                int index = 0;
262                while ((index < commonDenominatorPath.size()) && (index < currentPath.size()) &&
263                        commonDenominatorPath.get(index).equals(currentPath.get(index)))
264                {
265                    index++;
266                }
267               
268                // remove all elements from the common denonimator path, that do not match
269                while (index < commonDenominatorPath.size()) {
270                    commonDenominatorPath.remove(index);
271                }
272            }
273           
274            if (commonDenominatorPath.size() > 0) {
275                commonDenominator = commonDenominatorPath.get(commonDenominatorPath.size() - 1);
276            }
277        }
278       
279        return commonDenominator;
280    }
281
282    /**
283     * <p>
284     * TODO: comment
285     * </p>
286     *
287     * @param child
288     * @return
289     */
290    private void getTerminalGUIElements(ITaskTreeNode node, List<IGUIElement> terminalGUIElements) {
291        if (node instanceof IEventTask) {
292            if (((IEventTask) node).getEventTarget() instanceof IGUIElement) {
293                terminalGUIElements.add((IGUIElement) ((IEventTask) node).getEventTarget());
294            }
295        }
296        else {
297            for (ITaskTreeNode child : node.getChildren()) {
298                getTerminalGUIElements(child, terminalGUIElements);
299            }
300        }
301    }
302
303    /**
304     * <p>
305     * TODO: comment
306     * </p>
307     *
308     * @param currentCommonDenominator
309     * @param guiElement
310     * @return
311     */
312    private boolean isOnGuiElementPath(IGUIElement potentialPathElement, IGUIElement child) {
313        IGUIElement guiElement = child;
314       
315        while (guiElement != null) {
316            if (guiElement.equals(potentialPathElement)) {
317                return true;
318            }
319            guiElement = guiElement.getParent();
320        }
321       
322        return false;
323    }
324
325    /**
326     *
327     */
328    private static class ReducableCommonDenominator {
329       
330        /** the GUI element being the common denominator */
331        private IGUIElement commonGuiElement;
332       
333        /** the number of tasks that match the common denominator */
334        private int noOfTasks;
335
336        /* (non-Javadoc)
337         * @see java.lang.Object#toString()
338         */
339        @Override
340        public String toString() {
341            return noOfTasks + " tasks on " + commonGuiElement;
342        }
343       
344    }
345}
Note: See TracBrowser for help on using the repository browser.