72 * therefore suitable for methods that require ObservableList on input.
73 * <br><br>
74 * The utility methods are here mainly for performance reasons. All methods are optimized in a way that
75 * they yield only limited number of notifications. On the other hand, java.util.Collections methods
76 * might call "modification methods" on an ObservableList multiple times, resulting in a number of notifications.
77 *
78 * @since JavaFX 2.0
79 */
80 public class FXCollections {
81 /** Not to be instantiated. */
82 private FXCollections() { }
83
84 /**
85 * Constructs an ObservableList that is backed by the specified list.
86 * Mutation operations on the ObservableList instance will be reported
87 * to observers that have registered on that instance.<br>
88 * Note that mutation operations made directly to the underlying list are
89 * <em>not</em> reported to observers of any ObservableList that
90 * wraps it.
91 *
92 * @param list a concrete List that backs this ObservableList
93 * @return a newly created ObservableList
94 */
95 public static <E> ObservableList<E> observableList(List<E> list) {
96 if (list == null) {
97 throw new NullPointerException();
98 }
99 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list) :
100 new ObservableSequentialListWrapper<E>(list);
101 }
102
103 /**
104 * Constructs an ObservableList that is backed by the specified list.
105 * Mutation operations on the ObservableList instance will be reported
106 * to observers that have registered on that instance.<br>
107 * Note that mutation operations made directly to the underlying list are
108 * <em>not</em> reported to observers of any ObservableList that
109 * wraps it.
110 * <br>
111 * This list also reports mutations of the elements in it by using <code>extractor</code>.
112 * Observable objects returned by extractor (applied to each list element) are listened for changes
113 * and transformed into "update" change of ListChangeListener.
114 *
115 * @param list a concrete List that backs this ObservableList
116 * @param extractor element to Observable[] convertor
117 * @since JavaFX 2.1
118 * @return a newly created ObservableList
119 */
120 public static <E> ObservableList<E> observableList(List<E> list, Callback<E, Observable[]> extractor) {
121 if (list == null || extractor == null) {
122 throw new NullPointerException();
123 }
124 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list, extractor) :
125 new ObservableSequentialListWrapper<E>(list, extractor);
126 }
127
128 /**
129 * Constructs an ObservableMap that is backed by the specified map.
130 * Mutation operations on the ObservableMap instance will be reported
131 * to observers that have registered on that instance.<br>
132 * Note that mutation operations made directly to the underlying map are <em>not</em>
133 * reported to observers of any ObservableMap that wraps it.
134 * @param map a Map that backs this ObservableMap
135 * @return a newly created ObservableMap
136 */
137 public static <K, V> ObservableMap<K, V> observableMap(Map<K, V> map) {
138 if (map == null) {
139 throw new NullPointerException();
140 }
141 return new ObservableMapWrapper<K, V>(map);
142 }
143
144 /**
145 * Constructs an ObservableSet that is backed by the specified set.
146 * Mutation operations on the ObservableSet instance will be reported
147 * to observers that have registered on that instance.<br>
148 * Note that mutation operations made directly to the underlying set are <em>not</em>
149 * reported to observers of any ObservableSet that wraps it.
150 * @param set a Set that backs this ObservableSet
151 * @return a newly created ObservableSet
152 * @since JavaFX 2.1
153 */
154 public static <E> ObservableSet<E> observableSet(Set<E> set) {
155 if (set == null) {
156 throw new NullPointerException();
157 }
158 return new ObservableSetWrapper<E>(set);
159 }
160
161 /**
162 * Constructs an ObservableSet backed by a HashSet
163 * that contains all the specified elements.
164 * @param elements elements that will be added into returned ObservableSet
165 * @return a newly created ObservableSet
166 * @since JavaFX 2.1
167 */
168 public static <E> ObservableSet<E> observableSet(E... elements) {
169 if (elements == null) {
170 throw new NullPointerException();
171 }
172 Set<E> set = new HashSet<E>(elements.length);
173 Collections.addAll(set, elements);
174 return new ObservableSetWrapper<E>(set);
175 }
176
177 /**
178 * Constructs a read-only interface to the specified ObservableMap. Only
179 * mutation operations made to the underlying ObservableMap will be reported
180 * to observers that have registered on the unmodifiable instance. This allows
181 * clients to track changes in a Map but disallows the ability to modify it.
182 * @param map an ObservableMap that is to be monitored by this interface
183 * @return a newly created UnmodifiableObservableMap
184 */
185 public static <K, V> ObservableMap<K, V> unmodifiableObservableMap(ObservableMap<K, V> map) {
186 if (map == null) {
187 throw new NullPointerException();
188 }
189 return new com.sun.javafx.collections.UnmodifiableObservableMap<K, V>(map);
190 }
191
192 /**
193 * Creates and returns a typesafe wrapper on top of provided observable map.
194 * @param map an Observable map to be wrapped
195 * @param keyType the type of key that {@code map} is permitted to hold
196 * @param valueType the type of value that {@code map} is permitted to hold
197 * @return a dynamically typesafe view of the specified map
198 * @see Collections#checkedMap(java.util.Map, java.lang.Class)
199 * @since JavaFX 8.0
200 */
201 public static <K, V> ObservableMap<K, V> checkedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) {
202 if (map == null || keyType == null || valueType == null) {
203 throw new NullPointerException();
204 }
205 return new CheckedObservableMap<K, V>(map, keyType, valueType);
206 }
207
208 /**
209 * Creates and returns a synchronized wrapper on top of provided observable map.
210 * @param map the map to be "wrapped" in a synchronized map.
211 * @return A synchronized version of the observable map
212 * @see Collections#synchronizedMap(java.util.Map)
213 * @since JavaFX 8.0
214 */
215 public static <K, V> ObservableMap<K, V> synchronizedObservableMap(ObservableMap<K, V> map) {
216 if (map == null) {
217 throw new NullPointerException();
218 }
219 return new SynchronizedObservableMap<K, V>(map);
220 }
221
222 private static ObservableMap EMPTY_OBSERVABLE_MAP = new EmptyObservableMap();
223
224 /**
225 * Creates and empty unmodifiable observable map.
226 * @return An empty unmodifiable observable map
227 * @see Collections#emptyMap()
228 * @since JavaFX 8.0
229 */
230 @SuppressWarnings("unchecked")
231 public static <K, V> ObservableMap<K, V> emptyObservableMap() {
232 return EMPTY_OBSERVABLE_MAP;
233 }
234
235 /**
236 * Creates a new empty observable integer array.
237 * @return a newly created ObservableIntegerArray
238 * @since JavaFX 8.0
239 */
240 public static ObservableIntegerArray observableIntegerArray() {
241 return new ObservableIntegerArrayImpl();
242 }
243
244 /**
245 * Creates a new observable integer array with {@code values} set to it.
278 * @since JavaFX 8.0
279 */
280 public static ObservableFloatArray observableFloatArray(float... values) {
281 return new ObservableFloatArrayImpl(values);
282 }
283
284 /**
285 * Creates a new observable float array with copy of elements in given
286 * {@code array}.
287 * @param array observable float array to copy
288 * @return a newly created ObservableFloatArray
289 * @since JavaFX 8.0
290 */
291 public static ObservableFloatArray observableFloatArray(ObservableFloatArray array) {
292 return new ObservableFloatArrayImpl(array);
293 }
294
295 /**
296 * Creates a new empty observable list that is backed by an arraylist.
297 * @see #observableList(java.util.List)
298 * @return a newly created ObservableList
299 */
300 @SuppressWarnings("unchecked")
301 public static <E> ObservableList<E> observableArrayList() {
302 return observableList(new ArrayList());
303 }
304
305 /**
306 * Creates a new empty observable list backed by an arraylist.
307 *
308 * This list reports element updates.
309 * @param extractor element to Observable[] convertor. Observable objects are listened for changes on the element.
310 * @see #observableList(java.util.List, javafx.util.Callback)
311 * @since JavaFX 2.1
312 * @return a newly created ObservableList
313 */
314 public static <E> ObservableList<E> observableArrayList(Callback<E, Observable[]> extractor) {
315 return observableList(new ArrayList(), extractor);
316 }
317
318 /**
319 * Creates a new observable array list with {@code items} added to it.
320 * @return a newly created observableArrayList
321 * @param items the items that will be in the new observable ArrayList
322 * @see #observableArrayList()
323 */
324 public static <E> ObservableList<E> observableArrayList(E... items) {
325 ObservableList<E> list = observableArrayList();
326 list.addAll(items);
327 return list;
328 }
329
330 /**
331 * Creates a new observable array list and adds a content of collection {@code col}
332 * to it.
333 * @param col a collection which content should be added to the observableArrayList
334 * @return a newly created observableArrayList
335 */
336 public static <E> ObservableList<E> observableArrayList(Collection<? extends E> col) {
337 ObservableList<E> list = observableArrayList();
338 list.addAll(col);
339 return list;
340 }
341
342 /**
343 * Creates a new empty observable map that is backed by a HashMap.
344 * @param <K> the type of keys
345 * @param <V> the type of values
346 * @return a newly created observable HashMap
347 */
348 public static <K,V> ObservableMap<K,V> observableHashMap() {
349 return observableMap(new HashMap<K, V>());
350 }
351
352 /**
353 * Concatenates more observable lists into one. The resulting list
354 * would be backed by an arraylist.
355 * @param lists lists to concatenate
356 * @return new observable array list concatenated from the arguments
357 */
358 public static <E> ObservableList<E> concat(ObservableList<E>... lists) {
359 if (lists.length == 0 ) {
360 return observableArrayList();
361 }
362 if (lists.length == 1) {
363 return observableArrayList(lists[0]);
364 }
365 ArrayList<E> backingList = new ArrayList<E>();
366 for (ObservableList<E> s : lists) {
367 backingList.addAll(s);
368 }
369
370 return observableList(backingList);
371 }
372
373 /**
374 * Creates and returns unmodifiable wrapper list on top of provided observable list.
375 * @param list an ObservableList that is to be wrapped
376 * @return an ObserableList wrapper that is unmodifiable
377 * @see Collections#unmodifiableList(java.util.List)
378 */
379 public static<E> ObservableList<E> unmodifiableObservableList(ObservableList<E> list) {
380 if (list == null) {
381 throw new NullPointerException();
382 }
383 return new UnmodifiableObservableListImpl<E>(list);
384 }
385
386 /**
387 * Creates and returns a typesafe wrapper on top of provided observable list.
388 * @param list an Observable list to be wrapped
389 * @param type the type of element that <tt>list</tt> is permitted to hold
390 * @return a dynamically typesafe view of the specified list
391 * @see Collections#checkedList(java.util.List, java.lang.Class)
392 */
393 public static<E> ObservableList<E> checkedObservableList(ObservableList<E> list, Class<E> type) {
394 if (list == null) {
395 throw new NullPointerException();
396 }
397 return new CheckedObservableList<E>(list, type);
398 }
399
400 /**
401 * Creates and returns a synchronized wrapper on top of provided observable list.
402 * @param list the list to be "wrapped" in a synchronized list.
403 * @return A synchronized version of the observable list
404 * @see Collections#synchronizedList(java.util.List)
405 */
406 public static<E> ObservableList<E> synchronizedObservableList(ObservableList<E> list) {
407 if (list == null) {
408 throw new NullPointerException();
409 }
410 return new SynchronizedObservableList<E>(list);
411 }
412
413 private static ObservableList EMPTY_OBSERVABLE_LIST = new EmptyObservableList();
414
415
416 /**
417 * Creates and empty unmodifiable observable list.
418 * @return An empty unmodifiable observable list
419 * @see Collections#emptyList()
420 */
421 @SuppressWarnings("unchecked")
422 public static<E> ObservableList<E> emptyObservableList() {
423 return EMPTY_OBSERVABLE_LIST;
424 }
425
426 /**
427 * Creates an unmodifiable observable list with single element.
428 * @param e the only elements that will be contained in this singleton observable list
429 * @return a singleton observable list
430 * @see Collections#singletonList(java.lang.Object)
431 */
432 public static<E> ObservableList<E> singletonObservableList(E e) {
433 return new SingletonObservableList<E>(e);
434 }
435
436 /**
437 * Creates and returns unmodifiable wrapper on top of provided observable set.
438 * @param set an ObservableSet that is to be wrapped
439 * @return an ObserableSet wrapper that is unmodifiable
440 * @see Collections#unmodifiableSet(java.util.Set)
441 * @since JavaFX 8.0
442 */
443 public static<E> ObservableSet<E> unmodifiableObservableSet(ObservableSet<E> set) {
444 if (set == null) {
445 throw new NullPointerException();
446 }
447 return new UnmodifiableObservableSet<E>(set);
448 }
449
450 /**
451 * Creates and returns a typesafe wrapper on top of provided observable set.
452 * @param set an Observable set to be wrapped
453 * @param type the type of element that <tt>set</tt> is permitted to hold
454 * @return a dynamically typesafe view of the specified set
455 * @see Collections#checkedSet(java.util.Set, java.lang.Class)
456 * @since JavaFX 8.0
457 */
458 public static<E> ObservableSet<E> checkedObservableSet(ObservableSet<E> set, Class<E> type) {
459 if (set == null) {
460 throw new NullPointerException();
461 }
462 return new CheckedObservableSet<E>(set, type);
463 }
464
465 /**
466 * Creates and returns a synchronized wrapper on top of provided observable set.
467 * @param set the set to be "wrapped" in a synchronized set.
468 * @return A synchronized version of the observable set
469 * @see Collections#synchronizedSet(java.util.Set)
470 * @since JavaFX 8.0
471 */
472 public static<E> ObservableSet<E> synchronizedObservableSet(ObservableSet<E> set) {
473 if (set == null) {
474 throw new NullPointerException();
475 }
476 return new SynchronizedObservableSet<E>(set);
477 }
478
479 private static ObservableSet EMPTY_OBSERVABLE_SET = new EmptyObservableSet();
480
481 /**
482 * Creates and empty unmodifiable observable set.
483 * @return An empty unmodifiable observable set
484 * @see Collections#emptySet()
485 * @since JavaFX 8.0
486 */
487 @SuppressWarnings("unchecked")
488 public static<E> ObservableSet<E> emptyObservableSet() {
489 return EMPTY_OBSERVABLE_SET;
490 }
491
492 /**
493 * Copies elements from src to dest. Fires only <b>one</b> change notification on dest.
494 * @param dest the destination observable list
495 * @param src the source list
496 * @see Collections#copy(java.util.List, java.util.List)
497 */
498 @SuppressWarnings("unchecked")
499 public static <T> void copy(ObservableList<? super T> dest, List<? extends T> src) {
500 final int srcSize = src.size();
501 if (srcSize > dest.size()) {
502 throw new IndexOutOfBoundsException("Source does not fit in dest");
503 }
504 T[] destArray = (T[]) dest.toArray();
505 System.arraycopy(src.toArray(), 0, destArray, 0, srcSize);
506 dest.setAll(destArray);
507 }
508
509 /**
510 * Fills the provided list with obj. Fires only <b>one</b> change notification on the list.
511 * @param list the list to fill
512 * @param obj the object to fill the list with
513 * @see Collections#fill(java.util.List, java.lang.Object)
514 */
515 @SuppressWarnings("unchecked")
516 public static <T> void fill(ObservableList<? super T> list, T obj) {
517 T[] newContent = (T[]) new Object[list.size()];
518 Arrays.fill(newContent, obj);
519 list.setAll(newContent);
520 }
521
522 /**
523 * Replace all oldVal elements in the list with newVal element.
524 * Fires only <b>one</b> change notification on the list.
525 * @param list the list which will have it's elements replaced
526 * @param oldVal the element that is going to be replace
527 * @param newVal the replacement
528 * @return true if the list was modified
529 * @see Collections#replaceAll(java.util.List, java.lang.Object, java.lang.Object)
530 */
531 @SuppressWarnings("unchecked")
532 public static <T> boolean replaceAll(ObservableList<T> list, T oldVal, T newVal) {
533 T[] newContent = (T[]) list.toArray();
534 boolean modified = false;
535 for (int i = 0 ; i < newContent.length; ++i) {
536 if (newContent[i].equals(oldVal)) {
537 newContent[i] = newVal;
538 modified = true;
539 }
540 }
541 if (modified) {
542 list.setAll(newContent);
543 }
544 return modified;
620 @SuppressWarnings("unchecked")
621 public static void shuffle(ObservableList list, Random rnd) {
622 Object newContent[] = list.toArray();
623
624 for (int i = list.size(); i > 1; i--) {
625 swap(newContent, i - 1, rnd.nextInt(i));
626 }
627
628 list.setAll(newContent);
629 }
630
631 private static void swap(Object[] arr, int i, int j) {
632 Object tmp = arr[i];
633 arr[i] = arr[j];
634 arr[j] = tmp;
635 }
636
637 /**
638 * Sorts the provided observable list.
639 * Fires only <b>one</b> change notification on the list.
640 * @see Collections#sort(java.util.List)
641 */
642 @SuppressWarnings("unchecked")
643 public static <T extends Comparable<? super T>> void sort(ObservableList<T> list) {
644 if (list instanceof SortableList) {
645 ((SortableList<? extends T>)list).sort();
646 } else {
647 List<T> newContent = new ArrayList<T>(list);
648 Collections.sort(newContent);
649 list.setAll((Collection<T>)newContent);
650 }
651 }
652
653 /**
654 * Sorts the provided observable list using the c comparator.
655 * Fires only <b>one</b> change notification on the list.
656 * @param list the list to sort
657 * @param c comparator used for sorting. Null if natural ordering is required.
658 * @see Collections#sort(java.util.List, java.util.Comparator)
659 */
660 @SuppressWarnings("unchecked")
661 public static <T> void sort(ObservableList<T> list, Comparator<? super T> c) {
662 if (list instanceof SortableList) {
663 ((SortableList<? extends T>)list).sort(c);
664 } else {
665 List<T> newContent = new ArrayList<T>(list);
666 Collections.sort(newContent, c);
667 list.setAll((Collection<T>)newContent);
668 }
669 }
670
671 private static class EmptyObservableList<E> extends AbstractList<E> implements ObservableList<E> {
672
673 private static final ListIterator iterator = new ListIterator() {
674
675 @Override
|
72 * therefore suitable for methods that require ObservableList on input.
73 * <br><br>
74 * The utility methods are here mainly for performance reasons. All methods are optimized in a way that
75 * they yield only limited number of notifications. On the other hand, java.util.Collections methods
76 * might call "modification methods" on an ObservableList multiple times, resulting in a number of notifications.
77 *
78 * @since JavaFX 2.0
79 */
80 public class FXCollections {
81 /** Not to be instantiated. */
82 private FXCollections() { }
83
84 /**
85 * Constructs an ObservableList that is backed by the specified list.
86 * Mutation operations on the ObservableList instance will be reported
87 * to observers that have registered on that instance.<br>
88 * Note that mutation operations made directly to the underlying list are
89 * <em>not</em> reported to observers of any ObservableList that
90 * wraps it.
91 *
92 * @param <E> The type of List to be wrapped
93 * @param list a concrete List that backs this ObservableList
94 * @return a newly created ObservableList
95 */
96 public static <E> ObservableList<E> observableList(List<E> list) {
97 if (list == null) {
98 throw new NullPointerException();
99 }
100 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list) :
101 new ObservableSequentialListWrapper<E>(list);
102 }
103
104 /**
105 * Constructs an ObservableList that is backed by the specified list.
106 * Mutation operations on the ObservableList instance will be reported
107 * to observers that have registered on that instance.<br>
108 * Note that mutation operations made directly to the underlying list are
109 * <em>not</em> reported to observers of any ObservableList that
110 * wraps it.
111 * <br>
112 * This list also reports mutations of the elements in it by using <code>extractor</code>.
113 * Observable objects returned by extractor (applied to each list element) are listened for changes
114 * and transformed into "update" change of ListChangeListener.
115 *
116 * @param <E> The type of List to be wrapped
117 * @param list a concrete List that backs this ObservableList
118 * @param extractor element to Observable[] convertor
119 * @since JavaFX 2.1
120 * @return a newly created ObservableList
121 */
122 public static <E> ObservableList<E> observableList(List<E> list, Callback<E, Observable[]> extractor) {
123 if (list == null || extractor == null) {
124 throw new NullPointerException();
125 }
126 return list instanceof RandomAccess ? new ObservableListWrapper<E>(list, extractor) :
127 new ObservableSequentialListWrapper<E>(list, extractor);
128 }
129
130 /**
131 * Constructs an ObservableMap that is backed by the specified map.
132 * Mutation operations on the ObservableMap instance will be reported
133 * to observers that have registered on that instance.<br>
134 * Note that mutation operations made directly to the underlying map are <em>not</em>
135 * reported to observers of any ObservableMap that wraps it.
136 * @param <K> the type of the wrapped key
137 * @param <V> the type of the wrapped value
138 * @param map a Map that backs this ObservableMap
139 * @return a newly created ObservableMap
140 */
141 public static <K, V> ObservableMap<K, V> observableMap(Map<K, V> map) {
142 if (map == null) {
143 throw new NullPointerException();
144 }
145 return new ObservableMapWrapper<K, V>(map);
146 }
147
148 /**
149 * Constructs an ObservableSet that is backed by the specified set.
150 * Mutation operations on the ObservableSet instance will be reported
151 * to observers that have registered on that instance.<br>
152 * Note that mutation operations made directly to the underlying set are <em>not</em>
153 * reported to observers of any ObservableSet that wraps it.
154 * @param <E> The type of List to be wrapped
155 * @param set a Set that backs this ObservableSet
156 * @return a newly created ObservableSet
157 * @since JavaFX 2.1
158 */
159 public static <E> ObservableSet<E> observableSet(Set<E> set) {
160 if (set == null) {
161 throw new NullPointerException();
162 }
163 return new ObservableSetWrapper<E>(set);
164 }
165
166 /**
167 * Constructs an ObservableSet backed by a HashSet
168 * that contains all the specified elements.
169 * @param <E> The type of List to be wrapped
170 * @param elements elements that will be added into returned ObservableSet
171 * @return a newly created ObservableSet
172 * @since JavaFX 2.1
173 */
174 public static <E> ObservableSet<E> observableSet(E... elements) {
175 if (elements == null) {
176 throw new NullPointerException();
177 }
178 Set<E> set = new HashSet<E>(elements.length);
179 Collections.addAll(set, elements);
180 return new ObservableSetWrapper<E>(set);
181 }
182
183 /**
184 * Constructs a read-only interface to the specified ObservableMap. Only
185 * mutation operations made to the underlying ObservableMap will be reported
186 * to observers that have registered on the unmodifiable instance. This allows
187 * clients to track changes in a Map but disallows the ability to modify it.
188 * @param <K> the type of the wrapped key
189 * @param <V> the type of the wrapped value
190 * @param map an ObservableMap that is to be monitored by this interface
191 * @return a newly created UnmodifiableObservableMap
192 */
193 public static <K, V> ObservableMap<K, V> unmodifiableObservableMap(ObservableMap<K, V> map) {
194 if (map == null) {
195 throw new NullPointerException();
196 }
197 return new com.sun.javafx.collections.UnmodifiableObservableMap<K, V>(map);
198 }
199
200 /**
201 * Creates and returns a typesafe wrapper on top of provided observable map.
202 * @param <K> the type of the wrapped key
203 * @param <V> the type of the wrapped value
204 * @param map an Observable map to be wrapped
205 * @param keyType the type of key that {@code map} is permitted to hold
206 * @param valueType the type of value that {@code map} is permitted to hold
207 * @return a dynamically typesafe view of the specified map
208 * @see Collections#checkedMap(java.util.Map, java.lang.Class, java.lang.Class)
209 * @since JavaFX 8.0
210 */
211 public static <K, V> ObservableMap<K, V> checkedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) {
212 if (map == null || keyType == null || valueType == null) {
213 throw new NullPointerException();
214 }
215 return new CheckedObservableMap<K, V>(map, keyType, valueType);
216 }
217
218 /**
219 * Creates and returns a synchronized wrapper on top of provided observable map.
220 * @param <K> the type of the wrapped key
221 * @param <V> the type of the wrapped value
222 * @param map the map to be "wrapped" in a synchronized map.
223 * @return A synchronized version of the observable map
224 * @see Collections#synchronizedMap(java.util.Map)
225 * @since JavaFX 8.0
226 */
227 public static <K, V> ObservableMap<K, V> synchronizedObservableMap(ObservableMap<K, V> map) {
228 if (map == null) {
229 throw new NullPointerException();
230 }
231 return new SynchronizedObservableMap<K, V>(map);
232 }
233
234 private static ObservableMap EMPTY_OBSERVABLE_MAP = new EmptyObservableMap();
235
236 /**
237 * Creates and empty unmodifiable observable map.
238 * @param <K> the type of the wrapped key
239 * @param <V> the type of the wrapped value
240 * @return An empty unmodifiable observable map
241 * @see Collections#emptyMap()
242 * @since JavaFX 8.0
243 */
244 @SuppressWarnings("unchecked")
245 public static <K, V> ObservableMap<K, V> emptyObservableMap() {
246 return EMPTY_OBSERVABLE_MAP;
247 }
248
249 /**
250 * Creates a new empty observable integer array.
251 * @return a newly created ObservableIntegerArray
252 * @since JavaFX 8.0
253 */
254 public static ObservableIntegerArray observableIntegerArray() {
255 return new ObservableIntegerArrayImpl();
256 }
257
258 /**
259 * Creates a new observable integer array with {@code values} set to it.
292 * @since JavaFX 8.0
293 */
294 public static ObservableFloatArray observableFloatArray(float... values) {
295 return new ObservableFloatArrayImpl(values);
296 }
297
298 /**
299 * Creates a new observable float array with copy of elements in given
300 * {@code array}.
301 * @param array observable float array to copy
302 * @return a newly created ObservableFloatArray
303 * @since JavaFX 8.0
304 */
305 public static ObservableFloatArray observableFloatArray(ObservableFloatArray array) {
306 return new ObservableFloatArrayImpl(array);
307 }
308
309 /**
310 * Creates a new empty observable list that is backed by an arraylist.
311 * @see #observableList(java.util.List)
312 * @param <E> The type of List to be wrapped
313 * @return a newly created ObservableList
314 */
315 @SuppressWarnings("unchecked")
316 public static <E> ObservableList<E> observableArrayList() {
317 return observableList(new ArrayList());
318 }
319
320 /**
321 * Creates a new empty observable list backed by an arraylist.
322 *
323 * This list reports element updates.
324 * @param <E> The type of List to be wrapped
325 * @param extractor element to Observable[] convertor. Observable objects are listened for changes on the element.
326 * @see #observableList(java.util.List, javafx.util.Callback)
327 * @since JavaFX 2.1
328 * @return a newly created ObservableList
329 */
330 public static <E> ObservableList<E> observableArrayList(Callback<E, Observable[]> extractor) {
331 return observableList(new ArrayList(), extractor);
332 }
333
334 /**
335 * Creates a new observable array list with {@code items} added to it.
336 * @param <E> The type of List to be wrapped
337 * @param items the items that will be in the new observable ArrayList
338 * @return a newly created observableArrayList
339 * @see #observableArrayList()
340 */
341 public static <E> ObservableList<E> observableArrayList(E... items) {
342 ObservableList<E> list = observableArrayList();
343 list.addAll(items);
344 return list;
345 }
346
347 /**
348 * Creates a new observable array list and adds a content of collection {@code col}
349 * to it.
350 * @param <E> The type of List to be wrapped
351 * @param col a collection which content should be added to the observableArrayList
352 * @return a newly created observableArrayList
353 */
354 public static <E> ObservableList<E> observableArrayList(Collection<? extends E> col) {
355 ObservableList<E> list = observableArrayList();
356 list.addAll(col);
357 return list;
358 }
359
360 /**
361 * Creates a new empty observable map that is backed by a HashMap.
362 * @param <K> the type of the wrapped key
363 * @param <V> the type of the wrapped value
364 * @return a newly created observable HashMap
365 */
366 public static <K,V> ObservableMap<K,V> observableHashMap() {
367 return observableMap(new HashMap<K, V>());
368 }
369
370 /**
371 * Concatenates more observable lists into one. The resulting list
372 * would be backed by an arraylist.
373 * @param <E> The type of List to be wrapped
374 * @param lists lists to concatenate
375 * @return new observable array list concatenated from the arguments
376 */
377 public static <E> ObservableList<E> concat(ObservableList<E>... lists) {
378 if (lists.length == 0 ) {
379 return observableArrayList();
380 }
381 if (lists.length == 1) {
382 return observableArrayList(lists[0]);
383 }
384 ArrayList<E> backingList = new ArrayList<E>();
385 for (ObservableList<E> s : lists) {
386 backingList.addAll(s);
387 }
388
389 return observableList(backingList);
390 }
391
392 /**
393 * Creates and returns unmodifiable wrapper list on top of provided observable list.
394 * @param list an ObservableList that is to be wrapped
395 * @param <E> The type of List to be wrapped
396 * @return an ObserableList wrapper that is unmodifiable
397 * @see Collections#unmodifiableList(java.util.List)
398 */
399 public static<E> ObservableList<E> unmodifiableObservableList(ObservableList<E> list) {
400 if (list == null) {
401 throw new NullPointerException();
402 }
403 return new UnmodifiableObservableListImpl<E>(list);
404 }
405
406 /**
407 * Creates and returns a typesafe wrapper on top of provided observable list.
408 * @param <E> The type of List to be wrapped
409 * @param list an Observable list to be wrapped
410 * @param type the type of element that <tt>list</tt> is permitted to hold
411 * @return a dynamically typesafe view of the specified list
412 * @see Collections#checkedList(java.util.List, java.lang.Class)
413 */
414 public static<E> ObservableList<E> checkedObservableList(ObservableList<E> list, Class<E> type) {
415 if (list == null) {
416 throw new NullPointerException();
417 }
418 return new CheckedObservableList<E>(list, type);
419 }
420
421 /**
422 * Creates and returns a synchronized wrapper on top of provided observable list.
423 * @param <E> The type of List to be wrapped
424 * @param list the list to be "wrapped" in a synchronized list.
425 * @return A synchronized version of the observable list
426 * @see Collections#synchronizedList(java.util.List)
427 */
428 public static<E> ObservableList<E> synchronizedObservableList(ObservableList<E> list) {
429 if (list == null) {
430 throw new NullPointerException();
431 }
432 return new SynchronizedObservableList<E>(list);
433 }
434
435 private static ObservableList EMPTY_OBSERVABLE_LIST = new EmptyObservableList();
436
437
438 /**
439 * Creates and empty unmodifiable observable list.
440 * @param <E> The type of List to be wrapped
441 * @return An empty unmodifiable observable list
442 * @see Collections#emptyList()
443 */
444 @SuppressWarnings("unchecked")
445 public static<E> ObservableList<E> emptyObservableList() {
446 return EMPTY_OBSERVABLE_LIST;
447 }
448
449 /**
450 * Creates an unmodifiable observable list with single element.
451 * @param <E> The type of List to be wrapped
452 * @param e the only elements that will be contained in this singleton observable list
453 * @return a singleton observable list
454 * @see Collections#singletonList(java.lang.Object)
455 */
456 public static<E> ObservableList<E> singletonObservableList(E e) {
457 return new SingletonObservableList<E>(e);
458 }
459
460 /**
461 * Creates and returns unmodifiable wrapper on top of provided observable set.
462 * @param <E> The type of List to be wrapped
463 * @param set an ObservableSet that is to be wrapped
464 * @return an ObserableSet wrapper that is unmodifiable
465 * @see Collections#unmodifiableSet(java.util.Set)
466 * @since JavaFX 8.0
467 */
468 public static<E> ObservableSet<E> unmodifiableObservableSet(ObservableSet<E> set) {
469 if (set == null) {
470 throw new NullPointerException();
471 }
472 return new UnmodifiableObservableSet<E>(set);
473 }
474
475 /**
476 * Creates and returns a typesafe wrapper on top of provided observable set.
477 * @param <E> The type of List to be wrapped
478 * @param set an Observable set to be wrapped
479 * @param type the type of element that <tt>set</tt> is permitted to hold
480 * @return a dynamically typesafe view of the specified set
481 * @see Collections#checkedSet(java.util.Set, java.lang.Class)
482 * @since JavaFX 8.0
483 */
484 public static<E> ObservableSet<E> checkedObservableSet(ObservableSet<E> set, Class<E> type) {
485 if (set == null) {
486 throw new NullPointerException();
487 }
488 return new CheckedObservableSet<E>(set, type);
489 }
490
491 /**
492 * Creates and returns a synchronized wrapper on top of provided observable set.
493 * @param <E> The type of List to be wrapped
494 * @param set the set to be "wrapped" in a synchronized set.
495 * @return A synchronized version of the observable set
496 * @see Collections#synchronizedSet(java.util.Set)
497 * @since JavaFX 8.0
498 */
499 public static<E> ObservableSet<E> synchronizedObservableSet(ObservableSet<E> set) {
500 if (set == null) {
501 throw new NullPointerException();
502 }
503 return new SynchronizedObservableSet<E>(set);
504 }
505
506 private static ObservableSet EMPTY_OBSERVABLE_SET = new EmptyObservableSet();
507
508 /**
509 * Creates and empty unmodifiable observable set.
510 * @param <E> The type of List to be wrapped
511 * @return An empty unmodifiable observable set
512 * @see Collections#emptySet()
513 * @since JavaFX 8.0
514 */
515 @SuppressWarnings("unchecked")
516 public static<E> ObservableSet<E> emptyObservableSet() {
517 return EMPTY_OBSERVABLE_SET;
518 }
519
520 /**
521 * Copies elements from src to dest. Fires only <b>one</b> change notification on dest.
522 * @param <T> The type of List to be wrapped
523 * @param dest the destination observable list
524 * @param src the source list
525 * @see Collections#copy(java.util.List, java.util.List)
526 */
527 @SuppressWarnings("unchecked")
528 public static <T> void copy(ObservableList<? super T> dest, List<? extends T> src) {
529 final int srcSize = src.size();
530 if (srcSize > dest.size()) {
531 throw new IndexOutOfBoundsException("Source does not fit in dest");
532 }
533 T[] destArray = (T[]) dest.toArray();
534 System.arraycopy(src.toArray(), 0, destArray, 0, srcSize);
535 dest.setAll(destArray);
536 }
537
538 /**
539 * Fills the provided list with obj. Fires only <b>one</b> change notification on the list.
540 * @param <T> The type of List to be wrapped
541 * @param list the list to fill
542 * @param obj the object to fill the list with
543 * @see Collections#fill(java.util.List, java.lang.Object)
544 */
545 @SuppressWarnings("unchecked")
546 public static <T> void fill(ObservableList<? super T> list, T obj) {
547 T[] newContent = (T[]) new Object[list.size()];
548 Arrays.fill(newContent, obj);
549 list.setAll(newContent);
550 }
551
552 /**
553 * Replace all oldVal elements in the list with newVal element.
554 * Fires only <b>one</b> change notification on the list.
555 * @param <T> The type of List to be wrapped
556 * @param list the list which will have it's elements replaced
557 * @param oldVal the element that is going to be replace
558 * @param newVal the replacement
559 * @return true if the list was modified
560 * @see Collections#replaceAll(java.util.List, java.lang.Object, java.lang.Object)
561 */
562 @SuppressWarnings("unchecked")
563 public static <T> boolean replaceAll(ObservableList<T> list, T oldVal, T newVal) {
564 T[] newContent = (T[]) list.toArray();
565 boolean modified = false;
566 for (int i = 0 ; i < newContent.length; ++i) {
567 if (newContent[i].equals(oldVal)) {
568 newContent[i] = newVal;
569 modified = true;
570 }
571 }
572 if (modified) {
573 list.setAll(newContent);
574 }
575 return modified;
651 @SuppressWarnings("unchecked")
652 public static void shuffle(ObservableList list, Random rnd) {
653 Object newContent[] = list.toArray();
654
655 for (int i = list.size(); i > 1; i--) {
656 swap(newContent, i - 1, rnd.nextInt(i));
657 }
658
659 list.setAll(newContent);
660 }
661
662 private static void swap(Object[] arr, int i, int j) {
663 Object tmp = arr[i];
664 arr[i] = arr[j];
665 arr[j] = tmp;
666 }
667
668 /**
669 * Sorts the provided observable list.
670 * Fires only <b>one</b> change notification on the list.
671 * @param <T> The type of List to be wrapped
672 * @param list the list to be sorted
673 * @see Collections#sort(java.util.List)
674 */
675 @SuppressWarnings("unchecked")
676 public static <T extends Comparable<? super T>> void sort(ObservableList<T> list) {
677 if (list instanceof SortableList) {
678 ((SortableList<? extends T>)list).sort();
679 } else {
680 List<T> newContent = new ArrayList<T>(list);
681 Collections.sort(newContent);
682 list.setAll((Collection<T>)newContent);
683 }
684 }
685
686 /**
687 * Sorts the provided observable list using the c comparator.
688 * Fires only <b>one</b> change notification on the list.
689 * @param <T> The type of List to be wrapped
690 * @param list the list to sort
691 * @param c comparator used for sorting. Null if natural ordering is required.
692 * @see Collections#sort(java.util.List, java.util.Comparator)
693 */
694 @SuppressWarnings("unchecked")
695 public static <T> void sort(ObservableList<T> list, Comparator<? super T> c) {
696 if (list instanceof SortableList) {
697 ((SortableList<? extends T>)list).sort(c);
698 } else {
699 List<T> newContent = new ArrayList<T>(list);
700 Collections.sort(newContent, c);
701 list.setAll((Collection<T>)newContent);
702 }
703 }
704
705 private static class EmptyObservableList<E> extends AbstractList<E> implements ObservableList<E> {
706
707 private static final ListIterator iterator = new ListIterator() {
708
709 @Override
|