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

Last change on this file since 2042 was 2042, checked in by pharms, 9 years ago
  • finalized smell detection for phd thesis
File size: 8.6 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.List;
20import java.util.Map;
21
22import de.ugoe.cs.autoquest.eventcore.IEventType;
23import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction;
24import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
25import de.ugoe.cs.autoquest.eventcore.gui.MouseDoubleClick;
26import de.ugoe.cs.autoquest.eventcore.guimodel.IButton;
27import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
28import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView;
29import de.ugoe.cs.autoquest.eventcore.guimodel.IImage;
30import de.ugoe.cs.autoquest.eventcore.guimodel.IText;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
36
37/**
38 * TODO comment
39 *
40 * @version $Revision: $ $Date: 16.07.2012$
41 * @author 2012, last modified by $Author: pharms$
42 */
43public class MisleadingClickCueRule implements UsabilityEvaluationRule {
44
45    /*
46     * (non-Javadoc)
47     *
48     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
49     */
50    @Override
51    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
52        UselessClickStatistics statistics = new UselessClickStatistics();
53        int allObserved = calculateStatistics(taskModel.getUserSessions(), statistics);
54
55        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
56        analyzeStatistics(statistics, allObserved, results);
57
58        return results;
59    }
60
61    /**
62     *
63     */
64    private void analyzeStatistics(UselessClickStatistics    statistics,
65                                   int                       allObserved,
66                                   UsabilityEvaluationResult results)
67    {
68        for (Map.Entry<IGUIElement, Map<IGUIView, Integer>> uselessClickCounter :
69                statistics.getUselessClickCounters().entrySet())
70        {
71            int uselessClicks = 0;
72            int noOfViewDisplays = 0;
73           
74            for (Map.Entry<IGUIView, Integer> counter : uselessClickCounter.getValue().entrySet()) {
75                uselessClicks += counter.getValue();
76                noOfViewDisplays += statistics.getViewOpenedCount(counter.getKey());
77            }
78
79            int ratio = Math.min(1000, 1000 * uselessClicks / noOfViewDisplays);
80
81            UsabilitySmellIntensity intensity =
82                UsabilitySmellIntensity.getIntensity(ratio, uselessClicks, -1);
83
84            if (intensity != null) {
85                Map<String, Object> parameters = new HashMap<String, Object>();
86                parameters.put("noOfViewDisplays", noOfViewDisplays);
87                parameters.put("uselessClicks", uselessClicks);
88                parameters.put("element", uselessClickCounter.getKey());
89
90                results.addSmell
91                    (intensity, UsabilitySmellDescription.MISLEADING_CLICK_CUE, parameters);
92            }
93        }
94    }
95
96
97    /**
98     *
99     */
100    private int calculateStatistics(List<IUserSession>            sessions,
101                                     final UselessClickStatistics statistics)
102    {
103        final List<IEventTaskInstance> leafNodes = new ArrayList<>();
104        final IGUIView[] currentView = new IGUIView[1];
105       
106        for (IUserSession session : sessions) {
107            currentView[0] = null;
108           
109            for (final ITaskInstance currentRoot : session) {
110                currentRoot.accept(new DefaultTaskInstanceTraversingVisitor() {
111                    @Override
112                    public void visit(IEventTaskInstance eventTaskInstance) {
113                        leafNodes.add(eventTaskInstance);
114                       
115                        if (eventTaskInstance.getEvent().getTarget() instanceof IGUIElement) {
116                            IGUIView view =
117                                ((IGUIElement) eventTaskInstance.getEvent().getTarget()).getView();
118                           
119                            if (((currentView[0] == null) && (view != null)) ||
120                                ((currentView[0] != null) && (!currentView[0].equals(view))))
121                            {
122                                currentView[0] = view;
123                                statistics.addViewOpened(view);
124                            }
125                           
126                            if (isUselessMouseClick(eventTaskInstance)) {
127                                statistics.addUselessClick(eventTaskInstance);
128                            }
129                        }
130                    }
131                });
132            }
133        }
134       
135        return leafNodes.size();
136    }
137
138    /**
139     *
140     */
141    private boolean isUselessMouseClick(IEventTaskInstance eventTaskInstance) {
142        IEventType type = eventTaskInstance.getEvent().getType();
143       
144        if ((!(type instanceof MouseClick)) && (!(type instanceof MouseDoubleClick))) {
145            return false;
146        }
147       
148        if (((MouseButtonInteraction) type).getButton() != MouseButtonInteraction.Button.LEFT) {
149            return false;
150        }
151               
152        IGUIElement target = (IGUIElement) eventTaskInstance.getEvent().getTarget();
153       
154        if ((target instanceof IImage) /*|| (target instanceof IPanel) ||
155            (target instanceof IProgressBar) || (target instanceof IScrollPane) ||
156            (target instanceof IShape) || (target instanceof ITable)*/ ||
157            (target instanceof IText))
158        {
159            // check if the parent is a button
160            IGUIElement parent = target;
161            while ((parent != null) && !(parent instanceof IButton)) {
162                parent = parent.getParent();
163            }
164           
165            return !(parent instanceof IButton);
166        }
167        else {
168            return false;
169        }
170    }
171
172    /**
173     *
174     */
175    private class UselessClickStatistics {
176       
177        /** */
178        private Map<IGUIView, Integer> viewOpenedCounters = new HashMap<>();
179       
180        /** */
181        private Map<IGUIElement, Map<IGUIView, Integer>> uselessClickCounters = new HashMap<>();
182
183        /**
184         * <p>
185         * TODO: comment
186         * </p>
187         *
188         * @param view
189         */
190        private void addViewOpened(IGUIView view) {
191            Integer counter = viewOpenedCounters.get(view);
192           
193            if (counter == null) {
194                viewOpenedCounters.put(view, 1);
195            }
196            else {
197                viewOpenedCounters.put(view, counter + 1);
198            }
199        }
200
201        /**
202         * <p>
203         * TODO: comment
204         * </p>
205         *
206         * @param eventTaskInstance
207         */
208        private void addUselessClick(IEventTaskInstance eventTaskInstance) {
209            IGUIElement target = (IGUIElement) eventTaskInstance.getEvent().getTarget();
210           
211            Map<IGUIView, Integer> counterMap = uselessClickCounters.get(target);
212           
213            if (counterMap == null) {
214                counterMap = new HashMap<>();
215                uselessClickCounters.put(target, counterMap);
216            }
217           
218            Integer counter = counterMap.get(target.getView());
219           
220            if (counter == null) {
221                counterMap.put(target.getView(), 1);
222            }
223            else {
224                counterMap.put(target.getView(), counter + 1);
225            }
226        }
227
228        /**
229         *
230         */
231        private Map<IGUIElement, Map<IGUIView, Integer>> getUselessClickCounters() {
232            return uselessClickCounters;
233        }
234
235        /**
236         *
237         */
238        private int getViewOpenedCount(IGUIView view) {
239            Integer counter = viewOpenedCounters.get(view);
240           
241            if (counter == null) {
242                return 0;
243            }
244            else {
245                return counter;
246            }
247        }
248    }
249}
Note: See TracBrowser for help on using the repository browser.