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
RevLine 
[1493]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
[2042]17import java.util.ArrayList;
[1493]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;
[2042]31import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
[1493]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;
[2042]36import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
[1493]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;
[2042]42import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
[1493]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);
[2042]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        }
[1493]70
71        return results;
72    }
73
74    /**
[2042]75     * @param results
[1493]76     *
77     */
[2042]78    private void handleUnusedGUIElements(Map<IGUIView, Set<IGUIElement>> usedGUIElements,
79                                         IGUIView                        view,
80                                         List<Set<IGUIElement>>          viewUsages,
81                                         UsabilityEvaluationResult       results)
[1493]82    {
[2042]83        Set<IGUIElement> allElementsInView = usedGUIElements.get(view);
[1493]84       
[2042]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;
[1493]93           
[2042]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);
[1493]108        }
[2042]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();
[1493]119
[2042]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);
[1493]134            }
135        }
136    }
137
138    /**
139     *
140     */
[2042]141    private Map<IGUIView, Set<IGUIElement>> getAllGUIElements(ITaskModel taskModel) {
142        Map<IGUIView, Set<IGUIElement>> result = new HashMap<>();
[1493]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                   
[2042]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());
[1493]162                    }
163                }
164            }
165        }
166       
[2135]167        if (result.size() <= 0) {
168            return result;
169        }
170
[2042]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.
[1493]174       
[2042]175        GUIModel model = result.values().iterator().next().iterator().next().getGUIModel();
176       
177        GUIModel.Traverser traverser = model.getTraverser();
[1493]178
[2042]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;
[1493]193                    }
194                }
[2042]195            }
[1493]196
[2042]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);
[1493]205                }
[2042]206               
207                elements.add(currentGUIElement);
[1493]208            }
209        }
[2042]210        while (currentGUIElement != null);
[1493]211       
[2042]212        return result;
[1493]213    }
[2042]214
[1493]215    /**
[2042]216     *
[1493]217     */
[2042]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                });
[1493]252            }
[2042]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            }
[1493]258        }
259       
[2042]260        return result;
[1493]261    }
262
263    /**
264     *
265     */
[2042]266    private void addRelevantTargets(IGUIView                              view,
267                                    List<IEventTaskInstance>              actionInstances,
268                                    Map<IGUIView, List<Set<IGUIElement>>> result)
[1493]269    {
[2042]270        List<Set<IGUIElement>> usedGUIElements = result.get(view);
271       
272        if (usedGUIElements == null) {
273            usedGUIElements = new LinkedList<>();
274            result.put(view, usedGUIElements);
[1493]275        }
[2042]276       
277        Set<IGUIElement> elementsInViewDisplay = new HashSet<>();
278       
279        for (IEventTaskInstance actionInstance : actionInstances) {
280            IGUIElement element = (IGUIElement) actionInstance.getEvent().getTarget();
[1493]281           
[2042]282            while (element != null) {
283                if (isRelevant(element)) {
284                    elementsInViewDisplay.add(element);
[1493]285                }
[2042]286               
287                element = element.getParent();
[1493]288            }
289        }
290       
[2042]291        usedGUIElements.add(elementsInViewDisplay);
[1493]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.