Changeset 1918 for trunk/autoquest-core-usability/src
- Timestamp:
- 03/12/15 15:50:28 (10 years ago)
- Location:
- trunk/autoquest-core-usability/src/main
- Files:
-
- 7 added
- 11 edited
- 5 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageQuantileRule.java
r1493 r1918 57 57 58 58 //TODO document magic numbers 59 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity60 (ratio, 990, 975, 950, 900, sequence, taskModel);59 UsabilitySmellIntensity severity = 60 UsabilitySmellIntensity.getIntensity(ratio, sequence, taskModel); 61 61 62 62 if (severity != null) { … … 81 81 parameters.put("ratio", effRatio); 82 82 83 results.add Defect(severity, UsabilityDefectDescription.HIGH_EVENT_COVERAGE,84 parameters);83 results.addSmell(sequence, severity, 84 UsabilitySmellDescription.HIGH_EVENT_COVERAGE, parameters); 85 85 } 86 86 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/EventCoverageRatioRule.java
r1493 r1918 56 56 (TaskMetric.EVENT_COVERAGE_RATIO); 57 57 58 //TODO document magic numbers 59 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 60 (ratio, 300, 150, 50, 10, sequence, taskModel); 58 UsabilitySmellIntensity severity = 59 UsabilitySmellIntensity.getIntensity(ratio, sequence, taskModel); 61 60 62 61 if (severity != null) { … … 65 64 parameters.put("ratio", (ratio / 10)); 66 65 67 results.add Defect(severity, UsabilityDefectDescription.HIGH_EVENT_COVERAGE,68 parameters);66 results.addSmell(sequence, severity, 67 UsabilitySmellDescription.HIGH_EVENT_COVERAGE, parameters); 69 68 } 70 69 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/MissingFeedbackRule.java
r1493 r1918 78 78 // be considered as usability smell. 79 79 80 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity81 (entry.getValue(), 2000, 1000, 500, 50, entry.getKey(), taskModel);82 83 if ( severity != null) {80 UsabilitySmellIntensity intensity = 81 UsabilitySmellIntensity.getIntensity(entry.getValue(), entry.getKey(), taskModel); 82 83 if (intensity != null) { 84 84 Map<String, Object> parameters = new HashMap<String, Object>(); 85 85 … … 88 88 long cummulatedWaitingTime = 0; 89 89 int numberOfAdditionalClicks = 0; 90 91 System.out.println("\n\n#################################");92 90 93 91 Event exampleEvent = null; … … 101 99 for (List<Event> subsequence : clicksOnIdenticalButton) { 102 100 exampleEvent = subsequence.get(0); 103 System.out.println(exampleEvent.getTimestamp());104 101 105 102 Event endEvent = subsequence.get(subsequence.size() - 1); … … 123 120 parameters.put("task", entry.getKey()); 124 121 125 results.add Defect126 (severity, UsabilityDefectDescription.MISSING_FEEDBACK, parameters);122 results.addSmell(entry.getKey(), intensity, 123 UsabilitySmellDescription.MISSING_FEEDBACK, parameters); 127 124 } 128 125 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/RequiredInefficientActionsRule.java
r1493 r1918 67 67 int ratio = (int) (1000 * stats.getMean()); 68 68 69 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity70 (ratio, 500, 300, 200, 100, entry.getKey(), taskModel);69 UsabilitySmellIntensity severity = 70 UsabilitySmellIntensity.getIntensity(ratio, entry.getKey(), taskModel); 71 71 72 72 if (severity != null) { … … 75 75 parameters.put("ratio", (ratio / 10)); 76 76 77 results.add Defect78 (severity, UsabilityDefectDescription.INEFFICIENT_ACTIONS, parameters);77 results.addSmell(entry.getKey(), severity, 78 UsabilitySmellDescription.INEFFICIENT_ACTIONS, parameters); 79 79 } 80 80 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TargetDistanceRule.java
r1493 r1918 136 136 // for HTML: 600 means not on the same page 137 137 // for HTML: 501 means in average not on the same page 138 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity139 (ratio, 800, 600, 501, 501, task, taskModel);138 UsabilitySmellIntensity severity = 139 UsabilitySmellIntensity.getIntensity(ratio, task, taskModel); 140 140 141 141 if (severity != null) { … … 148 148 parameters.put("distance", ((double) ratio / 1000)); 149 149 150 results.add Defect151 ( severity, UsabilityDefectDescription.HIGH_TARGET_DISTANCE, parameters);150 results.addSmell 151 (task, severity, UsabilitySmellDescription.HIGH_TARGET_DISTANCE, parameters); 152 152 } 153 153 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskCooccurrenceRule.java
r1493 r1918 62 62 int index2 = 1; 63 63 List<ITask> children = sequence.getChildren(); 64 ITaskInfo infoSequence = taskModel.getTaskInfo(sequence); 65 int countSequence = infoSequence.getMeasureValue(TaskMetric.COUNT); 64 66 65 67 while (index2 < children.size()) { … … 69 71 ITaskInfo info2 = taskModel.getTaskInfo(task2); 70 72 71 int ratioTask1 = 1000 * info1.getMeasureValue(TaskMetric.COUNT, sequence) / 72 info1.getMeasureValue(TaskMetric.COUNT); 73 int ratioTask2 = 1000 * info2.getMeasureValue(TaskMetric.COUNT, sequence) / 74 info2.getMeasureValue(TaskMetric.COUNT); 73 int ratioTask1 = 1000 * countSequence / info1.getMeasureValue(TaskMetric.COUNT); 74 int ratioTask2 = 1000 * countSequence / info2.getMeasureValue(TaskMetric.COUNT); 75 75 76 createSucceeded DefectIfRequired(ratioTask1, task1, task2, results, taskModel);77 createPreceded DefectIfRequired(ratioTask2, task1, task2, results, taskModel);76 createSucceededSmellIfRequired(ratioTask1, task1, task2, results, taskModel); 77 createPrecededSmellIfRequired(ratioTask2, task1, task2, results, taskModel); 78 78 79 79 index1 = index2; … … 87 87 * 88 88 */ 89 private void createSucceeded DefectIfRequired(int ratio,90 91 92 93 89 private void createSucceededSmellIfRequired(int ratio, 90 ITask task1, 91 ITask task2, 92 UsabilityEvaluationResult results, 93 ITaskModel taskModel) 94 94 { 95 95 //TODO document magic numbers 96 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity97 (ratio, 900, 700, 500, 300, task1, taskModel);96 UsabilitySmellIntensity severity = 97 UsabilitySmellIntensity.getIntensity(ratio, task1, taskModel); 98 98 99 99 if (!isScroll(task1) && !isScroll(task2) && (severity != null)) { … … 103 103 parameters.put("ratio", (ratio / 10)); 104 104 105 results.addDefect(severity, UsabilityDefectDescription.COOCCURENCE_SUCCEED, parameters); 105 results.addSmell 106 (task1, severity, UsabilitySmellDescription.COOCCURENCE_SUCCEED, parameters); 106 107 } 107 108 } … … 110 111 * 111 112 */ 112 private void createPreceded DefectIfRequired(int ratio,113 114 115 116 113 private void createPrecededSmellIfRequired(int ratio, 114 ITask task1, 115 ITask task2, 116 UsabilityEvaluationResult results, 117 ITaskModel taskModel) 117 118 { 118 119 //TODO document magic numbers 119 Usability DefectSeverity severity = UsabilityDefectSeverity.getSeverity120 (ratio, 900, 700, 500, 300, task2, taskModel);120 UsabilitySmellIntensity severity = 121 UsabilitySmellIntensity.getIntensity(ratio, task2, taskModel); 121 122 122 123 if (!isScroll(task1) && !isScroll(task2) && (severity != null)) { … … 126 127 parameters.put("ratio", (ratio / 10)); 127 128 128 results.addDefect(severity, UsabilityDefectDescription.COOCCURENCE_PRECED, parameters); 129 results.addSmell 130 (task1, severity, UsabilitySmellDescription.COOCCURENCE_PRECED, parameters); 129 131 } 130 132 } … … 140 142 private boolean isScroll(ITask task) { 141 143 if (task instanceof IEventTask) { 142 return ((IEventTaskInstance) ((IEventTask) task).getInstances().iterator().next()).getEvent().getType() instanceof Scroll; 144 return ((IEventTaskInstance) ((IEventTask) task).getInstances().iterator().next()) 145 .getEvent().getType() instanceof Scroll; 143 146 } 144 147 else if (task instanceof IIteration) { -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TaskTreeTestRule.java
r1493 r1918 15 15 package de.ugoe.cs.autoquest.usability; 16 16 17 import java.util.ArrayList; 18 import java.util.HashSet; 19 import java.util.List; 20 import java.util.Set; 21 17 22 import de.ugoe.cs.autoquest.eventcore.Event; 18 23 import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor; 24 import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor; 25 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; 19 26 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; 27 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; 28 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; 29 import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; 30 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 31 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo; 20 32 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; 21 33 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceVisitor; … … 41 53 42 54 checkTimestamps(taskModel); 55 checkTaskInfos(taskModel); 56 checkEventTaskInstances(taskModel); 57 checkTraversal(taskModel); 43 58 44 59 return results; 60 } 61 62 /** 63 * <p> 64 * TODO: comment 65 * </p> 66 * 67 * @param taskModel 68 */ 69 private void checkEventTaskInstances(ITaskModel taskModel) { 70 Set<IEventTaskInstance> instancesInModel = new HashSet<>(); 71 72 for (ITask task : taskModel.getTasks()) { 73 if (task instanceof IEventTask) { 74 for (ITaskInstance instance : task.getInstances()) { 75 instancesInModel.add((IEventTaskInstance) instance); 76 } 77 } 78 } 79 80 final Set<IEventTaskInstance> instancesInSessions = new HashSet<>(); 81 82 for (IUserSession session : taskModel.getUserSessions()) { 83 for (ITaskInstance rootInstance : session) { 84 rootInstance.accept(new DefaultTaskInstanceTraversingVisitor() { 85 @Override 86 public void visit(IEventTaskInstance eventTaskInstance) { 87 instancesInSessions.add(eventTaskInstance); 88 } 89 }); 90 } 91 } 92 93 if (instancesInModel.size() != instancesInSessions.size()) { 94 throw new RuntimeException("instances not equal"); 95 } 96 else { 97 for (IEventTaskInstance instance : instancesInModel) { 98 if (!instancesInSessions.contains(instance)) { 99 throw new RuntimeException("instance of model not contained in sessions"); 100 } 101 } 102 103 for (IEventTaskInstance instance : instancesInSessions) { 104 if (!instancesInModel.contains(instance)) { 105 throw new RuntimeException("instance of sessions not contained in model"); 106 } 107 } 108 } 109 } 110 111 /** 112 * <p> 113 * TODO: comment 114 * </p> 115 * 116 * @param taskModel 117 */ 118 private void checkTraversal(ITaskModel taskModel) { 119 for (ITask task : taskModel.getTasks()) { 120 final List<ITask> traversal1 = new ArrayList<>(); 121 122 task.accept(new DefaultTaskTraversingVisitor() { 123 @Override 124 public void visit(IEventTask eventTask) { 125 traversal1.add(eventTask); 126 super.visit(eventTask); 127 } 128 129 @Override 130 public void visit(IStructuringTemporalRelationship relationship) { 131 traversal1.add(relationship); 132 super.visit(relationship); 133 } 134 135 }); 136 137 final List<ITask> traversal2 = new ArrayList<>(); 138 139 task.accept(new DefaultTaskTraversingVisitor() { 140 @Override 141 public void visit(IEventTask eventTask) { 142 traversal2.add(eventTask); 143 super.visit(eventTask); 144 } 145 146 @Override 147 public void visit(ISelection selection) { 148 traversal2.add(selection); 149 super.visit(selection); 150 } 151 152 @Override 153 public void visit(ISequence sequence) { 154 traversal2.add(sequence); 155 super.visit(sequence); 156 } 157 }); 158 159 if (traversal1.size() != traversal2.size()) { 160 throw new RuntimeException("traversals not equal"); 161 } 162 else { 163 for (int i = 0; i < traversal1.size(); i++) { 164 if (!traversal1.get(i).equals(traversal2.get(i))) { 165 throw new RuntimeException("traversals not equal at position " + i); 166 } 167 } 168 } 169 } 45 170 } 46 171 … … 78 203 79 204 } 205 206 /** 207 * <p> 208 * TODO: comment 209 * </p> 210 * 211 * @param taskModel 212 */ 213 private void checkTaskInfos(ITaskModel taskModel) { 214 for (ITask task : taskModel.getTasks()) { 215 ITaskInfo taskInfo = taskModel.getTaskInfo(task); 216 if (taskInfo == null) { 217 System.out.println("task " + task + " has no associated task infos"); 218 } 219 } 220 } 80 221 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/TextInputStatisticsRule.java
r1493 r1918 84 84 int ratio = 1000 * allTextFieldInputs / statistics.getNoOfAllEvents(); 85 85 86 // TODO comment magic numbers 87 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 88 (ratio, 900, 700, 500, 300); 86 UsabilitySmellIntensity severity = UsabilitySmellIntensity.getIntensity(ratio); 89 87 90 88 if (severity != null) { … … 92 90 parameters.put("textInputRatio", (ratio / 10)); 93 91 94 results.add Defect95 (severity, Usability DefectDescription.TEXT_FIELD_INPUT_RATIO, parameters);92 results.addSmell 93 (severity, UsabilitySmellDescription.TEXT_FIELD_INPUT_RATIO, parameters); 96 94 } 97 95 } … … 117 115 1000 * noOfUsagesOfTextField1WithSameTextInTextField2 / noOfUsagesOfTextField2; 118 116 119 createTextFieldEntryRepetition Defect(ratioTextField1, entry.textField1,117 createTextFieldEntryRepetitionSmell(ratioTextField1, entry.textField1, 120 118 entry.textField2, results); 121 119 122 createTextFieldEntryRepetition Defect(ratioTextField2, entry.textField2,120 createTextFieldEntryRepetitionSmell(ratioTextField2, entry.textField2, 123 121 entry.textField1, results); 124 122 … … 129 127 * 130 128 */ 131 private void createTextFieldEntryRepetition Defect(int ratioOfEqualEntries,129 private void createTextFieldEntryRepetitionSmell(int ratioOfEqualEntries, 132 130 ITextField textField1, 133 131 ITextField textField2, 134 132 UsabilityEvaluationResult results) 135 133 { 136 // TODO comment magic numbers 137 UsabilityDefectSeverity severity = UsabilityDefectSeverity.getSeverity 138 (ratioOfEqualEntries, 900, 500, 200, 100); 134 UsabilitySmellIntensity severity = 135 UsabilitySmellIntensity.getIntensity(ratioOfEqualEntries); 139 136 140 137 if (severity != null) { … … 144 141 parameters.put("textField2", textField2); 145 142 146 results.add Defect147 (severity, Usability DefectDescription.TEXT_FIELD_INPUT_REPETITIONS, parameters);143 results.addSmell 144 (severity, UsabilitySmellDescription.TEXT_FIELD_INPUT_REPETITIONS, parameters); 148 145 } 149 146 } … … 172 169 int ratio = 1000 * noLetterOrDigitCount / allCharactersCount; 173 170 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 ); 171 UsabilitySmellIntensity severity = UsabilitySmellIntensity.getIntensity(ratio); 181 172 182 173 if (severity != null) { … … 185 176 parameters.put("noLetterOrDigitRatio", (ratio / 10)); 186 177 187 results.add Defect188 (severity, Usability DefectDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO,178 results.addSmell 179 (severity, UsabilitySmellDescription.TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO, 189 180 parameters); 190 181 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UnusedGUIElementsRule.java
r1493 r1918 78 78 int ratio = 1000 * unusedGUIElements.size() / allGUIElements.size(); 79 79 80 UsabilityDefectSeverity severity = 81 UsabilityDefectSeverity.getSeverity(ratio, 200, 100, 50, 25); 80 UsabilitySmellIntensity severity = UsabilitySmellIntensity.getIntensity(ratio); 82 81 83 82 if (severity != null) { … … 89 88 parameters.put("unusedGuiElements", unusedGUIElements); 90 89 91 results.add Defect92 (severity, Usability DefectDescription.UNUSED_GUI_ELEMENTS, parameters);90 results.addSmell 91 (severity, UsabilitySmellDescription.UNUSED_GUI_ELEMENTS, parameters); 93 92 } 94 93 } -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationManager.java
r1493 r1918 48 48 */ 49 49 private void init() { 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()); 50 rules.add(new TaskTreeTestRule()); 51 // rules.add(new TextInputStatisticsRule()); 52 // rules.add(new MissingFeedbackRule()); 53 // rules.add(new EventCoverageRatioRule()); 54 // rules.add(new TargetDistanceRule()); 55 // rules.add(new RequiredInefficientActionsRule()); 56 // rules.add(new DataEntryMethodChangeRule()); 57 rules.add(new DefaultValueRule()); 58 // rules.add(new CheckBoxMultipleSelectionRule()); 59 // rules.add(new CommonTaskRateRule()); 60 // rules.add(new MisleadingClickCueRule()); 61 // rules.add(new DefaultCursorPositioningRule()); 62 // rules.add(new UnusedGUIElementsRule()); 63 // rules.add(new TaskCooccurrenceRule()); 58 64 } 59 65 … … 70 76 UsabilityEvaluationResult result = rule.evaluate(taskModel); 71 77 interimResults.add(result); 72 Console.traceln(Level.INFO, "the rule found " + result.getAllDefects().size() + 73 " usability defects, of which " + result.getSevereDefects().size() + 74 " are severe."); 78 Console.traceln(Level.INFO, "the rule found " + result.getAllSmells().size() + 79 " usability smells."); 75 80 76 if ((rule instanceof EventCoverageRatioRule) || 77 (rule instanceof RequiredInefficientActionsRule) || 78 (rule instanceof TargetDistanceRule)) 79 { 80 ITask[] referredTasks = new ITask[result.getAllDefects().size()]; 81 List<ITask> referredTasks = new ArrayList<ITask>(); 81 82 82 for (int i = 0; i < result.getAllDefects().size(); i++) {83 referredTasks[i] =84 (ITask) result.getAllDefects().get(i).getDescriptionFragments().get(1);83 for (UsabilitySmell smell : result.getAllSmells()) { 84 if (smell.getSmellingTask() != null) { 85 referredTasks.add(smell.getSmellingTask()); 85 86 } 87 } 86 88 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 } 89 int counter = 0; 90 for (int i = 0; i < referredTasks.size(); i++) { 91 for (int j = 0; j < referredTasks.size(); j++) { 92 if (isChildOf(referredTasks.get(i), referredTasks.get(j))) { 93 counter++; 94 break; 94 95 } 95 96 } 97 } 96 98 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 } 99 if (counter > 0) { 100 Console.traceln(Level.INFO, counter + " of the findings are duplicates in " + 101 "that they refer to tasks whose parent tasks are also " + 102 "referred by the findings"); 102 103 } 103 104 } 104 105 105 106 UsabilityEvaluationResult result = new UsabilityEvaluationResult(taskModel, interimResults); 106 Console.println("the evaluation result contains " + result.getAll Defects().size() +107 " defects, of which " + result.getSevereDefects().size() + " are severe.");107 Console.println("the evaluation result contains " + result.getAllSmells().size() + 108 " smells."); 108 109 109 110 return result; -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilityEvaluationResult.java
r1493 r1918 19 19 import java.util.Map; 20 20 21 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 21 22 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; 22 23 … … 33 34 34 35 /** */ 35 private List<Usability Defect> defects = new ArrayList<UsabilityDefect>();36 private List<UsabilitySmell> smells = new ArrayList<UsabilitySmell>(); 36 37 37 38 /** … … 50 51 this.taskModel = taskModel; 51 52 for (UsabilityEvaluationResult result : results) { 52 for (Usability Defect defect : result.getAllDefects()) {53 defects.add(defect);53 for (UsabilitySmell smell : result.getAllSmells()) { 54 smells.add(smell); 54 55 } 55 56 } … … 59 60 * 60 61 */ 61 public void add Defect(UsabilityDefectSeverity severity,62 UsabilityDefectDescription description,63 Map<String, Object>parameters)62 public void addSmell(UsabilitySmellIntensity intensity, 63 UsabilitySmellDescription description, 64 Map<String, Object> parameters) 64 65 { 65 defects.add(new UsabilityDefect(severity, description, parameters));66 addSmell(null, intensity, description, parameters); 66 67 } 67 68 … … 69 70 * 70 71 */ 71 public List<UsabilityDefect> getAllDefects() { 72 return defects; 72 public void addSmell(ITask smellingTask, 73 UsabilitySmellIntensity intensity, 74 UsabilitySmellDescription description, 75 Map<String, Object> parameters) 76 { 77 smells.add(new UsabilitySmell(smellingTask, intensity, description, parameters)); 73 78 } 74 79 … … 76 81 * 77 82 */ 78 public List<UsabilityDefect> getSevereDefects() { 79 List<UsabilityDefect> severeDefects = new ArrayList<UsabilityDefect>(); 80 81 for (UsabilityDefect defect : defects) { 82 if (defect.getSeverity() == UsabilityDefectSeverity.HIGH) { 83 severeDefects.add(defect); 84 } 85 } 86 87 return severeDefects; 83 public List<UsabilitySmell> getAllSmells() { 84 return smells; 88 85 } 89 86 -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilitySmell.java
r1493 r1918 18 18 import java.util.Map; 19 19 20 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 21 20 22 /** 21 23 * TODO comment … … 24 26 * @author 2012, last modified by $Author: pharms$ 25 27 */ 26 public class Usability Defect{28 public class UsabilitySmell { 27 29 28 30 /** */ 29 private UsabilityDefectSeverity severity; 31 private ITask smellingTask; 32 33 /** */ 34 private UsabilitySmellIntensity intensity; 30 35 31 36 /** */ 32 private Usability DefectDescription description;37 private UsabilitySmellDescription description; 33 38 34 39 /** */ … … 38 43 * 39 44 */ 40 UsabilityDefect(UsabilityDefectSeverity severity, UsabilityDefectDescription description) { 41 this(severity, description, null); 45 UsabilitySmell(UsabilitySmellIntensity intensity, UsabilitySmellDescription description) { 46 this(intensity, description, null); 47 } 48 49 /** 50 * 51 */ 52 UsabilitySmell(ITask smellingTask, 53 UsabilitySmellIntensity intensity, 54 UsabilitySmellDescription description) 55 { 56 this(intensity, description, null); 42 57 } 43 58 … … 45 60 * 46 61 */ 47 Usability Defect(UsabilityDefectSeverity severity,48 UsabilityDefectDescription description,49 Map<String, Object>parameters)62 UsabilitySmell(UsabilitySmellIntensity intensity, 63 UsabilitySmellDescription description, 64 Map<String, Object> parameters) 50 65 { 51 this.severity = severity; 66 this(null, intensity, description, parameters); 67 } 68 69 /** 70 * 71 */ 72 UsabilitySmell(ITask smellingTask, 73 UsabilitySmellIntensity intensity, 74 UsabilitySmellDescription description, 75 Map<String, Object> parameters) 76 { 77 this.smellingTask = smellingTask; 78 this.intensity = intensity; 52 79 this.description = description; 53 80 this.descriptionParameters = parameters; … … 57 84 * 58 85 */ 59 public UsabilityDefectSeverity getSeverity() { 60 return severity; 86 public ITask getSmellingTask() { 87 return smellingTask; 88 } 89 90 /** 91 * 92 */ 93 public UsabilitySmellIntensity getIntensity() { 94 return intensity; 61 95 } 62 96 … … 64 98 * 65 99 */ 66 public void set Severity(UsabilityDefectSeverity severity) {67 this. severity = severity;100 public void setIntensity(UsabilitySmellIntensity intensity) { 101 this.intensity = intensity; 68 102 } 69 103 … … 71 105 * 72 106 */ 73 public void setDescription(Usability DefectDescription description) {107 public void setDescription(UsabilitySmellDescription description) { 74 108 this.description = description; 75 109 } … … 102 136 @Override 103 137 public boolean equals(Object obj) { 104 if (obj instanceof UsabilityDefect) { 105 return 106 (severity == ((UsabilityDefect) obj).severity) && 107 (description == ((UsabilityDefect) obj).description); 138 if (obj instanceof UsabilitySmell) { 139 return description.equals(((UsabilitySmell) obj).description); 108 140 } 109 141 else { … … 119 151 @Override 120 152 public int hashCode() { 121 return severity.hashCode() +description.hashCode();153 return description.hashCode(); 122 154 } 123 155 … … 129 161 @Override 130 162 public String toString() { 131 return "UsabilityDefect(" + severity.name() + ", " + description.name() + ")"; 163 if (smellingTask == null) { 164 return "UsabilitySmell(" + intensity + ", " + description.name() + ")"; 165 } 166 else { 167 return "UsabilitySmell(" + smellingTask + ", " + intensity + ", " + 168 description.name() + ")"; 169 } 132 170 } 133 171 -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilitySmellDescription.java
r1493 r1918 32 32 * @author 2012, last modified by $Author: pharms$ 33 33 */ 34 public enum Usability DefectDescription {34 public enum UsabilitySmellDescription { 35 35 36 36 INEFFICIENT_ACTIONS, … … 43 43 HIGH_TARGET_DISTANCE, 44 44 MISSING_FEEDBACK, 45 UNUSED_GUI_ELEMENTS; 45 UNUSED_GUI_ELEMENTS, 46 DATA_ENTRY_METHOD_CHANGE, 47 GOOD_DEFAULTS, 48 CHECK_BOX_SINGLE_SELECTION, 49 COMMON_TASK_RATE, 50 MISLEADING_CLICK_CUE, 51 MOST_OFTEN_DONE_FIRST; 46 52 47 53 /** */ 48 private static final String DEFAULT_MESSAGES_FILE = " defectDescriptions_en.xml";54 private static final String DEFAULT_MESSAGES_FILE = "smellDescriptions_en.xml"; 49 55 50 56 /** */ 51 private static DefectDescriptions sDefectDescriptions;57 private static SmellDescriptions sSmellDescriptions; 52 58 53 59 /** */ 54 private DefectDescription defectDescription;60 private SmellDescription smellDescription; 55 61 56 62 /** 57 63 * 58 64 */ 59 private Usability DefectDescription() {65 private UsabilitySmellDescription() { 60 66 init(); 61 67 } … … 67 73 private void init() { 68 74 synchronized (this.getClass()) { 69 if (s DefectDescriptions == null) {75 if (sSmellDescriptions == null) { 70 76 InputStream inputStream = 71 77 ClassLoader.getSystemResourceAsStream(DEFAULT_MESSAGES_FILE); 72 78 73 79 try { 74 String packageName = DefectDescriptions.class.getPackage().getName();80 String packageName = SmellDescriptions.class.getPackage().getName(); 75 81 JAXBContext jaxbContext = JAXBContext.newInstance(packageName); 76 82 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 77 83 78 s DefectDescriptions =79 ((JAXBElement< DefectDescriptions>) unmarshaller.unmarshal(inputStream))84 sSmellDescriptions = 85 ((JAXBElement<SmellDescriptions>) unmarshaller.unmarshal(inputStream)) 80 86 .getValue(); 81 87 } 82 88 catch (Exception e) { 83 89 throw new RuntimeException 84 ("error while initializing usability defectdescriptions", e);90 ("error while initializing usability smell descriptions", e); 85 91 } 86 92 finally { … … 97 103 } 98 104 99 for ( DefectDescription description : sDefectDescriptions.getDefectDescription()) {100 if (this.name().equals(description.get DefectId())) {101 defectDescription = description;105 for (SmellDescription description : sSmellDescriptions.getSmellDescription()) { 106 if (this.name().equals(description.getSmellId())) { 107 smellDescription = description; 102 108 break; 103 109 } 104 110 } 105 111 106 if ( defectDescription == null) {112 if (smellDescription == null) { 107 113 throw new RuntimeException 108 ("error while initializing usability defectdescriptions. No " +114 ("error while initializing usability smell descriptions. No " + 109 115 "description text available for description " + this.name()); 110 116 } … … 117 123 List<String> parameters = new ArrayList<String>(); 118 124 119 for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {125 for (Object fragment : smellDescription.getTextFragmentOrParameterFragment()) { 120 126 if (fragment instanceof ParameterFragment) { 121 127 parameters.add(((ParameterFragment) fragment).getParameterName()); … … 132 138 StringBuffer result = new StringBuffer(); 133 139 134 for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {140 for (Object fragment : smellDescription.getTextFragmentOrParameterFragment()) { 135 141 if (result.length() > 0) { 136 142 result.append(" "); … … 161 167 ("required parameter \"" + 162 168 ((ParameterFragment) fragment).getParameterName() + 163 "\" for usability defectdescription " + this.name() + " not provided");169 "\" for usability smell description " + this.name() + " not provided"); 164 170 } 165 171 } … … 180 186 List<Object> result = new ArrayList<Object>(); 181 187 182 for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {188 for (Object fragment : smellDescription.getTextFragmentOrParameterFragment()) { 183 189 if (fragment instanceof ParameterFragment) { 184 190 Object value = null; … … 194 200 ("required parameter \"" + 195 201 ((ParameterFragment) fragment).getParameterName() + 196 "\" for usability defectdescription " + this.name() + " not provided");202 "\" for usability smell description " + this.name() + " not provided"); 197 203 } 198 204 } … … 209 215 */ 210 216 public String getBriefDescription() { 211 return defectDescription.briefText;217 return smellDescription.briefText; 212 218 } 213 219 … … 222 228 223 229 int paramCount = 1; 224 for (Object fragment : defectDescription.getTextFragmentOrParameterFragment()) {230 for (Object fragment : smellDescription.getTextFragmentOrParameterFragment()) { 225 231 if (result.length() > 0) { 226 232 result.append(" "); -
trunk/autoquest-core-usability/src/main/java/de/ugoe/cs/autoquest/usability/UsabilitySmellIntensity.java
r1493 r1918 26 26 * @author 2012, last modified by $Author: pharms$ 27 27 */ 28 public enum UsabilityDefectSeverity { 29 30 INFO, LOW, MEDIUM, HIGH; 28 public class UsabilitySmellIntensity { 31 29 32 30 /** */ 33 static int defaultCoverageQuantile = 950; 31 private int ratio; 32 33 /** */ 34 private int eventCoverage; 35 36 /** */ 37 private int eventCoverageQuantile; 34 38 35 39 /** 36 40 * 37 41 */ 38 static UsabilityDefectSeverity getSeverity(int ratio, 39 int highRatioLevel, 40 int mediumRatioLevel, 41 int lowRatioLevel, 42 int infoRatioLevel) 42 static UsabilitySmellIntensity getIntensity(int ratio, 43 ITask taskWithSmell, 44 ITaskModel wholeTaskModel) 43 45 { 44 return getSeverity(ratio, highRatioLevel, mediumRatioLevel, lowRatioLevel, infoRatioLevel, 45 defaultCoverageQuantile); 46 ITaskInfo taskInfo = wholeTaskModel.getTaskInfo(taskWithSmell); 47 int eventCoverage = taskInfo.getMeasureValue(TaskMetric.EVENT_COVERAGE); 48 int eventCoverageQuantile = taskInfo.getMeasureValue(TaskMetric.EVENT_COVERAGE_QUANTILE); 49 return getIntensity(ratio, eventCoverage, eventCoverageQuantile); 46 50 } 47 51 … … 49 53 * 50 54 */ 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); 55 static UsabilitySmellIntensity getIntensity(int ratio) { 56 return getIntensity(ratio, -1, -1); 63 57 } 64 58 … … 66 60 * 67 61 */ 68 static UsabilityDefectSeverity getSeverity(int ratio, 69 int highRatioLevel, 70 int mediumRatioLevel, 71 int lowRatioLevel, 72 int infoRatioLevel, 73 int coverageQuantile) 62 static UsabilitySmellIntensity getIntensity(int ratio, 63 int eventCoverage, 64 int eventCoverageQuantile) 74 65 { 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; 66 if ((ratio > 0) && ((eventCoverageQuantile == -1) || (eventCoverageQuantile > 0))) { 67 return new UsabilitySmellIntensity(ratio, eventCoverage, eventCoverageQuantile); 82 68 } 83 else if (eventCoverageRatio < 5) { 84 // 5 per mille, so one of 250 events is covered 85 effectiveRatio *= 0.4; 69 else { 70 return null; 86 71 } 87 else if (eventCoverageRatio < 10) {88 // 1 percent, so one of 100 events is covered89 effectiveRatio *= 0.5;90 }91 else if (eventCoverageRatio < 20) {92 // 2 percent, so one of 50 events is covered93 effectiveRatio *= 0.6;94 }95 else if (eventCoverageRatio < 30) {96 // 3 percent, so one of 33 events is covered97 effectiveRatio *= 0.7;98 }99 else if (eventCoverageRatio < 40) {100 // 4 percent, so one of 28 events is covered101 effectiveRatio *= 0.8;102 }103 else if (eventCoverageRatio < 50) {104 // 5 percent, so one of 25 events is covered105 effectiveRatio *= 0.9;106 }*/107 //else {108 // more than 5 percent, so 1 of 20 events, do not change ratio109 //}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 72 } 73 74 /** 75 * <p> 76 * TODO: comment 77 * </p> 78 * 79 * @param ratio 80 * @param eventCoverage 81 * @param eventCoverageQuantile 82 */ 83 private UsabilitySmellIntensity(int ratio, int eventCoverage, int eventCoverageQuantile) { 84 super(); 85 this.ratio = ratio; 86 this.eventCoverage = eventCoverage; 87 this.eventCoverageQuantile = eventCoverageQuantile; 88 } 89 90 /** 91 * @return the ratio 92 */ 93 public int getRatio() { 94 return ratio; 95 } 96 97 /** 98 * @return the eventCoverage 99 */ 100 public int getEventCoverage() { 101 return eventCoverage; 102 } 103 104 /** 105 * @return the eventCoverageQuantile 106 */ 107 public int getEventCoverageQuantile() { 108 return eventCoverageQuantile; 109 } 110 111 /* (non-Javadoc) 112 * @see java.lang.Object#toString() 113 */ 114 @Override 115 public String toString() { 116 return Integer.toString(ratio); 117 } 118 127 119 } -
trunk/autoquest-core-usability/src/main/resources/smellDescriptions.xsd
r1493 r1918 8 8 elementFormDefault="qualified"> 9 9 10 <xsd:element name=" defectDescriptions" type="tns:DefectDescriptions" />10 <xsd:element name="smellDescriptions" type="tns:SmellDescriptions" /> 11 11 12 <xsd:complexType name=" DefectDescriptions">12 <xsd:complexType name="SmellDescriptions"> 13 13 <xsd:sequence> 14 <xsd:element name=" defectDescription" type="tns:DefectDescription" maxOccurs="unbounded" />14 <xsd:element name="smellDescription" type="tns:SmellDescription" maxOccurs="unbounded" /> 15 15 </xsd:sequence> 16 16 </xsd:complexType> 17 17 18 <xsd:complexType name=" DefectDescription">18 <xsd:complexType name="SmellDescription"> 19 19 <xsd:choice maxOccurs="unbounded"> 20 20 <xsd:element name="textFragment" type="tns:SimpleFragment" /> 21 21 <xsd:element name="parameterFragment" type="tns:ParameterFragment" /> 22 22 </xsd:choice> 23 <xsd:attribute name=" defectId" type="xsd:string" use="required" />23 <xsd:attribute name="smellId" type="xsd:string" use="required" /> 24 24 <xsd:attribute name="briefText" type="xsd:string" use="required" /> 25 25 </xsd:complexType> -
trunk/autoquest-core-usability/src/main/resources/smellDescriptions_en.xml
r1493 r1918 1 1 <?xml version="1.0" encoding="UTF-8"?> 2 < defectDescriptions2 <smellDescriptions 3 3 xmlns="http://autoquest.informatik.uni-goettingen.de" 4 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://autoquest.informatik.uni-goettingen.de defectDescriptions.xsd">6 7 < defectDescription defectId="TEXT_FIELD_INPUT_RATIO" briefText="many text inputs">5 xsi:schemaLocation="http://autoquest.informatik.uni-goettingen.de smellDescriptions.xsd"> 6 7 <smellDescription smellId="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 … … 15 15 or combo boxes in the case predefined values must be entered. 16 16 </textFragment> 17 </ defectDescription>18 19 < defectDescription defectId="TEXT_FIELD_INPUT_REPETITIONS" briefText="many text repetitions">17 </smellDescription> 18 19 <smellDescription smellId="TEXT_FIELD_INPUT_REPETITIONS" briefText="many text repetitions"> 20 20 <textFragment> 21 21 In … … 34 34 reenter the same text several times into different text fields. 35 35 </textFragment> 36 </ defectDescription>37 38 < defectDescription defectId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO" briefText="many special signs">36 </smellDescription> 37 38 <smellDescription smellId="TEXT_FIELD_NO_LETTER_OR_DIGIT_RATIO" briefText="many special signs"> 39 39 <parameterFragment parameterName="noLetterOrDigitRatio" /> 40 40 <textFragment> … … 48 48 included at the right positions. 49 49 </textFragment> 50 </ defectDescription>51 52 < defectDescription defectId="HIGH_EVENT_COVERAGE" briefText="often executed">50 </smellDescription> 51 52 <smellDescription smellId="HIGH_EVENT_COVERAGE" briefText="often executed"> 53 53 <textFragment> 54 54 The task … … 64 64 be executed by users for fulfilling this task. 65 65 </textFragment> 66 </ defectDescription>67 68 < defectDescription defectId="INEFFICIENT_ACTIONS" briefText="inefficient actions">66 </smellDescription> 67 68 <smellDescription smellId="INEFFICIENT_ACTIONS" briefText="inefficient actions"> 69 69 <textFragment> 70 70 For executing task … … 81 81 them: scrolling. 82 82 </textFragment> 83 </ defectDescription>84 85 < defectDescription defectId="COOCCURENCE_SUCCEED" briefText="usual cooccurrence">83 </smellDescription> 84 85 <smellDescription smellId="COOCCURENCE_SUCCEED" briefText="usual cooccurrence"> 86 86 <textFragment> 87 87 In … … 101 101 reduce the number of actions to be performed by the user. 102 102 </textFragment> 103 </ defectDescription>104 105 < defectDescription defectId="COOCCURENCE_PRECED" briefText="usual cooccurrence">103 </smellDescription> 104 105 <smellDescription smellId="COOCCURENCE_PRECED" briefText="usual cooccurrence"> 106 106 <textFragment> 107 107 In … … 121 121 reduce the number of actions to be performed by the user. 122 122 </textFragment> 123 </ defectDescription>124 125 < defectDescription defectId="HIGH_TARGET_DISTANCE" briefText="long way to go">123 </smellDescription> 124 125 <smellDescription smellId="HIGH_TARGET_DISTANCE" briefText="long way to go"> 126 126 <textFragment> 127 127 For executing the task … … 139 139 on average ), they should be more colocated to ease the execution of the task for the user. 140 140 </textFragment> 141 </ defectDescription>142 143 < defectDescription defectId="MISSING_FEEDBACK" briefText="missing feedback">141 </smellDescription> 142 143 <smellDescription smellId="MISSING_FEEDBACK" briefText="missing feedback"> 144 144 <textFragment> 145 145 A click on the button … … 163 163 actions. Please consider showing the user some progress after he performed the 164 164 first click. This is especially important if the operation triggered with the click usually 165 takes longer than one second. This defectwas observed based on task165 takes longer than one second. This smell was observed based on task 166 166 </textFragment> 167 167 <parameterFragment parameterName="task" /> … … 169 169 . 170 170 </textFragment> 171 </ defectDescription>172 173 < defectDescription defectId="UNUSED_GUI_ELEMENTS" briefText="unused GUI elements">171 </smellDescription> 172 173 <smellDescription smellId="UNUSED_GUI_ELEMENTS" briefText="unused GUI elements"> 174 174 <parameterFragment parameterName="ratio" /> 175 175 <textFragment> … … 189 189 </textFragment> 190 190 <parameterFragment parameterName="unusedGuiElements" /> 191 </defectDescription> 192 </defectDescriptions> 191 </smellDescription> 192 193 <smellDescription smellId="DATA_ENTRY_METHOD_CHANGE" briefText="data entry method change"> 194 <textFragment> 195 When executing task 196 </textFragment> 197 <parameterFragment parameterName="task" /> 198 <textFragment> 199 , the users have to switch between keyboard and mouse in 200 </textFragment> 201 <parameterFragment parameterName="ratio" /> 202 <textFragment> 203 % on average between two subsequently executed actions. Frequently changing between mouse and 204 keyboard causes users to become slow when utilizing a GUI. Hence, these should be minimized to 205 optimize the users performance. 206 </textFragment> 207 </smellDescription> 208 209 <smellDescription smellId="GOOD_DEFAULTS" briefText="good defaults"> 210 <textFragment> 211 When using GUI element 212 </textFragment> 213 <parameterFragment parameterName="guiElement" /> 214 <textFragment> 215 in view 216 </textFragment> 217 <parameterFragment parameterName="view" /> 218 <textFragment> 219 , the values selected by the users are not equally distributed. Hence, it may be useful to 220 have a good default value. The users entered the following values with their respective 221 frequency in brackets most often (only the five most important entries listed): 222 </textFragment> 223 <parameterFragment parameterName="selectedValues" /> 224 </smellDescription> 225 226 <smellDescription smellId="CHECK_BOX_SINGLE_SELECTION" briefText="check box single selection"> 227 <textFragment> 228 Found a group of check boxes of which only one is usually selected. In this case, radio 229 buttons should be used instead, if the alternatives are mutually exclusive. The check boxes 230 belonging to the group are: 231 </textFragment> 232 <parameterFragment parameterName="radioButtons" /> 233 </smellDescription> 234 235 <smellDescription smellId="COMMON_TASK_RATE" briefText="common task rate"> 236 <textFragment> 237 The user sessions show only a few commonalities. On average, ten subsequently executed 238 actions need to be described by 239 </textFragment> 240 <parameterFragment parameterName="ratio" /> 241 <textFragment> 242 different determined tasks. In the worst case, each action is its own task. In the best case, 243 all actions are described by the same tasks. This indicates, that the users act relatively 244 different as otherwise, all their actions would be described by only a few tasks. Hence, 245 users seem to be missing guidance, as otherwise, they would behave similar resulting in less 246 generated task which still cover many recorded actions. 247 </textFragment> 248 </smellDescription> 249 250 <smellDescription smellId="MISLEADING_CLICK_CUE" briefText="misleading cue to click"> 251 <textFragment> 252 In the 253 </textFragment> 254 <parameterFragment parameterName="noOfViewDisplays" /> 255 <textFragment> 256 times the view 257 </textFragment> 258 <parameterFragment parameterName="view" /> 259 <textFragment> 260 has been displayed, the element 261 </textFragment> 262 <parameterFragment parameterName="element" /> 263 <textFragment> 264 has been clicked 265 </textFragment> 266 <parameterFragment parameterName="uselessClicks" /> 267 <textFragment> 268 times although it may not be clickable (it is no, e.g., button). If the element is not 269 clickable, then the element seems to give a cue that it was clickable although it is not. 270 Hence, it should be considered to change the appearance of the element to prevent it from 271 looking clickable. 272 </textFragment> 273 </smellDescription> 274 275 <smellDescription smellId="MOST_OFTEN_DONE_FIRST" briefText="most often done first in view"> 276 <textFragment> 277 When opening the view 278 </textFragment> 279 <parameterFragment parameterName="view" /> 280 <textFragment> 281 , users most often position the cursor into the text field 282 </textFragment> 283 <parameterFragment parameterName="textfield" /> 284 <textFragment> 285 (in 286 </textFragment> 287 <parameterFragment parameterName="ratio" /> 288 <textFragment> 289 % of cases when the view is opened). This should be automated to remove one action required 290 for users. 291 </textFragment> 292 </smellDescription> 293 </smellDescriptions>
Note: See TracChangeset
for help on using the changeset viewer.