| /* |
| * Copyright 2009 Google Inc. |
| * |
| * 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 com.google.gwt.event.dom.client; |
| |
| import com.google.gwt.dom.client.Element; |
| import com.google.gwt.dom.client.NativeEvent; |
| import com.google.gwt.event.shared.EventHandler; |
| import com.google.gwt.event.shared.GwtEvent; |
| import com.google.gwt.event.shared.HasHandlers; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * {@link DomEvent} is a subclass of {@link GwtEvent} that provides events that |
| * underlying native browser event object as well as a subclass of {@link Type} |
| * that understands GWT event bits used by sinkEvents(). |
| * |
| * @param <H> handler type |
| * |
| */ |
| public abstract class DomEvent<H extends EventHandler> extends GwtEvent<H> |
| implements HasNativeEvent { |
| |
| /** |
| * Type class used by dom event subclasses. Type is specialized for dom in |
| * order to carry information about the native event. |
| * |
| * @param <H> handler type |
| */ |
| public static class Type<H extends EventHandler> extends GwtEvent.Type<H> { |
| private DomEvent<H> flyweight; |
| private String name; |
| |
| /** |
| * This constructor allows dom event types to be triggered by the |
| * {@link DomEvent#fireNativeEvent(com.google.gwt.dom.client.NativeEvent, HasHandlers)} |
| * method. It should only be used by implementors supporting new dom events. |
| * |
| * <p> |
| * Any such dom event type must act as a flyweight around a native event |
| * object. |
| * </p> |
| * |
| * @param eventName the raw native event name |
| * @param flyweight the instance that will be used as a flyweight to wrap a |
| * native event |
| */ |
| public Type(String eventName, DomEvent<H> flyweight) { |
| this.flyweight = flyweight; |
| |
| // Until we have eager clinits implemented, we are manually initializing |
| // DomEvent here. |
| if (registered == null) { |
| init(); |
| } |
| List<Type<?>> types = registered.unsafeGet(eventName); |
| if (types == null) { |
| types = new ArrayList<Type<?>>(); |
| registered.unsafePut(eventName, types); |
| } |
| types.add(this); |
| name = eventName; |
| } |
| |
| /** |
| * Gets the name associated with this event type. |
| * |
| * @return the name of this event type |
| */ |
| public String getName() { |
| return name; |
| } |
| } |
| |
| private static PrivateMap<List<Type<?>>> registered; |
| |
| /** |
| * Fires the given native event on the specified handlers. |
| * |
| * @param nativeEvent the native event |
| * @param handlerSource the source of the handlers to fire |
| */ |
| public static void fireNativeEvent(NativeEvent nativeEvent, |
| HasHandlers handlerSource) { |
| fireNativeEvent(nativeEvent, handlerSource, null); |
| } |
| |
| /** |
| * Fires the given native event on the specified handlers. |
| * |
| * @param nativeEvent the native event |
| * @param handlerSource the source of the handlers to fire |
| * @param relativeElem the element relative to which event coordinates will be |
| * measured |
| */ |
| public static void fireNativeEvent(NativeEvent nativeEvent, |
| HasHandlers handlerSource, Element relativeElem) { |
| assert nativeEvent != null : "nativeEvent must not be null"; |
| |
| if (registered != null) { |
| List<Type<?>> types = registered.unsafeGet(nativeEvent.getType()); |
| if (types != null) { |
| for (DomEvent.Type<?> type : types) { |
| // Store and restore native event just in case we are in recursive |
| // loop. |
| NativeEvent currentNative = type.flyweight.nativeEvent; |
| Element currentRelativeElem = type.flyweight.relativeElem; |
| type.flyweight.setNativeEvent(nativeEvent); |
| type.flyweight.setRelativeElement(relativeElem); |
| |
| handlerSource.fireEvent(type.flyweight); |
| |
| type.flyweight.setNativeEvent(currentNative); |
| type.flyweight.setRelativeElement(currentRelativeElem); |
| } |
| } |
| } |
| } |
| |
| // This method can go away once we have eager clinits. |
| static void init() { |
| registered = new PrivateMap<List<Type<?>>>(); |
| } |
| |
| private NativeEvent nativeEvent; |
| private Element relativeElem; |
| |
| @Override |
| public abstract DomEvent.Type<H> getAssociatedType(); |
| |
| public final NativeEvent getNativeEvent() { |
| assertLive(); |
| return nativeEvent; |
| } |
| |
| /** |
| * Gets the element relative to which event coordinates will be measured. |
| * If this element is <code>null</code>, event coordinates will be measured |
| * relative to the window's client area. |
| * |
| * @return the event's relative element |
| */ |
| public final Element getRelativeElement() { |
| assertLive(); |
| return relativeElem; |
| } |
| |
| /** |
| * Prevents the wrapped native event's default action. |
| */ |
| public void preventDefault() { |
| assertLive(); |
| // If there is no native event object set, do nothing. There will be no |
| // default action anyway. |
| if (nativeEvent != null) { |
| nativeEvent.preventDefault(); |
| } |
| } |
| |
| /** |
| * Sets the native event associated with this dom event. In general, dom |
| * events should be fired using the static firing methods. |
| * |
| * @param nativeEvent the native event |
| */ |
| public final void setNativeEvent(NativeEvent nativeEvent) { |
| this.nativeEvent = nativeEvent; |
| } |
| |
| /** |
| * Gets the element relative to which event coordinates will be measured. |
| * |
| * @param relativeElem the event's relative element |
| */ |
| public void setRelativeElement(Element relativeElem) { |
| this.relativeElem = relativeElem; |
| } |
| |
| /** |
| * Stops the propagation of the underlying native event. |
| */ |
| public void stopPropagation() { |
| assertLive(); |
| nativeEvent.stopPropagation(); |
| } |
| } |