001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.cheatsheets.composite.model;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.ui.internal.provisional.cheatsheets.ICompositeCheatSheetTask;
016: import org.eclipse.ui.internal.provisional.cheatsheets.ITaskGroup;
017:
018: public class SuccesorTaskFinder {
019:
020: private AbstractTask currentTask;
021: ICompositeCheatSheetTask bestLaterTask;
022: ICompositeCheatSheetTask bestEarlierTask;
023: private boolean seenThisTask;
024:
025: public SuccesorTaskFinder(ICompositeCheatSheetTask task) {
026: currentTask = (AbstractTask) task;
027: }
028:
029: /**
030: * Find the next recommended task or tasks to be completed.
031: * Algorithm - visualize the tree as having its root at the top,
032: * children below and to the left of their parents and then
033: * search the tree from left to right. Look for
034: * the best predecessor which is the first task to the
035: * left of this task that is runnable and the best successor
036: * which is the first task to the
037: * right of this task which is runnable.
038: * @param task The task which was just completed
039: * @return An array of tasks which can be started
040: */
041: public ICompositeCheatSheetTask[] getRecommendedSuccessors() {
042: // TODO this code could be moved to TaskGroup
043: if (ITaskGroup.CHOICE.equals(currentTask.getKind())) {
044: // For a choice if more than one child is runnable return it
045: List runnableChoices = findRunnableChoices();
046: if (runnableChoices.size() != 0) {
047: return (ICompositeCheatSheetTask[]) runnableChoices
048: .toArray(new ICompositeCheatSheetTask[runnableChoices
049: .size()]);
050: }
051: }
052: return getBestSuccessor();
053: }
054:
055: private List findRunnableChoices() {
056: List result;
057: result = new ArrayList();
058: if (isStartable(currentTask)) {
059: ICompositeCheatSheetTask[] subtasks = currentTask
060: .getSubtasks();
061: for (int i = 0; i < subtasks.length; i++) {
062: if (isStartable(subtasks[i])) {
063: result.add(subtasks[i]);
064: }
065: }
066: }
067: return result;
068: }
069:
070: private boolean isStartable(ICompositeCheatSheetTask task) {
071: int state = task.getState();
072: return (state != ICompositeCheatSheetTask.COMPLETED
073: && state != ICompositeCheatSheetTask.SKIPPED && task
074: .requiredTasksCompleted());
075: }
076:
077: private ICompositeCheatSheetTask[] getBestSuccessor() {
078: bestLaterTask = null;
079: bestEarlierTask = null;
080: seenThisTask = false;
081: searchRunnableChildren(currentTask.getCompositeCheatSheet()
082: .getRootTask());
083: // If there is a task which is found later in the tree return
084: // that, otherwise an earlier task.
085: if (bestLaterTask != null) {
086: return new ICompositeCheatSheetTask[] { bestLaterTask };
087: }
088: if (bestEarlierTask != null) {
089: return new ICompositeCheatSheetTask[] { bestEarlierTask };
090: }
091: return new ICompositeCheatSheetTask[0];
092: }
093:
094: private void searchRunnableChildren(ICompositeCheatSheetTask task) {
095: // Don't search completed tasks or their children
096: // and stop searching if we've already found the best successor
097: if (bestLaterTask != null) {
098: return;
099: }
100: if (task == currentTask) {
101: seenThisTask = true;
102: }
103: if (task.getState() == ICompositeCheatSheetTask.COMPLETED
104: || task.getState() == ICompositeCheatSheetTask.SKIPPED) {
105: if (isTaskAncestor(task, currentTask)) {
106: seenThisTask = true;
107: }
108: return;
109: }
110:
111: if (isStartable(task) && task != currentTask) {
112: if (seenThisTask) {
113: if (bestLaterTask == null) {
114: bestLaterTask = task;
115: }
116: } else {
117: if (bestEarlierTask == null) {
118: bestEarlierTask = task;
119: }
120: }
121: }
122:
123: ICompositeCheatSheetTask[] subtasks = task.getSubtasks();
124: for (int i = 0; i < subtasks.length; i++) {
125: searchRunnableChildren(subtasks[i]);
126: }
127:
128: }
129:
130: private boolean isTaskAncestor(
131: ICompositeCheatSheetTask ancestorCandididate,
132: ICompositeCheatSheetTask task) {
133: ICompositeCheatSheetTask nextTask = task;
134: while (nextTask != null) {
135: if (nextTask == ancestorCandididate) {
136: return true;
137: }
138: nextTask = nextTask.getParent();
139: }
140: return false;
141: }
142: }
|