source: trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/DataEntryMethodChangeRule.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: 7.1 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.Collection;
18import java.util.HashMap;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Map;
22
23import de.ugoe.cs.autoquest.eventcore.IEventType;
24import de.ugoe.cs.autoquest.eventcore.gui.KeyInteraction;
25import de.ugoe.cs.autoquest.eventcore.gui.MouseInteraction;
26import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
27import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
28import de.ugoe.cs.autoquest.eventcore.gui.TextSelection;
29import de.ugoe.cs.autoquest.eventcore.gui.ValueSelection;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
38
39/**
40 * TODO comment
41 *
42 * @version $Revision: $ $Date: 16.07.2012$
43 * @author 2012, last modified by $Author: pharms$
44 */
45public class DataEntryMethodChangeRule implements UsabilityEvaluationRule {
46
47    /*
48     * (non-Javadoc)
49     *
50     * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree)
51     */
52    @Override
53    public UsabilityEvaluationResult evaluate(ITaskModel taskModel) {
54        UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel);
55
56        Map<ITask, Integer> smellingTasks = getDataEntryMethodChangeRatios(taskModel.getTasks());
57        analyzeDataEntryMethodChangeRatios(smellingTasks, results, taskModel);
58
59        return results;
60    }
61
62    /**
63     *
64     */
65    private void analyzeDataEntryMethodChangeRatios(Map<ITask, Integer>       smellingTasks,
66                                                    UsabilityEvaluationResult results,
67                                                    ITaskModel                taskModel)
68    {
69
70        for (Map.Entry<ITask, Integer> entry : smellingTasks.entrySet()) {
71            // data entry method change ratio of an instance is the sum of data entry method
72            // changes between subsequent events divided by the number of events minus one. The
73            // data entry method change ratio of a tasks is the average of the ratios of the
74            // instances. If this ratio is 0 no changes are done at all. If it is higher, it should
75            // be informed.
76           
77            UsabilitySmellIntensity intensity =
78                UsabilitySmellIntensity.getIntensity(entry.getValue(), entry.getKey(), taskModel);
79
80            if (intensity != null) {
81                Map<String, Object> parameters = new HashMap<String, Object>();
82
83                parameters.put("task", entry.getKey());
84                parameters.put("ratio", (float) entry.getValue() / 10);
85               
86                results.addSmell(entry.getKey(), intensity,
87                                 UsabilitySmellDescription.DATA_ENTRY_METHOD_CHANGE, parameters);
88            }
89        }
90    }
91
92    /**
93     *
94     */
95    private Map<ITask, Integer> getDataEntryMethodChangeRatios(Collection<ITask> tasks) {
96        Map<ITask, Integer> methodChangeRatios = new HashMap<ITask, Integer>();
97       
98        for (ITask task : tasks) {
99            if (task instanceof ISequence)  {
100                int ratio = getAverageDataEntryMethodChangeRatio((ISequence) task);
101               
102                if ((ratio > 0) && (getLeafNodes(task) > 2)) {
103                    methodChangeRatios.put(task, ratio);
104                }
105            }
106        }
107       
108        return methodChangeRatios;
109    }
110
111    /**
112     *
113     */
114    private int getLeafNodes(ITask task) {
115        final int[] counter = new int[1];
116       
117        task.accept(new DefaultTaskTraversingVisitor() {
118            @Override
119            public void visit(IEventTask eventTask) {
120                counter[0]++;
121            }
122        });
123       
124        return counter[0];
125    }
126
127    /**
128     *
129     */
130    private int getAverageDataEntryMethodChangeRatio(ISequence task) {
131        if (task.getInstances().size() > 0) {
132            int cummulativeDataEntryMethodChangeRatio = 0;
133            for (ITaskInstance instance : task.getInstances()) {
134                cummulativeDataEntryMethodChangeRatio += getDataEntryMethodChangeRatio(instance);
135            }
136
137            return cummulativeDataEntryMethodChangeRatio / task.getInstances().size();
138        }
139        else {
140            return 0;
141        }
142    }
143
144    /**
145     *
146     */
147    private long getDataEntryMethodChangeRatio(ITaskInstance instance) {
148        final List<IEventTaskInstance> terminalNodes = new LinkedList<>();
149       
150        instance.accept(new DefaultTaskInstanceTraversingVisitor() {
151            @Override
152            public void visit(IEventTaskInstance eventTaskInstance) {
153                terminalNodes.add(eventTaskInstance);
154            }
155        });
156       
157        if (terminalNodes.size() > 1) {
158            IEventTaskInstance previous = null;
159            int changeCount = 0;
160
161            for (IEventTaskInstance current : terminalNodes) {
162                if ((previous != null) && (dataEntryMethodChanges(previous, current))) {
163                    changeCount++;
164                }
165               
166                previous = current;
167            }
168
169            return changeCount * 1000 / (terminalNodes.size() - 1);
170        }
171        else {
172            return 0;
173        }
174    }
175
176
177    /**
178     *
179     */
180    private boolean dataEntryMethodChanges(IEventTaskInstance first, IEventTaskInstance second) {
181        IEventType firstEventType = first.getEvent().getType();
182        IEventType secondEventType = second.getEvent().getType();
183       
184        boolean hasKeyboardInteraction =
185            isKeyboardInteraction(firstEventType) || isKeyboardInteraction(secondEventType);
186       
187        boolean hasMouseInteraction =
188            isMouseInteraction(firstEventType) || isMouseInteraction(secondEventType);
189       
190        return hasKeyboardInteraction && hasMouseInteraction;
191    }
192
193    /**
194     *
195     */
196    private boolean isKeyboardInteraction(IEventType eventType) {
197        return (eventType instanceof KeyInteraction) || (eventType instanceof TextInput);
198    }
199
200    /**
201     *
202     */
203    private boolean isMouseInteraction(IEventType eventType) {
204        return (eventType instanceof MouseInteraction) || (eventType instanceof ValueSelection) ||
205            (eventType instanceof TextSelection) || (eventType instanceof Scroll);
206    }
207}
Note: See TracBrowser for help on using the repository browser.