Changeset 1493 for trunk/autoquest-core-usability/src
- Timestamp:
- 04/11/14 11:21:45 (11 years ago)
- Location:
- trunk/autoquest-core-usability/src/main
- Files:
-
- 7 added
- 8 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java
r1335 r1493 15 15 package de.ugoe.cs.autoquest.usability; 16 16 17 import java.text.DecimalFormat;18 17 import java.util.Collection; 19 18 import java.util.HashMap; 20 19 import java.util.Map; 21 20 22 import de.ugoe.cs.autoquest.eventcore.IEventType; 21 import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; 22 23 import de.ugoe.cs.autoquest.eventcore.Event; 23 24 import de.ugoe.cs.autoquest.eventcore.gui.Scroll; 25 import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor; 26 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; 24 27 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; 25 import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance; 26 import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance; 27 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance; 28 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; 29 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance; 28 import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; 30 29 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 31 30 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; … … 38 37 * @author 2012, last modified by $Author: pharms$ 39 38 */ 40 public class Required ScrollRule implements UsabilityEvaluationRule {39 public class RequiredInefficientActionsRule implements UsabilityEvaluationRule { 41 40 42 41 /* … … 47 46 @Override 48 47 public UsabilityEvaluationResult evaluate(ITaskModel taskModel) { 49 Map<ITask, Integer> smellingTasks = getTasksStartingWithScroll(taskModel.getTasks());48 UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel); 50 49 51 UsabilityEvaluationResult results = new UsabilityEvaluationResult();52 analyzeTasks StartingWithScroll(smellingTasks, results);50 Map<ITask, double[]> smellingTasks = getInefficientActionStatistics(taskModel.getTasks()); 51 analyzeTasksWithInefficientActions(smellingTasks, results, taskModel); 53 52 54 53 return results; … … 58 57 * 59 58 */ 60 private void analyzeTasksStartingWithScroll(Map<ITask, Integer> smellingTasks, 61 UsabilityEvaluationResult results) 59 private void analyzeTasksWithInefficientActions(Map<ITask, double[]> smellingTasks, 60 UsabilityEvaluationResult results, 61 ITaskModel taskModel) 62 62 { 63 63 64 for (Map.Entry<ITask, Integer> entry : smellingTasks.entrySet()) { 65 float ratio = entry.getValue() / (float) entry.getKey().getInstances().size(); 64 for (Map.Entry<ITask, double[]> entry : smellingTasks.entrySet()) { 65 DescriptiveStatistics stats = new DescriptiveStatistics(entry.getValue()); 66 67 int ratio = (int) (1000 * stats.getMean()); 66 68 67 UsabilityDefectSeverity severity = null; 68 if (ratio > 0.9) { 69 severity = UsabilityDefectSeverity.HIGH; 70 } 71 else if (ratio > 0.6) { 72 severity = UsabilityDefectSeverity.MEDIUM; 73 } 74 else if (ratio > 0.4) { 75 severity = UsabilityDefectSeverity.LOW; 76 } 77 else if (ratio > 0.2) { 78 severity = UsabilityDefectSeverity.INFO; 79 } 69 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 70 (ratio, 500, 300, 200, 100, entry.getKey(), taskModel); 80 71 81 72 if (severity != null) { 82 Map<String, String> parameters = new HashMap<String, String>();83 parameters.put("task", entry.getKey() .toString());84 parameters.put(" scrollRatio", DecimalFormat.getInstance().format(ratio * 100));73 Map<String, Object> parameters = new HashMap<String, Object>(); 74 parameters.put("task", entry.getKey()); 75 parameters.put("ratio", (ratio / 10)); 85 76 86 results.addDefect(severity, UsabilityDefectDescription.SCROLL_REQUIRED, parameters); 77 results.addDefect 78 (severity, UsabilityDefectDescription.INEFFICIENT_ACTIONS, parameters); 87 79 } 88 80 } … … 92 84 * 93 85 */ 94 private Map<ITask, Integer> getTasksStartingWithScroll(Collection<ITask> tasks) {95 Map<ITask, Integer> scrollCounts = new HashMap<ITask, Integer>();86 private Map<ITask, double[]> getInefficientActionStatistics(Collection<ITask> tasks) { 87 Map<ITask, double[]> inefficientActionRatios = new HashMap<ITask, double[]>(); 96 88 97 89 for (ITask task : tasks) { 98 // only sequences are important for required scrolls 99 if (task instanceof ISequence) { 100 int count = countInstancesStartingWithScroll(task); 101 if (count > 0) { 102 scrollCounts.put(task, count); 90 if (taskMustBeChecked(task)) { 91 double[] ratios = getRatiosOfInefficientActionsInInstances(task); 92 93 for (int i = 0; i < ratios.length; i++) { 94 if (ratios[i] > 0) { 95 // there is at least on inefficient action 96 inefficientActionRatios.put(task, ratios); 97 break; 98 } 103 99 } 104 100 } 105 101 } 106 102 107 return scrollCounts;103 return inefficientActionRatios; 108 104 } 109 105 … … 111 107 * 112 108 */ 113 private int countInstancesStartingWithScroll(ITask task) { 114 Collection<ITaskInstance> instances = task.getInstances(); 115 116 int counter = 0; 117 for (ITaskInstance instance : instances) { 118 if (startsWithScroll(instance)) { 119 counter++; 120 } 109 private boolean taskMustBeChecked(ITask task) { 110 if ((task instanceof IEventTask) || (task instanceof IMarkingTemporalRelationship)) { 111 // event tasks are not considered 112 // marking temporal relationships have a child, that is more important, but it will 113 // be checked independently as all tasks of a task model are checked separately 114 return false; 121 115 } 122 123 return counter; 116 else { 117 return true; 118 } 124 119 } 125 120 … … 127 122 * 128 123 */ 129 private boolean startsWithScroll(ITaskInstance instance) { 130 if (instance instanceof ISequenceInstance) { 131 ITaskInstance firstChild = ((ISequenceInstance) instance).size() > 1 ? 132 ((ISequenceInstance) instance).get(0) : null; 133 134 if (firstChild == null) { 135 throw new IllegalArgumentException 136 ("instance of a sequence must have at least two children"); 137 } 138 139 if (startsWithScroll(firstChild)) { 140 return true; 141 } 142 } 143 else if (instance instanceof ISelectionInstance) { 144 ITaskInstance child = ((ISelectionInstance) instance).getChild(); 145 146 if (child != null) { 147 return startsWithScroll(child); 148 } 149 else { 150 throw new IllegalArgumentException("instance of a selection must have a child"); 151 } 152 } 153 else if (instance instanceof IIterationInstance) { 154 ITaskInstance firstChild = ((IIterationInstance) instance).size() > 0 ? 155 ((IIterationInstance) instance).get(0) : null; 156 157 if (firstChild == null) { 158 throw new IllegalArgumentException 159 ("instance of an iteration must have at least one child"); 160 } 161 162 if (startsWithScroll(firstChild)) { 163 return true; 164 } 165 } 166 else if (instance instanceof IOptionalInstance) { 167 ITaskInstance child = ((IOptionalInstance) instance).getChild(); 168 169 if (child != null) { 170 return startsWithScroll(child); 171 } 172 } 173 else if (isScroll(instance)) { 174 return true; 124 private double[] getRatiosOfInefficientActionsInInstances(ITask task) { 125 Collection<ITaskInstance> instances = task.getInstances(); 126 127 double[] ratios = new double[instances.size()]; 128 int index = 0; 129 for (ITaskInstance instance : instances) { 130 ratios[index++] = getRatioOfInefficientActionsInInstance(instance); 175 131 } 176 132 177 return false;133 return ratios; 178 134 } 179 135 180 136 /** 181 * @param firstChild 182 * @return 137 * 183 138 */ 184 private boolean isScroll(ITaskInstance instance) { 185 ITaskInstance instanceToCheck = instance; 139 private double getRatioOfInefficientActionsInInstance(ITaskInstance instance) { 140 final int[] count = new int[2]; 141 count[0] = 0; 142 count[1] = 0; 186 143 187 if (instanceToCheck instanceof IIterationInstance) { 188 instanceToCheck = ((IIterationInstance) instanceToCheck).size() > 0 ? 189 ((IIterationInstance) instanceToCheck).get(0) : null; 144 instance.accept(new DefaultTaskInstanceTraversingVisitor() { 145 @Override 146 public void visit(IEventTaskInstance eventTaskInstance) { 147 if (isInefficientAction(eventTaskInstance.getEvent())) { 148 count[0]++; 149 } 150 151 count[1]++; 152 } 153 154 }); 155 156 return (double) count[0] / count[1]; 157 } 190 158 191 if (instanceToCheck == null) { 192 throw new IllegalArgumentException 193 ("instance of an iteration must have at least one child"); 194 } 195 } 196 197 if (instanceToCheck instanceof IEventTaskInstance) { 198 IEventType type = ((IEventTaskInstance) instanceToCheck).getEvent().getType(); 199 200 return (type instanceof Scroll); 201 } 202 203 return false; 159 /** 160 * 161 */ 162 private boolean isInefficientAction(Event event) { 163 return (event.getType() instanceof Scroll); 204 164 } 205 165 -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TextInputStatisticsRule.java
r1335 r1493 15 15 package de.ugoe.cs.autoquest.usability; 16 16 17 import java.text.DecimalFormat;18 17 import java.util.ArrayList; 19 18 import java.util.Collection; … … 57 56 calculateStatistics(taskModel.getUserSessions(), statistics); 58 57 59 UsabilityEvaluationResult results = new UsabilityEvaluationResult( );58 UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel); 60 59 analyzeStatistics(statistics, results); 61 60 … … 80 79 UsabilityEvaluationResult results) 81 80 { 82 float allTextFieldInputs =81 int allTextFieldInputs = 83 82 statistics.getNoOfTextFieldInputs() + statistics.getNoOfTextAreaInputs(); 84 83 85 float ratio = allTextFieldInputs / (float) statistics.getNoOfAllEvents(); 86 87 UsabilityDefectSeverity severity = null; 88 if (ratio > 0.9) { 89 severity = UsabilityDefectSeverity.HIGH; 90 } 91 else if (ratio > 0.7) { 92 severity = UsabilityDefectSeverity.MEDIUM; 93 } 94 else if (ratio > 0.5) { 95 severity = UsabilityDefectSeverity.LOW; 96 } 97 else if (ratio > 0.3) { 98 severity = UsabilityDefectSeverity.INFO; 99 } 100 84 int ratio = 1000 * allTextFieldInputs / statistics.getNoOfAllEvents(); 85 86 // TODO comment magic numbers 87 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 88 (ratio, 900, 700, 500, 300); 89 101 90 if (severity != null) { 102 Map<String, String> parameters = new HashMap<String, String>();103 parameters.put("textInputRatio", DecimalFormat.getInstance().format(ratio * 100));91 Map<String, Object> parameters = new HashMap<String, Object>(); 92 parameters.put("textInputRatio", (ratio / 10)); 104 93 105 94 results.addDefect … … 122 111 int noOfUsagesOfTextField1WithSameTextInTextField2 = entry.enteredTexts.size(); 123 112 124 float ratioTextField1 =125 noOfUsagesOfTextField1WithSameTextInTextField2 / (float)noOfUsagesOfTextField1;126 127 float ratioTextField2 =128 noOfUsagesOfTextField1WithSameTextInTextField2 / (float)noOfUsagesOfTextField2;129 130 createTextFieldEntryRepetitionDefect 131 (ratioTextField1, entry.textField1,entry.textField2, results);132 133 createTextFieldEntryRepetitionDefect 134 (ratioTextField2, entry.textField2,entry.textField1, results);135 136 } 137 } 138 139 /** 140 * 141 */ 142 private void createTextFieldEntryRepetitionDefect( floatratioOfEqualEntries,113 int ratioTextField1 = 114 1000 * noOfUsagesOfTextField1WithSameTextInTextField2 / noOfUsagesOfTextField1; 115 116 int ratioTextField2 = 117 1000 * noOfUsagesOfTextField1WithSameTextInTextField2 / noOfUsagesOfTextField2; 118 119 createTextFieldEntryRepetitionDefect(ratioTextField1, entry.textField1, 120 entry.textField2, results); 121 122 createTextFieldEntryRepetitionDefect(ratioTextField2, entry.textField2, 123 entry.textField1, results); 124 125 } 126 } 127 128 /** 129 * 130 */ 131 private void createTextFieldEntryRepetitionDefect(int ratioOfEqualEntries, 143 132 ITextField textField1, 144 133 ITextField textField2, 145 134 UsabilityEvaluationResult results) 146 135 { 147 UsabilityDefectSeverity severity = null; 148 if (ratioOfEqualEntries > 0.9) { 149 severity = UsabilityDefectSeverity.HIGH; 150 } 151 else if (ratioOfEqualEntries > 0.5) { 152 severity = UsabilityDefectSeverity.MEDIUM; 153 } 154 else if (ratioOfEqualEntries > 0.2) { 155 severity = UsabilityDefectSeverity.LOW; 156 } 157 else if (ratioOfEqualEntries > 0.1) { 158 severity = UsabilityDefectSeverity.INFO; 159 } 136 // TODO comment magic numbers 137 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 138 (ratioOfEqualEntries, 900, 500, 200, 100); 160 139 161 140 if (severity != null) { 162 Map<String, String> parameters = new HashMap<String, String>(); 163 parameters.put("textRepetitionRatio", 164 DecimalFormat.getInstance().format(ratioOfEqualEntries * 100)); 165 parameters.put("textField1", textField1.toString()); 166 parameters.put("textField2", textField2.toString()); 141 Map<String, Object> parameters = new HashMap<String, Object>(); 142 parameters.put("textRepetitionRatio", (ratioOfEqualEntries / 10)); 143 parameters.put("textField1", textField1); 144 parameters.put("textField2", textField2); 167 145 168 146 results.addDefect … … 192 170 } 193 171 194 float ratio = (float) noLetterOrDigitCount / (float) allCharactersCount; 195 196 UsabilityDefectSeverity severity = null; 197 if (ratio > 0.1) { // every 10th sign 198 severity = UsabilityDefectSeverity.HIGH; 199 } 200 else if (ratio > 0.05) { // every 20th sign 201 severity = UsabilityDefectSeverity.MEDIUM; 202 } 203 else if (ratio > 0.02) { // every 50th sign 204 severity = UsabilityDefectSeverity.LOW; 205 } 206 else if (ratio > 0.01) { // every 100th sign 207 severity = UsabilityDefectSeverity.INFO; 208 } 172 int ratio = 1000 * noLetterOrDigitCount / allCharactersCount; 173 174 UsabilityDefectSeverity severity = 175 UsabilityDefectSeverity.getSeverity(ratio, 176 100, // every 10th sign 177 50, // every 20th sign 178 20, // every 50th sign 179 10 // every 100th sign 180 ); 209 181 210 182 if (severity != null) { 211 Map<String, String> parameters = new HashMap<String, String>(); 212 parameters.put("textField", textField.toString()); 213 parameters.put("noLetterOrDigitRatio", 214 DecimalFormat.getInstance().format(ratio * 100)); 183 Map<String, Object> parameters = new HashMap<String, Object>(); 184 parameters.put("textField", textField); 185 parameters.put("noLetterOrDigitRatio", (ratio / 10)); 215 186 216 187 results.addDefect 217 (severity, UsabilityDefectDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO, parameters); 188 (severity, UsabilityDefectDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO, 189 parameters); 218 190 } 219 191 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefect.java
r1335 r1493 15 15 package de.ugoe.cs.autoquest.usability; 16 16 17 import java.util.List; 17 18 import java.util.Map; 18 19 … … 32 33 33 34 /** */ 34 private Map<String, String> descriptionParameters;35 private Map<String, Object> descriptionParameters; 35 36 36 37 /** 37 38 * 38 39 */ 39 UsabilityDefect(UsabilityDefectSeverity severity, UsabilityDefectDescription description) 40 { 40 UsabilityDefect(UsabilityDefectSeverity severity, UsabilityDefectDescription description) { 41 41 this(severity, description, null); 42 42 } … … 47 47 UsabilityDefect(UsabilityDefectSeverity severity, 48 48 UsabilityDefectDescription description, 49 Map<String, String> parameters)49 Map<String, Object> parameters) 50 50 { 51 51 this.severity = severity; … … 80 80 public String getParameterizedDescription() { 81 81 return description.toString(descriptionParameters); 82 } 83 84 /** 85 * 86 */ 87 public List<Object> getDescriptionFragments() { 88 return description.toFragmentList(descriptionParameters); 89 } 90 91 /* 92 */ 93 public String getBriefDescription() { 94 return description.getBriefDescription(); 82 95 } 83 96 -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectDescription.java
r1335 r1493 18 18 import java.io.InputStream; 19 19 import java.util.ArrayList; 20 import java.util.Collection; 20 21 import java.util.List; 21 22 import java.util.Map; … … 33 34 public enum UsabilityDefectDescription { 34 35 35 SCROLL_REQUIRED,36 INEFFICIENT_ACTIONS, 36 37 TEXT_FIELD_INPUT_RATIO, 37 38 TEXT_FIELD_INPUT_REPETITIONS, 38 TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO; 39 TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO, 40 COOCCURENCE_SUCCEED, 41 COOCCURENCE_PRECED, 42 HIGH_EVENT_COVERAGE, 43 HIGH_TARGET_DISTANCE, 44 MISSING_FEEDBACK, 45 UNUSED_GUI_ELEMENTS; 39 46 40 47 /** */ … … 122 129 * 123 130 */ 124 public String toString(Map<String, String> parameters) throws IllegalArgumentException {131 public String toString(Map<String, Object> parameters) throws IllegalArgumentException { 125 132 StringBuffer result = new StringBuffer(); 126 133 … … 131 138 132 139 if (fragment instanceof ParameterFragment) { 133 Stringvalue = null;140 Object value = null; 134 141 if (parameters != null) { 135 142 value = parameters.get(((ParameterFragment) fragment).getParameterName()); … … 137 144 138 145 if (value != null) { 139 result.append(value); 146 if (value instanceof Collection<?>) { 147 int counter = 1; 148 for (Object elem : ((Collection<?>) value)) { 149 result.append('\n'); 150 result.append(counter++); 151 result.append(".: "); 152 result.append(elem); 153 } 154 } 155 else { 156 result.append(value.toString()); 157 } 140 158 } 141 159 else { … … 154 172 } 155 173 174 /** 175 * 176 */ 177 public List<Object> toFragmentList(Map<String, Object> parameters) 178 throws IllegalArgumentException 179 { 180 List<Object> result = new ArrayList<Object>(); 181 182 for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) { 183 if (fragment instanceof ParameterFragment) { 184 Object value = null; 185 if (parameters != null) { 186 value = parameters.get(((ParameterFragment) fragment).getParameterName()); 187 } 188 189 if (value != null) { 190 result.add(value); 191 } 192 else { 193 throw new IllegalArgumentException 194 ("required parameter \"" + 195 ((ParameterFragment) fragment).getParameterName() + 196 "\" for usability defect description " + this.name() + " not provided"); 197 } 198 } 199 else { 200 result.add(getFragmentString(fragment)); 201 } 202 } 203 204 return result; 205 } 206 207 /** 208 * 209 */ 210 public String getBriefDescription() { 211 return defectDescription.briefText; 212 } 213 156 214 /* 157 215 * (non-Javadoc) -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityDefectSeverity.java
r927 r1493 15 15 package de.ugoe.cs.autoquest.usability; 16 16 17 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 18 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo; 19 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; 20 import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric; 21 17 22 /** 18 23 * TODO comment … … 24 29 25 30 INFO, LOW, MEDIUM, HIGH; 31 32 /** */ 33 static int defaultCoverageQuantile = 950; 26 34 35 /** 36 * 37 */ 38 static UsabilityDefectSeverity getSeverity(int ratio, 39 int highRatioLevel, 40 int mediumRatioLevel, 41 int lowRatioLevel, 42 int infoRatioLevel) 43 { 44 return getSeverity(ratio, highRatioLevel, mediumRatioLevel, lowRatioLevel, infoRatioLevel, 45 defaultCoverageQuantile); 46 } 47 48 /** 49 * 50 */ 51 static UsabilityDefectSeverity getSeverity(int ratio, 52 int highRatioLevel, 53 int mediumRatioLevel, 54 int lowRatioLevel, 55 int infoRatioLevel, 56 ITask taskWithDefect, 57 ITaskModel wholeTaskModel) 58 { 59 ITaskInfo taskInfo = wholeTaskModel.getTaskInfo(taskWithDefect); 60 int eventCoverageQuantile = taskInfo.getMeasureValue(TaskMetric.EVENT_COVERAGE_QUANTILE); 61 return getSeverity(ratio, highRatioLevel, mediumRatioLevel, lowRatioLevel, infoRatioLevel, 62 eventCoverageQuantile); 63 } 64 65 /** 66 * 67 */ 68 static UsabilityDefectSeverity getSeverity(int ratio, 69 int highRatioLevel, 70 int mediumRatioLevel, 71 int lowRatioLevel, 72 int infoRatioLevel, 73 int coverageQuantile) 74 { 75 int effectiveRatio = ratio; 76 77 // event coverage ratio is in per mille. The more executed events a task covers, the more 78 // important a related usability defect. 79 /*if (eventCoverageRatio < 1) { 80 // one per mille, so one of thousand events is covered 81 effectiveRatio *= 0.2; 82 } 83 else if (eventCoverageRatio < 5) { 84 // 5 per mille, so one of 250 events is covered 85 effectiveRatio *= 0.4; 86 } 87 else if (eventCoverageRatio < 10) { 88 // 1 percent, so one of 100 events is covered 89 effectiveRatio *= 0.5; 90 } 91 else if (eventCoverageRatio < 20) { 92 // 2 percent, so one of 50 events is covered 93 effectiveRatio *= 0.6; 94 } 95 else if (eventCoverageRatio < 30) { 96 // 3 percent, so one of 33 events is covered 97 effectiveRatio *= 0.7; 98 } 99 else if (eventCoverageRatio < 40) { 100 // 4 percent, so one of 28 events is covered 101 effectiveRatio *= 0.8; 102 } 103 else if (eventCoverageRatio < 50) { 104 // 5 percent, so one of 25 events is covered 105 effectiveRatio *= 0.9; 106 }*/ 107 //else { 108 // more than 5 percent, so 1 of 20 events, do not change ratio 109 //} 110 if (coverageQuantile >= defaultCoverageQuantile) { 111 if (effectiveRatio >= highRatioLevel) { 112 return UsabilityDefectSeverity.HIGH; 113 } 114 else if (effectiveRatio >= mediumRatioLevel) { 115 return UsabilityDefectSeverity.MEDIUM; 116 } 117 else if (effectiveRatio >= lowRatioLevel) { 118 return UsabilityDefectSeverity.LOW; 119 } 120 else if (effectiveRatio >= infoRatioLevel) { 121 return UsabilityDefectSeverity.INFO; 122 } 123 } 124 125 return null; 126 } 27 127 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationManager.java
r1335 r1493 19 19 import java.util.logging.Level; 20 20 21 import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; 22 import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; 23 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 21 24 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; 22 25 import de.ugoe.cs.util.console.Console; … … 45 48 */ 46 49 private void init() { 47 rules.add(new TextInputStatisticsRule()); 48 rules.add(new RequiredScrollRule()); 50 //rules.add(new TextInputStatisticsRule()); 51 rules.add(new MissingFeedbackRule()); 52 rules.add(new EventCoverageRatioRule()); 53 rules.add(new RequiredInefficientActionsRule()); 54 //rules.add(new TaskCooccurrenceRule()); 55 rules.add(new TargetDistanceRule()); 56 //rules.add(new UnusedGUIElementsRule()); 57 //rules.add(new TaskTreeTestRule()); 49 58 } 50 59 … … 64 73 " usability defects, of which " + result.getSevereDefects().size() + 65 74 " are severe."); 75 76 if ((rule instanceof EventCoverageRatioRule) || 77 (rule instanceof RequiredInefficientActionsRule) || 78 (rule instanceof TargetDistanceRule)) 79 { 80 ITask[] referredTasks = new ITask[result.getAllDefects().size()]; 81 82 for (int i = 0; i < result.getAllDefects().size(); i++) { 83 referredTasks[i] = 84 (ITask) result.getAllDefects().get(i).getDescriptionFragments().get(1); 85 } 86 87 int counter = 0; 88 for (int i = 0; i < referredTasks.length; i++) { 89 for (int j = 0; j < referredTasks.length; j++) { 90 if (isChildOf(referredTasks[i], referredTasks[j])) { 91 counter++; 92 break; 93 } 94 } 95 } 96 97 if (counter > 0) { 98 Console.traceln(Level.INFO, counter + " of the findings are duplicates in " + 99 "that they refer to tasks whose parent tasks are also " + 100 "referred by the findings"); 101 } 102 } 66 103 } 67 104 68 UsabilityEvaluationResult result = new UsabilityEvaluationResult( interimResults);105 UsabilityEvaluationResult result = new UsabilityEvaluationResult(taskModel, interimResults); 69 106 Console.println("the evaluation result contains " + result.getAllDefects().size() + 70 107 " defects, of which " + result.getSevereDefects().size() + " are severe."); 71 72 List<UsabilityDefect> defects = result.getAllDefects();73 for (int i = 0; i < defects.size(); i++) {74 Console.println((i + 1) + ": " + defects.get(i).getParameterizedDescription());75 }76 108 77 109 return result; 78 110 } 79 111 112 /** 113 * <p> 114 * TODO: comment 115 * </p> 116 * 117 * @param iTask 118 * @param iTask2 119 * @return 120 */ 121 private boolean isChildOf(final ITask potChild, ITask potParent) { 122 123 if (potParent instanceof IStructuringTemporalRelationship) { 124 for (ITask child : ((IStructuringTemporalRelationship) potParent).getChildren()) { 125 if ((child == potChild) || isChildOf(potChild, child)) { 126 return true; 127 } 128 } 129 } 130 else if (potParent instanceof IMarkingTemporalRelationship) { 131 ITask child = ((IMarkingTemporalRelationship) potParent).getMarkedTask(); 132 if ((child == potChild) || isChildOf(potChild, child)) { 133 return true; 134 } 135 } 136 137 return false; 138 } 139 80 140 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationResult.java
r1335 r1493 19 19 import java.util.Map; 20 20 21 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; 22 21 23 /** 22 24 * TODO comment … … 28 30 29 31 /** */ 32 private ITaskModel taskModel; 33 34 /** */ 30 35 private List<UsabilityDefect> defects = new ArrayList<UsabilityDefect>(); 31 36 … … 33 38 * 34 39 */ 35 public UsabilityEvaluationResult( ) {36 // default constructor40 public UsabilityEvaluationResult(ITaskModel taskModel) { 41 this.taskModel = taskModel; 37 42 } 38 43 … … 40 45 * 41 46 */ 42 public UsabilityEvaluationResult(List<UsabilityEvaluationResult> results) { 47 public UsabilityEvaluationResult(ITaskModel taskModel, 48 List<UsabilityEvaluationResult> results) 49 { 50 this.taskModel = taskModel; 43 51 for (UsabilityEvaluationResult result : results) { 44 52 for (UsabilityDefect defect : result.getAllDefects()) { … … 53 61 public void addDefect(UsabilityDefectSeverity severity, 54 62 UsabilityDefectDescription description, 55 Map<String, String> parameters)63 Map<String, Object> parameters) 56 64 { 57 65 defects.add(new UsabilityDefect(severity, description, parameters)); … … 80 88 } 81 89 90 /** 91 * @return the taskModel 92 */ 93 public ITaskModel getTaskModel() { 94 return taskModel; 95 } 96 82 97 } -
trunk/autoquest-core-usability/src/main/resources/defectDescriptions.xsd
r442 r1493 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 2 <xsd:schema 3 targetNamespace="http:// quest"4 xmlns:tns="http:// quest"3 targetNamespace="http://autoquest.informatik.uni-goettingen.de" 4 xmlns:tns="http://autoquest.informatik.uni-goettingen.de" 5 5 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 6 6 xmlns:jxb="http://java.sun.com/xml/ns/jaxb" … … 22 22 </xsd:choice> 23 23 <xsd:attribute name="defectId" type="xsd:string" use="required" /> 24 <xsd:attribute name="briefText" type="xsd:string" use="required" /> 24 25 </xsd:complexType> 25 26 -
trunk/autoquest-core-usability/src/main/resources/defectDescriptions_en.xml
r1335 r1493 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 2 <defectDescriptions 3 xmlns="http:// quest"3 xmlns="http://autoquest.informatik.uni-goettingen.de" 4 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http:// questdefectDescriptions.xsd">5 xsi:schemaLocation="http://autoquest.informatik.uni-goettingen.de defectDescriptions.xsd"> 6 6 7 <defectDescription defectId="TEXT_FIELD_INPUT_RATIO" >7 <defectDescription defectId="TEXT_FIELD_INPUT_RATIO" briefText="many text inputs"> 8 8 <textFragment> 9 9 The ratio of interactions that enter text into text fields is relatively high in comparison … … 17 17 </defectDescription> 18 18 19 <defectDescription defectId="TEXT_FIELD_INPUT_REPETITIONS" >19 <defectDescription defectId="TEXT_FIELD_INPUT_REPETITIONS" briefText="many text repetitions"> 20 20 <textFragment> 21 21 In … … 36 36 </defectDescription> 37 37 38 <defectDescription defectId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO" >38 <defectDescription defectId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO" briefText="many special signs"> 39 39 <parameterFragment parameterName="noLetterOrDigitRatio" /> 40 40 <textFragment> … … 50 50 </defectDescription> 51 51 52 <defectDescription defectId="SCROLL_REQUIRED"> 52 <defectDescription defectId="HIGH_EVENT_COVERAGE" briefText="often executed"> 53 <textFragment> 54 The task 55 </textFragment> 56 <parameterFragment parameterName="task" /> 57 <textFragment> 58 covers 59 </textFragment> 60 <parameterFragment parameterName="ratio" /> 61 <textFragment> 62 % of all recorded user actions. Therefore, it should be executed with a high efficiency. 63 You should consider making the task more efficient, by minimizing the number of actions to 64 be executed by users for fulfilling this task. 65 </textFragment> 66 </defectDescription> 67 68 <defectDescription defectId="INEFFICIENT_ACTIONS" briefText="inefficient actions"> 69 <textFragment> 70 For executing task 71 </textFragment> 72 <parameterFragment parameterName="task" /> 73 <textFragment> 74 , the user has to execute a high number of inefficient actions ( 75 </textFragment> 76 <parameterFragment parameterName="ratio" /> 77 <textFragment> 78 % in average). Such actions are, e.g., scrolls. The number of inefficient actions should 79 be as minimal as possible to increase the users efficiency in executing a task. Please 80 check the task structure for occurrences of the following event tasks and consider to prevent 81 them: scrolling. 82 </textFragment> 83 </defectDescription> 84 85 <defectDescription defectId="COOCCURENCE_SUCCEED" briefText="usual cooccurrence"> 53 86 <textFragment> 54 87 In 55 88 </textFragment> 56 <parameterFragment parameterName=" scrollRatio" />89 <parameterFragment parameterName="ratio" /> 57 90 <textFragment> 58 91 % of all occurrences, the task 59 92 </textFragment> 93 <parameterFragment parameterName="task1" /> 94 <textFragment> 95 is succeeded by 96 </textFragment> 97 <parameterFragment parameterName="task2" /> 98 <textFragment> 99 . This shows, that both tasks are likely used in combination. Please consider to support the 100 execution of both tasks in one user action, e.g., by providing an appropriate button, to 101 reduce the number of actions to be performed by the user. 102 </textFragment> 103 </defectDescription> 104 105 <defectDescription defectId="COOCCURENCE_PRECED" briefText="usual cooccurrence"> 106 <textFragment> 107 In 108 </textFragment> 109 <parameterFragment parameterName="ratio" /> 110 <textFragment> 111 % of all occurrences, the task 112 </textFragment> 113 <parameterFragment parameterName="task2" /> 114 <textFragment> 115 is preceded by 116 </textFragment> 117 <parameterFragment parameterName="task1" /> 118 <textFragment> 119 . This shows, that both tasks are likely used in combination. Please consider to support the 120 execution of both tasks in one user action, e.g., by providing an appropriate button, to 121 reduce the number of actions to be performed by the user. 122 </textFragment> 123 </defectDescription> 124 125 <defectDescription defectId="HIGH_TARGET_DISTANCE" briefText="long way to go"> 126 <textFragment> 127 For executing the task 128 </textFragment> 60 129 <parameterFragment parameterName="task" /> 61 130 <textFragment> 62 is started with a scroll. This should be prevented as scrolling decreases the efficiency of 63 the user and indicates, that not all required information is visible at once in the 64 respective view. However, scrolling for reading of texts is no problem. 131 , the user utilizes 132 </textFragment> 133 <parameterFragment parameterName="noOfGUIElements" /> 134 <textFragment> 135 GUI elements on average. As these GUI elements have a high distance to each other ( 136 </textFragment> 137 <parameterFragment parameterName="distance" /> 138 <textFragment> 139 on average ), they should be more colocated to ease the execution of the task for the user. 65 140 </textFragment> 66 141 </defectDescription> 142 143 <defectDescription defectId="MISSING_FEEDBACK" briefText="missing feedback"> 144 <textFragment> 145 A click on the button 146 </textFragment> 147 <parameterFragment parameterName="button" /> 148 <textFragment> 149 seems to be missing user feedback. In 150 </textFragment> 151 <parameterFragment parameterName="multipleClickCount" /> 152 <textFragment> 153 of 154 </textFragment> 155 <parameterFragment parameterName="allClickCount" /> 156 <textFragment> 157 uses, the button was clicked several times. The average waiting time between two subsequent 158 clicks is 159 </textFragment> 160 <parameterFragment parameterName="averageWaitingTime" /> 161 <textFragment> 162 seconds. This is typical user behavior if the user does not see progress following his 163 actions. Please consider showing the user some progress after he performed the 164 first click. This is especially important if the operation triggered with the click usually 165 takes longer than one second. This defect was observed based on task 166 </textFragment> 167 <parameterFragment parameterName="task" /> 168 <textFragment> 169 . 170 </textFragment> 171 </defectDescription> 172 173 <defectDescription defectId="UNUSED_GUI_ELEMENTS" briefText="unused GUI elements"> 174 <parameterFragment parameterName="ratio" /> 175 <textFragment> 176 % of the GUI elements ( 177 </textFragment> 178 <parameterFragment parameterName="noOfUnused" /> 179 <textFragment> 180 of 181 </textFragment> 182 <parameterFragment parameterName="noOfAll" /> 183 <textFragment> 184 ) are not used. This can have several reasons. Either they are not 185 visible to the user or they are not required. If they are important, they may not be 186 recognized by the user. This can be caused by visual design or because they are too hidden. 187 If they are less important, they can either be removed from the GUI or relocated to a less 188 prominent position. The unused GUI elements are: 189 </textFragment> 190 <parameterFragment parameterName="unusedGuiElements" /> 191 </defectDescription> 67 192 </defectDescriptions>
Note: See TracChangeset
for help on using the changeset viewer.