org.reactfx.collection.LiveList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of richtextfx Show documentation
Show all versions of richtextfx Show documentation
FX-Text-Area for formatted text and other special effects.
package org.reactfx.collection;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import javafx.beans.InvalidationListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.control.IndexRange;
import org.reactfx.EventStream;
import org.reactfx.EventStreamBase;
import org.reactfx.Observable;
import org.reactfx.Subscription;
import org.reactfx.collection.LiveList.QuasiChangeObserver;
import org.reactfx.collection.LiveList.QuasiModificationObserver;
import org.reactfx.util.AccumulatorSize;
import org.reactfx.util.Experimental;
import org.reactfx.util.WrapperBase;
import org.reactfx.value.Val;
/**
* Adds additional methods to {@link ObservableList}.
*
* @param type of list elements
*/
public interface LiveList
extends ObservableList, Observable> {
/* ************ *
* Nested Types *
* ************ */
public interface Observer {
AccumulatorSize sizeOf(ListModificationSequence extends E> mods);
O headOf(ListModificationSequence extends E> mods);
ListModificationSequence tailOf(ListModificationSequence mods);
void onChange(O change);
}
@FunctionalInterface
public interface QuasiChangeObserver
extends Observer> {
@Override
default AccumulatorSize sizeOf(
ListModificationSequence extends E> mods) {
return AccumulatorSize.ONE;
}
@Override
default QuasiListChange extends E> headOf(
ListModificationSequence extends E> mods) {
return mods.asListChange();
}
@Override
default ListModificationSequence tailOf(
ListModificationSequence mods) {
throw new NoSuchElementException();
}
}
@FunctionalInterface
public interface QuasiModificationObserver
extends Observer> {
@Override
default AccumulatorSize sizeOf(
ListModificationSequence extends E> mods) {
return AccumulatorSize.fromInt(mods.getModificationCount());
}
@Override
default QuasiListModification extends E> headOf(
ListModificationSequence extends E> mods) {
return mods.getModifications().get(0);
}
@Override
default ListModificationSequence tailOf(
ListModificationSequence mods) {
return mods.asListChangeAccumulator().drop(1);
}
}
/* *************** *
* Default Methods *
* *************** */
default void addQuasiChangeObserver(QuasiChangeObserver super E> observer) {
addObserver(observer);
}
default void removeQuasiChangeObserver(QuasiChangeObserver super E> observer) {
removeObserver(observer);
}
default void addQuasiModificationObserver(QuasiModificationObserver super E> observer) {
addObserver(observer);
}
default void removeQuasiModificationObserver(QuasiModificationObserver super E> observer) {
removeObserver(observer);
}
default void addChangeObserver(Consumer super ListChange extends E>> observer) {
addQuasiChangeObserver(new ChangeObserverWrapper<>(this, observer));
}
default void removeChangeObserver(Consumer super ListChange extends E>> observer) {
removeQuasiChangeObserver(new ChangeObserverWrapper<>(this, observer));
}
default void addModificationObserver(Consumer super ListModification extends E>> observer) {
addQuasiModificationObserver(new ModificationObserverWrapper<>(this, observer));
}
default void removeModificationObserver(Consumer super ListModification extends E>> observer) {
removeQuasiModificationObserver(new ModificationObserverWrapper<>(this, observer));
}
default Subscription observeQuasiChanges(QuasiChangeObserver super E> observer) {
addQuasiChangeObserver(observer);
return () -> removeQuasiChangeObserver(observer);
}
default Subscription observeQuasiModifications(QuasiModificationObserver super E> observer) {
addQuasiModificationObserver(observer);
return () -> removeQuasiModificationObserver(observer);
}
default Subscription observeChanges(Consumer super ListChange extends E>> observer) {
addChangeObserver(observer);
return () -> removeChangeObserver(observer);
}
default Subscription observeModifications(Consumer super ListModification extends E>> observer) {
addModificationObserver(observer);
return () -> removeModificationObserver(observer);
}
@Override
default void addListener(ListChangeListener super E> listener) {
addQuasiChangeObserver(new ChangeListenerWrapper<>(this, listener));
}
@Override
default void removeListener(ListChangeListener super E> listener) {
removeQuasiChangeObserver(new ChangeListenerWrapper<>(this, listener));
}
@Override
default void addListener(InvalidationListener listener) {
addQuasiChangeObserver(new InvalidationListenerWrapper<>(this, listener));
}
@Override
default void removeListener(InvalidationListener listener) {
removeQuasiChangeObserver(new InvalidationListenerWrapper<>(this, listener));
}
default Subscription pin() {
return observeQuasiChanges(qc -> {});
}
default Val sizeProperty() {
return sizeOf(this);
}
default LiveList map(Function super E, ? extends F> f) {
return map(this, f);
}
default LiveList mapDynamic(
ObservableValue extends Function super E, ? extends F>> f) {
return mapDynamic(this, f);
}
default SuspendableList suspendable() {
return suspendable(this);
}
default MemoizationList memoize() {
return memoize(this);
}
default Val reduce(BinaryOperator reduction) {
return reduce(this, reduction);
}
@Experimental
default Val reduceRange(
ObservableValue range, BinaryOperator reduction) {
return reduceRange(this, range, reduction);
}
@Experimental
default Val collapse(Function super List, ? extends T> f) {
return collapse(this, f);
}
@Experimental
default Val collapseDynamic(
ObservableValue extends Function super List, ? extends T>> f) {
return collapseDynamic(this, f);
}
default EventStream> quasiChanges() {
return new EventStreamBase>() {
@Override
protected Subscription observeInputs() {
return observeQuasiChanges(this::emit);
}
};
}
default EventStream> changes() {
return quasiChanges().map(qc -> QuasiListChange.instantiate(qc, this));
}
default EventStream> quasiModifications() {
return new EventStreamBase>() {
@Override
protected Subscription observeInputs() {
return observeQuasiModifications(this::emit);
}
};
}
default EventStream> modifications() {
return quasiModifications().map(qm -> QuasiListModification.instantiate(qm, this));
}
/* ************** *
* Static Methods *
* ************** */
static Subscription observeQuasiChanges(
ObservableList extends E> list,
QuasiChangeObserver super E> observer) {
if(list instanceof LiveList) {
LiveList extends E> lst = (LiveList extends E>) list;
return lst.observeQuasiChanges(observer);
} else {
ListChangeListener listener = ch -> {
QuasiListChange extends E> change = QuasiListChange.from(ch);
observer.onChange(change);
};
list.addListener(listener);
return () -> list.removeListener(listener);
}
}
static Subscription observeChanges(
ObservableList list,
Consumer super ListChange extends E>> observer) {
return observeQuasiChanges(
list, qc -> observer.accept(QuasiListChange.instantiate(qc, list)));
}
static EventStream> quasiChangesOf(
ObservableList list) {
if(list instanceof LiveList) {
LiveList lst = (LiveList) list;
return lst.quasiChanges();
} else {
return new EventStreamBase>() {
@Override
protected Subscription observeInputs() {
return LiveList.observeQuasiChanges(list, this::emit);
}
};
}
}
static EventStream> changesOf(ObservableList list) {
return quasiChangesOf(list).map(qc -> QuasiListChange.instantiate(qc, list));
}
static Val sizeOf(ObservableList> list) {
return Val.create(() -> list.size(), list);
}
static LiveList map(
ObservableList extends E> list,
Function super E, ? extends F> f) {
return new MappedList<>(list, f);
}
static LiveList mapDynamic(
ObservableList extends E> list,
ObservableValue extends Function super E, ? extends F>> f) {
return new DynamicallyMappedList<>(list, f);
}
static SuspendableList suspendable(ObservableList list) {
if(list instanceof SuspendableList) {
return (SuspendableList) list;
} else {
return new SuspendableListWrapper<>(list);
}
}
static MemoizationList memoize(ObservableList list) {
if(list instanceof MemoizationList) {
return (MemoizationList) list;
} else {
return new MemoizationListImpl<>(list);
}
}
static Val reduce(
ObservableList list, BinaryOperator reduction) {
return new ListReduction<>(list, reduction);
}
@Experimental
static Val reduceRange(
ObservableList list,
ObservableValue range,
BinaryOperator reduction) {
return new ListRangeReduction<>(list, range, reduction);
}
@Experimental
static Val collapse(
ObservableList extends E> list,
Function super List, ? extends T> f) {
return Val.create(() -> f.apply(Collections.unmodifiableList(list)), list);
}
@Experimental
static Val collapseDynamic(
ObservableList extends E> list,
ObservableValue extends Function super List, ? extends T>> f) {
return Val.create(
() -> f.getValue().apply(Collections.unmodifiableList(list)),
list, f);
}
/**
* Returns a {@linkplain LiveList} view of the given
* {@linkplain ObservableValue} {@code obs}. The returned list will have
* size 1 when the given observable value is not {@code null} and size 0
* otherwise.
*/
static LiveList wrapVal(ObservableValue obs) {
return new ValAsList<>(obs);
}
}
class ChangeObserverWrapper
extends WrapperBase>>
implements QuasiChangeObserver {
private final ObservableList list;
ChangeObserverWrapper(
ObservableList list,
Consumer super ListChange extends T>> delegate) {
super(delegate);
this.list = list;
}
@Override
public void onChange(QuasiListChange extends T> change) {
getWrappedValue().accept(QuasiListChange.instantiate(change, list));
}
}
class ModificationObserverWrapper
extends WrapperBase>>
implements QuasiModificationObserver {
private final ObservableList list;
ModificationObserverWrapper(
ObservableList list,
Consumer super ListModification extends T>> delegate) {
super(delegate);
this.list = list;
}
@Override
public void onChange(QuasiListModification extends T> change) {
getWrappedValue().accept(QuasiListModification.instantiate(change, list));
}
}
class InvalidationListenerWrapper
extends WrapperBase
implements QuasiChangeObserver {
private final ObservableList list;
public InvalidationListenerWrapper(
ObservableList list,
InvalidationListener listener) {
super(listener);
this.list = list;
}
@Override
public void onChange(QuasiListChange extends T> change) {
getWrappedValue().invalidated(list);
}
}
class ChangeListenerWrapper
extends WrapperBase>
implements QuasiChangeObserver {
private final ObservableList list;
public ChangeListenerWrapper(
ObservableList list,
ListChangeListener super T> listener) {
super(listener);
this.list = list;
}
@Override
public void onChange(QuasiListChange extends T> change) {
List extends QuasiListModification extends T>> modifications =
change.getModifications();
if(modifications.isEmpty()) {
return;
}
getWrappedValue().onChanged(new ListChangeListener.Change(list) {
private int current = -1;
@Override
public int getFrom() {
return modifications.get(current).getFrom();
}
@Override
protected int[] getPermutation() {
return new int[0]; // not a permutation
}
/* Can change to List extends E> and remove unsafe cast when
* https://javafx-jira.kenai.com/browse/RT-39683 is resolved. */
@Override
@SuppressWarnings("unchecked")
public List getRemoved() {
// cast is safe, because the list is unmodifiable
return (List) modifications.get(current).getRemoved();
}
@Override
public int getTo() {
return modifications.get(current).getTo();
}
@Override
public boolean next() {
if(current + 1 < modifications.size()) {
++current;
return true;
} else {
return false;
}
}
@Override
public void reset() {
current = -1;
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy