/* * This is customized version of HandlerManager provided by google. The purpose of this * extension is to enable user triggered events to bypass ISSUE 101 * * Fixed ISSUE 101: To support event handling when event handlers are added as part of event processing * * 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 org.myxyz.custom;
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;
import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerRegistration; import org.myxyz.custom.X10GwtEvent.Type;
/** * Manager responsible for adding handlers to event sources and firing those * handlers on passed in events. */ public class X10HandlerManager { public static int CONFIGURED_DEPTH = 5; /** * Interface for queued add/remove operations. */ private interface AddOrRemoveCommand { /*ISSUE 101*/ public EventHandler execute(); }
/** * Inner class used to actually contain the handlers. */ private static class HandlerRegistry { private final HashMap<X10GwtEvent.Type<?>, ArrayList<?>> map = new HashMap<X10GwtEvent.Type<?>, ArrayList<?>>();
private <H extends EventHandler> void addHandler(Type<H> type, H handler) { ArrayList<H> l = get(type); if (l == null) { l = new ArrayList<H>(); map.put(type, l); } l.add(handler); }
private <H extends EventHandler> void fireEvent(X10GwtEvent<H> event, boolean isReverseOrder) { Type<H> type = event.getAssociatedType(); int count = getHandlerCount(type); if (isReverseOrder) { for (int i = count - 1; i >= 0; i--) { H handler = this.<H> getHandler(type, i); event.dispatch(handler); } } else { for (int i = 0; i < count; i++) { H handler = this.<H> getHandler(type, i); event.dispatch(handler); } } } /* ISSUE 101 */ private <T extends EventHandler> void fireForSkippedHandler(X10GwtEvent<T> event, boolean isReverseOrder, List<T> handlers) { int count = handlers.size(); if (isReverseOrder) { for (int i = count - 1; i >= 0; i--) { T handler = handlers.get(i); event.dispatch(handler); } } else { for (int i = 0; i < count; i++) { T handler = handlers.get(i); event.dispatch(handler); } } }
@SuppressWarnings("unchecked") private <H> ArrayList<H> get(X10GwtEvent.Type<H> type) { // This cast is safe because we control the puts. return (ArrayList<H>) map.get(type); }
private <H extends EventHandler> H getHandler(X10GwtEvent.Type<H> eventKey, int index) { ArrayList<H> l = get(eventKey); return l.get(index); }
private int getHandlerCount(X10GwtEvent.Type<?> eventKey) { ArrayList<?> l = map.get(eventKey); return l == null ? 0 : l.size(); }
private boolean isEventHandled(X10GwtEvent.Type<?> eventKey) { return map.containsKey(eventKey); }
private <H> void removeHandler(X10GwtEvent.Type<H> eventKey, H handler) { ArrayList<H> l = get(eventKey); boolean result = l.remove(handler); if (l.size() == 0) { map.remove(eventKey); } assert result : "Tried to remove unknown handler: " + handler + " from " + eventKey; } }
private int firingDepth = 0; private boolean isReverseOrder;
// map storing the actual handlers private HandlerRegistry registry;
// source of the event. private final Object source;
// Add and remove operations received during dispatch. private List<AddOrRemoveCommand> deferredDeltas;
/** * Creates a handler manager with the given source. Handlers will be fired * in the order that they are added. * * @param source * the event source */ public X10HandlerManager(Object source) { this(source, false); }
/** * Creates a handler manager with the given source, specifying the order in * which handlers are fired. * * @param source * the event source * @param fireInReverseOrder * true to fire handlers in reverse order */ public X10HandlerManager(Object source, boolean fireInReverseOrder) { registry = new HandlerRegistry(); this.source = source; this.isReverseOrder = fireInReverseOrder; }
/** * Adds a handle. * * @param <H> * The type of handler * @param type * the event type associated with this handler * @param handler * the handler * @return the handler registration, can be stored in order to remove the * handler later */ public <H extends EventHandler> X10HandlerRegistration addHandler(X10GwtEvent.Type<H> type, final H handler) { assert type != null : "Cannot add a handler with a null type"; assert handler != null : "Cannot add a null handler"; if (firingDepth > 0) { enqueueAdd(type, handler); } else { doAdd(type, handler); }
return new X10HandlerRegistration(this, type, handler); }
/** * Fires the given event to the handlers listening to the event's type. * * Note, any subclass should be very careful about overriding this method, * as adds/removes of handlers will not be safe except within this * implementation. * * @param event * the event */ public <H extends EventHandler> void fireEvent(X10GwtEvent<H> event) { // If it not live we should revive it. if (!event.isLive()) { event.revive(); } Object oldSource = event.getSource(); event.setSource(source); try { firingDepth++;
registry.fireEvent(event, isReverseOrder);
} finally { /*ISSUE 101*/ int eventTries = 0; do { eventTries++; List<H> newHandlers = handleQueuedAddsAndRemoves(); /* pass the event to newly added handlers alone */ registry.fireForSkippedHandler(event, isReverseOrder, newHandlers); } while(eventTries < CONFIGURED_DEPTH && deferredDeltas != null); } if (oldSource == null) { // This was my event, so I should kill it now that I'm done. event.kill(); } else { // Restoring the source for the next handler to use. event.setSource(oldSource); } }
/** * Gets the handler at the given index. * * @param <H> * the event handler type * @param index * the index * @param type * the handler's event type * @return the given handler */ public <H extends EventHandler> H getHandler(X10GwtEvent.Type<H> type, int index) { assert index < getHandlerCount(type) : "handlers for " + type.getClass() + " have size: " + getHandlerCount(type) + " so do not have a handler at index: " + index; return registry.getHandler(type, index); }
/** * Gets the number of handlers listening to the event type. * * @param type * the event type * @return the number of registered handlers */ public int getHandlerCount(Type<?> type) { return registry.getHandlerCount(type); }
/** * Does this handler manager handle the given event type? * * @param e * the event type * @return whether the given event type is handled */ public boolean isEventHandled(Type<?> e) { return registry.isEventHandled(e); }
/** * Removes the given handler from the specified event type. Normally, * applications should call {@link HandlerRegistration#removeHandler()} * instead. * * @param <H> * handler type * * @param type * the event type * @param handler * the handler * @deprecated This method is likely to be removed along with "listener" * interfaces in a future release. If you have a reason it * should be retained beyond that time, please add your comments * to GWT <a href= * "http://code.google.com/p/google-web-toolkit/issues/detail?id=3102" * >issue 3102</a> */ @Deprecated public <H extends EventHandler> void removeHandler(X10GwtEvent.Type<H> type, final H handler) { if (firingDepth > 0) { enqueueRemove(type, handler); } else { doRemove(type, handler); } }
/** * Not part of the public API, available only to allow visualization tools * to be developed in gwt-incubator. * * @return a map of all handlers in this handler manager */ Map<X10GwtEvent.Type<?>, ArrayList<?>> createHandlerInfo() { return registry.map; }
private void defer(AddOrRemoveCommand command) { if (deferredDeltas == null) { deferredDeltas = new ArrayList<AddOrRemoveCommand>(); } deferredDeltas.add(command); }
private <H extends EventHandler> void doAdd(X10GwtEvent.Type<H> type, final H handler) { registry.addHandler(type, handler); }
private <H extends EventHandler> void doRemove(X10GwtEvent.Type<H> type, final H handler) { registry.removeHandler(type, handler); }
private <H extends EventHandler> void enqueueAdd(final X10GwtEvent.Type<H> type, final H handler) { defer(new AddOrRemoveCommand() { public EventHandler execute() { doAdd(type, handler); return handler; } }); }
private <H extends EventHandler> void enqueueRemove(final X10GwtEvent.Type<H> type, final H handler) { defer(new AddOrRemoveCommand() { public EventHandler execute() { doRemove(type, handler); return null; } }); }
@SuppressWarnings("unchecked") private <H extends EventHandler> List<H> handleQueuedAddsAndRemoves() { List<H> handlers = new ArrayList<H>(10); if (deferredDeltas != null) { try { for (AddOrRemoveCommand c : deferredDeltas) { EventHandler newHander = c.execute(); /*ISSUE 101*/ if(newHander != null){ handlers.add((H) newHander); } } } finally { deferredDeltas = null; } } return handlers; } }
|