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

org.panteleyev.fx.PredicateProperty Maven / Gradle / Ivy

The newest version!
/*
 Copyright © 2020 Petr Panteleyev 
 SPDX-License-Identifier: BSD-2-Clause
 */
package org.panteleyev.fx;

import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * This class implements property that wraps {@link Predicate} instance.
 * 

* Default value is x -> true i.e. {@link PredicateProperty#test(Object)} will return * true until the predicate is altered via {@link PredicateProperty#set(Predicate)}. * * @param the type of the input to the predicate */ public class PredicateProperty extends SimpleObjectProperty> implements Predicate { private enum Op { AND, OR } private final Collection> inputs = new ArrayList<>(); private final Op op; @SuppressWarnings("FieldCanBeLocal") private final ChangeListener> LISTENER = (x, y, newValue) -> onInputUpdate(); /** * Creates an instance with default predicate. */ public PredicateProperty() { super(x -> true); this.op = null; } /** * Creates an instance with default predicate. * * @param bean bean of this property * @param name name of this property */ public PredicateProperty(Object bean, String name) { super(bean, name, x -> true); this.op = null; } /** * Creates an instance with the specified predicate value. * * @param initialValue initial predicate value */ public PredicateProperty(Predicate initialValue) { super(initialValue); this.op = null; } /** * Creates an instance with the specified predicate value. * * @param bean bean of this property * @param name name of this property * @param initialValue initial predicate value */ public PredicateProperty(Object bean, String name, Predicate initialValue) { super(bean, name, initialValue); Objects.requireNonNull(initialValue, "Predicate value cannot be null"); this.op = null; } private PredicateProperty(Op op, Collection> inputs) { this.op = op; this.inputs.addAll(inputs); super.set(buildPredicate(op, inputs)); for (var p : inputs) { p.addListener(new WeakChangeListener<>(LISTENER)); } } private void onInputUpdate() { super.set(buildPredicate(op, inputs)); } private static Predicate buildPredicate(Op op, Collection> inputs) { Predicate result = op == Op.AND ? x -> true : x -> false; for (var p : inputs) { result = switch (op) { case AND -> result.and(p.get()); case OR -> result.or(p.get()); }; } return result; } /** * Creates calculated predicate property that produces logical AND from its arguments. * * @param args arguments * @param type of the input to the predicate * @return predicate property */ public static PredicateProperty and(Collection> args) { return new PredicateProperty<>(Op.AND, args); } /** * Creates calculated predicate property that produces logical OR from its arguments. * * @param args arguments * @param type of the input to the predicate * @return predicate property */ public static PredicateProperty or(Collection> args) { return new PredicateProperty<>(Op.OR, args); } /** * Sets the wrapped predicate value. * * @param predicate predicate value. * @throws IllegalStateException if property is calculated */ @Override public void set(Predicate predicate) { if (op != null) { throw new IllegalStateException("Calculated property cannot be set"); } super.set(predicate); } /** * Create a unidirectional binding for this Property. * * @param observableValue observable this {@link javafx.beans.Observable} should be bound to */ @Override public void bind(ObservableValue> observableValue) { if (op != null) { throw new IllegalStateException("Calculated property cannot be bound"); } super.bind(observableValue); } /** * Sets the wrapped predicate value. * * @param predicate predicate value. * @throws IllegalStateException if property is calculated */ @Override public void setValue(Predicate predicate) { if (op != null) { throw new IllegalStateException("Calculated property cannot be set"); } super.setValue(predicate); } /** * Changes predicate to its initial value, i.e. x -> true. * * @throws IllegalStateException if property is calculated */ public void reset() { if (op != null) { throw new IllegalStateException("Calculated property cannot be reset"); } super.setValue(x -> true); } // Predicate methods @Override public boolean test(T t) { return get().test(t); } @Override public Predicate and(Predicate other) { return get().and(other); } @Override public Predicate negate() { return get().negate(); } @Override public Predicate or(Predicate other) { return get().or(other); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy