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

Last change on this file since 2162 was 2162, checked in by pharms, 7 years ago
  • changes for first VR oriented usability evaluation
File size: 11.0 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.ListIterator;
23import java.util.Map;
24import java.util.Set;
25import java.util.logging.Level;
26
27import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
28import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
29import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
35import de.ugoe.cs.util.console.Console;
36
37/**
38 * TODO comment
39 *
40 * @version $Revision: $ $Date: 16.07.2012$
41 * @author 2012, last modified by $Author: pharms$
42 */
43public class UsabilityEvaluationManager {
44   
45    /** */
46    private List<UsabilityEvaluationRule> rules = new ArrayList<UsabilityEvaluationRule>();
47
48    /**
49     *
50     */
51    public UsabilityEvaluationManager() {
52        super();
53        init();
54    }
55
56    /**
57     *
58     */
59    private void init() {
60//        rules.add(new TaskTreeTestRule());
61       
62        rules.add(new EventCoverageRatioRule());
63        rules.add(new RequiredInefficientActionsRule());
64        rules.add(new TargetDistanceRule());
65        rules.add(new MissingFeedbackRule());
66        rules.add(new TaskRetryRule());
67        rules.add(new DataEntryMethodChangeRule());
68        rules.add(new CommonTaskRateRule());
69        rules.add(new TextInputStatisticsRule());
70        rules.add(new CheckBoxMultipleSelectionRule());
71        rules.add(new MisleadingClickCueRule());
72        rules.add(new DefaultCursorPositioningRule());
73        rules.add(new DefaultValueRule());
74        rules.add(new UnusedGUIElementsRule());
75       
76//        rules.add(new TaskCooccurrenceRule());
77    }
78
79    /**
80     *
81     */
82    public UsabilityEvaluationResult evaluateUsability(ITaskModel taskModel,
83                                                       int        maxCount,
84                                                       boolean    onlyMostRepresentative)
85    {
86        Console.traceln(Level.INFO, "evaluating usability of task model " + taskModel);
87
88        List<UsabilityEvaluationResult> interimResults = new ArrayList<UsabilityEvaluationResult>();
89        Set<ITask> mostRepresentativeTasks = null;
90
91        for (UsabilityEvaluationRule rule : rules) {
92            Console.traceln(Level.INFO, "\napplying rule " + rule.getClass().getSimpleName());
93            UsabilityEvaluationResult ruleResult = rule.evaluate(taskModel);
94
95            Map<String, List<UsabilitySmell>> smellGroups = new HashMap<>();
96           
97            for (UsabilitySmell smell : ruleResult.getAllSmells()) {
98                List<UsabilitySmell> smellGroup = smellGroups.get(smell.getBriefDescription());
99               
100                if (smellGroup == null) {
101                    smellGroup = new LinkedList<>();
102                    smellGroups.put(smell.getBriefDescription(), smellGroup);
103                }
104               
105                smellGroup.add(smell);
106            }
107           
108            for (Map.Entry<String, List<UsabilitySmell>> smellGroup : smellGroups.entrySet()) {
109                Console.traceln(Level.INFO, "the rule found " + smellGroup.getValue().size() +
110                                " usability smells of type \"" + smellGroup.getKey() + "\"");
111               
112                ruleResult = new UsabilityEvaluationResult(taskModel, smellGroup.getValue());
113               
114                checkDuplicates(ruleResult);
115               
116                if ((onlyMostRepresentative) || (maxCount < ruleResult.getAllSmells().size())) {
117                    LinkedList<UsabilitySmell> sortedSmells = new LinkedList<>();
118                   
119                    if (onlyMostRepresentative) {
120                        Console.traceln(Level.INFO, "filtering for smells that refer to only most " +
121                                        "representative tasks.");
122                    }
123                   
124                    for (UsabilitySmell smell : ruleResult.getAllSmells()) {
125                        if (onlyMostRepresentative && (smell.getSmellingTask() != null)) {
126                            if (mostRepresentativeTasks == null) {
127                                mostRepresentativeTasks = getMostRepresentativeSequences(taskModel);
128                            }
129                           
130                            if (!mostRepresentativeTasks.contains(smell.getSmellingTask())) {
131                                continue;
132                            }
133                        }
134                       
135                        ListIterator<UsabilitySmell> iterator = sortedSmells.listIterator();
136
137                        boolean added = false;
138                       
139                        while (iterator.hasNext()) {
140                            if (iterator.next().getIntensity().getEventCoverage() <
141                                smell.getIntensity().getEventCoverage())
142                            {
143                                iterator.previous();
144                                iterator.add(smell);
145                                added = true;
146                                break;
147                            }
148                        }
149                   
150                        if (!added) {
151                            sortedSmells.add(smell);
152                        }
153                   
154                    }
155                   
156                    if (maxCount < ruleResult.getAllSmells().size()) {
157                        Console.traceln(Level.INFO, "filtering for " + maxCount +
158                                " smells of same type with highest event coverage.");
159                       
160                        while (sortedSmells.size() > maxCount) {
161                            sortedSmells.removeLast();
162                        }
163                    }
164               
165                    Console.traceln(Level.INFO, sortedSmells.size() + " remaining.");
166                    ruleResult = new UsabilityEvaluationResult(taskModel, sortedSmells);
167                    checkDuplicates(ruleResult);
168                }
169           
170                interimResults.add(ruleResult);
171            }
172        }
173
174        UsabilityEvaluationResult result = new UsabilityEvaluationResult(taskModel, interimResults);
175        Console.println("the evaluation result contains " + result.getAllSmells().size() +
176                        " smells.");
177
178        return result;
179    }
180
181    /**
182     * <p>
183     * TODO: comment
184     * </p>
185     *
186     * @param taskModel
187     * @return
188     */
189    private Set<ITask> getMostRepresentativeSequences(ITaskModel taskModel) {
190        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
191        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
192        int maxCoverage = 0;
193
194        for (ITask task : taskModel.getTasks()) {
195            if (task instanceof ISequence) {
196                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
197
198                for (ITaskInstance instance : task.getInstances()) {
199                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
200                        @Override
201                        public void visit(IEventTaskInstance eventTaskInstance) {
202                            coveredEvents.add(eventTaskInstance);
203                        }
204                    });
205                }
206
207                coverages.put((ISequence) task, coveredEvents);
208
209                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
210
211                if (tasksWithSameCoverage == null) {
212                    tasksWithSameCoverage = new LinkedList<>();
213                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
214                }
215
216                tasksWithSameCoverage.add((ISequence) task);
217
218                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
219            }
220        }
221
222        Set<ITask> mostRepresentativeSequences = new HashSet<>();
223
224        for (int i = maxCoverage; i > 0; i--) {
225            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
226
227            if (sequencesWithSameCoverage == null) {
228                continue;
229            }
230
231            for (ISequence sequence : sequencesWithSameCoverage) {
232                mostRepresentativeSequences.add(sequence);
233            }
234           
235            if ((100 * mostRepresentativeSequences.size() / coverages.size()) > 20) {
236                break;
237            }
238        }
239
240        return mostRepresentativeSequences;
241    }
242
243    /**
244     *
245     */
246    private void checkDuplicates(UsabilityEvaluationResult result) {
247        List<ITask> referredTasks = new ArrayList<ITask>();
248
249        for (UsabilitySmell smell : result.getAllSmells()) {
250            if (smell.getSmellingTask() != null) {
251                referredTasks.add(smell.getSmellingTask());
252            }
253        }
254           
255        int counter = 0;
256        for (int i = 0; i < referredTasks.size(); i++) {
257            for (int j = 0; j < referredTasks.size(); j++) {
258                if (isChildOf(referredTasks.get(i), referredTasks.get(j))) {
259                    counter++;
260                    break;
261                }
262            }
263        }
264           
265        if (counter > 0) {
266            Console.traceln(Level.INFO, counter + " of the findings are duplicates in " +
267                            "that they refer to tasks whose parent tasks are also " +
268                            "referred by the findings");
269        }
270    }
271
272    /**
273     *
274     */
275    private boolean isChildOf(final ITask potChild, ITask potParent) {
276       
277        if (potParent instanceof IStructuringTemporalRelationship) {
278            for (ITask child : ((IStructuringTemporalRelationship) potParent).getChildren()) {
279                if ((child == potChild) || isChildOf(potChild, child)) {
280                    return true;
281                }
282            }
283        }
284        else if (potParent instanceof IMarkingTemporalRelationship) {
285            ITask child = ((IMarkingTemporalRelationship) potParent).getMarkedTask();
286            if ((child == potChild) || isChildOf(potChild, child)) {
287                return true;
288            }
289        }
290       
291        return false;
292    }
293
294}
Note: See TracBrowser for help on using the repository browser.