Lines 12-24
Link Here
|
12 |
package org.eclipse.jface.viewers; |
12 |
package org.eclipse.jface.viewers; |
13 |
|
13 |
|
14 |
import java.util.ArrayList; |
14 |
import java.util.ArrayList; |
15 |
import java.util.Arrays; |
|
|
16 |
import java.util.HashSet; |
15 |
import java.util.HashSet; |
17 |
import java.util.Iterator; |
16 |
import java.util.Iterator; |
18 |
import java.util.List; |
17 |
import java.util.List; |
19 |
|
18 |
|
20 |
import org.eclipse.core.runtime.Platform; |
19 |
import org.eclipse.core.runtime.Platform; |
21 |
|
20 |
import org.eclipse.jface.util.Assert; |
|
|
21 |
import org.eclipse.jface.util.ListenerList; |
22 |
import org.eclipse.jface.util.SafeRunnable; |
22 |
import org.eclipse.swt.SWT; |
23 |
import org.eclipse.swt.SWT; |
23 |
import org.eclipse.swt.custom.BusyIndicator; |
24 |
import org.eclipse.swt.custom.BusyIndicator; |
24 |
import org.eclipse.swt.events.SelectionListener; |
25 |
import org.eclipse.swt.events.SelectionListener; |
Lines 28-37
Link Here
|
28 |
import org.eclipse.swt.widgets.Item; |
29 |
import org.eclipse.swt.widgets.Item; |
29 |
import org.eclipse.swt.widgets.Widget; |
30 |
import org.eclipse.swt.widgets.Widget; |
30 |
|
31 |
|
31 |
import org.eclipse.jface.util.Assert; |
|
|
32 |
import org.eclipse.jface.util.ListenerList; |
33 |
import org.eclipse.jface.util.SafeRunnable; |
34 |
|
35 |
/** |
32 |
/** |
36 |
* Abstract base implementation for tree-structure-oriented viewers |
33 |
* Abstract base implementation for tree-structure-oriented viewers |
37 |
* (trees and table trees). |
34 |
* (trees and table trees). |
Lines 57-69
Link Here
|
57 |
* @see #expandToLevel |
54 |
* @see #expandToLevel |
58 |
* @see #collapseToLevel |
55 |
* @see #collapseToLevel |
59 |
*/ |
56 |
*/ |
60 |
public static final int ALL_LEVELS= -1; |
57 |
public static final int ALL_LEVELS = -1; |
61 |
|
58 |
|
62 |
/** |
59 |
/** |
63 |
* List of registered tree listeners (element type: <code>TreeListener</code>). |
60 |
* List of registered tree listeners (element type: <code>TreeListener</code>). |
64 |
*/ |
61 |
*/ |
65 |
private ListenerList treeListeners = new ListenerList(1); |
62 |
private ListenerList treeListeners = new ListenerList(1); |
66 |
|
63 |
|
67 |
/** |
64 |
/** |
68 |
* The level to which the tree is automatically expanded each time |
65 |
* The level to which the tree is automatically expanded each time |
69 |
* the viewer's input is changed (that is, by <code>setInput</code>). |
66 |
* the viewer's input is changed (that is, by <code>setInput</code>). |
Lines 72-1522
Link Here
|
72 |
* @see #setAutoExpandLevel |
69 |
* @see #setAutoExpandLevel |
73 |
*/ |
70 |
*/ |
74 |
private int expandToLevel = 0; |
71 |
private int expandToLevel = 0; |
75 |
|
72 |
|
76 |
/** |
73 |
/** |
77 |
* The safe runnable used to call the label provider. |
74 |
* The safe runnable used to call the label provider. |
78 |
*/ |
75 |
*/ |
79 |
private UpdateItemSafeRunnable safeUpdateItem = new UpdateItemSafeRunnable(); |
76 |
private UpdateItemSafeRunnable safeUpdateItem = |
80 |
|
77 |
new UpdateItemSafeRunnable(); |
|
|
78 |
|
81 |
class UpdateItemSafeRunnable extends SafeRunnable { |
79 |
class UpdateItemSafeRunnable extends SafeRunnable { |
82 |
Object element; |
80 |
Object element; |
83 |
Item item; |
81 |
Item item; |
84 |
boolean exception = false; |
82 |
boolean exception = false; |
85 |
public void run() { |
83 |
public void run() { |
86 |
if(exception) return; |
84 |
if (exception) |
87 |
doUpdateItem(item,element); |
85 |
return; |
|
|
86 |
doUpdateItem(item, element); |
88 |
} |
87 |
} |
89 |
public void handleException(Throwable e) { |
88 |
public void handleException(Throwable e) { |
90 |
super.handleException(e); |
89 |
super.handleException(e); |
91 |
//If and unexpected exception happens, remove it |
90 |
//If and unexpected exception happens, remove it |
92 |
//to make sure the application keeps running. |
91 |
//to make sure the application keeps running. |
93 |
exception = true; |
92 |
exception = true; |
94 |
} |
|
|
95 |
} |
96 |
|
97 |
/** |
98 |
* Creates an abstract tree viewer. The viewer has no input, no content provider, a |
99 |
* default label provider, no sorter, no filters, and has auto-expand turned off. |
100 |
*/ |
101 |
protected AbstractTreeViewer() { |
102 |
} |
103 |
/** |
104 |
* Adds the given child elements to this viewer as children of the given parent element. |
105 |
* If this viewer does not have a sorter, the elements are added at the end of the |
106 |
* parent's list of children in the order given; otherwise, the elements are inserted |
107 |
* at the appropriate positions. |
108 |
* <p> |
109 |
* This method should be called (by the content provider) when elements |
110 |
* have been added to the model, in order to cause the viewer to accurately |
111 |
* reflect the model. This method only affects the viewer, not the model. |
112 |
* </p> |
113 |
* |
114 |
* @param parentElement the parent element |
115 |
* @param childElements the child elements to add |
116 |
*/ |
117 |
public void add(Object parentElement, Object[] childElements) { |
118 |
Assert.isNotNull(parentElement); |
119 |
Assert.isNotNull(childElements); |
120 |
Widget widget = findItem(parentElement); |
121 |
// If parent hasn't been realized yet, just ignore the add. |
122 |
if (widget == null) |
123 |
return; |
124 |
|
125 |
Control tree = getControl(); |
126 |
|
127 |
// optimization! |
128 |
// if the widget is not expanded we just invalidate the subtree |
129 |
if (widget instanceof Item) { |
130 |
Item ti= (Item) widget; |
131 |
if (!getExpanded(ti)) { |
132 |
boolean needDummy = isExpandable(parentElement); |
133 |
boolean haveDummy = false; |
134 |
// remove all children |
135 |
Item[] items= getItems(ti); |
136 |
for (int i = 0; i < items.length; i++) { |
137 |
if (items[i].getData() != null) { |
138 |
disassociate(items[i]); |
139 |
items[i].dispose(); |
140 |
} |
141 |
else { |
142 |
if (needDummy && !haveDummy) { |
143 |
haveDummy = true; |
144 |
} |
145 |
else { |
146 |
items[i].dispose(); |
147 |
} |
148 |
} |
149 |
} |
150 |
// append a dummy if necessary |
151 |
if (needDummy && !haveDummy) { |
152 |
newItem(ti, SWT.NULL, -1); |
153 |
} else { |
154 |
// XXX: Workaround (PR missing) |
155 |
tree.redraw(); |
156 |
} |
157 |
|
158 |
return; |
159 |
} |
93 |
} |
160 |
} |
94 |
} |
161 |
|
95 |
|
162 |
if (childElements.length > 0) { |
96 |
/** |
163 |
List children = Arrays.asList(getSortedChildren(parentElement)); |
97 |
* Creates an abstract tree viewer. The viewer has no input, no content provider, a |
164 |
for (int cc = 0; cc < childElements.length; cc++) { |
98 |
* default label provider, no sorter, no filters, and has auto-expand turned off. |
165 |
|
99 |
*/ |
166 |
int ix = children.indexOf(childElements[cc]); |
100 |
protected AbstractTreeViewer() { |
167 |
if (ix < 0) // child not found: ignore |
|
|
168 |
continue; |
169 |
|
170 |
Item[] ch = getChildren(widget); |
171 |
if (ch.length + 1 == children.size()) { |
172 |
createTreeItem(widget, childElements[cc], ix); // insert child at position |
173 |
if (ch.length == 0) { |
174 |
//System.out.println("WORKAROUND setRedraw"); |
175 |
tree.setRedraw(false); // WORKAROUND |
176 |
tree.setRedraw(true); // WORKAROUND |
177 |
} |
178 |
continue; |
179 |
} |
180 |
|
181 |
// couldn't handle this child: |
182 |
// skip other children and do general case |
183 |
// call refresh rather than internalRefresh to preserve selection |
184 |
refresh(parentElement); |
185 |
return; |
186 |
} |
187 |
} |
101 |
} |
188 |
} |
102 |
/** |
189 |
/** |
103 |
* Return the current children of the parent element with the |
190 |
* Adds the given child element to this viewer as a child of the given parent element. |
104 |
* newChildren added in. This method |
191 |
* If this viewer does not have a sorter, the element is added at the end of the |
105 |
* does not invoke the content provider but rather asks the |
192 |
* parent's list of children; otherwise, the element is inserted at the appropriate position. |
106 |
* widget. |
193 |
* <p> |
107 |
* @param parentElement |
194 |
* This method should be called (by the content provider) when a single element |
108 |
* @param newChildren Object[]. The children to be added to the |
195 |
* has been added to the model, in order to cause the viewer to accurately |
109 |
* view. |
196 |
* reflect the model. This method only affects the viewer, not the model. |
110 |
* @return Collection |
197 |
* Note that there is another method for efficiently processing the simultaneous |
111 |
*/ |
198 |
* addition of multiple elements. |
112 |
private Object[] getMergedChildren( |
199 |
* </p> |
113 |
Widget parentElement, |
200 |
* |
114 |
Object[] newChildren) { |
201 |
* @param parentElement the parent element |
115 |
Item[] items = getChildren(parentElement); |
202 |
* @param childElement the child element |
116 |
Object[] result = new Object[items.length + newChildren.length]; |
203 |
*/ |
117 |
for (int i = 0; i < items.length; i++) { |
204 |
public void add(Object parentElement, Object childElement) { |
118 |
result[i] = items[i].getData(); |
205 |
add(parentElement, new Object[] { childElement }); |
119 |
} |
206 |
} |
|
|
207 |
/** |
208 |
* Adds the given SWT selection listener to the given SWT control. |
209 |
* |
210 |
* @param control the SWT control |
211 |
* @param listener the SWT selection listener |
212 |
* |
213 |
* @deprecated |
214 |
*/ |
215 |
protected void addSelectionListener(Control control, SelectionListener listener) {} |
216 |
/** |
217 |
* Adds a listener for expand and collapse events in this viewer. |
218 |
* Has no effect if an identical listener is already registered. |
219 |
* |
220 |
* @param listener a tree viewer listener |
221 |
*/ |
222 |
public void addTreeListener(ITreeViewerListener listener) { |
223 |
treeListeners.add(listener); |
224 |
} |
225 |
/** |
226 |
* Adds the given SWT tree listener to the given SWT control. |
227 |
* |
228 |
* @param control the SWT control |
229 |
* @param listener the SWT tree listener |
230 |
*/ |
231 |
protected abstract void addTreeListener(Control control, TreeListener listener); |
232 |
|
120 |
|
233 |
/* (non-Javadoc) |
121 |
System.arraycopy( |
234 |
* @see StructuredViewer#associate(Object, Item) |
122 |
newChildren, |
235 |
*/ |
123 |
0, |
236 |
protected void associate(Object element, Item item) { |
124 |
result, |
237 |
Object data = item.getData(); |
125 |
items.length, |
238 |
if (data != null && data != element && equals(data, element)) { |
126 |
newChildren.length); |
239 |
// workaround for PR 1FV62BT |
127 |
return result; |
240 |
// assumption: elements are equal but not identical |
|
|
241 |
// -> remove from map but don't touch children |
242 |
unmapElement(data, item); |
243 |
item.setData(element); |
244 |
mapElement(element, item); |
245 |
} else { |
246 |
// recursively disassociate all |
247 |
super.associate(element, item); |
248 |
} |
128 |
} |
249 |
} |
|
|
250 |
|
129 |
|
251 |
/** |
130 |
/** |
252 |
* Collapses all nodes of the viewer's tree, starting with the root. |
131 |
* Return the index of element in the array elements. |
253 |
* This method is equivalent to <code>collapseToLevel(ALL_LEVELS)</code>. |
132 |
* @param element |
254 |
*/ |
133 |
* @param elements |
255 |
public void collapseAll() { |
134 |
*/ |
256 |
collapseToLevel(getRoot(), ALL_LEVELS); |
135 |
private int indexOf(Object element, Object[] elements) { |
257 |
} |
136 |
for (int i = 0; i < elements.length; i++) { |
258 |
/** |
137 |
if (elements[i].equals(element)) |
259 |
* Collapses the subtree rooted at the given element to the given level. |
138 |
return i; |
260 |
* |
139 |
} |
261 |
* @param element the element |
140 |
return -1; |
262 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
|
|
263 |
* all levels of the tree |
264 |
*/ |
265 |
public void collapseToLevel(Object element, int level) { |
266 |
Widget w = findItem(element); |
267 |
if (w != null) |
268 |
internalCollapseToLevel(w, level); |
269 |
} |
270 |
/** |
271 |
* Creates all children for the given widget. |
272 |
* <p> |
273 |
* The default implementation of this framework method assumes |
274 |
* that <code>widget.getData()</code> returns the element corresponding |
275 |
* to the node. Note: the node is not visually expanded! You may have to |
276 |
* call <code>parent.setExpanded(true)</code>. |
277 |
* </p> |
278 |
* |
279 |
* @param widget the widget |
280 |
*/ |
281 |
protected void createChildren(final Widget widget) { |
282 |
final Item[] tis = getChildren(widget); |
283 |
if (tis != null && tis.length > 0) { |
284 |
Object data = tis[0].getData(); |
285 |
if (data != null) |
286 |
return; // children already there! |
287 |
} |
141 |
} |
|
|
142 |
/** |
143 |
* Adds the given child elements to this viewer as children of the given parent element. |
144 |
* If this viewer does not have a sorter, the elements are added at the end of the |
145 |
* parent's list of children in the order given; otherwise, the elements are inserted |
146 |
* at the appropriate positions. |
147 |
* <p> |
148 |
* This method should be called (by the content provider) when elements |
149 |
* have been added to the model, in order to cause the viewer to accurately |
150 |
* reflect the model. This method only affects the viewer, not the model. |
151 |
* </p> |
152 |
* |
153 |
* @param parentElement the parent element |
154 |
* @param childElements the child elements to add |
155 |
*/ |
156 |
public void add(Object parentElement, Object[] childElements) { |
157 |
Assert.isNotNull(parentElement); |
158 |
Assert.isNotNull(childElements); |
159 |
Widget widget = findItem(parentElement); |
160 |
// If parent hasn't been realized yet, just ignore the add. |
161 |
if (widget == null) |
162 |
return; |
288 |
|
163 |
|
289 |
BusyIndicator.showWhile(widget.getDisplay(), new Runnable() { |
164 |
Object[] newElements; |
290 |
public void run() { |
165 |
//If it is not an item we have no children to worry about |
291 |
// fix for PR 1FW89L7: |
166 |
if (widget instanceof Item) |
292 |
// don't complain and remove all "dummies" ... |
167 |
newElements = |
293 |
if (tis != null) { |
168 |
filter(getMergedChildren((Item) widget, childElements)); |
294 |
for (int i = 0; i < tis.length; i++) { |
169 |
else |
295 |
tis[i].dispose(); |
170 |
newElements = childElements; |
296 |
} |
171 |
|
297 |
} |
172 |
getSorter().sort(this, newElements); |
298 |
Object d = widget.getData(); |
173 |
|
299 |
if (d != null) { |
174 |
Item[] ch = getChildren(widget); |
300 |
Object parentElement = d; |
|
|
301 |
Object[] children = getSortedChildren(parentElement); |
302 |
for (int i = 0; i < children.length; i++) { |
303 |
createTreeItem(widget, children[i], -1); |
304 |
} |
305 |
} |
306 |
} |
307 |
}); |
308 |
} |
309 |
/** |
310 |
* Creates a single item for the given parent and synchronizes it with |
311 |
* the given element. |
312 |
* |
313 |
* @param parent the parent widget |
314 |
* @param element the element |
315 |
* @param index if non-negative, indicates the position to insert the item |
316 |
* into its parent |
317 |
*/ |
318 |
protected void createTreeItem(Widget parent, Object element, int index) { |
319 |
Item item = newItem(parent, SWT.NULL, index); |
320 |
updateItem(item, element); |
321 |
updatePlus(item, element); |
322 |
} |
323 |
/** |
324 |
* The <code>AbstractTreeViewer</code> implementation of this method |
325 |
* also recurses over children of the corresponding element. |
326 |
*/ |
327 |
protected void disassociate(Item item) { |
328 |
super.disassociate(item); |
329 |
// recursively unmapping the items is only required when |
330 |
// the hash map is used. In the other case disposing |
331 |
// an item will recursively dispose its children. |
332 |
if (usingElementMap()) |
333 |
disassociateChildren(item); |
334 |
} |
335 |
/** |
336 |
* Disassociates the children of the given SWT item from their |
337 |
* corresponding elements. |
338 |
* |
339 |
* @param item the widget |
340 |
*/ |
341 |
private void disassociateChildren(Item item) { |
342 |
Item[] items = getChildren(item); |
343 |
for (int i = 0; i < items.length; i++) { |
344 |
if (items[i].getData() != null) |
345 |
disassociate(items[i]); |
346 |
} |
347 |
} |
348 |
/* (non-Javadoc) |
349 |
* Method declared on StructuredViewer. |
350 |
*/ |
351 |
protected Widget doFindInputItem(Object element) { |
352 |
// compare with root |
353 |
Object root= getRoot(); |
354 |
if (root == null) |
355 |
return null; |
356 |
|
175 |
|
357 |
if (equals(root, element)) |
176 |
/** |
358 |
return getControl(); |
177 |
* Go through the new elements as we need to |
359 |
return null; |
178 |
* create them in order to avoid ArrayIndexOutOfBounds |
360 |
} |
179 |
* exceptions. |
361 |
/* (non-Javadoc) |
180 |
*/ |
362 |
* Method declared on StructuredViewer. |
181 |
for (int i = 0; i < newElements.length; i++) { |
363 |
*/ |
182 |
|
364 |
protected Widget doFindItem(Object element) { |
183 |
//Check if this is a new one if not continue |
365 |
// compare with root |
184 |
if(indexOf(newElements[i],childElements) < 0) |
366 |
Object root= getRoot(); |
185 |
continue; |
367 |
if (root == null) |
186 |
|
368 |
return null; |
187 |
createTreeItem(widget, newElements[i], i); |
369 |
|
188 |
continue; |
370 |
Item[] items= getChildren(getControl()); |
|
|
371 |
if (items != null) { |
372 |
for (int i= 0; i < items.length; i++) { |
373 |
Widget o= internalFindItem(items[i], element); |
374 |
if (o != null) |
375 |
return o; |
376 |
} |
189 |
} |
377 |
} |
190 |
} |
378 |
return null; |
191 |
/** |
379 |
} |
192 |
* Adds the given child element to this viewer as a child of the given parent element. |
380 |
/** |
193 |
* If this viewer does not have a sorter, the element is added at the end of the |
381 |
* Copies the attributes of the given element into the given SWT item. |
194 |
* parent's list of children; otherwise, the element is inserted at the appropriate position. |
382 |
* |
195 |
* <p> |
383 |
* @param item the SWT item |
196 |
* This method should be called (by the content provider) when a single element |
384 |
* @param element the element |
197 |
* has been added to the model, in order to cause the viewer to accurately |
385 |
*/ |
198 |
* reflect the model. This method only affects the viewer, not the model. |
386 |
protected abstract void doUpdateItem(Item item, Object element); |
199 |
* Note that there is another method for efficiently processing the simultaneous |
387 |
/* (non-Javadoc) |
200 |
* addition of multiple elements. |
388 |
* Method declared on StructuredViewer. |
201 |
* </p> |
389 |
*/ |
202 |
* |
390 |
protected void doUpdateItem(Widget widget, Object element, boolean fullMap) { |
203 |
* @param parentElement the parent element |
391 |
if (widget instanceof Item) { |
204 |
* @param childElement the child element |
392 |
Item item = (Item) widget; |
205 |
*/ |
393 |
|
206 |
public void add(Object parentElement, Object childElement) { |
394 |
// ensure that backpointer is correct |
207 |
add(parentElement, new Object[] { childElement }); |
395 |
if (fullMap) { |
208 |
} |
396 |
associate(element, item); |
209 |
/** |
397 |
} else { |
210 |
* Adds the given SWT selection listener to the given SWT control. |
|
|
211 |
* |
212 |
* @param control the SWT control |
213 |
* @param listener the SWT selection listener |
214 |
* |
215 |
* @deprecated |
216 |
*/ |
217 |
protected void addSelectionListener( |
218 |
Control control, |
219 |
SelectionListener listener) { |
220 |
} |
221 |
/** |
222 |
* Adds a listener for expand and collapse events in this viewer. |
223 |
* Has no effect if an identical listener is already registered. |
224 |
* |
225 |
* @param listener a tree viewer listener |
226 |
*/ |
227 |
public void addTreeListener(ITreeViewerListener listener) { |
228 |
treeListeners.add(listener); |
229 |
} |
230 |
/** |
231 |
* Adds the given SWT tree listener to the given SWT control. |
232 |
* |
233 |
* @param control the SWT control |
234 |
* @param listener the SWT tree listener |
235 |
*/ |
236 |
protected abstract void addTreeListener( |
237 |
Control control, |
238 |
TreeListener listener); |
239 |
|
240 |
/* (non-Javadoc) |
241 |
* @see StructuredViewer#associate(Object, Item) |
242 |
*/ |
243 |
protected void associate(Object element, Item item) { |
244 |
Object data = item.getData(); |
245 |
if (data != null && data != element && equals(data, element)) { |
246 |
// workaround for PR 1FV62BT |
247 |
// assumption: elements are equal but not identical |
248 |
// -> remove from map but don't touch children |
249 |
unmapElement(data, item); |
398 |
item.setData(element); |
250 |
item.setData(element); |
399 |
mapElement(element, item); |
251 |
mapElement(element, item); |
|
|
252 |
} else { |
253 |
// recursively disassociate all |
254 |
super.associate(element, item); |
400 |
} |
255 |
} |
|
|
256 |
} |
401 |
|
257 |
|
402 |
// update icon and label |
258 |
/** |
403 |
safeUpdateItem.item = item; |
259 |
* Collapses all nodes of the viewer's tree, starting with the root. |
404 |
safeUpdateItem.element = element; |
260 |
* This method is equivalent to <code>collapseToLevel(ALL_LEVELS)</code>. |
405 |
try { |
261 |
*/ |
406 |
Platform.run(safeUpdateItem); |
262 |
public void collapseAll() { |
407 |
} |
263 |
collapseToLevel(getRoot(), ALL_LEVELS); |
408 |
finally { |
|
|
409 |
safeUpdateItem.item = null; |
410 |
safeUpdateItem.element = null; |
411 |
} |
412 |
} |
264 |
} |
413 |
} |
265 |
/** |
414 |
/** |
266 |
* Collapses the subtree rooted at the given element to the given level. |
415 |
* Expands all nodes of the viewer's tree, starting with the root. |
267 |
* |
416 |
* This method is equivalent to <code>expandToLevel(ALL_LEVELS)</code>. |
268 |
* @param element the element |
417 |
*/ |
269 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
418 |
public void expandAll() { |
270 |
* all levels of the tree |
419 |
expandToLevel(ALL_LEVELS); |
271 |
*/ |
420 |
} |
272 |
public void collapseToLevel(Object element, int level) { |
421 |
/** |
273 |
Widget w = findItem(element); |
422 |
* Expands the root of the viewer's tree to the given level. |
274 |
if (w != null) |
423 |
* |
275 |
internalCollapseToLevel(w, level); |
424 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
|
|
425 |
* all levels of the tree |
426 |
*/ |
427 |
public void expandToLevel(int level) { |
428 |
expandToLevel(getRoot(), level); |
429 |
} |
430 |
/** |
431 |
* Expands all ancestors of the given element so that the given element |
432 |
* becomes visible in this viewer's tree control, and then expands the |
433 |
* subtree rooted at the given element to the given level. |
434 |
* |
435 |
* @param element the element |
436 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
437 |
* all levels of the tree |
438 |
*/ |
439 |
public void expandToLevel(Object element, int level) { |
440 |
Widget w = internalExpand(element, true); |
441 |
if (w != null) |
442 |
internalExpandToLevel(w, level); |
443 |
} |
444 |
/** |
445 |
* Fires a tree collapsed event. |
446 |
* Only listeners registered at the time this method is called are notified. |
447 |
* |
448 |
* @param event the tree expansion event |
449 |
* |
450 |
* @see ITreeViewerListener#treeCollapsed |
451 |
*/ |
452 |
protected void fireTreeCollapsed(final TreeExpansionEvent event) { |
453 |
Object[] listeners = treeListeners.getListeners(); |
454 |
for (int i = 0; i < listeners.length; ++i) { |
455 |
final ITreeViewerListener l = (ITreeViewerListener)listeners[i]; |
456 |
Platform.run(new SafeRunnable() { |
457 |
public void run() { |
458 |
l.treeCollapsed(event); |
459 |
} |
460 |
public void handleException(Throwable e) { |
461 |
super.handleException(e); |
462 |
//If and unexpected exception happens, remove it |
463 |
//to make sure the application keeps running. |
464 |
removeTreeListener(l); |
465 |
} |
466 |
}); |
467 |
} |
276 |
} |
468 |
} |
277 |
/** |
469 |
/** |
278 |
* Creates all children for the given widget. |
470 |
* Fires a tree expanded event. |
279 |
* <p> |
471 |
* Only listeners registered at the time this method is called are notified. |
280 |
* The default implementation of this framework method assumes |
472 |
* |
281 |
* that <code>widget.getData()</code> returns the element corresponding |
473 |
* @param event the tree expansion event |
282 |
* to the node. Note: the node is not visually expanded! You may have to |
474 |
* |
283 |
* call <code>parent.setExpanded(true)</code>. |
475 |
* @see ITreeViewerListener#treeExpanded |
284 |
* </p> |
476 |
*/ |
285 |
* |
477 |
protected void fireTreeExpanded(final TreeExpansionEvent event) { |
286 |
* @param widget the widget |
478 |
Object[] listeners = treeListeners.getListeners(); |
287 |
*/ |
479 |
for (int i = 0; i < listeners.length; ++i) { |
288 |
protected void createChildren(final Widget widget) { |
480 |
final ITreeViewerListener l = (ITreeViewerListener)listeners[i]; |
289 |
final Item[] tis = getChildren(widget); |
481 |
Platform.run(new SafeRunnable() { |
290 |
if (tis != null && tis.length > 0) { |
|
|
291 |
Object data = tis[0].getData(); |
292 |
if (data != null) |
293 |
return; // children already there! |
294 |
} |
295 |
|
296 |
BusyIndicator.showWhile(widget.getDisplay(), new Runnable() { |
482 |
public void run() { |
297 |
public void run() { |
483 |
l.treeExpanded(event); |
298 |
// fix for PR 1FW89L7: |
|
|
299 |
// don't complain and remove all "dummies" ... |
300 |
if (tis != null) { |
301 |
for (int i = 0; i < tis.length; i++) { |
302 |
tis[i].dispose(); |
303 |
} |
304 |
} |
305 |
Object d = widget.getData(); |
306 |
if (d != null) { |
307 |
Object parentElement = d; |
308 |
Object[] children = getSortedChildren(parentElement); |
309 |
for (int i = 0; i < children.length; i++) { |
310 |
createTreeItem(widget, children[i], -1); |
311 |
} |
312 |
} |
484 |
} |
313 |
} |
485 |
public void handleException(Throwable e) { |
314 |
}); |
486 |
super.handleException(e); |
|
|
487 |
//If and unexpected exception happens, remove it |
488 |
//to make sure the application keeps running. |
489 |
removeTreeListener(l); |
490 |
} |
491 |
}); |
492 |
} |
493 |
|
494 |
} |
495 |
/** |
496 |
* Returns the auto-expand level. |
497 |
* |
498 |
* @return non-negative level, or <code>ALL_LEVELS</code> if |
499 |
* all levels of the tree are expanded automatically |
500 |
* @see #setAutoExpandLevel |
501 |
*/ |
502 |
public int getAutoExpandLevel() { |
503 |
return expandToLevel; |
504 |
} |
505 |
/** |
506 |
* Returns the SWT child items for the given SWT widget. |
507 |
* |
508 |
* @param widget the widget |
509 |
* @return the child items |
510 |
*/ |
511 |
protected abstract Item[] getChildren(Widget widget); |
512 |
/** |
513 |
* Returns whether the given SWT item is expanded or collapsed. |
514 |
* |
515 |
* @param item the item |
516 |
* @return <code>true</code> if the item is considered expanded |
517 |
* and <code>false</code> if collapsed |
518 |
*/ |
519 |
protected abstract boolean getExpanded(Item item); |
520 |
/** |
521 |
* Returns a list of elements corresponding to expanded nodes in this |
522 |
* viewer's tree, including currently hidden ones that are marked as |
523 |
* expanded but are under a collapsed ancestor. |
524 |
* <p> |
525 |
* This method is typically used when preserving the interesting |
526 |
* state of a viewer; <code>setExpandedElements</code> is used during the restore. |
527 |
* </p> |
528 |
* |
529 |
* @return the array of expanded elements |
530 |
* |
531 |
* @see #setExpandedElements |
532 |
*/ |
533 |
public Object[] getExpandedElements() { |
534 |
ArrayList v= new ArrayList(); |
535 |
internalCollectExpanded(v, getControl()); |
536 |
return v.toArray(); |
537 |
} |
538 |
/** |
539 |
* Returns whether the node corresponding to the given element is expanded or collapsed. |
540 |
* |
541 |
* @param element the element |
542 |
* @return <code>true</code> if the node is expanded, and <code>false</code> if collapsed |
543 |
*/ |
544 |
public boolean getExpandedState(Object element) { |
545 |
Widget item = findItem(element); |
546 |
if (item instanceof Item) |
547 |
return getExpanded((Item) item); |
548 |
return false; |
549 |
} |
550 |
/** |
551 |
* Returns the number of child items of the given SWT control. |
552 |
* |
553 |
* @param control the control |
554 |
* @return the number of children |
555 |
*/ |
556 |
protected abstract int getItemCount(Control control); |
557 |
/** |
558 |
* Returns the number of child items of the given SWT item. |
559 |
* |
560 |
* @param item the item |
561 |
* @return the number of children |
562 |
*/ |
563 |
protected abstract int getItemCount(Item item); |
564 |
/** |
565 |
* Returns the child items of the given SWT item. |
566 |
* |
567 |
* @param item the item |
568 |
* @return the child items |
569 |
*/ |
570 |
protected abstract Item[] getItems(Item item); |
571 |
/** |
572 |
* Returns the item after the given item in the tree, or |
573 |
* <code>null</code> if there is no next item. |
574 |
* |
575 |
* @param item the item |
576 |
* @param includeChildren <code>true</code> if the children are |
577 |
* considered in determining which item is next, and <code>false</code> |
578 |
* if subtrees are ignored |
579 |
* @return the next item, or <code>null</code> if none |
580 |
*/ |
581 |
protected Item getNextItem(Item item, boolean includeChildren) { |
582 |
if (item == null) { |
583 |
return null; |
584 |
} |
315 |
} |
585 |
if (includeChildren && getExpanded(item)) { |
316 |
/** |
586 |
Item[] children = getItems(item); |
317 |
* Creates a single item for the given parent and synchronizes it with |
587 |
if (children != null && children.length > 0) { |
318 |
* the given element. |
588 |
return children[0]; |
319 |
* |
|
|
320 |
* @param parent the parent widget |
321 |
* @param element the element |
322 |
* @param index if non-negative, indicates the position to insert the item |
323 |
* into its parent |
324 |
*/ |
325 |
protected void createTreeItem(Widget parent, Object element, int index) { |
326 |
Item item = newItem(parent, SWT.NULL, index); |
327 |
updateItem(item, element); |
328 |
updatePlus(item, element); |
329 |
} |
330 |
/** |
331 |
* The <code>AbstractTreeViewer</code> implementation of this method |
332 |
* also recurses over children of the corresponding element. |
333 |
*/ |
334 |
protected void disassociate(Item item) { |
335 |
super.disassociate(item); |
336 |
// recursively unmapping the items is only required when |
337 |
// the hash map is used. In the other case disposing |
338 |
// an item will recursively dispose its children. |
339 |
if (usingElementMap()) |
340 |
disassociateChildren(item); |
341 |
} |
342 |
/** |
343 |
* Disassociates the children of the given SWT item from their |
344 |
* corresponding elements. |
345 |
* |
346 |
* @param item the widget |
347 |
*/ |
348 |
private void disassociateChildren(Item item) { |
349 |
Item[] items = getChildren(item); |
350 |
for (int i = 0; i < items.length; i++) { |
351 |
if (items[i].getData() != null) |
352 |
disassociate(items[i]); |
589 |
} |
353 |
} |
590 |
} |
354 |
} |
|
|
355 |
/* (non-Javadoc) |
356 |
* Method declared on StructuredViewer. |
357 |
*/ |
358 |
protected Widget doFindInputItem(Object element) { |
359 |
// compare with root |
360 |
Object root = getRoot(); |
361 |
if (root == null) |
362 |
return null; |
591 |
|
363 |
|
592 |
//next item is either next sibling or next sibling of first |
364 |
if (equals(root, element)) |
593 |
//parent that has a next sibling. |
365 |
return getControl(); |
594 |
Item parent = getParentItem(item); |
|
|
595 |
if (parent == null) { |
596 |
return null; |
366 |
return null; |
597 |
} |
367 |
} |
598 |
Item[] siblings = getItems(parent); |
368 |
/* (non-Javadoc) |
599 |
if (siblings != null && siblings.length <= 1) { |
369 |
* Method declared on StructuredViewer. |
600 |
return getNextItem(parent, false); |
370 |
*/ |
601 |
} |
371 |
protected Widget doFindItem(Object element) { |
602 |
for (int i = 0; i < siblings.length; i++) { |
372 |
// compare with root |
603 |
if (siblings[i] == item && i < (siblings.length - 1)) { |
373 |
Object root = getRoot(); |
604 |
return siblings[i+1]; |
374 |
if (root == null) |
|
|
375 |
return null; |
376 |
|
377 |
Item[] items = getChildren(getControl()); |
378 |
if (items != null) { |
379 |
for (int i = 0; i < items.length; i++) { |
380 |
Widget o = internalFindItem(items[i], element); |
381 |
if (o != null) |
382 |
return o; |
383 |
} |
605 |
} |
384 |
} |
606 |
} |
|
|
607 |
return getNextItem(parent, false); |
608 |
} |
609 |
/** |
610 |
* Returns the parent item of the given item in the tree, or |
611 |
* <code>null</code> if there is parent item. |
612 |
* |
613 |
* @param item the item |
614 |
* @return the parent item, or <code>null</code> if none |
615 |
*/ |
616 |
protected abstract Item getParentItem(Item item); |
617 |
/** |
618 |
* Returns the item before the given item in the tree, or |
619 |
* <code>null</code> if there is no previous item. |
620 |
* |
621 |
* @param item the item |
622 |
* @return the previous item, or <code>null</code> if none |
623 |
*/ |
624 |
protected Item getPreviousItem(Item item) { |
625 |
//previous item is either right-most visible descendent of previous |
626 |
//sibling or parent |
627 |
Item parent = getParentItem(item); |
628 |
if (parent == null) { |
629 |
return null; |
385 |
return null; |
630 |
} |
386 |
} |
631 |
Item[] siblings = getItems(parent); |
387 |
/** |
632 |
if (siblings.length == 0 || siblings[0] == item) { |
388 |
* Copies the attributes of the given element into the given SWT item. |
633 |
return parent; |
389 |
* |
634 |
} |
390 |
* @param item the SWT item |
635 |
Item previous = siblings[0]; |
391 |
* @param element the element |
636 |
for (int i = 1; i < siblings.length; i++) { |
392 |
*/ |
637 |
if (siblings[i] == item) { |
393 |
protected abstract void doUpdateItem(Item item, Object element); |
638 |
return rightMostVisibleDescendent(previous); |
394 |
/* (non-Javadoc) |
639 |
} |
395 |
* Method declared on StructuredViewer. |
640 |
previous = siblings[i]; |
396 |
*/ |
641 |
} |
397 |
protected void doUpdateItem( |
642 |
return null; |
398 |
Widget widget, |
643 |
} |
399 |
Object element, |
644 |
/* (non-Javadoc) |
400 |
boolean fullMap) { |
645 |
* Method declared on StructuredViewer. |
401 |
if (widget instanceof Item) { |
646 |
*/ |
402 |
Item item = (Item) widget; |
647 |
protected Object[] getRawChildren(Object parent) { |
403 |
|
648 |
if (parent != null) { |
404 |
// ensure that backpointer is correct |
649 |
if (equals(parent, getRoot())) |
405 |
if (fullMap) { |
650 |
return super.getRawChildren(parent); |
406 |
associate(element, item); |
651 |
ITreeContentProvider cp = (ITreeContentProvider) getContentProvider(); |
407 |
} else { |
652 |
if (cp != null) { |
408 |
item.setData(element); |
653 |
Object[] result = cp.getChildren(parent); |
409 |
mapElement(element, item); |
654 |
if (result != null) |
410 |
} |
655 |
return result; |
411 |
|
|
|
412 |
// update icon and label |
413 |
safeUpdateItem.item = item; |
414 |
safeUpdateItem.element = element; |
415 |
try { |
416 |
Platform.run(safeUpdateItem); |
417 |
} finally { |
418 |
safeUpdateItem.item = null; |
419 |
safeUpdateItem.element = null; |
420 |
} |
656 |
} |
421 |
} |
657 |
} |
422 |
} |
658 |
return new Object[0]; |
423 |
/** |
659 |
} |
424 |
* Expands all nodes of the viewer's tree, starting with the root. |
660 |
/** |
425 |
* This method is equivalent to <code>expandToLevel(ALL_LEVELS)</code>. |
661 |
* Returns all selected items for the given SWT control. |
426 |
*/ |
662 |
* |
427 |
public void expandAll() { |
663 |
* @param control the control |
428 |
expandToLevel(ALL_LEVELS); |
664 |
* @return the list of selected items |
|
|
665 |
*/ |
666 |
protected abstract Item[] getSelection(Control control); |
667 |
/* (non-Javadoc) |
668 |
* Method declared on StructuredViewer. |
669 |
*/ |
670 |
protected List getSelectionFromWidget() { |
671 |
Widget[] items = getSelection(getControl()); |
672 |
ArrayList list = new ArrayList(items.length); |
673 |
for (int i = 0; i < items.length; i++) { |
674 |
Widget item = items[i]; |
675 |
Object e = item.getData(); |
676 |
if (e != null) |
677 |
list.add(e); |
678 |
} |
429 |
} |
679 |
return list; |
430 |
/** |
680 |
} |
431 |
* Expands the root of the viewer's tree to the given level. |
681 |
/** |
432 |
* |
682 |
* Handles a tree collapse event from the SWT widget. |
433 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
683 |
* |
434 |
* all levels of the tree |
684 |
* @param event the SWT tree event |
435 |
*/ |
685 |
*/ |
436 |
public void expandToLevel(int level) { |
686 |
protected void handleTreeCollapse(TreeEvent event) { |
437 |
expandToLevel(getRoot(), level); |
687 |
if (event.item.getData() != null) { |
|
|
688 |
fireTreeCollapsed(new TreeExpansionEvent(this, event.item.getData())); |
689 |
} |
438 |
} |
690 |
} |
439 |
/** |
691 |
/** |
440 |
* Expands all ancestors of the given element so that the given element |
692 |
* Handles a tree expand event from the SWT widget. |
441 |
* becomes visible in this viewer's tree control, and then expands the |
693 |
* |
442 |
* subtree rooted at the given element to the given level. |
694 |
* @param event the SWT tree event |
443 |
* |
695 |
*/ |
444 |
* @param element the element |
696 |
protected void handleTreeExpand(TreeEvent event) { |
445 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
697 |
createChildren(event.item); |
446 |
* all levels of the tree |
698 |
if (event.item.getData() != null) { |
447 |
*/ |
699 |
fireTreeExpanded(new TreeExpansionEvent(this, event.item.getData())); |
448 |
public void expandToLevel(Object element, int level) { |
700 |
} |
449 |
Widget w = internalExpand(element, true); |
701 |
} |
450 |
if (w != null) |
702 |
/* (non-Javadoc) |
451 |
internalExpandToLevel(w, level); |
703 |
* Method declared on Viewer. |
|
|
704 |
*/ |
705 |
protected void hookControl(Control control) { |
706 |
super.hookControl(control); |
707 |
addTreeListener(control,new TreeListener() { |
708 |
public void treeExpanded(TreeEvent event) { |
709 |
handleTreeExpand(event); |
710 |
} |
711 |
public void treeCollapsed(TreeEvent event) { |
712 |
handleTreeCollapse(event); |
713 |
} |
714 |
}); |
715 |
} |
716 |
/* (non-Javadoc) |
717 |
* Method declared on StructuredViewer. |
718 |
* Builds the initial tree and handles the automatic expand feature. |
719 |
*/ |
720 |
protected void inputChanged(Object input, Object oldInput) { |
721 |
preservingSelection(new Runnable() { |
722 |
public void run() { |
723 |
Control tree = getControl(); |
724 |
boolean useRedraw = true; // (size > REDRAW_THRESHOLD) || (table.getItemCount() > REDRAW_THRESHOLD); |
725 |
if (useRedraw) |
726 |
tree.setRedraw(false); |
727 |
removeAll(tree); |
728 |
tree.setData(getRoot()); |
729 |
createChildren(tree); |
730 |
internalExpandToLevel(tree, expandToLevel); |
731 |
if (useRedraw) |
732 |
tree.setRedraw(true); |
733 |
} |
734 |
}); |
735 |
} |
736 |
/** |
737 |
* Recursively collapses the subtree rooted at the given widget to the |
738 |
* given level. |
739 |
* <p> |
740 |
* </p> |
741 |
* Note that the default implementation of this method does not call |
742 |
* <code>setRedraw</code>. |
743 |
* |
744 |
* @param widget the widget |
745 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
746 |
* all levels of the tree |
747 |
*/ |
748 |
protected void internalCollapseToLevel(Widget widget, int level) { |
749 |
if (level == ALL_LEVELS || level > 0) { |
750 |
|
751 |
if (widget instanceof Item) |
752 |
setExpanded((Item) widget, false); |
753 |
|
754 |
if (level == ALL_LEVELS || level > 1) { |
755 |
Item[] children = getChildren(widget); |
756 |
if (children != null) { |
757 |
int nextLevel = (level == ALL_LEVELS ? ALL_LEVELS : level - 1); |
758 |
for (int i = 0; i < children.length; i++) |
759 |
internalCollapseToLevel(children[i], nextLevel); |
760 |
} |
761 |
} |
762 |
} |
452 |
} |
763 |
} |
453 |
/** |
764 |
/** |
454 |
* Fires a tree collapsed event. |
765 |
* Recursively collects all expanded elements from the given widget. |
455 |
* Only listeners registered at the time this method is called are notified. |
766 |
* |
456 |
* |
767 |
* @param result a list (element type: <code>Object</code>) into which |
457 |
* @param event the tree expansion event |
768 |
* to collect the elements |
458 |
* |
769 |
* @param widget the widget |
459 |
* @see ITreeViewerListener#treeCollapsed |
770 |
*/ |
460 |
*/ |
771 |
private void internalCollectExpanded(List result, Widget widget) { |
461 |
protected void fireTreeCollapsed(final TreeExpansionEvent event) { |
772 |
Item[] items = getChildren(widget); |
462 |
Object[] listeners = treeListeners.getListeners(); |
773 |
for (int i = 0; i < items.length; i++) { |
463 |
for (int i = 0; i < listeners.length; ++i) { |
774 |
Item item = items[i]; |
464 |
final ITreeViewerListener l = (ITreeViewerListener) listeners[i]; |
775 |
if (getExpanded(item)) { |
465 |
Platform.run(new SafeRunnable() { |
776 |
Object data = item.getData(); |
466 |
public void run() { |
777 |
if (data != null) |
467 |
l.treeCollapsed(event); |
778 |
result.add(data); |
468 |
} |
|
|
469 |
public void handleException(Throwable e) { |
470 |
super.handleException(e); |
471 |
//If and unexpected exception happens, remove it |
472 |
//to make sure the application keeps running. |
473 |
removeTreeListener(l); |
474 |
} |
475 |
}); |
779 |
} |
476 |
} |
780 |
internalCollectExpanded(result, item); |
|
|
781 |
} |
477 |
} |
782 |
} |
478 |
/** |
783 |
/** |
479 |
* Fires a tree expanded event. |
784 |
* Tries to create a path of tree items for the given element. |
480 |
* Only listeners registered at the time this method is called are notified. |
785 |
* This method recursively walks up towards the root of the tree |
481 |
* |
786 |
* and assumes that <code>getParent</code> returns the correct |
482 |
* @param event the tree expansion event |
787 |
* parent of an element. |
483 |
* |
788 |
* |
484 |
* @see ITreeViewerListener#treeExpanded |
789 |
* @param element the element |
485 |
*/ |
790 |
* @param expand <code>true</code> if all nodes on the path should be expanded, |
486 |
protected void fireTreeExpanded(final TreeExpansionEvent event) { |
791 |
* and <code>false</code> otherwise |
487 |
Object[] listeners = treeListeners.getListeners(); |
792 |
*/ |
488 |
for (int i = 0; i < listeners.length; ++i) { |
793 |
protected Widget internalExpand(Object element, boolean expand) { |
489 |
final ITreeViewerListener l = (ITreeViewerListener) listeners[i]; |
794 |
|
490 |
Platform.run(new SafeRunnable() { |
795 |
if (element == null) |
491 |
public void run() { |
796 |
return null; |
492 |
l.treeExpanded(event); |
797 |
|
|
|
798 |
Widget w= findItem(element); |
799 |
if (w == null) { |
800 |
if (equals(element, getRoot())) { // stop at root |
801 |
return null; |
802 |
} |
803 |
// my parent has to create me |
804 |
ITreeContentProvider cp = (ITreeContentProvider) getContentProvider(); |
805 |
if (cp == null) { |
806 |
return null; |
807 |
} |
808 |
Object parent= cp.getParent(element); |
809 |
if (parent != null) { |
810 |
Widget pw= internalExpand(parent, expand); |
811 |
if (pw != null) { |
812 |
// let my parent create me |
813 |
createChildren(pw); |
814 |
// expand parent and find me |
815 |
if (pw instanceof Item) { |
816 |
Item item= (Item)pw; |
817 |
if (expand) |
818 |
setExpanded(item, true); |
819 |
w= internalFindChild(item, element); |
820 |
} |
493 |
} |
821 |
} |
494 |
public void handleException(Throwable e) { |
|
|
495 |
super.handleException(e); |
496 |
//If and unexpected exception happens, remove it |
497 |
//to make sure the application keeps running. |
498 |
removeTreeListener(l); |
499 |
} |
500 |
}); |
822 |
} |
501 |
} |
|
|
502 |
|
823 |
} |
503 |
} |
824 |
return w; |
504 |
/** |
825 |
} |
505 |
* Returns the auto-expand level. |
826 |
/** |
506 |
* |
827 |
* Recursively expands the subtree rooted at the given widget to the |
507 |
* @return non-negative level, or <code>ALL_LEVELS</code> if |
828 |
* given level. |
508 |
* all levels of the tree are expanded automatically |
829 |
* <p> |
509 |
* @see #setAutoExpandLevel |
830 |
* </p> |
510 |
*/ |
831 |
* Note that the default implementation of this method does not call |
511 |
public int getAutoExpandLevel() { |
832 |
* <code>setRedraw</code>. |
512 |
return expandToLevel; |
833 |
* |
|
|
834 |
* @param widget the widget |
835 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
836 |
* all levels of the tree |
837 |
*/ |
838 |
protected void internalExpandToLevel(Widget widget, int level) { |
839 |
if (level == ALL_LEVELS || level > 0) { |
840 |
createChildren(widget); |
841 |
if (widget instanceof Item) |
842 |
setExpanded((Item) widget, true); |
843 |
if (level == ALL_LEVELS || level > 1) { |
844 |
Item[] children = getChildren(widget); |
845 |
if (children != null) { |
846 |
int newLevel = (level == ALL_LEVELS ? ALL_LEVELS : level - 1); |
847 |
for (int i = 0; i < children.length; i++) |
848 |
internalExpandToLevel(children[i], newLevel); |
849 |
} |
850 |
} |
851 |
} |
513 |
} |
852 |
} |
514 |
/** |
853 |
/** |
515 |
* Returns the SWT child items for the given SWT widget. |
854 |
* Non-recursively tries to find the given element as a child of the given parent item. |
516 |
* |
855 |
* |
517 |
* @param widget the widget |
856 |
* @param parent the parent item |
518 |
* @return the child items |
857 |
* @param element the element |
519 |
*/ |
858 |
*/ |
520 |
protected abstract Item[] getChildren(Widget widget); |
859 |
private Widget internalFindChild(Item parent, Object element) { |
521 |
/** |
860 |
Item[] items = getChildren(parent); |
522 |
* Returns whether the given SWT item is expanded or collapsed. |
861 |
for (int i = 0; i < items.length; i++) { |
523 |
* |
862 |
Item item = items[i]; |
524 |
* @param item the item |
863 |
Object data = item.getData(); |
525 |
* @return <code>true</code> if the item is considered expanded |
864 |
if (data != null && equals(data, element)) |
526 |
* and <code>false</code> if collapsed |
865 |
return item; |
527 |
*/ |
|
|
528 |
protected abstract boolean getExpanded(Item item); |
529 |
/** |
530 |
* Returns a list of elements corresponding to expanded nodes in this |
531 |
* viewer's tree, including currently hidden ones that are marked as |
532 |
* expanded but are under a collapsed ancestor. |
533 |
* <p> |
534 |
* This method is typically used when preserving the interesting |
535 |
* state of a viewer; <code>setExpandedElements</code> is used during the restore. |
536 |
* </p> |
537 |
* |
538 |
* @return the array of expanded elements |
539 |
* |
540 |
* @see #setExpandedElements |
541 |
*/ |
542 |
public Object[] getExpandedElements() { |
543 |
ArrayList v = new ArrayList(); |
544 |
internalCollectExpanded(v, getControl()); |
545 |
return v.toArray(); |
866 |
} |
546 |
} |
867 |
return null; |
547 |
/** |
868 |
} |
548 |
* Returns whether the node corresponding to the given element is expanded or collapsed. |
869 |
/** |
549 |
* |
870 |
* Recursively tries to find the given element. |
550 |
* @param element the element |
871 |
* |
551 |
* @return <code>true</code> if the node is expanded, and <code>false</code> if collapsed |
872 |
* @param parent the parent item |
552 |
*/ |
873 |
* @param element the element |
553 |
public boolean getExpandedState(Object element) { |
874 |
*/ |
554 |
Widget item = findItem(element); |
875 |
private Widget internalFindItem(Item parent, Object element) { |
555 |
if (item instanceof Item) |
|
|
556 |
return getExpanded((Item) item); |
557 |
return false; |
558 |
} |
559 |
/** |
560 |
* Returns the number of child items of the given SWT control. |
561 |
* |
562 |
* @param control the control |
563 |
* @return the number of children |
564 |
*/ |
565 |
protected abstract int getItemCount(Control control); |
566 |
/** |
567 |
* Returns the number of child items of the given SWT item. |
568 |
* |
569 |
* @param item the item |
570 |
* @return the number of children |
571 |
*/ |
572 |
protected abstract int getItemCount(Item item); |
573 |
/** |
574 |
* Returns the child items of the given SWT item. |
575 |
* |
576 |
* @param item the item |
577 |
* @return the child items |
578 |
*/ |
579 |
protected abstract Item[] getItems(Item item); |
580 |
/** |
581 |
* Returns the item after the given item in the tree, or |
582 |
* <code>null</code> if there is no next item. |
583 |
* |
584 |
* @param item the item |
585 |
* @param includeChildren <code>true</code> if the children are |
586 |
* considered in determining which item is next, and <code>false</code> |
587 |
* if subtrees are ignored |
588 |
* @return the next item, or <code>null</code> if none |
589 |
*/ |
590 |
protected Item getNextItem(Item item, boolean includeChildren) { |
591 |
if (item == null) { |
592 |
return null; |
593 |
} |
594 |
if (includeChildren && getExpanded(item)) { |
595 |
Item[] children = getItems(item); |
596 |
if (children != null && children.length > 0) { |
597 |
return children[0]; |
598 |
} |
599 |
} |
876 |
|
600 |
|
877 |
// compare with node |
601 |
//next item is either next sibling or next sibling of first |
878 |
Object data= parent.getData(); |
602 |
//parent that has a next sibling. |
879 |
if (data != null) { |
603 |
Item parent = getParentItem(item); |
880 |
if (equals(data, element)) |
604 |
if (parent == null) { |
|
|
605 |
return null; |
606 |
} |
607 |
Item[] siblings = getItems(parent); |
608 |
if (siblings != null && siblings.length <= 1) { |
609 |
return getNextItem(parent, false); |
610 |
} |
611 |
for (int i = 0; i < siblings.length; i++) { |
612 |
if (siblings[i] == item && i < (siblings.length - 1)) { |
613 |
return siblings[i + 1]; |
614 |
} |
615 |
} |
616 |
return getNextItem(parent, false); |
617 |
} |
618 |
/** |
619 |
* Returns the parent item of the given item in the tree, or |
620 |
* <code>null</code> if there is parent item. |
621 |
* |
622 |
* @param item the item |
623 |
* @return the parent item, or <code>null</code> if none |
624 |
*/ |
625 |
protected abstract Item getParentItem(Item item); |
626 |
/** |
627 |
* Returns the item before the given item in the tree, or |
628 |
* <code>null</code> if there is no previous item. |
629 |
* |
630 |
* @param item the item |
631 |
* @return the previous item, or <code>null</code> if none |
632 |
*/ |
633 |
protected Item getPreviousItem(Item item) { |
634 |
//previous item is either right-most visible descendent of previous |
635 |
//sibling or parent |
636 |
Item parent = getParentItem(item); |
637 |
if (parent == null) { |
638 |
return null; |
639 |
} |
640 |
Item[] siblings = getItems(parent); |
641 |
if (siblings.length == 0 || siblings[0] == item) { |
881 |
return parent; |
642 |
return parent; |
|
|
643 |
} |
644 |
Item previous = siblings[0]; |
645 |
for (int i = 1; i < siblings.length; i++) { |
646 |
if (siblings[i] == item) { |
647 |
return rightMostVisibleDescendent(previous); |
648 |
} |
649 |
previous = siblings[i]; |
650 |
} |
651 |
return null; |
882 |
} |
652 |
} |
883 |
// recurse over children |
653 |
/* (non-Javadoc) |
884 |
Item[] items= getChildren(parent); |
654 |
* Method declared on StructuredViewer. |
885 |
for (int i= 0; i < items.length; i++) { |
655 |
*/ |
886 |
Item item= items[i]; |
656 |
protected Object[] getRawChildren(Object parent) { |
887 |
Widget o= internalFindItem(item, element); |
657 |
if (parent != null) { |
888 |
if (o != null) |
658 |
if (equals(parent, getRoot())) |
889 |
return o; |
659 |
return super.getRawChildren(parent); |
890 |
} |
660 |
ITreeContentProvider cp = |
891 |
return null; |
661 |
(ITreeContentProvider) getContentProvider(); |
892 |
} |
662 |
if (cp != null) { |
893 |
/* (non-Javadoc) |
663 |
Object[] result = cp.getChildren(parent); |
894 |
* Method declared on StructuredViewer. |
664 |
if (result != null) |
895 |
*/ |
665 |
return result; |
896 |
protected void internalRefresh(Object element) { |
666 |
} |
897 |
internalRefresh(element, true); |
667 |
} |
898 |
} |
668 |
return new Object[0]; |
899 |
/* (non-Javadoc) |
|
|
900 |
* Method declared on StructuredViewer. |
901 |
*/ |
902 |
protected void internalRefresh(Object element, boolean updateLabels) { |
903 |
// If element is null, do a full refresh. |
904 |
if (element == null) { |
905 |
internalRefresh(getControl(), getRoot(), true, updateLabels); |
906 |
return; |
907 |
} |
908 |
Widget item = findItem(element); |
909 |
if (item != null) { |
910 |
// pick up structure changes too |
911 |
internalRefresh(item, element, true, updateLabels); |
912 |
} |
669 |
} |
913 |
} |
670 |
/** |
914 |
/** |
671 |
* Returns all selected items for the given SWT control. |
915 |
* Refreshes the tree starting at the given widget. |
672 |
* |
916 |
* |
673 |
* @param control the control |
917 |
* @param widget the widget |
674 |
* @return the list of selected items |
918 |
* @param element the element |
675 |
*/ |
919 |
* @param doStruct <code>true</code> if structural changes are to be picked up, |
676 |
protected abstract Item[] getSelection(Control control); |
920 |
* and <code>false</code> if only label provider changes are of interest |
677 |
/* (non-Javadoc) |
921 |
* @param updateLabels <code>true</code> to update labels for existing elements, |
678 |
* Method declared on StructuredViewer. |
922 |
* <code>false</code> to only update labels as needed, assuming that labels |
679 |
*/ |
923 |
* for existing elements are unchanged. |
680 |
protected List getSelectionFromWidget() { |
924 |
*/ |
681 |
Widget[] items = getSelection(getControl()); |
925 |
private void internalRefresh(Widget widget, Object element, boolean doStruct, boolean updateLabels) { |
682 |
ArrayList list = new ArrayList(items.length); |
926 |
|
683 |
for (int i = 0; i < items.length; i++) { |
927 |
if (widget instanceof Item) { |
684 |
Widget item = items[i]; |
928 |
if (doStruct) { |
685 |
Object e = item.getData(); |
929 |
updatePlus((Item)widget, element); |
686 |
if (e != null) |
930 |
} |
687 |
list.add(e); |
931 |
if (updateLabels || !equals(element, widget.getData())) { |
|
|
932 |
doUpdateItem(widget, element, true); |
933 |
} |
688 |
} |
934 |
else { |
689 |
return list; |
935 |
associate(element, (Item) widget); |
690 |
} |
|
|
691 |
/** |
692 |
* Handles a tree collapse event from the SWT widget. |
693 |
* |
694 |
* @param event the SWT tree event |
695 |
*/ |
696 |
protected void handleTreeCollapse(TreeEvent event) { |
697 |
if (event.item.getData() != null) { |
698 |
fireTreeCollapsed( |
699 |
new TreeExpansionEvent(this, event.item.getData())); |
936 |
} |
700 |
} |
937 |
} |
701 |
} |
|
|
702 |
/** |
703 |
* Handles a tree expand event from the SWT widget. |
704 |
* |
705 |
* @param event the SWT tree event |
706 |
*/ |
707 |
protected void handleTreeExpand(TreeEvent event) { |
708 |
createChildren(event.item); |
709 |
if (event.item.getData() != null) { |
710 |
fireTreeExpanded( |
711 |
new TreeExpansionEvent(this, event.item.getData())); |
712 |
} |
713 |
} |
714 |
/* (non-Javadoc) |
715 |
* Method declared on Viewer. |
716 |
*/ |
717 |
protected void hookControl(Control control) { |
718 |
super.hookControl(control); |
719 |
addTreeListener(control, new TreeListener() { |
720 |
public void treeExpanded(TreeEvent event) { |
721 |
handleTreeExpand(event); |
722 |
} |
723 |
public void treeCollapsed(TreeEvent event) { |
724 |
handleTreeCollapse(event); |
725 |
} |
726 |
}); |
727 |
} |
728 |
/* (non-Javadoc) |
729 |
* Method declared on StructuredViewer. |
730 |
* Builds the initial tree and handles the automatic expand feature. |
731 |
*/ |
732 |
protected void inputChanged(Object input, Object oldInput) { |
733 |
preservingSelection(new Runnable() { |
734 |
public void run() { |
735 |
Control tree = getControl(); |
736 |
boolean useRedraw = true; |
737 |
// (size > REDRAW_THRESHOLD) || (table.getItemCount() > REDRAW_THRESHOLD); |
738 |
if (useRedraw) |
739 |
tree.setRedraw(false); |
740 |
removeAll(tree); |
741 |
tree.setData(getRoot()); |
742 |
createChildren(tree); |
743 |
internalExpandToLevel(tree, expandToLevel); |
744 |
if (useRedraw) |
745 |
tree.setRedraw(true); |
746 |
} |
747 |
}); |
748 |
} |
749 |
/** |
750 |
* Recursively collapses the subtree rooted at the given widget to the |
751 |
* given level. |
752 |
* <p> |
753 |
* </p> |
754 |
* Note that the default implementation of this method does not call |
755 |
* <code>setRedraw</code>. |
756 |
* |
757 |
* @param widget the widget |
758 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
759 |
* all levels of the tree |
760 |
*/ |
761 |
protected void internalCollapseToLevel(Widget widget, int level) { |
762 |
if (level == ALL_LEVELS || level > 0) { |
763 |
|
764 |
if (widget instanceof Item) |
765 |
setExpanded((Item) widget, false); |
938 |
|
766 |
|
939 |
if (doStruct) { |
767 |
if (level == ALL_LEVELS || level > 1) { |
940 |
internalRefreshStruct(widget, element, updateLabels); |
768 |
Item[] children = getChildren(widget); |
|
|
769 |
if (children != null) { |
770 |
int nextLevel = |
771 |
(level == ALL_LEVELS ? ALL_LEVELS : level - 1); |
772 |
for (int i = 0; i < children.length; i++) |
773 |
internalCollapseToLevel(children[i], nextLevel); |
774 |
} |
775 |
} |
776 |
} |
941 |
} |
777 |
} |
942 |
else { |
778 |
/** |
943 |
Item[] children= getChildren(widget); |
779 |
* Recursively collects all expanded elements from the given widget. |
944 |
if (children != null) { |
780 |
* |
945 |
for (int i= 0; i < children.length; i++) { |
781 |
* @param result a list (element type: <code>Object</code>) into which |
946 |
Widget item= children[i]; |
782 |
* to collect the elements |
947 |
Object data= item.getData(); |
783 |
* @param widget the widget |
|
|
784 |
*/ |
785 |
private void internalCollectExpanded(List result, Widget widget) { |
786 |
Item[] items = getChildren(widget); |
787 |
for (int i = 0; i < items.length; i++) { |
788 |
Item item = items[i]; |
789 |
if (getExpanded(item)) { |
790 |
Object data = item.getData(); |
948 |
if (data != null) |
791 |
if (data != null) |
949 |
internalRefresh(item, data, doStruct, updateLabels); |
792 |
result.add(data); |
950 |
} |
793 |
} |
|
|
794 |
internalCollectExpanded(result, item); |
951 |
} |
795 |
} |
952 |
} |
796 |
} |
953 |
} |
797 |
/** |
|
|
798 |
* Tries to create a path of tree items for the given element. |
799 |
* This method recursively walks up towards the root of the tree |
800 |
* and assumes that <code>getParent</code> returns the correct |
801 |
* parent of an element. |
802 |
* |
803 |
* @param element the element |
804 |
* @param expand <code>true</code> if all nodes on the path should be expanded, |
805 |
* and <code>false</code> otherwise |
806 |
*/ |
807 |
protected Widget internalExpand(Object element, boolean expand) { |
954 |
|
808 |
|
955 |
/** |
809 |
if (element == null) |
956 |
* Update the structure and recurse. |
810 |
return null; |
957 |
* Items are updated in updateChildren, as needed. |
811 |
|
958 |
*/ |
812 |
Widget w = findItem(element); |
959 |
private void internalRefreshStruct(Widget widget, Object element, boolean updateLabels) { |
813 |
if (w == null) { |
960 |
updateChildren(widget, element, null, updateLabels); |
814 |
if (equals(element, getRoot())) { // stop at root |
961 |
Item[] children= getChildren(widget); |
815 |
return null; |
962 |
if (children != null) { |
816 |
} |
963 |
for (int i= 0; i < children.length; i++) { |
817 |
// my parent has to create me |
964 |
Widget item= children[i]; |
818 |
ITreeContentProvider cp = |
965 |
Object data= item.getData(); |
819 |
(ITreeContentProvider) getContentProvider(); |
966 |
if (data != null) |
820 |
if (cp == null) { |
967 |
internalRefreshStruct(item, data, updateLabels); |
821 |
return null; |
|
|
822 |
} |
823 |
Object parent = cp.getParent(element); |
824 |
if (parent != null) { |
825 |
Widget pw = internalExpand(parent, expand); |
826 |
if (pw != null) { |
827 |
// let my parent create me |
828 |
createChildren(pw); |
829 |
// expand parent and find me |
830 |
if (pw instanceof Item) { |
831 |
Item item = (Item) pw; |
832 |
if (expand) |
833 |
setExpanded(item, true); |
834 |
w = internalFindChild(item, element); |
835 |
} |
836 |
} |
837 |
} |
838 |
} |
839 |
return w; |
840 |
} |
841 |
/** |
842 |
* Recursively expands the subtree rooted at the given widget to the |
843 |
* given level. |
844 |
* <p> |
845 |
* </p> |
846 |
* Note that the default implementation of this method does not call |
847 |
* <code>setRedraw</code>. |
848 |
* |
849 |
* @param widget the widget |
850 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to collapse |
851 |
* all levels of the tree |
852 |
*/ |
853 |
protected void internalExpandToLevel(Widget widget, int level) { |
854 |
if (level == ALL_LEVELS || level > 0) { |
855 |
createChildren(widget); |
856 |
if (widget instanceof Item) |
857 |
setExpanded((Item) widget, true); |
858 |
if (level == ALL_LEVELS || level > 1) { |
859 |
Item[] children = getChildren(widget); |
860 |
if (children != null) { |
861 |
int newLevel = |
862 |
(level == ALL_LEVELS ? ALL_LEVELS : level - 1); |
863 |
for (int i = 0; i < children.length; i++) |
864 |
internalExpandToLevel(children[i], newLevel); |
865 |
} |
866 |
} |
968 |
} |
867 |
} |
969 |
} |
868 |
} |
970 |
} |
869 |
/** |
|
|
870 |
* Non-recursively tries to find the given element as a child of the given parent item. |
871 |
* |
872 |
* @param parent the parent item |
873 |
* @param element the element |
874 |
*/ |
875 |
private Widget internalFindChild(Item parent, Object element) { |
876 |
Item[] items = getChildren(parent); |
877 |
for (int i = 0; i < items.length; i++) { |
878 |
Item item = items[i]; |
879 |
Object data = item.getData(); |
880 |
if (data != null && equals(data, element)) |
881 |
return item; |
882 |
} |
883 |
return null; |
884 |
} |
885 |
/** |
886 |
* Recursively tries to find the given element. |
887 |
* |
888 |
* @param parent the parent item |
889 |
* @param element the element |
890 |
*/ |
891 |
private Widget internalFindItem(Item parent, Object element) { |
971 |
|
892 |
|
972 |
/** |
893 |
// compare with node |
973 |
* Removes the given elements from this viewer. |
894 |
Object data = parent.getData(); |
974 |
* |
895 |
if (data != null) { |
975 |
* @param elements the elements to remove |
896 |
if (equals(data, element)) |
976 |
*/ |
897 |
return parent; |
977 |
private void internalRemove(Object[] elements) { |
898 |
} |
978 |
Object input = getInput(); |
899 |
// recurse over children |
979 |
HashSet parentItems = new HashSet(5); |
900 |
Item[] items = getChildren(parent); |
980 |
for (int i = 0; i < elements.length; ++i) { |
901 |
for (int i = 0; i < items.length; i++) { |
981 |
if (equals(elements[i], input)) { |
902 |
Item item = items[i]; |
982 |
setInput(null); |
903 |
Widget o = internalFindItem(item, element); |
|
|
904 |
if (o != null) |
905 |
return o; |
906 |
} |
907 |
return null; |
908 |
} |
909 |
/* (non-Javadoc) |
910 |
* Method declared on StructuredViewer. |
911 |
*/ |
912 |
protected void internalRefresh(Object element) { |
913 |
internalRefresh(element, true); |
914 |
} |
915 |
/* (non-Javadoc) |
916 |
* Method declared on StructuredViewer. |
917 |
*/ |
918 |
protected void internalRefresh(Object element, boolean updateLabels) { |
919 |
// If element is null, do a full refresh. |
920 |
if (element == null) { |
921 |
internalRefresh(getControl(), getRoot(), true, updateLabels); |
983 |
return; |
922 |
return; |
984 |
} |
923 |
} |
985 |
Widget childItem = findItem(elements[i]); |
924 |
Widget item = findItem(element); |
986 |
if (childItem instanceof Item) { |
925 |
if (item != null) { |
987 |
Item parentItem = getParentItem((Item) childItem); |
926 |
// pick up structure changes too |
988 |
if (parentItem != null) { |
927 |
internalRefresh(item, element, true, updateLabels); |
989 |
parentItems.add(parentItem); |
928 |
} |
990 |
} |
929 |
} |
991 |
disassociate((Item) childItem); |
930 |
/** |
992 |
childItem.dispose(); |
931 |
* Refreshes the tree starting at the given widget. |
993 |
} |
932 |
* |
994 |
} |
933 |
* @param widget the widget |
995 |
Control tree = getControl(); |
934 |
* @param element the element |
996 |
for (Iterator i = parentItems.iterator(); i.hasNext();) { |
935 |
* @param doStruct <code>true</code> if structural changes are to be picked up, |
997 |
Item parentItem = (Item) i.next(); |
936 |
* and <code>false</code> if only label provider changes are of interest |
998 |
if (!getExpanded(parentItem) && getItemCount(parentItem) == 0) { |
937 |
* @param updateLabels <code>true</code> to update labels for existing elements, |
999 |
// append a dummy if necessary |
938 |
* <code>false</code> to only update labels as needed, assuming that labels |
1000 |
if (isExpandable(parentItem.getData())) { |
939 |
* for existing elements are unchanged. |
1001 |
newItem(parentItem, SWT.NULL, -1); |
940 |
*/ |
|
|
941 |
private void internalRefresh( |
942 |
Widget widget, |
943 |
Object element, |
944 |
boolean doStruct, |
945 |
boolean updateLabels) { |
946 |
|
947 |
if (widget instanceof Item) { |
948 |
if (doStruct) { |
949 |
updatePlus((Item) widget, element); |
950 |
} |
951 |
if (updateLabels || !equals(element, widget.getData())) { |
952 |
doUpdateItem(widget, element, true); |
1002 |
} else { |
953 |
} else { |
1003 |
// XXX: Workaround (PR missing) |
954 |
associate(element, (Item) widget); |
1004 |
tree.redraw(); |
955 |
} |
1005 |
} |
956 |
} |
|
|
957 |
|
958 |
if (doStruct) { |
959 |
internalRefreshStruct(widget, element, updateLabels); |
960 |
} else { |
961 |
Item[] children = getChildren(widget); |
962 |
if (children != null) { |
963 |
for (int i = 0; i < children.length; i++) { |
964 |
Widget item = children[i]; |
965 |
Object data = item.getData(); |
966 |
if (data != null) |
967 |
internalRefresh(item, data, doStruct, updateLabels); |
968 |
} |
969 |
} |
1006 |
} |
970 |
} |
1007 |
} |
971 |
} |
1008 |
} |
972 |
|
1009 |
/** |
973 |
/** |
1010 |
* Sets the expanded state of all items to correspond to the given set of expanded elements. |
974 |
* Update the structure and recurse. |
1011 |
* |
975 |
* Items are updated in updateChildren, as needed. |
1012 |
* @param expandedElements the set (element type: <code>Object</code>) of elements which are expanded |
976 |
*/ |
1013 |
* @param widget the widget |
977 |
private void internalRefreshStruct( |
1014 |
*/ |
978 |
Widget widget, |
1015 |
private void internalSetExpanded(HashSet expandedElements, Widget widget) { |
979 |
Object element, |
1016 |
Item[] items = getChildren(widget); |
980 |
boolean updateLabels) { |
1017 |
for (int i = 0; i < items.length; i++) { |
981 |
updateChildren(widget, element, null, updateLabels); |
1018 |
Item item = items[i]; |
982 |
Item[] children = getChildren(widget); |
1019 |
Object data = item.getData(); |
983 |
if (children != null) { |
1020 |
if (data != null) { |
984 |
for (int i = 0; i < children.length; i++) { |
1021 |
// remove the element to avoid an infinite loop |
985 |
Widget item = children[i]; |
1022 |
// if the same element appears on a child item |
986 |
Object data = item.getData(); |
1023 |
boolean expanded = expandedElements.remove(data); |
987 |
if (data != null) |
1024 |
if (expanded != getExpanded(item)) { |
988 |
internalRefreshStruct(item, data, updateLabels); |
1025 |
if (expanded) { |
989 |
} |
1026 |
createChildren(item); |
990 |
} |
|
|
991 |
} |
992 |
|
993 |
/** |
994 |
* Removes the given elements from this viewer. |
995 |
* |
996 |
* @param elements the elements to remove |
997 |
*/ |
998 |
private void internalRemove(Object[] elements) { |
999 |
Object input = getInput(); |
1000 |
HashSet parentItems = new HashSet(5); |
1001 |
for (int i = 0; i < elements.length; ++i) { |
1002 |
if (equals(elements[i], input)) { |
1003 |
setInput(null); |
1004 |
return; |
1005 |
} |
1006 |
Widget childItem = findItem(elements[i]); |
1007 |
if (childItem instanceof Item) { |
1008 |
Item parentItem = getParentItem((Item) childItem); |
1009 |
if (parentItem != null) { |
1010 |
parentItems.add(parentItem); |
1011 |
} |
1012 |
disassociate((Item) childItem); |
1013 |
childItem.dispose(); |
1014 |
} |
1015 |
} |
1016 |
Control tree = getControl(); |
1017 |
for (Iterator i = parentItems.iterator(); i.hasNext();) { |
1018 |
Item parentItem = (Item) i.next(); |
1019 |
if (!getExpanded(parentItem) && getItemCount(parentItem) == 0) { |
1020 |
// append a dummy if necessary |
1021 |
if (isExpandable(parentItem.getData())) { |
1022 |
newItem(parentItem, SWT.NULL, -1); |
1023 |
} else { |
1024 |
// XXX: Workaround (PR missing) |
1025 |
tree.redraw(); |
1027 |
} |
1026 |
} |
1028 |
setExpanded(item, expanded); |
|
|
1029 |
} |
1027 |
} |
1030 |
} |
1028 |
} |
1031 |
internalSetExpanded(expandedElements, item); |
|
|
1032 |
} |
1029 |
} |
1033 |
} |
1030 |
/** |
1034 |
/** |
1031 |
* Sets the expanded state of all items to correspond to the given set of expanded elements. |
1035 |
* Return whether the tree node representing the given element |
1032 |
* |
1036 |
* can be expanded. |
1033 |
* @param expandedElements the set (element type: <code>Object</code>) of elements which are expanded |
1037 |
* <p> |
1034 |
* @param widget the widget |
1038 |
* The default implementation of this framework method calls |
1035 |
*/ |
1039 |
* <code>hasChildren</code> on this viewer's content provider. |
1036 |
private void internalSetExpanded(HashSet expandedElements, Widget widget) { |
1040 |
* It may be overridden if necessary. |
1037 |
Item[] items = getChildren(widget); |
1041 |
* </p> |
1038 |
for (int i = 0; i < items.length; i++) { |
1042 |
* |
1039 |
Item item = items[i]; |
1043 |
* @param element the element |
1040 |
Object data = item.getData(); |
1044 |
* @return <code>true</code> if the tree node representing |
1041 |
if (data != null) { |
1045 |
* the given element can be expanded, or <code>false</code> if not |
1042 |
// remove the element to avoid an infinite loop |
1046 |
*/ |
1043 |
// if the same element appears on a child item |
1047 |
public boolean isExpandable(Object element) { |
1044 |
boolean expanded = expandedElements.remove(data); |
1048 |
ITreeContentProvider cp = (ITreeContentProvider) getContentProvider(); |
1045 |
if (expanded != getExpanded(item)) { |
1049 |
return cp != null && cp.hasChildren(element); |
1046 |
if (expanded) { |
1050 |
} |
1047 |
createChildren(item); |
1051 |
/* (non-Javadoc) |
1048 |
} |
1052 |
* Method declared on Viewer. |
1049 |
setExpanded(item, expanded); |
1053 |
*/ |
1050 |
} |
1054 |
protected void labelProviderChanged() { |
1051 |
} |
1055 |
// we have to walk the (visible) tree and update every item |
1052 |
internalSetExpanded(expandedElements, item); |
1056 |
Control tree= getControl(); |
|
|
1057 |
tree.setRedraw(false); |
1058 |
// don't pick up structure changes, but do force label updates |
1059 |
internalRefresh(tree, getRoot(), false, true); |
1060 |
tree.setRedraw(true); |
1061 |
} |
1062 |
/** |
1063 |
* Creates a new item. |
1064 |
* |
1065 |
* @param parent the parent widget |
1066 |
* @param style SWT style bits |
1067 |
* @param index if non-negative, indicates the position to insert the item |
1068 |
* into its parent |
1069 |
* @return the newly-created item |
1070 |
*/ |
1071 |
protected abstract Item newItem(Widget parent, int style, int index); |
1072 |
/** |
1073 |
* Removes the given elements from this viewer. |
1074 |
* The selection is updated if required. |
1075 |
* <p> |
1076 |
* This method should be called (by the content provider) when elements |
1077 |
* have been removed from the model, in order to cause the viewer to accurately |
1078 |
* reflect the model. This method only affects the viewer, not the model. |
1079 |
* </p> |
1080 |
* |
1081 |
* @param elements the elements to remove |
1082 |
*/ |
1083 |
public void remove(final Object[] elements) { |
1084 |
preservingSelection(new Runnable() { |
1085 |
public void run() { |
1086 |
internalRemove(elements); |
1087 |
} |
1053 |
} |
1088 |
}); |
|
|
1089 |
} |
1090 |
/** |
1091 |
* Removes the given element from the viewer. |
1092 |
* The selection is updated if necessary. |
1093 |
* <p> |
1094 |
* This method should be called (by the content provider) when a single element |
1095 |
* has been removed from the model, in order to cause the viewer to accurately |
1096 |
* reflect the model. This method only affects the viewer, not the model. |
1097 |
* Note that there is another method for efficiently processing the simultaneous |
1098 |
* removal of multiple elements. |
1099 |
* </p> |
1100 |
* |
1101 |
* @param element the element |
1102 |
*/ |
1103 |
public void remove(Object element) { |
1104 |
remove(new Object[] { element }); |
1105 |
} |
1106 |
/** |
1107 |
* Removes all items from the given control. |
1108 |
* |
1109 |
* @param control the control |
1110 |
*/ |
1111 |
protected abstract void removeAll(Control control); |
1112 |
/** |
1113 |
* Removes a listener for expand and collapse events in this viewer. |
1114 |
* Has no affect if an identical listener is not registered. |
1115 |
* |
1116 |
* @param listener a tree viewer listener |
1117 |
*/ |
1118 |
public void removeTreeListener(ITreeViewerListener listener) { |
1119 |
treeListeners.remove(listener); |
1120 |
} |
1121 |
/* |
1122 |
* Non-Javadoc. |
1123 |
* Method defined on StructuredViewer. |
1124 |
*/ |
1125 |
public void reveal(Object element) { |
1126 |
Widget w = internalExpand(element, true); |
1127 |
if (w instanceof Item) |
1128 |
showItem((Item) w); |
1129 |
} |
1130 |
/** |
1131 |
* Returns the rightmost visible descendent of the given item. |
1132 |
* Returns the item itself if it has no children. |
1133 |
* |
1134 |
* @param item the item to compute the descendent of |
1135 |
* @return the rightmost visible descendent or the item iself |
1136 |
* if it has no children |
1137 |
*/ |
1138 |
private Item rightMostVisibleDescendent(Item item) { |
1139 |
Item[] children = getItems(item); |
1140 |
if (getExpanded(item) && children != null && children.length > 0) { |
1141 |
return rightMostVisibleDescendent(children[children.length-1]); |
1142 |
} else { |
1143 |
return item; |
1144 |
} |
1145 |
} |
1146 |
/* (non-Javadoc) |
1147 |
* Method declared on Viewer. |
1148 |
*/ |
1149 |
public Item scrollDown(int x, int y) { |
1150 |
Item current = getItem(x, y); |
1151 |
if (current != null) { |
1152 |
Item next = getNextItem(current, true); |
1153 |
showItem(next == null ? current : next); |
1154 |
return next; |
1155 |
} |
1156 |
return null; |
1157 |
} |
1158 |
/* (non-Javadoc) |
1159 |
* Method declared on Viewer. |
1160 |
*/ |
1161 |
public Item scrollUp(int x, int y) { |
1162 |
Item current = getItem(x, y); |
1163 |
if (current != null) { |
1164 |
Item previous = getPreviousItem(current); |
1165 |
showItem(previous == null ? current : previous); |
1166 |
return previous; |
1167 |
} |
1054 |
} |
1168 |
return null; |
1055 |
/** |
1169 |
} |
1056 |
* Return whether the tree node representing the given element |
1170 |
/** |
1057 |
* can be expanded. |
1171 |
* Sets the auto-expand level. |
1058 |
* <p> |
1172 |
* The value 0 means that there is no auto-expand; |
1059 |
* The default implementation of this framework method calls |
1173 |
* 1 means that top-level elements are expanded, but not their children; |
1060 |
* <code>hasChildren</code> on this viewer's content provider. |
1174 |
* 2 means that top-level elements are expanded, and their children, |
1061 |
* It may be overridden if necessary. |
1175 |
* but not grandchildren; and so on. |
1062 |
* </p> |
1176 |
* <p> |
1063 |
* |
1177 |
* The value <code>ALL_LEVELS</code> means that all subtrees should be |
1064 |
* @param element the element |
1178 |
* expanded. |
1065 |
* @return <code>true</code> if the tree node representing |
1179 |
* </p> |
1066 |
* the given element can be expanded, or <code>false</code> if not |
1180 |
* |
1067 |
*/ |
1181 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
1068 |
public boolean isExpandable(Object element) { |
1182 |
* all levels of the tree |
1069 |
ITreeContentProvider cp = (ITreeContentProvider) getContentProvider(); |
1183 |
*/ |
1070 |
return cp != null && cp.hasChildren(element); |
1184 |
public void setAutoExpandLevel(int level) { |
|
|
1185 |
expandToLevel = level; |
1186 |
} |
1187 |
/** |
1188 |
* The <code>AbstractTreeViewer</code> implementation of this method |
1189 |
* checks to ensure that the content provider is an <code>ITreeContentProvider</code>. |
1190 |
*/ |
1191 |
public void setContentProvider(IContentProvider provider) { |
1192 |
Assert.isTrue(provider instanceof ITreeContentProvider); |
1193 |
super.setContentProvider(provider); |
1194 |
} |
1195 |
/** |
1196 |
* Sets the expand state of the given item. |
1197 |
* |
1198 |
* @param item the item |
1199 |
* @param expand the expand state of the item |
1200 |
*/ |
1201 |
protected abstract void setExpanded(Item item, boolean expand); |
1202 |
/** |
1203 |
* Sets which nodes are expanded in this viewer's tree. |
1204 |
* The given list contains the elements that are to be expanded; |
1205 |
* all other nodes are to be collapsed. |
1206 |
* <p> |
1207 |
* This method is typically used when restoring the interesting |
1208 |
* state of a viewer captured by an earlier call to <code>getExpandedElements</code>. |
1209 |
* </p> |
1210 |
* |
1211 |
* @param elements the array of expanded elements |
1212 |
* @see #getExpandedElements |
1213 |
*/ |
1214 |
public void setExpandedElements(Object[] elements) { |
1215 |
HashSet expandedElements = new HashSet(elements.length*2+1); |
1216 |
for (int i = 0; i < elements.length; ++i) { |
1217 |
// Ensure item exists for element |
1218 |
internalExpand(elements[i], false); |
1219 |
expandedElements.add(elements[i]); |
1220 |
} |
1071 |
} |
1221 |
internalSetExpanded(expandedElements, getControl()); |
1072 |
/* (non-Javadoc) |
1222 |
} |
1073 |
* Method declared on Viewer. |
1223 |
/** |
1074 |
*/ |
1224 |
* Sets whether the node corresponding to the given element is expanded or collapsed. |
1075 |
protected void labelProviderChanged() { |
1225 |
* |
1076 |
// we have to walk the (visible) tree and update every item |
1226 |
* @param element the element |
1077 |
Control tree = getControl(); |
1227 |
* @param expanded <code>true</code> if the node is expanded, and <code>false</code> if collapsed |
1078 |
tree.setRedraw(false); |
1228 |
*/ |
1079 |
// don't pick up structure changes, but do force label updates |
1229 |
public void setExpandedState(Object element, boolean expanded) { |
1080 |
internalRefresh(tree, getRoot(), false, true); |
1230 |
Widget item = internalExpand(element, false); |
1081 |
tree.setRedraw(true); |
1231 |
if (item instanceof Item) { |
1082 |
} |
1232 |
if (expanded) { |
1083 |
/** |
1233 |
createChildren(item); |
1084 |
* Creates a new item. |
|
|
1085 |
* |
1086 |
* @param parent the parent widget |
1087 |
* @param style SWT style bits |
1088 |
* @param index if non-negative, indicates the position to insert the item |
1089 |
* into its parent |
1090 |
* @return the newly-created item |
1091 |
*/ |
1092 |
protected abstract Item newItem(Widget parent, int style, int index); |
1093 |
/** |
1094 |
* Removes the given elements from this viewer. |
1095 |
* The selection is updated if required. |
1096 |
* <p> |
1097 |
* This method should be called (by the content provider) when elements |
1098 |
* have been removed from the model, in order to cause the viewer to accurately |
1099 |
* reflect the model. This method only affects the viewer, not the model. |
1100 |
* </p> |
1101 |
* |
1102 |
* @param elements the elements to remove |
1103 |
*/ |
1104 |
public void remove(final Object[] elements) { |
1105 |
preservingSelection(new Runnable() { |
1106 |
public void run() { |
1107 |
internalRemove(elements); |
1108 |
} |
1109 |
}); |
1110 |
} |
1111 |
/** |
1112 |
* Removes the given element from the viewer. |
1113 |
* The selection is updated if necessary. |
1114 |
* <p> |
1115 |
* This method should be called (by the content provider) when a single element |
1116 |
* has been removed from the model, in order to cause the viewer to accurately |
1117 |
* reflect the model. This method only affects the viewer, not the model. |
1118 |
* Note that there is another method for efficiently processing the simultaneous |
1119 |
* removal of multiple elements. |
1120 |
* </p> |
1121 |
* |
1122 |
* @param element the element |
1123 |
*/ |
1124 |
public void remove(Object element) { |
1125 |
remove(new Object[] { element }); |
1126 |
} |
1127 |
/** |
1128 |
* Removes all items from the given control. |
1129 |
* |
1130 |
* @param control the control |
1131 |
*/ |
1132 |
protected abstract void removeAll(Control control); |
1133 |
/** |
1134 |
* Removes a listener for expand and collapse events in this viewer. |
1135 |
* Has no affect if an identical listener is not registered. |
1136 |
* |
1137 |
* @param listener a tree viewer listener |
1138 |
*/ |
1139 |
public void removeTreeListener(ITreeViewerListener listener) { |
1140 |
treeListeners.remove(listener); |
1141 |
} |
1142 |
/* |
1143 |
* Non-Javadoc. |
1144 |
* Method defined on StructuredViewer. |
1145 |
*/ |
1146 |
public void reveal(Object element) { |
1147 |
Widget w = internalExpand(element, true); |
1148 |
if (w instanceof Item) |
1149 |
showItem((Item) w); |
1150 |
} |
1151 |
/** |
1152 |
* Returns the rightmost visible descendent of the given item. |
1153 |
* Returns the item itself if it has no children. |
1154 |
* |
1155 |
* @param item the item to compute the descendent of |
1156 |
* @return the rightmost visible descendent or the item iself |
1157 |
* if it has no children |
1158 |
*/ |
1159 |
private Item rightMostVisibleDescendent(Item item) { |
1160 |
Item[] children = getItems(item); |
1161 |
if (getExpanded(item) && children != null && children.length > 0) { |
1162 |
return rightMostVisibleDescendent(children[children.length - 1]); |
1163 |
} else { |
1164 |
return item; |
1234 |
} |
1165 |
} |
1235 |
setExpanded((Item) item, expanded); |
|
|
1236 |
} |
1166 |
} |
1237 |
} |
1167 |
/* (non-Javadoc) |
1238 |
/** |
1168 |
* Method declared on Viewer. |
1239 |
* Sets the selection to the given list of items. |
1169 |
*/ |
1240 |
* |
1170 |
public Item scrollDown(int x, int y) { |
1241 |
* @param items list of items (element type: <code>org.eclipse.swt.widgets.Item</code>) |
1171 |
Item current = getItem(x, y); |
1242 |
*/ |
1172 |
if (current != null) { |
1243 |
protected abstract void setSelection(List items); |
1173 |
Item next = getNextItem(current, true); |
1244 |
/* (non-Javadoc) |
1174 |
showItem(next == null ? current : next); |
1245 |
* Method declared on StructuredViewer. |
1175 |
return next; |
1246 |
*/ |
1176 |
} |
1247 |
protected void setSelectionToWidget(List v, boolean reveal) { |
1177 |
return null; |
1248 |
if (v == null) { |
|
|
1249 |
setSelection(new ArrayList(0)); |
1250 |
return; |
1251 |
} |
1252 |
int size = v.size(); |
1253 |
List newSelection = new ArrayList(size); |
1254 |
for (int i = 0; i < size; ++i) { |
1255 |
// Use internalExpand since item may not yet be created. See 1G6B1AR. |
1256 |
Widget w = internalExpand(v.get(i), true); |
1257 |
if (w instanceof Item) { |
1258 |
newSelection.add(w); |
1259 |
} |
1260 |
} |
1261 |
setSelection(newSelection); |
1262 |
if (reveal && newSelection.size() > 0) { |
1263 |
showItem((Item) newSelection.get(0)); |
1264 |
} |
1178 |
} |
1265 |
} |
1179 |
/* (non-Javadoc) |
1266 |
/** |
1180 |
* Method declared on Viewer. |
1267 |
* Shows the given item. |
1181 |
*/ |
1268 |
* |
1182 |
public Item scrollUp(int x, int y) { |
1269 |
* @param item the item |
1183 |
Item current = getItem(x, y); |
1270 |
*/ |
1184 |
if (current != null) { |
1271 |
protected abstract void showItem(Item item); |
1185 |
Item previous = getPreviousItem(current); |
|
|
1186 |
showItem(previous == null ? current : previous); |
1187 |
return previous; |
1188 |
} |
1189 |
return null; |
1190 |
} |
1191 |
/** |
1192 |
* Sets the auto-expand level. |
1193 |
* The value 0 means that there is no auto-expand; |
1194 |
* 1 means that top-level elements are expanded, but not their children; |
1195 |
* 2 means that top-level elements are expanded, and their children, |
1196 |
* but not grandchildren; and so on. |
1197 |
* <p> |
1198 |
* The value <code>ALL_LEVELS</code> means that all subtrees should be |
1199 |
* expanded. |
1200 |
* </p> |
1201 |
* |
1202 |
* @param level non-negative level, or <code>ALL_LEVELS</code> to expand |
1203 |
* all levels of the tree |
1204 |
*/ |
1205 |
public void setAutoExpandLevel(int level) { |
1206 |
expandToLevel = level; |
1207 |
} |
1208 |
/** |
1209 |
* The <code>AbstractTreeViewer</code> implementation of this method |
1210 |
* checks to ensure that the content provider is an <code>ITreeContentProvider</code>. |
1211 |
*/ |
1212 |
public void setContentProvider(IContentProvider provider) { |
1213 |
Assert.isTrue(provider instanceof ITreeContentProvider); |
1214 |
super.setContentProvider(provider); |
1215 |
} |
1216 |
/** |
1217 |
* Sets the expand state of the given item. |
1218 |
* |
1219 |
* @param item the item |
1220 |
* @param expand the expand state of the item |
1221 |
*/ |
1222 |
protected abstract void setExpanded(Item item, boolean expand); |
1223 |
/** |
1224 |
* Sets which nodes are expanded in this viewer's tree. |
1225 |
* The given list contains the elements that are to be expanded; |
1226 |
* all other nodes are to be collapsed. |
1227 |
* <p> |
1228 |
* This method is typically used when restoring the interesting |
1229 |
* state of a viewer captured by an earlier call to <code>getExpandedElements</code>. |
1230 |
* </p> |
1231 |
* |
1232 |
* @param elements the array of expanded elements |
1233 |
* @see #getExpandedElements |
1234 |
*/ |
1235 |
public void setExpandedElements(Object[] elements) { |
1236 |
HashSet expandedElements = new HashSet(elements.length * 2 + 1); |
1237 |
for (int i = 0; i < elements.length; ++i) { |
1238 |
// Ensure item exists for element |
1239 |
internalExpand(elements[i], false); |
1240 |
expandedElements.add(elements[i]); |
1241 |
} |
1242 |
internalSetExpanded(expandedElements, getControl()); |
1243 |
} |
1244 |
/** |
1245 |
* Sets whether the node corresponding to the given element is expanded or collapsed. |
1246 |
* |
1247 |
* @param element the element |
1248 |
* @param expanded <code>true</code> if the node is expanded, and <code>false</code> if collapsed |
1249 |
*/ |
1250 |
public void setExpandedState(Object element, boolean expanded) { |
1251 |
Widget item = internalExpand(element, false); |
1252 |
if (item instanceof Item) { |
1253 |
if (expanded) { |
1254 |
createChildren(item); |
1255 |
} |
1256 |
setExpanded((Item) item, expanded); |
1257 |
} |
1258 |
} |
1259 |
/** |
1260 |
* Sets the selection to the given list of items. |
1261 |
* |
1262 |
* @param items list of items (element type: <code>org.eclipse.swt.widgets.Item</code>) |
1263 |
*/ |
1264 |
protected abstract void setSelection(List items); |
1265 |
/* (non-Javadoc) |
1266 |
* Method declared on StructuredViewer. |
1267 |
*/ |
1268 |
protected void setSelectionToWidget(List v, boolean reveal) { |
1269 |
if (v == null) { |
1270 |
setSelection(new ArrayList(0)); |
1271 |
return; |
1272 |
} |
1273 |
int size = v.size(); |
1274 |
List newSelection = new ArrayList(size); |
1275 |
for (int i = 0; i < size; ++i) { |
1276 |
// Use internalExpand since item may not yet be created. See 1G6B1AR. |
1277 |
Widget w = internalExpand(v.get(i), true); |
1278 |
if (w instanceof Item) { |
1279 |
newSelection.add(w); |
1280 |
} |
1281 |
} |
1282 |
setSelection(newSelection); |
1283 |
if (reveal && newSelection.size() > 0) { |
1284 |
showItem((Item) newSelection.get(0)); |
1285 |
} |
1286 |
} |
1287 |
/** |
1288 |
* Shows the given item. |
1289 |
* |
1290 |
* @param item the item |
1291 |
*/ |
1292 |
protected abstract void showItem(Item item); |
1272 |
|
1293 |
|
1273 |
/** |
1294 |
/** |
1274 |
* Updates the tree items to correspond to the child elements of the given parent element. |
1295 |
* Updates the tree items to correspond to the child elements of the given parent element. |
1275 |
* If null is passed for the children, this method obtains them (only if needed). |
1296 |
* If null is passed for the children, this method obtains them (only if needed). |
1276 |
* |
1297 |
* |
1277 |
* @param widget the widget |
1298 |
* @param widget the widget |
1278 |
* @param parent the parent element |
1299 |
* @param parent the parent element |
1279 |
* @param elementChildren the child elements, or null |
1300 |
* @param elementChildren the child elements, or null |
1280 |
* |
1301 |
* |
1281 |
* @deprecated this is no longer called by the framework |
1302 |
* @deprecated this is no longer called by the framework |
1282 |
*/ |
1303 |
*/ |
1283 |
protected void updateChildren(Widget widget, Object parent, Object[] elementChildren) { |
1304 |
protected void updateChildren( |
1284 |
updateChildren(widget, parent, elementChildren, true); |
1305 |
Widget widget, |
1285 |
} |
1306 |
Object parent, |
|
|
1307 |
Object[] elementChildren) { |
1308 |
updateChildren(widget, parent, elementChildren, true); |
1309 |
} |
1286 |
|
1310 |
|
1287 |
/** |
1311 |
/** |
1288 |
* Updates the tree items to correspond to the child elements of the given parent element. |
1312 |
* Updates the tree items to correspond to the child elements of the given parent element. |
1289 |
* If null is passed for the children, this method obtains them (only if needed). |
1313 |
* If null is passed for the children, this method obtains them (only if needed). |
1290 |
* |
1314 |
* |
1291 |
* @param widget the widget |
1315 |
* @param widget the widget |
1292 |
* @param parent the parent element |
1316 |
* @param parent the parent element |
1293 |
* @param elementChildren the child elements, or null |
1317 |
* @param elementChildren the child elements, or null |
1294 |
* @param updateLabels <code>true</code> to update labels for existing elements, |
1318 |
* @param updateLabels <code>true</code> to update labels for existing elements, |
1295 |
* <code>false</code> to only update labels as needed, assuming that labels |
1319 |
* <code>false</code> to only update labels as needed, assuming that labels |
1296 |
* for existing elements are unchanged. |
1320 |
* for existing elements are unchanged. |
1297 |
* |
1321 |
* |
1298 |
* @since 2.1 |
1322 |
* @since 2.1 |
1299 |
*/ |
1323 |
*/ |
1300 |
private void updateChildren(Widget widget, Object parent, Object[] elementChildren, boolean updateLabels) { |
1324 |
private void updateChildren( |
1301 |
// optimization! prune collapsed subtrees |
1325 |
Widget widget, |
1302 |
if (widget instanceof Item) { |
1326 |
Object parent, |
1303 |
Item ti= (Item) widget; |
1327 |
Object[] elementChildren, |
1304 |
if (!getExpanded(ti)) { |
1328 |
boolean updateLabels) { |
1305 |
// need a dummy node if element is expandable; |
1329 |
// optimization! prune collapsed subtrees |
1306 |
// but try to avoid recreating the dummy node |
1330 |
if (widget instanceof Item) { |
1307 |
boolean needDummy = isExpandable(parent); |
1331 |
Item ti = (Item) widget; |
1308 |
boolean haveDummy = false; |
1332 |
if (!getExpanded(ti)) { |
1309 |
// remove all children |
1333 |
// need a dummy node if element is expandable; |
1310 |
Item[] items= getItems(ti); |
1334 |
// but try to avoid recreating the dummy node |
1311 |
for (int i= 0; i < items.length; i++) { |
1335 |
boolean needDummy = isExpandable(parent); |
1312 |
if (items[i].getData() != null) { |
1336 |
boolean haveDummy = false; |
1313 |
disassociate(items[i]); |
1337 |
// remove all children |
1314 |
items[i].dispose(); |
1338 |
Item[] items = getItems(ti); |
1315 |
} |
1339 |
for (int i = 0; i < items.length; i++) { |
1316 |
else { |
1340 |
if (items[i].getData() != null) { |
1317 |
if (needDummy && !haveDummy) { |
1341 |
disassociate(items[i]); |
1318 |
haveDummy = true; |
|
|
1319 |
} |
1320 |
else { |
1321 |
items[i].dispose(); |
1342 |
items[i].dispose(); |
|
|
1343 |
} else { |
1344 |
if (needDummy && !haveDummy) { |
1345 |
haveDummy = true; |
1346 |
} else { |
1347 |
items[i].dispose(); |
1348 |
} |
1322 |
} |
1349 |
} |
1323 |
} |
1350 |
} |
|
|
1351 |
if (needDummy && !haveDummy) { |
1352 |
newItem(ti, SWT.NULL, -1); |
1353 |
} |
1354 |
|
1355 |
return; |
1324 |
} |
1356 |
} |
1325 |
if (needDummy && !haveDummy) { |
1357 |
} |
1326 |
newItem(ti, SWT.NULL, -1); |
1358 |
|
|
|
1359 |
// If the children weren't passed in, get them now since they're needed below. |
1360 |
if (elementChildren == null) { |
1361 |
elementChildren = getSortedChildren(parent); |
1362 |
} |
1363 |
|
1364 |
Control tree = getControl(); |
1365 |
|
1366 |
// WORKAROUND |
1367 |
int oldCnt = -1; |
1368 |
if (widget == tree) |
1369 |
oldCnt = getItemCount(tree); |
1370 |
|
1371 |
Item[] items = getChildren(widget); |
1372 |
|
1373 |
// save the expanded elements |
1374 |
HashSet expanded = new HashSet(); // assume num expanded is small |
1375 |
for (int i = 0; i < items.length; ++i) { |
1376 |
if (getExpanded(items[i])) { |
1377 |
Object element = items[i].getData(); |
1378 |
if (element != null) { |
1379 |
expanded.add(element); |
1380 |
} |
1327 |
} |
1381 |
} |
1328 |
|
|
|
1329 |
return; |
1330 |
} |
1382 |
} |
1331 |
} |
|
|
1332 |
|
1383 |
|
1333 |
// If the children weren't passed in, get them now since they're needed below. |
1384 |
int min = Math.min(elementChildren.length, items.length); |
1334 |
if (elementChildren == null) { |
1385 |
|
1335 |
elementChildren = getSortedChildren(parent); |
1386 |
// Note: In the code below, doing disassociate calls before associate calls is important, |
1336 |
} |
1387 |
// since a later disassociate can undo an earlier associate, |
1337 |
|
1388 |
// if items are changing position. |
1338 |
Control tree = getControl(); |
1389 |
|
1339 |
|
1390 |
// dispose of all items beyond the end of the current elements |
1340 |
// WORKAROUND |
1391 |
for (int i = items.length; --i >= min;) { |
1341 |
int oldCnt= -1; |
1392 |
if (items[i].getData() != null) { |
1342 |
if (widget == tree) |
1393 |
disassociate(items[i]); |
1343 |
oldCnt= getItemCount(tree); |
|
|
1344 |
|
1345 |
Item[] items = getChildren(widget); |
1346 |
|
1347 |
// save the expanded elements |
1348 |
HashSet expanded = new HashSet(); // assume num expanded is small |
1349 |
for (int i = 0; i < items.length; ++i) { |
1350 |
if (getExpanded(items[i])) { |
1351 |
Object element = items[i].getData(); |
1352 |
if (element != null) { |
1353 |
expanded.add(element); |
1354 |
} |
1394 |
} |
|
|
1395 |
items[i].dispose(); |
1355 |
} |
1396 |
} |
1356 |
} |
1397 |
|
1357 |
|
1398 |
// compare first min items, and update item if necessary |
1358 |
int min = Math.min(elementChildren.length, items.length); |
1399 |
// need to do it in two passes: |
1359 |
|
1400 |
// 1: disassociate old items |
1360 |
// Note: In the code below, doing disassociate calls before associate calls is important, |
1401 |
// 2: associate new items |
1361 |
// since a later disassociate can undo an earlier associate, |
1402 |
// because otherwise a later disassociate can remove a mapping made for a previous associate, |
1362 |
// if items are changing position. |
1403 |
// making the map inconsistent |
1363 |
|
1404 |
for (int i = 0; i < min; ++i) { |
1364 |
// dispose of all items beyond the end of the current elements |
1405 |
Item item = items[i]; |
1365 |
for (int i = items.length; --i >= min;) { |
1406 |
Object oldElement = item.getData(); |
1366 |
if (items[i].getData() != null) { |
1407 |
if (oldElement != null) { |
1367 |
disassociate(items[i]); |
1408 |
Object newElement = elementChildren[i]; |
1368 |
} |
1409 |
if (newElement != oldElement) { |
1369 |
items[i].dispose(); |
1410 |
if (equals(newElement, oldElement)) { |
1370 |
} |
1411 |
// update the data to be the new element, since although the elements |
1371 |
|
1412 |
// may be equal, they may still have different labels or children |
1372 |
// compare first min items, and update item if necessary |
1413 |
item.setData(newElement); |
1373 |
// need to do it in two passes: |
1414 |
mapElement(newElement, item); |
1374 |
// 1: disassociate old items |
1415 |
} else { |
1375 |
// 2: associate new items |
1416 |
disassociate(item); |
1376 |
// because otherwise a later disassociate can remove a mapping made for a previous associate, |
1417 |
} |
1377 |
// making the map inconsistent |
|
|
1378 |
for (int i = 0; i < min; ++i) { |
1379 |
Item item = items[i]; |
1380 |
Object oldElement = item.getData(); |
1381 |
if (oldElement != null) { |
1382 |
Object newElement = elementChildren[i]; |
1383 |
if (newElement != oldElement) { |
1384 |
if (equals(newElement, oldElement)) { |
1385 |
// update the data to be the new element, since although the elements |
1386 |
// may be equal, they may still have different labels or children |
1387 |
item.setData(newElement); |
1388 |
mapElement(newElement, item); |
1389 |
} else { |
1390 |
disassociate(item); |
1391 |
} |
1418 |
} |
1392 |
} |
1419 |
} |
1393 |
} |
1420 |
} |
1394 |
} |
1421 |
for (int i = 0; i < min; ++i) { |
1395 |
for (int i = 0; i < min; ++i) { |
1422 |
Item item = items[i]; |
1396 |
Item item = items[i]; |
1423 |
Object newElement = elementChildren[i]; |
1397 |
Object newElement = elementChildren[i]; |
1424 |
if (item.getData() == null) { |
1398 |
if (item.getData() == null) { |
1425 |
// old and new elements are not equal |
1399 |
// old and new elements are not equal |
1426 |
associate(newElement, item); |
1400 |
associate(newElement, item); |
1427 |
updatePlus(item, newElement); |
1401 |
updatePlus(item, newElement); |
|
|
1402 |
updateItem(item, newElement); |
1403 |
// Restore expanded state for items that changed position. |
1404 |
// Make sure setExpanded is called after updatePlus, since |
1405 |
// setExpanded(false) fails if item has no children. |
1406 |
// Need to call setExpanded for both expanded and unexpanded cases |
1407 |
// since the expanded state can change either way. |
1408 |
setExpanded(item, expanded.contains(newElement)); |
1409 |
} |
1410 |
else { |
1411 |
// old and new elements are equal |
1412 |
updatePlus(item, newElement); |
1413 |
if (updateLabels) { |
1414 |
updateItem(item, newElement); |
1428 |
updateItem(item, newElement); |
|
|
1429 |
// Restore expanded state for items that changed position. |
1430 |
// Make sure setExpanded is called after updatePlus, since |
1431 |
// setExpanded(false) fails if item has no children. |
1432 |
// Need to call setExpanded for both expanded and unexpanded cases |
1433 |
// since the expanded state can change either way. |
1434 |
setExpanded(item, expanded.contains(newElement)); |
1435 |
} else { |
1436 |
// old and new elements are equal |
1437 |
updatePlus(item, newElement); |
1438 |
if (updateLabels) { |
1439 |
updateItem(item, newElement); |
1440 |
} |
1415 |
} |
1441 |
} |
1416 |
} |
1442 |
} |
1417 |
} |
1443 |
|
1418 |
|
1444 |
// add any remaining elements |
1419 |
// add any remaining elements |
1445 |
if (min < elementChildren.length) { |
1420 |
if (min < elementChildren.length) { |
|
|
1421 |
for (int i = min; i < elementChildren.length; ++i) { |
1422 |
createTreeItem(widget, elementChildren[i], i); |
1423 |
} |
1424 |
|
1425 |
// Need to restore expanded state in a separate pass |
1426 |
// because createTreeItem does not return the new item. |
1427 |
// Avoid doing this unless needed. |
1428 |
if (!expanded.isEmpty()) { |
1429 |
// get the items again, to include the new items |
1430 |
items = getChildren(widget); |
1431 |
for (int i = min; i < elementChildren.length; ++i) { |
1446 |
for (int i = min; i < elementChildren.length; ++i) { |
1432 |
// Restore expanded state for items that changed position. |
1447 |
createTreeItem(widget, elementChildren[i], i); |
1433 |
// Make sure setExpanded is called after updatePlus (called in createTreeItem), since |
1448 |
} |
1434 |
// setExpanded(false) fails if item has no children. |
1449 |
|
1435 |
// Only need to call setExpanded if element was expanded |
1450 |
// Need to restore expanded state in a separate pass |
1436 |
// since new items are initially unexpanded. |
1451 |
// because createTreeItem does not return the new item. |
1437 |
if (expanded.contains(elementChildren[i])) { |
1452 |
// Avoid doing this unless needed. |
1438 |
setExpanded(items[i], true); |
1453 |
if (!expanded.isEmpty()) { |
|
|
1454 |
// get the items again, to include the new items |
1455 |
items = getChildren(widget); |
1456 |
for (int i = min; i < elementChildren.length; ++i) { |
1457 |
// Restore expanded state for items that changed position. |
1458 |
// Make sure setExpanded is called after updatePlus (called in createTreeItem), since |
1459 |
// setExpanded(false) fails if item has no children. |
1460 |
// Only need to call setExpanded if element was expanded |
1461 |
// since new items are initially unexpanded. |
1462 |
if (expanded.contains(elementChildren[i])) { |
1463 |
setExpanded(items[i], true); |
1464 |
} |
1439 |
} |
1465 |
} |
1440 |
} |
1466 |
} |
1441 |
} |
1467 |
} |
|
|
1468 |
|
1469 |
// WORKAROUND |
1470 |
if (widget == tree && oldCnt == 0 && getItemCount(tree) != 0) { |
1471 |
//System.out.println("WORKAROUND setRedraw"); |
1472 |
tree.setRedraw(false); |
1473 |
tree.setRedraw(true); |
1474 |
} |
1442 |
} |
1475 |
} |
1443 |
|
1476 |
/** |
1444 |
// WORKAROUND |
1477 |
* Updates the "+"/"-" icon of the tree node from the given element. |
1445 |
if (widget == tree && oldCnt == 0 && getItemCount(tree) != 0) { |
1478 |
* It calls <code>isExpandable</code> to determine whether |
1446 |
//System.out.println("WORKAROUND setRedraw"); |
1479 |
* an element is expandable. |
1447 |
tree.setRedraw(false); |
1480 |
* |
1448 |
tree.setRedraw(true); |
1481 |
* @param item the item |
1449 |
} |
1482 |
* @param element the element |
1450 |
} |
1483 |
*/ |
1451 |
/** |
1484 |
protected void updatePlus(Item item, Object element) { |
1452 |
* Updates the "+"/"-" icon of the tree node from the given element. |
1485 |
boolean hasPlus = getItemCount(item) > 0; |
1453 |
* It calls <code>isExpandable</code> to determine whether |
1486 |
boolean needsPlus = isExpandable(element); |
1454 |
* an element is expandable. |
1487 |
boolean removeAll = false; |
1455 |
* |
1488 |
boolean addDummy = false; |
1456 |
* @param item the item |
1489 |
Object data = item.getData(); |
1457 |
* @param element the element |
1490 |
if (data != null && equals(element, data)) { |
1458 |
*/ |
1491 |
// item shows same element |
1459 |
protected void updatePlus(Item item, Object element) { |
1492 |
if (hasPlus != needsPlus) { |
1460 |
boolean hasPlus = getItemCount(item) > 0; |
1493 |
if (needsPlus) |
1461 |
boolean needsPlus = isExpandable(element); |
1494 |
addDummy = true; |
1462 |
boolean removeAll = false; |
1495 |
else |
1463 |
boolean addDummy = false; |
1496 |
removeAll = true; |
1464 |
Object data = item.getData(); |
1497 |
} |
1465 |
if (data != null && equals(element, data)) { |
1498 |
} else { |
1466 |
// item shows same element |
1499 |
// item shows different element |
1467 |
if (hasPlus != needsPlus) { |
1500 |
removeAll = true; |
1468 |
if (needsPlus) |
1501 |
addDummy = needsPlus; |
1469 |
addDummy = true; |
1502 |
|
1470 |
else |
1503 |
// we cannot maintain expand state so collapse it |
1471 |
removeAll = true; |
1504 |
setExpanded(item, false); |
1472 |
} |
1505 |
} |
1473 |
} else { |
1506 |
if (removeAll) { |
1474 |
// item shows different element |
1507 |
// remove all children |
1475 |
removeAll = true; |
1508 |
Item[] items = getItems(item); |
1476 |
addDummy = needsPlus; |
1509 |
for (int i = 0; i < items.length; i++) { |
1477 |
|
1510 |
if (items[i].getData() != null) |
1478 |
// we cannot maintain expand state so collapse it |
1511 |
disassociate(items[i]); |
1479 |
setExpanded(item, false); |
1512 |
items[i].dispose(); |
1480 |
} |
1513 |
} |
1481 |
if (removeAll) { |
|
|
1482 |
// remove all children |
1483 |
Item[] items = getItems(item); |
1484 |
for (int i = 0; i < items.length; i++) { |
1485 |
if (items[i].getData() != null) |
1486 |
disassociate(items[i]); |
1487 |
items[i].dispose(); |
1488 |
} |
1514 |
} |
|
|
1515 |
if (addDummy) |
1516 |
newItem(item, SWT.NULL, -1); // append a dummy |
1489 |
} |
1517 |
} |
1490 |
if (addDummy) |
|
|
1491 |
newItem(item, SWT.NULL, -1); // append a dummy |
1492 |
} |
1493 |
|
1518 |
|
1494 |
/** |
1519 |
/** |
1495 |
* Gets the expanded elements that are visible |
1520 |
* Gets the expanded elements that are visible |
1496 |
* to the user. An expanded element is only |
1521 |
* to the user. An expanded element is only |
1497 |
* visible if the parent is expanded. |
1522 |
* visible if the parent is expanded. |
1498 |
* |
1523 |
* |
1499 |
* @return the visible expanded elements |
1524 |
* @return the visible expanded elements |
1500 |
* @since 2.0 |
1525 |
* @since 2.0 |
1501 |
*/ |
1526 |
*/ |
1502 |
public Object[] getVisibleExpandedElements() { |
1527 |
public Object[] getVisibleExpandedElements() { |
1503 |
ArrayList v= new ArrayList(); |
1528 |
ArrayList v = new ArrayList(); |
1504 |
internalCollectVisibleExpanded(v, getControl()); |
1529 |
internalCollectVisibleExpanded(v, getControl()); |
1505 |
return v.toArray(); |
1530 |
return v.toArray(); |
1506 |
} |
1531 |
} |
1507 |
|
1532 |
|
1508 |
private void internalCollectVisibleExpanded(ArrayList result, Widget widget){ |
1533 |
private void internalCollectVisibleExpanded( |
1509 |
Item[] items = getChildren(widget); |
1534 |
ArrayList result, |
1510 |
for (int i = 0; i < items.length; i++) { |
1535 |
Widget widget) { |
1511 |
Item item = items[i]; |
1536 |
Item[] items = getChildren(widget); |
1512 |
if (getExpanded(item)) { |
1537 |
for (int i = 0; i < items.length; i++) { |
1513 |
Object data = item.getData(); |
1538 |
Item item = items[i]; |
1514 |
if (data != null) |
1539 |
if (getExpanded(item)) { |
1515 |
result.add(data); |
1540 |
Object data = item.getData(); |
1516 |
//Only recurse if it is expanded - if |
1541 |
if (data != null) |
1517 |
//not then the children aren't visible |
1542 |
result.add(data); |
1518 |
internalCollectVisibleExpanded(result, item); |
1543 |
//Only recurse if it is expanded - if |
|
|
1544 |
//not then the children aren't visible |
1545 |
internalCollectVisibleExpanded(result, item); |
1546 |
} |
1519 |
} |
1547 |
} |
1520 |
} |
1548 |
} |
1521 |
} |
|
|
1522 |
} |
1549 |
} |