// 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.rules.patterns; import java.util.List; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; import de.ugoe.cs.autoquest.usability.taskmodel.filter.ITaskModelFilter; import de.ugoe.cs.autoquest.usability.taskmodel.filter.TaskModelFilter; import de.ugoe.cs.autoquest.usability.taskmodel.filter.types.TaskTypeFilter; /** *

* A interaction pattern is a simple approach to describe the structure of usage behaviour. *

* * @author Alexander Deicke */ public class InteractionPattern { /** *

* {@link TaskModelFilterAccessor}, which is used to filter a task model after different {@link ITask}s *

*/ private ITaskModelFilter taskTreeFilter = new TaskModelFilter(); /** *

* Type of root task. Determines the order in which sub task appear. *

*/ private TaskTypeFilter rootTask; /** *

* Helper objects, which decide whether or not a defined pattern condition holds. *

*/ private List patternVisitors; /** *

* Flag, which indicates if the interaction pattern was found within a given task model. *

*/ private boolean present = false; /** *

* Constructor. Creates a new interaction pattern for a given root task and a collection of * {@link InteractionPatternVisitor}s. *

* * @param rootTask * Type of root task, which determines the order in which sub task appear. * @param patternVisitors * {@link InteractionPatternVisitor}s, which decide whether or not a defined pattern * condition holds */ public InteractionPattern(TaskTypeFilter rootTask, List patternVisitors) { this.patternVisitors = patternVisitors; this.rootTask = rootTask; } /** * *

* Checks if a interaction pattern is contained in a given task model. *

* * @param taskModel * {@link ITaskModel}, which might contain the interaction pattern * @return true, iff interaction pattern is contained */ public boolean containedIn(ITaskModel taskModel) { List allConcernedTasks = filterAllConcernedTasksFrom(taskModel); for (ITask concernedTask : allConcernedTasks) { checkTask(concernedTask); if (this.present) break; } return this.present; } /** * *

* Checks a single {@link ITask} for the interaction pattern. *

* * @param task * task, which might contain the interaction pattern */ private void checkTask(ITask task) { applyAllVisitors(task); if (allVisitorsArePresent()) { this.present = true; } else { resetAllVisitors(); } } /** * *

* Checks if a interaction pattern is contained in a given task. *

* * @param task * task, which might contain the interaction pattern * @return true, iff interaction pattern is contained */ public boolean containedIn(ITask task) { checkTask(task); return this.present; } /** * *

* Method applys all {@link InteractionPatternVisitor}s, to check single interaction pattern * conditions. *

* * @param task * task, which might contain the interaction pattern */ private void applyAllVisitors(ITask task) { Optional previousVisitor = Optional.absent(); for (InteractionPatternVisitor visitor : patternVisitors) { if (appliedOnSelectionNode(previousVisitor)) { for (ITask selection : previousVisitor.get().getRetainedSelectionNodes()) { selection.accept(visitor); } } else { previousVisitor = Optional.of(visitor); task.accept(visitor); } } } /** * *

* Checks, if a {@link InteractionPatternVisitor} was applied on a {@link ISelection} task. *

* * @param interactionPatternVisitor * {@link InteractionPatternVisitor} * @return true, iff {@link InteractionPatternVisitor} was applied on {@link ISelection} task */ private boolean appliedOnSelectionNode(Optional interactionPatternVisitor) { return interactionPatternVisitor.isPresent() && interactionPatternVisitor.get().hasExcludedSelectionNodes(); } /** *

* Filters given task model after root task of interaction pattern. *

* * @param taskModel * {@link ITaskModel} * @return all tasks of task model, which matches root task of interaction pattern */ private List filterAllConcernedTasksFrom(ITaskModel taskModel) { return this.taskTreeFilter.filter(taskModel, this.rootTask).tasksMatchedFilter(); } /** *

* Checks, if all interaction pattern condition are evaluated to true. *

* * @return true, iff all interaction pattern condition are true */ private boolean allVisitorsArePresent() { Iterable allPresent = Iterables.filter(this.patternVisitors, new Predicate() { public boolean apply(InteractionPatternVisitor visitor) { return visitor.isPresent(); } }); return Iterables.size(allPresent) == this.patternVisitors.size(); } /** *

* Resets all interaction pattern condition. *

* */ private void resetAllVisitors() { for (InteractionPatternVisitor visitor : this.patternVisitors) { visitor.reset(); } } }