Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: c508c2f1ac17d12ea19927cb6dd5813556b9093c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*******************************************************************************
 * Copyright (c) 2011, 2012 Wind River Systems, Inc. and others. All rights reserved.
 * This program and the accompanying materials are made available under the terms
 * of the Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Wind River Systems - initial API and implementation
 *******************************************************************************/
package org.eclipse.tcf.te.ui.internal;

import java.util.LinkedList;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.tcf.te.ui.interfaces.ISearchMatcher;

/**
 * The search engine for the execution context viewer. It has three methods
 * which defines the process of searching elements in the viewer:
 * <ol>
 * <li><code>startSearch</code> with an initial path to prepare the searching
 * context.</li>
 * <li><code>searchNext</code> to search an element with a rule defined by
 * ISearchMatcher.</li>
 * <li><code>endSearch</code> to clear up the searching context.</li>
 * </ol>
 * 
 * @see ISearchMatcher
 * @see ISearchCallback
 */
public class DepthTreeSearcher extends AbstractSearcher {
	private static final int START_INDEX = -1;
	private static final int END_INDEX = -2;

	// A stack element used to store the current context and the children index
	private class StackElement {
		Object node;
		int index;

		public StackElement(Object node, int index) {
			this.node = node;
			this.index = index;
		}
	}
	// The searching stack in which searching contexts are stored.
	private LinkedList<StackElement> fSearchStack;

	/**
	 * Create an execution context searcher with the specified viewer and its
	 * controller.
	 * 
	 * @param viewer
	 *            The execution context viewer.
	 * @param controller
	 *            The controller of the execution context viewer.
	 */
	public DepthTreeSearcher(TreeViewer viewer) {
		super(viewer);
	}

	/**
	 * Start the search process. This method is called to clear the searching
	 * context. Each search process is stateful process. Callers must call this
	 * method to reset the search state before each searching process starts.
	 * 
	 * @param start
	 *            The beginning path from which the seach process starts.
	 */
	@Override
    public void startSearch(TreePath start) {
		fSearchStack = new LinkedList<StackElement>();
		if (start == null) {
			Object obj = fViewer.getInput();
			start = new TreePath(new Object[] { obj });
		}
		initSearchContext(start);
	}

	/**
	 * Populate the stacks with initial path.
	 * 
	 * @param start The initial path.
	 */
	private void initSearchContext(TreePath start) {
		int count = start.getSegmentCount();
		for (int i = 0; i < count; i++) {
			Object element = start.getSegment(i);
			//Push a stack element with initial index as START_INDEX.
			fSearchStack.addLast(new StackElement(element, START_INDEX));
			if (i > 0) {
				IProgressMonitor monitor = new NullProgressMonitor();
				Object parent = start.getSegment(i-1);
				Object[] children = getUpdatedChildren(parent, monitor);
				for (int j = 0; j < children.length; j++) {
					if (children[j] == element) {
						StackElement parentStack = fSearchStack.get(i - 1);
						//Assign the stack element's index with element index in the children list.
						parentStack.index = j;
						break;
					}
				}
			}
		}
	}

	/**
	 * Search the tree using a matcher when the data model is not lazy.
	 * 
	 * @param forward Forward search or backward search.
	 * @param matcher The matcher defining the searching rule.
	 * @param monitor The monitor reporting the progress.
	 * @return The tree path whose leaf node statisfies the searching rule.
	 */
	@SuppressWarnings("synthetic-access")
    protected TreePath searchNode(boolean forward, ISearchMatcher matcher, IProgressMonitor monitor) {
		TreePath result = null;
		while (!fSearchStack.isEmpty() && result == null && !monitor.isCanceled()) { //Search util the stack is empty or the result is found.
			StackElement top = fSearchStack.getLast(); //Get the top stack element.
			if(!forward && top.index == END_INDEX || forward && top.index == START_INDEX){
				reportProgress(top.node, monitor);
				result = matchContext(matcher, top.node);
			}
			if (top.index == END_INDEX) {//If the top index is END_INDEX, it means the node has been finished.
				fSearchStack.removeLast(); //Then discard it.
			} else {
				Object[] children = getUpdatedChildren(top.node, monitor);//Get current node's children.
				if (children != null && children.length > 0) {//If there are some children.
					if(forward && top.index == children.length-1 || !forward && top.index == 0){
						//If this is the last index
						top.index = END_INDEX;
					}else{
						//Increase or decrease the index according to the direction.
						if(top.index == START_INDEX)
							top.index = forward ? 0 : children.length - 1;
						else
							top.index = forward ? top.index + 1 : top.index - 1;
						//Push the child at the index with START_INDEX into the stack.
						fSearchStack.addLast(new StackElement(children[top.index], START_INDEX));
					}
				} else {//If there's no children.
					top.index = END_INDEX;//Assign the index with END_INDEX.
				}
			}
		}
		return result;
	}
	private TreePath matchContext(ISearchMatcher matcher, Object context){
		if (matcher.match(context)) {//Match the context using the matcher.
			return createContextPath();//If the matching is successful, assign the result with the current path.
		}
		return null;
	}
	/**
	 * Create a path using the current elements of the stack.
	 * 
	 * @return The tree path representing the path of the stack.
	 */
	private TreePath createContextPath() {
		StackElement[] contexts = new StackElement[fSearchStack.size()];
		fSearchStack.toArray(contexts);
		Object[] elements = new Object[contexts.length];
		for (int i = 0; i < contexts.length; i++) {
			elements[i] = contexts[i].node;
		}
		return new TreePath(elements);
	}
}

Back to the top