org.fxmisc.wellbehaved.event.StatefulEventHandlerTemplate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of WellBehavedFX Show documentation
Show all versions of WellBehavedFX Show documentation
Composable event handlers and skin skeletons for JavaFX controls.
The newest version!
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 - 2024 Weber Informatics LLC | Privacy Policy