View | Details | Raw Unified | Return to bug 167323 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jface/viewers/TreeViewer.java (-770 / +50 lines)
Lines 13-35 Link Here
13
13
14
package org.eclipse.jface.viewers;
14
package org.eclipse.jface.viewers;
15
15
16
import java.util.Iterator;
17
import java.util.List;
16
import java.util.List;
18
17
19
import org.eclipse.jface.util.Policy;
20
import org.eclipse.jface.viewers.CellEditor.LayoutData;
18
import org.eclipse.jface.viewers.CellEditor.LayoutData;
21
import org.eclipse.swt.SWT;
19
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.custom.TreeEditor;
20
import org.eclipse.swt.custom.TreeEditor;
23
import org.eclipse.swt.events.DisposeEvent;
24
import org.eclipse.swt.events.DisposeListener;
25
import org.eclipse.swt.events.TreeEvent;
26
import org.eclipse.swt.events.TreeListener;
21
import org.eclipse.swt.events.TreeListener;
27
import org.eclipse.swt.graphics.Point;
22
import org.eclipse.swt.graphics.Point;
28
import org.eclipse.swt.widgets.Composite;
23
import org.eclipse.swt.widgets.Composite;
29
import org.eclipse.swt.widgets.Control;
24
import org.eclipse.swt.widgets.Control;
30
import org.eclipse.swt.widgets.Event;
31
import org.eclipse.swt.widgets.Item;
25
import org.eclipse.swt.widgets.Item;
32
import org.eclipse.swt.widgets.Listener;
33
import org.eclipse.swt.widgets.Tree;
26
import org.eclipse.swt.widgets.Tree;
34
import org.eclipse.swt.widgets.TreeItem;
27
import org.eclipse.swt.widgets.TreeItem;
35
import org.eclipse.swt.widgets.Widget;
28
import org.eclipse.swt.widgets.Widget;
Lines 53-82 Link Here
53
 * support sorting or filtering.
46
 * support sorting or filtering.
54
 * </p>
47
 * </p>
55
 */
48
 */
56
public class TreeViewer extends AbstractTreeViewer {
49
public class TreeViewer extends VirtualAbstractTreeViewer {
57
58
	private static final String VIRTUAL_DISPOSE_KEY = Policy.JFACE
59
			+ ".DISPOSE_LISTENER"; //$NON-NLS-1$
60
61
	/**
62
	 * This viewer's control.
63
	 */
64
	private Tree tree;
50
	private Tree tree;
65
51
	
66
	/**
67
	 * This viewer's tree editor.
68
	 */
69
	private TreeEditor treeEditor;
52
	private TreeEditor treeEditor;
70
53
	
71
	/**
72
	 * Flag for whether the tree has been disposed of.
73
	 */
74
	private boolean treeIsDisposed = false;
75
76
	private boolean contentProviderIsLazy;
77
78
	private boolean contentProviderIsTreeBased;
79
80
	/**
54
	/**
81
	 * Creates a tree viewer on a newly-created tree control under the given
55
	 * Creates a tree viewer on a newly-created tree control under the given
82
	 * parent. The tree control is created using the SWT style bits
56
	 * parent. The tree control is created using the SWT style bits
Lines 127-207 Link Here
127
		((Tree) c).addTreeListener(listener);
101
		((Tree) c).addTreeListener(listener);
128
	}
102
	}
129
103
130
	/*
104
	protected Widget doGetColumn(int index) {
131
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
105
		return tree.getColumn(index);
132
	 */
133
	protected void doUpdateItem(final Item item, Object element) {
134
		if (!(item instanceof TreeItem)) {
135
			return;
136
		}
137
		TreeItem treeItem = (TreeItem) item;
138
		if (treeItem.isDisposed()) {
139
			unmapElement(element, treeItem);
140
			return;
141
		}
142
143
		int columnCount = getTree().getColumnCount();
144
		if (columnCount == 0)// If no columns are created then fake one
145
			columnCount = 1;
146
147
		for (int column = 0; column < columnCount; column++) {
148
			ViewerColumn columnViewer = getViewerColumn(column);
149
			columnViewer.refresh(updateCell(getViewerRowFromItem(treeItem),
150
					column));
151
152
			// As it is possible for user code to run the event
153
			// loop check here.
154
			if (item.isDisposed()) {
155
				unmapElement(element, item);
156
				return;
157
			}
158
159
		}
160
161
	}
106
	}
162
107
163
	/*
108
	protected int doGetColumnCount() {
164
	 * (non-Javadoc)
109
		return tree.getColumnCount();
165
	 * 
166
	 * @see org.eclipse.jface.viewers.ColumnViewer#getColumnViewerOwner(int)
167
	 */
168
	protected Widget getColumnViewerOwner(int columnIndex) {
169
		if (columnIndex < 0 || ( columnIndex > 0 && columnIndex >= getTree().getColumnCount() ) ) {
170
			return null;
171
		}
172
173
		if (getTree().getColumnCount() == 0)// Hang it off the table if it
174
			return getTree();
175
176
		return getTree().getColumn(columnIndex);
177
	}
110
	}
178
111
179
	/**
180
	 * Override to handle tree paths.
181
	 * 
182
	 * @see org.eclipse.jface.viewers.StructuredViewer#buildLabel(org.eclipse.jface.viewers.ViewerLabel,
183
	 *      java.lang.Object)
184
	 */
185
	protected void buildLabel(ViewerLabel updateLabel, Object elementOrPath) {
186
		Object element;
187
		if (elementOrPath instanceof TreePath) {
188
			TreePath path = (TreePath) elementOrPath;
189
			IBaseLabelProvider provider = getLabelProvider();
190
			if (provider instanceof ITreePathLabelProvider) {
191
				ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
192
				buildLabel(updateLabel, path, pprov);
193
				return;
194
			}
195
			element = path.getLastSegment();
196
		} else {
197
			element = elementOrPath;
198
		}
199
		super.buildLabel(updateLabel, element);
200
	}
201
202
	/*
203
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
204
	 */
205
	protected Item[] getChildren(Widget o) {
112
	protected Item[] getChildren(Widget o) {
206
		if (o instanceof TreeItem) {
113
		if (o instanceof TreeItem) {
207
			return ((TreeItem) o).getItems();
114
			return ((TreeItem) o).getItems();
Lines 211-335 Link Here
211
		}
118
		}
212
		return null;
119
		return null;
213
	}
120
	}
214
121
	
215
	/*
216
	 * (non-Javadoc) Method declared in Viewer.
217
	 */
218
	public Control getControl() {
122
	public Control getControl() {
219
		return tree;
123
		return tree;
220
	}
124
	}
221
125
222
	/*
223
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
224
	 */
225
	protected boolean getExpanded(Item item) {
126
	protected boolean getExpanded(Item item) {
226
		return ((TreeItem) item).getExpanded();
127
		return ((TreeItem) item).getExpanded();
227
	}
128
	}
228
129
229
	/*
230
	 * (non-Javadoc)
231
	 * 
232
	 * @see org.eclipse.jface.viewers.ColumnViewer#getItemAt(org.eclipse.swt.graphics.Point)
233
	 */
234
	protected Item getItemAt(Point p) {
130
	protected Item getItemAt(Point p) {
235
		return getTree().getItem(p);
131
		return tree.getItem(p);
236
	}
237
238
	/*
239
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
240
	 */
241
	protected int getItemCount(Control widget) {
242
		return ((Tree) widget).getItemCount();
243
	}
244
245
	/*
246
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
247
	 */
248
	protected int getItemCount(Item item) {
249
		return ((TreeItem) item).getItemCount();
250
	}
132
	}
251
133
252
	/*
253
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
254
	 */
255
	protected Item[] getItems(Item item) {
134
	protected Item[] getItems(Item item) {
256
		return ((TreeItem) item).getItems();
135
		return ((TreeItem) item).getItems();
257
	}
136
	}
258
137
	
259
	/**
138
	/**
260
	 * The tree viewer implementation of this <code>Viewer</code> framework
139
	 * Returns this tree viewer's tree control.
261
	 * method ensures that the given label provider is an instance of either
140
	 * 
262
	 * <code>ITableLabelProvider</code> or <code>ILabelProvider</code>. If
141
	 * @return the tree control
263
	 * it is an <code>ITableLabelProvider</code>, then it provides a separate
264
	 * label text and image for each column. If it is an
265
	 * <code>ILabelProvider</code>, then it provides only the label text and
266
	 * image for the first column, and any remaining columns are blank.
267
	 */
142
	 */
268
	public IBaseLabelProvider getLabelProvider() {
143
	public Tree getTree() {
269
		return super.getLabelProvider();
144
		return tree;
270
	}
145
	}
271
146
	
272
	/*
273
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
274
	 */
275
	protected Item getParentItem(Item item) {
147
	protected Item getParentItem(Item item) {
276
		return ((TreeItem) item).getParentItem();
148
		return ((TreeItem) item).getParentItem();
277
	}
149
	}
278
150
279
	/*
280
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
281
	 */
282
	protected Item[] getSelection(Control widget) {
151
	protected Item[] getSelection(Control widget) {
283
		return ((Tree) widget).getSelection();
152
		return ((Tree) widget).getSelection();
284
	}
153
	}
285
154
286
	/**
155
	protected Item doGetParentItem(Item item) {
287
	 * Returns this tree viewer's tree control.
156
		return ((TreeItem)item).getParentItem();
288
	 * 
289
	 * @return the tree control
290
	 */
291
	public Tree getTree() {
292
		return tree;
293
	}
157
	}
294
158
295
	/*
159
	protected int doIndexOf(Item parentItem, Item item) {
296
	 * (non-Javadoc)
160
		return ((TreeItem)parentItem).indexOf((TreeItem)item);
297
	 * 
298
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#hookControl(org.eclipse.swt.widgets.Control)
299
	 */
300
	protected void hookControl(Control control) {
301
		super.hookControl(control);
302
		Tree treeControl = (Tree) control;
303
		
304
		if ((treeControl.getStyle() & SWT.VIRTUAL) != 0) {
305
			treeControl.addDisposeListener(new DisposeListener() {
306
				public void widgetDisposed(DisposeEvent e) {
307
					treeIsDisposed = true;
308
					unmapAllElements();
309
				}
310
			});
311
			treeControl.addListener(SWT.SetData, new Listener() {
312
313
				public void handleEvent(Event event) {
314
					if (contentProviderIsLazy) {
315
						TreeItem item = (TreeItem) event.item;
316
						TreeItem parentItem = item.getParentItem();
317
						int index;
318
						if (parentItem != null) {
319
							index = parentItem.indexOf(item);
320
						} else {
321
							index = getTree().indexOf(item);
322
						}
323
						virtualLazyUpdateWidget(
324
								parentItem == null ? (Widget) getTree()
325
										: parentItem, index);
326
					}
327
				}
328
329
			});
330
		}
331
	}
161
	}
332
162
163
	protected int doIndexOf(Item item) {
164
		return tree.indexOf((TreeItem)item);
165
	}
166
	
333
	protected AbstractViewerEditor createViewerEditor() {
167
	protected AbstractViewerEditor createViewerEditor() {
334
		return new AbstractViewerEditor(this) {
168
		return new AbstractViewerEditor(this) {
335
169
Lines 361-470 Link Here
361
195
362
		};
196
		};
363
	}
197
	}
364
198
	
365
	/*
366
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
367
	 */
368
	protected Item newItem(Widget parent, int flags, int ix) {
369
		TreeItem item;
370
371
		if (parent instanceof TreeItem) {
372
			item = (TreeItem) createNewRowPart(getViewerRowFromItem(parent),
373
					flags, ix).getItem();
374
		} else {
375
			item = (TreeItem) createNewRowPart(null, flags, ix).getItem();
376
		}
377
378
		return item;
379
	}
380
381
	/*
382
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
383
	 */
384
	protected void removeAll(Control widget) {
199
	protected void removeAll(Control widget) {
385
		((Tree) widget).removeAll();
200
		((Tree) widget).removeAll();
386
	}
201
	}
387
202
388
	/*
203
	protected void doSetExpanded(Item item, boolean expanded) {
389
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
204
		((TreeItem) item).setExpanded(expanded);
390
	 */
391
	protected void setExpanded(Item node, boolean expand) {
392
		((TreeItem) node).setExpanded(expand);
393
		if (contentProviderIsLazy) {
394
			// force repaints to happen
395
			getControl().update();
396
		}
397
	}
205
	}
398
206
399
	/*
207
	protected void doSetSelection(List items) {
400
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
401
	 */
402
	protected void setSelection(List items) {
403
404
		Item[] current = getSelection(getTree());
405
406
		// Don't bother resetting the same selection
407
		if (isSameSelection(items, current)) {
408
			return;
409
		}
410
411
		TreeItem[] newItems = new TreeItem[items.size()];
208
		TreeItem[] newItems = new TreeItem[items.size()];
412
		items.toArray(newItems);
209
		items.toArray(newItems);
413
		getTree().setSelection(newItems);
210
		getTree().setSelection(newItems);
414
	}
211
	}
415
212
416
	/**
417
	 * Returns <code>true</code> if the given list and array of items refer to
418
	 * the same model elements. Order is unimportant.
419
	 * 
420
	 * @param items
421
	 *            the list of items
422
	 * @param current
423
	 *            the array of items
424
	 * @return <code>true</code> if the refer to the same elements,
425
	 *         <code>false</code> otherwise
426
	 * 
427
	 * @since 3.1
428
	 */
429
	protected boolean isSameSelection(List items, Item[] current) {
430
		// If they are not the same size then they are not equivalent
431
		int n = items.size();
432
		if (n != current.length) {
433
			return false;
434
		}
435
436
		CustomHashtable itemSet = newHashtable(n * 2 + 1);
437
		for (Iterator i = items.iterator(); i.hasNext();) {
438
			Item item = (Item) i.next();
439
			Object element = item.getData();
440
			itemSet.put(element, element);
441
		}
442
443
		// Go through the items of the current collection
444
		// If there is a mismatch return false
445
		for (int i = 0; i < current.length; i++) {
446
			if (current[i].getData() == null
447
					|| !itemSet.containsKey(current[i].getData())) {
448
				return false;
449
			}
450
		}
451
452
		return true;
453
	}
454
455
	/*
456
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
457
	 */
458
	protected void showItem(Item item) {
213
	protected void showItem(Item item) {
459
		getTree().showItem((TreeItem) item);
214
		getTree().showItem((TreeItem) item);
460
	}
215
	}
461
216
	
462
	/*
463
	 * (non-Javadoc)
464
	 * 
465
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#getChild(org.eclipse.swt.widgets.Widget,
466
	 *      int)
467
	 */
468
	protected Item getChild(Widget widget, int index) {
217
	protected Item getChild(Widget widget, int index) {
469
		if (widget instanceof TreeItem) {
218
		if (widget instanceof TreeItem) {
470
			return ((TreeItem) widget).getItem(index);
219
			return ((TreeItem) widget).getItem(index);
Lines 475-756 Link Here
475
		return null;
224
		return null;
476
	}
225
	}
477
226
478
	protected void assertContentProviderType(IContentProvider provider) {
227
	protected void doSetItemCount(int count) {
479
		if (provider instanceof ILazyTreeContentProvider
228
		getTree().setItemCount(count);
480
				|| provider instanceof ILazyTreePathContentProvider) {
481
			return;
482
		}
483
		super.assertContentProviderType(provider);
484
	}
229
	}
485
230
486
	protected Object[] getRawChildren(Object parent) {
231
	protected void doSetItemCount(Item item, int count) {
487
		if (contentProviderIsLazy) {
232
		((TreeItem)item).setItemCount(count);
488
			return new Object[0];
489
		}
490
		return super.getRawChildren(parent);
491
	}
233
	}
492
234
493
	/**
235
	protected int doGetItemCount() {
494
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, set the
236
		return tree.getItemCount();
495
	 * number of children of the given element or tree path. To set the number
496
	 * of children of the invisible root of the tree, you can pass the input
497
	 * object or an empty tree path.
498
	 * 
499
	 * @param elementOrTreePath
500
	 *            the element, or tree path
501
	 * @param count
502
	 * 
503
	 * @since 3.2
504
	 */
505
	public void setChildCount(final Object elementOrTreePath, final int count) {
506
		preservingSelection(new Runnable() {
507
			public void run() {
508
				if (internalIsInputOrEmptyPath(elementOrTreePath)) {
509
					getTree().setItemCount(count);
510
					return;
511
				}
512
				Widget[] items = internalFindItems(elementOrTreePath);
513
				for (int i = 0; i < items.length; i++) {
514
					TreeItem treeItem = (TreeItem) items[i];
515
					treeItem.setItemCount(count);
516
				}
517
			}
518
		});
519
	}
237
	}
520
238
521
	/**
239
	protected Item doGetItem(int index) {
522
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, replace the
240
		return tree.getItem(index);
523
	 * given parent's child at index with the given element. If the given parent
524
	 * is this viewer's input or an empty tree path, this will replace the root
525
	 * element at the given index.
526
	 * <p>
527
	 * This method should be called by implementers of ILazyTreeContentProvider
528
	 * to populate this viewer.
529
	 * </p>
530
	 * 
531
	 * @param parentElementOrTreePath
532
	 *            the parent of the element that should be updated, or the tree
533
	 *            path to that parent
534
	 * @param index
535
	 *            the index in the parent's children
536
	 * @param element
537
	 *            the new element
538
	 * 
539
	 * @see #setChildCount(Object, int)
540
	 * @see ILazyTreeContentProvider
541
	 * @see ILazyTreePathContentProvider
542
	 * 
543
	 * @since 3.2
544
	 */
545
	public void replace(final Object parentElementOrTreePath, final int index,
546
			final Object element) {
547
		preservingSelection(new Runnable() {
548
			public void run() {
549
				if (internalIsInputOrEmptyPath(parentElementOrTreePath)) {
550
					if (index < tree.getItemCount()) {
551
						updateItem(tree.getItem(index), element);
552
					}
553
				} else {
554
					Widget[] parentItems = internalFindItems(parentElementOrTreePath);
555
					for (int i = 0; i < parentItems.length; i++) {
556
						TreeItem parentItem = (TreeItem) parentItems[i];
557
						if (index < parentItem.getItemCount()) {
558
							updateItem(parentItem.getItem(index), element);
559
						}
560
					}
561
				}
562
			}
563
564
		});
565
	}
241
	}
566
242
567
	public boolean isExpandable(Object element) {
243
	protected Item doGetItem(Item item, int index) {
568
		if (contentProviderIsLazy) {
244
		return ((TreeItem)item).getItem(index);
569
			TreeItem treeItem = (TreeItem) internalExpand(element, false);
570
			if (treeItem == null) {
571
				return false;
572
			}
573
			virtualMaterializeItem(treeItem);
574
			return treeItem.getItemCount() > 0;
575
		}
576
		return super.isExpandable(element);
577
	}
245
	}
578
246
579
	protected Object getParentElement(Object element) {
247
	protected void doClearAll(Item item, boolean all) {
580
		if (contentProviderIsLazy && !contentProviderIsTreeBased && !(element instanceof TreePath)) {
248
		((TreeItem)item).clearAll(all);
581
			ILazyTreeContentProvider lazyTreeContentProvider = (ILazyTreeContentProvider) getContentProvider();
582
			return lazyTreeContentProvider.getParent(element);
583
		}
584
		if (contentProviderIsLazy && contentProviderIsTreeBased && !(element instanceof TreePath)) {
585
			ILazyTreePathContentProvider lazyTreePathContentProvider = (ILazyTreePathContentProvider) getContentProvider();
586
			TreePath[] parents = lazyTreePathContentProvider
587
					.getParents(element);
588
			if (parents != null && parents.length > 0) {
589
				return parents[0];
590
			}
591
		}
592
		return super.getParentElement(element);
593
	}
249
	}
594
250
595
	protected void createChildren(Widget widget) {
251
	protected int doGetItemCount(Item item) {
596
		if (contentProviderIsLazy) {
252
		return ((TreeItem)item).getItemCount();
597
			Object element = widget.getData();
598
			if (element == null && widget instanceof TreeItem) {
599
				// parent has not been materialized
600
				virtualMaterializeItem((TreeItem) widget);
601
				// try getting the element now that updateElement was called
602
				element = widget.getData();
603
			}
604
			if (element ==  null) {
605
				// give up because the parent is still not materialized
606
				return;
607
			}
608
			Item[] children = getChildren(widget);
609
			if (children.length == 1 && children[0].getData() == null) {
610
				// found a dummy node
611
				virtualLazyUpdateChildCount(widget, children.length);
612
				children = getChildren(widget);
613
			}
614
			// touch all children to make sure they are materialized
615
			for (int i = 0; i < children.length; i++) {
616
				if (children[i].getData() == null) {
617
					virtualLazyUpdateWidget(widget, i);
618
				}
619
			}
620
			return;
621
		}
622
		super.createChildren(widget);
623
	}
253
	}
624
254
625
	protected void internalAdd(Widget widget, Object parentElement,
255
	protected void doClearAll(boolean all) {
626
			Object[] childElements) {
256
		tree.clearAll(all);
627
		if (contentProviderIsLazy) {
628
			if (widget instanceof TreeItem) {
629
				TreeItem ti = (TreeItem) widget;
630
				int count = ti.getItemCount() + childElements.length;
631
				ti.setItemCount(count);
632
				ti.clearAll(false);
633
			} else {
634
				Tree t = (Tree) widget;
635
				t.setItemCount(t.getItemCount() + childElements.length);
636
				t.clearAll(false);
637
			}
638
			return;
639
		}
640
		super.internalAdd(widget, parentElement, childElements);
641
	}
257
	}
642
258
643
	private void virtualMaterializeItem(TreeItem treeItem) {
644
		if (treeItem.getData() != null) {
645
			// already materialized
646
			return;
647
		}
648
		if (!contentProviderIsLazy) {
649
			return;
650
		}
651
		int index;
652
		Widget parent = treeItem.getParentItem();
653
		if (parent == null) {
654
			parent = treeItem.getParent();
655
		}
656
		Object parentElement = parent.getData();
657
		if (parentElement != null) {
658
			if (parent instanceof Tree) {
659
				index = ((Tree) parent).indexOf(treeItem);
660
			} else {
661
				index = ((TreeItem) parent).indexOf(treeItem);
662
			}
663
			virtualLazyUpdateWidget(parent, index);
664
		}
665
	}
666
667
	/*
668
	 * (non-Javadoc)
669
	 * 
670
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefreshStruct(org.eclipse.swt.widgets.Widget,
671
	 *      java.lang.Object, boolean)
672
	 */
673
	protected void internalRefreshStruct(Widget widget, Object element,
674
			boolean updateLabels) {
675
		if (contentProviderIsLazy) {
676
			// first phase: update child counts
677
			virtualRefreshChildCounts(widget, element);
678
			// second phase: update labels
679
			if (updateLabels) {
680
				if (widget instanceof Tree) {
681
					((Tree) widget).clearAll(true);
682
				} else if (widget instanceof TreeItem) {
683
					((TreeItem) widget).clearAll(true);
684
				}
685
			}
686
			return;
687
		}
688
		super.internalRefreshStruct(widget, element, updateLabels);
689
	}
690
691
	/**
692
	 * Traverses the visible (expanded) part of the tree and updates child
693
	 * counts.
694
	 * 
695
	 * @param widget
696
	 * @param element
697
	 */
698
	private void virtualRefreshChildCounts(Widget widget, Object element) {
699
		if (widget instanceof Tree || ((TreeItem) widget).getExpanded()) {
700
			// widget shows children - it is safe to call getChildren
701
			if (element != null) {
702
				virtualLazyUpdateChildCount(widget, getChildren(widget).length);
703
			} else {
704
				if (widget instanceof Tree) {
705
					((Tree) widget).setItemCount(0);
706
				} else {
707
					((TreeItem) widget).setItemCount(0);
708
				}
709
			}
710
			// need to get children again because they might have been updated
711
			// through a callback to setChildCount.
712
			Item[] items = getChildren(widget);
713
			for (int i = 0; i < items.length; i++) {
714
				Item item = items[i];
715
				Object data = item.getData();
716
				if (data != null) {
717
					virtualRefreshChildCounts(item, data);
718
				}
719
			}
720
		}
721
	}
722
723
	/*
724
	 * To unmap elements correctly, we need to register a dispose listener with
725
	 * the item if the tree is virtual.
726
	 */
727
	protected void mapElement(Object element, final Widget item) {
728
		super.mapElement(element, item);
729
		// make sure to unmap elements if the tree is virtual
730
		if ((getTree().getStyle() & SWT.VIRTUAL) != 0) {
731
			// only add a dispose listener if item hasn't already on assigned
732
			// because it is reused
733
			if (item.getData(VIRTUAL_DISPOSE_KEY) == null) {
734
				item.setData(VIRTUAL_DISPOSE_KEY, Boolean.TRUE);
735
				item.addDisposeListener(new DisposeListener() {
736
					public void widgetDisposed(DisposeEvent e) {
737
						if (!treeIsDisposed) {
738
							Object data = item.getData();
739
							if (usingElementMap() && data != null) {
740
								unmapElement(data, item);
741
							}
742
						}
743
					}
744
				});
745
			}
746
		}
747
	}
748
749
	/*
750
	 * (non-Javadoc)
751
	 * 
752
	 * @see org.eclipse.jface.viewers.ColumnViewer#getRowPartFromItem(org.eclipse.swt.widgets.Widget)
753
	 */
754
	protected ViewerRow getViewerRowFromItem(Widget item) {
259
	protected ViewerRow getViewerRowFromItem(Widget item) {
755
		ViewerRow part = (ViewerRow) item.getData(ViewerRow.ROWPART_KEY);
260
		ViewerRow part = (ViewerRow) item.getData(ViewerRow.ROWPART_KEY);
756
261
Lines 760-775 Link Here
760
265
761
		return part;
266
		return part;
762
	}
267
	}
268
	
763
269
764
	/**
270
	protected ViewerRow doCreateNewRowPart(ViewerRow parent, int style, int rowIndex) {
765
	 * Create a new ViewerRow at rowIndex
766
	 * 
767
	 * @param parent
768
	 * @param style
769
	 * @param rowIndex
770
	 * @return ViewerRow
771
	 */
772
	private ViewerRow createNewRowPart(ViewerRow parent, int style, int rowIndex) {
773
		if (parent == null) {
271
		if (parent == null) {
774
			if (rowIndex >= 0) {
272
			if (rowIndex >= 0) {
775
				return getViewerRowFromItem(new TreeItem(tree, style, rowIndex));
273
				return getViewerRowFromItem(new TreeItem(tree, style, rowIndex));
Lines 786-1012 Link Here
786
				SWT.NONE));
284
				SWT.NONE));
787
	}
285
	}
788
286
789
	/*
287
				
790
	 * (non-Javadoc)
288
	protected void doClear(Item item, boolean all) {
791
	 * 
289
		((TreeItem)item).clear(0, true);
792
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalInitializeTree(org.eclipse.swt.widgets.Control)
793
	 */
794
	protected void internalInitializeTree(Control widget) {
795
		if (contentProviderIsLazy) {
796
			if (widget instanceof Tree && widget.getData() != null) {
797
				virtualLazyUpdateChildCount(widget, 0);
798
				return;
799
			}
800
		}
801
		super.internalInitializeTree(tree);
802
	}
803
804
	/*
805
	 * (non-Javadoc)
806
	 * 
807
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#updatePlus(org.eclipse.swt.widgets.Item,
808
	 *      java.lang.Object)
809
	 */
810
	protected void updatePlus(Item item, Object element) {
811
		if (contentProviderIsLazy) {
812
			Object data = item.getData();
813
			int itemCount = 0;
814
			if (data != null) {
815
				// item is already materialized
816
				itemCount = ((TreeItem) item).getItemCount();
817
			}
818
			virtualLazyUpdateHasChildren(item, itemCount);
819
		} else {
820
			super.updatePlus(item, element);
821
		}
822
	}
823
824
	/**
825
	 * Removes the element at the specified index of the parent.  The selection is updated if required.
826
	 * 
827
	 * @param parentOrTreePath the parent element, the input element, or a tree path to the parent element 
828
	 * @param index child index
829
	 * @since 3.3
830
	 */
831
	public void remove(final Object parentOrTreePath, final int index) {
832
		preservingSelection(new Runnable() {
833
			public void run() {
834
				if (internalIsInputOrEmptyPath(parentOrTreePath)) {
835
					Tree tree = (Tree) getControl();
836
					if (index < tree.getItemCount()) {
837
						TreeItem item = tree.getItem(index);
838
						if (item.getData() != null) {
839
							disassociate(item);
840
						}
841
						item.dispose();
842
					}
843
				} else {
844
					Widget[] parentItems = internalFindItems(parentOrTreePath);
845
					for (int i = 0; i < parentItems.length; i++) {
846
						TreeItem parentItem = (TreeItem) parentItems[i];
847
						if (index < parentItem.getItemCount()) {
848
							TreeItem item = parentItem.getItem(index);
849
							if (item.getData() != null) {
850
								disassociate(item);
851
							}
852
							item.dispose();
853
						}
854
					}
855
				}
856
			}
857
		});
858
	}
859
	
860
	/* (non-Javadoc)
861
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#handleTreeExpand(org.eclipse.swt.events.TreeEvent)
862
	 */
863
	protected void handleTreeExpand(TreeEvent event) {
864
		if (contentProviderIsLazy) {
865
			if (event.item.getData() != null) {
866
				Item[] children = getChildren(event.item);
867
				if (children.length == 1 && children[0].getData()==null) {
868
					// we have a dummy child node, ask for an updated child
869
					// count
870
					virtualLazyUpdateChildCount(event.item, children.length);
871
				}
872
				fireTreeExpanded(new TreeExpansionEvent(this, event.item
873
						.getData()));
874
			}
875
			return;
876
		}
877
		super.handleTreeExpand(event);
878
	}
879
	
880
	/* (non-Javadoc)
881
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#setContentProvider(org.eclipse.jface.viewers.IContentProvider)
882
	 */
883
	public void setContentProvider(IContentProvider provider) {
884
		contentProviderIsLazy = (provider instanceof ILazyTreeContentProvider)
885
				|| (provider instanceof ILazyTreePathContentProvider);
886
		contentProviderIsTreeBased = provider instanceof ILazyTreePathContentProvider;
887
		super.setContentProvider(provider);
888
	}
889
	
890
	/**
891
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, inform the
892
	 * viewer about whether the given element or tree path has children. Avoid
893
	 * calling this method if the number of children has already been set.
894
	 * 
895
	 * @param elementOrTreePath
896
	 *            the element, or tree path
897
	 * @param hasChildren
898
	 * 
899
	 * @since 3.3
900
	 */
901
	public void setHasChildren(Object elementOrTreePath, boolean hasChildren) {
902
		if (internalIsInputOrEmptyPath(elementOrTreePath)) {
903
			if (hasChildren) {
904
				virtualLazyUpdateChildCount(getTree(), getChildren(getTree()).length);
905
			} else {
906
				setChildCount(elementOrTreePath, 0);
907
			}
908
			return;
909
		}
910
		Widget[] items = internalFindItems(elementOrTreePath);
911
		for (int i = 0; i < items.length; i++) {
912
				TreeItem item = (TreeItem) items[i];
913
				if (!hasChildren) {
914
					item.setItemCount(0);
915
				} else {
916
					if (!item.getExpanded()) {
917
						item.setItemCount(1);
918
						TreeItem child = item.getItem(0);
919
						if (child.getData() != null) {
920
							disassociate(child);
921
						}
922
						item.clear(0, true);
923
					}
924
				}
925
		}
926
	}
927
928
	/**
929
	 * Update the widget at index.
930
	 * @param widget
931
	 * @param index
932
	 */
933
	private void virtualLazyUpdateWidget(Widget widget, int index) {
934
		if (contentProviderIsTreeBased) {
935
			TreePath treePath;
936
			if (widget instanceof Item) {
937
				if (widget.getData() == null) {
938
					// temporary fix to avoid a NPE (the tree will still be screwed up)
939
					// see bug 167668
940
					return;
941
				}
942
				treePath = getTreePathFromItem((Item) widget);
943
			} else {
944
				treePath = TreePath.EMPTY;
945
			}
946
			((ILazyTreePathContentProvider) getContentProvider())
947
					.updateElement(treePath, index);
948
		} else {
949
			((ILazyTreeContentProvider) getContentProvider()).updateElement(
950
					widget.getData(), index);
951
		}
952
	}
953
954
	/**
955
	 * Update the child count
956
	 * @param widget
957
	 * @param currentChildCount
958
	 */
959
	private void virtualLazyUpdateChildCount(Widget widget, int currentChildCount) {
960
		if (contentProviderIsTreeBased) {
961
			TreePath treePath;
962
			if (widget instanceof Item) {
963
				treePath = getTreePathFromItem((Item) widget);
964
			} else {
965
				treePath = TreePath.EMPTY;
966
			}
967
			((ILazyTreePathContentProvider) getContentProvider())
968
					.updateChildCount(treePath, currentChildCount);
969
		} else {
970
			((ILazyTreeContentProvider) getContentProvider()).updateChildCount(widget.getData(), currentChildCount);
971
		}
972
	}
973
	
974
	/**
975
	 * Update the item with the current child count.
976
	 * @param item
977
	 * @param currentChildCount
978
	 */
979
	private void virtualLazyUpdateHasChildren(Item item, int currentChildCount) {
980
		if (contentProviderIsTreeBased) {
981
			TreePath treePath;
982
			treePath = getTreePathFromItem(item);
983
			if (currentChildCount == 0) {
984
				// item is not expanded (but may have a plus currently)
985
				((ILazyTreePathContentProvider) getContentProvider())
986
						.updateHasChildren(treePath);
987
			} else {
988
				((ILazyTreePathContentProvider) getContentProvider())
989
						.updateChildCount(treePath, currentChildCount);
990
			}
991
		} else {
992
			((ILazyTreeContentProvider) getContentProvider()).updateChildCount(item.getData(), currentChildCount);
993
		}
994
	}
995
996
	private boolean internalIsInputOrEmptyPath(final Object elementOrTreePath) {
997
		if (elementOrTreePath.equals(getInput()))
998
			return true;
999
		if (!(elementOrTreePath instanceof TreePath))
1000
			return false;
1001
		return ((TreePath) elementOrTreePath).getSegmentCount() == 0;
1002
	}
1003
	
1004
	protected void disassociate(Item item) {
1005
		if (contentProviderIsLazy) {
1006
			// avoid causing a callback:
1007
			item.setText(" "); //$NON-NLS-1$
1008
		}
1009
		super.disassociate(item);
1010
	}
290
	}
1011
291
1012
}
292
}
(-)src/org/eclipse/jface/viewers/AbstractTreeViewer.java (+2 lines)
Lines 1920-1925 Link Here
1920
	 *         element can be expanded, or <code>false</code> if not
1920
	 *         element can be expanded, or <code>false</code> if not
1921
	 */
1921
	 */
1922
	public boolean isExpandable(Object elementOrTreePath) {
1922
	public boolean isExpandable(Object elementOrTreePath) {
1923
		System.err.println("EXPANDABLE CHECK"); //$NON-NLS-1$
1923
		Object element;
1924
		Object element;
1924
		TreePath path;
1925
		TreePath path;
1925
		if (elementOrTreePath instanceof TreePath) {
1926
		if (elementOrTreePath instanceof TreePath) {
Lines 1931-1936 Link Here
1931
		}
1932
		}
1932
		IContentProvider cp = getContentProvider();
1933
		IContentProvider cp = getContentProvider();
1933
		if (cp instanceof ITreePathContentProvider) {
1934
		if (cp instanceof ITreePathContentProvider) {
1935
			System.err.println("TREE-PATH"); //$NON-NLS-1$
1934
			ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
1936
			ITreePathContentProvider tpcp = (ITreePathContentProvider) cp;
1935
			if (path == null) {
1937
			if (path == null) {
1936
				// A path was not provided so try and find one
1938
				// A path was not provided so try and find one
(-)src/org/eclipse/jface/viewers/AbstractTableViewer.java (+3 lines)
Lines 19-24 Link Here
19
19
20
import org.eclipse.core.runtime.Assert;
20
import org.eclipse.core.runtime.Assert;
21
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.graphics.Point;
22
import org.eclipse.swt.widgets.Control;
23
import org.eclipse.swt.widgets.Control;
23
import org.eclipse.swt.widgets.Event;
24
import org.eclipse.swt.widgets.Event;
24
import org.eclipse.swt.widgets.Item;
25
import org.eclipse.swt.widgets.Item;
Lines 1272-1275 Link Here
1272
	 * @since 3.3
1273
	 * @since 3.3
1273
	 */
1274
	 */
1274
	protected abstract void doClear(int index);
1275
	protected abstract void doClear(int index);
1276
	
1277
	protected abstract Item getItemAt(Point p);
1275
}
1278
}
(-)src/org/eclipse/jface/viewers/VirtualAbstractTreeViewer.java (+1152 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2006 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *     Tom Schindl <tom.schindl@bestsolution.at> - concept of ViewerRow,
11
 *                                                 refactoring (bug 153993)
12
 *******************************************************************************/
13
14
package org.eclipse.jface.viewers;
15
16
import java.util.Iterator;
17
import java.util.List;
18
19
import org.eclipse.jface.util.Policy;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.SWTException;
22
import org.eclipse.swt.events.DisposeEvent;
23
import org.eclipse.swt.events.DisposeListener;
24
import org.eclipse.swt.events.TreeEvent;
25
import org.eclipse.swt.graphics.Point;
26
import org.eclipse.swt.widgets.Control;
27
import org.eclipse.swt.widgets.Event;
28
import org.eclipse.swt.widgets.Item;
29
import org.eclipse.swt.widgets.Listener;
30
import org.eclipse.swt.widgets.Widget;
31
32
/**
33
 * A concrete viewer based on an SWT <code>Tree</code> control.
34
 * <p>
35
 * This class is not intended to be subclassed outside the viewer framework. It
36
 * is designed to be instantiated with a pre-existing SWT tree control and
37
 * configured with a domain-specific content provider, label provider, element
38
 * filter (optional), and element sorter (optional).
39
 * </p>
40
 * <p>
41
 * Content providers for tree viewers must implement either the
42
 * {@link ITreeContentProvider} interface, (as of 3.2) the
43
 * {@link ILazyTreeContentProvider} interface, or (as of 3.3) the
44
 * {@link ILazyTreePathContentProvider}. If the content provider is an
45
 * <code>ILazyTreeContentProvider</code> or an
46
 * <code>ILazyTreePathContentProvider</code>, the underlying Tree must be
47
 * created using the {@link SWT#VIRTUAL} style bit, and the tree viewer will not
48
 * support sorting or filtering.
49
 * </p>
50
 */
51
public abstract class VirtualAbstractTreeViewer extends AbstractTreeViewer {
52
53
	private static final String VIRTUAL_DISPOSE_KEY = Policy.JFACE
54
			+ ".DISPOSE_LISTENER"; //$NON-NLS-1$
55
56
	/**
57
	 * Flag for whether the tree has been disposed of.
58
	 */
59
	private boolean treeIsDisposed = false;
60
61
	private boolean contentProviderIsLazy;
62
63
	private boolean contentProviderIsTreeBased;
64
65
	/*
66
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
67
	 */
68
	protected void doUpdateItem(final Item item, Object element) {
69
		if (item.isDisposed()) {
70
			unmapElement(element, item);
71
			return;
72
		}
73
74
		int columnCount = doGetColumnCount();
75
		if (columnCount == 0)// If no columns are created then fake one
76
			columnCount = 1;
77
78
		for (int column = 0; column < columnCount; column++) {
79
			ViewerColumn columnViewer = getViewerColumn(column);
80
			columnViewer
81
					.refresh(updateCell(getViewerRowFromItem(item), column));
82
83
			// As it is possible for user code to run the event
84
			// loop check here.
85
			if (item.isDisposed()) {
86
				unmapElement(element, item);
87
				return;
88
			}
89
90
		}
91
	}
92
93
	/*
94
	 * (non-Javadoc)
95
	 * 
96
	 * @see org.eclipse.jface.viewers.ColumnViewer#getColumnViewerOwner(int)
97
	 */
98
	protected Widget getColumnViewerOwner(int columnIndex) {
99
		if (columnIndex < 0
100
				|| (columnIndex > 0 && columnIndex >= doGetColumnCount())) {
101
			return null;
102
		}
103
104
		if (doGetColumnCount() == 0)// Hang it off the table if it
105
			return getControl();
106
107
		return doGetColumn(columnIndex);
108
	}
109
110
	/**
111
	 * Override to handle tree paths.
112
	 * 
113
	 * @see org.eclipse.jface.viewers.StructuredViewer#buildLabel(org.eclipse.jface.viewers.ViewerLabel,
114
	 *      java.lang.Object)
115
	 */
116
	protected void buildLabel(ViewerLabel updateLabel, Object elementOrPath) {
117
		Object element;
118
		if (elementOrPath instanceof TreePath) {
119
			TreePath path = (TreePath) elementOrPath;
120
			IBaseLabelProvider provider = getLabelProvider();
121
			if (provider instanceof ITreePathLabelProvider) {
122
				ITreePathLabelProvider pprov = (ITreePathLabelProvider) provider;
123
				buildLabel(updateLabel, path, pprov);
124
				return;
125
			}
126
			element = path.getLastSegment();
127
		} else {
128
			element = elementOrPath;
129
		}
130
		super.buildLabel(updateLabel, element);
131
	}
132
133
	/**
134
	 * The tree viewer implementation of this <code>Viewer</code> framework
135
	 * method ensures that the given label provider is an instance of either
136
	 * <code>ITableLabelProvider</code> or <code>ILabelProvider</code>. If
137
	 * it is an <code>ITableLabelProvider</code>, then it provides a separate
138
	 * label text and image for each column. If it is an
139
	 * <code>ILabelProvider</code>, then it provides only the label text and
140
	 * image for the first column, and any remaining columns are blank.
141
	 */
142
	public IBaseLabelProvider getLabelProvider() {
143
		return super.getLabelProvider();
144
	}
145
146
	/*
147
	 * (non-Javadoc)
148
	 * 
149
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#hookControl(org.eclipse.swt.widgets.Control)
150
	 */
151
	protected void hookControl(Control control) {
152
		super.hookControl(control);
153
154
		if ((control.getStyle() & SWT.VIRTUAL) != 0) {
155
			control.addDisposeListener(new DisposeListener() {
156
				public void widgetDisposed(DisposeEvent e) {
157
					treeIsDisposed = true;
158
					unmapAllElements();
159
				}
160
			});
161
			control.addListener(SWT.SetData, new Listener() {
162
163
				public void handleEvent(Event event) {
164
					if (contentProviderIsLazy) {
165
						Item item = (Item) event.item;
166
						Item parentItem = doGetParentItem(item);
167
						int index;
168
						if (parentItem != null) {
169
							index = doIndexOf(parentItem, item);
170
						} else {
171
							index = doIndexOf(item);
172
						}
173
						virtualLazyUpdateWidget(
174
								parentItem == null ? (Widget) getControl()
175
										: parentItem, index);
176
					}
177
				}
178
179
			});
180
		}
181
	}
182
183
	/*
184
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
185
	 */
186
	protected Item newItem(Widget parent, int flags, int ix) {
187
		Item item;
188
189
		if (parent instanceof Item) {
190
			item = doCreateNewRowPart(getViewerRowFromItem(parent), flags, ix)
191
					.getItem();
192
		} else {
193
			item = doCreateNewRowPart(null, flags, ix).getItem();
194
		}
195
196
		return item;
197
	}
198
199
	/*
200
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
201
	 */
202
	protected void setExpanded(Item node, boolean expand) {
203
		doSetExpanded(node, expand);
204
		if (contentProviderIsLazy) {
205
			// force repaints to happen
206
			getControl().update();
207
		}
208
	}
209
210
	/*
211
	 * (non-Javadoc) Method declared in AbstractTreeViewer.
212
	 */
213
	protected void setSelection(List items) {
214
215
		Item[] current = getSelection(getControl());
216
217
		// Don't bother resetting the same selection
218
		if (isSameSelection(items, current)) {
219
			return;
220
		}
221
222
		doSetSelection(items);
223
	}
224
225
	/**
226
	 * Returns <code>true</code> if the given list and array of items refer to
227
	 * the same model elements. Order is unimportant.
228
	 * 
229
	 * @param items
230
	 *            the list of items
231
	 * @param current
232
	 *            the array of items
233
	 * @return <code>true</code> if the refer to the same elements,
234
	 *         <code>false</code> otherwise
235
	 * 
236
	 * @since 3.1
237
	 */
238
	protected boolean isSameSelection(List items, Item[] current) {
239
		// If they are not the same size then they are not equivalent
240
		int n = items.size();
241
		if (n != current.length) {
242
			return false;
243
		}
244
245
		CustomHashtable itemSet = newHashtable(n * 2 + 1);
246
		for (Iterator i = items.iterator(); i.hasNext();) {
247
			Item item = (Item) i.next();
248
			Object element = item.getData();
249
			itemSet.put(element, element);
250
		}
251
252
		// Go through the items of the current collection
253
		// If there is a mismatch return false
254
		for (int i = 0; i < current.length; i++) {
255
			if (current[i].getData() == null
256
					|| !itemSet.containsKey(current[i].getData())) {
257
				return false;
258
			}
259
		}
260
261
		return true;
262
	}
263
264
	protected void assertContentProviderType(IContentProvider provider) {
265
		if (provider instanceof ILazyTreeContentProvider
266
				|| provider instanceof ILazyTreePathContentProvider) {
267
			return;
268
		}
269
		super.assertContentProviderType(provider);
270
	}
271
272
	protected Object[] getRawChildren(Object parent) {
273
		if (contentProviderIsLazy) {
274
			return new Object[0];
275
		}
276
		return super.getRawChildren(parent);
277
	}
278
279
	/**
280
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, set the
281
	 * number of children of the given element or tree path. To set the number
282
	 * of children of the invisible root of the tree, you can pass the input
283
	 * object or an empty tree path.
284
	 * 
285
	 * @param elementOrTreePath
286
	 *            the element, or tree path
287
	 * @param count
288
	 * 
289
	 * @since 3.2
290
	 */
291
	public void setChildCount(final Object elementOrTreePath, final int count) {
292
		preservingSelection(new Runnable() {
293
			public void run() {
294
				if (internalIsInputOrEmptyPath(elementOrTreePath)) {
295
					doSetItemCount(count);
296
					return;
297
				}
298
				Widget[] items = internalFindItems(elementOrTreePath);
299
				for (int i = 0; i < items.length; i++) {
300
					doSetItemCount((Item) items[i], count);
301
				}
302
			}
303
		});
304
	}
305
306
	/**
307
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, replace the
308
	 * given parent's child at index with the given element. If the given parent
309
	 * is this viewer's input or an empty tree path, this will replace the root
310
	 * element at the given index.
311
	 * <p>
312
	 * This method should be called by implementers of ILazyTreeContentProvider
313
	 * to populate this viewer.
314
	 * </p>
315
	 * 
316
	 * @param parentElementOrTreePath
317
	 *            the parent of the element that should be updated, or the tree
318
	 *            path to that parent
319
	 * @param index
320
	 *            the index in the parent's children
321
	 * @param element
322
	 *            the new element
323
	 * 
324
	 * @see #setChildCount(Object, int)
325
	 * @see ILazyTreeContentProvider
326
	 * @see ILazyTreePathContentProvider
327
	 * 
328
	 * @since 3.2
329
	 */
330
	public void replace(final Object parentElementOrTreePath, final int index,
331
			final Object element) {
332
		preservingSelection(new Runnable() {
333
			public void run() {
334
				if (internalIsInputOrEmptyPath(parentElementOrTreePath)) {
335
					if (index < doGetItemCount()) {
336
						updateItem(doGetItem(index), element);
337
					}
338
				} else {
339
					Widget[] parentItems = internalFindItems(parentElementOrTreePath);
340
					for (int i = 0; i < parentItems.length; i++) {
341
						Item parentItem = (Item) parentItems[i];
342
						if (index < doGetItemCount(parentItem)) {
343
							updateItem(doGetItem(parentItem, index), element);
344
						}
345
					}
346
				}
347
			}
348
349
		});
350
	}
351
352
	public boolean isExpandable(Object element) {
353
		if (contentProviderIsLazy) {
354
			Item treeItem = (Item) internalExpand(element, false);
355
			if (treeItem == null) {
356
				return false;
357
			}
358
			virtualMaterializeItem(treeItem);
359
			return doGetItemCount(treeItem) > 0;
360
		}
361
		return super.isExpandable(element);
362
	}
363
364
	protected Object getParentElement(Object element) {
365
		if (contentProviderIsLazy && !contentProviderIsTreeBased
366
				&& !(element instanceof TreePath)) {
367
			ILazyTreeContentProvider lazyTreeContentProvider = (ILazyTreeContentProvider) getContentProvider();
368
			return lazyTreeContentProvider.getParent(element);
369
		}
370
		if (contentProviderIsLazy && contentProviderIsTreeBased
371
				&& !(element instanceof TreePath)) {
372
			ILazyTreePathContentProvider lazyTreePathContentProvider = (ILazyTreePathContentProvider) getContentProvider();
373
			TreePath[] parents = lazyTreePathContentProvider
374
					.getParents(element);
375
			if (parents != null && parents.length > 0) {
376
				return parents[0];
377
			}
378
		}
379
		return super.getParentElement(element);
380
	}
381
382
	protected void createChildren(Widget widget) {
383
		if (contentProviderIsLazy) {
384
			Object element = widget.getData();
385
			if (element == null && widget instanceof Item) {
386
				// parent has not been materialized
387
				virtualMaterializeItem((Item) widget);
388
				// try getting the element now that updateElement was called
389
				element = widget.getData();
390
			}
391
			if (element == null) {
392
				// give up because the parent is still not materialized
393
				return;
394
			}
395
			Item[] children = getChildren(widget);
396
			if (children.length == 1 && children[0].getData() == null) {
397
				// found a dummy node
398
				virtualLazyUpdateChildCount(widget, children.length);
399
				children = getChildren(widget);
400
			}
401
			// touch all children to make sure they are materialized
402
			for (int i = 0; i < children.length; i++) {
403
				if (children[i].getData() == null) {
404
					virtualLazyUpdateWidget(widget, i);
405
				}
406
			}
407
			return;
408
		}
409
		super.createChildren(widget);
410
	}
411
412
	protected void internalAdd(Widget widget, Object parentElement,
413
			Object[] childElements) {
414
		if (contentProviderIsLazy) {
415
			if (widget instanceof Item) {
416
				Item ti = (Item) widget;
417
				int count = doGetItemCount(ti) + childElements.length;
418
				doSetItemCount(ti, count);
419
				doClearAll(ti, false);
420
			} else {
421
				doSetItemCount(doGetItemCount() + childElements.length);
422
				doClearAll(false);
423
			}
424
			return;
425
		}
426
		super.internalAdd(widget, parentElement, childElements);
427
	}
428
429
	private void virtualMaterializeItem(Item treeItem) {
430
		if (treeItem.getData() != null) {
431
			// already materialized
432
			return;
433
		}
434
		if (!contentProviderIsLazy) {
435
			return;
436
		}
437
		int index;
438
		Widget parent = doGetParentItem(treeItem);
439
		if (parent == null) {
440
			parent = getControl();
441
		}
442
		Object parentElement = parent.getData();
443
		if (parentElement != null) {
444
			if (parent instanceof Item) {
445
				index = doIndexOf((Item) parent, treeItem);
446
			} else {
447
				index = doIndexOf(treeItem);
448
			}
449
			virtualLazyUpdateWidget(parent, index);
450
		}
451
	}
452
453
	/*
454
	 * (non-Javadoc)
455
	 * 
456
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefreshStruct(org.eclipse.swt.widgets.Widget,
457
	 *      java.lang.Object, boolean)
458
	 */
459
	protected void internalRefreshStruct(Widget widget, Object element,
460
			boolean updateLabels) {
461
		if (contentProviderIsLazy) {
462
			// first phase: update child counts
463
			virtualRefreshChildCounts(widget, element);
464
			// second phase: update labels
465
			if (updateLabels) {
466
				if (widget instanceof Item) {
467
					doClearAll((Item) widget, true);
468
				} else if (widget instanceof Control) {
469
					doClearAll(true);
470
				}
471
			}
472
			return;
473
		}
474
		super.internalRefreshStruct(widget, element, updateLabels);
475
	}
476
477
	/**
478
	 * Traverses the visible (expanded) part of the tree and updates child
479
	 * counts.
480
	 * 
481
	 * @param widget
482
	 * @param element
483
	 */
484
	private void virtualRefreshChildCounts(Widget widget, Object element) {
485
		if (widget instanceof Control || getExpanded((Item) widget)) {
486
			// widget shows children - it is safe to call getChildren
487
			if (element != null) {
488
				virtualLazyUpdateChildCount(widget, getChildren(widget).length);
489
			} else {
490
				if (widget instanceof Item) {
491
					doSetItemCount((Item) widget, 0);
492
				} else {
493
					doSetItemCount(0);
494
				}
495
			}
496
			// need to get children again because they might have been updated
497
			// through a callback to setChildCount.
498
			Item[] items = getChildren(widget);
499
			for (int i = 0; i < items.length; i++) {
500
				Item item = items[i];
501
				Object data = item.getData();
502
				if (data != null) {
503
					virtualRefreshChildCounts(item, data);
504
				}
505
			}
506
		}
507
	}
508
509
	/*
510
	 * To unmap elements correctly, we need to register a dispose listener with
511
	 * the item if the tree is virtual.
512
	 */
513
	protected void mapElement(Object element, final Widget item) {
514
		super.mapElement(element, item);
515
		// make sure to unmap elements if the tree is virtual
516
		if ((getControl().getStyle() & SWT.VIRTUAL) != 0) {
517
			// only add a dispose listener if item hasn't already on assigned
518
			// because it is reused
519
			if (item.getData(VIRTUAL_DISPOSE_KEY) == null) {
520
				item.setData(VIRTUAL_DISPOSE_KEY, Boolean.TRUE);
521
				item.addDisposeListener(new DisposeListener() {
522
					public void widgetDisposed(DisposeEvent e) {
523
						if (!treeIsDisposed) {
524
							Object data = item.getData();
525
							if (usingElementMap() && data != null) {
526
								unmapElement(data, item);
527
							}
528
						}
529
					}
530
				});
531
			}
532
		}
533
	}
534
535
	/*
536
	 * (non-Javadoc)
537
	 * 
538
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#internalInitializeTree(org.eclipse.swt.widgets.Control)
539
	 */
540
	protected void internalInitializeTree(Control widget) {
541
		if (contentProviderIsLazy) {
542
			if (widget.getData() != null) {
543
				virtualLazyUpdateChildCount(widget, 0);
544
				return;
545
			}
546
		}
547
		super.internalInitializeTree(getControl());
548
	}
549
550
	/*
551
	 * (non-Javadoc)
552
	 * 
553
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#updatePlus(org.eclipse.swt.widgets.Item,
554
	 *      java.lang.Object)
555
	 */
556
	protected void updatePlus(Item item, Object element) {
557
		if (contentProviderIsLazy) {
558
			Object data = item.getData();
559
			int itemCount = 0;
560
			if (data != null) {
561
				// item is already materialized
562
				itemCount = doGetItemCount(item);
563
			}
564
			virtualLazyUpdateHasChildren(item, itemCount);
565
		} else {
566
			super.updatePlus(item, element);
567
		}
568
	}
569
570
	/**
571
	 * Removes the element at the specified index of the parent. The selection
572
	 * is updated if required.
573
	 * 
574
	 * @param parentOrTreePath
575
	 *            the parent element, the input element, or a tree path to the
576
	 *            parent element
577
	 * @param index
578
	 *            child index
579
	 * @since 3.3
580
	 */
581
	public void remove(final Object parentOrTreePath, final int index) {
582
		preservingSelection(new Runnable() {
583
			public void run() {
584
				if (internalIsInputOrEmptyPath(parentOrTreePath)) {
585
586
					if (index < doGetItemCount()) {
587
						Item item = doGetItem(index);
588
						if (item.getData() != null) {
589
							disassociate(item);
590
						}
591
						item.dispose();
592
					}
593
				} else {
594
					Widget[] parentItems = internalFindItems(parentOrTreePath);
595
					for (int i = 0; i < parentItems.length; i++) {
596
						Item parentItem = (Item) parentItems[i];
597
						if (index < doGetItemCount(parentItem)) {
598
							Item item = doGetItem(parentItem, index);
599
							if (item.getData() != null) {
600
								disassociate(item);
601
							}
602
							item.dispose();
603
						}
604
					}
605
				}
606
			}
607
		});
608
	}
609
610
	/*
611
	 * (non-Javadoc)
612
	 * 
613
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#handleTreeExpand(org.eclipse.swt.events.TreeEvent)
614
	 */
615
	protected void handleTreeExpand(TreeEvent event) {
616
		if (contentProviderIsLazy) {
617
			if (event.item.getData() != null) {
618
				Item[] children = getChildren(event.item);
619
				if (children.length == 1 && children[0].getData() == null) {
620
					// we have a dummy child node, ask for an updated child
621
					// count
622
					virtualLazyUpdateChildCount(event.item, children.length);
623
				}
624
				fireTreeExpanded(new TreeExpansionEvent(this, event.item
625
						.getData()));
626
			}
627
			return;
628
		}
629
		super.handleTreeExpand(event);
630
	}
631
632
	/*
633
	 * (non-Javadoc)
634
	 * 
635
	 * @see org.eclipse.jface.viewers.AbstractTreeViewer#setContentProvider(org.eclipse.jface.viewers.IContentProvider)
636
	 */
637
	public void setContentProvider(IContentProvider provider) {
638
		contentProviderIsLazy = (provider instanceof ILazyTreeContentProvider)
639
				|| (provider instanceof ILazyTreePathContentProvider);
640
		contentProviderIsTreeBased = provider instanceof ILazyTreePathContentProvider;
641
		super.setContentProvider(provider);
642
	}
643
644
	/**
645
	 * For a TreeViewer with a tree with the VIRTUAL style bit set, inform the
646
	 * viewer about whether the given element or tree path has children. Avoid
647
	 * calling this method if the number of children has already been set.
648
	 * 
649
	 * @param elementOrTreePath
650
	 *            the element, or tree path
651
	 * @param hasChildren
652
	 * 
653
	 * @since 3.3
654
	 */
655
	public void setHasChildren(Object elementOrTreePath, boolean hasChildren) {
656
		if (internalIsInputOrEmptyPath(elementOrTreePath)) {
657
			if (hasChildren) {
658
				virtualLazyUpdateChildCount(getControl(),
659
						getChildren(getControl()).length);
660
			} else {
661
				setChildCount(elementOrTreePath, 0);
662
			}
663
			return;
664
		}
665
		Widget[] items = internalFindItems(elementOrTreePath);
666
		for (int i = 0; i < items.length; i++) {
667
			Item item = (Item) items[i];
668
			if (!hasChildren) {
669
				doSetItemCount(item, 0);
670
			} else {
671
				if (!getExpanded(item)) {
672
					doSetItemCount(item, 1);
673
					Item child = doGetItem(item, 0);
674
					if (child.getData() != null) {
675
						disassociate(child);
676
					}
677
					doClear(item, true);
678
				}
679
			}
680
		}
681
	}
682
683
	/**
684
	 * Update the widget at index.
685
	 * 
686
	 * @param widget
687
	 * @param index
688
	 */
689
	private void virtualLazyUpdateWidget(Widget widget, int index) {
690
		if (contentProviderIsTreeBased) {
691
			TreePath treePath;
692
			if (widget instanceof Item) {
693
				if (widget.getData() == null) {
694
					// temporary fix to avoid a NPE (the tree will still be
695
					// screwed up)
696
					// see bug 167668
697
					return;
698
				}
699
				treePath = getTreePathFromItem((Item) widget);
700
			} else {
701
				treePath = TreePath.EMPTY;
702
			}
703
			((ILazyTreePathContentProvider) getContentProvider())
704
					.updateElement(treePath, index);
705
		} else {
706
			((ILazyTreeContentProvider) getContentProvider()).updateElement(
707
					widget.getData(), index);
708
		}
709
	}
710
711
	/**
712
	 * Update the child count
713
	 * 
714
	 * @param widget
715
	 * @param currentChildCount
716
	 */
717
	private void virtualLazyUpdateChildCount(Widget widget,
718
			int currentChildCount) {
719
		if (contentProviderIsTreeBased) {
720
			TreePath treePath;
721
			if (widget instanceof Item) {
722
				treePath = getTreePathFromItem((Item) widget);
723
			} else {
724
				treePath = TreePath.EMPTY;
725
			}
726
			((ILazyTreePathContentProvider) getContentProvider())
727
					.updateChildCount(treePath, currentChildCount);
728
		} else {
729
			((ILazyTreeContentProvider) getContentProvider()).updateChildCount(
730
					widget.getData(), currentChildCount);
731
		}
732
	}
733
734
	/**
735
	 * Update the item with the current child count.
736
	 * 
737
	 * @param item
738
	 * @param currentChildCount
739
	 */
740
	private void virtualLazyUpdateHasChildren(Item item, int currentChildCount) {
741
		if (contentProviderIsTreeBased) {
742
			TreePath treePath;
743
			treePath = getTreePathFromItem(item);
744
			if (currentChildCount == 0) {
745
				// item is not expanded (but may have a plus currently)
746
				((ILazyTreePathContentProvider) getContentProvider())
747
						.updateHasChildren(treePath);
748
			} else {
749
				((ILazyTreePathContentProvider) getContentProvider())
750
						.updateChildCount(treePath, currentChildCount);
751
			}
752
		} else {
753
			((ILazyTreeContentProvider) getContentProvider()).updateChildCount(
754
					item.getData(), currentChildCount);
755
		}
756
	}
757
758
	private boolean internalIsInputOrEmptyPath(final Object elementOrTreePath) {
759
		if (elementOrTreePath.equals(getInput()))
760
			return true;
761
		if (!(elementOrTreePath instanceof TreePath))
762
			return false;
763
		return ((TreePath) elementOrTreePath).getSegmentCount() == 0;
764
	}
765
766
	protected void disassociate(Item item) {
767
		if (contentProviderIsLazy) {
768
			// avoid causing a callback:
769
			item.setText(" "); //$NON-NLS-1$
770
		}
771
		super.disassociate(item);
772
	}
773
774
	// Force subclasses to provide a meaningful implementation
775
	protected abstract Item getItemAt(Point p);
776
777
	// Force subclasses to provide a meaningful implementation
778
	protected abstract AbstractViewerEditor createViewerEditor();
779
780
	// Force subclasses to provide a meaningful implementation
781
	protected abstract Item getChild(Widget widget, int index);
782
783
	protected final int getItemCount(Control widget) {
784
		return doGetItemCount();
785
	}
786
	
787
	protected final int getItemCount(Item item) {
788
		return doGetItemCount(item);
789
	}
790
	
791
	/**
792
	 * @param parent
793
	 *            the parent viewer row or <code>null</code> if no parent is
794
	 *            known
795
	 * @param style
796
	 *            the style used to create the row
797
	 * @param rowIndex
798
	 *            the row index or <code>-1</code> if the row is append to the
799
	 *            end
800
	 * @return the new row
801
	 */
802
	protected abstract ViewerRow doCreateNewRowPart(ViewerRow parent,
803
			int style, int rowIndex);
804
805
	/**
806
	 * Returns the number of columns contained in the receiver. If no columns
807
	 * were created by the programmer, this value is zero, despite the fact that
808
	 * visually, one column of items may be visible. This occurs when the
809
	 * programmer uses the tree like a list, adding items but never creating a
810
	 * column.
811
	 * 
812
	 * @return the number of columns
813
	 * 
814
	 * @exception SWTException
815
	 *                <ul>
816
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
817
	 *                disposed</li>
818
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
819
	 *                thread that created the receiver</li>
820
	 *                </ul>
821
	 * 
822
	 * @since 3.3
823
	 */
824
	protected abstract int doGetColumnCount();
825
826
	/**
827
	 * Returns the column at the given, zero-relative index in the receiver.
828
	 * Throws an exception if the index is out of range. Columns are returned in
829
	 * the order that they were created. If no <code>TreeColumn</code>s were
830
	 * created by the programmer, this method will throw
831
	 * <code>ERROR_INVALID_RANGE</code> despite the fact that a single column
832
	 * of data may be visible in the tree. This occurs when the programmer uses
833
	 * the tree like a list, adding items but never creating a column.
834
	 * 
835
	 * @param index
836
	 *            the index of the column to return
837
	 * @return the column at the given index
838
	 * 
839
	 * @exception IllegalArgumentException
840
	 *                <ul>
841
	 *                <li>ERROR_INVALID_RANGE - if the index is not between 0
842
	 *                and the number of elements in the list minus 1 (inclusive)</li>
843
	 *                </ul>
844
	 * @exception SWTException
845
	 *                <ul>
846
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
847
	 *                disposed</li>
848
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
849
	 *                thread that created the receiver</li>
850
	 *                </ul>
851
	 * 
852
	 * 
853
	 * @since 3.3
854
	 */
855
	protected abstract Widget doGetColumn(int index);
856
857
	/**
858
	 * TODO Boris please give me hints what's done here
859
	 * 
860
	 * @param item
861
	 * @param all
862
	 * 
863
	 * @since 3.3
864
	 */
865
	protected abstract void doClear(Item item, boolean all);
866
867
	/**
868
	 * Returns the given item's parent item or <code>null</code> when the
869
	 * receiver is a root.
870
	 * 
871
	 * @param item
872
	 *            the item the parent is searched for
873
	 * 
874
	 * @return the receiver's parent item
875
	 * 
876
	 * @exception SWTException
877
	 *                <ul>
878
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
879
	 *                disposed</li>
880
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
881
	 *                thread that created the receiver</li>
882
	 *                </ul>
883
	 * @since 3.3
884
	 */
885
	protected abstract Item doGetParentItem(Item item);
886
887
	/**
888
	 * Searches the parent's item list starting at the first item (index 0)
889
	 * until an item is found that is equal to the argument, and returns the
890
	 * index of that item. If no item is found, returns -1.
891
	 * 
892
	 * @param parentItem
893
	 *            the item which is parent of the searched one
894
	 * 
895
	 * @param item
896
	 *            the search item
897
	 * @return the index of the item
898
	 * 
899
	 * @exception IllegalArgumentException
900
	 *                <ul>
901
	 *                <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
902
	 *                <li>ERROR_INVALID_ARGUMENT - if the tool item has been
903
	 *                disposed</li>
904
	 *                </ul>
905
	 * @exception SWTException
906
	 *                <ul>
907
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
908
	 *                disposed</li>
909
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
910
	 *                thread that created the receiver</li>
911
	 *                </ul>
912
	 * 
913
	 * @since 3.3
914
	 */
915
	protected abstract int doIndexOf(Item parentItem, Item item);
916
917
	/**
918
	 * Searches the receiver's list starting at the first item (index 0) until
919
	 * an item is found that is equal to the argument, and returns the index of
920
	 * that item. If no item is found, returns -1.
921
	 * 
922
	 * @param item
923
	 *            the search item
924
	 * @return the index of the item
925
	 * 
926
	 * @exception IllegalArgumentException
927
	 *                <ul>
928
	 *                <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
929
	 *                <li>ERROR_INVALID_ARGUMENT - if the tool item has been
930
	 *                disposed</li>
931
	 *                </ul>
932
	 * @exception SWTException
933
	 *                <ul>
934
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
935
	 *                disposed</li>
936
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
937
	 *                thread that created the receiver</li>
938
	 *                </ul>
939
	 * 
940
	 * @since 3.3
941
	 */
942
	protected abstract int doIndexOf(Item item);
943
944
	/**
945
	 * Sets the expanded state of the given item.
946
	 * <p>
947
	 * 
948
	 * @param item
949
	 *            the item the state is modified
950
	 * 
951
	 * @param expanded
952
	 *            the new expanded state
953
	 * 
954
	 * @exception SWTException
955
	 *                <ul>
956
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
957
	 *                disposed</li>
958
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
959
	 *                thread that created the receiver</li>
960
	 *                </ul>
961
	 */
962
	protected abstract void doSetExpanded(Item item, boolean expanded);
963
964
	/**
965
	 * Sets the receiver's selection to be the given list of items. The current
966
	 * selection is cleared before the new items are selected.
967
	 * <p>
968
	 * Items that are not in the receiver are ignored. If the receiver is
969
	 * single-select and multiple items are specified, then all items are
970
	 * ignored.
971
	 * </p>
972
	 * 
973
	 * @param items
974
	 *            the list of items
975
	 * 
976
	 * @exception IllegalArgumentException
977
	 *                <ul>
978
	 *                <li>ERROR_NULL_ARGUMENT - if the array of items is null</li>
979
	 *                <li>ERROR_INVALID_ARGUMENT - if one of the items has been
980
	 *                disposed</li>
981
	 *                </ul>
982
	 * @exception SWTException
983
	 *                <ul>
984
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
985
	 *                disposed</li>
986
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
987
	 *                thread that created the receiver</li>
988
	 *                </ul>
989
	 * 
990
	 * @since 3.3
991
	 */
992
	protected abstract void doSetSelection(List items);
993
994
	/**
995
	 * Sets the number of root-level items contained in the receiver.
996
	 * 
997
	 * @param count
998
	 *            the number of items
999
	 * 
1000
	 * @exception SWTException
1001
	 *                <ul>
1002
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1003
	 *                disposed</li>
1004
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1005
	 *                thread that created the receiver</li>
1006
	 *                </ul>
1007
	 * 
1008
	 * @since 3.3
1009
	 */
1010
	protected abstract void doSetItemCount(int count);
1011
1012
	/**
1013
	 * Sets the number of child items contained in the given item.
1014
	 * 
1015
	 * @param item
1016
	 *            the item the count is modified
1017
	 * 
1018
	 * @param count
1019
	 *            the number of items
1020
	 * 
1021
	 * @exception SWTException
1022
	 *                <ul>
1023
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1024
	 *                disposed</li>
1025
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1026
	 *                thread that created the receiver</li>
1027
	 *                </ul>
1028
	 * 
1029
	 * @since 3.3
1030
	 */
1031
	protected abstract void doSetItemCount(Item item, int count);
1032
1033
	/**
1034
	 * Returns the number of items contained in the receiver that are direct
1035
	 * item children of the receiver. The number that is returned is the number
1036
	 * of roots in the tree.
1037
	 * 
1038
	 * @return the number of items
1039
	 * 
1040
	 * @exception SWTException
1041
	 *                <ul>
1042
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1043
	 *                disposed</li>
1044
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1045
	 *                thread that created the receiver</li>
1046
	 *                </ul>
1047
	 * @since 3.3
1048
	 */
1049
	protected abstract int doGetItemCount();
1050
1051
	/**
1052
	 * Returns the number of items contained in the given item that are direct
1053
	 * item children of the receiver.
1054
	 * 
1055
	 * @param item
1056
	 *            the item the count is searched for
1057
	 * 
1058
	 * @return the number of items
1059
	 * 
1060
	 * @exception SWTException
1061
	 *                <ul>
1062
	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
1063
	 *                disposed</li>
1064
	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
1065
	 *                thread that created the receiver</li>
1066
	 *                </ul>
1067
	 */
1068
	protected abstract int doGetItemCount(Item item);
1069
1070
	/**
1071
	 * Returns the item at the given, zero-relative index in the
1072
	 * receiver. Throws an exception if the index is out of range.
1073
	 *
1074
	 * @param index the index of the item to return
1075
	 * @return the item at the given index
1076
	 *
1077
	 * @exception IllegalArgumentException <ul>
1078
	 *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1079
	 * </ul>
1080
	 * @exception SWTException <ul>
1081
	 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1082
	 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1083
	 * </ul>
1084
	 * 
1085
	 * @since 3.3
1086
	 */
1087
	protected abstract Item doGetItem(int index);
1088
1089
	/**
1090
	 * Returns the item at the given, zero-relative index in the
1091
	 * given item. Throws an exception if the index is out of range.
1092
	 * @param item the parent item to search in
1093
	 *
1094
	 * @param index the index of the item to return
1095
	 * @return the item at the given index
1096
	 *
1097
	 * @exception IllegalArgumentException <ul>
1098
	 *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
1099
	 * </ul>
1100
	 * @exception SWTException <ul>
1101
	 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1102
	 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1103
	 * </ul>
1104
	 * 
1105
	 * @since 3.3
1106
	 */
1107
	protected abstract Item doGetItem(Item item, int index);
1108
1109
	/**
1110
	 * Clears all the items in the given item. The text, icon and other
1111
	 * attributes of the items are set to their default values. If the
1112
	 * tree was created with the <code>SWT.VIRTUAL</code> style, these
1113
	 * attributes are requested again as needed.
1114
	 * @param item the item whose children should be cleared
1115
	 * 
1116
	 * @param all <code>true</code> if all child items should be cleared
1117
	 * recursively, and <code>false</code> otherwise
1118
	 *
1119
	 * @exception SWTException <ul>
1120
	 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1121
	 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1122
	 * </ul>
1123
	 * 
1124
	 * @see SWT#VIRTUAL
1125
	 * @see SWT#SetData
1126
	 * 
1127
	 * @since 3.3
1128
	 */
1129
	protected abstract void doClearAll(Item item, boolean all);
1130
1131
	/**
1132
	 * Clears all the items in the tree. The text, icon and other
1133
	 * attributes of the items are set to their default values. If the
1134
	 * tree was created with the <code>SWT.VIRTUAL</code> style, these
1135
	 * attributes are requested again as needed.
1136
	 * 
1137
	 * @param all <code>true</code> if all child items should be cleared
1138
	 * recursively, and <code>false</code> otherwise
1139
	 *
1140
	 * @exception SWTException <ul>
1141
	 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1142
	 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1143
	 * </ul>
1144
	 * 
1145
	 * @see SWT#VIRTUAL
1146
	 * @see SWT#SetData
1147
	 * 
1148
	 * @since 3.3
1149
	 */
1150
	protected abstract void doClearAll(boolean all);
1151
1152
}

Return to bug 167323