Mercurial > projects > dwt2
comparison org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/observable/ValidatedObservableList.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.ValidatedObservableList; | |
13 | |
14 import java.lang.all; | |
15 | |
16 import java.util.ArrayList; | |
17 import java.util.Collection; | |
18 import java.util.Collections; | |
19 import java.util.Iterator; | |
20 import java.util.List; | |
21 import java.util.ListIterator; | |
22 | |
23 import org.eclipse.core.databinding.observable.Diffs; | |
24 import org.eclipse.core.databinding.observable.IStaleListener; | |
25 import org.eclipse.core.databinding.observable.ObservableTracker; | |
26 import org.eclipse.core.databinding.observable.StaleEvent; | |
27 import org.eclipse.core.databinding.observable.list.IListChangeListener; | |
28 import org.eclipse.core.databinding.observable.list.IObservableList; | |
29 import org.eclipse.core.databinding.observable.list.ListChangeEvent; | |
30 import org.eclipse.core.databinding.observable.list.ListDiff; | |
31 import org.eclipse.core.databinding.observable.list.ListDiffEntry; | |
32 import org.eclipse.core.databinding.observable.list.ListDiffVisitor; | |
33 import org.eclipse.core.databinding.observable.list.ObservableList; | |
34 import org.eclipse.core.databinding.observable.value.IObservableValue; | |
35 import org.eclipse.core.databinding.observable.value.IValueChangeListener; | |
36 import org.eclipse.core.databinding.observable.value.ValueChangeEvent; | |
37 import org.eclipse.core.runtime.Assert; | |
38 import org.eclipse.core.runtime.IStatus; | |
39 | |
40 /** | |
41 * @since 3.3 | |
42 * | |
43 */ | |
44 public class ValidatedObservableList : ObservableList { | |
45 private IObservableList target; | |
46 private IObservableValue validationStatus; | |
47 | |
48 // Only true when out of sync with target due to validation status | |
49 private bool stale; | |
50 | |
51 // True when validaton status changes from invalid to valid. | |
52 private bool computeNextDiff = false; | |
53 | |
54 private bool updatingTarget = false; | |
55 | |
56 private IListChangeListener targetChangeListener = new class() IListChangeListener { | |
57 public void handleListChange(ListChangeEvent event) { | |
58 if (updatingTarget) | |
59 return; | |
60 IStatus status = cast(IStatus) validationStatus.getValue(); | |
61 if (isValid(status)) { | |
62 if (stale) { | |
63 // this.stale means we are out of sync with target, | |
64 // so reset wrapped list to exactly mirror target | |
65 stale = false; | |
66 updateWrappedList(new ArrayList(target)); | |
67 } else { | |
68 ListDiff diff = event.diff; | |
69 if (computeNextDiff) { | |
70 diff = Diffs.computeListDiff(wrappedList, target); | |
71 computeNextDiff = false; | |
72 } | |
73 applyDiff(diff, wrappedList); | |
74 fireListChange(diff); | |
75 } | |
76 } else { | |
77 makeStale(); | |
78 } | |
79 } | |
80 }; | |
81 | |
82 private static bool isValid(IStatus status) { | |
83 return status.isOK() || status.matches(IStatus.INFO | IStatus.WARNING); | |
84 } | |
85 | |
86 private IStaleListener targetStaleListener = new class() IStaleListener { | |
87 public void handleStale(StaleEvent staleEvent) { | |
88 fireStale(); | |
89 } | |
90 }; | |
91 | |
92 private IValueChangeListener validationStatusChangeListener = new class() IValueChangeListener { | |
93 public void handleValueChange(ValueChangeEvent event) { | |
94 IStatus oldStatus = cast(IStatus) event.diff.getOldValue(); | |
95 IStatus newStatus = cast(IStatus) event.diff.getNewValue(); | |
96 if (stale && !isValid(oldStatus) && isValid(newStatus)) { | |
97 // this.stale means we are out of sync with target, | |
98 // reset wrapped list to exactly mirror target | |
99 stale = false; | |
100 updateWrappedList(new ArrayList(target)); | |
101 | |
102 // If the validation status becomes valid because of a change in | |
103 // target observable | |
104 computeNextDiff = true; | |
105 } | |
106 } | |
107 }; | |
108 | |
109 /** | |
110 * @param target | |
111 * @param validationStatus | |
112 */ | |
113 public this(IObservableList target, | |
114 IObservableValue validationStatus) { | |
115 super(target.getRealm(), new ArrayList(target), target.getElementType()); | |
116 Assert.isNotNull(validationStatus, | |
117 "Validation status observable cannot be null"); //$NON-NLS-1$ | |
118 Assert | |
119 .isTrue(target.getRealm().equals(validationStatus.getRealm()), | |
120 "Target and validation status observables must be on the same realm"); //$NON-NLS-1$ | |
121 this.target = target; | |
122 this.validationStatus = validationStatus; | |
123 target.addListChangeListener(targetChangeListener); | |
124 target.addStaleListener(targetStaleListener); | |
125 validationStatus.addValueChangeListener(validationStatusChangeListener); | |
126 } | |
127 | |
128 private void makeStale() { | |
129 if (!stale) { | |
130 stale = true; | |
131 fireStale(); | |
132 } | |
133 } | |
134 | |
135 private void updateTargetList(ListDiff diff) { | |
136 updatingTarget = true; | |
137 try { | |
138 if (stale) { | |
139 stale = false; | |
140 applyDiff(Diffs.computeListDiff(target, wrappedList), target); | |
141 } else { | |
142 applyDiff(diff, target); | |
143 } | |
144 } finally { | |
145 updatingTarget = false; | |
146 } | |
147 } | |
148 | |
149 private void applyDiff(ListDiff diff, List list) { | |
150 diff.accept(new class(list) ListDiffVisitor { | |
151 List list_; | |
152 this(List a){ list_=a;} | |
153 public void handleAdd(int index, Object element) { | |
154 list_.add(index, element); | |
155 } | |
156 | |
157 public void handleRemove(int index, Object element) { | |
158 list_.remove(index); | |
159 } | |
160 | |
161 public void handleReplace(int index, Object oldElement, | |
162 Object newElement) { | |
163 list_.set(index, newElement); | |
164 } | |
165 }); | |
166 } | |
167 | |
168 public bool isStale() { | |
169 ObservableTracker.getterCalled(this); | |
170 return stale || target.isStale(); | |
171 } | |
172 | |
173 public void add(int index, Object element) { | |
174 checkRealm(); | |
175 wrappedList.add(index, element); | |
176 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, | |
177 true, element)); | |
178 updateTargetList(diff); | |
179 fireListChange(diff); | |
180 } | |
181 | |
182 public bool add(Object o) { | |
183 checkRealm(); | |
184 add(wrappedList.size(), o); | |
185 return true; | |
186 } | |
187 | |
188 public bool addAll(Collection c) { | |
189 checkRealm(); | |
190 return addAll(wrappedList.size(), c); | |
191 } | |
192 | |
193 public bool addAll(int index, Collection c) { | |
194 checkRealm(); | |
195 Object[] elements = c.toArray(); | |
196 ListDiffEntry[] entries = new ListDiffEntry[elements.length]; | |
197 for (int i = 0; i < elements.length; i++) { | |
198 wrappedList.add(index + i, elements[i]); | |
199 entries[i] = Diffs | |
200 .createListDiffEntry(index + i, true, elements[i]); | |
201 } | |
202 ListDiff diff = Diffs.createListDiff(entries); | |
203 updateTargetList(diff); | |
204 fireListChange(diff); | |
205 return true; | |
206 } | |
207 | |
208 public void clear() { | |
209 checkRealm(); | |
210 if (isEmpty()) | |
211 return; | |
212 ListDiff diff = Diffs.computeListDiff(wrappedList, | |
213 Collections.EMPTY_LIST); | |
214 wrappedList.clear(); | |
215 updateTargetList(diff); | |
216 fireListChange(diff); | |
217 } | |
218 | |
219 public Iterator iterator() { | |
220 getterCalled(); | |
221 final ListIterator wrappedIterator = wrappedList.listIterator(); | |
222 return new class() Iterator { | |
223 Object last = null; | |
224 | |
225 public bool hasNext() { | |
226 return wrappedIterator.hasNext(); | |
227 } | |
228 | |
229 public Object next() { | |
230 return last = wrappedIterator.next(); | |
231 } | |
232 | |
233 public void remove() { | |
234 int index = wrappedIterator.previousIndex(); | |
235 wrappedIterator.remove(); | |
236 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( | |
237 index, false, last)); | |
238 updateTargetList(diff); | |
239 fireListChange(diff); | |
240 } | |
241 }; | |
242 } | |
243 | |
244 public ListIterator listIterator() { | |
245 return listIterator(0); | |
246 } | |
247 | |
248 public ListIterator listIterator(int index) { | |
249 getterCalled(); | |
250 final ListIterator wrappedIterator = wrappedList.listIterator(index); | |
251 return new class() ListIterator { | |
252 int lastIndex = -1; | |
253 Object last = null; | |
254 | |
255 public void add(Object o) { | |
256 wrappedIterator.add(o); | |
257 lastIndex = previousIndex(); | |
258 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( | |
259 lastIndex, true, o)); | |
260 updateTargetList(diff); | |
261 fireListChange(diff); | |
262 } | |
263 | |
264 public bool hasNext() { | |
265 return wrappedIterator.hasNext(); | |
266 } | |
267 | |
268 public bool hasPrevious() { | |
269 return wrappedIterator.hasPrevious(); | |
270 } | |
271 | |
272 public Object next() { | |
273 last = wrappedIterator.next(); | |
274 lastIndex = previousIndex(); | |
275 return last; | |
276 } | |
277 | |
278 public int nextIndex() { | |
279 return wrappedIterator.nextIndex(); | |
280 } | |
281 | |
282 public Object previous() { | |
283 last = wrappedIterator.previous(); | |
284 lastIndex = nextIndex(); | |
285 return last; | |
286 } | |
287 | |
288 public int previousIndex() { | |
289 return wrappedIterator.previousIndex(); | |
290 } | |
291 | |
292 public void remove() { | |
293 wrappedIterator.remove(); | |
294 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( | |
295 lastIndex, false, last)); | |
296 lastIndex = -1; | |
297 updateTargetList(diff); | |
298 fireListChange(diff); | |
299 } | |
300 | |
301 public void set(Object o) { | |
302 wrappedIterator.set(o); | |
303 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( | |
304 lastIndex, false, last), Diffs.createListDiffEntry( | |
305 lastIndex, true, o)); | |
306 last = o; | |
307 updateTargetList(diff); | |
308 fireListChange(diff); | |
309 } | |
310 }; | |
311 } | |
312 | |
313 public Object move(int oldIndex, int newIndex) { | |
314 checkRealm(); | |
315 int size = wrappedList.size(); | |
316 if (oldIndex >= size) | |
317 throw new IndexOutOfBoundsException( | |
318 "oldIndex: " + oldIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$ | |
319 if (newIndex >= size) | |
320 throw new IndexOutOfBoundsException( | |
321 "newIndex: " + newIndex + ", size:" + size); //$NON-NLS-1$ //$NON-NLS-2$ | |
322 if (oldIndex is newIndex) | |
323 return wrappedList.get(oldIndex); | |
324 Object element = wrappedList.remove(oldIndex); | |
325 wrappedList.add(newIndex, element); | |
326 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry( | |
327 oldIndex, false, element), Diffs.createListDiffEntry(newIndex, | |
328 true, element)); | |
329 updateTargetList(diff); | |
330 fireListChange(diff); | |
331 return element; | |
332 } | |
333 | |
334 public Object remove(int index) { | |
335 checkRealm(); | |
336 Object element = wrappedList.remove(index); | |
337 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, | |
338 false, element)); | |
339 updateTargetList(diff); | |
340 fireListChange(diff); | |
341 return element; | |
342 } | |
343 | |
344 public bool remove(Object o) { | |
345 checkRealm(); | |
346 int index = wrappedList.indexOf(o); | |
347 if (index is -1) | |
348 return false; | |
349 remove(index); | |
350 return true; | |
351 } | |
352 | |
353 public bool removeAll(Collection c) { | |
354 checkRealm(); | |
355 List list = new ArrayList(wrappedList); | |
356 bool changed = list.removeAll(c); | |
357 if (changed) { | |
358 ListDiff diff = Diffs.computeListDiff(wrappedList, list); | |
359 wrappedList = list; | |
360 updateTargetList(diff); | |
361 fireListChange(diff); | |
362 } | |
363 return changed; | |
364 } | |
365 | |
366 public bool retainAll(Collection c) { | |
367 checkRealm(); | |
368 List list = new ArrayList(wrappedList); | |
369 bool changed = list.retainAll(c); | |
370 if (changed) { | |
371 ListDiff diff = Diffs.computeListDiff(wrappedList, list); | |
372 wrappedList = list; | |
373 updateTargetList(diff); | |
374 fireListChange(diff); | |
375 } | |
376 return changed; | |
377 } | |
378 | |
379 public Object set(int index, Object element) { | |
380 checkRealm(); | |
381 Object oldElement = wrappedList.set(index, element); | |
382 ListDiff diff = Diffs.createListDiff(Diffs.createListDiffEntry(index, | |
383 false, oldElement), Diffs.createListDiffEntry(index, true, | |
384 element)); | |
385 updateTargetList(diff); | |
386 fireListChange(diff); | |
387 return oldElement; | |
388 } | |
389 | |
390 public synchronized void dispose() { | |
391 target.removeListChangeListener(targetChangeListener); | |
392 target.removeStaleListener(targetStaleListener); | |
393 validationStatus | |
394 .removeValueChangeListener(validationStatusChangeListener); | |
395 super.dispose(); | |
396 } | |
397 } |