javafx.collections.FXCollections Maven / Gradle / Ivy
/*
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.collections;
import com.sun.javafx.collections.ListListenerHelper;
import com.sun.javafx.collections.MapListenerHelper;
import com.sun.javafx.collections.SetListenerHelper;
import java.lang.reflect.Array;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import javafx.beans.InvalidationListener;
import com.sun.javafx.collections.ObservableListWrapper;
import com.sun.javafx.collections.ObservableMapWrapper;
import com.sun.javafx.collections.ObservableSetWrapper;
import com.sun.javafx.collections.MapAdapterChange;
import com.sun.javafx.collections.ObservableFloatArrayImpl;
import com.sun.javafx.collections.ObservableIntegerArrayImpl;
import com.sun.javafx.collections.ObservableSequentialListWrapper;
import com.sun.javafx.collections.SetAdapterChange;
import com.sun.javafx.collections.SortableList;
import com.sun.javafx.collections.SourceAdapterChange;
import java.util.RandomAccess;
import javafx.beans.Observable;
import javafx.collections.ListChangeListener.Change;
import javafx.util.Callback;
/**
* Utility class that consists of static methods that are 1:1 copies of java.util.Collections methods.
*
* The wrapper methods (like synchronizedObservableList or emptyObservableList) has exactly the same
* functionality as the methods in Collections, with exception that they return ObservableList and are
* therefore suitable for methods that require ObservableList on input.
*
* The utility methods are here mainly for performance reasons. All methods are optimized in a way that
* they yield only limited number of notifications. On the other hand, java.util.Collections methods
* might call "modification methods" on an ObservableList multiple times, resulting in a number of notifications.
*
* @since JavaFX 2.0
*/
public class FXCollections {
/** Not to be instantiated. */
private FXCollections() { }
/**
* Constructs an ObservableList that is backed by the specified list.
* Mutation operations on the ObservableList instance will be reported
* to observers that have registered on that instance.
* Note that mutation operations made directly to the underlying list are
* not reported to observers of any ObservableList that
* wraps it.
*
* @param The type of List to be wrapped
* @param list a concrete List that backs this ObservableList
* @return a newly created ObservableList
*/
public static ObservableList observableList(List list) {
if (list == null) {
throw new NullPointerException();
}
return list instanceof RandomAccess ? new ObservableListWrapper(list) :
new ObservableSequentialListWrapper(list);
}
/**
* Constructs an {@code ObservableList} that is backed by the specified list and listens to changes in observables of its items.
* Mutation operations made directly to the underlying list are
* not reported to observers of any {@code ObservableList} that
* wraps it.
*
* The {@code extractor} returns observables (usually properties) of the objects in the created list. These observables are
* listened for changes, and the user is notified of these through an
* {@linkplain ListChangeListener.Change#wasUpdated() update} change of an attached {@code ListChangeListener}. These changes
* are unrelated to the changes made to the observable list itself using methods such as {@code add} and {@code remove}.
*
* For example, a list of {@code Shape}s can listen to changes in the shapes' {@code fill} property.
*
* @param The type of {@code List} to be wrapped
* @param list a concrete {@code List} that backs this {@code ObservableList}
* @param extractor element to {@code Observable[]} converter
* @return a newly created {@code ObservableList}
* @see #observableArrayList(javafx.util.Callback)
* @since JavaFX 2.1
*/
public static ObservableList observableList(List list, Callback extractor) {
if (list == null || extractor == null) {
throw new NullPointerException();
}
return list instanceof RandomAccess ? new ObservableListWrapper(list, extractor) :
new ObservableSequentialListWrapper(list, extractor);
}
/**
* Constructs an ObservableMap that is backed by the specified map.
* Mutation operations on the ObservableMap instance will be reported
* to observers that have registered on that instance.
* Note that mutation operations made directly to the underlying map are not
* reported to observers of any ObservableMap that wraps it.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @param map a Map that backs this ObservableMap
* @return a newly created ObservableMap
*/
public static ObservableMap observableMap(Map map) {
if (map == null) {
throw new NullPointerException();
}
return new ObservableMapWrapper(map);
}
/**
* Constructs an ObservableSet that is backed by the specified set.
* Mutation operations on the ObservableSet instance will be reported
* to observers that have registered on that instance.
* Note that mutation operations made directly to the underlying set are not
* reported to observers of any ObservableSet that wraps it.
* @param The type of List to be wrapped
* @param set a Set that backs this ObservableSet
* @return a newly created ObservableSet
* @since JavaFX 2.1
*/
public static ObservableSet observableSet(Set set) {
if (set == null) {
throw new NullPointerException();
}
return new ObservableSetWrapper(set);
}
/**
* Constructs an ObservableSet backed by a HashSet
* that contains all the specified elements.
* @param The type of List to be wrapped
* @param elements elements that will be added into returned ObservableSet
* @return a newly created ObservableSet
* @since JavaFX 2.1
*/
public static ObservableSet observableSet(E... elements) {
if (elements == null) {
throw new NullPointerException();
}
Set set = new HashSet(elements.length);
Collections.addAll(set, elements);
return new ObservableSetWrapper(set);
}
/**
* Constructs a read-only interface to the specified ObservableMap. Only
* mutation operations made to the underlying ObservableMap will be reported
* to observers that have registered on the unmodifiable instance. This allows
* clients to track changes in a Map but disallows the ability to modify it.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @param map an ObservableMap that is to be monitored by this interface
* @return a newly created UnmodifiableObservableMap
*/
public static ObservableMap unmodifiableObservableMap(ObservableMap map) {
if (map == null) {
throw new NullPointerException();
}
return new com.sun.javafx.collections.UnmodifiableObservableMap(map);
}
/**
* Creates and returns a typesafe wrapper on top of provided observable map.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @param map an Observable map to be wrapped
* @param keyType the type of key that {@code map} is permitted to hold
* @param valueType the type of value that {@code map} is permitted to hold
* @return a dynamically typesafe view of the specified map
* @see Collections#checkedMap(java.util.Map, java.lang.Class, java.lang.Class)
* @since JavaFX 8.0
*/
public static ObservableMap checkedObservableMap(ObservableMap map, Class keyType, Class valueType) {
if (map == null || keyType == null || valueType == null) {
throw new NullPointerException();
}
return new CheckedObservableMap(map, keyType, valueType);
}
/**
* Creates and returns a synchronized wrapper on top of provided observable map.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @param map the map to be "wrapped" in a synchronized map.
* @return A synchronized version of the observable map
* @see Collections#synchronizedMap(java.util.Map)
* @since JavaFX 8.0
*/
public static ObservableMap synchronizedObservableMap(ObservableMap map) {
if (map == null) {
throw new NullPointerException();
}
return new SynchronizedObservableMap(map);
}
private static ObservableMap EMPTY_OBSERVABLE_MAP = new EmptyObservableMap();
/**
* Creates an empty unmodifiable observable map.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @return An empty unmodifiable observable map
* @see Collections#emptyMap()
* @since JavaFX 8.0
*/
@SuppressWarnings("unchecked")
public static ObservableMap emptyObservableMap() {
return EMPTY_OBSERVABLE_MAP;
}
/**
* Creates a new empty observable integer array.
* @return a newly created ObservableIntegerArray
* @since JavaFX 8.0
*/
public static ObservableIntegerArray observableIntegerArray() {
return new ObservableIntegerArrayImpl();
}
/**
* Creates a new observable integer array with {@code values} set to it.
* @param values the values that will be in the new observable integer array
* @return a newly created ObservableIntegerArray
* @since JavaFX 8.0
*/
public static ObservableIntegerArray observableIntegerArray(int... values) {
return new ObservableIntegerArrayImpl(values);
}
/**
* Creates a new observable integer array with copy of elements in given
* {@code array}.
* @param array observable integer array to copy
* @return a newly created ObservableIntegerArray
* @since JavaFX 8.0
*/
public static ObservableIntegerArray observableIntegerArray(ObservableIntegerArray array) {
return new ObservableIntegerArrayImpl(array);
}
/**
* Creates a new empty observable float array.
* @return a newly created ObservableFloatArray
* @since JavaFX 8.0
*/
public static ObservableFloatArray observableFloatArray() {
return new ObservableFloatArrayImpl();
}
/**
* Creates a new observable float array with {@code values} set to it.
* @param values the values that will be in the new observable float array
* @return a newly created ObservableFloatArray
* @since JavaFX 8.0
*/
public static ObservableFloatArray observableFloatArray(float... values) {
return new ObservableFloatArrayImpl(values);
}
/**
* Creates a new observable float array with copy of elements in given
* {@code array}.
* @param array observable float array to copy
* @return a newly created ObservableFloatArray
* @since JavaFX 8.0
*/
public static ObservableFloatArray observableFloatArray(ObservableFloatArray array) {
return new ObservableFloatArrayImpl(array);
}
/**
* Creates a new empty observable list that is backed by an array list.
* @see #observableList(java.util.List)
* @param The type of List to be wrapped
* @return a newly created ObservableList
*/
@SuppressWarnings("unchecked")
public static ObservableList observableArrayList() {
return observableList(new ArrayList());
}
/**
* Creates a new empty {@code ObservableList} that is backed by an array list and listens to changes in observables of its items.
*
* The {@code extractor} returns observables (usually properties) of the objects in the created list. These observables are
* listened for changes and the user is notified of these through an
* {@linkplain ListChangeListener.Change#wasUpdated() update} change of an attached {@code ListChangeListener}. These changes
* are unrelated to the changes made to the observable list itself using methods such as {@code add} and {@code remove}.
*
* For example, a list of {@code Shape}s can listen to changes in the shapes' {@code fill} property.
*
* @param The type of {@code List} to be wrapped
* @param extractor element to {@code Observable[]} converter
* @return a newly created {@code ObservableList}
* @see #observableList(java.util.List, javafx.util.Callback)
* @since JavaFX 2.1
*/
public static ObservableList observableArrayList(Callback extractor) {
return observableList(new ArrayList(), extractor);
}
/**
* Creates a new observable array list with {@code items} added to it.
* @param The type of List to be wrapped
* @param items the items that will be in the new observable ArrayList
* @return a newly created observableArrayList
* @see #observableArrayList()
*/
public static ObservableList observableArrayList(E... items) {
ObservableList list = observableArrayList();
list.addAll(items);
return list;
}
/**
* Creates a new observable array list and adds a content of collection {@code col}
* to it.
* @param The type of List to be wrapped
* @param col a collection which content should be added to the observableArrayList
* @return a newly created observableArrayList
*/
public static ObservableList observableArrayList(Collection extends E> col) {
ObservableList list = observableArrayList();
list.addAll(col);
return list;
}
/**
* Creates a new empty observable map that is backed by a HashMap.
* @param the type of the wrapped key
* @param the type of the wrapped value
* @return a newly created observable HashMap
*/
public static ObservableMap observableHashMap() {
return observableMap(new HashMap());
}
/**
* Concatenates more observable lists into one. The resulting list
* would be backed by an array list.
* @param The type of List to be wrapped
* @param lists lists to concatenate
* @return new observable array list concatenated from the arguments
*/
public static ObservableList concat(ObservableList... lists) {
if (lists.length == 0 ) {
return observableArrayList();
}
if (lists.length == 1) {
return observableArrayList(lists[0]);
}
ArrayList backingList = new ArrayList();
for (ObservableList s : lists) {
backingList.addAll(s);
}
return observableList(backingList);
}
/**
* Creates and returns unmodifiable wrapper list on top of provided observable list.
* @param list an ObservableList that is to be wrapped
* @param The type of List to be wrapped
* @return an ObserableList wrapper that is unmodifiable
* @see Collections#unmodifiableList(java.util.List)
*/
public static ObservableList unmodifiableObservableList(ObservableList list) {
if (list == null) {
throw new NullPointerException();
}
return new UnmodifiableObservableListImpl(list);
}
/**
* Creates and returns a typesafe wrapper on top of provided observable list.
* @param The type of List to be wrapped
* @param list an Observable list to be wrapped
* @param type the type of element that {@code list} is permitted to hold
* @return a dynamically typesafe view of the specified list
* @see Collections#checkedList(java.util.List, java.lang.Class)
*/
public static ObservableList checkedObservableList(ObservableList list, Class type) {
if (list == null) {
throw new NullPointerException();
}
return new CheckedObservableList(list, type);
}
/**
* Creates and returns a synchronized wrapper on top of provided observable list.
* @param The type of List to be wrapped
* @param list the list to be "wrapped" in a synchronized list.
* @return A synchronized version of the observable list
* @see Collections#synchronizedList(java.util.List)
*/
public static ObservableList synchronizedObservableList(ObservableList list) {
if (list == null) {
throw new NullPointerException();
}
return new SynchronizedObservableList(list);
}
private static ObservableList EMPTY_OBSERVABLE_LIST = new EmptyObservableList();
/**
* Creates an empty unmodifiable observable list.
* @param The type of List to be wrapped
* @return An empty unmodifiable observable list
* @see Collections#emptyList()
*/
@SuppressWarnings("unchecked")
public static ObservableList emptyObservableList() {
return EMPTY_OBSERVABLE_LIST;
}
/**
* Creates an unmodifiable observable list with single element.
* @param The type of List to be wrapped
* @param e the only elements that will be contained in this singleton observable list
* @return a singleton observable list
* @see Collections#singletonList(java.lang.Object)
*/
public static ObservableList singletonObservableList(E e) {
return new SingletonObservableList(e);
}
/**
* Creates and returns unmodifiable wrapper on top of provided observable set.
* @param The type of List to be wrapped
* @param set an ObservableSet that is to be wrapped
* @return an ObserableSet wrapper that is unmodifiable
* @see Collections#unmodifiableSet(java.util.Set)
* @since JavaFX 8.0
*/
public static ObservableSet unmodifiableObservableSet(ObservableSet set) {
if (set == null) {
throw new NullPointerException();
}
return new UnmodifiableObservableSet(set);
}
/**
* Creates and returns a typesafe wrapper on top of provided observable set.
* @param The type of List to be wrapped
* @param set an Observable set to be wrapped
* @param type the type of element that {@code set} is permitted to hold
* @return a dynamically typesafe view of the specified set
* @see Collections#checkedSet(java.util.Set, java.lang.Class)
* @since JavaFX 8.0
*/
public static ObservableSet checkedObservableSet(ObservableSet set, Class type) {
if (set == null) {
throw new NullPointerException();
}
return new CheckedObservableSet(set, type);
}
/**
* Creates and returns a synchronized wrapper on top of provided observable set.
* @param The type of List to be wrapped
* @param set the set to be "wrapped" in a synchronized set.
* @return A synchronized version of the observable set
* @see Collections#synchronizedSet(java.util.Set)
* @since JavaFX 8.0
*/
public static ObservableSet synchronizedObservableSet(ObservableSet set) {
if (set == null) {
throw new NullPointerException();
}
return new SynchronizedObservableSet(set);
}
private static ObservableSet EMPTY_OBSERVABLE_SET = new EmptyObservableSet();
/**
* Creates an empty unmodifiable observable set.
* @param The type of List to be wrapped
* @return An empty unmodifiable observable set
* @see Collections#emptySet()
* @since JavaFX 8.0
*/
@SuppressWarnings("unchecked")
public static ObservableSet emptyObservableSet() {
return EMPTY_OBSERVABLE_SET;
}
/**
* Copies elements from src to dest. Fires only one change notification on dest.
* @param The type of List to be wrapped
* @param dest the destination observable list
* @param src the source list
* @see Collections#copy(java.util.List, java.util.List)
*/
@SuppressWarnings("unchecked")
public static void copy(ObservableList super T> dest, List extends T> src) {
final int srcSize = src.size();
if (srcSize > dest.size()) {
throw new IndexOutOfBoundsException("Source does not fit in dest");
}
T[] destArray = (T[]) dest.toArray();
System.arraycopy(src.toArray(), 0, destArray, 0, srcSize);
dest.setAll(destArray);
}
/**
* Fills the provided list with obj. Fires only one change notification on the list.
* @param The type of List to be wrapped
* @param list the list to fill
* @param obj the object to fill the list with
* @see Collections#fill(java.util.List, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public static void fill(ObservableList super T> list, T obj) {
T[] newContent = (T[]) new Object[list.size()];
Arrays.fill(newContent, obj);
list.setAll(newContent);
}
/**
* Replace all oldVal elements in the list with newVal element.
* Fires only one change notification on the list.
* @param The type of List to be wrapped
* @param list the list which will have it's elements replaced
* @param oldVal the element that is going to be replace
* @param newVal the replacement
* @return true if the list was modified
* @see Collections#replaceAll(java.util.List, java.lang.Object, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public static boolean replaceAll(ObservableList list, T oldVal, T newVal) {
T[] newContent = (T[]) list.toArray();
boolean modified = false;
for (int i = 0 ; i < newContent.length; ++i) {
if (newContent[i].equals(oldVal)) {
newContent[i] = newVal;
modified = true;
}
}
if (modified) {
list.setAll(newContent);
}
return modified;
}
/**
* Reverses the order in the list.
* Fires only one change notification on the list.
* @param list the list to be reversed
* @see Collections#reverse(java.util.List)
*/
@SuppressWarnings("unchecked")
public static void reverse(ObservableList list) {
Object[] newContent = list.toArray();
for (int i = 0; i < newContent.length / 2; ++i) {
Object tmp = newContent[i];
newContent[i] = newContent[newContent.length - i - 1];
newContent[newContent.length -i - 1] = tmp;
}
list.setAll(newContent);
}
/**
* Rotates the list by distance.
* Fires only one change notification on the list.
* @param list the list to be rotated
* @param distance the distance of rotation
* @see Collections#rotate(java.util.List, int)
*/
@SuppressWarnings("unchecked")
public static void rotate(ObservableList list, int distance) {
Object[] newContent = list.toArray();
int size = list.size();
distance = distance % size;
if (distance < 0)
distance += size;
if (distance == 0)
return;
for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
Object displaced = newContent[cycleStart];
Object tmp;
int i = cycleStart;
do {
i += distance;
if (i >= size)
i -= size;
tmp = newContent[i];
newContent[i] = displaced;
displaced = tmp;
nMoved ++;
} while(i != cycleStart);
}
list.setAll(newContent);
}
/**
* Shuffles all elements in the observable list.
* Fires only one change notification on the list.
* @param list the list to shuffle
* @see Collections#shuffle(java.util.List)
*/
public static void shuffle(ObservableList> list) {
if (r == null) {
r = new Random();
}
shuffle(list, r);
}
private static Random r;
/**
* Shuffles all elements in the observable list.
* Fires only one change notification on the list.
* @param list the list to be shuffled
* @param rnd the random generator used for shuffling
* @see Collections#shuffle(java.util.List, java.util.Random)
*/
@SuppressWarnings("unchecked")
public static void shuffle(ObservableList list, Random rnd) {
Object newContent[] = list.toArray();
for (int i = list.size(); i > 1; i--) {
swap(newContent, i - 1, rnd.nextInt(i));
}
list.setAll(newContent);
}
private static void swap(Object[] arr, int i, int j) {
Object tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
/**
* Sorts the provided observable list.
* Fires only one change notification on the list.
* @param The type of List to be wrapped
* @param list the list to be sorted
* @see Collections#sort(java.util.List)
*/
@SuppressWarnings("unchecked")
public static > void sort(ObservableList list) {
if (list instanceof SortableList) {
((SortableList extends T>)list).sort();
} else {
List newContent = new ArrayList(list);
Collections.sort(newContent);
list.setAll((Collection)newContent);
}
}
/**
* Sorts the provided observable list using the c comparator.
* Fires only one change notification on the list.
* @param The type of List to be wrapped
* @param list the list to sort
* @param c comparator used for sorting. Null if natural ordering is required.
* @see Collections#sort(java.util.List, java.util.Comparator)
*/
@SuppressWarnings("unchecked")
public static void sort(ObservableList list, Comparator super T> c) {
if (list instanceof SortableList) {
((SortableList extends T>)list).sort(c);
} else {
List newContent = new ArrayList(list);
Collections.sort(newContent, c);
list.setAll((Collection)newContent);
}
}
private static class EmptyObservableList extends AbstractList implements ObservableList {
private static final ListIterator iterator = new ListIterator() {
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasPrevious() {
return false;
}
@Override
public Object previous() {
throw new NoSuchElementException();
}
@Override
public int nextIndex() {
return 0;
}
@Override
public int previousIndex() {
return -1;
}
@Override
public void set(Object e) {
throw new UnsupportedOperationException();
}
@Override
public void add(Object e) {
throw new UnsupportedOperationException();
}
};
public EmptyObservableList() {
}
@Override
public final void addListener(InvalidationListener listener) {
}
@Override
public final void removeListener(InvalidationListener listener) {
}
@Override
public void addListener(ListChangeListener super E> o) {
}
@Override
public void removeListener(ListChangeListener super E> o) {
}
@Override
public int size() {
return 0;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
@SuppressWarnings("unchecked")
public Iterator iterator() {
return iterator;
}
@Override
public boolean containsAll(Collection> c) {
return c.isEmpty();
}
@Override
public E get(int index) {
throw new IndexOutOfBoundsException();
}
@Override
public int indexOf(Object o) {
return -1;
}
@Override
public int lastIndexOf(Object o) {
return -1;
}
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator() {
return iterator;
}
@Override
@SuppressWarnings("unchecked")
public ListIterator listIterator(int index) {
if (index != 0) {
throw new IndexOutOfBoundsException();
}
return iterator;
}
@Override
public List subList(int fromIndex, int toIndex) {
if (fromIndex != 0 || toIndex != 0) {
throw new IndexOutOfBoundsException();
}
return this;
}
@Override
public boolean addAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(Collection extends E> col) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public void remove(int from, int to) {
throw new UnsupportedOperationException();
}
}
private static class SingletonObservableList extends AbstractList implements ObservableList {
private final E element;
public SingletonObservableList(E element) {
if (element == null) {
throw new NullPointerException();
}
this.element = element;
}
@Override
public boolean addAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(Collection extends E> col) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(E... elements) {
throw new UnsupportedOperationException();
}
@Override
public void remove(int from, int to) {
throw new UnsupportedOperationException();
}
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
}
@Override
public void addListener(ListChangeListener super E> o) {
}
@Override
public void removeListener(ListChangeListener super E> o) {
}
@Override
public int size() {
return 1;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return element.equals(o);
}
@Override
public E get(int index) {
if (index != 0) {
throw new IndexOutOfBoundsException();
}
return element;
}
}
private static class UnmodifiableObservableListImpl extends ObservableListBase implements ObservableList {
private final ObservableList backingList;
private final ListChangeListener listener;
public UnmodifiableObservableListImpl(ObservableList backingList) {
this.backingList = backingList;
listener = c -> {
fireChange(new SourceAdapterChange(UnmodifiableObservableListImpl.this, c));
};
this.backingList.addListener(new WeakListChangeListener(listener));
}
@Override
public T get(int index) {
return backingList.get(index);
}
@Override
public int size() {
return backingList.size();
}
@Override
public boolean addAll(T... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(T... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean setAll(Collection extends T> col) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(T... elements) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(T... elements) {
throw new UnsupportedOperationException();
}
@Override
public void remove(int from, int to) {
throw new UnsupportedOperationException();
}
}
private static class SynchronizedList implements List {
final Object mutex;
private final List backingList;
SynchronizedList(List list, Object mutex) {
this.backingList = list;
this.mutex = mutex;
}
SynchronizedList(List list) {
this.backingList = list;
this.mutex = this;
}
@Override
public int size() {
synchronized(mutex) {
return backingList.size();
}
}
@Override
public boolean isEmpty() {
synchronized(mutex) {
return backingList.isEmpty();
}
}
@Override
public boolean contains(Object o) {
synchronized(mutex) {
return backingList.contains(o);
}
}
@Override
public Iterator iterator() {
return backingList.iterator();
}
@Override
public Object[] toArray() {
synchronized(mutex) {
return backingList.toArray();
}
}
@Override
public T[] toArray(T[] a) {
synchronized(mutex) {
return backingList.toArray(a);
}
}
@Override
public boolean add(T e) {
synchronized(mutex) {
return backingList.add(e);
}
}
@Override
public boolean remove(Object o) {
synchronized(mutex) {
return backingList.remove(o);
}
}
@Override
public boolean containsAll(Collection> c) {
synchronized(mutex) {
return backingList.containsAll(c);
}
}
@Override
public boolean addAll(Collection extends T> c) {
synchronized(mutex) {
return backingList.addAll(c);
}
}
@Override
public boolean addAll(int index, Collection extends T> c) {
synchronized(mutex) {
return backingList.addAll(index, c);
}
}
@Override
public boolean removeAll(Collection> c) {
synchronized(mutex) {
return backingList.removeAll(c);
}
}
@Override
public boolean retainAll(Collection> c) {
synchronized(mutex) {
return backingList.retainAll(c);
}
}
@Override
public void clear() {
synchronized(mutex) {
backingList.clear();
}
}
@Override
public T get(int index) {
synchronized(mutex) {
return backingList.get(index);
}
}
@Override
public T set(int index, T element) {
synchronized(mutex) {
return backingList.set(index, element);
}
}
@Override
public void add(int index, T element) {
synchronized(mutex) {
backingList.add(index, element);
}
}
@Override
public T remove(int index) {
synchronized(mutex) {
return backingList.remove(index);
}
}
@Override
public int indexOf(Object o) {
synchronized(mutex) {
return backingList.indexOf(o);
}
}
@Override
public int lastIndexOf(Object o) {
synchronized(mutex) {
return backingList.lastIndexOf(o);
}
}
@Override
public ListIterator listIterator() {
return backingList.listIterator();
}
@Override
public ListIterator listIterator(int index) {
synchronized(mutex) {
return backingList.listIterator(index);
}
}
@Override
public List subList(int fromIndex, int toIndex) {
synchronized(mutex) {
return new SynchronizedList(backingList.subList(fromIndex, toIndex),
mutex);
}
}
@Override
public String toString() {
synchronized(mutex) {
return backingList.toString();
}
}
@Override
public int hashCode() {
synchronized(mutex) {
return backingList.hashCode();
}
}
@Override
public boolean equals(Object o) {
synchronized(mutex) {
return backingList.equals(o);
}
}
}
private static class SynchronizedObservableList extends SynchronizedList implements ObservableList {
private ListListenerHelper helper;
private final ObservableList backingList;
private final ListChangeListener listener;
SynchronizedObservableList(ObservableList seq) {
super(seq);
this.backingList = seq;
listener = c -> {
ListListenerHelper.fireValueChangedEvent(helper, new SourceAdapterChange(SynchronizedObservableList.this, c));
};
backingList.addListener(new WeakListChangeListener(listener));
}
@Override
public boolean addAll(T... elements) {
synchronized(mutex) {
return backingList.addAll(elements);
}
}
@Override
public boolean setAll(T... elements) {
synchronized(mutex) {
return backingList.setAll(elements);
}
}
@Override
public boolean removeAll(T... elements) {
synchronized(mutex) {
return backingList.removeAll(elements);
}
}
@Override
public boolean retainAll(T... elements) {
synchronized(mutex) {
return backingList.retainAll(elements);
}
}
@Override
public void remove(int from, int to) {
synchronized(mutex) {
backingList.remove(from, to);
}
}
@Override
public boolean setAll(Collection extends T> col) {
synchronized(mutex) {
return backingList.setAll(col);
}
}
@Override
public final void addListener(InvalidationListener listener) {
synchronized (mutex) {
helper = ListListenerHelper.addListener(helper, listener);
}
}
@Override
public final void removeListener(InvalidationListener listener) {
synchronized (mutex) {
helper = ListListenerHelper.removeListener(helper, listener);
}
}
@Override
public void addListener(ListChangeListener super T> listener) {
synchronized (mutex) {
helper = ListListenerHelper.addListener(helper, listener);
}
}
@Override
public void removeListener(ListChangeListener super T> listener) {
synchronized (mutex) {
helper = ListListenerHelper.removeListener(helper, listener);
}
}
}
private static class CheckedObservableList extends ObservableListBase implements ObservableList {
private final ObservableList list;
private final Class type;
private final ListChangeListener listener;
CheckedObservableList(ObservableList list, Class type) {
if (list == null || type == null) {
throw new NullPointerException();
}
this.list = list;
this.type = type;
listener = c -> {
fireChange(new SourceAdapterChange(CheckedObservableList.this, c));
};
list.addListener(new WeakListChangeListener(listener));
}
void typeCheck(Object o) {
if (o != null && !type.isInstance(o)) {
throw new ClassCastException("Attempt to insert "
+ o.getClass() + " element into collection with element type "
+ type);
}
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public String toString() {
return list.toString();
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection> coll) {
return list.containsAll(coll);
}
@Override
public boolean removeAll(Collection> coll) {
return list.removeAll(coll);
}
@Override
public boolean retainAll(Collection> coll) {
return list.retainAll(coll);
}
@Override
public boolean removeAll(T... elements) {
return list.removeAll(elements);
}
@Override
public boolean retainAll(T... elements) {
return list.retainAll(elements);
}
@Override
public void remove(int from, int to) {
list.remove(from, to);
}
@Override
public void clear() {
list.clear();
}
@Override
public boolean equals(Object o) {
return o == this || list.equals(o);
}
@Override
public int hashCode() {
return list.hashCode();
}
@Override
public T get(int index) {
return list.get(index);
}
@Override
public T remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public T set(int index, T element) {
typeCheck(element);
return list.set(index, element);
}
@Override
public void add(int index, T element) {
typeCheck(element);
list.add(index, element);
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(int index, Collection extends T> c) {
T[] a = null;
try {
a = c.toArray((T[]) Array.newInstance(type, 0));
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
return this.list.addAll(index, Arrays.asList(a));
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection extends T> coll) {
T[] a = null;
try {
a = coll.toArray((T[]) Array.newInstance(type, 0));
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
return this.list.addAll(Arrays.asList(a));
}
@Override
public ListIterator listIterator() {
return listIterator(0);
}
@Override
public ListIterator listIterator(final int index) {
return new ListIterator() {
ListIterator i = list.listIterator(index);
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public T next() {
return i.next();
}
@Override
public boolean hasPrevious() {
return i.hasPrevious();
}
@Override
public T previous() {
return i.previous();
}
@Override
public int nextIndex() {
return i.nextIndex();
}
@Override
public int previousIndex() {
return i.previousIndex();
}
@Override
public void remove() {
i.remove();
}
@Override
public void set(T e) {
typeCheck(e);
i.set(e);
}
@Override
public void add(T e) {
typeCheck(e);
i.add(e);
}
};
}
@Override
public Iterator iterator() {
return new Iterator() {
private final Iterator it = list.iterator();
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public T next() {
return it.next();
}
@Override
public void remove() {
it.remove();
}
};
}
@Override
public boolean add(T e) {
typeCheck(e);
return list.add(e);
}
@Override
public List subList(int fromIndex, int toIndex) {
return Collections.checkedList(list.subList(fromIndex, toIndex), type);
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(T... elements) {
try {
T[] array = (T[]) Array.newInstance(type, elements.length);
System.arraycopy(elements, 0, array, 0, elements.length);
return list.addAll(array);
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
}
@Override
@SuppressWarnings("unchecked")
public boolean setAll(T... elements) {
try {
T[] array = (T[]) Array.newInstance(type, elements.length);
System.arraycopy(elements, 0, array, 0, elements.length);
return list.setAll(array);
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
}
@Override
@SuppressWarnings("unchecked")
public boolean setAll(Collection extends T> col) {
T[] a = null;
try {
a = col.toArray((T[]) Array.newInstance(type, 0));
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
return list.setAll(Arrays.asList(a));
}
}
private static class EmptyObservableSet extends AbstractSet implements ObservableSet {
public EmptyObservableSet() {
}
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
}
@Override
public void addListener(SetChangeListener super E> listener) {
}
@Override
public void removeListener(SetChangeListener super E> listener) {
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public boolean contains(Object obj) {
return false;
}
@Override
public boolean containsAll(Collection> c) {
return c.isEmpty();
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public E[] toArray(E[] a) {
if (a.length > 0)
a[0] = null;
return a;
}
@Override
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return false;
}
@Override
public Object next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
private static class UnmodifiableObservableSet extends AbstractSet implements ObservableSet {
private final ObservableSet backingSet;
private SetListenerHelper listenerHelper;
private SetChangeListener listener;
public UnmodifiableObservableSet(ObservableSet backingSet) {
this.backingSet = backingSet;
this.listener = null;
}
private void initListener() {
if (listener == null) {
listener = c -> {
callObservers(new SetAdapterChange(UnmodifiableObservableSet.this, c));
};
this.backingSet.addListener(new WeakSetChangeListener(listener));
}
}
private void callObservers(SetChangeListener.Change extends E> change) {
SetListenerHelper.fireValueChangedEvent(listenerHelper, change);
}
@Override
public Iterator iterator() {
return new Iterator() {
private final Iterator extends E> i = backingSet.iterator();
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public E next() {
return i.next();
}
};
}
@Override
public int size() {
return backingSet.size();
}
@Override
public boolean isEmpty() {
return backingSet.isEmpty();
}
@Override
public boolean contains(Object o) {
return backingSet.contains(o);
}
@Override
public void addListener(InvalidationListener listener) {
initListener();
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
@Override
public void removeListener(InvalidationListener listener) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
@Override
public void addListener(SetChangeListener super E> listener) {
initListener();
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
@Override
public void removeListener(SetChangeListener super E> listener) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
}
private static class SynchronizedSet implements Set {
final Object mutex;
private final Set backingSet;
SynchronizedSet(Set set, Object mutex) {
this.backingSet = set;
this.mutex = mutex;
}
SynchronizedSet(Set set) {
this.backingSet = set;
this.mutex = this;
}
@Override
public int size() {
synchronized(mutex) {
return backingSet.size();
}
}
@Override
public boolean isEmpty() {
synchronized(mutex) {
return backingSet.isEmpty();
}
}
@Override
public boolean contains(Object o) {
synchronized(mutex) {
return backingSet.contains(o);
}
}
@Override
public Iterator iterator() {
return backingSet.iterator();
}
@Override
public Object[] toArray() {
synchronized(mutex) {
return backingSet.toArray();
}
}
@Override
public E[] toArray(E[] a) {
synchronized(mutex) {
return backingSet.toArray(a);
}
}
@Override
public boolean add(E e) {
synchronized(mutex) {
return backingSet.add(e);
}
}
@Override
public boolean remove(Object o) {
synchronized(mutex) {
return backingSet.remove(o);
}
}
@Override
public boolean containsAll(Collection> c) {
synchronized(mutex) {
return backingSet.containsAll(c);
}
}
@Override
public boolean addAll(Collection extends E> c) {
synchronized(mutex) {
return backingSet.addAll(c);
}
}
@Override
public boolean retainAll(Collection> c) {
synchronized(mutex) {
return backingSet.retainAll(c);
}
}
@Override
public boolean removeAll(Collection> c) {
synchronized(mutex) {
return backingSet.removeAll(c);
}
}
@Override
public void clear() {
synchronized(mutex) {
backingSet.clear();
}
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
synchronized(mutex) {
return backingSet.equals(o);
}
}
@Override
public int hashCode() {
synchronized (mutex) {
return backingSet.hashCode();
}
}
}
private static class SynchronizedObservableSet extends SynchronizedSet implements ObservableSet {
private final ObservableSet backingSet;
private SetListenerHelper listenerHelper;
private final SetChangeListener listener;
SynchronizedObservableSet(ObservableSet set) {
super(set);
backingSet = set;
listener = c -> {
SetListenerHelper.fireValueChangedEvent(listenerHelper, new SetAdapterChange(SynchronizedObservableSet.this, c));
};
backingSet.addListener(new WeakSetChangeListener(listener));
}
@Override
public void addListener(InvalidationListener listener) {
synchronized (mutex) {
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
}
@Override
public void removeListener(InvalidationListener listener) {
synchronized (mutex) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
}
@Override
public void addListener(SetChangeListener super E> listener) {
synchronized (mutex) {
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
}
@Override
public void removeListener(SetChangeListener super E> listener) {
synchronized (mutex) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
}
}
private static class CheckedObservableSet extends AbstractSet implements ObservableSet {
private final ObservableSet backingSet;
private final Class type;
private SetListenerHelper listenerHelper;
private final SetChangeListener listener;
CheckedObservableSet(ObservableSet set, Class type) {
if (set == null || type == null) {
throw new NullPointerException();
}
backingSet = set;
this.type = type;
listener = c -> {
callObservers(new SetAdapterChange(CheckedObservableSet.this, c));
};
backingSet.addListener(new WeakSetChangeListener(listener));
}
private void callObservers(SetChangeListener.Change extends E> c) {
SetListenerHelper.fireValueChangedEvent(listenerHelper, c);
}
void typeCheck(Object o) {
if (o != null && !type.isInstance(o)) {
throw new ClassCastException("Attempt to insert "
+ o.getClass() + " element into collection with element type "
+ type);
}
}
@Override
public void addListener(InvalidationListener listener) {
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
@Override
public void removeListener(InvalidationListener listener) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
@Override
public void addListener(SetChangeListener super E> listener) {
listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
}
@Override
public void removeListener(SetChangeListener super E> listener) {
listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
}
@Override
public int size() {
return backingSet.size();
}
@Override
public boolean isEmpty() {
return backingSet.isEmpty();
}
@Override
public boolean contains(Object o) {
return backingSet.contains(o);
}
@Override
public Object[] toArray() {
return backingSet.toArray();
}
@Override
public T[] toArray(T[] a) {
return backingSet.toArray(a);
}
@Override
public boolean add(E e) {
typeCheck(e);
return backingSet.add(e);
}
@Override
public boolean remove(Object o) {
return backingSet.remove(o);
}
@Override
public boolean containsAll(Collection> c) {
return backingSet.containsAll(c);
}
@Override
@SuppressWarnings("unchecked")
public boolean addAll(Collection extends E> c) {
E[] a = null;
try {
a = c.toArray((E[]) Array.newInstance(type, 0));
} catch (ArrayStoreException e) {
throw new ClassCastException();
}
return backingSet.addAll(Arrays.asList(a));
}
@Override
public boolean retainAll(Collection> c) {
return backingSet.retainAll(c);
}
@Override
public boolean removeAll(Collection> c) {
return backingSet.removeAll(c);
}
@Override
public void clear() {
backingSet.clear();
}
@Override
public boolean equals(Object o) {
return o == this || backingSet.equals(o);
}
@Override
public int hashCode() {
return backingSet.hashCode();
}
@Override
public Iterator iterator() {
final Iterator it = backingSet.iterator();
return new Iterator() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public E next() {
return it.next();
}
@Override
public void remove() {
it.remove();
}
};
}
}
private static class EmptyObservableMap extends AbstractMap implements ObservableMap {
public EmptyObservableMap() {
}
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
}
@Override
public void addListener(MapChangeListener super K, ? super V> listener) {
}
@Override
public void removeListener(MapChangeListener super K, ? super V> listener) {
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
public V get(Object key) {
return null;
}
@Override
public Set keySet() {
return emptyObservableSet();
}
@Override
public Collection values() {
return emptyObservableSet();
}
@Override
public Set