blob: 92d27f86567ddee4b80eb612adf240fd3e3b7909 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.cheatsheets.composite.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.ui.internal.provisional.cheatsheets.ICompositeCheatSheetTask;
import org.eclipse.ui.internal.provisional.cheatsheets.IEditableTask;
import org.eclipse.ui.internal.provisional.cheatsheets.ITaskGroup;
/**
* This class contains utility functions to determine the state of a task based on
* dependencies, parent state etc.
*/
public class TaskStateUtilities {
/**
* Find the most recent ancestor of this task that is blocked
* @param task
* @return A blocked task or null if no ancestors are blocked
*/
public static ICompositeCheatSheetTask findBlockedAncestor(ICompositeCheatSheetTask task) {
ITaskGroup parent = ((AbstractTask)task).getParent();
if (parent == null) {
return null;
}
if (!parent.requiredTasksCompleted()) {
return parent;
}
return findBlockedAncestor(parent);
}
/**
* Find the most recent ancestor of this task that is skipped
* @param task
* @return A skipped task or null if no ancestors are skipped
*/
public static ICompositeCheatSheetTask findSkippedAncestor(ICompositeCheatSheetTask task) {
ITaskGroup parent = ((AbstractTask)task).getParent();
if (parent == null) {
return null;
}
if (parent.getState() == ICompositeCheatSheetTask.SKIPPED) {
return parent;
}
return findSkippedAncestor(parent);
}
/**
* Find the most recent ancestor of this task that is completed
* @param task
* @return A completed task or null if no ancestors are completed
*/
public static ICompositeCheatSheetTask findCompletedAncestor(ICompositeCheatSheetTask task) {
ITaskGroup parent = ((AbstractTask)task).getParent();
if (parent == null) {
return null;
}
if (parent.getState() == ICompositeCheatSheetTask.COMPLETED) {
return parent;
}
return findCompletedAncestor(parent);
}
/**
* Determine whether a task can be skipped.
* A task can be skipped if it is skippable, its state is not SKIPPED or completed
* and it has no skipped ot completed ancestors.
*/
public static boolean isSkipEnabled(ICompositeCheatSheetTask task) {
if (!task.isSkippable()) return false;
if (task.getState() == ICompositeCheatSheetTask.COMPLETED) return false;
if (task.getState() == ICompositeCheatSheetTask.SKIPPED) return false;
if (findCompletedAncestor(task) != null) return false;
if (findSkippedAncestor(task) != null) return false;
return true;
}
/**
* Determine whether a task can be started
* Only editable tasks which are not blocked and whose ancestors
* are not completed can be started
*/
public static boolean isStartEnabled(ICompositeCheatSheetTask task) {
if (!(task instanceof IEditableTask)) return false;
return isStartable(task);
}
/**
* Determines whether a task is in a state where it has net been started and
* cannot be started. This is used to determine when to gray out the icon for a task.
*/
public static boolean isBlocked(ICompositeCheatSheetTask task) {
return (task.getState() == ICompositeCheatSheetTask.NOT_STARTED && !isStartable(task));
}
/**
* Determines whether an editable task, or a task group has anything
* that would prevent it or its children from being started.
*/
private static boolean isStartable(ICompositeCheatSheetTask task) {
if (task.getState() != ICompositeCheatSheetTask.NOT_STARTED) return false;
if (findSkippedAncestor(task) != null) return false;
if (findCompletedAncestor(task) != null) return false;
if (!task.requiredTasksCompleted()) return false;
if (findBlockedAncestor(task) != null) return false;
return true;
}
/**
* Determine which tasks need to be restarted if this tasks is restarted
*/
public static AbstractTask[] getRestartTasks(ICompositeCheatSheetTask task) {
List<ICompositeCheatSheetTask> restartables = new ArrayList<>();
Set<ICompositeCheatSheetTask> visited = new HashSet<>();
addRestartableTasks(restartables, task, visited);
return restartables.toArray(new AbstractTask[restartables.size()]);
}
private static void addRestartableTasks(List<ICompositeCheatSheetTask> restartables, ICompositeCheatSheetTask task,
Set<ICompositeCheatSheetTask> visited) {
if (visited.contains(task)) {
return;
}
visited.add(task);
if (task instanceof IEditableTask && task.getState() != ICompositeCheatSheetTask.NOT_STARTED) {
restartables.add(task);
} else if (task.getState() == ICompositeCheatSheetTask.SKIPPED){
restartables.add(task);
}
// Add all children
ICompositeCheatSheetTask[] children = task.getSubtasks();
for (int i = 0; i < children.length; i++) {
addRestartableTasks(restartables, children[i], visited);
}
// Add all dependents that are started or in progress but not skipped
ICompositeCheatSheetTask[] successors = ((AbstractTask)task).getSuccessorTasks();
for (int i = 0; i < successors.length; i++) {
int state = successors[i].getState();
if (state == ICompositeCheatSheetTask.COMPLETED || state == ICompositeCheatSheetTask.IN_PROGRESS) {
addRestartableTasks(restartables, successors[i], visited);
}
}
}
}