// 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.usability; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementGroup; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; /** *

* TODO comment *

* * @author Patrick Harms */ class RuleUtils { /** * */ static Map> getGroups(Collection guiElements, int maxDistToCommonParent) { Map> groups = new HashMap<>(); List guiElementsToGroup = new LinkedList<>(guiElements); IGUIElement parentToGroup; do { List> sortedPaths = new LinkedList<>(); List commonParents = new LinkedList<>(); createSortedPaths (guiElementsToGroup, sortedPaths, commonParents, maxDistToCommonParent); // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION // Iterator> sortedPathsIt1 = sortedPaths.iterator(); // Iterator commonParentIt1 = commonParents.iterator(); // // while (commonParentIt1.hasNext()) { // IGUIElement currentParent = commonParentIt1.next(); // IGUIElement sortedPath = sortedPathsIt1.next().getLast(); // // System.out.println(toPathString(sortedPath)); // System.out.println(toPathString(currentParent) + "###########"); // } // // System.out.println(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION parentToGroup = getParentToGroup(commonParents); if (parentToGroup != null) { Iterator> sortedPathsIt = sortedPaths.iterator(); ListIterator commonParentIt = commonParents.listIterator(); while (commonParentIt.hasNext()) { if (!parentToGroup.equals(commonParentIt.next())) { sortedPathsIt.next(); } else { break; } } List groupedGUIElements = new LinkedList<>(); // go one backward to ensure, that next will return the first occurrence // of the parent to create the group for. commonParentIt.previous(); do { IGUIElement guiElementToGroup = sortedPathsIt.next().getLast(); groupedGUIElements.add(guiElementToGroup); guiElementsToGroup.remove(guiElementToGroup); } while (parentToGroup.equals(commonParentIt.next())); groups.put(parentToGroup, groupedGUIElements); // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION // System.out.println("group for"); // System.out.println(toPathString(parentToGroup)); // // for (IGUIElement element : groupedGUIElements) { // System.out.println(toPathString(element)); // } // // System.out.println(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION } } while (parentToGroup != null); return groups; } /** * */ static String toPathString(IGUIElement element) { IGUIElement parent = element; String result = ""; while (parent != null) { if (!(parent instanceof GUIElementGroup)) { result = parent.toString() + "/" + result; } else { result = parent.toString().hashCode() + "/" + result; } parent = parent.getParent(); } return result.toString(); } /** * */ private static void createSortedPaths(List guiElements, List> sortedPaths, List commonParents, int maxDistToCommonParent) { for (IGUIElement guiElement : guiElements) { // create the path LinkedList path = new LinkedList<>(); IGUIElement parent = guiElement; while (parent != null) { if (!(parent instanceof GUIElementGroup)) { path.addFirst(parent); } parent = parent.getParent(); } // sort it into the list of paths int maxEquality = 0; int maxEqualityPos = 0; int pos = 0; for (List candidate : sortedPaths) { int equality = 0; while ((equality < candidate.size()) && (equality < path.size()) && (candidate.get(equality).equals(path.get(equality)))) { equality++; } if (equality > maxEquality) { maxEquality = equality; maxEqualityPos = pos; } pos++; } sortedPaths.add(maxEqualityPos, path); if ((maxEquality > 0) && ((path.size() - maxEquality) < maxDistToCommonParent)) { commonParents.add(maxEqualityPos, path.get(maxEquality - 1)); } else { commonParents.add(maxEqualityPos, null); } } } /** * */ private static IGUIElement getParentToGroup(List commonParents) { Map occurrenceCounts = new HashMap<>(); Map depths = new HashMap<>(); // get the required information about path lengths and occurrence counts for (IGUIElement commonParent : commonParents) { Integer occurrenceCount = occurrenceCounts.get(commonParent); if (occurrenceCount != null) { occurrenceCounts.put(commonParent, occurrenceCount + 1); } else { occurrenceCounts.put(commonParent, 1); } if (!depths.containsKey(commonParent)) { int depth = 0; IGUIElement parent = commonParent; while (parent != null) { depth++; parent = parent.getParent(); } depths.put(commonParent, depth); } } IGUIElement elementToGroup = null; // get the GUI element being the parent most often for (IGUIElement commonParent : commonParents) { if (elementToGroup == null) { elementToGroup = commonParent; } else if ((commonParent != null) && (!elementToGroup.equals(commonParent))) { int occurrenceCountCandidate = occurrenceCounts.get(commonParent); int depthCandidate = depths.get(commonParent); int occurrenceCountElement = occurrenceCounts.get(elementToGroup); int depthElement = depths.get(elementToGroup); if ((depthCandidate > depthElement) || ((depthCandidate == depthElement) && (occurrenceCountCandidate > occurrenceCountElement))) { elementToGroup = commonParent; } else if ((occurrenceCountCandidate == occurrenceCountElement) && (depthCandidate == depthElement)) { // in this situation, the order is irrelevant. The GUI elements for which // both paths were identified as parents are completely different. // Otherwise, they would have the same parent. But as they are that // different, they will not occur subsequently in the ordered list // of GUI elements to group. Hence, we just reuse the one the is currently // identified as the one to group next. } } } return elementToGroup; } /** * */ private RuleUtils() { // prevent instantiation } }