1 | // Copyright 2012 Georg-August-Universität Göttingen, Germany |
---|
2 | // |
---|
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
---|
4 | // you may not use this file except in compliance with the License. |
---|
5 | // You may obtain a copy of the License at |
---|
6 | // |
---|
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
---|
8 | // |
---|
9 | // Unless required by applicable law or agreed to in writing, software |
---|
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
---|
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
12 | // See the License for the specific language governing permissions and |
---|
13 | // limitations under the License. |
---|
14 | |
---|
15 | package de.ugoe.cs.autoquest.usability; |
---|
16 | |
---|
17 | import java.util.Collection; |
---|
18 | import java.util.HashMap; |
---|
19 | import java.util.Iterator; |
---|
20 | import java.util.LinkedList; |
---|
21 | import java.util.List; |
---|
22 | import java.util.ListIterator; |
---|
23 | import java.util.Map; |
---|
24 | |
---|
25 | import de.ugoe.cs.autoquest.eventcore.guimodel.GUIElementGroup; |
---|
26 | import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; |
---|
27 | |
---|
28 | /** |
---|
29 | * <p> |
---|
30 | * TODO comment |
---|
31 | * </p> |
---|
32 | * |
---|
33 | * @author Patrick Harms |
---|
34 | */ |
---|
35 | class RuleUtils { |
---|
36 | |
---|
37 | /** |
---|
38 | * |
---|
39 | */ |
---|
40 | static Map<IGUIElement, List<IGUIElement>> getGroups(Collection<IGUIElement> guiElements, |
---|
41 | int maxDistToCommonParent) |
---|
42 | { |
---|
43 | Map<IGUIElement, List<IGUIElement>> groups = new HashMap<>(); |
---|
44 | List<IGUIElement> guiElementsToGroup = new LinkedList<>(guiElements); |
---|
45 | IGUIElement parentToGroup; |
---|
46 | |
---|
47 | do { |
---|
48 | List<LinkedList<IGUIElement>> sortedPaths = new LinkedList<>(); |
---|
49 | List<IGUIElement> commonParents = new LinkedList<>(); |
---|
50 | |
---|
51 | createSortedPaths |
---|
52 | (guiElementsToGroup, sortedPaths, commonParents, maxDistToCommonParent); |
---|
53 | |
---|
54 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION |
---|
55 | // Iterator<LinkedList<IGUIElement>> sortedPathsIt1 = sortedPaths.iterator(); |
---|
56 | // Iterator<IGUIElement> commonParentIt1 = commonParents.iterator(); |
---|
57 | // |
---|
58 | // while (commonParentIt1.hasNext()) { |
---|
59 | // IGUIElement currentParent = commonParentIt1.next(); |
---|
60 | // IGUIElement sortedPath = sortedPathsIt1.next().getLast(); |
---|
61 | // |
---|
62 | // System.out.println(toPathString(sortedPath)); |
---|
63 | // System.out.println(toPathString(currentParent) + "###########"); |
---|
64 | // } |
---|
65 | // |
---|
66 | // System.out.println(); |
---|
67 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION |
---|
68 | |
---|
69 | parentToGroup = getParentToGroup(commonParents); |
---|
70 | |
---|
71 | if (parentToGroup != null) { |
---|
72 | Iterator<LinkedList<IGUIElement>> sortedPathsIt = sortedPaths.iterator(); |
---|
73 | ListIterator<IGUIElement> commonParentIt = commonParents.listIterator(); |
---|
74 | |
---|
75 | while (commonParentIt.hasNext()) { |
---|
76 | if (!parentToGroup.equals(commonParentIt.next())) { |
---|
77 | sortedPathsIt.next(); |
---|
78 | } |
---|
79 | else { |
---|
80 | break; |
---|
81 | } |
---|
82 | } |
---|
83 | |
---|
84 | List<IGUIElement> groupedGUIElements = new LinkedList<>(); |
---|
85 | |
---|
86 | // go one backward to ensure, that next will return the first occurrence |
---|
87 | // of the parent to create the group for. |
---|
88 | commonParentIt.previous(); |
---|
89 | |
---|
90 | do { |
---|
91 | IGUIElement guiElementToGroup = sortedPathsIt.next().getLast(); |
---|
92 | groupedGUIElements.add(guiElementToGroup); |
---|
93 | guiElementsToGroup.remove(guiElementToGroup); |
---|
94 | |
---|
95 | } |
---|
96 | while (parentToGroup.equals(commonParentIt.next())); |
---|
97 | |
---|
98 | groups.put(parentToGroup, groupedGUIElements); |
---|
99 | |
---|
100 | // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION |
---|
101 | // System.out.println("group for"); |
---|
102 | // System.out.println(toPathString(parentToGroup)); |
---|
103 | // |
---|
104 | // for (IGUIElement element : groupedGUIElements) { |
---|
105 | // System.out.println(toPathString(element)); |
---|
106 | // } |
---|
107 | // |
---|
108 | // System.out.println(); |
---|
109 | // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION |
---|
110 | } |
---|
111 | } |
---|
112 | while (parentToGroup != null); |
---|
113 | |
---|
114 | return groups; |
---|
115 | } |
---|
116 | |
---|
117 | /** |
---|
118 | * |
---|
119 | */ |
---|
120 | static String toPathString(IGUIElement element) { |
---|
121 | IGUIElement parent = element; |
---|
122 | String result = ""; |
---|
123 | |
---|
124 | while (parent != null) { |
---|
125 | if (!(parent instanceof GUIElementGroup)) { |
---|
126 | result = parent.toString() + "/" + result; |
---|
127 | } |
---|
128 | else { |
---|
129 | result = parent.toString().hashCode() + "/" + result; |
---|
130 | } |
---|
131 | |
---|
132 | parent = parent.getParent(); |
---|
133 | } |
---|
134 | |
---|
135 | return result.toString(); |
---|
136 | } |
---|
137 | |
---|
138 | /** |
---|
139 | * |
---|
140 | */ |
---|
141 | private static void createSortedPaths(List<IGUIElement> guiElements, |
---|
142 | List<LinkedList<IGUIElement>> sortedPaths, |
---|
143 | List<IGUIElement> commonParents, |
---|
144 | int maxDistToCommonParent) |
---|
145 | { |
---|
146 | for (IGUIElement guiElement : guiElements) { |
---|
147 | // create the path |
---|
148 | LinkedList<IGUIElement> path = new LinkedList<>(); |
---|
149 | IGUIElement parent = guiElement; |
---|
150 | while (parent != null) { |
---|
151 | if (!(parent instanceof GUIElementGroup)) { |
---|
152 | path.addFirst(parent); |
---|
153 | } |
---|
154 | |
---|
155 | parent = parent.getParent(); |
---|
156 | } |
---|
157 | |
---|
158 | // sort it into the list of paths |
---|
159 | int maxEquality = 0; |
---|
160 | int maxEqualityPos = 0; |
---|
161 | int pos = 0; |
---|
162 | |
---|
163 | for (List<IGUIElement> candidate : sortedPaths) { |
---|
164 | int equality = 0; |
---|
165 | while ((equality < candidate.size()) && (equality < path.size()) && |
---|
166 | (candidate.get(equality).equals(path.get(equality)))) |
---|
167 | { |
---|
168 | equality++; |
---|
169 | } |
---|
170 | |
---|
171 | if (equality > maxEquality) { |
---|
172 | maxEquality = equality; |
---|
173 | maxEqualityPos = pos; |
---|
174 | } |
---|
175 | |
---|
176 | pos++; |
---|
177 | } |
---|
178 | |
---|
179 | sortedPaths.add(maxEqualityPos, path); |
---|
180 | |
---|
181 | if ((maxEquality > 0) && ((path.size() - maxEquality) < maxDistToCommonParent)) { |
---|
182 | commonParents.add(maxEqualityPos, path.get(maxEquality - 1)); |
---|
183 | } |
---|
184 | else { |
---|
185 | commonParents.add(maxEqualityPos, null); |
---|
186 | } |
---|
187 | } |
---|
188 | } |
---|
189 | |
---|
190 | /** |
---|
191 | * |
---|
192 | */ |
---|
193 | private static IGUIElement getParentToGroup(List<IGUIElement> commonParents) { |
---|
194 | Map<IGUIElement, Integer> occurrenceCounts = new HashMap<>(); |
---|
195 | Map<IGUIElement, Integer> depths = new HashMap<>(); |
---|
196 | |
---|
197 | // get the required information about path lengths and occurrence counts |
---|
198 | for (IGUIElement commonParent : commonParents) { |
---|
199 | Integer occurrenceCount = occurrenceCounts.get(commonParent); |
---|
200 | |
---|
201 | if (occurrenceCount != null) { |
---|
202 | occurrenceCounts.put(commonParent, occurrenceCount + 1); |
---|
203 | } |
---|
204 | else { |
---|
205 | occurrenceCounts.put(commonParent, 1); |
---|
206 | } |
---|
207 | |
---|
208 | if (!depths.containsKey(commonParent)) { |
---|
209 | int depth = 0; |
---|
210 | IGUIElement parent = commonParent; |
---|
211 | |
---|
212 | while (parent != null) { |
---|
213 | depth++; |
---|
214 | parent = parent.getParent(); |
---|
215 | } |
---|
216 | |
---|
217 | depths.put(commonParent, depth); |
---|
218 | } |
---|
219 | } |
---|
220 | |
---|
221 | IGUIElement elementToGroup = null; |
---|
222 | |
---|
223 | // get the GUI element being the parent most often |
---|
224 | for (IGUIElement commonParent : commonParents) { |
---|
225 | if (elementToGroup == null) { |
---|
226 | elementToGroup = commonParent; |
---|
227 | } |
---|
228 | else if ((commonParent != null) && |
---|
229 | (!elementToGroup.equals(commonParent))) |
---|
230 | { |
---|
231 | int occurrenceCountCandidate = occurrenceCounts.get(commonParent); |
---|
232 | int depthCandidate = depths.get(commonParent); |
---|
233 | |
---|
234 | int occurrenceCountElement = occurrenceCounts.get(elementToGroup); |
---|
235 | int depthElement = depths.get(elementToGroup); |
---|
236 | |
---|
237 | if ((depthCandidate > depthElement) || |
---|
238 | ((depthCandidate == depthElement) && |
---|
239 | (occurrenceCountCandidate > occurrenceCountElement))) |
---|
240 | { |
---|
241 | elementToGroup = commonParent; |
---|
242 | } |
---|
243 | else if ((occurrenceCountCandidate == occurrenceCountElement) && |
---|
244 | (depthCandidate == depthElement)) |
---|
245 | { |
---|
246 | // in this situation, the order is irrelevant. The GUI elements for which |
---|
247 | // both paths were identified as parents are completely different. |
---|
248 | // Otherwise, they would have the same parent. But as they are that |
---|
249 | // different, they will not occur subsequently in the ordered list |
---|
250 | // of GUI elements to group. Hence, we just reuse the one the is currently |
---|
251 | // identified as the one to group next. |
---|
252 | } |
---|
253 | } |
---|
254 | } |
---|
255 | |
---|
256 | return elementToGroup; |
---|
257 | } |
---|
258 | |
---|
259 | /** |
---|
260 | * |
---|
261 | */ |
---|
262 | private RuleUtils() { |
---|
263 | // prevent instantiation |
---|
264 | } |
---|
265 | } |
---|