package de.ugoe.cs.autoquest.tasktrees.temporalrelation; import java.util.ArrayList; import java.util.List; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeBuilder; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNode; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNodeFactory; /** * TODO comment * * @version $Revision: $ $Date: 18.03.2012$ * @author 2012, last modified by $Author: patrick$ */ public class DefaultGuiElementSequenceDetectionRule implements TemporalRelationshipRule { /* * (non-Javadoc) * * @see de.ugoe.cs.tasktree.temporalrelation.TemporalRelationshipRule#apply(TaskTreeNode, * TaskTreeBuilder, TaskTreeNodeFactory) */ @Override public RuleApplicationResult apply(ITaskTreeNode parent, ITaskTreeBuilder builder, ITaskTreeNodeFactory nodeFactory, boolean finalize) { if (!(parent instanceof ISequence)) { return null; } RuleApplicationResult result = new RuleApplicationResult(); IGUIElement lastGuiElement = null; int index = 0; while (index < parent.getChildren().size()) { ITaskTreeNode child = parent.getChildren().get(index); IGUIElement currentGuiElement = getGUIElement(child); if ((index > 0) && (!lastGuiElement.equals(currentGuiElement))) { ReducableCommonDenominator commonDenominator = getNextReducableCommonDenominator(parent, index - 1); if (commonDenominator != null) { // condense only if not all children would be condensed or if we can be sure, // that there will be no further child that should be included in the condensed // sequence if ((commonDenominator.noOfTasks < parent.getChildren().size()) && (!isOnGuiElementPath(commonDenominator.commonGuiElement, currentGuiElement))) { condenseTasksToSequence(parent, index, commonDenominator.noOfTasks, builder, nodeFactory, result); result.setRuleApplicationStatus (RuleApplicationStatus.RULE_APPLICATION_FINISHED); return result; } else { // the common denominator is on the parent path of the next GUI element. // Therefore, the current sequences is not finished yet. So break up. result.setRuleApplicationStatus (RuleApplicationStatus.RULE_APPLICATION_FEASIBLE); } } } lastGuiElement = currentGuiElement; index++; } ReducableCommonDenominator commonDenominator = getNextReducableCommonDenominator(parent, parent.getChildren().size() - 1); if ((commonDenominator != null) && (commonDenominator.noOfTasks < parent.getChildren().size())) { if (finalize) { condenseTasksToSequence (parent, index, commonDenominator.noOfTasks, builder, nodeFactory, result); result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FINISHED); return result; } else { result.setRuleApplicationStatus(RuleApplicationStatus.RULE_APPLICATION_FEASIBLE); } } return result; } /** *

* TODO: comment *

* * @param guiElement * @param detectedTasks * @param parent * @param index * @param builder * @param nodeFactory * @return */ private void condenseTasksToSequence(ITaskTreeNode parent, int parentIndex, int noOfTasks, ITaskTreeBuilder builder, ITaskTreeNodeFactory nodeFactory, RuleApplicationResult result) { ISequence newSequence = nodeFactory.createNewSequence(); for (int i = 0; i < noOfTasks; i++) { builder.addChild(newSequence, parent.getChildren().get(parentIndex - noOfTasks)); // remove exactly the same number of children from the parent. builder.removeChild((ISequence) parent, parentIndex - noOfTasks); } builder.addChild((ISequence) parent, parentIndex - noOfTasks, newSequence); result.addNewlyCreatedParentNode(newSequence); } /** *

* TODO: comment *

* * @param detectedTasks * @return */ private ReducableCommonDenominator getNextReducableCommonDenominator(ITaskTreeNode parent, int childIndex) { ReducableCommonDenominator commonDenominator = null; // a common denominator can only exist for at least two task tree nodes if (childIndex > 0) { // start with the last one int pos = childIndex; commonDenominator = new ReducableCommonDenominator(); // check for further predecessors, if they match the same common denominator IGUIElement currentCommonDenominator = null; do { if (--pos < 0) { currentCommonDenominator = null; } else { currentCommonDenominator = getCommonDenominator (getGUIElement(parent.getChildren().get(pos)), getGUIElement(parent.getChildren().get(pos + 1))); } if (commonDenominator.commonGuiElement == null) { commonDenominator.commonGuiElement = currentCommonDenominator; } } while ((commonDenominator.commonGuiElement != null) && (commonDenominator.commonGuiElement.equals(currentCommonDenominator))); if (commonDenominator.commonGuiElement != null) { // pos points to the last element, that has not the same common denominator. // This one must be subtracted from the task number as well commonDenominator.noOfTasks = childIndex - pos; } else { commonDenominator = null; } } return commonDenominator; } /** *

* TODO: comment *

* * @param child * @return */ private IGUIElement getGUIElement(ITaskTreeNode node) { List terminalGUIElements = new ArrayList(); getTerminalGUIElements(node, terminalGUIElements); return getCommonDenominator(terminalGUIElements); } /** *

* TODO: comment *

* * @param detectedTaskGroups * @return */ /*private IGUIElement getCommonDenominator(Stack detectedTasks, int start) { List allGUIElements = new ArrayList(); for (int i = start; i < detectedTasks.size(); i++) { allGUIElements.add(detectedTasks.get(i).commonGuiElement); } return getCommonDenominator(allGUIElements); }*/ /** *

* TODO: comment *

* * @param child * @return */ private IGUIElement getCommonDenominator(IGUIElement guiElement1, IGUIElement guiElement2) { List allGUIElements = new ArrayList(); allGUIElements.add(guiElement1); allGUIElements.add(guiElement2); return getCommonDenominator(allGUIElements); } /** *

* TODO: comment *

* * @param child * @return */ private IGUIElement getCommonDenominator(List guiElements) { IGUIElement commonDenominator = null; if (guiElements.size() > 0) { List commonDenominatorPath = new ArrayList(); // create a reference list using the first GUI element IGUIElement guiElement = guiElements.get(0); while (guiElement != null) { commonDenominatorPath.add(0, guiElement); guiElement = guiElement.getParent(); } // for each other GUI element, check the reference list for the first element in the // path, that is not common to the current one, and delete it as well as it subsequent // siblings List currentPath = new ArrayList(); for (int i = 1; i < guiElements.size(); i++) { currentPath.clear(); guiElement = guiElements.get(i); while (guiElement != null) { currentPath.add(0, guiElement); guiElement = guiElement.getParent(); } // determine the index of the first unequal path element int index = 0; while ((index < commonDenominatorPath.size()) && (index < currentPath.size()) && commonDenominatorPath.get(index).equals(currentPath.get(index))) { index++; } // remove all elements from the common denonimator path, that do not match while (index < commonDenominatorPath.size()) { commonDenominatorPath.remove(index); } } if (commonDenominatorPath.size() > 0) { commonDenominator = commonDenominatorPath.get(commonDenominatorPath.size() - 1); } } return commonDenominator; } /** *

* TODO: comment *

* * @param child * @return */ private void getTerminalGUIElements(ITaskTreeNode node, List terminalGUIElements) { if (node instanceof IEventTask) { if (((IEventTask) node).getEventTarget() instanceof IGUIElement) { terminalGUIElements.add((IGUIElement) ((IEventTask) node).getEventTarget()); } } else { for (ITaskTreeNode child : node.getChildren()) { getTerminalGUIElements(child, terminalGUIElements); } } } /** *

* TODO: comment *

* * @param currentCommonDenominator * @param guiElement * @return */ private boolean isOnGuiElementPath(IGUIElement potentialPathElement, IGUIElement child) { IGUIElement guiElement = child; while (guiElement != null) { if (guiElement.equals(potentialPathElement)) { return true; } guiElement = guiElement.getParent(); } return false; } /** * */ private static class ReducableCommonDenominator { /** the GUI element being the common denominator */ private IGUIElement commonGuiElement; /** the number of tasks that match the common denominator */ private int noOfTasks; /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return noOfTasks + " tasks on " + commonGuiElement; } } }