All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rx.javafx.sources.ObservableListSource Maven / Gradle / Ivy

/**
 * Copyright 2016 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package rx.javafx.sources;

import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import rx.Observable;
import rx.functions.Func1;
import rx.schedulers.JavaFxScheduler;
import rx.subscriptions.JavaFxSubscriptions;

import java.util.HashMap;

public final class ObservableListSource {
    private ObservableListSource() {}

    public static  Observable> fromObservableList(final ObservableList source) {

        return Observable.create((Observable.OnSubscribe>) subscriber -> {
            ListChangeListener listener = c -> subscriber.onNext(source);
            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));
        }).startWith(source).subscribeOn(JavaFxScheduler.getInstance());
    }

    public static  Observable fromObservableListAdds(final ObservableList source) {

        return Observable.create((Observable.OnSubscribe) subscriber -> {

            ListChangeListener listener = c -> {
                while (c.next()) {
                    if (c.wasAdded()) {
                        c.getAddedSubList().forEach(subscriber::onNext);
                    }
                }
            };
            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));

        }).subscribeOn(JavaFxScheduler.getInstance());
    }
    public static  Observable fromObservableListRemovals(final ObservableList source) {

        return Observable.create((Observable.OnSubscribe) subscriber -> {

            ListChangeListener listener = c -> {
                while (c.next()) {
                    if (c.wasRemoved()) {
                        c.getRemoved().forEach(subscriber::onNext);
                    }
                }
            };

            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));

        }).subscribeOn(JavaFxScheduler.getInstance());
    }
    public static  Observable fromObservableListUpdates(final ObservableList source) {

        return Observable.create((Observable.OnSubscribe) subscriber -> {

            ListChangeListener listener = c -> {
                while (c.next()) {
                    if (c.wasUpdated()) {
                        for (int i = c.getFrom(); i < c.getTo(); i++) {
                            subscriber.onNext(c.getList().get(i));
                        }
                    }
                }
            };
            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));

        }).subscribeOn(JavaFxScheduler.getInstance());
    }
    public static  Observable> fromObservableListChanges(final ObservableList source) {
        return Observable.create((Observable.OnSubscribe>) subscriber -> {

            ListChangeListener listener = c -> {
                while (c.next()) {
                    if (c.wasAdded()) {
                        c.getAddedSubList().forEach(v -> subscriber.onNext(ListChange.of(v,Flag.ADDED)));
                    }
                    if (c.wasRemoved()) {
                        c.getRemoved().forEach(v -> subscriber.onNext(ListChange.of(v,Flag.REMOVED)));
                    }
                    if (c.wasUpdated()) {
                        for (int i = c.getFrom(); i < c.getTo(); i++) {
                            subscriber.onNext(ListChange.of(c.getList().get(i),Flag.UPDATED));
                        }
                    }
                }
            };
            source.addListener(listener);

            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));
        }).subscribeOn(JavaFxScheduler.getInstance());
    }

    public static  Observable> fromObservableListDistinctChanges(final ObservableList source) {

        return Observable.create((Observable.OnSubscribe>) subscriber -> {

            final DupeCounter dupeCounter = new DupeCounter<>();
            source.stream().forEach(dupeCounter::add);

            ListChangeListener listener = c -> {

                while (c.next()) {
                    if (c.wasAdded()) {
                        c.getAddedSubList().stream().filter(v -> dupeCounter.add(v) == 1)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.ADDED)));
                    }
                    if (c.wasRemoved()) {
                        c.getRemoved().stream().filter(v -> dupeCounter.remove(v) == 0)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.REMOVED)));
                    }
                }
            };
            source.addListener(listener);

            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));
        }).subscribeOn(JavaFxScheduler.getInstance());
    }
    public static  Observable> fromObservableListDistinctChanges(final ObservableList source, Func1 mapper) {

        return Observable.create((Observable.OnSubscribe>) subscriber -> {

            final DupeCounter dupeCounter = new DupeCounter<>();
            source.stream().map(mapper::call).forEach(dupeCounter::add);

            ListChangeListener listener = c -> {

                while (c.next()) {
                    if (c.wasAdded()) {
                        c.getAddedSubList().stream().filter(v -> dupeCounter.add(mapper.call(v)) == 1)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.ADDED)));
                    }
                    if (c.wasRemoved()) {
                        c.getRemoved().stream().filter(v -> dupeCounter.remove(mapper.call(v)) == 0)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.REMOVED)));
                    }
                }
            };
            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));
        }).subscribeOn(JavaFxScheduler.getInstance());
    }
    public static  Observable> fromObservableListDistinctMappings(final ObservableList source, Func1 mapper) {

        return Observable.create((Observable.OnSubscribe>) subscriber -> {

            final DupeCounter dupeCounter = new DupeCounter<>();
            source.stream().map(mapper::call).forEach(dupeCounter::add);

            ListChangeListener listener = c -> {

                while (c.next()) {
                    if (c.wasAdded()) {
                        c.getAddedSubList().stream().map(mapper::call)
                                .filter(v -> dupeCounter.add(v) == 1)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.ADDED)));
                    }
                    if (c.wasRemoved()) {
                        c.getRemoved().stream().map(mapper::call)
                                .filter(v -> dupeCounter.remove(v) == 0)
                                .forEach(v -> subscriber.onNext(ListChange.of(v,Flag.REMOVED)));
                    }
                }
            };
            source.addListener(listener);
            subscriber.add(JavaFxSubscriptions.unsubscribeInEventDispatchThread(() -> source.removeListener(listener)));

        }).subscribeOn(JavaFxScheduler.getInstance());
    }

    private static final class DupeCounter {
        private final HashMap counts = new HashMap<>();

        public int add(T value) {
            Integer prev = counts.get(value);
            int newVal = 0;
            if (prev == null) {
                newVal = 1;
                counts.put(value, newVal);
            }  else {
                newVal = prev + 1;
                counts.put(value, newVal);
            }
            return newVal;
        }
        public int remove(T value) {
            Integer prev = counts.get(value);
            if (prev != null && prev > 0) {
                int newVal = prev - 1;
                if (newVal == 0) {
                    counts.remove(value);
                } else {
                    counts.put(value, newVal);
                }
                return newVal;
            }
            else {
                throw new IllegalStateException();
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy