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

Collapse All | Expand All

(-)src/org/eclipse/jface/examples/databinding/snippets/Snippet024AsyncAndCheckAndFilter.java (+454 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 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
 ******************************************************************************/
11
12
package org.eclipse.jface.examples.databinding.snippets;
13
14
import java.util.ArrayList;
15
import java.util.Collections;
16
import java.util.Iterator;
17
import java.util.List;
18
19
import org.eclipse.core.databinding.observable.IObservable;
20
import org.eclipse.core.databinding.observable.Observables;
21
import org.eclipse.core.databinding.observable.Realm;
22
import org.eclipse.core.databinding.observable.list.ComputedList;
23
import org.eclipse.core.databinding.observable.list.IObservableList;
24
import org.eclipse.core.databinding.observable.list.WritableList;
25
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
26
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
28
import org.eclipse.core.databinding.observable.set.SetChangeEvent;
29
import org.eclipse.core.databinding.observable.set.WritableSet;
30
import org.eclipse.core.databinding.observable.value.IObservableValue;
31
import org.eclipse.jface.databinding.swt.ISWTObservableValue;
32
import org.eclipse.jface.databinding.swt.SWTObservables;
33
import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
34
import org.eclipse.jface.databinding.viewers.TreeStructureAdvisor;
35
import org.eclipse.jface.layout.GridDataFactory;
36
import org.eclipse.jface.viewers.CheckStateChangedEvent;
37
import org.eclipse.jface.viewers.CheckboxTreeViewer;
38
import org.eclipse.jface.viewers.DoubleClickEvent;
39
import org.eclipse.jface.viewers.ICheckStateListener;
40
import org.eclipse.jface.viewers.IDoubleClickListener;
41
import org.eclipse.jface.viewers.IStructuredSelection;
42
import org.eclipse.swt.SWT;
43
import org.eclipse.swt.events.DisposeEvent;
44
import org.eclipse.swt.events.DisposeListener;
45
import org.eclipse.swt.layout.GridLayout;
46
import org.eclipse.swt.widgets.Control;
47
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.swt.widgets.Text;
50
51
public class Snippet024AsyncAndCheckAndFilter {
52
53
	public static void main(String[] args) {
54
		final Display display = new Display();
55
		final Shell shell = new Shell(display);
56
		shell.setLayout(new GridLayout(1, false));
57
58
		Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
59
			public void run() {
60
				new Snippet024AsyncAndCheckAndFilter().createControls(shell);
61
62
				shell.pack();
63
				shell.open();
64
				while (!shell.isDisposed()) {
65
					if (!display.readAndDispatch())
66
						display.sleep();
67
				}
68
			}
69
		});
70
		display.dispose();
71
	}
72
73
	static abstract class Node {
74
		private final String name;
75
		private final Node parent;
76
77
		public Node getParent() {
78
			return parent;
79
		}
80
81
		Node(Node parent, String name) {
82
			this.parent = parent;
83
			this.name = name;
84
		}
85
86
		public String toString() {
87
			return name;
88
		}
89
90
		public abstract IObservableList createChildren();
91
	}
92
93
	static class Pending extends Node {
94
		Pending(Node parent) {
95
			super(parent, "Pending...");
96
		}
97
98
		public IObservableList createChildren() {
99
			return null;
100
		}
101
	}
102
103
	static class Root extends Node {
104
		private final IObservableSet checked;
105
		private final IObservableValue filter;
106
		private final ObservableListTreeContentProvider provider;
107
108
		Root(IObservableSet checkedElements, IObservableValue filter, ObservableListTreeContentProvider contentProvider) {
109
			super(null, "root");
110
			checked = checkedElements;
111
			this.filter = filter;
112
			provider = contentProvider;
113
		}
114
115
		public IObservableList createChildren() {
116
			final List repositories = new ArrayList();
117
			repositories.add(new Repository(this, "Eclipse SDK Update Site",
118
					checked, filter));
119
			repositories.add(new Repository(this, "EMF Update Site", checked,
120
					filter));
121
			repositories.add(new Repository(this, "Ganymede Update Site",
122
					checked, filter));
123
			repositories.add(new Repository(this, "Mylyn Update Site", checked,
124
					filter));
125
			return new ComputedList() {
126
				protected List calculate() {
127
					if (((String)filter.getValue()).length() == 0) {
128
						return Observables.staticObservableList(repositories);
129
					} else {
130
						List result = new ArrayList();
131
						for (Iterator it = repositories.iterator(); it
132
								.hasNext();) {
133
							Object object = it.next();
134
							if (!provider.getObservableChildren(object).isEmpty()) {
135
								result.add(object);
136
							}
137
						}
138
						return result;
139
					}
140
				}
141
			};
142
		}
143
	}
144
145
	static class Repository extends Node {
146
		private WritableList iuList;
147
		protected Pending pendingNode;
148
		private final IObservableSet checked;
149
		private final IObservableValue filter;
150
151
		Repository(Root root, String name, IObservableSet checkedElements,
152
				IObservableValue filter) {
153
			super(root, name);
154
			checked = checkedElements;
155
			this.filter = filter;
156
		}
157
158
		public IObservableList getIUList() {
159
			return new ComputedList() {
160
				protected List calculate() {
161
					List result = new ArrayList();
162
					for (Iterator it = getUnfilteredIUList().iterator(); it
163
							.hasNext();) {
164
						Node nodeObject = (Node) it.next();
165
						String filterString = (String) filter.getValue();
166
						if (filterString.length() == 0
167
								|| nodeObject.name.toLowerCase().indexOf(
168
										filterString.toLowerCase()) != -1) {
169
							result.add(nodeObject);
170
						}
171
					}
172
					return result;
173
				}
174
			};
175
		}
176
177
		private IObservableList getUnfilteredIUList() {
178
			if (iuList == null) {
179
				iuList = new WritableList();
180
				refreshIUList();
181
			}
182
			return iuList;
183
		}
184
185
		public void refreshIUList() {
186
			if (iuList.isStale()) {
187
				// we are already refreshing
188
				return;
189
			}
190
			iuList.setStale(true);
191
			iuList.clear();
192
			Display.getDefault().timerExec(3000, new Runnable() {
193
				public void run() {
194
					List bulkAdd = new ArrayList();
195
					Category c1 = new Category(Repository.this,
196
							"Alpha Category");
197
					bulkAdd.add(new IU(c1, "Alpha Bar"));
198
					bulkAdd.add(new IU(c1, "Alpha Bas"));
199
					bulkAdd.add(new IU(c1, "Alpha Foo"));
200
					bulkAdd.add(new IU(c1, "Alpha Meh"));
201
					bulkAdd.add(new IU(c1, "Alpha Moo"));
202
					Category c2 = new Category(Repository.this,
203
							"Beta Category");
204
					bulkAdd.add(new IU(c2, "Beta Bar"));
205
					bulkAdd.add(new IU(c2, "Beta Bas"));
206
					bulkAdd.add(new IU(c2, "Beta Foo"));
207
					bulkAdd.add(new IU(c2, "Beta Meh"));
208
					bulkAdd.add(new IU(c2, "Beta Moo"));
209
					Category c3 = new Category(Repository.this,
210
							"Gamma Category");
211
					bulkAdd.add(new IU(c3, "Gamma Bar"));
212
					bulkAdd.add(new IU(c3, "Gamma Bas"));
213
					bulkAdd.add(new IU(c3, "Gamma Foo"));
214
					bulkAdd.add(new IU(c3, "Gamma Meh"));
215
					bulkAdd.add(new IU(c3, "Gamma Moo"));
216
					iuList.setStale(false);
217
					// System.out.println("finished retrieval, pendingNode="
218
					// + pendingNode);
219
					if (pendingNode != null) {
220
						if (checked.contains(pendingNode)) {
221
							// System.out
222
							// .println(
223
							// "pending node was checked, adding nodes to checked set:"
224
							// + bulkAdd.size());
225
							checked.remove(pendingNode);
226
							checked.add(c1);
227
							checked.add(c2);
228
							checked.add(c3);
229
							checked.addAll(bulkAdd);
230
						}
231
						pendingNode = null;
232
					}
233
					iuList.addAll(bulkAdd);
234
				}
235
			});
236
		}
237
238
		public IObservableList createChildren() {
239
			return new ComputedList() {
240
				protected List calculate() {
241
					if (getIUList().isStale()) {
242
						if (pendingNode == null) {
243
							pendingNode = new Pending(Repository.this);
244
						}
245
						return Collections.singletonList(pendingNode);
246
					}
247
					List result = new ArrayList();
248
					for (Iterator it = getIUList().iterator(); it.hasNext();) {
249
						IU iu = (IU) it.next();
250
						if (!result.contains(iu.getParent())) {
251
							result.add(iu.getParent());
252
						}
253
					}
254
					return result;
255
				}
256
			};
257
		}
258
	}
259
260
	static class Category extends Node {
261
		Category(Repository repo, String name) {
262
			super(repo, name);
263
		}
264
265
		public IObservableList createChildren() {
266
			return new ComputedList() {
267
				protected List calculate() {
268
					List result = new ArrayList();
269
					for (Iterator it = ((Repository) getParent()).getIUList()
270
							.iterator(); it.hasNext();) {
271
						IU iu = (IU) it.next();
272
						if (iu.getParent() == Category.this) {
273
							result.add(iu);
274
						}
275
					}
276
					// System.out.println("returning children, " +
277
					// result.size());
278
					return result;
279
				}
280
			};
281
		}
282
	}
283
284
	static class IU extends Node {
285
		IU(Category category, String name) {
286
			super(category, name);
287
		}
288
289
		public IObservableList createChildren() {
290
			return null;
291
		}
292
	}
293
294
	private CheckboxTreeViewer viewer;
295
	private IObservableSet knownElements;
296
	private IObservableSet checkedElements;
297
	private IObservableSet grayedElements;
298
	private ObservableListTreeContentProvider contentProvider;
299
	private TreeStructureAdvisor treeStructureAdvisor;
300
	private ISWTObservableValue delayedFilterValue;
301
302
    boolean viewerIsDisposed;
303
304
    protected void createControls(Shell shell) {
305
		Text filter = new Text(shell, SWT.BORDER | SWT.SEARCH);
306
		ISWTObservableValue filterValue = SWTObservables.observeText(filter,
307
				SWT.Modify);
308
		delayedFilterValue = SWTObservables.observeDelayedValue(200,
309
				filterValue);
310
		viewer = new CheckboxTreeViewer(shell){
311
		    protected void hookControl(Control control) {
312
		        control.addDisposeListener(new DisposeListener() {
313
		            public void widgetDisposed(DisposeEvent event) {
314
		                viewerIsDisposed = true;
315
		            }
316
		        });
317
		        super.hookControl(control);
318
		    }
319
		};
320
		GridDataFactory.defaultsFor(viewer.getControl()).hint(400, 600)
321
				.applyTo(viewer.getControl());
322
		treeStructureAdvisor = new TreeStructureAdvisor() {
323
			public Object getParent(Object element) {
324
				if (element instanceof Node) {
325
					return ((Node) element).getParent();
326
				}
327
				return null;
328
			}
329
330
			public Boolean hasChildren(Object element) {
331
				return (element instanceof IU || element instanceof Pending) ? Boolean.FALSE
332
						: Boolean.TRUE;
333
			}
334
		};
335
		IObservableFactory listFactory = new IObservableFactory() {
336
			public IObservable createObservable(Object target) {
337
				return ((Node) target).createChildren();
338
			}
339
		};
340
		contentProvider = new ObservableListTreeContentProvider(listFactory,
341
				treeStructureAdvisor);
342
		viewer.setContentProvider(contentProvider);
343
		knownElements = contentProvider.getDeferredKnownElements();
344
		checkedElements = new WritableSet();
345
		grayedElements = new WritableSet();
346
		viewer.addCheckStateListener(new ICheckStateListener() {
347
			public void checkStateChanged(CheckStateChangedEvent event) {
348
				handleChecked(event.getElement(), event.getChecked());
349
			}
350
		});
351
		knownElements.addSetChangeListener(new ISetChangeListener() {
352
			public void handleSetChange(SetChangeEvent event) {
353
				if (viewerIsDisposed) {
354
					return;
355
				}
356
				for (Iterator it = event.diff.getRemovals().iterator(); it
357
						.hasNext();) {
358
					Object removed = it.next();
359
					if (removed instanceof IU) {
360
						Object parent = treeStructureAdvisor.getParent(removed);
361
						Object[] children = contentProvider.getChildren(parent);
362
						boolean atLeastOneChecked = false;
363
						boolean atLeastOneUnchecked = false;
364
						for (int i = 0; i < children.length; i++) {
365
							Object child = children[i];
366
							if (checkedElements.contains(child)) {
367
								atLeastOneChecked = true;
368
							} else {
369
								atLeastOneUnchecked = true;
370
							}
371
						}
372
						checkParentPath(parent, !atLeastOneUnchecked, atLeastOneChecked && atLeastOneUnchecked);
373
					}
374
				}
375
				for (Iterator it = event.diff.getAdditions().iterator(); it
376
						.hasNext();) {
377
					Object added = it.next();
378
					if (added instanceof IU) {
379
						boolean checked = checkedElements.contains(added);
380
						viewer.setChecked(added, checked);
381
						handleChecked(added, checked);
382
					}
383
				}
384
			}
385
		});
386
		viewer.addDoubleClickListener(new IDoubleClickListener(){
387
			public void doubleClick(DoubleClickEvent event) {
388
				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
389
				if (selection.getFirstElement() instanceof Repository) {
390
					((Repository) selection.getFirstElement()).refreshIUList();
391
				}
392
			}
393
		});
394
		viewer.setInput(new Root(checkedElements, delayedFilterValue, 
395
				contentProvider));
396
	}
397
398
	protected void handleChecked(Object element, boolean checked) {
399
		checkSubtree(element, checked);
400
		checkParentPath(element, checked, false);
401
	}
402
403
	private void checkParentPath(Object element, boolean checked, boolean grayed) {
404
		if (element == null) {
405
			return;
406
		}
407
		if (grayed) {
408
			checked = true;
409
		} else {
410
			Object[] children = contentProvider.getChildren(element);
411
			for (int i = 0; i < children.length; i++) {
412
				Object child = children[i];
413
				if (grayedElements.contains(child)
414
						|| checked != checkedElements.contains(child)) {
415
					checked = grayed = true;
416
					break;
417
				}
418
			}
419
		}
420
		updateCheckedGrayed(element, checked, grayed);
421
		checkParentPath(treeStructureAdvisor.getParent(element), checked,
422
				grayed);
423
	}
424
425
	private void checkSubtree(Object element, boolean checked) {
426
		updateCheckedGrayed(element, checked, false);
427
		if (!(element instanceof Pending)) {
428
			Object[] children = contentProvider.getChildren(element);
429
			for (int i = 0; i < children.length; i++) {
430
				Object child = children[i];
431
				checkSubtree(child, checked);
432
			}
433
		}
434
	}
435
436
	private void updateCheckedGrayed(Object element, boolean checked,
437
			boolean grayed) {
438
		if (checked) {
439
			checkedElements.add(element);
440
		} else {
441
			checkedElements.remove(element);
442
		}
443
		if (grayed) {
444
			grayedElements.add(element);
445
		} else {
446
			grayedElements.remove(element);
447
		}
448
		if (knownElements.contains(element)) {
449
			viewer.setChecked(element, checked);
450
			viewer.setGrayed(element, grayed);
451
		}
452
	}
453
454
}
(-)src/org/eclipse/core/databinding/observable/list/AbstractObservableList.java (-7 / +21 lines)
Lines 76-108 Link Here
76
	}
76
	}
77
77
78
	public synchronized void addListChangeListener(IListChangeListener listener) {
78
	public synchronized void addListChangeListener(IListChangeListener listener) {
79
		changeSupport.addListener(ListChangeEvent.TYPE, listener);
79
		if (changeSupport != null) {
80
			changeSupport.addListener(ListChangeEvent.TYPE, listener);
81
		}
80
	}
82
	}
81
83
82
	public synchronized void removeListChangeListener(IListChangeListener listener) {
84
	public synchronized void removeListChangeListener(IListChangeListener listener) {
83
		changeSupport.removeListener(ListChangeEvent.TYPE, listener);
85
		if (changeSupport != null) {
86
			changeSupport.removeListener(ListChangeEvent.TYPE, listener);
87
		}
84
	}
88
	}
85
89
86
	protected void fireListChange(ListDiff diff) {
90
	protected void fireListChange(ListDiff diff) {
87
		// fire general change event first
91
		// fire general change event first
88
		fireChange();
92
		fireChange();
89
		changeSupport.fireEvent(new ListChangeEvent(this, diff));
93
		if (changeSupport != null) {
94
			changeSupport.fireEvent(new ListChangeEvent(this, diff));
95
		}
90
	}
96
	}
91
97
92
	public synchronized void addChangeListener(IChangeListener listener) {
98
	public synchronized void addChangeListener(IChangeListener listener) {
93
		changeSupport.addChangeListener(listener);
99
		if (changeSupport != null) {
100
			changeSupport.addChangeListener(listener);
101
		}
94
	}
102
	}
95
103
96
	public synchronized void removeChangeListener(IChangeListener listener) {
104
	public synchronized void removeChangeListener(IChangeListener listener) {
97
		changeSupport.removeChangeListener(listener);
105
		if (changeSupport != null) {
106
			changeSupport.removeChangeListener(listener);
107
		}
98
	}
108
	}
99
109
100
	public synchronized void addStaleListener(IStaleListener listener) {
110
	public synchronized void addStaleListener(IStaleListener listener) {
101
		changeSupport.addStaleListener(listener);
111
		if (changeSupport != null) {
112
			changeSupport.addStaleListener(listener);
113
		}
102
	}
114
	}
103
115
104
	public synchronized void removeStaleListener(IStaleListener listener) {
116
	public synchronized void removeStaleListener(IStaleListener listener) {
105
		changeSupport.removeStaleListener(listener);
117
		if (changeSupport != null) {
118
			changeSupport.removeStaleListener(listener);
119
		}
106
	}
120
	}
107
121
108
	/**
122
	/**
(-)src/org/eclipse/core/databinding/observable/list/ComputedList.java (-13 / +25 lines)
Lines 121-132 Link Here
121
		}
121
		}
122
122
123
		public void handleStale(StaleEvent event) {
123
		public void handleStale(StaleEvent event) {
124
			if (!dirty)
124
			if (!disposed && !dirty)
125
				makeStale();
125
				makeStale();
126
		}
126
		}
127
127
128
		public void handleChange(ChangeEvent event) {
128
		public void handleChange(ChangeEvent event) {
129
			makeDirty();
129
			if (!disposed) {
130
				makeDirty();
131
			}
130
		}
132
		}
131
	}
133
	}
132
134
Lines 134-139 Link Here
134
136
135
	private Object elementType;
137
	private Object elementType;
136
138
139
	private boolean disposed;
140
137
	protected int doGetSize() {
141
	protected int doGetSize() {
138
		return doGetList().size();
142
		return doGetList().size();
139
	}
143
	}
Lines 154-172 Link Here
154
			// - Run the calculate method
158
			// - Run the calculate method
155
			// - While doing so, add any observable that is touched to the
159
			// - While doing so, add any observable that is touched to the
156
			// dependencies list
160
			// dependencies list
157
			IObservable[] newDependencies = ObservableTracker.runAndMonitor(
161
			final IObservable[] newDependencies = ObservableTracker.runAndMonitor(
158
					privateInterface, privateInterface, null);
162
					privateInterface, privateInterface, null);
159
163
160
			// If any dependencies are stale, a stale event will be fired here
164
			ObservableTracker.runAndIgnore(new Runnable() {
161
			// even if we were already stale before recomputing. This is in case
165
				public void run() {
162
			// clients assume that a list change is indicative of non-staleness.
166
					// If any dependencies are stale, a stale event will be fired here
163
			stale = false;
167
					// even if we were already stale before recomputing. This is in case
164
			for (int i = 0; i < newDependencies.length; i++) {
168
					// clients assume that a list change is indicative of non-staleness.
165
				if (newDependencies[i].isStale()) {
169
					stale = false;
166
					makeStale();
170
					for (int i = 0; i < newDependencies.length; i++) {
167
					break;
171
						if (newDependencies[i].isStale()) {
172
							makeStale();
173
							break;
174
						}
175
					}
168
				}
176
				}
169
			}
177
			});
170
178
171
			if (!stale) {
179
			if (!stale) {
172
				for (int i = 0; i < newDependencies.length; i++) {
180
				for (int i = 0; i < newDependencies.length; i++) {
Lines 231-243 Link Here
231
	}
239
	}
232
240
233
	private void makeStale() {
241
	private void makeStale() {
234
		if (!stale) {
242
		if (!disposed && !stale) {
235
			stale = true;
243
			stale = true;
236
			fireStale();
244
			fireStale();
237
		}
245
		}
238
	}
246
	}
239
247
240
	public boolean isStale() {
248
	public boolean isStale() {
249
		if (disposed) {
250
			return false;
251
		}
241
		// recalculate list if dirty, to ensure staleness is correct.
252
		// recalculate list if dirty, to ensure staleness is correct.
242
		getList();
253
		getList();
243
		return stale;
254
		return stale;
Lines 284-289 Link Here
284
	}
295
	}
285
296
286
	public synchronized void dispose() {
297
	public synchronized void dispose() {
298
		disposed = true;
287
		stopListening();
299
		stopListening();
288
		super.dispose();
300
		super.dispose();
289
	}
301
	}
(-)src/org/eclipse/core/databinding/observable/set/DeferredObservableSet.java (+98 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2008 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
 ******************************************************************************/
11
12
package org.eclipse.core.databinding.observable.set;
13
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.Set;
17
18
import org.eclipse.core.databinding.observable.Diffs;
19
import org.eclipse.core.runtime.Assert;
20
21
/**
22
 * A read-only observable set that can defer changes to its underlying
23
 * observable set.
24
 * 
25
 * @since 1.1
26
 * 
27
 */
28
public class DeferredObservableSet extends ObservableSet {
29
	
30
	private IObservableSet target;
31
	private ISetChangeListener listener = new ISetChangeListener(){
32
		public void handleSetChange(SetChangeEvent event) {
33
			if (deferChanges == 0) {
34
				fireSetChange(Diffs.createSetDiff(event.diff.getAdditions(), event.diff.getRemovals()));
35
			} else {
36
				for (Iterator it = event.diff.getAdditions().iterator(); it
37
						.hasNext();) {
38
					Object added = it.next();
39
					if (!deferredRemovals.remove(added)) {
40
						deferredAdditions.add(added);
41
					}
42
				}
43
				for (Iterator it = event.diff.getRemovals().iterator(); it
44
				.hasNext();) {
45
					Object removed = it.next();
46
					if (!deferredAdditions.remove(removed)) {
47
						deferredRemovals.add(removed);
48
					}
49
				}
50
			}
51
		}
52
	};
53
	
54
	private int deferChanges;
55
	
56
	private Set deferredAdditions = new HashSet();
57
	private Set deferredRemovals = new HashSet();
58
59
	/**
60
	 * @param target
61
	 * @param elementType 
62
	 */
63
	public DeferredObservableSet(IObservableSet target, Object elementType) {
64
		super(new HashSet(), elementType);
65
		this.target = target;
66
		target.addSetChangeListener(listener);
67
		wrappedSet.addAll(target);
68
	}
69
	
70
	/**
71
	 * @param defer
72
	 */
73
	public void deferChanges(boolean defer) {
74
		checkRealm();
75
		if (defer) {
76
			deferChanges++;
77
		} else {
78
			--deferChanges;
79
		}
80
		Assert.isTrue(deferChanges >= 0);
81
		if (deferChanges == 0 && (deferredRemovals.size() > 0 || deferredAdditions.size() > 0)) {
82
			wrappedSet.removeAll(deferredRemovals);
83
			wrappedSet.addAll(deferredAdditions);
84
			SetDiff diff = Diffs.createSetDiff(new HashSet(deferredAdditions), new HashSet(deferredRemovals));
85
			deferredAdditions.clear();
86
			deferredRemovals.clear();
87
			fireSetChange(diff);
88
		}
89
	}
90
	
91
	public synchronized void dispose() {
92
		target.removeSetChangeListener(listener);
93
		listener = null;
94
		target = null;
95
		super.dispose();
96
	}
97
98
}
(-)src/org/eclipse/jface/databinding/viewers/ObservableSetTreeContentProvider.java (+7 lines)
Lines 159-162 Link Here
159
	public IObservableSet getKnownElements() {
159
	public IObservableSet getKnownElements() {
160
		return impl.getKnownElements();
160
		return impl.getKnownElements();
161
	}
161
	}
162
163
	/**
164
	 * @return bla
165
	 */
166
	public IObservableSet getDeferredKnownElements() {
167
		return impl.getDeferredKnownElements();
168
	}
162
}
169
}
(-)src/org/eclipse/jface/databinding/viewers/ObservableListTreeContentProvider.java (+21 lines)
Lines 64-73 Link Here
64
				final Set removals = ViewerElementSet.withComparer(comparer);
64
				final Set removals = ViewerElementSet.withComparer(comparer);
65
				event.diff.accept(new ListDiffVisitor() {
65
				event.diff.accept(new ListDiffVisitor() {
66
					public void handleAdd(int index, Object child) {
66
					public void handleAdd(int index, Object child) {
67
68
						deferredKnownElements.deferChanges(true);
67
						// adds to known elements if new element
69
						// adds to known elements if new element
68
						getOrCreateNode(child).addParent(parentElement);
70
						getOrCreateNode(child).addParent(parentElement);
69
71
70
						viewerUpdater.insert(parentElement, child, index);
72
						viewerUpdater.insert(parentElement, child, index);
73
						
74
						deferredKnownElements.deferChanges(false);
71
					}
75
					}
72
76
73
					public void handleRemove(int index, Object child) {
77
					public void handleRemove(int index, Object child) {
Lines 78-88 Link Here
78
82
79
					public void handleReplace(int index, Object oldChild,
83
					public void handleReplace(int index, Object oldChild,
80
							Object newChild) {
84
							Object newChild) {
85
						deferredKnownElements.deferChanges(true);
81
						getOrCreateNode(newChild).addParent(parentElement);
86
						getOrCreateNode(newChild).addParent(parentElement);
82
87
83
						viewerUpdater.replace(parentElement, oldChild,
88
						viewerUpdater.replace(parentElement, oldChild,
84
								newChild, index);
89
								newChild, index);
85
90
91
						deferredKnownElements.deferChanges(false);
86
						removals.add(oldChild);
92
						removals.add(oldChild);
87
					}
93
					}
88
94
Lines 183-186 Link Here
183
	public IObservableSet getKnownElements() {
189
	public IObservableSet getKnownElements() {
184
		return impl.getKnownElements();
190
		return impl.getKnownElements();
185
	}
191
	}
192
193
	/**
194
	 * @return bla
195
	 */
196
	public IObservableSet getDeferredKnownElements() {
197
		return impl.getDeferredKnownElements();
198
	}
199
200
	/**
201
	 * @param element
202
	 * @return bla
203
	 */
204
	public IObservableList getObservableChildren(Object element) {
205
		return (IObservableList) impl.getObservableChildren(element);
206
	}
186
}
207
}
(-)src/org/eclipse/jface/internal/databinding/viewers/ObservableCollectionTreeContentProvider.java (-2 / +55 lines)
Lines 23-28 Link Here
23
import org.eclipse.core.databinding.observable.Realm;
23
import org.eclipse.core.databinding.observable.Realm;
24
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
24
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
25
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
25
import org.eclipse.core.databinding.observable.masterdetail.MasterDetailObservables;
26
import org.eclipse.core.databinding.observable.set.DeferredObservableSet;
26
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.set.IObservableSet;
27
import org.eclipse.core.databinding.observable.value.IObservableValue;
28
import org.eclipse.core.databinding.observable.value.IObservableValue;
28
import org.eclipse.core.databinding.observable.value.WritableValue;
29
import org.eclipse.core.databinding.observable.value.WritableValue;
Lines 62-67 Link Here
62
	protected IElementComparer comparer;
63
	protected IElementComparer comparer;
63
64
64
	private IObservableSet knownElements;
65
	private IObservableSet knownElements;
66
	protected DeferredObservableSet deferredKnownElements;
65
	private IObservableSet unmodifiableKnownElements;
67
	private IObservableSet unmodifiableKnownElements;
66
68
67
	private IObservableFactory /* <IObservableCollection> */collectionFactory;
69
	private IObservableFactory /* <IObservableCollection> */collectionFactory;
Lines 70-75 Link Here
70
72
71
	private TreeStructureAdvisor structureAdvisor;
73
	private TreeStructureAdvisor structureAdvisor;
72
74
75
	private IObservableSet unmodifiableDeferredKnownElements;
76
73
	/**
77
	/**
74
	 * Constructs an ObservableCollectionTreeContentProvider using the given
78
	 * Constructs an ObservableCollectionTreeContentProvider using the given
75
	 * parent provider and collection factory.
79
	 * parent provider and collection factory.
Lines 100-105 Link Here
100
				knownElementsFactory, null);
104
				knownElementsFactory, null);
101
		unmodifiableKnownElements = Observables
105
		unmodifiableKnownElements = Observables
102
				.unmodifiableObservableSet(knownElements);
106
				.unmodifiableObservableSet(knownElements);
107
		deferredKnownElements = new DeferredObservableSet(knownElements, null);
108
		unmodifiableDeferredKnownElements = Observables
109
				.unmodifiableObservableSet(deferredKnownElements);
103
110
104
		Assert
111
		Assert
105
				.isNotNull(collectionFactory,
112
				.isNotNull(collectionFactory,
Lines 158-169 Link Here
158
		return getChildren(input, true);
165
		return getChildren(input, true);
159
	}
166
	}
160
167
168
	private boolean deferringKnownElements;
169
	
161
	public Object[] getChildren(Object element) {
170
	public Object[] getChildren(Object element) {
162
		return getChildren(element, false);
171
		return getChildren(element, false);
163
	}
172
	}
164
173
165
	private Object[] getChildren(Object element, boolean input) {
174
	private Object[] getChildren(Object element, boolean input) {
166
		Object[] children = getOrCreateNode(element, input).getChildren();
175
		if (!deferringKnownElements) {
176
			deferringKnownElements = true;
177
			deferredKnownElements.deferChanges(true);
178
			realm.asyncExec(new Runnable(){
179
				public void run() {
180
					deferringKnownElements = false;
181
					if (deferredKnownElements != null) {
182
						deferredKnownElements.deferChanges(false);
183
					}
184
				}
185
			});
186
		}
187
		TreeNode node = getOrCreateNode(element, input);
188
		Object[] children = node.getChildren();
167
		for (int i = 0; i < children.length; i++)
189
		for (int i = 0; i < children.length; i++)
168
			getOrCreateNode(children[i], false).addParent(element);
190
			getOrCreateNode(children[i], false).addParent(element);
169
		return children;
191
		return children;
Lines 176-184 Link Here
176
				return hasChildren.booleanValue();
198
				return hasChildren.booleanValue();
177
			}
199
			}
178
		}
200
		}
201
		if (!deferringKnownElements) {
202
			deferringKnownElements = true;
203
			deferredKnownElements.deferChanges(true);
204
			realm.asyncExec(new Runnable(){
205
				public void run() {
206
					deferringKnownElements = false;
207
					deferredKnownElements.deferChanges(false);
208
				}
209
			});
210
		}
179
		return getOrCreateNode(element, false).hasChildren();
211
		return getOrCreateNode(element, false).hasChildren();
180
	}
212
	}
181
213
	
182
	protected TreeNode getOrCreateNode(Object element) {
214
	protected TreeNode getOrCreateNode(Object element) {
183
		return getOrCreateNode(element, false);
215
		return getOrCreateNode(element, false);
184
	}
216
	}
Lines 226-231 Link Here
226
		viewerUpdater = null;
258
		viewerUpdater = null;
227
		comparer = null;
259
		comparer = null;
228
		knownElements = null;
260
		knownElements = null;
261
		deferredKnownElements = null;
229
		unmodifiableKnownElements = null;
262
		unmodifiableKnownElements = null;
230
		collectionFactory = null;
263
		collectionFactory = null;
231
	}
264
	}
Lines 244-249 Link Here
244
	}
277
	}
245
278
246
	/**
279
	/**
280
	 * @return bla
281
	 */
282
	public IObservableSet getDeferredKnownElements() {
283
		return unmodifiableDeferredKnownElements;
284
	}
285
	
286
	/**
247
	 * Returns a listener which, when a collection change event is received,
287
	 * Returns a listener which, when a collection change event is received,
248
	 * updates the tree viewer through the {@link #viewerUpdater} field, and
288
	 * updates the tree viewer through the {@link #viewerUpdater} field, and
249
	 * maintains the adds and removes parents from the appropriate tree nodes.
289
	 * maintains the adds and removes parents from the appropriate tree nodes.
Lines 369-374 Link Here
369
			initChildren();
409
			initChildren();
370
			return children.toArray();
410
			return children.toArray();
371
		}
411
		}
412
		
413
		IObservableCollection getChildrenObservable() {
414
			initChildren();
415
			return children;
416
		}
372
417
373
		private void dispose() {
418
		private void dispose() {
374
			if (element != null) {
419
			if (element != null) {
Lines 395-398 Link Here
395
			}
440
			}
396
		}
441
		}
397
	}
442
	}
443
444
	/**
445
	 * @param element
446
	 * @return bla
447
	 */
448
	public IObservableCollection getObservableChildren(Object element) {
449
		return getOrCreateNode(element).getChildrenObservable();
450
	}
398
}
451
}
(-)src/org/eclipse/jface/internal/databinding/swt/DelayedObservableValue.java (-1 / +5 lines)
Lines 138-144 Link Here
138
138
139
	protected Object doGetValue() {
139
	protected Object doGetValue() {
140
		if (dirty) {
140
		if (dirty) {
141
			cachedValue = observable.getValue();
141
			ObservableTracker.runAndIgnore(new Runnable(){
142
				public void run() {
143
					cachedValue = observable.getValue();
144
				}
145
			});
142
			dirty = false;
146
			dirty = false;
143
147
144
			if (updater != null && !updater.running) {
148
			if (updater != null && !updater.running) {

Return to bug 237359