EventSupportpublic 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. |
Fields Summary |
---|
public static final int | CAPTURE_PHASEOne of the values allowed for the phase parameter
in the addEventListener method | public static final int | BUBBLE_PHASEOne of the values allowed for the phase parameter
in the addEventListener method | protected Hashtable | allListenersMaps nodes to a map of listeners for a given event type | protected EventListener[] | freezeListTemporary array used to dispatch events. |
Methods Summary |
---|
void | addEventListener(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.
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 void | dispatchEvent(ModelEvent evt)Dispatches the input event to the listeners, performing a
capture and bubble phase, as defined by the DOM Level 2
event model.
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 void | fireBubble(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.
if (evt.getStopPropagation()) {
return;
}
fireEventListeners(currentTarget, evt, BUBBLE_PHASE);
if (currentTarget.parent != null) {
fireBubble(currentTarget.parent, evt);
}
| protected void | fireCapture(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.
if (currentTarget.parent != null) {
fireCapture(currentTarget.parent, evt);
}
if (!evt.getStopPropagation()) {
fireEventListeners(currentTarget, evt, CAPTURE_PHASE);
}
| protected void | fireEventListeners(ModelNode currentTarget, ModelEvent evt, int phase)Fires the event listeners attached to the input current target
// 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.Vector | getEventListeners(ModelNode node, int phase, ModelEvent evt)
// 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.
if (freezeList == null || freezeList.length < n) {
freezeList = new EventListener[n];
}
return freezeList;
| void | removeEventListener(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.
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);
}
|
|