001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.perseus.model;
028:
029: import java.util.Hashtable;
030: import java.util.Vector;
031:
032: import org.w3c.dom.events.EventListener;
033:
034: /**
035: * <code>EventSupport</code> assumes two functions. First, it offers
036: * a central place for listeners to register for specific event types on
037: * specific observers for a particular event propagation phase (capture
038: * or bubble). Second, it performs the event dispatching according to the
039: * DOM Level 2 Event model of capture, at target and bubbling.
040: *
041: * @version $Id: EventSupport.java,v 1.9 2006/06/29 10:47:31 ln156897 Exp $
042: */
043: class EventSupport {
044: /**
045: * One of the values allowed for the phase parameter
046: * in the addEventListener method
047: */
048: public static final int CAPTURE_PHASE = 0;
049:
050: /**
051: * One of the values allowed for the phase parameter
052: * in the addEventListener method
053: */
054: public static final int BUBBLE_PHASE = 1;
055:
056: /**
057: * Maps nodes to a map of listeners for a given event type
058: */
059: protected Hashtable allListeners = new Hashtable();
060:
061: /**
062: * Temporary array used to dispatch events.
063: */
064: protected EventListener[] freezeList;
065:
066: /**
067: * Implementation.
068: *
069: * @param n the minimal size needed for the returned freezeList
070: */
071: EventListener[] getFreezeList(final int n) {
072: if (freezeList == null || freezeList.length < n) {
073: freezeList = new EventListener[n];
074: }
075:
076: return freezeList;
077: }
078:
079: /**
080: * Removes an event listener from the input handler, for the given
081: * input event type and phase.
082: *
083: * @param handler the node on which the listener was hooked
084: * @param type the event type the listener was listening to
085: * @param phase the phase the listener was listening to
086: * @param listener the listener to be removed
087: */
088: void removeEventListener(ModelNode handler, final String type,
089: final int phase, final EventListener listener) {
090: if (handler == null) {
091: throw new NullPointerException();
092: }
093:
094: if (type == null) {
095: throw new NullPointerException();
096: }
097:
098: if (!(phase == BUBBLE_PHASE || phase == CAPTURE_PHASE)) {
099: throw new IllegalArgumentException();
100: }
101:
102: if (listener == null) {
103: throw new NullPointerException();
104: }
105:
106: // See the SVG 1.1 specification, section 5.6 "The use element". An
107: // element and all its corresponding SVGElementInstance objects share an
108: // event listener list.
109: if (handler instanceof ElementNodeProxy) {
110: handler = ((ElementNodeProxy) handler).proxied;
111: }
112:
113: Hashtable nodeListeners = (Hashtable) allListeners.get(handler);
114: if (nodeListeners == null) {
115: return;
116: }
117:
118: Vector[] evtTypeListeners = (Vector[]) nodeListeners.get(type);
119:
120: if (evtTypeListeners == null) {
121: return;
122: }
123:
124: Vector phaseListeners = evtTypeListeners[phase];
125:
126: // If phaseListeners is null, this means the listener was not registered
127: // for that phase. According to the DOM Events Level 2 spec, just ignore
128: // the request.
129: if (phaseListeners != null) {
130: phaseListeners.removeElement(listener);
131: }
132: }
133:
134: /**
135: * Adds a event listener on the input handler for the input event type
136: * and phase.
137: *
138: * @param handler the node on which the listener is hooked
139: * @param type the type of events to listen to. Should not be null
140: * @param phase the phase the listener listens to. Should be one
141: * of CAPTURE_PHASE or BUBBLE_PHASE
142: * @param listener the listener to hook to the handler
143: */
144: void addEventListener(ModelNode handler, final String type,
145: final int phase, final EventListener listener) {
146: if (handler == null) {
147: throw new NullPointerException();
148: }
149:
150: if (type == null) {
151: throw new NullPointerException();
152: }
153:
154: if (!(phase == CAPTURE_PHASE || phase == BUBBLE_PHASE)) {
155: throw new IllegalArgumentException();
156: }
157:
158: if (listener == null) {
159: throw new NullPointerException();
160: }
161:
162: // See the SVG 1.1 specification, section 5.6 "The use element". An
163: // element and all its corresponding SVGElementInstance objects share an
164: // event listener list.
165: if (handler instanceof ElementNodeProxy) {
166: handler = ((ElementNodeProxy) handler).proxied;
167: }
168:
169: Hashtable nodeListeners = (Hashtable) allListeners.get(handler);
170: if (nodeListeners == null) {
171: // Create entry if none exists for this node
172: nodeListeners = new Hashtable();
173: allListeners.put(handler, nodeListeners);
174: }
175:
176: Vector[] evtTypeListeners = (Vector[]) nodeListeners.get(type);
177:
178: if (evtTypeListeners == null) {
179: // Create array for listeners of this event
180: // type if none exists
181: evtTypeListeners = new Vector[2];
182: nodeListeners.put(type, evtTypeListeners);
183: }
184:
185: Vector phaseListeners = evtTypeListeners[phase];
186: if (phaseListeners == null) {
187: // Create vector for listeners on that phase
188: // if none exists
189: phaseListeners = new Vector(1);
190: evtTypeListeners[phase] = phaseListeners;
191: }
192:
193: if (!phaseListeners.contains(listener)) {
194: phaseListeners.addElement(listener);
195: }
196: }
197:
198: /**
199: * Debug. Traces all the registered listeners
200: */
201: /*
202: public void dumpListeners() {
203: Iterator iter = allListeners.keySet().iterator();
204: while (iter.hasNext()) {
205: Object node = iter.next();
206: Hashtable nodeListeners = (Hashtable) allListeners.get(node);
207: Iterator iter2 = nodeListeners.keySet().iterator();
208: System.out.println("Listeners for " + node);
209: while (iter2.hasNext()) {
210: Object type = iter2.next();
211: System.out.println("----> " + type);
212: Vector[] evtTypeListeners = (Vector[]) nodeListeners.get(type);
213: if (evtTypeListeners == null) {
214: System.out.println(" +--> (null)");
215: } else {
216: System.out.println(" +--> [capture]");
217: Vector captureListeners = evtTypeListeners[CAPTURE_PHASE];
218: if (captureListeners == null) {
219: System.out.println(" +--> null");
220: } else {
221: int n = captureListeners.size();
222: for (int i = 0; i < n; i++) {
223: System.out.println(" +--> "
224: + captureListeners.elementAt(i));
225: }
226: }
227:
228: System.out.println(" +--> [bubble]");
229: Vector bubbleListeners = evtTypeListeners[BUBBLE_PHASE];
230: if (bubbleListeners == null) {
231: System.out.println(" +--> null");
232: } else {
233: int n = bubbleListeners.size();
234: for (int i = 0; i < n; i++) {
235: System.out.println(" +--> "
236: + bubbleListeners.elementAt(i));
237: }
238: }
239:
240: }
241:
242: }
243: }
244: }
245: */
246:
247: /**
248: * Dispatches the input event to the listeners, performing a
249: * capture and bubble phase, as defined by the DOM Level 2
250: * event model.
251: *
252: * @param evt the event to dispatch
253: */
254: public void dispatchEvent(final ModelEvent evt) {
255: if (evt == null) {
256: return;
257: }
258:
259: // Note that an event type cannot be null,
260: // see the Event class.
261: String type = evt.getType();
262:
263: ModelNode target = (ModelNode) evt.getTarget();
264:
265: // CAPTURE PHASE
266: // ====================================================================
267: // Now, perform the capture phase
268: // We go from the root (last in the dynasty array)
269: // to the last element (immediate parent).
270: if (target.parent != null) {
271: fireCapture(target.parent, evt);
272: }
273:
274: // AT TARGET PHASE
275: // ====================================================================
276: if (!evt.getStopPropagation()) {
277: fireEventListeners(target, evt, CAPTURE_PHASE);
278: fireEventListeners(target, evt, BUBBLE_PHASE);
279: }
280:
281: // BUBBLE PHASE
282: // ====================================================================
283: if (target.parent != null) {
284: fireBubble(target.parent, evt);
285: }
286: }
287:
288: /**
289: * Fires the bubble event listeners on the input target. This starts
290: * by firing this node's listeners, then the parent bubble listeners and
291: * so on, up to the tree's root which has no parent.
292: *
293: * @param currentTarget the node on which the event should be dispatched
294: * unless the event propagation has been stopped.
295: * @param evt the event to dispatch.
296: */
297: protected void fireBubble(final ModelNode currentTarget,
298: final ModelEvent evt) {
299: if (evt.getStopPropagation()) {
300: return;
301: }
302:
303: fireEventListeners(currentTarget, evt, BUBBLE_PHASE);
304:
305: if (currentTarget.parent != null) {
306: fireBubble(currentTarget.parent, evt);
307: }
308: }
309:
310: /**
311: * Fires the capture event listeners on the input target. This starts
312: * by firing the node's parent capture listeners. As a result of this
313: * recursive behavior, the listeners on the tree root (which has no parent)
314: * are fired first, then listeners down the tree are fired.
315: *
316: * @param currentTarget the node on which the event should be dispatched
317: * unless the event propagation has been stopped.
318: * @param evt the event to dispatch.
319: */
320: protected void fireCapture(final ModelNode currentTarget,
321: final ModelEvent evt) {
322: if (currentTarget.parent != null) {
323: fireCapture(currentTarget.parent, evt);
324: }
325:
326: if (!evt.getStopPropagation()) {
327: fireEventListeners(currentTarget, evt, CAPTURE_PHASE);
328: }
329: }
330:
331: /**
332: * Fires the event listeners attached to the input current target
333: * @param currentTarget the node on which the event is currently flowing
334: * @param evt the event to propagate
335: * @param phase defines whether the event is propagating in the capture
336: * or bubble phase. One of CAPTURE_PHASE or BUBBLE_PHASE.
337: */
338: protected void fireEventListeners(final ModelNode currentTarget,
339: final ModelEvent evt, final int phase) {
340: // Update Href. Remember that the Event's anchor is sticky and
341: // cannot be changed once set
342: if (evt.getAnchor() == null && currentTarget instanceof Anchor) {
343: evt.setAnchor((Anchor) currentTarget);
344: }
345:
346: Vector listeners = getEventListeners(currentTarget, phase, evt);
347: if (listeners == null) {
348: return;
349: }
350:
351: // We use a copy of the list because event listeners may be removed
352: // during event dispatching.
353: int n = listeners.size();
354: EventListener[] freezeList = getFreezeList(n);
355: listeners.copyInto(freezeList);
356:
357: evt.currentTarget = currentTarget;
358:
359: for (int i = 0; i < n; i++) {
360: // The DOM Level 2 specification requires that an event listener
361: // never be called after it has been removed.
362: if (listeners.contains(freezeList[i])) {
363: freezeList[i].handleEvent(evt);
364: }
365: }
366: }
367:
368: /**
369: * @param node the ModelNode on which listeners are seeked
370: * @param phase the event propagation phase for which listeners are
371: * seeked.
372: * @param evt the event
373: * @return a Vector of EventListener registered on the input node,
374: * for the given phase and the given event type.
375: */
376: protected Vector getEventListeners(ModelNode node, final int phase,
377: final ModelEvent evt) {
378: // See the SVG 1.1 specification, section 5.6 "The use element". An
379: // element and all its corresponding SVGElementInstance objects share an
380: // event listener list.
381: if (node instanceof ElementNodeProxy) {
382: node = ((ElementNodeProxy) node).proxied;
383: }
384:
385: Hashtable nodeListeners = (Hashtable) allListeners.get(node);
386: if (nodeListeners == null) {
387: return null;
388: }
389:
390: Vector[] evtTypeListeners = (Vector[]) nodeListeners.get(evt
391: .getType());
392: if (evtTypeListeners == null) {
393: return null;
394: }
395:
396: return evtTypeListeners[phase];
397: }
398: }
|