Author: [EMAIL PROTECTED] Date: Wed Nov 12 13:27:13 2008 New Revision: 4030
Removed: branches/1_6_clean_events/user/src/com/google/gwt/event/shared/JavaHandlerRegistry.java branches/1_6_clean_events/user/src/com/google/gwt/event/shared/JsHandlerRegistry.java Modified: branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java Log: Merging JavaHandlerRegistry and JsHandlerREgister into HandlerManager as private classes, adding privates where necessary. Modified: branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java ============================================================================== --- branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java (original) +++ branches/1_6_clean_events/user/src/com/google/gwt/event/shared/HandlerManager.java Wed Nov 12 13:27:13 2008 @@ -16,9 +16,11 @@ package com.google.gwt.event.shared; import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.event.shared.GwtEvent.Type; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; /** @@ -26,32 +28,251 @@ * handlers on passed in events. */ public class HandlerManager { - // Used to optimize the JavaScript handler container structure. - static int EXPECTED_HANDLERS = 5; - private static final boolean useJs = GWT.isClient(); - private static int index; - /** - * Is the given event live? - * - * @param event the event - * @return is the event live + * The default Handler manager's handler registry for running in Java code. */ - public static boolean isLive(GwtEvent<?> event) { - return event.isLive(); + private static class JavaHandlerRegistry extends + HashMap<GwtEvent.Type<?>, ArrayList<?>> { + + public <H extends EventHandler> void addHandler(Type<H> type, H handler) { + ArrayList<H> l = get(type); + if (l == null) { + l = new ArrayList<H>(); + super.put(type, l); + } + l.add(handler); + } + + public <H extends EventHandler> void fireEvent(GwtEvent<H> event) { + Type<H> type = event.getAssociatedType(); + int count = getHandlerCount(type); + for (int i = 0; i < count; i++) { + H handler = getHandler(type, i); + event.dispatch(handler); + } + } + + public <H extends EventHandler> H getHandler(GwtEvent.Type<H> eventKey, + int index) { + ArrayList<H> l = get(eventKey); + return l.get(index); + } + + public int getHandlerCount(GwtEvent.Type<?> eventKey) { + ArrayList<?> l = super.get(eventKey); + if (l == null) { + return 0; + } else { + return l.size(); + } + } + + public <H> void removeHandler(GwtEvent.Type<H> eventKey, H handler) { + ArrayList<H> l = get(eventKey); + if (l != null) { + l.remove(handler); + } + } + + @SuppressWarnings("unchecked") + private <H> ArrayList<H> get(GwtEvent.Type<H> type) { + // This cast is safe because we control the puts. + return (ArrayList<H>) super.get(type); + } } /** - * Revives the given event. + * Default JavaScript handler registry. This is in the shared class but should + * never be called outside of a GWT runtime environment. * - * @param event the event + * The JsHandlerRegistry makes use of the fact that in the large majority of + * cases, only one or two handlers are added for each event type. Therefore, + * rather than storing handlers in a list of lists, we store then in a single + * flattened array with an escape clause to handle the rare case where we have + * more handlers then expected. */ - public static void revive(GwtEvent<?> event) { - if (event.isLive() == false) { - event.revive(); + private static class JsHandlerRegistry extends JavaScriptObject { + + /** + * Required constructor. + */ + protected JsHandlerRegistry() { + } + + public final <H extends EventHandler> void addHandler( + HandlerManager manager, Type<H> type, H myHandler) { + + // The base is the equivalent to a c pointer into the flattened handler + // data structure. + int base = type.hashCode(); + int count = getCount(base); + boolean flattened = isFlattened(base); + H handler = myHandler; + // If we already have the maximum number of handlers we can store in the + // flattened data structure, store the handlers in an external list + // instead. + if ((count == EXPECTED_HANDLERS) & flattened) { + // As long as we are only adding to the end of a handler list, should + // not need to queue. + if (manager.firingDepth > 0) { + manager.enqueueAdd(type, myHandler); + return; + } + unflatten(base); + flattened = false; + } + if (flattened) { + setFlatHandler(base, count, handler); + } else { + setHandler(base, count, handler); + } + setCount(base, count + 1); + } + + public final <H extends EventHandler> void fireEvent(GwtEvent<H> event) { + Type<H> type = event.getAssociatedType(); + int base = type.hashCode(); + int count = getCount(base); + boolean isFlattened = isFlattened(base); + if (isFlattened) { + for (int i = 0; i < count; i++) { + // Gets the given handler to fire. + H handler = getFlatHandler(base, i); + // Fires the handler. + event.dispatch(handler); + } + } else { + JavaScriptObject handlers = getHandlers(base); + for (int i = 0; i < count; i++) { + // Gets the given handler to fire. + + H handler = getHandler(handlers, i); + + // Fires the handler. + event.dispatch(handler); + } + } + } + + public final <H extends EventHandler> H getHandler(GwtEvent.Type<H> type, + int index) { + int base = type.hashCode(); + int count = getCount(base); + if (index >= count) { + throw new IndexOutOfBoundsException("index: " + index); + } + return getHandler(base, index, isFlattened(base)); } + + public final int getHandlerCount(GwtEvent.Type<?> eventKey) { + return getCount(eventKey.hashCode()); + } + + public final <H> void removeHandler(GwtEvent.Type<H> eventKey, + EventHandler handler) { + int base = eventKey.hashCode(); + + // Removing a handler is unusual, so smaller code is preferable then + // handling both flat and dangling list of pointers. + if (isFlattened(base)) { + unflatten(base); + } + boolean result = removeHelper(base, handler); + // Hiding this behind an assertion as we'd rather not force the compiler + // to + // have to include all handler.toString() instances. + assert result : handler + " did not exist"; + } + + private native int getCount(int index) /*-{ + var count = this[index]; + return count == null? 0:count; + }-*/; + + private native <H extends EventHandler> H getFlatHandler(int base, int index) /*-{ + return this[base + 2 + index]; + }-*/; + + private native <H extends EventHandler> H getHandler(int base, int index, + boolean flattened) /*-{ + return flattened? this[base + 2 + index]: this[base + 1][index]; + }-*/; + + private native <H extends EventHandler> H getHandler( + JavaScriptObject handlers, int index) /*-{ + return handlers[index]; + }-*/; + + private native JavaScriptObject getHandlers(int base) /*-{ + return this[base + 1]; + }-*/; + + private native boolean isFlattened(int base) /*-{ + return this[base + 1] == null; + }-*/; + + private native boolean removeHelper(int base, EventHandler handler) /*-{ + // Find the handler. + var count = this[base]; + var handlerList = this[base + 1]; + var handlerIndex = -1; + for(var index = 0; index < count; index++){ + if(handlerList[index] == handler){ + handlerIndex = index; + break; + } + } + if(handlerIndex == -1) { + return false; + } + + // Remove the handler. + var last = count -1; + for(; handlerIndex < last; handlerIndex++){ + handlerList[handlerIndex] = handlerList[handlerIndex+1] + } + handlerList[last] = null; + this[base] = this[base]-1; + return true; + }-*/; + + private native void setCount(int index, int count) /*-{ + this[index] = count; + }-*/; + + private native void setFlatHandler(int base, int index, EventHandler handler) /*-{ + this[base + 2 + index] = handler; + }-*/; + + private native void setHandler(int base, int index, EventHandler handler) /*-{ + this[base + 1][index] = handler; + }-*/; + + private native void setHandlerList(int base, JavaScriptObject handlerList) /*-{ + this[base + 1] = handlerList; + }-*/; + + private native void unflatten(int base) /*-{ + var handlerList = {}; + var count = this[base]; + var start = base + 2; + for(var i = 0; i < count;i++){ + handlerList[i] = this[start + i]; + this[start + i] = null; + } + this[base + 1] = handlerList; + }-*/; } + // Used to optimize the JavaScript handler container structure. + private static int EXPECTED_HANDLERS = 5; + + private static final boolean useJs = GWT.isClient(); + + private static int index; + + // Used to assign hash codes to gwt event types so they are easy to store in a + // js structure. static int createKeyIndex() { // Need to leave space for the size and the unflattened list if we end up // needing it. @@ -59,12 +280,10 @@ return index; } - // package protected to allow it to be used in JsHandlerRegistry - int firingDepth = 0; - + private int firingDepth = 0; // Only one of JsHandlerRegistry and JavaHandlerRegistry are live at once. - private final JsHandlerRegistry javaScriptRegistry; - private final JavaHandlerRegistry javaRegistry; + private JsHandlerRegistry javaScriptRegistry; + private JavaHandlerRegistry javaRegistry; // source of the event. private final Object source; @@ -82,11 +301,9 @@ */ public HandlerManager(Object source) { if (useJs) { - javaScriptRegistry = JsHandlerRegistry.create(); - javaRegistry = null; + javaScriptRegistry = JavaScriptObject.createObject().cast(); } else { javaRegistry = new JavaHandlerRegistry(); - javaScriptRegistry = null; } this.source = source; } @@ -94,7 +311,7 @@ /** * Adds a handle. * - * @param <H> The type of handler. + * @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 @@ -102,16 +319,15 @@ */ public <H extends EventHandler> HandlerRegistration addHandler( GwtEvent.Type<H> type, final H handler) { - + /* * We used to keep the enqueue / dequeue entirely inside HandlerManager. * However, we found a 30% speed improvement in handler registration if * JsHandlerRegistry is allowed to make its own decision about queuing. Thus - * the funny code path here. + * the funny code path here. * - * No parallel optimization was made for removing handlers, as that - * rarely happens anyway, and is not a significant contributer to startup - * time. + * No parallel optimization was made for removing handlers, as that rarely + * happens anyway, and is not a significant contributer to startup time. */ if (useJs) { javaScriptRegistry.addHandler(this, type, handler); @@ -126,19 +342,6 @@ } /** - * Clears all the handlers associated with the given type. - * - * @param type the type - */ - public void clearHandlers(Type<?> type) { - if (useJs) { - javaScriptRegistry.clearHandlers(type); - } else { - javaRegistry.clearHandlers(type); - } - } - - /** * Fires the given event to the handlers listening to the event's type. * * @param event the event @@ -146,9 +349,9 @@ // Final so we can manage buffering adds and removes without a subclass // throwing all our calculations off. public final void fireEvent(GwtEvent<?> event) { - // If it not live we should clear the source and make it live. + // If it not live we should revive it. if (event.isLive() == false) { - revive(event); + event.revive(); } Object oldSource = event.getSource(); event.setSource(source); @@ -183,6 +386,9 @@ * @return the given handler */ public <H extends EventHandler> H getHandler(GwtEvent.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; if (useJs) { return javaScriptRegistry.getHandler(type, index); } else { @@ -223,6 +429,10 @@ * * @param type the event type * @param handler the handler + * @deprecated We currently believe this method will not be needed after + * listeners are removed in GWT 2.0. If you have a use case for it after that + * time, please add your comments to issue + * http://code.google.com/p/google-web-toolkit/issues/detail?id=3102 */ public <H extends EventHandler> void removeHandler(GwtEvent.Type<H> type, final H handler) { @@ -233,22 +443,21 @@ } } - // Package protected so JsHandlerRegistry can call enqueueAdd. - <H extends EventHandler> void enqueueAdd(GwtEvent.Type<H> type, - final H handler) { - if (addQueue == null) { - addQueue = new ArrayList<Object>(); - addQueue.add(type); - addQueue.add(handler); - } - } - private <H extends EventHandler> void doRemove(GwtEvent.Type<H> type, final H handler) { if (useJs) { javaScriptRegistry.removeHandler(type, handler); } else { javaRegistry.removeHandler(type, handler); + } + } + + private <H extends EventHandler> void enqueueAdd(GwtEvent.Type<H> type, + final H handler) { + if (addQueue == null) { + addQueue = new ArrayList<Object>(); + addQueue.add(type); + addQueue.add(handler); } } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---