
org.fxmisc.wellbehaved.event.StatefulEventHandlerTemplate Maven / Gradle / Ivy
package org.fxmisc.wellbehaved.event;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javafx.event.Event;
import javafx.event.EventType;
public final class StatefulEventHandlerTemplate implements EventHandlerTemplate {
@FunctionalInterface
public interface StateTransition {
S transition(T target, S state, E event);
}
/**
* An instance of this interface is expected to consume the event
* if it successfully handled the event. If the event was not handled by an
* instance of this interface, the event should be left unconsumed and the
* returned state should be unchanged.
*/
@FunctionalInterface
public interface StateTransitioningHandler {
S handle(T target, S state, E event);
default StateTransitioningHandler orElse(
StateTransitioningHandler super U, S, ? super F> nextHandler) {
return (u, s, f) -> {
S newState = StateTransitioningHandler.this.handle(u, s, f);
if(f.isConsumed()) {
return newState;
} else {
return nextHandler.handle(u, s, f);
}
};
}
default StateTransitioningHandler onlyWhen(BiPredicate super U, ? super S> condition) {
return (u, s, e) -> {
return condition.test(u, s)
? StateTransitioningHandler.this.handle(u, s, e)
: s;
};
}
default StatefulEventHandlerTemplate initialStateSupplier(Supplier extends S> initialStateSupplier) {
return new StatefulEventHandlerTemplate<>(this, initialStateSupplier);
}
}
public static abstract class Builder {
private static Builder empty() {
return new Builder() {
@Override
List> getHandlers(
int additionalCapacity) {
return new ArrayList<>(additionalCapacity);
}
};
}
// private constructor to prevent subclassing by the user
private Builder() {}
public On on(EventPattern super E, ? extends F> eventMatcher) {
return new On<>(this, eventMatcher);
}
public On on(EventType extends F> eventType) {
return on(EventPattern.eventTypePattern(eventType));
}
public Builder addHandler(
StateTransitioningHandler super U, S, ? super F> handler) {
return new CompositeBuilder<>(this, handler);
}
public StateTransitioningHandler createHandler() {
return (t, s, e) -> {
S newState = s;
for(StateTransitioningHandler super T, S, ? super E> handler: getHandlers()) {
newState = handler.handle(t, newState, e);
if(e.isConsumed()) {
break;
}
}
return newState;
};
}
public StatefulEventHandlerTemplate initialStateSupplier(Supplier extends S> initialStateSupplier) {
return createHandler().initialStateSupplier(initialStateSupplier);
}
List> getHandlers() {
return getHandlers(0);
}
abstract List> getHandlers(int additionalCapacity);
}
private static class CompositeBuilder extends Builder {
private final Builder super T, S, ? super E> previousBuilder;
private final StateTransitioningHandler super T, S, ? super E> handler;
private CompositeBuilder(
Builder super T, S, ? super E> previousBuilder,
StateTransitioningHandler super T, S, ? super E> handler) {
this.previousBuilder = previousBuilder;
this.handler = handler;
}
@Override
List> getHandlers(
int additionalCapacity) {
List> handlers = previousBuilder.getHandlers(additionalCapacity + 1);
handlers.add(handler);
return handlers;
}
}
public static class On {
private final Builder super T, S, ? super E> previousBuilder;
private final EventPattern super E, ? extends F> eventMatcher;
private On(
Builder super T, S, ? super E> previousBuilder,
EventPattern super E, ? extends F> eventMatcher) {
this.previousBuilder = previousBuilder;
this.eventMatcher = eventMatcher;
}
public On where(Predicate super E> condition) {
return new On<>(previousBuilder, eventMatcher.and(condition));
}
public When when(Predicate super U> condition) {
return when((u, s) -> condition.test(u));
}
public When when(BiPredicate super U, ? super S> condition) {
return new When<>(previousBuilder, eventMatcher, condition);
}
public Builder act(BiConsumer super U, ? super E> action) {
return act((u, s, e) -> { action.accept(u, e); return s; });
}
public Builder act(StateTransition super U, S, ? super F> action) {
return previousBuilder.addHandler((u, s, e) -> {
Optional extends F> optF = eventMatcher.match(e);
if(optF.isPresent()) {
F f = optF.get();
S newState = action.transition(u, s, f);
f.consume();
return newState;
} else {
return s;
}
});
}
}
public static class When {
private final Builder super T, S, ? super E> previousBuilder;
private final EventPattern super E, ? extends F> eventMatcher;
private final BiPredicate super T, ? super S> condition;
private When(
Builder super T, S, ? super E> previousBuilder,
EventPattern super E, ? extends F> eventMatcher,
BiPredicate super T, ? super S> condition) {
this.previousBuilder = previousBuilder;
this.eventMatcher = eventMatcher;
this.condition = condition;
}
public Builder act(BiConsumer super U, ? super F> action) {
return act((u, s, e) -> { action.accept(u, e); return s; });
}
public Builder act(StateTransition super U, S, ? super F> action) {
return previousBuilder.addHandler((u, s, e) -> {
Optional extends F> optF = eventMatcher.match(e);
if(optF.isPresent() && condition.test(u, s)) {
F f = optF.get();
S newState = action.transition(u, s, f);
f.consume();
return newState;
} else {
return s;
}
});
}
}
public static On on(
EventPattern super E, ? extends F> eventMatcher) {
return Builder.empty().on(eventMatcher);
}
public static On on(
EventType extends F> eventType) {
return Builder.empty().on(eventType);
}
public static Builder
startWith(StateTransitioningHandler super T, S, ? super E> handler) {
return Builder.empty().addHandler(handler);
}
private final Supplier extends S> initialStateSupplier;
private final StateTransitioningHandler super T, S, ? super E> handler;
StatefulEventHandlerTemplate(
StateTransitioningHandler super T, S, ? super E> handler,
Supplier extends S> initialStateSupplier) {
this.initialStateSupplier = initialStateSupplier;
this.handler = handler;
}
@Override
public BiConsumer super T, ? super E> getHandler() {
return new BiConsumer() {
private S state = initialStateSupplier.get();
@Override
public void accept(T t, E e) {
state = handler.handle(t, state, e);
}
};
}
public StatefulEventHandlerTemplate onlyWhen(
BiPredicate super U, ? super S> condition) {
return handler.onlyWhen(condition).initialStateSupplier(initialStateSupplier);
}
public StatefulEventHandlerTemplate addHandler(
StateTransitioningHandler super U, S, ? super F> nextHandler) {
return handler.orElse(nextHandler).initialStateSupplier(initialStateSupplier);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy