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

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