org.fxmisc.wellbehaved.event.EventHandlerHelper 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.function.Consumer;
import java.util.function.Predicate;
import javafx.beans.property.ObjectProperty;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
/**
* Methods of this class could be added directly to the {@link EventHandler}
* interface. The interface could further be extended with default methods
*
* {@code
* EventHandler super T> orElse(EventHandler super T> other);
* EventHandler super T> without(EventHandler> other);
* }
*
* The latter may replace the {@link #exclude(EventHandler, EventHandler)}
* static method.
* @param
*/
public final class EventHandlerHelper {
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 T, ? extends U> eventMatcher) {
return new On<>(this, eventMatcher);
}
public On on(EventType extends U> eventType) {
return on(EventPattern.eventTypePattern(eventType));
}
public Builder addHandler(EventHandler super U> handler) {
return new CompositeBuilder<>(this, handler);
}
public final EventHandler create() {
List> handlers = getHandlers();
return new CompositeEventHandler<>(handlers);
}
List> getHandlers() {
return getHandlers(0);
}
abstract List> getHandlers(int additionalCapacity);
}
private static class CompositeBuilder extends Builder {
private final Builder super T> previousBuilder;
private final EventHandler super T> handler;
private CompositeBuilder(
Builder super T> previousBuilder,
EventHandler super T> 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> previousBuilder;
private final EventPattern super T, ? extends U> eventMatcher;
private On(
Builder super T> previous,
EventPattern super T, ? extends U> eventMatcher) {
this.previousBuilder = previous;
this.eventMatcher = eventMatcher;
}
public On where(Predicate super U> condition) {
return new On<>(previousBuilder, eventMatcher.and(condition));
}
public Builder act(Consumer super U> action) {
return previousBuilder.addHandler(t -> {
eventMatcher.match(t).ifPresent(u -> {
action.accept(u);
t.consume();
});
});
}
}
public static On on(
EventPattern super T, ? extends U> eventMatcher) {
return Builder.empty().on(eventMatcher);
}
public static On on(
EventType extends T> eventType) {
return Builder.empty().on(eventType);
}
public static Builder
startWith(EventHandler super T> handler) {
return Builder.empty().addHandler(handler);
}
static EventHandler empty() {
return EmptyEventHandler.instance();
}
@SafeVarargs
public static EventHandler super T> chain(EventHandler super T>... handlers) {
ArrayList> nonEmptyHandlers = new ArrayList<>(handlers.length);
for(EventHandler super T> handler: handlers) {
if(handler != empty()) {
nonEmptyHandlers.add(handler);
}
}
if(nonEmptyHandlers.isEmpty()) {
return empty();
} else if(nonEmptyHandlers.size() == 1) {
return nonEmptyHandlers.get(0);
} else {
nonEmptyHandlers.trimToSize();
return new CompositeEventHandler<>(nonEmptyHandlers);
}
}
public static EventHandler super T> exclude(EventHandler handler, EventHandler> subHandler) {
if(handler instanceof CompositeEventHandler) {
return ((CompositeEventHandler) handler).without(subHandler);
} else if(handler.equals(subHandler)) {
return empty();
} else {
return handler;
}
}
public static void install(
ObjectProperty> handlerProperty,
EventHandler super T> handler) {
EventHandler super T> oldHandler = handlerProperty.get();
if(oldHandler != null) {
handlerProperty.set(EventHandlerHelper.chain(handler, oldHandler));
} else {
handlerProperty.set(handler);
}
}
public static void installAfter(
ObjectProperty> handlerProperty,
EventHandler super T> handler) {
EventHandler super T> oldHandler = handlerProperty.get();
if(oldHandler != null) {
handlerProperty.set(EventHandlerHelper.chain(oldHandler, handler));
} else {
handlerProperty.set(handler);
}
}
public static void remove(
ObjectProperty> handlerProperty,
EventHandler super T> handler) {
EventHandler super T> oldHandler = handlerProperty.get();
if(oldHandler != null) {
handlerProperty.set(EventHandlerHelper.exclude(oldHandler, handler));
}
}
// prevent instantiation
private EventHandlerHelper() {}
}
final class EmptyEventHandler implements EventHandler {
private static EmptyEventHandler> INSTANCE = new EmptyEventHandler<>();
@SuppressWarnings("unchecked")
static EmptyEventHandler instance() {
return (EmptyEventHandler) INSTANCE;
}
private EmptyEventHandler() {}
@Override
public void handle(T event) {
// do nothing
}
}
class CompositeEventHandler implements EventHandler {
private final List> handlers;
CompositeEventHandler(List> handlers) {
// Since this constructor is package-private, we can be sure that
// the given list of handlers is never mutated, thus there is no need
// to create a copy.
this.handlers = handlers;
}
@Override
public void handle(T event) {
for(EventHandler super T> handler: handlers) {
handler.handle(event);
if(event.isConsumed()) {
break;
}
}
}
public EventHandler super T> without(EventHandler> other) {
if(this.equals(other)) {
return EmptyEventHandler.instance();
} else {
boolean changed = false;
List> newHandlers = new ArrayList<>(handlers.size());
for(EventHandler super T> handler: handlers) {
EventHandler super T> h = EventHandlerHelper.exclude(handler, other);
if(h != handler) {
changed = true;
}
if(h != EmptyEventHandler.instance()) {
newHandlers.add(h);
}
}
if(!changed) {
return this;
} else if(newHandlers.isEmpty()) {
return EmptyEventHandler.instance();
} else if(newHandlers.size() == 1) {
return newHandlers.get(0);
} else {
return new CompositeEventHandler<>(newHandlers);
}
}
}
@Override
public boolean equals(Object other) {
return other instanceof CompositeEventHandler
&& this.handlers.equals(((CompositeEventHandler>) other).handlers);
}
@Override
public int hashCode() {
return handlers.hashCode();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy