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

Collapse All | Expand All

(-)src/org/eclipse/core/internal/databinding/observable/DelayedObservableValue.java (-1 / +5 lines)
Lines 114-120 Link Here
114
114
115
	protected Object doGetValue() {
115
	protected Object doGetValue() {
116
		if (dirty) {
116
		if (dirty) {
117
			cachedValue = observable.getValue();
117
			ObservableTracker.runAndIgnore(new Runnable(){
118
			public void run() {
119
				cachedValue = observable.getValue();
120
			}
121
			});
118
			dirty = false;
122
			dirty = false;
119
123
120
			if (updater != null && !updater.running) {
124
			if (updater != null && !updater.running) {
(-)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/jface/internal/databinding/viewers/ObservableCollectionTreeContentProvider.java (+10 lines)
Lines 389-394 Link Here
389
		return comparer.equals(left, right);
389
		return comparer.equals(left, right);
390
	}
390
	}
391
391
392
	/**
393
	 * @param element
394
	 * @return bla
395
	 */
396
	public IObservableCollection getObservableChildren(Object element) {
397
		TreeNode node = getOrCreateNode(element);
398
		node.initChildren();
399
		return node.children;
400
	}
401
392
	protected final class TreeNode {
402
	protected final class TreeNode {
393
		private Object element;
403
		private Object element;
394
404
(-)src/org/eclipse/jface/databinding/viewers/ObservableListTreeContentProvider.java (+9 lines)
Lines 227-230 Link Here
227
	public IObservableSet getRealizedElements() {
227
	public IObservableSet getRealizedElements() {
228
		return impl.getRealizedElements();
228
		return impl.getRealizedElements();
229
	}
229
	}
230
231
	/**
232
	 * @param element
233
	 * @return bla
234
	 * @since 1.3
235
	 */
236
	public IObservableList getObservableChildren(Object element) {
237
		return (IObservableList) impl.getObservableChildren(element);
238
	}
230
}
239
}
(-)src/org/eclipse/jface/databinding/viewers/ObservableSetTreeContentProvider.java (+10 lines)
Lines 17-22 Link Here
17
17
18
import org.eclipse.core.databinding.observable.IObservableCollection;
18
import org.eclipse.core.databinding.observable.IObservableCollection;
19
import org.eclipse.core.databinding.observable.IObservablesListener;
19
import org.eclipse.core.databinding.observable.IObservablesListener;
20
import org.eclipse.core.databinding.observable.list.IObservableList;
20
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
21
import org.eclipse.core.databinding.observable.masterdetail.IObservableFactory;
21
import org.eclipse.core.databinding.observable.set.IObservableSet;
22
import org.eclipse.core.databinding.observable.set.IObservableSet;
22
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
23
import org.eclipse.core.databinding.observable.set.ISetChangeListener;
Lines 189-192 Link Here
189
	public IObservableSet getRealizedElements() {
190
	public IObservableSet getRealizedElements() {
190
		return impl.getRealizedElements();
191
		return impl.getRealizedElements();
191
	}
192
	}
193
194
	/**
195
	 * @param element
196
	 * @return bla
197
	 * @since 1.3
198
	 */
199
	public IObservableList getObservableChildren(Object element) {
200
		return (IObservableList) impl.getObservableChildren(element);
201
	}
192
}
202
}
(-)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,
109
				ObservableListTreeContentProvider contentProvider) {
110
			super(null, "root");
111
			checked = checkedElements;
112
			this.filter = filter;
113
			provider = contentProvider;
114
		}
115
116
		public IObservableList createChildren() {
117
			final List repositories = new ArrayList();
118
			repositories.add(new Repository(this, "Eclipse SDK Update Site",
119
					checked, filter));
120
			repositories.add(new Repository(this, "EMF Update Site", checked,
121
					filter));
122
			repositories.add(new Repository(this, "Ganymede Update Site",
123
					checked, filter));
124
			repositories.add(new Repository(this, "Mylyn Update Site", checked,
125
					filter));
126
			return new ComputedList() {
127
				protected List calculate() {
128
					if (((String) filter.getValue()).length() == 0) {
129
						return Observables.staticObservableList(repositories);
130
					}
131
					List result = new ArrayList();
132
					for (Iterator it = repositories.iterator(); it.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
	static class Repository extends Node {
145
		private WritableList iuList;
146
		protected Pending pendingNode;
147
		private final IObservableSet checked;
148
		private final IObservableValue filter;
149
150
		Repository(Root root, String name, IObservableSet checkedElements,
151
				IObservableValue filter) {
152
			super(root, name);
153
			checked = checkedElements;
154
			this.filter = filter;
155
		}
156
157
		public IObservableList getIUList() {
158
			return new ComputedList() {
159
				protected List calculate() {
160
					List result = new ArrayList();
161
					for (Iterator it = getUnfilteredIUList().iterator(); it
162
							.hasNext();) {
163
						Node nodeObject = (Node) it.next();
164
						String filterString = (String) filter.getValue();
165
						if (filterString.length() == 0
166
								|| nodeObject.name.toLowerCase().indexOf(
167
										filterString.toLowerCase()) != -1) {
168
							result.add(nodeObject);
169
						}
170
					}
171
					return result;
172
				}
173
			};
174
		}
175
176
		private IObservableList getUnfilteredIUList() {
177
			if (iuList == null) {
178
				iuList = new WritableList();
179
				refreshIUList();
180
			}
181
			return iuList;
182
		}
183
184
		public void refreshIUList() {
185
			if (iuList.isStale()) {
186
				// we are already refreshing
187
				return;
188
			}
189
			iuList.setStale(true);
190
			iuList.clear();
191
			Display.getDefault().timerExec(3000, new Runnable() {
192
				public void run() {
193
					List bulkAdd = new ArrayList();
194
					Category c1 = new Category(Repository.this,
195
							"Alpha Category");
196
					bulkAdd.add(new IU(c1, "Alpha Bar"));
197
					bulkAdd.add(new IU(c1, "Alpha Bas"));
198
					bulkAdd.add(new IU(c1, "Alpha Foo"));
199
					bulkAdd.add(new IU(c1, "Alpha Meh"));
200
					bulkAdd.add(new IU(c1, "Alpha Moo"));
201
					Category c2 = new Category(Repository.this, "Beta Category");
202
					bulkAdd.add(new IU(c2, "Beta Bar"));
203
					bulkAdd.add(new IU(c2, "Beta Bas"));
204
					bulkAdd.add(new IU(c2, "Beta Foo"));
205
					bulkAdd.add(new IU(c2, "Beta Meh"));
206
					bulkAdd.add(new IU(c2, "Beta Moo"));
207
					Category c3 = new Category(Repository.this,
208
							"Gamma Category");
209
					bulkAdd.add(new IU(c3, "Gamma Bar"));
210
					bulkAdd.add(new IU(c3, "Gamma Bas"));
211
					bulkAdd.add(new IU(c3, "Gamma Foo"));
212
					bulkAdd.add(new IU(c3, "Gamma Meh"));
213
					bulkAdd.add(new IU(c3, "Gamma Moo"));
214
					iuList.setStale(false);
215
					// System.out.println("finished retrieval, pendingNode="
216
					// + pendingNode);
217
					if (pendingNode != null) {
218
						if (checked.contains(pendingNode)) {
219
							// System.out
220
							// .println(
221
							// "pending node was checked, adding nodes to checked set:"
222
							// + bulkAdd.size());
223
							checked.remove(pendingNode);
224
							checked.add(c1);
225
							checked.add(c2);
226
							checked.add(c3);
227
							checked.addAll(bulkAdd);
228
						}
229
						pendingNode = null;
230
					}
231
					iuList.addAll(bulkAdd);
232
				}
233
			});
234
		}
235
236
		public IObservableList createChildren() {
237
			return new ComputedList() {
238
				protected List calculate() {
239
					if (getIUList().isStale()) {
240
						if (pendingNode == null) {
241
							pendingNode = new Pending(Repository.this);
242
						}
243
						return Collections.singletonList(pendingNode);
244
					}
245
					List result = new ArrayList();
246
					for (Iterator it = getIUList().iterator(); it.hasNext();) {
247
						IU iu = (IU) it.next();
248
						if (!result.contains(iu.getParent())) {
249
							result.add(iu.getParent());
250
						}
251
					}
252
					return result;
253
				}
254
			};
255
		}
256
	}
257
258
	static class Category extends Node {
259
		Category(Repository repo, String name) {
260
			super(repo, name);
261
		}
262
263
		public IObservableList createChildren() {
264
			return new ComputedList() {
265
				protected List calculate() {
266
					List result = new ArrayList();
267
					for (Iterator it = ((Repository) getParent()).getIUList()
268
							.iterator(); it.hasNext();) {
269
						IU iu = (IU) it.next();
270
						if (iu.getParent() == Category.this) {
271
							result.add(iu);
272
						}
273
					}
274
					// System.out.println("returning children, " +
275
					// result.size());
276
					return result;
277
				}
278
			};
279
		}
280
	}
281
282
	static class IU extends Node {
283
		IU(Category category, String name) {
284
			super(category, name);
285
		}
286
287
		public IObservableList createChildren() {
288
			return null;
289
		}
290
	}
291
292
	private CheckboxTreeViewer viewer;
293
	private IObservableSet realizedElements;
294
	private IObservableSet checkedElements;
295
	private IObservableSet grayedElements;
296
	private ObservableListTreeContentProvider contentProvider;
297
	private TreeStructureAdvisor treeStructureAdvisor;
298
	private ISWTObservableValue delayedFilterValue;
299
300
	boolean viewerIsDisposed;
301
302
	protected void createControls(Shell shell) {
303
		Text filter = new Text(shell, SWT.BORDER | SWT.SEARCH);
304
		ISWTObservableValue filterValue = SWTObservables.observeText(filter,
305
				SWT.Modify);
306
		delayedFilterValue = SWTObservables.observeDelayedValue(200,
307
				filterValue);
308
		viewer = new CheckboxTreeViewer(shell) {
309
			protected void hookControl(Control control) {
310
				control.addDisposeListener(new DisposeListener() {
311
					public void widgetDisposed(DisposeEvent event) {
312
						viewerIsDisposed = true;
313
					}
314
				});
315
				super.hookControl(control);
316
			}
317
		};
318
		GridDataFactory.defaultsFor(viewer.getControl()).hint(400, 600)
319
				.applyTo(viewer.getControl());
320
		treeStructureAdvisor = new TreeStructureAdvisor() {
321
			public Object getParent(Object element) {
322
				if (element instanceof Node) {
323
					return ((Node) element).getParent();
324
				}
325
				return null;
326
			}
327
328
			public Boolean hasChildren(Object element) {
329
				return (element instanceof IU || element instanceof Pending) ? Boolean.FALSE
330
						: Boolean.TRUE;
331
			}
332
		};
333
		IObservableFactory listFactory = new IObservableFactory() {
334
			public IObservable createObservable(Object target) {
335
				return ((Node) target).createChildren();
336
			}
337
		};
338
		contentProvider = new ObservableListTreeContentProvider(listFactory,
339
				treeStructureAdvisor);
340
		viewer.setContentProvider(contentProvider);
341
		realizedElements = contentProvider.getRealizedElements();
342
		checkedElements = new WritableSet();
343
		grayedElements = new WritableSet();
344
		viewer.addCheckStateListener(new ICheckStateListener() {
345
			public void checkStateChanged(CheckStateChangedEvent event) {
346
				handleChecked(event.getElement(), event.getChecked());
347
			}
348
		});
349
		realizedElements.addSetChangeListener(new ISetChangeListener() {
350
			public void handleSetChange(SetChangeEvent event) {
351
				if (viewerIsDisposed) {
352
					return;
353
				}
354
				for (Iterator it = event.diff.getRemovals().iterator(); it
355
						.hasNext();) {
356
					Object removed = it.next();
357
					if (removed instanceof IU) {
358
						Object parent = treeStructureAdvisor.getParent(removed);
359
						Object[] children = contentProvider.getChildren(parent);
360
						boolean atLeastOneChecked = false;
361
						boolean atLeastOneUnchecked = false;
362
						for (int i = 0; i < children.length; i++) {
363
							Object child = children[i];
364
							if (checkedElements.contains(child)) {
365
								atLeastOneChecked = true;
366
							} else {
367
								atLeastOneUnchecked = true;
368
							}
369
						}
370
						checkParentPath(parent, !atLeastOneUnchecked,
371
								atLeastOneChecked && atLeastOneUnchecked);
372
					}
373
				}
374
				for (Iterator it = event.diff.getAdditions().iterator(); it
375
						.hasNext();) {
376
					Object added = it.next();
377
					if (added instanceof IU) {
378
						boolean checked = checkedElements.contains(added);
379
						viewer.setChecked(added, checked);
380
						handleChecked(added, checked);
381
					}
382
				}
383
			}
384
		});
385
		viewer.addDoubleClickListener(new IDoubleClickListener() {
386
			public void doubleClick(DoubleClickEvent event) {
387
				IStructuredSelection selection = (IStructuredSelection) event
388
						.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 (realizedElements.contains(element)) {
449
			viewer.setChecked(element, checked);
450
			viewer.setGrayed(element, grayed);
451
		}
452
	}
453
454
}

Return to bug 237359