// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.usability; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import de.ugoe.cs.autoquest.eventcore.guimodel.ICheckBox; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric; /** * TODO comment * * @version $Revision: $ $Date: 16.07.2012$ * @author 2012, last modified by $Author: pharms$ */ public class CheckBoxMultipleSelectionRule implements UsabilityEvaluationRule { /* * (non-Javadoc) * * @see de.ugoe.cs.usability.UsabilityEvaluationRule#evaluate(TaskTree) */ @Override public UsabilityEvaluationResult evaluate(ITaskModel taskModel) { ValueChangeStatistics statistics = new ValueChangeStatistics(); calculateStatistics(taskModel.getTasks(), statistics); statistics.condenseCheckBoxGroups(); UsabilityEvaluationResult results = new UsabilityEvaluationResult(taskModel); analyzeStatistics(statistics, taskModel, results); return results; } /** * */ private void analyzeStatistics(ValueChangeStatistics statistics, ITaskModel taskModel, UsabilityEvaluationResult results) { Map> checkBoxGroups = statistics.getCheckBoxGroups(); CHECK_NEXT_GROUP: for (List group : checkBoxGroups.values()) { Set tasksUsingGroup = new HashSet<>(); for (IGUIElement checkBox : group) { Set tasksUsingCheckBox = getTasksUsingCheckBox(checkBox, taskModel); for (ITask taskUsingCheckBox : tasksUsingCheckBox) { if (tasksUsingGroup.contains(taskUsingCheckBox)) { continue CHECK_NEXT_GROUP; } else { tasksUsingGroup.add(taskUsingCheckBox); } } } if (tasksUsingGroup.size() > 0) { int eventCoverage = 0; int allRecordedEvents = 0; for (ITask task : tasksUsingGroup) { if (task instanceof IEventTask) { eventCoverage += taskModel.getTaskInfo(task).getMeasureValue(TaskMetric.EVENT_COVERAGE); } } for (ITask task : taskModel.getTasks()) { if (task instanceof IEventTask) { allRecordedEvents += taskModel.getTaskInfo(task).getMeasureValue(TaskMetric.EVENT_COVERAGE); } } UsabilitySmellIntensity intensity = UsabilitySmellIntensity.getIntensity ((int) (1000 * eventCoverage / allRecordedEvents), eventCoverage, -1); if (intensity != null) { Map parameters = new HashMap(); parameters.put("radioButtons", group); results.addSmell (intensity, UsabilitySmellDescription.CHECK_BOX_SINGLE_SELECTION, parameters); } } } } /** * */ private Set getTasksUsingCheckBox(final IGUIElement checkBox, ITaskModel taskModel) { final Set tasksUsingCheckBox = new HashSet(); for (ITask candidate : taskModel.getTasks()) { candidate.accept(new DefaultTaskTraversingVisitor() { @Override public void visit(IEventTask eventTask) { if (!eventTask.getInstances().isEmpty()) { IEventTaskInstance instance = (IEventTaskInstance) eventTask.getInstances().iterator().next(); if (checkBox.equals(instance.getEvent().getTarget())) { tasksUsingCheckBox.add(eventTask); } } } @Override public void visit(IStructuringTemporalRelationship relationship) { if (tasksUsingCheckBox.contains(relationship)) { return; } else { for (ITask child : relationship.getChildren()) { if (tasksUsingCheckBox.contains(child)) { tasksUsingCheckBox.add(relationship); return; } } super.visit(relationship); for (ITask child : relationship.getChildren()) { if (tasksUsingCheckBox.contains(child)) { tasksUsingCheckBox.add(relationship); break; } } } } @Override public void visit(IMarkingTemporalRelationship relationship) { if (tasksUsingCheckBox.contains(relationship)) { return; } else { if (tasksUsingCheckBox.contains(relationship.getMarkedTask())) { tasksUsingCheckBox.add(relationship); return; } super.visit(relationship); if (tasksUsingCheckBox.contains(relationship.getMarkedTask())) { tasksUsingCheckBox.add(relationship); return; } } } }); } return tasksUsingCheckBox; } /** * */ private void calculateStatistics(Collection tasks, ValueChangeStatistics statistics) { for (ITask task : tasks) { if (task instanceof IEventTask) { for (ITaskInstance taskInstance : task.getInstances()) { statistics.addValueChange((IEventTaskInstance) taskInstance); } } } } /** * */ private static class ValueChangeStatistics { /** */ private Set checkBoxes = new HashSet<>(); /** */ private Map> checkBoxGroups = new HashMap<>(); /** * */ private void addValueChange(IEventTaskInstance instance) { IGUIElement target = (IGUIElement) instance.getEvent().getTarget(); if (target instanceof ICheckBox) { checkBoxes.add(target); } } /** * */ private void condenseCheckBoxGroups() { checkBoxGroups = RuleUtils.getGroups(checkBoxes, 3); } /** * */ private Map> getCheckBoxGroups() { return checkBoxGroups; } } }