// 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.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import de.ugoe.cs.autoquest.eventcore.IEventTarget; import de.ugoe.cs.autoquest.eventcore.gui.MouseClick; import de.ugoe.cs.autoquest.eventcore.gui.ValueSelection; import de.ugoe.cs.autoquest.eventcore.guimodel.ICheckBox; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIView; import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; 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.IUserSession; /** * 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) { System.out.println("\n\n########################################\n"); final List> actionInstancesInSameView = new LinkedList<>(); for (IUserSession session : taskModel.getUserSessions()) { for (ITaskInstance instance : session) { final LinkedList currentList = new LinkedList<>(); instance.accept(new DefaultTaskInstanceTraversingVisitor() { @Override public void visit(IEventTaskInstance eventTaskInstance) { if (eventTaskInstance.getEvent().getTarget() instanceof IGUIElement) { IEventTarget target = eventTaskInstance.getEvent().getTarget(); IGUIView currentView = ((IGUIElement) target).getView(); IGUIView previousView = null; if (currentList.size() > 0) { target = currentList.getLast().getEvent().getTarget(); previousView = ((IGUIElement) target).getView(); } if ((previousView == currentView) || ((previousView != null) && (previousView.equals(currentView)))) { currentList.add(eventTaskInstance); } else { if (currentList.size() > 0) { actionInstancesInSameView.add(new ArrayList<>(currentList)); } currentList.clear(); currentList.add(eventTaskInstance); } } } }); if (currentList.size() > 0) { actionInstancesInSameView.add(new ArrayList<>(currentList)); } } } Map> checkBoxGroups = statistics.getCheckBoxGroups(); for (Map.Entry> group : checkBoxGroups.entrySet()) { IGUIView currentView = group.getKey().getView(); int noOfEvents = 0; int noOfGroupUsages = 0; int noOfSingleCheckBoxUsages = 0; for (List actionInstanceList : actionInstancesInSameView) { IEventTarget target = actionInstanceList.get(0).getEvent().getTarget(); IGUIView viewOfList = ((IGUIElement) target).getView(); if ((viewOfList == currentView) || ((viewOfList != null) && (viewOfList.equals(currentView)))) { noOfGroupUsages++; boolean[] checkBoxUsages = new boolean[group.getValue().size()]; for (IEventTaskInstance actionInstance : actionInstanceList) { int index = 0; for (IGUIElement checkBox : group.getValue()) { if ((("JFC".equals(actionInstance.getEvent().getTarget().getPlatform())) && (actionInstance.getEvent().getType() instanceof MouseClick) && (actionInstance.getEvent().getTarget().equals(checkBox))) || ((actionInstance.getEvent().getType() instanceof ValueSelection) && (actionInstance.getEvent().getTarget().equals(checkBox)))) { checkBoxUsages[index] = !checkBoxUsages[index]; noOfEvents++; } index++; } } int noOfCheckedBoxes = 0; for (int i = 0; i < checkBoxUsages.length; i++) { if (checkBoxUsages[i]) { noOfCheckedBoxes++; } } if (noOfCheckedBoxes == 1) { noOfSingleCheckBoxUsages++; } } } // get a value that is 1 if for one group usage there is on average one check box usage // get a value of 0 if for one group usage there is on average two check box usages int ratio = noOfGroupUsages > 0 ? 1000 * noOfSingleCheckBoxUsages / noOfGroupUsages : 0; System.out.println(currentView + " " + ratio + " " + noOfGroupUsages + " " + noOfSingleCheckBoxUsages); UsabilitySmellIntensity intensity = UsabilitySmellIntensity.getIntensity (ratio, noOfEvents, -1); if (intensity != null) { Map parameters = new HashMap(); parameters.put("allUsages", noOfGroupUsages); parameters.put("singleUsages", noOfSingleCheckBoxUsages); parameters.put("ratio", 100 * noOfSingleCheckBoxUsages / noOfGroupUsages); parameters.put("radioButtons", group.getValue()); results.addSmell (intensity, UsabilitySmellDescription.CHECK_BOX_SINGLE_SELECTION, parameters); } } } /** * */ 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; } } }