source: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java @ 2135

Last change on this file since 2135 was 2135, checked in by pharms, 7 years ago

Correction of smaller issues for being able to process generic events

File size: 11.8 KB
Line 
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
15package de.ugoe.cs.autoquest.usability;
16
17import java.util.ArrayList;
18import java.util.HashMap;
19import java.util.HashSet;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Set;
24
25import de.ugoe.cs.autoquest.eventcore.Event;
26import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
27import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
28import de.ugoe.cs.autoquest.eventcore.guimodel.ICheckBox;
29import de.ugoe.cs.autoquest.eventcore.guimodel.IComboBox;
30import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
31import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
32import de.ugoe.cs.autoquest.eventcore.guimodel.IListBox;
33import de.ugoe.cs.autoquest.eventcore.guimodel.IMenuButton;
34import de.ugoe.cs.autoquest.eventcore.guimodel.ITextArea;
35import de.ugoe.cs.autoquest.eventcore.guimodel.ITextField;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
39import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
40import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
41import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
42import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
43
44/**
45 * TODO comment
46 *
47 * @version $Revision: $ $Date: 16.07.2012$
48 * @author 2012, last modified by $Author: pharms$
49 */
50public class UnusedGUIElementsRule implements UsabilityEvaluationRule {
51
52    /*
53     * (non-Javadoc)
54     *
55     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
56     */
57    @Override
58    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
59        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
60       
61        Map<IGUIView, List<Set<IGUIElement>>> viewDisplays =
62            getViewDisplays(taskModel.getUserSessions());
63       
64        Map<IGUIView, Set<IGUIElement>> allGUIElements = getAllGUIElements(taskModel);
65       
66        for (Map.Entry<IGUIView, List<Set<IGUIElement>>> viewDisplay : viewDisplays.entrySet()) {
67            handleUnusedGUIElements
68                (allGUIElements, viewDisplay.getKey(), viewDisplay.getValue(), results);
69        }
70
71        return results;
72    }
73
74    /**
75     * @param results
76     *
77     */
78    private void handleUnusedGUIElements(Map<IGUIView, Set<IGUIElement>> usedGUIElements,
79                                         IGUIView                        view,
80                                         List<Set<IGUIElement>>          viewUsages,
81                                         UsabilityEvaluationResult       results)
82    {
83        Set<IGUIElement> allElementsInView = usedGUIElements.get(view);
84       
85        if (allElementsInView == null) {
86            return;
87        }
88       
89        Map<Integer, List<IGUIElement>> usageCounters = new HashMap<>();
90       
91        for (IGUIElement relevantElement : allElementsInView) {
92            int usageCounter = 0;
93           
94            for (Set<IGUIElement> viewUsage : viewUsages) {
95                if (viewUsage.contains(relevantElement)) {
96                    usageCounter++;
97                }
98            }
99           
100            List<IGUIElement> elementsWithSameUsage = usageCounters.get(usageCounter);
101           
102            if (elementsWithSameUsage == null) {
103                elementsWithSameUsage = new LinkedList<>();
104                usageCounters.put(usageCounter, elementsWithSameUsage);
105            }
106           
107            elementsWithSameUsage.add(relevantElement);
108        }
109       
110        int cumulativeGuiElementUsage = 0;
111        for (Set<IGUIElement> viewUsage : viewUsages) {
112            cumulativeGuiElementUsage += viewUsage.size();
113        }
114       
115        List<IGUIElement> unusedElements = usageCounters.get(0);
116       
117        if (unusedElements != null) {
118            int ratio = 1000 * unusedElements.size() / allElementsInView.size();
119
120            UsabilitySmellIntensity severity = UsabilitySmellIntensity.getIntensity
121                (ratio, cumulativeGuiElementUsage, -1);
122
123            if (severity != null) {
124                Map<String, Object> parameters = new HashMap<String, Object>();
125
126                parameters.put("ratio", ratio / 10);
127                parameters.put("allDisplays", viewUsages.size());
128                parameters.put("view", view);
129                parameters.put("unusedGuiElements", unusedElements);
130                parameters.put("allGuiElements", allElementsInView.size());
131
132                results.addSmell
133                    (severity, UsabilitySmellDescription.UNUSED_GUI_ELEMENTS, parameters);
134            }
135        }
136    }
137
138    /**
139     *
140     */
141    private Map<IGUIView, Set<IGUIElement>> getAllGUIElements(ITaskModel taskModel) {
142        Map<IGUIView, Set<IGUIElement>> result = new HashMap<>();
143       
144        for (ITask task : taskModel.getTasks()) {
145            if (task instanceof IEventTask) {
146                for (ITaskInstance instance : task.getInstances()) {
147                    Event event = ((IEventTaskInstance) instance).getEvent();
148                   
149                    if ((event.getTarget() instanceof IGUIElement) &&
150                        (isRelevant((IGUIElement) event.getTarget())))
151                    {
152                        IGUIView view = ((IGUIElement) event.getTarget()).getView();
153                       
154                        Set<IGUIElement> elements = result.get(view);
155                       
156                        if (elements == null) {
157                            elements = new HashSet<>();
158                            result.put(view, elements);
159                        }
160                       
161                        elements.add((IGUIElement) event.getTarget());
162                    }
163                }
164            }
165        }
166       
167        if (result.size() <= 0) {
168            return result;
169        }
170
171        // the problem is, that using the GUI model does not allow to find all in a specific view
172        // as the GUI model may return a merged element instead. But anyway, we can add those, which
173        // are in the GUI model and have the same view.
174       
175        GUIModel model = result.values().iterator().next().iterator().next().getGUIModel();
176       
177        GUIModel.Traverser traverser = model.getTraverser();
178
179        IGUIElement currentGUIElement = null;
180        do {
181            if (traverser.hasFirstChild()) {
182                currentGUIElement = traverser.firstChild();
183            }
184            else if (traverser.hasNextSibling()) {
185                currentGUIElement = traverser.nextSibling();
186            }
187            else {
188                while (currentGUIElement != null) {
189                    currentGUIElement = traverser.parent();
190                    if (traverser.hasNextSibling()) {
191                        currentGUIElement = traverser.nextSibling();
192                        break;
193                    }
194                }
195            }
196
197            if (isRelevant(currentGUIElement)) {
198                IGUIView view = currentGUIElement.getView();
199               
200                Set<IGUIElement> elements = result.get(view);
201               
202                if (elements == null) {
203                    elements = new HashSet<>();
204                    result.put(view, elements);
205                }
206               
207                elements.add(currentGUIElement);
208            }
209        }
210        while (currentGUIElement != null);
211       
212        return result;
213    }
214
215    /**
216     *
217     */
218    private Map<IGUIView, List<Set<IGUIElement>>> getViewDisplays(List<IUserSession> sessions) {
219        final IGUIView[] currentView = new IGUIView[1];
220        final List<IEventTaskInstance> actionInstances = new ArrayList<>();
221        final Map<IGUIView, List<Set<IGUIElement>>> result = new HashMap<>();
222       
223        for (IUserSession session : sessions) {
224            currentView[0] = null;
225            actionInstances.clear();
226           
227            for (final ITaskInstance currentRoot : session) {
228                currentRoot.accept(new DefaultTaskInstanceTraversingVisitor() {
229                    @Override
230                    public void visit(IEventTaskInstance eventTaskInstance) {
231                        if (eventTaskInstance.getEvent().getTarget() instanceof IGUIElement) {
232                            IGUIView view =
233                                ((IGUIElement) eventTaskInstance.getEvent().getTarget()).getView();
234                           
235                            if ((currentView[0] == null) && (view != null)) {
236                                currentView[0] = view;
237                                actionInstances.clear();
238                            }
239                            else if ((currentView[0] != null) && (!currentView[0].equals(view))) {
240                                addRelevantTargets(currentView[0], actionInstances, result);
241                               
242                                currentView[0] = view;
243                                actionInstances.clear();
244                            }
245                        }
246                       
247                        if (eventTaskInstance.getEvent().getTarget() instanceof IGUIElement) {
248                            actionInstances.add(eventTaskInstance);
249                        }
250                    }
251                });
252            }
253           
254            // add the used GUI elements of the last shown view in the session
255            if (currentView[0] != null) {
256                addRelevantTargets(currentView[0], actionInstances, result);
257            }
258        }
259       
260        return result;
261    }
262
263    /**
264     *
265     */
266    private void addRelevantTargets(IGUIView                              view,
267                                    List<IEventTaskInstance>              actionInstances,
268                                    Map<IGUIView, List<Set<IGUIElement>>> result)
269    {
270        List<Set<IGUIElement>> usedGUIElements = result.get(view);
271       
272        if (usedGUIElements == null) {
273            usedGUIElements = new LinkedList<>();
274            result.put(view, usedGUIElements);
275        }
276       
277        Set<IGUIElement> elementsInViewDisplay = new HashSet<>();
278       
279        for (IEventTaskInstance actionInstance : actionInstances) {
280            IGUIElement element = (IGUIElement) actionInstance.getEvent().getTarget();
281           
282            while (element != null) {
283                if (isRelevant(element)) {
284                    elementsInViewDisplay.add(element);
285                }
286               
287                element = element.getParent();
288            }
289        }
290       
291        usedGUIElements.add(elementsInViewDisplay);
292    }
293
294    /**
295     *
296     */
297    private boolean isRelevant(IGUIElement currentGUIElement) {
298        if (currentGUIElement == null) {
299            return false;
300        }
301       
302        if ((currentGUIElement instanceof IButton) ||
303            (currentGUIElement instanceof ICheckBox) ||
304            (currentGUIElement instanceof IComboBox) ||
305            (currentGUIElement instanceof IListBox) ||
306            (currentGUIElement instanceof IMenuButton) ||
307            (currentGUIElement instanceof ITextArea) ||
308            (currentGUIElement instanceof ITextField))
309        {
310            return true;
311        }
312       
313        return false;
314    }
315}
Note: See TracBrowser for help on using the repository browser.