org.jdesktop.observablecollections.ObservableCollections Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swixml Show documentation
Show all versions of swixml Show documentation
GUI generating engine for Java applications
The newest version!
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc. All rights reserved. Use is
* subject to license terms.
*/
package org.jdesktop.observablecollections;
import java.util.AbstractList;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* {@code ObservableCollections} provides factory methods for creating
* observable lists and maps.
*
*
* @author sky
*/
public final class ObservableCollections {
/**
* Creates and returns an {@code ObservableMap} wrapping the supplied
* {@code Map}.
*
* @param map the {@code Map} to wrap
* @return an {@code ObservableMap}
* @throws IllegalArgumentException if {@code map} is {@code null}
*/
public static ObservableMap observableMap(Map map) {
if (map == null) {
throw new IllegalArgumentException("Map must be non-null");
}
return new ObservableMapImpl(map);
}
/**
* Creates and returns an {@code ObservableList} wrapping the supplied
* {@code List}.
*
* @param list the {@code List} to wrap
* @return an {@code ObservableList}
* @throws IllegalArgumentException if {@code list} is {@code null}
*/
public static ObservableList observableList(List list) {
if (list == null) {
throw new IllegalArgumentException("List must be non-null");
}
return new ObservableListImpl(list, false);
}
/**
* Creates and returns an {@code ObservableListHelper} wrapping
* the supplied {@code List}. If you can track changes to the underlying
* list, use this method instead of {@code observableList()}.
*
* @param list the {@code List} to wrap
* @return an {@code ObservableList}
* @throws IllegalArgumentException if {@code list} is {@code null}
*
* @see #observableList
*/
public static ObservableListHelper observableListHelper(List list) {
ObservableListImpl oList = new ObservableListImpl(list, true);
return new ObservableListHelper(oList);
}
/**
* {@code ObservableListHelper} is created by {@code observableListHelper},
* and useful when changes to individual elements of the list can be
* tracked.
*
* @see #observableListHelper
*/
public static final class ObservableListHelper {
private final ObservableListImpl list;
ObservableListHelper(ObservableListImpl list) {
this.list = list;
}
/**
* Returns the {@code ObservableList}.
*
* @return the observable list
*/
public ObservableList getObservableList() {
return list;
}
/**
* Sends notification that the element at the specified index
* has changed.
*
* @param index the index of the element that has changed
* @throws ArrayIndexOutOfBoundsException if index is outside the
* range of the {@code List} ({@code < 0 || >= size})
*/
public void fireElementChanged(int index) {
if (index < 0 || index >= list.size()) {
throw new ArrayIndexOutOfBoundsException("Illegal index");
}
list.fireElementChanged(index);
}
}
private static final class ObservableMapImpl extends AbstractMap
implements ObservableMap {
private Map map;
private List listeners;
private Set> entrySet;
ObservableMapImpl(Map map) {
this.map = map;
listeners = new CopyOnWriteArrayList();
}
public void clear() {
// Remove all elements via iterator to trigger notification
Iterator iterator = keySet().iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
}
public boolean containsKey(Object key) {
return map.containsKey(key);
}
public boolean containsValue(Object value) {
return map.containsValue(value);
}
public Set> entrySet() {
Set> es = entrySet;
return es != null ? es : (entrySet = new EntrySet());
}
public V get(Object key) {
return map.get(key);
}
public boolean isEmpty() {
return map.isEmpty();
}
public V put(K key, V value) {
V lastValue;
if (containsKey(key)) {
lastValue = map.put(key, value);
for (ObservableMapListener listener : listeners) {
listener.mapKeyValueChanged(this, key, lastValue);
}
} else {
lastValue = map.put(key, value);
for (ObservableMapListener listener : listeners) {
listener.mapKeyAdded(this, key);
}
}
return lastValue;
}
public void putAll(Map extends K, ? extends V> m) {
for (K key : m.keySet()) {
put(key, m.get(key));
}
}
public V remove(Object key) {
if (containsKey(key)) {
V value = map.remove(key);
for (ObservableMapListener listener : listeners) {
listener.mapKeyRemoved(this, key, value);
}
return value;
}
return null;
}
public int size() {
return map.size();
}
public void addObservableMapListener(ObservableMapListener listener) {
listeners.add(listener);
}
public void removeObservableMapListener(ObservableMapListener listener) {
listeners.remove(listener);
}
private class EntryIterator implements Iterator> {
private Iterator> realIterator;
private Map.Entry last;
EntryIterator() {
realIterator = map.entrySet().iterator();
}
public boolean hasNext() {
return realIterator.hasNext();
}
public Map.Entry next() {
last = realIterator.next();
return last;
}
public void remove() {
if (last == null) {
throw new IllegalStateException();
}
Object toRemove = last.getKey();
last = null;
ObservableMapImpl.this.remove(toRemove);
}
}
private class EntrySet extends AbstractSet> {
public Iterator> iterator() {
return new EntryIterator();
}
@SuppressWarnings("unchecked")
public boolean contains(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry)o;
return containsKey(e.getKey());
}
@SuppressWarnings("unchecked")
public boolean remove(Object o) {
if (o instanceof Map.Entry) {
K key = ((Map.Entry)o).getKey();
if (containsKey(key)) {
remove(key);
return true;
}
}
return false;
}
public int size() {
return ObservableMapImpl.this.size();
}
public void clear() {
ObservableMapImpl.this.clear();
}
}
}
private static final class ObservableListImpl extends AbstractList
implements ObservableList {
private final boolean supportsElementPropertyChanged;
private List list;
private List listeners;
ObservableListImpl(List list, boolean supportsElementPropertyChanged) {
this.list = list;
listeners = new CopyOnWriteArrayList();
this.supportsElementPropertyChanged = supportsElementPropertyChanged;
}
public E get(int index) {
return list.get(index);
}
public int size() {
return list.size();
}
public E set(int index, E element) {
E oldValue = list.set(index, element);
for (ObservableListListener listener : listeners) {
listener.listElementReplaced(this, index, oldValue);
}
return oldValue;
}
public void add(int index, E element) {
list.add(index, element);
modCount++;
for (ObservableListListener listener : listeners) {
listener.listElementsAdded(this, index, 1);
}
}
public E remove(int index) {
E oldValue = list.remove(index);
modCount++;
for (ObservableListListener listener : listeners) {
listener.listElementsRemoved(this, index,
java.util.Collections.singletonList(oldValue));
}
return oldValue;
}
public boolean addAll(Collection extends E> c) {
return addAll(size(), c);
}
public boolean addAll(int index, Collection extends E> c) {
if (list.addAll(index, c)) {
modCount++;
for (ObservableListListener listener : listeners) {
listener.listElementsAdded(this, index, c.size());
}
}
return false;
}
public void clear() {
List dup = new ArrayList(list);
list.clear();
modCount++;
if (dup.size() != 0) {
for (ObservableListListener listener : listeners) {
listener.listElementsRemoved(this, 0, dup);
}
}
}
public boolean containsAll(Collection> c) {
return list.containsAll(c);
}
public T[] toArray(T[] a) {
return list.toArray(a);
}
public Object[] toArray() {
return list.toArray();
}
private void fireElementChanged(int index) {
for (ObservableListListener listener : listeners) {
listener.listElementPropertyChanged(this, index);
}
}
public void addObservableListListener(ObservableListListener listener) {
listeners.add(listener);
}
public void removeObservableListListener(ObservableListListener listener) {
listeners.remove(listener);
}
public boolean supportsElementPropertyChanged() {
return supportsElementPropertyChanged;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy