FileDocCategorySizeDatePackage
EventSupport.javaAPI DocphoneME MR2 API (J2ME)14525Wed May 02 18:00:36 BST 2007com.sun.perseus.model

EventSupport

public class EventSupport extends Object
EventSupport assumes two functions. First, it offers a central place for listeners to register for specific event types on specific observers for a particular event propagation phase (capture or bubble). Second, it performs the event dispatching according to the DOM Level 2 Event model of capture, at target and bubbling.
version
$Id: EventSupport.java,v 1.9 2006/06/29 10:47:31 ln156897 Exp $

Fields Summary
public static final int
CAPTURE_PHASE
One of the values allowed for the phase parameter in the addEventListener method
public static final int
BUBBLE_PHASE
One of the values allowed for the phase parameter in the addEventListener method
protected Hashtable
allListeners
Maps nodes to a map of listeners for a given event type
protected EventListener[]
freezeList
Temporary array used to dispatch events.
Constructors Summary
Methods Summary
voidaddEventListener(ModelNode handler, java.lang.String type, int phase, org.w3c.dom.events.EventListener listener)
Adds a event listener on the input handler for the input event type and phase.

param
handler the node on which the listener is hooked
param
type the type of events to listen to. Should not be null
param
phase the phase the listener listens to. Should be one of CAPTURE_PHASE or BUBBLE_PHASE
param
listener the listener to hook to the handler

        if (handler == null) {
            throw new NullPointerException();
        }

        if (type == null) {
            throw new NullPointerException();
        }

        if (!(phase == CAPTURE_PHASE || phase == BUBBLE_PHASE)) {
            throw new IllegalArgumentException();
        }

        if (listener == null) {
            throw new NullPointerException();
        }

        // See the SVG 1.1 specification, section 5.6 "The use element".  An
        // element and all its corresponding SVGElementInstance objects share an
        // event listener list.
        if (handler instanceof ElementNodeProxy) {
            handler = ((ElementNodeProxy) handler).proxied;
        }

        Hashtable nodeListeners = (Hashtable) allListeners.get(handler);
        if (nodeListeners == null) {
            // Create entry if none exists for this node
            nodeListeners = new Hashtable();
            allListeners.put(handler, nodeListeners);
        }

        Vector[] evtTypeListeners = 
            (Vector[]) nodeListeners.get(type);

        if (evtTypeListeners == null) {
            // Create array for listeners of this event
            // type if none exists
            evtTypeListeners = new Vector[2];
            nodeListeners.put(type, evtTypeListeners);
        }

        Vector phaseListeners = evtTypeListeners[phase];
        if (phaseListeners == null) {
            // Create vector for listeners on that phase
            // if none exists
            phaseListeners = new Vector(1);
            evtTypeListeners[phase] = phaseListeners;
        }

        if (!phaseListeners.contains(listener)) {
            phaseListeners.addElement(listener);
        }
    
public voiddispatchEvent(ModelEvent evt)
Dispatches the input event to the listeners, performing a capture and bubble phase, as defined by the DOM Level 2 event model.

param
evt the event to dispatch

        if (evt == null) {
            return;
        }

        // Note that an event type cannot be null,
        // see the Event class.
        String type = evt.getType();

        ModelNode target = (ModelNode) evt.getTarget();

        // CAPTURE PHASE
        // ====================================================================
        // Now, perform the capture phase
        // We go from the root (last in the dynasty array)
        // to the last element (immediate parent).
        if (target.parent != null) {
            fireCapture(target.parent, evt);
        }
        
        // AT TARGET PHASE
        // ====================================================================
        if (!evt.getStopPropagation()) {
            fireEventListeners(target, evt, CAPTURE_PHASE);
            fireEventListeners(target, evt, BUBBLE_PHASE);
        }

        // BUBBLE PHASE
        // ====================================================================
        if (target.parent != null) {
            fireBubble(target.parent, evt);
        }
    
protected voidfireBubble(ModelNode currentTarget, ModelEvent evt)
Fires the bubble event listeners on the input target. This starts by firing this node's listeners, then the parent bubble listeners and so on, up to the tree's root which has no parent.

param
currentTarget the node on which the event should be dispatched unless the event propagation has been stopped.
param
evt the event to dispatch.

        if (evt.getStopPropagation()) {
            return;
        }

        fireEventListeners(currentTarget, evt, BUBBLE_PHASE);

        if (currentTarget.parent != null) {
            fireBubble(currentTarget.parent, evt);
        }
    
protected voidfireCapture(ModelNode currentTarget, ModelEvent evt)
Fires the capture event listeners on the input target. This starts by firing the node's parent capture listeners. As a result of this recursive behavior, the listeners on the tree root (which has no parent) are fired first, then listeners down the tree are fired.

param
currentTarget the node on which the event should be dispatched unless the event propagation has been stopped.
param
evt the event to dispatch.

        if (currentTarget.parent != null) {
            fireCapture(currentTarget.parent, evt);
        }
        
        if (!evt.getStopPropagation()) {
            fireEventListeners(currentTarget, evt, CAPTURE_PHASE);
        }
    
protected voidfireEventListeners(ModelNode currentTarget, ModelEvent evt, int phase)
Fires the event listeners attached to the input current target

param
currentTarget the node on which the event is currently flowing
param
evt the event to propagate
param
phase defines whether the event is propagating in the capture or bubble phase. One of CAPTURE_PHASE or BUBBLE_PHASE.

        // Update Href. Remember that the Event's anchor is sticky and 
        // cannot be changed once set
        if (evt.getAnchor() == null && currentTarget instanceof Anchor) {
            evt.setAnchor((Anchor) currentTarget);
        }
 
        Vector listeners = getEventListeners(currentTarget,
                                             phase,
                                             evt);
        if (listeners == null) {
            return;
        }

        // We use a copy of the list because event listeners may be removed
        // during event dispatching.
        int n = listeners.size();
        EventListener[] freezeList = getFreezeList(n);
        listeners.copyInto(freezeList);

        evt.currentTarget = currentTarget;

        for (int i = 0; i < n; i++) {
            // The DOM Level 2 specification requires that an event listener
            // never be called after it has been removed.
            if (listeners.contains(freezeList[i])) {
                freezeList[i].handleEvent(evt);
            }
        }
    
protected java.util.VectorgetEventListeners(ModelNode node, int phase, ModelEvent evt)

param
node the ModelNode on which listeners are seeked
param
phase the event propagation phase for which listeners are seeked.
param
evt the event
return
a Vector of EventListener registered on the input node, for the given phase and the given event type.

        // See the SVG 1.1 specification, section 5.6 "The use element".  An
        // element and all its corresponding SVGElementInstance objects share an
        // event listener list.
        if (node instanceof ElementNodeProxy) {
            node = ((ElementNodeProxy) node).proxied;
        }

        Hashtable nodeListeners = (Hashtable) allListeners.get(node);
        if (nodeListeners == null) {
            return null;
        }

        Vector[] evtTypeListeners = (Vector[]) nodeListeners.get(evt.getType());
        if (evtTypeListeners == null) {
            return null;
        }

        return evtTypeListeners[phase];
    
org.w3c.dom.events.EventListener[]getFreezeList(int n)
Implementation.

param
n the minimal size needed for the returned freezeList


                    
        
        if (freezeList == null || freezeList.length < n) {
            freezeList = new EventListener[n];
        }

        return freezeList;
    
voidremoveEventListener(ModelNode handler, java.lang.String type, int phase, org.w3c.dom.events.EventListener listener)
Removes an event listener from the input handler, for the given input event type and phase.

param
handler the node on which the listener was hooked
param
type the event type the listener was listening to
param
phase the phase the listener was listening to
param
listener the listener to be removed

        if (handler == null) {
            throw new NullPointerException();
        }

        if (type == null) {
            throw new NullPointerException();
        }

        if (!(phase == BUBBLE_PHASE || phase == CAPTURE_PHASE)) {
            throw new IllegalArgumentException();
        }

        if (listener == null) {
            throw new NullPointerException();
        }

        // See the SVG 1.1 specification, section 5.6 "The use element".  An
        // element and all its corresponding SVGElementInstance objects share an
        // event listener list.
        if (handler instanceof ElementNodeProxy) {
            handler = ((ElementNodeProxy) handler).proxied;
        }

        Hashtable nodeListeners = (Hashtable) allListeners.get(handler);
        if (nodeListeners == null) {
            return;
        }

        Vector[] evtTypeListeners =
            (Vector[]) nodeListeners.get(type);

        if (evtTypeListeners == null) {
            return;
        }

        Vector phaseListeners = evtTypeListeners[phase];

        // If phaseListeners is null, this means the listener was not registered
        // for that phase. According to the DOM Events Level 2 spec, just ignore
        // the request.
        if (phaseListeners != null) {
            phaseListeners.removeElement(listener);
        }