comparison org.eclipse.jface.databinding/src/org/eclipse/jface/internal/databinding/provisional/viewers/TreeNode.d @ 78:0a55d2d5a946

Added file for databinding
author Frank Benoit <benoit@tionex.de>
date Tue, 14 Apr 2009 11:35:29 +0200
parents
children 6be48cf9f95c
comparison
equal deleted inserted replaced
76:f05e6e8b2f2d 78:0a55d2d5a946
1 /*******************************************************************************
2 * Copyright (c) 2006, 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 * Stefan Xenos, IBM - initial API and implementation
11 *******************************************************************************/
12 module org.eclipse.jface.internal.databinding.provisional.viewers.TreeNode;
13
14 import java.lang.all;
15
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.Set;
19
20 import org.eclipse.core.databinding.observable.IStaleListener;
21 import org.eclipse.core.databinding.observable.Observables;
22 import org.eclipse.core.databinding.observable.StaleEvent;
23 import org.eclipse.core.databinding.observable.set.IObservableSet;
24 import org.eclipse.core.databinding.observable.set.ISetChangeListener;
25 import org.eclipse.core.databinding.observable.set.SetChangeEvent;
26 import org.eclipse.core.databinding.observable.set.SetDiff;
27 import org.eclipse.jface.databinding.viewers.ObservableListTreeContentProvider;
28 import org.eclipse.jface.databinding.viewers.ObservableSetTreeContentProvider;
29 import org.eclipse.jface.viewers.TreeViewer;
30 import org.eclipse.swt.widgets.Control;
31
32 /**
33 *
34 * @since 1.0
35 * @deprecated Use {@link ObservableSetTreeContentProvider} or
36 * {@link ObservableListTreeContentProvider} instead.
37 */
38 /* package */ class TreeNode : ISetChangeListener, IStaleListener {
39 private UnorderedTreeContentProvider contentProvider;
40 private Object element;
41
42 // Stores the set of parents (null if there are less than 2)
43 private HashSet parents = null;
44
45 // Stores one representative parent. If there is more than one parent,
46 // the complete set of parents can be found in the parents set.
47 Object parent;
48
49 /**
50 * Set of child elements.
51 */
52 private IObservableSet children;
53
54 private bool hasPendingNode = false;
55 private bool isStale;
56 private bool listeningToChildren = false;
57 private bool prefetchEnqueued = false;
58
59 /**
60 * @param element
61 * @param cp
62 */
63 public this(Object element, UnorderedTreeContentProvider cp) {
64 this.element = element;
65 this.contentProvider = cp;
66 children = contentProvider.createChildSet(element);
67 if (children is null) {
68 children = Observables.emptyObservableSet();
69 listeningToChildren = true;
70 }
71 hasPendingNode = children.isStale();
72 }
73
74 /**
75 * @param parent
76 */
77 public void addParent(Object parent) {
78 if (this.parent is null) {
79 this.parent = parent;
80 } else {
81 if (parent.equals(this.parent)) {
82 return;
83 }
84 if (parents is null) {
85 parents = new HashSet();
86 parents.add(this.parent);
87 }
88 parents.add(parent);
89 }
90 }
91
92 /**
93 * @param parent
94 */
95 public void removeParent(Object parent) {
96 if (this.parents !is null) {
97 parents.remove(parent);
98 }
99
100 if (parent is this.parent) {
101 if (parents is null || parents.isEmpty()) {
102 this.parent = null;
103 } else {
104 this.parent = parents.iterator().next();
105 }
106 }
107
108 if (this.parents !is null && this.parents.size() <= 1) {
109 this.parents = null;
110 }
111 }
112
113 /**
114 * Returns the set of children for this node. If new children are discovered later, they
115 * will be added directly to the viewer.
116 *
117 * @return TODO
118 */
119 public Set getChildren() {
120 if (!listeningToChildren) {
121 listeningToChildren = true;
122 children.addSetChangeListener(this);
123 hasPendingNode = children.isEmpty() && children.isStale();
124 children.addStaleListener(this);
125 updateStale();
126 }
127
128 // If the child set is stale and empty, show the "pending" node
129 if (hasPendingNode) {
130 Object pendingNode = contentProvider.getPendingNode();
131 return Collections.singleton(pendingNode);
132 }
133 return children;
134 }
135
136 /**
137 * @return TODO
138 */
139 public IObservableSet getChildrenSet() {
140 return children;
141 }
142
143 private void updateStale() {
144 bool willBeStale = children.isStale();
145 if (willBeStale !is isStale) {
146 isStale = willBeStale;
147
148 contentProvider.changeStale(isStale? 1 : -1);
149 }
150 }
151
152 /**
153 * @return TODO
154 */
155 public bool isStale() {
156 return isStale;
157 }
158
159 /**
160 * Returns true if the viewer should show a plus sign for expanding this
161 * node.
162 *
163 * @return TODO
164 */
165 public bool shouldShowPlus() {
166 if (children is null) {
167 // if (!hasPendingNode) {
168 // hasPendingNode = true;
169 // contentProvider.add(element, Collections.singleton(contentProvider.getPendingNode()));
170 // }
171 return true;
172 }
173 if (!listeningToChildren && !prefetchEnqueued) {
174 prefetchEnqueued = true;
175 contentProvider.enqueuePrefetch(this);
176 }
177 return !listeningToChildren || hasPendingNode || !children.isEmpty();
178 }
179
180 /**
181 * Disposes this node and removes all remaining children.
182 */
183 public void dispose() {
184 if (children !is null) {
185 if (listeningToChildren) {
186 contentProvider.remove(element, children, true);
187 children.removeSetChangeListener(this);
188 children.removeStaleListener(this);
189 }
190 children.dispose();
191 children = null;
192
193 if (listeningToChildren && isStale) {
194 contentProvider.changeStale(-1);
195 }
196 }
197 }
198
199 /**
200 * @return TODO
201 */
202 public bool isDisposed() {
203 return children is null;
204 }
205
206 /**
207 * Returns one representative parent, or null if this node is unparented. Use
208 * getParents() to get the complete set of known parents.
209 *
210 * @return TODO
211 */
212 public Object getParent() {
213 return parent;
214 }
215
216 /**
217 *
218 * @return the set of all known parents for this node
219 */
220 public Set getParents() {
221 if (parents is null) {
222 if (parent is null) {
223 return Collections.EMPTY_SET;
224 }
225 return Collections.singleton(parent);
226 }
227 return parents;
228 }
229
230 /**
231 * Called when the child set changes. Should not be called directly by the viewer.
232 */
233 public void handleSetChange(SetChangeEvent event) {
234 SetDiff diff = event.diff;
235 TreeViewer viewer = this.contentProvider.getViewer();
236 if (viewer !is null) {
237 Control control = viewer.getControl();
238 if (control !is null) {
239 if (control.isDisposed()) {
240 // If the widgetry was disposed without notifying the content provider, then
241 // dispose the content provider now and stop processing events.
242 contentProvider.dispose();
243 return;
244 }
245 }
246 }
247
248 bool shouldHavePendingNode = children.isEmpty() && children.isStale();
249
250 Set additions = diff.getAdditions();
251 // Check if we should add the pending node
252 if (shouldHavePendingNode && !hasPendingNode) {
253 HashSet newAdditions = new HashSet();
254 newAdditions.addAll(additions);
255 newAdditions.add(contentProvider.getPendingNode());
256 additions = newAdditions;
257 hasPendingNode = true;
258 }
259
260 Set removals = diff.getRemovals();
261 // Check if we should remove the pending node
262 if (!shouldHavePendingNode && hasPendingNode) {
263 HashSet newRemovals = new HashSet();
264 newRemovals.addAll(removals);
265 newRemovals.add(contentProvider.getPendingNode());
266 removals = newRemovals;
267 hasPendingNode = false;
268 }
269 if (!additions.isEmpty()) {
270 contentProvider.add(element, additions);
271 }
272 if (!removals.isEmpty()) {
273 contentProvider.remove(element, removals, children.isEmpty() && !hasPendingNode);
274 }
275
276 updateStale();
277 }
278
279 public void handleStale(StaleEvent staleEvent) {
280 TreeViewer viewer = this.contentProvider.getViewer();
281 if (viewer !is null) {
282 Control control = viewer.getControl();
283 if (control !is null) {
284 if (control.isDisposed()) {
285 // If the widgetry was disposed without notifying the content provider, then
286 // dispose the content provider now and stop processing events.
287 contentProvider.dispose();
288 return;
289 }
290 }
291 }
292
293 bool shouldHavePendingNode = children.isEmpty() && children.isStale();
294
295 // Check if we should add the pending node
296 if (shouldHavePendingNode && !hasPendingNode) {
297 hasPendingNode = shouldHavePendingNode;
298 contentProvider.add(element, Collections.singleton(contentProvider.getPendingNode()));
299 }
300
301 // Check if we should remove the pending node
302 if (!shouldHavePendingNode && hasPendingNode) {
303 hasPendingNode = shouldHavePendingNode;
304 contentProvider.remove(element, Collections.singleton(contentProvider.getPendingNode()), true);
305 }
306
307 updateStale();
308 }
309
310 /**
311 * @return TODO
312 */
313 public Object getElement() {
314 return element;
315 }
316
317 /**
318 *
319 */
320 public void prefetch() {
321 TreeViewer viewer = this.contentProvider.getViewer();
322 if (viewer !is null) {
323 Control control = viewer.getControl();
324 if (control !is null) {
325 if (control.isDisposed()) {
326 // If the widgetry has been disposed, then avoid sending anything
327 // to the viewer.
328 return;
329 }
330 }
331 }
332
333 Set children = getChildren();
334 if (!children.isEmpty()) {
335 contentProvider.add(element, children);
336 } else {
337 // We need to remove the + sign, and adding/removing elements won't do the trick
338 contentProvider.getViewer().refresh(element);
339 }
340 }
341 }