1 | |
package com.sun.javafx.runtime.location; |
2 | |
|
3 | |
import java.util.Iterator; |
4 | |
import java.util.List; |
5 | |
import java.util.ArrayList; |
6 | |
|
7 | |
import com.sun.javafx.runtime.AssignToBoundException; |
8 | |
import com.sun.javafx.runtime.ErrorHandler; |
9 | |
import com.sun.javafx.runtime.sequence.Sequence; |
10 | |
import com.sun.javafx.runtime.sequence.SequenceMutator; |
11 | |
import com.sun.javafx.runtime.sequence.SequencePredicate; |
12 | |
import com.sun.javafx.runtime.sequence.Sequences; |
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | 8155 | public class SequenceVariable<T> |
20 | |
extends AbstractVariable<Sequence<T>, SequenceLocation<T>, SequenceBindingExpression<T>> |
21 | |
implements SequenceLocation<T> { |
22 | |
|
23 | |
private final Class<T> clazz; |
24 | |
private final SequenceMutator.Listener<T> mutationListener; |
25 | |
private List<SequenceChangeListener<T>> changeListeners; |
26 | |
private Sequence<T> value; |
27 | |
private SequenceLocation<T> boundLocation; |
28 | |
|
29 | |
|
30 | |
public static <T> SequenceVariable<T> make(Class clazz) { |
31 | 602 | return new SequenceVariable<T>(clazz); |
32 | |
} |
33 | |
|
34 | |
public static <T> SequenceVariable<T> make(Sequence<T> value) { |
35 | 31 | return new SequenceVariable<T>(value); |
36 | |
} |
37 | |
|
38 | |
public static <T> SequenceVariable<T> make(Class clazz, Sequence<? extends T> value) { |
39 | 648 | return new SequenceVariable<T>(clazz, value); |
40 | |
} |
41 | |
|
42 | |
public static<T> SequenceVariable<T> make(Class clazz, boolean lazy, SequenceBindingExpression<T> binding, Location... dependencies) { |
43 | 8 | return new SequenceVariable<T>(clazz, lazy, binding, dependencies); |
44 | |
} |
45 | |
|
46 | |
public static<T> SequenceVariable<T> make(Class clazz, SequenceBindingExpression<T> binding, Location... dependencies) { |
47 | 40 | return new SequenceVariable<T>(clazz, false, binding, dependencies); |
48 | |
} |
49 | |
|
50 | |
public static<T> SequenceVariable<T> make(Class clazz, SequenceLocation<T> otherLocation) { |
51 | 0 | SequenceVariable<T> me = make(clazz); |
52 | 0 | me.bind(otherLocation); |
53 | 0 | return me; |
54 | |
} |
55 | |
|
56 | |
|
57 | |
public static<T> SequenceVariable<T> makeBijective(Class clazz, SequenceVariable<T> other) { |
58 | 0 | SequenceVariable<T> me = SequenceVariable.<T>make(clazz); |
59 | 0 | me.bijectiveBind(other); |
60 | 0 | return me; |
61 | |
} |
62 | |
|
63 | 1733 | protected SequenceVariable(Class clazz) { |
64 | 1733 | this.clazz = clazz; |
65 | 1733 | this.value = Sequences.emptySequence(clazz); |
66 | 1733 | this.mutationListener = new SequenceMutator.Listener<T>() { |
67 | |
public void onReplaceSlice(int startPos, int endPos, Sequence<? extends T> newElements, Sequence<T> oldValue, Sequence<T> newValue) { |
68 | 7262 | replaceSlice(startPos, endPos, newElements, newValue); |
69 | 7262 | } |
70 | |
}; |
71 | 1733 | } |
72 | |
|
73 | |
protected SequenceVariable(Sequence<T> value) { |
74 | 31 | this(value.getElementType()); |
75 | 31 | replaceValue(value); |
76 | 31 | } |
77 | |
|
78 | |
protected SequenceVariable(Class clazz, Sequence<? extends T> value) { |
79 | 648 | this(clazz); |
80 | 648 | if (value == null) |
81 | 0 | value = Sequences.emptySequence(clazz); |
82 | 648 | replaceValue(Sequences.upcast(clazz, value)); |
83 | 648 | } |
84 | |
|
85 | |
protected SequenceVariable(Class clazz, boolean lazy, SequenceBindingExpression<T> binding, Location... dependencies) { |
86 | 48 | this(clazz); |
87 | 48 | bind(lazy, binding); |
88 | 48 | addDependencies(dependencies); |
89 | 48 | } |
90 | |
|
91 | |
private void ensureValid() { |
92 | 17996 | if (isBound() && !isValid()) |
93 | 332 | update(); |
94 | 17996 | } |
95 | |
|
96 | |
|
97 | |
private void replaceValue(Sequence<T> newValue) { |
98 | 1695 | assert(boundLocation == null); |
99 | 1695 | if (newValue == null) |
100 | 0 | newValue = Sequences.emptySequence(clazz); |
101 | 1695 | replaceSlice(0, Sequences.size(value)-1, newValue, newValue); |
102 | 1695 | } |
103 | |
|
104 | |
|
105 | |
private void replaceSlice(int startPos, int endPos, Sequence<? extends T> newElements, Sequence<T> newValue) { |
106 | 8957 | assert(boundLocation == null); |
107 | 8957 | Sequence<T> oldValue = value; |
108 | 8957 | if (!Sequences.isEqual(oldValue, newValue) || !isInitialized() || !isEverValid()) { |
109 | 8598 | boolean notifyDependencies = isValid() || !isInitialized() || !isEverValid(); |
110 | 8598 | value = newValue; |
111 | 8598 | setValid(); |
112 | 8598 | notifyListeners(startPos, endPos, newElements, oldValue, newValue, notifyDependencies); |
113 | 8598 | } |
114 | |
else |
115 | 359 | setValid(); |
116 | 8957 | } |
117 | |
|
118 | |
|
119 | |
private Sequence<T> getRawValue() { |
120 | 8737 | return value; |
121 | |
} |
122 | |
|
123 | |
public Sequence<T> get() { |
124 | 27 | return getAsSequence(); |
125 | |
} |
126 | |
|
127 | |
public T get(int position) { |
128 | 10420 | return getAsSequence().get(position); |
129 | |
} |
130 | |
|
131 | |
public Sequence<T> getAsSequence() { |
132 | 17996 | ensureValid(); |
133 | 17996 | return value; |
134 | |
} |
135 | |
|
136 | |
public Sequence<T> getSlice(int startPos, int endPos) { |
137 | 40 | return getAsSequence().getSlice(startPos, endPos); |
138 | |
} |
139 | |
|
140 | |
public boolean isNull() { |
141 | 0 | return Sequences.size(getAsSequence()) == 0; |
142 | |
} |
143 | |
|
144 | |
protected SequenceBindingExpression<T> makeBindingExpression(final SequenceLocation<T> otherLocation) { |
145 | 0 | return new SequenceBindingExpression<T>() { |
146 | |
public Sequence<T> computeValue() { |
147 | 0 | return otherLocation.getAsSequence(); |
148 | |
} |
149 | |
}; |
150 | |
} |
151 | |
|
152 | |
public void addChangeListener(final ObjectChangeListener<Sequence<T>> listener) { |
153 | 0 | addChangeListener(new SequenceChangeListener<T>() { |
154 | |
public void onChange(int startPos, int endPos, Sequence<? extends T> newElements, Sequence<T> oldValue, Sequence<T> newValue) { |
155 | 0 | listener.onChange(oldValue, newValue); |
156 | 0 | } |
157 | |
}); |
158 | 0 | } |
159 | |
|
160 | |
public void addChangeListener(SequenceChangeListener<T> listener) { |
161 | 589 | if (changeListeners == null) |
162 | 566 | changeListeners = new ArrayList<SequenceChangeListener<T>>(); |
163 | 589 | changeListeners.add(listener); |
164 | 589 | } |
165 | |
|
166 | |
public void removeChangeListener(SequenceChangeListener<T> listener) { |
167 | 159 | if (changeListeners != null) |
168 | 159 | changeListeners.remove(listener); |
169 | 159 | } |
170 | |
|
171 | |
private void notifyListeners(int startPos, int endPos, |
172 | |
Sequence<? extends T> newElements, |
173 | |
Sequence<T> oldValue, Sequence<T> newValue, |
174 | |
boolean notifyDependencies) { |
175 | 9047 | if (notifyDependencies) |
176 | 8351 | invalidateDependencies(); |
177 | 9047 | if (changeListeners != null) { |
178 | 568 | for (SequenceChangeListener<T> listener : changeListeners) |
179 | 662 | listener.onChange(startPos, endPos, newElements, oldValue, newValue); |
180 | |
} |
181 | 9047 | } |
182 | |
|
183 | |
public void bind(SequenceLocation<T> otherLocation) { |
184 | 65 | ensureBindable(); |
185 | 65 | boundLocation = otherLocation; |
186 | 65 | Sequence<T> oldValue = value; |
187 | 65 | value = otherLocation.get(); |
188 | 65 | otherLocation.addChangeListener(new ChangeListener() { |
189 | |
public boolean onChange() { |
190 | 384 | invalidateDependencies(); |
191 | 384 | return true; |
192 | |
} |
193 | |
}); |
194 | 65 | otherLocation.addChangeListener(new SequenceChangeListener<T>() { |
195 | |
public void onChange(int startPos, int endPos, Sequence<? extends T> newElements, Sequence<T> oldValue, Sequence<T> newValue) { |
196 | 384 | value = newValue; |
197 | |
|
198 | 384 | notifyListeners(startPos, endPos, newElements, oldValue, newValue, false); |
199 | 384 | } |
200 | |
}); |
201 | 65 | notifyListeners(0, Sequences.size(oldValue)-1, value, oldValue, value, true); |
202 | 65 | } |
203 | |
|
204 | |
public boolean isBound() { |
205 | 30735 | return super.isBound() || (boundLocation != null); |
206 | |
} |
207 | |
|
208 | |
@Override |
209 | |
public String toString() { |
210 | 0 | return getAsSequence().toString(); |
211 | |
} |
212 | |
|
213 | |
public Iterator<T> iterator() { |
214 | 0 | return getAsSequence().iterator(); |
215 | |
} |
216 | |
|
217 | |
@Override |
218 | |
public void update() { |
219 | |
try { |
220 | 1369 | if (isBound() && !isValid() && boundLocation == null) { |
221 | 1016 | replaceValue(Sequences.upcast(clazz, binding.computeValue())); |
222 | |
} |
223 | |
} |
224 | 0 | catch (RuntimeException e) { |
225 | 0 | ErrorHandler.bindException(e); |
226 | 0 | if (isInitialized()) |
227 | 0 | replaceValue(Sequences.emptySequence(clazz)); |
228 | 1369 | } |
229 | 1369 | } |
230 | |
|
231 | |
private void ensureNotBound() { |
232 | 9477 | if (isBound()) |
233 | 149 | throw new AssignToBoundException("Cannot mutate bound sequence"); |
234 | 9328 | } |
235 | |
|
236 | |
public Sequence<T> set(Sequence<T> value) { |
237 | 1 | return setAsSequence(value); |
238 | |
} |
239 | |
|
240 | |
public void setDefault() { |
241 | 0 | setAsSequence(Sequences.emptySequence(clazz)); |
242 | 0 | } |
243 | |
|
244 | |
public Sequence<T> setAsSequence(Sequence<? extends T> newValue) { |
245 | |
Sequence<T> result; |
246 | 2646 | ensureNotBound(); |
247 | 2645 | Sequence<T> oldValue = getRawValue(); |
248 | |
|
249 | |
|
250 | |
|
251 | |
|
252 | |
|
253 | |
|
254 | 2645 | if (!Sequences.isEqual(oldValue, newValue) || !isInitialized() || !isEverValid()) { |
255 | 2447 | result = SequenceMutator.replaceSlice(oldValue, mutationListener, 0, Sequences.size(oldValue) - 1, newValue); |
256 | |
} |
257 | |
else |
258 | 198 | result = oldValue; |
259 | 2645 | return result; |
260 | |
} |
261 | |
|
262 | |
public Sequence<T> setAsSequenceFromLiteral(final Sequence<? extends T> value) { |
263 | 77 | deferredLiteral = new DeferredInitializer() { |
264 | |
public void apply() { |
265 | 76 | setAsSequence(value); |
266 | 76 | } |
267 | |
}; |
268 | 77 | return Sequences.upcast(clazz, value); |
269 | |
} |
270 | |
|
271 | |
@Override |
272 | |
public T set(int position, T newValue) { |
273 | 2166 | ensureNotBound(); |
274 | 2122 | SequenceMutator.set(getRawValue(), mutationListener, position, newValue); |
275 | 2122 | return newValue; |
276 | |
} |
277 | |
|
278 | |
@Override |
279 | |
public Sequence<? extends T> replaceSlice(int startPos, int endPos, Sequence<? extends T> newValues) { |
280 | 585 | ensureNotBound(); |
281 | 576 | SequenceMutator.replaceSlice(getRawValue(), mutationListener, startPos, endPos, newValues); |
282 | 576 | return newValues; |
283 | |
} |
284 | |
|
285 | |
@Override |
286 | |
public void delete(int position) { |
287 | 475 | ensureNotBound(); |
288 | 465 | SequenceMutator.delete(getRawValue(), mutationListener, position); |
289 | 465 | } |
290 | |
|
291 | |
@Override |
292 | |
public void deleteSlice(int startPos, int endPos) { |
293 | 373 | replaceSlice(startPos, endPos, null); |
294 | 364 | } |
295 | |
|
296 | |
@Override |
297 | |
public void delete(SequencePredicate<T> sequencePredicate) { |
298 | 532 | ensureNotBound(); |
299 | 532 | SequenceMutator.delete(getRawValue(), mutationListener, sequencePredicate); |
300 | 532 | } |
301 | |
|
302 | |
@Override |
303 | |
public void deleteAll() { |
304 | 70 | ensureNotBound(); |
305 | 60 | setAsSequence(Sequences.emptySequence(clazz)); |
306 | 60 | } |
307 | |
|
308 | |
@Override |
309 | |
public void deleteValue(final T targetValue) { |
310 | 541 | ensureNotBound(); |
311 | 531 | delete(new SequencePredicate<T>() { |
312 | |
public boolean matches(Sequence<? extends T> sequence, int index, T value) { |
313 | 4305 | if (value == null) |
314 | 0 | return targetValue == null; |
315 | 4305 | return value.equals(targetValue); |
316 | |
} |
317 | |
}); |
318 | 531 | } |
319 | |
|
320 | |
@Override |
321 | |
public void insert(T value) { |
322 | 1954 | ensureNotBound(); |
323 | 1944 | SequenceMutator.insert(getRawValue(), mutationListener, value); |
324 | 1944 | } |
325 | |
|
326 | |
@Override |
327 | |
public void insert(Sequence<? extends T> values) { |
328 | 6 | ensureNotBound(); |
329 | 5 | SequenceMutator.insert(getRawValue(), mutationListener, values); |
330 | 5 | } |
331 | |
|
332 | |
public void insertFirst(T value) { |
333 | 21 | ensureNotBound(); |
334 | 20 | SequenceMutator.insertFirst(getRawValue(), mutationListener, value); |
335 | 20 | } |
336 | |
|
337 | |
@Override |
338 | |
public void insertFirst(Sequence<? extends T> values) { |
339 | 2 | ensureNotBound(); |
340 | 1 | SequenceMutator.insertFirst(getRawValue(), mutationListener, values); |
341 | 1 | } |
342 | |
|
343 | |
@Override |
344 | |
public void insertBefore(T value, int position) { |
345 | 33 | ensureNotBound(); |
346 | 7 | SequenceMutator.insertBefore(getRawValue(), mutationListener, value, position); |
347 | 7 | } |
348 | |
|
349 | |
@Override |
350 | |
public void insertBefore(T value, SequencePredicate<T> sequencePredicate) { |
351 | 1 | ensureNotBound(); |
352 | 1 | SequenceMutator.insertBefore(getRawValue(), mutationListener, value, sequencePredicate); |
353 | 1 | } |
354 | |
|
355 | |
@Override |
356 | |
public void insertBefore(Sequence<? extends T> values, int position) { |
357 | 204 | ensureNotBound(); |
358 | 204 | SequenceMutator.insertBefore(getRawValue(), mutationListener, values, position); |
359 | 204 | } |
360 | |
|
361 | |
@Override |
362 | |
public void insertBefore(Sequence<? extends T> values, SequencePredicate<T> sequencePredicate) { |
363 | 1 | ensureNotBound(); |
364 | 1 | SequenceMutator.insertBefore(getRawValue(), mutationListener, values, sequencePredicate); |
365 | 1 | } |
366 | |
|
367 | |
@Override |
368 | |
public void insertAfter(T value, int position) { |
369 | 34 | ensureNotBound(); |
370 | 8 | SequenceMutator.insertAfter(this.getRawValue(), mutationListener, value, position); |
371 | 8 | } |
372 | |
|
373 | |
@Override |
374 | |
public void insertAfter(T value, SequencePredicate<T> sequencePredicate) { |
375 | 1 | ensureNotBound(); |
376 | 1 | SequenceMutator.insertAfter(getRawValue(), mutationListener, value, sequencePredicate); |
377 | 1 | } |
378 | |
|
379 | |
@Override |
380 | |
public void insertAfter(Sequence<? extends T> values, int position) { |
381 | 204 | ensureNotBound(); |
382 | 204 | SequenceMutator.insertAfter(getRawValue(), mutationListener, values, position); |
383 | 204 | } |
384 | |
|
385 | |
@Override |
386 | |
public void insertAfter(Sequence<? extends T> values, SequencePredicate<T> sequencePredicate) { |
387 | 1 | ensureNotBound(); |
388 | 1 | SequenceMutator.insertAfter(getRawValue(), mutationListener, values, sequencePredicate); |
389 | 1 | } |
390 | |
} |