Mercurial > projects > dwt2
comparison org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/ValidatedObservableSet.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) 2008 Matthew Hall 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 * Matthew Hall - initial API and implementation (bug 218269) | |
10 ******************************************************************************/ | |
11 | |
12 module org.eclipse.core.internal.databinding.observable.ValidatedObservableSet; | |
13 | |
14 import java.lang.all; | |
15 | |
16 import java.util.Collection; | |
17 import java.util.Collections; | |
18 import java.util.HashSet; | |
19 import java.util.Iterator; | |
20 import java.util.Set; | |
21 | |
22 import org.eclipse.core.databinding.observable.Diffs; | |
23 import org.eclipse.core.databinding.observable.IStaleListener; | |
24 import org.eclipse.core.databinding.observable.StaleEvent; | |
25 import org.eclipse.core.databinding.observable.set.IObservableSet; | |
26 import org.eclipse.core.databinding.observable.set.ISetChangeListener; | |
27 import org.eclipse.core.databinding.observable.set.ObservableSet; | |
28 import org.eclipse.core.databinding.observable.set.SetChangeEvent; | |
29 import org.eclipse.core.databinding.observable.set.SetDiff; | |
30 import org.eclipse.core.databinding.observable.value.IObservableValue; | |
31 import org.eclipse.core.databinding.observable.value.IValueChangeListener; | |
32 import org.eclipse.core.databinding.observable.value.ValueChangeEvent; | |
33 import org.eclipse.core.runtime.Assert; | |
34 import org.eclipse.core.runtime.IStatus; | |
35 | |
36 /** | |
37 * @since 3.3 | |
38 * | |
39 */ | |
40 public class ValidatedObservableSet : ObservableSet { | |
41 private IObservableSet target; | |
42 private IObservableValue validationStatus; | |
43 | |
44 // Only true when out of sync with target due to validation status | |
45 private bool stale; | |
46 | |
47 // True when validation status changes from invalid to valid. | |
48 private bool computeNextDiff = false; | |
49 | |
50 private bool updatingTarget = false; | |
51 | |
52 private ISetChangeListener targetChangeListener = new class() ISetChangeListener { | |
53 public void handleSetChange(SetChangeEvent event) { | |
54 if (updatingTarget) | |
55 return; | |
56 IStatus status = cast(IStatus) validationStatus.getValue(); | |
57 if (isValid(status)) { | |
58 if (stale) { | |
59 // this.stale means we are out of sync with target, | |
60 // so reset wrapped list to exactly mirror target | |
61 stale = false; | |
62 updateWrappedSet(new HashSet(target)); | |
63 } else { | |
64 SetDiff diff = event.diff; | |
65 if (computeNextDiff) { | |
66 diff = Diffs.computeSetDiff(wrappedSet, target); | |
67 computeNextDiff = false; | |
68 } | |
69 applyDiff(diff, wrappedSet); | |
70 fireSetChange(diff); | |
71 } | |
72 } else { | |
73 makeStale(); | |
74 } | |
75 } | |
76 }; | |
77 | |
78 private IStaleListener targetStaleListener = new class() IStaleListener { | |
79 public void handleStale(StaleEvent staleEvent) { | |
80 fireStale(); | |
81 } | |
82 }; | |
83 | |
84 private IValueChangeListener validationStatusChangeListener = new class() IValueChangeListener { | |
85 public void handleValueChange(ValueChangeEvent event) { | |
86 IStatus oldStatus = cast(IStatus) event.diff.getOldValue(); | |
87 IStatus newStatus = cast(IStatus) event.diff.getNewValue(); | |
88 if (stale && !isValid(oldStatus) && isValid(newStatus)) { | |
89 // this.stale means we are out of sync with target, | |
90 // reset wrapped set to exactly mirror target | |
91 stale = false; | |
92 updateWrappedSet(new HashSet(target)); | |
93 | |
94 // If the validation status becomes valid because of a change in | |
95 // target observable | |
96 computeNextDiff = true; | |
97 } | |
98 } | |
99 }; | |
100 | |
101 /** | |
102 * @param target | |
103 * @param validationStatus | |
104 */ | |
105 public this(IObservableSet target, | |
106 IObservableValue validationStatus) { | |
107 super(target.getRealm(), new HashSet(target), target.getElementType()); | |
108 Assert.isNotNull(validationStatus, | |
109 "Validation status observable cannot be null"); //$NON-NLS-1$ | |
110 Assert | |
111 .isTrue(target.getRealm().equals(validationStatus.getRealm()), | |
112 "Target and validation status observables must be on the same realm"); //$NON-NLS-1$ | |
113 this.target = target; | |
114 this.validationStatus = validationStatus; | |
115 target.addSetChangeListener(targetChangeListener); | |
116 target.addStaleListener(targetStaleListener); | |
117 validationStatus.addValueChangeListener(validationStatusChangeListener); | |
118 } | |
119 | |
120 private void updateWrappedSet(Set newSet) { | |
121 Set oldSet = wrappedSet; | |
122 SetDiff diff = Diffs.computeSetDiff(oldSet, newSet); | |
123 wrappedSet = newSet; | |
124 fireSetChange(diff); | |
125 } | |
126 | |
127 private static bool isValid(IStatus status) { | |
128 return status.isOK() || status.matches(IStatus.INFO | IStatus.WARNING); | |
129 } | |
130 | |
131 private void applyDiff(SetDiff diff, Set set) { | |
132 for (Iterator iterator = diff.getRemovals().iterator(); iterator | |
133 .hasNext();) { | |
134 set.remove(iterator.next()); | |
135 } | |
136 for (Iterator iterator = diff.getAdditions().iterator(); iterator | |
137 .hasNext();) { | |
138 set.add(iterator.next()); | |
139 } | |
140 } | |
141 | |
142 private void makeStale() { | |
143 if (!stale) { | |
144 stale = true; | |
145 fireStale(); | |
146 } | |
147 } | |
148 | |
149 private void updateTargetSet(SetDiff diff) { | |
150 updatingTarget = true; | |
151 try { | |
152 if (stale) { | |
153 stale = false; | |
154 applyDiff(Diffs.computeSetDiff(target, wrappedSet), target); | |
155 } else { | |
156 applyDiff(diff, target); | |
157 } | |
158 } finally { | |
159 updatingTarget = false; | |
160 } | |
161 } | |
162 | |
163 public bool isStale() { | |
164 getterCalled(); | |
165 return stale || target.isStale(); | |
166 } | |
167 | |
168 public bool add(Object o) { | |
169 getterCalled(); | |
170 bool changed = wrappedSet.add(o); | |
171 if (changed) { | |
172 SetDiff diff = Diffs.createSetDiff(Collections.singleton(o), | |
173 Collections.EMPTY_SET); | |
174 updateTargetSet(diff); | |
175 fireSetChange(diff); | |
176 } | |
177 return changed; | |
178 } | |
179 | |
180 public bool addAll(Collection c) { | |
181 getterCalled(); | |
182 HashSet set = new HashSet(wrappedSet); | |
183 bool changed = set.addAll(c); | |
184 if (changed) { | |
185 SetDiff diff = Diffs.computeSetDiff(wrappedSet, set); | |
186 wrappedSet = set; | |
187 updateTargetSet(diff); | |
188 fireSetChange(diff); | |
189 } | |
190 return changed; | |
191 } | |
192 | |
193 public void clear() { | |
194 getterCalled(); | |
195 if (isEmpty()) | |
196 return; | |
197 SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, wrappedSet); | |
198 wrappedSet = new HashSet(); | |
199 updateTargetSet(diff); | |
200 fireSetChange(diff); | |
201 } | |
202 | |
203 public Iterator iterator() { | |
204 getterCalled(); | |
205 final Iterator wrappedIterator = wrappedSet.iterator(); | |
206 return new class() Iterator { | |
207 Object last = null; | |
208 | |
209 public bool hasNext() { | |
210 return wrappedIterator.hasNext(); | |
211 } | |
212 | |
213 public Object next() { | |
214 return last = wrappedIterator.next(); | |
215 } | |
216 | |
217 public void remove() { | |
218 wrappedIterator.remove(); | |
219 SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, | |
220 Collections.singleton(last)); | |
221 updateTargetSet(diff); | |
222 fireSetChange(diff); | |
223 } | |
224 }; | |
225 } | |
226 | |
227 public bool remove(Object o) { | |
228 getterCalled(); | |
229 bool changed = wrappedSet.remove(o); | |
230 if (changed) { | |
231 SetDiff diff = Diffs.createSetDiff(Collections.EMPTY_SET, | |
232 Collections.singleton(o)); | |
233 updateTargetSet(diff); | |
234 fireSetChange(diff); | |
235 } | |
236 return changed; | |
237 } | |
238 | |
239 public bool removeAll(Collection c) { | |
240 getterCalled(); | |
241 Set set = new HashSet(wrappedSet); | |
242 bool changed = set.removeAll(c); | |
243 if (changed) { | |
244 SetDiff diff = Diffs.computeSetDiff(wrappedSet, set); | |
245 wrappedSet = set; | |
246 updateTargetSet(diff); | |
247 fireSetChange(diff); | |
248 } | |
249 return changed; | |
250 } | |
251 | |
252 public bool retainAll(Collection c) { | |
253 getterCalled(); | |
254 Set set = new HashSet(wrappedSet); | |
255 bool changed = set.retainAll(c); | |
256 if (changed) { | |
257 SetDiff diff = Diffs.computeSetDiff(wrappedSet, set); | |
258 wrappedSet = set; | |
259 updateTargetSet(diff); | |
260 fireSetChange(diff); | |
261 } | |
262 return changed; | |
263 } | |
264 | |
265 public synchronized void dispose() { | |
266 target.removeSetChangeListener(targetChangeListener); | |
267 target.removeStaleListener(targetStaleListener); | |
268 validationStatus | |
269 .removeValueChangeListener(validationStatusChangeListener); | |
270 super.dispose(); | |
271 } | |
272 } |