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

Last change on this file was 2162, checked in by pharms, 7 years ago
  • changes for first VR oriented usability evaluation
File size: 11.0 KB
RevLine 
[927]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
[922]15package de.ugoe.cs.autoquest.usability;
[442]16
17import java.util.ArrayList;
[2042]18import java.util.HashMap;
[2162]19import java.util.HashSet;
[2042]20import java.util.LinkedList;
[442]21import java.util.List;
[2042]22import java.util.ListIterator;
23import java.util.Map;
[2162]24import java.util.Set;
[725]25import java.util.logging.Level;
[442]26
[2162]27import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
28import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
[1493]29import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
[2162]30import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
[1493]31import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
[2162]33import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
[1148]34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
[725]35import de.ugoe.cs.util.console.Console;
[442]36
37/**
38 * TODO comment
39 *
40 * @version $Revision: $ $Date: 16.07.2012$
41 * @author 2012, last modified by $Author: pharms$
42 */
[561]43public class UsabilityEvaluationManager {
44   
45    /** */
46    private List<UsabilityEvaluationRule> rules = new ArrayList<UsabilityEvaluationRule>();
[442]47
[561]48    /**
49     *
50     */
51    public UsabilityEvaluationManager() {
52        super();
53        init();
54    }
[442]55
[561]56    /**
57     *
58     */
59    private void init() {
[2042]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());
[2162]66        rules.add(new TaskRetryRule());
[2042]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());
[1918]73        rules.add(new DefaultValueRule());
[2042]74        rules.add(new UnusedGUIElementsRule());
75       
[1918]76//        rules.add(new TaskCooccurrenceRule());
[442]77    }
78
[561]79    /**
[1301]80     *
[561]81     */
[2162]82    public UsabilityEvaluationResult evaluateUsability(ITaskModel taskModel,
83                                                       int        maxCount,
84                                                       boolean    onlyMostRepresentative)
85    {
[1149]86        Console.traceln(Level.INFO, "evaluating usability of task model " + taskModel);
[561]87
[1335]88        List<UsabilityEvaluationResult> interimResults = new ArrayList<UsabilityEvaluationResult>();
[2162]89        Set<ITask> mostRepresentativeTasks = null;
[561]90
91        for (UsabilityEvaluationRule rule : rules) {
[2042]92            Console.traceln(Level.INFO, "\napplying rule " + rule.getClass().getSimpleName());
[2162]93            UsabilityEvaluationResult ruleResult = rule.evaluate(taskModel);
[2042]94
95            Map<String, List<UsabilitySmell>> smellGroups = new HashMap<>();
[1493]96           
[2162]97            for (UsabilitySmell smell : ruleResult.getAllSmells()) {
[2042]98                List<UsabilitySmell> smellGroup = smellGroups.get(smell.getBriefDescription());
99               
100                if (smellGroup == null) {
101                    smellGroup = new LinkedList<>();
102                    smellGroups.put(smell.getBriefDescription(), smellGroup);
[1493]103                }
[2042]104               
105                smellGroup.add(smell);
[1918]106            }
[2042]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() + "\"");
[1493]111               
[2162]112                ruleResult = new UsabilityEvaluationResult(taskModel, smellGroup.getValue());
[2042]113               
[2162]114                checkDuplicates(ruleResult);
[2042]115               
[2162]116                if ((onlyMostRepresentative) || (maxCount < ruleResult.getAllSmells().size())) {
[2042]117                    LinkedList<UsabilitySmell> sortedSmells = new LinkedList<>();
118                   
[2162]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                       
[2042]135                        ListIterator<UsabilitySmell> iterator = sortedSmells.listIterator();
136
137                        boolean added = false;
138                       
139                        while (iterator.hasNext()) {
140                            if (iterator.next().getIntensity().getEventCoverage() <
[2162]141                                smell.getIntensity().getEventCoverage())
[2042]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                   
[2162]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                       
[2042]160                        while (sortedSmells.size() > maxCount) {
161                            sortedSmells.removeLast();
162                        }
[1493]163                    }
[2042]164               
[2162]165                    Console.traceln(Level.INFO, sortedSmells.size() + " remaining.");
166                    ruleResult = new UsabilityEvaluationResult(taskModel, sortedSmells);
167                    checkDuplicates(ruleResult);
[1493]168                }
[2042]169           
[2162]170                interimResults.add(ruleResult);
[1918]171            }
[561]172        }
173
[1493]174        UsabilityEvaluationResult result = new UsabilityEvaluationResult(taskModel, interimResults);
[1918]175        Console.println("the evaluation result contains " + result.getAllSmells().size() +
176                        " smells.");
[561]177
178        return result;
179    }
180
[1493]181    /**
[2162]182     * <p>
183     * TODO: comment
184     * </p>
[1493]185     *
[2162]186     * @param taskModel
187     * @return
[1493]188     */
[2162]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     */
[2042]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     */
[1493]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
[442]294}
Note: See TracBrowser for help on using the repository browser.