~ubuntu-branches/ubuntu/karmic/batik/karmic

« back to all changes in this revision

Viewing changes to sources/org/apache/batik/dom/svg12/XBLEventSupport.java

  • Committer: Bazaar Package Importer
  • Author(s): Matvey Kozhev, Onkar Shinde, Matvey Kozhev
  • Date: 2008-07-19 01:03:05 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080719010305-0b24skqy185kdsb9
Tags: 1.7.dfsg-0ubuntu1
[ Onkar Shinde ]
* New upstream version (LP: #147818)
* debian/control
  - Add Sun JDK 1.5 as build dependency. Fixes FTBFS on buildd. (LP: #150484)
    Also add Sun JRE as runtime dependencies.
  - Add ant-optional as build dependency.
  - Add libxml-commons-external-java and libxmlgraphics-commons-java as
    build and runtime dependencies.
  - Add 'Homepage' field and correct the url.
  - Change standards version to 3.8.0.
  - Modify Maintainer value to match the DebianMaintainerField
    specification.
* debian/rules
  - Change JAVA_HOME_DIRS for Sun JDK.
  - Add jar file names to DEB_JARS to match new build requirements.
  - Extract version from changelog.
  - Delete bundled jar files in clean target.
  - Don't use hardcoded version in install target.
  - Add get-orig-source target.
* debian/README.Debian-source
  - Change the fo tag name to the one used for this version.
* debian/watch
  - Change expression to match src distribution.
* debian/patches/
  - 01_build_xml.patch, 02_fix_jar_target.patch - Refresh for current source.
  - 03_fix_lib_dirs.patch - Fix the library and classpath references needed
    for pdf transcoder build.
  - 04_fix_transcoder_pkg.patch - Fix transcoder-pkg target to not copy
    files from other jar files.

[ Matvey Kozhev ]
* debian/changelog:
  - Added ".dfsg" to version.
* debian/control, debian/rules:
  - Build with openjdk-6-jdk, depend on openjdk-6-jre.
  - Added java-6-sun as an alternate build JAVA_HOME directory.
  - Fixed get-orig-source to not include debian/ and delete the source dir,
    and made it delete jars from lib/, as done in the current batik package.
* debian/wrappers.sh:
  - Changed java-7-icedtea reference to java-6-openjdk, as the former has been
    removed back in Hardy.
  - Added newline.
* debian/libbatik-java.install:
  - Added newline.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
   Licensed to the Apache Software Foundation (ASF) under one or more
 
4
   contributor license agreements.  See the NOTICE file distributed with
 
5
   this work for additional information regarding copyright ownership.
 
6
   The ASF licenses this file to You under the Apache License, Version 2.0
 
7
   (the "License"); you may not use this file except in compliance with
 
8
   the License.  You may obtain a copy of the License at
 
9
 
 
10
       http://www.apache.org/licenses/LICENSE-2.0
 
11
 
 
12
   Unless required by applicable law or agreed to in writing, software
 
13
   distributed under the License is distributed on an "AS IS" BASIS,
 
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
15
   See the License for the specific language governing permissions and
 
16
   limitations under the License.
 
17
 
 
18
 */
 
19
package org.apache.batik.dom.svg12;
 
20
 
 
21
import java.util.HashSet;
 
22
 
 
23
import org.apache.batik.dom.AbstractNode;
 
24
import org.apache.batik.dom.events.AbstractEvent;
 
25
import org.apache.batik.dom.events.EventListenerList;
 
26
import org.apache.batik.dom.events.EventSupport;
 
27
import org.apache.batik.dom.events.NodeEventTarget;
 
28
import org.apache.batik.dom.util.HashTable;
 
29
import org.apache.batik.dom.xbl.NodeXBL;
 
30
import org.apache.batik.dom.xbl.ShadowTreeEvent;
 
31
import org.apache.batik.util.XMLConstants;
 
32
 
 
33
import org.w3c.dom.DOMException;
 
34
import org.w3c.dom.Node;
 
35
import org.w3c.dom.NodeList;
 
36
import org.w3c.dom.events.Event;
 
37
import org.w3c.dom.events.EventException;
 
38
import org.w3c.dom.events.EventListener;
 
39
import org.w3c.dom.events.MutationEvent;
 
40
 
 
41
/**
 
42
 * An EventSupport class that handles XBL-specific event processing.
 
43
 *
 
44
 * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
 
45
 * @version $Id: XBLEventSupport.java 601207 2007-12-05 04:57:31Z cam $
 
46
 */
 
47
public class XBLEventSupport extends EventSupport {
 
48
 
 
49
    /**
 
50
     * The unstoppable capturing listeners table.
 
51
     */
 
52
    protected HashTable capturingImplementationListeners;
 
53
 
 
54
    /**
 
55
     * The unstoppable bubbling listeners table.
 
56
     */
 
57
    protected HashTable bubblingImplementationListeners;
 
58
 
 
59
    /**
 
60
     * Map of event types to their aliases.
 
61
     */
 
62
    protected static HashTable eventTypeAliases = new HashTable();
 
63
    static {
 
64
        eventTypeAliases.put("SVGLoad",   "load");
 
65
        eventTypeAliases.put("SVGUnoad",  "unload");
 
66
        eventTypeAliases.put("SVGAbort",  "abort");
 
67
        eventTypeAliases.put("SVGError",  "error");
 
68
        eventTypeAliases.put("SVGResize", "resize");
 
69
        eventTypeAliases.put("SVGScroll", "scroll");
 
70
        eventTypeAliases.put("SVGZoom",   "zoom");
 
71
    }
 
72
 
 
73
    /**
 
74
     * Creates a new XBLEventSupport object.
 
75
     */
 
76
    public XBLEventSupport(AbstractNode n) {
 
77
        super(n);
 
78
    }
 
79
 
 
80
    /**
 
81
     * Registers an event listener for the given namespaced event type
 
82
     * in the specified group.
 
83
     */
 
84
    public void addEventListenerNS(String namespaceURI,
 
85
                                   String type,
 
86
                                   EventListener listener,
 
87
                                   boolean useCapture,
 
88
                                   Object group) {
 
89
        super.addEventListenerNS
 
90
            (namespaceURI, type, listener, useCapture, group);
 
91
        if (namespaceURI == null
 
92
                || namespaceURI.equals(XMLConstants.XML_EVENTS_NAMESPACE_URI)) {
 
93
            String alias = (String) eventTypeAliases.get(type);
 
94
            if (alias != null) {
 
95
                super.addEventListenerNS
 
96
                    (namespaceURI, alias, listener, useCapture, group);
 
97
            }
 
98
        }
 
99
    }
 
100
 
 
101
    /**
 
102
     * Deregisters an event listener.
 
103
     */
 
104
    public void removeEventListenerNS(String namespaceURI,
 
105
                                      String type,
 
106
                                      EventListener listener,
 
107
                                      boolean useCapture) {
 
108
        super.removeEventListenerNS(namespaceURI, type, listener, useCapture);
 
109
        if (namespaceURI == null
 
110
                || namespaceURI.equals(XMLConstants.XML_EVENTS_NAMESPACE_URI)) {
 
111
            String alias = (String) eventTypeAliases.get(type);
 
112
            if (alias != null) {
 
113
                super.removeEventListenerNS
 
114
                    (namespaceURI, alias, listener, useCapture);
 
115
            }
 
116
        }
 
117
    }
 
118
 
 
119
    /**
 
120
     * Registers an event listener that will not be stopped by the usual
 
121
     * XBL stopping.
 
122
     */
 
123
    public void addImplementationEventListenerNS(String namespaceURI,
 
124
                                                 String type,
 
125
                                                 EventListener listener,
 
126
                                                 boolean useCapture) {
 
127
        HashTable listeners;
 
128
        if (useCapture) {
 
129
            if (capturingImplementationListeners == null) {
 
130
                capturingImplementationListeners = new HashTable();
 
131
            }
 
132
            listeners = capturingImplementationListeners;
 
133
        } else {
 
134
            if (bubblingImplementationListeners == null) {
 
135
                bubblingImplementationListeners = new HashTable();
 
136
            }
 
137
            listeners = bubblingImplementationListeners;
 
138
        }
 
139
        EventListenerList list = (EventListenerList) listeners.get(type);
 
140
        if (list == null) {
 
141
            list = new EventListenerList();
 
142
            listeners.put(type, list);
 
143
        }
 
144
        list.addListener(namespaceURI, null, listener);
 
145
    }
 
146
 
 
147
    /**
 
148
     * Unregisters an implementation event listener.
 
149
     */
 
150
    public void removeImplementationEventListenerNS(String namespaceURI,
 
151
                                                    String type,
 
152
                                                    EventListener listener,
 
153
                                                    boolean useCapture) {
 
154
        HashTable listeners = useCapture ? capturingImplementationListeners
 
155
                                         : bubblingImplementationListeners;
 
156
        if (listeners == null) {
 
157
            return;
 
158
        }
 
159
        EventListenerList list = (EventListenerList) listeners.get(type);
 
160
        if (list == null) {
 
161
            return;
 
162
        }
 
163
        list.removeListener(namespaceURI, listener);
 
164
        if (list.size() == 0) {
 
165
            listeners.remove(type);
 
166
        }
 
167
    }
 
168
 
 
169
    /**
 
170
     * Moves all of the event listeners from this EventSupport object
 
171
     * to the given EventSupport object.
 
172
     * Used by {@link
 
173
     * org.apache.batik.dom.AbstractDocument#renameNode(Node,String,String)}.
 
174
     */
 
175
    public void moveEventListeners(EventSupport other) {
 
176
        super.moveEventListeners(other);
 
177
        XBLEventSupport es = (XBLEventSupport) other;
 
178
        es.capturingImplementationListeners = capturingImplementationListeners;
 
179
        es.bubblingImplementationListeners = bubblingImplementationListeners;
 
180
        capturingImplementationListeners = null;
 
181
        bubblingImplementationListeners = null;
 
182
    }
 
183
 
 
184
    /**
 
185
     * This method allows the dispatch of events into the
 
186
     * implementations event model. Events dispatched in this manner
 
187
     * will have the same capturing and bubbling behavior as events
 
188
     * dispatched directly by the implementation. The target of the
 
189
     * event is the <code> EventTarget</code> on which
 
190
     * <code>dispatchEvent</code> is called.
 
191
     *
 
192
     * @param target the target node
 
193
     * @param evt Specifies the event type, behavior, and contextual
 
194
     * information to be used in processing the event.
 
195
     *
 
196
     * @return The return value of <code>dispatchEvent</code>
 
197
     * indicates whether any of the listeners which handled the event
 
198
     * called <code>preventDefault</code>.  If
 
199
     * <code>preventDefault</code> was called the value is false, else
 
200
     * the value is true.
 
201
     *
 
202
     * @exception EventException
 
203
     *   UNSPECIFIED_EVENT_TYPE_ERR: Raised if the
 
204
     *   <code>Event</code>'s type was not specified by initializing
 
205
     *   the event before <code>dispatchEvent</code> was
 
206
     *   called. Specification of the <code>Event</code>'s type as
 
207
     *   <code>null</code> or an empty string will also trigger this
 
208
     *   exception.  
 
209
     */
 
210
    public boolean dispatchEvent(NodeEventTarget target, Event evt) 
 
211
            throws EventException {
 
212
//         System.err.println("\t[] dispatching " + e.getType() + " on " + ((Node) target).getNodeName());
 
213
        if (evt == null) {
 
214
            return false;
 
215
        }
 
216
        if (!(evt instanceof AbstractEvent)) {
 
217
            throw createEventException
 
218
                (DOMException.NOT_SUPPORTED_ERR,
 
219
                 "unsupported.event",
 
220
                 new Object[] {});
 
221
        }
 
222
        AbstractEvent e = (AbstractEvent) evt;
 
223
        String type = e.getType();
 
224
        if (type == null || type.length() == 0) {
 
225
            throw createEventException
 
226
                (EventException.UNSPECIFIED_EVENT_TYPE_ERR,
 
227
                 "unspecified.event",
 
228
                 new Object[] {});
 
229
        }
 
230
        // fix event status
 
231
        setTarget(e, target);
 
232
        stopPropagation(e, false);
 
233
        stopImmediatePropagation(e, false);
 
234
        preventDefault(e, false);
 
235
        // dump the tree hierarchy from top to the target
 
236
        NodeEventTarget[] ancestors = getAncestors(target);
 
237
        int bubbleLimit = e.getBubbleLimit();
 
238
        int minAncestor = 0;
 
239
        if (isSingleScopeEvent(e)) {
 
240
            // DOM Mutation events are dispatched only within the
 
241
            // one shadow scope
 
242
            AbstractNode targetNode = (AbstractNode) target;
 
243
            Node boundElement = targetNode.getXblBoundElement();
 
244
            if (boundElement != null) {
 
245
                minAncestor = ancestors.length;
 
246
                while (minAncestor > 0) {
 
247
                    AbstractNode ancestorNode =
 
248
                        (AbstractNode) ancestors[minAncestor - 1];
 
249
                    if (ancestorNode.getXblBoundElement() != boundElement) {
 
250
                        break;
 
251
                    }
 
252
                    minAncestor--;
 
253
                }
 
254
            }
 
255
        } else if (bubbleLimit != 0) {
 
256
            // Other events may have a bubble limit (such as UI events)
 
257
            minAncestor = ancestors.length - bubbleLimit + 1;
 
258
            if (minAncestor < 0) {
 
259
                minAncestor = 0;
 
260
            }
 
261
        }
 
262
//         System.err.println("\t== ancestors:");
 
263
//         for (int i = 0; i < ancestors.length; i++) {
 
264
//             if (i < minAncestor) {
 
265
//                 System.err.print("\t     ");
 
266
//             } else {
 
267
//                 System.err.print("\t   * ");
 
268
//             }
 
269
//             System.err.println(((Node) ancestors[i]).getNodeName());
 
270
//         }
 
271
        AbstractEvent[] es = getRetargettedEvents(target, ancestors, e);
 
272
        boolean preventDefault = false;
 
273
        // CAPTURING_PHASE : fire event listeners from top to EventTarget
 
274
        HashSet stoppedGroups = new HashSet();
 
275
        HashSet toBeStoppedGroups = new HashSet();
 
276
        for (int i = 0; i < minAncestor; i++) {
 
277
            NodeEventTarget node = ancestors[i];
 
278
//             System.err.println("\t--   CAPTURING " + e.getType() + "  " + ((Node) node).getNodeName());
 
279
            setCurrentTarget(es[i], node);
 
280
            setEventPhase(es[i], Event.CAPTURING_PHASE);
 
281
            fireImplementationEventListeners(node, es[i], true);
 
282
        }
 
283
        for (int i = minAncestor; i < ancestors.length; i++) {
 
284
            NodeEventTarget node = ancestors[i];
 
285
//             System.err.println("\t-- * CAPTURING " + e.getType() + "  " + ((Node) node).getNodeName());
 
286
            setCurrentTarget(es[i], node);
 
287
            setEventPhase(es[i], Event.CAPTURING_PHASE);
 
288
            fireImplementationEventListeners(node, es[i], true);
 
289
            fireEventListeners(node, es[i], true, stoppedGroups,
 
290
                               toBeStoppedGroups);
 
291
            fireHandlerGroupEventListeners(node, es[i], true, stoppedGroups,
 
292
                                           toBeStoppedGroups);
 
293
            preventDefault = preventDefault || es[i].getDefaultPrevented();
 
294
            stoppedGroups.addAll(toBeStoppedGroups);
 
295
            toBeStoppedGroups.clear();
 
296
        }
 
297
        // AT_TARGET : fire local event listeners
 
298
//         System.err.println("\t-- * AT_TARGET " + e.getType() + "  " + ((Node) target).getNodeName());
 
299
        setEventPhase(e, Event.AT_TARGET);
 
300
        setCurrentTarget(e, target);
 
301
        fireImplementationEventListeners(target, e, false);
 
302
        fireEventListeners(target, e, false, stoppedGroups,
 
303
                           toBeStoppedGroups);
 
304
        fireHandlerGroupEventListeners(node, e, false, stoppedGroups,
 
305
                                       toBeStoppedGroups);
 
306
        stoppedGroups.addAll(toBeStoppedGroups);
 
307
        toBeStoppedGroups.clear();
 
308
        preventDefault = preventDefault || e.getDefaultPrevented();
 
309
        // BUBBLING_PHASE : fire event listeners from target to top
 
310
        if (e.getBubbles()) {
 
311
            for (int i = ancestors.length - 1; i >= minAncestor; i--) {
 
312
                NodeEventTarget node = ancestors[i];
 
313
//                 System.err.println("\t-- * BUBBLING  " + e.getType() + "  " + ((Node) node).getNodeName());
 
314
                setCurrentTarget(es[i], node);
 
315
                setEventPhase(es[i], Event.BUBBLING_PHASE);
 
316
                fireImplementationEventListeners(node, es[i], false);
 
317
                fireEventListeners(node, es[i], false, stoppedGroups,
 
318
                                   toBeStoppedGroups);
 
319
                fireHandlerGroupEventListeners
 
320
                    (node, es[i], false, stoppedGroups, toBeStoppedGroups);
 
321
                preventDefault =
 
322
                    preventDefault || es[i].getDefaultPrevented();
 
323
                stoppedGroups.addAll(toBeStoppedGroups);
 
324
                toBeStoppedGroups.clear();
 
325
            }
 
326
            for (int i = minAncestor - 1; i >= 0; i--) {
 
327
                NodeEventTarget node = ancestors[i];
 
328
//                 System.err.println("\t--   BUBBLING  " + e.getType() + "  " + ((Node) node).getNodeName());
 
329
                setCurrentTarget(es[i], node);
 
330
                setEventPhase(es[i], Event.BUBBLING_PHASE);
 
331
                fireImplementationEventListeners(node, es[i], false);
 
332
                preventDefault =
 
333
                    preventDefault || es[i].getDefaultPrevented();
 
334
            }
 
335
        }
 
336
        if (!preventDefault) {
 
337
            runDefaultActions(e);
 
338
        }
 
339
        return preventDefault;
 
340
    }
 
341
 
 
342
    /**
 
343
     * Fires the event handlers registered on an XBL 'handlerGroup' element.
 
344
     */
 
345
    protected void fireHandlerGroupEventListeners(NodeEventTarget node, 
 
346
                                                  AbstractEvent e,
 
347
                                                  boolean useCapture,
 
348
                                                  HashSet stoppedGroups,
 
349
                                                  HashSet toBeStoppedGroups) {
 
350
        // get the XBL definitions in effect for the event target
 
351
        NodeList defs = ((NodeXBL) node).getXblDefinitions();
 
352
        for (int j = 0; j < defs.getLength(); j++) {
 
353
            // find the 'handlerGroup' element
 
354
            Node n = defs.item(j).getFirstChild();
 
355
            while (n != null &&
 
356
                    !(n instanceof XBLOMHandlerGroupElement)) {
 
357
                n = n.getNextSibling();
 
358
            }
 
359
            if (n == null) {
 
360
                continue;
 
361
            }
 
362
            node = (NodeEventTarget) n;
 
363
            String type = e.getType();
 
364
            EventSupport support = node.getEventSupport();
 
365
            // check if the event support has been instantiated
 
366
            if (support == null) {
 
367
                continue;
 
368
            }
 
369
            EventListenerList list = support.getEventListeners(type, useCapture);
 
370
            // check if the event listeners list is not empty
 
371
            if (list == null) {
 
372
                return;
 
373
            }
 
374
            // dump event listeners, we get the registered listeners NOW
 
375
            EventListenerList.Entry[] listeners = list.getEventListeners();
 
376
            fireEventListeners(node, e, listeners, stoppedGroups,
 
377
                               toBeStoppedGroups);
 
378
        }
 
379
    }
 
380
 
 
381
    /**
 
382
     * Returns whether the given event should be stopped once it crosses
 
383
     * a shadow scope boundary.
 
384
     */
 
385
    protected boolean isSingleScopeEvent(Event evt) {
 
386
        return evt instanceof MutationEvent
 
387
            || evt instanceof ShadowTreeEvent;
 
388
    }
 
389
 
 
390
    /**
 
391
     * Returns an array of Event objects to be used for each event target
 
392
     * in the event flow.  The Event objects are retargetted if an sXBL
 
393
     * shadow scope is crossed and the event is not a DOM mutation event.
 
394
     */
 
395
    protected AbstractEvent[] getRetargettedEvents(NodeEventTarget target,
 
396
                                                   NodeEventTarget[] ancestors,
 
397
                                                   AbstractEvent e) {
 
398
        boolean singleScope = isSingleScopeEvent(e);
 
399
        AbstractNode targetNode = (AbstractNode) target;
 
400
        AbstractEvent[] es = new AbstractEvent[ancestors.length];
 
401
        if (ancestors.length > 0) {
 
402
            int index = ancestors.length - 1;
 
403
            Node boundElement = targetNode.getXblBoundElement();
 
404
            AbstractNode ancestorNode = (AbstractNode) ancestors[index];
 
405
            if (!singleScope &&
 
406
                    ancestorNode.getXblBoundElement() != boundElement) {
 
407
                es[index] = retargetEvent(e, ancestors[index]);
 
408
            } else {
 
409
                es[index] = e;
 
410
            }
 
411
            while (--index >= 0) {
 
412
                ancestorNode = (AbstractNode) ancestors[index + 1];
 
413
                boundElement = ancestorNode.getXblBoundElement();
 
414
                AbstractNode nextAncestorNode = (AbstractNode) ancestors[index];
 
415
                Node nextBoundElement = nextAncestorNode.getXblBoundElement();
 
416
                if (!singleScope && nextBoundElement != boundElement) {
 
417
                    es[index] = retargetEvent(es[index + 1], ancestors[index]);
 
418
                } else {
 
419
                    es[index] = es[index + 1];
 
420
                }
 
421
            }
 
422
        }
 
423
        return es;
 
424
    }
 
425
 
 
426
    /**
 
427
     * Clones and retargets the given event.
 
428
     */
 
429
    protected AbstractEvent retargetEvent(AbstractEvent e,
 
430
                                          NodeEventTarget target) {
 
431
        AbstractEvent clonedEvent = e.cloneEvent();
 
432
        setTarget(clonedEvent, target);
 
433
        return clonedEvent;
 
434
    }
 
435
    
 
436
    /**
 
437
     * Returns the implementation listneers.
 
438
     */
 
439
    public EventListenerList getImplementationEventListeners
 
440
            (String type, boolean useCapture) {
 
441
        HashTable listeners = useCapture ? capturingImplementationListeners
 
442
                                         : bubblingImplementationListeners;
 
443
        if (listeners == null) {
 
444
            return null;
 
445
        }
 
446
        return (EventListenerList) listeners.get(type);
 
447
    }
 
448
 
 
449
    /**
 
450
     * Fires the registered implementation listeners on the given event
 
451
     * target.
 
452
     */
 
453
    protected void fireImplementationEventListeners(NodeEventTarget node, 
 
454
                                                    AbstractEvent e,
 
455
                                                    boolean useCapture) {
 
456
        String type = e.getType();
 
457
        XBLEventSupport support = (XBLEventSupport) node.getEventSupport();
 
458
        // check if the event support has been instantiated
 
459
        if (support == null) {
 
460
            return;
 
461
        }
 
462
        EventListenerList list =
 
463
            support.getImplementationEventListeners(type, useCapture);
 
464
        // check if the event listeners list is not empty
 
465
        if (list == null) {
 
466
            return;
 
467
        }
 
468
        // dump event listeners, we get the registered listeners NOW
 
469
        EventListenerList.Entry[] listeners = list.getEventListeners();
 
470
        fireEventListeners(node, e, listeners, null, null);
 
471
    }
 
472
}