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

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