KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > BridgeEventSupport


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.bridge;
19
20 import java.awt.Point JavaDoc;
21 import java.awt.event.KeyEvent JavaDoc;
22 import java.awt.geom.NoninvertibleTransformException JavaDoc;
23 import java.awt.geom.Point2D JavaDoc;
24 import java.awt.geom.Rectangle2D JavaDoc;
25 import java.text.AttributedCharacterIterator JavaDoc;
26 import java.util.List JavaDoc;
27
28 import org.apache.batik.dom.events.DOMKeyEvent;
29 import org.apache.batik.gvt.GraphicsNode;
30 import org.apache.batik.gvt.TextNode;
31 import org.apache.batik.gvt.event.EventDispatcher;
32 import org.apache.batik.gvt.event.GraphicsNodeKeyEvent;
33 import org.apache.batik.gvt.event.GraphicsNodeKeyListener;
34 import org.apache.batik.gvt.event.GraphicsNodeMouseEvent;
35 import org.apache.batik.gvt.event.GraphicsNodeMouseListener;
36 import org.apache.batik.gvt.renderer.StrokingTextPainter;
37 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
38 import org.apache.batik.gvt.text.TextHit;
39 import org.apache.batik.gvt.text.TextSpanLayout;
40 import org.apache.batik.util.SVGConstants;
41 import org.w3c.dom.Document JavaDoc;
42 import org.w3c.dom.Element JavaDoc;
43 import org.w3c.dom.events.DocumentEvent JavaDoc;
44 import org.w3c.dom.events.Event JavaDoc;
45 import org.w3c.dom.events.EventListener JavaDoc;
46 import org.w3c.dom.events.EventTarget JavaDoc;
47 import org.w3c.dom.events.MouseEvent JavaDoc;
48
49 /**
50  * This class is responsible of tracking GraphicsNodeMouseEvent and
51  * fowarding them to the DOM as regular DOM MouseEvent.
52  *
53  * @author <a HREF="mailto:tkormann@ilog.fr">Thierry Kormann</a>
54  * @version $Id: BridgeEventSupport.java,v 1.59 2005/03/27 08:58:30 cam Exp $
55  */

56 public class BridgeEventSupport implements SVGConstants {
57
58     private BridgeEventSupport() {}
59
60     /**
61      * Is called only for the root element in order to dispatch GVT
62      * events to the DOM.
63      */

64     public static void addGVTListener(BridgeContext ctx, Document JavaDoc doc) {
65         UserAgent ua = ctx.getUserAgent();
66         if (ua != null) {
67             EventDispatcher dispatcher = ua.getEventDispatcher();
68             if (dispatcher != null) {
69                 final Listener listener = new Listener(ctx, ua);
70                 dispatcher.addGraphicsNodeMouseListener(listener);
71                 dispatcher.addGraphicsNodeKeyListener(listener);
72                 // add an unload listener on the SVGDocument to remove
73
// that listener for dispatching events
74
EventListener JavaDoc l = new GVTUnloadListener(dispatcher, listener);
75                 EventTarget JavaDoc target = (EventTarget JavaDoc)doc;
76                 target.addEventListener("SVGUnload", l, false);
77                 ctx.storeEventListener(target, "SVGUnload", l, false);
78             }
79         }
80     }
81
82     protected static class GVTUnloadListener implements EventListener JavaDoc {
83
84         protected EventDispatcher dispatcher;
85         protected Listener listener;
86
87         public GVTUnloadListener(EventDispatcher dispatcher,
88                                  Listener listener) {
89             this.dispatcher = dispatcher;
90             this.listener = listener;
91         }
92
93         public void handleEvent(Event JavaDoc evt) {
94             dispatcher.removeGraphicsNodeMouseListener(listener);
95             dispatcher.removeGraphicsNodeKeyListener(listener);
96             evt.getTarget().removeEventListener
97                 (SVGConstants.SVG_SVGUNLOAD_EVENT_TYPE, this, false);
98         }
99     }
100
101     /**
102      * A GraphicsNodeMouseListener that dispatch DOM events accordingly.
103      */

104     protected static class Listener
105         implements GraphicsNodeMouseListener, GraphicsNodeKeyListener {
106         
107         protected BridgeContext context;
108         protected UserAgent ua;
109         protected Element JavaDoc lastTargetElement;
110         protected boolean isDown;
111
112         public Listener(BridgeContext ctx, UserAgent u) {
113             context = ctx;
114             ua = u;
115         }
116
117         // Key -------------------------------------------------------------
118

119         /**
120          * Invoked when a key has been pressed.
121          * @param evt the graphics node key event
122          */

123         public void keyPressed(GraphicsNodeKeyEvent evt) {
124             if (!isDown) {
125                 isDown = true;
126                 dispatchKeyEvent("keydown", evt);
127             }
128             if (evt.getKeyChar() == KeyEvent.CHAR_UNDEFINED) {
129                 // We will not get a KEY_TYPED event for this char
130
// so generate a keypress event here.
131
dispatchKeyEvent("keypress", evt);
132             }
133         }
134
135         /**
136          * Invoked when a key has been released.
137          * @param evt the graphics node key event
138          */

139         public void keyReleased(GraphicsNodeKeyEvent evt) {
140             dispatchKeyEvent("keyup", evt);
141             isDown = false;
142         }
143
144         /**
145          * Invoked when a key has been typed.
146          * @param evt the graphics node key event
147          */

148         public void keyTyped(GraphicsNodeKeyEvent evt) {
149             dispatchKeyEvent("keypress", evt);
150         }
151
152         protected void dispatchKeyEvent(String JavaDoc eventType,
153                                         GraphicsNodeKeyEvent evt) {
154             FocusManager fmgr = context.getFocusManager();
155             if (fmgr == null) return;
156
157             Element JavaDoc targetElement = (Element JavaDoc)fmgr.getCurrentEventTarget();
158             if (targetElement == null) {
159                 return;
160             }
161             DocumentEvent JavaDoc d = (DocumentEvent JavaDoc)targetElement.getOwnerDocument();
162             DOMKeyEvent keyEvt = (DOMKeyEvent)d.createEvent("KeyEvents");
163             keyEvt.initKeyEvent(eventType,
164                                 true,
165                                 true,
166                                 evt.isControlDown(),
167                                 evt.isAltDown(),
168                                 evt.isShiftDown(),
169                                 evt.isMetaDown(),
170                                 mapKeyCode(evt.getKeyCode()),
171                                 evt.getKeyChar(),
172                                 null);
173
174             try {
175                 ((EventTarget JavaDoc)targetElement).dispatchEvent(keyEvt);
176             } catch (RuntimeException JavaDoc e) {
177                 ua.displayError(e);
178             }
179         }
180
181         /**
182          * The java KeyEvent keyCodes and the DOMKeyEvent keyCodes
183          * map except for the VK_ENTER code (which has a different value
184          * in DOM and the VK_KANA_LOCK and VK_INPUT_METHOD_ON_OFF which
185          * have no DOM equivalent.
186          */

187         protected final int mapKeyCode(int keyCode) {
188             switch (keyCode) {
189                 case KeyEvent.VK_ENTER:
190                     return DOMKeyEvent.DOM_VK_ENTER;
191             case KeyEvent.VK_KANA_LOCK:
192                 return DOMKeyEvent.DOM_VK_UNDEFINED;
193             case KeyEvent.VK_INPUT_METHOD_ON_OFF:
194                 return DOMKeyEvent.DOM_VK_UNDEFINED;
195             default:
196                 return keyCode;
197             }
198         }
199
200         // Mouse -----------------------------------------------------------
201

202         public void mouseClicked(GraphicsNodeMouseEvent evt) {
203             dispatchMouseEvent("click", evt, true);
204         }
205
206         public void mousePressed(GraphicsNodeMouseEvent evt) {
207             dispatchMouseEvent("mousedown", evt, true);
208         }
209
210         public void mouseReleased(GraphicsNodeMouseEvent evt) {
211             dispatchMouseEvent("mouseup", evt, true);
212         }
213
214         public void mouseEntered(GraphicsNodeMouseEvent evt) {
215             dispatchMouseEvent("mouseover", evt, true);
216         }
217
218         public void mouseExited(GraphicsNodeMouseEvent evt) {
219             Point JavaDoc clientXY = evt.getClientPoint();
220             // Get the 'new' node for the DOM event.
221
GraphicsNode node = evt.getRelatedNode();
222             Element JavaDoc targetElement = getEventTarget(node, clientXY);
223             if (lastTargetElement != null) {
224                 dispatchMouseEvent("mouseout",
225                                    lastTargetElement, // target
226
targetElement, // relatedTarget
227
clientXY,
228                                    evt,
229                                    true);
230             }
231         }
232
233         public void mouseDragged(GraphicsNodeMouseEvent evt) {
234             dispatchMouseEvent("mousemove", evt, false);
235         }
236
237         public void mouseMoved(GraphicsNodeMouseEvent evt) {
238             Point JavaDoc clientXY = evt.getClientPoint();
239             GraphicsNode node = evt.getGraphicsNode();
240             Element JavaDoc targetElement = getEventTarget(node, clientXY);
241             Element JavaDoc holdLTE = lastTargetElement;
242             if (holdLTE != targetElement) {
243                 if (holdLTE != null) {
244                     dispatchMouseEvent("mouseout",
245                                        holdLTE, // target
246
targetElement, // relatedTarget
247
clientXY,
248                                        evt,
249                                        true);
250                 }
251                 if (targetElement != null) {
252                     dispatchMouseEvent("mouseover",
253                                        targetElement, // target
254
holdLTE, // relatedTarget
255
clientXY,
256                                        evt,
257                                        true);
258                 }
259             }
260             dispatchMouseEvent("mousemove",
261                                targetElement, // target
262
null, // relatedTarget
263
clientXY,
264                                evt,
265                                false);
266         }
267
268         /**
269          * Dispatches a DOM MouseEvent according to the specified
270          * parameters.
271          *
272          * @param eventType the event type
273          * @param evt the GVT GraphicsNodeMouseEvent
274          * @param cancelable true means the event is cancelable
275          */

276         protected void dispatchMouseEvent(String JavaDoc eventType,
277                                           GraphicsNodeMouseEvent evt,
278                                           boolean cancelable) {
279             Point JavaDoc clientXY = evt.getClientPoint();
280             GraphicsNode node = evt.getGraphicsNode();
281             Element JavaDoc targetElement = getEventTarget
282                 (node, new Point2D.Float JavaDoc(evt.getX(), evt.getY()));
283             Element JavaDoc relatedElement = getRelatedElement(evt);
284             dispatchMouseEvent(eventType,
285                                targetElement,
286                                relatedElement,
287                                clientXY,
288                                evt,
289                                cancelable);
290         }
291
292         /**
293          * Dispatches a DOM MouseEvent according to the specified
294          * parameters.
295          *
296          * @param eventType the event type
297          * @param targetElement the target of the event
298          * @param relatedElement the related target if any
299          * @param clientXY the mouse coordinates in the client space
300          * @param evt the GVT GraphicsNodeMouseEvent
301          * @param cancelable true means the event is cancelable
302          */

303         protected void dispatchMouseEvent(String JavaDoc eventType,
304                                           Element JavaDoc targetElement,
305                                           Element JavaDoc relatedElement,
306                                           Point JavaDoc clientXY,
307                                           GraphicsNodeMouseEvent evt,
308                                           boolean cancelable) {
309             if (targetElement == null) {
310                 return;
311             }
312             /*
313             if (relatedElement != null) {
314                 System.out.println
315                     ("dispatching "+eventType+
316                      " target:"+targetElement.getLocalName()+
317                      " relatedElement:"+relatedElement.getLocalName());
318             } else {
319                 System.out.println
320                     ("dispatching "+eventType+
321                      " target:"+targetElement.getLocalName());
322
323             }
324             */

325             short button = getButton(evt);
326             Point JavaDoc screenXY = evt.getScreenPoint();
327             // create the coresponding DOM MouseEvent
328
DocumentEvent JavaDoc d = (DocumentEvent JavaDoc)targetElement.getOwnerDocument();
329             MouseEvent mouseEvt = (MouseEvent)d.createEvent("MouseEvents");
330             mouseEvt.initMouseEvent(eventType,
331                                     true,
332                                     cancelable,
333                                     null,
334                                     evt.getClickCount(),
335                                     screenXY.x,
336                                     screenXY.y,
337                                     clientXY.x,
338                                     clientXY.y,
339                                     evt.isControlDown(),
340                                     evt.isAltDown(),
341                                     evt.isShiftDown(),
342                                     evt.isMetaDown(),
343                                     button,
344                                     (EventTarget JavaDoc)relatedElement);
345
346             try {
347                 ((EventTarget JavaDoc)targetElement).dispatchEvent(mouseEvt);
348             } catch (RuntimeException JavaDoc e) {
349                 ua.displayError(e);
350             } finally {
351                 lastTargetElement = targetElement;
352             }
353         }
354
355         /**
356          * Returns the related element according to the specified event.
357          *
358          * @param evt the GVT GraphicsNodeMouseEvent
359          */

360         protected Element JavaDoc getRelatedElement(GraphicsNodeMouseEvent evt) {
361             GraphicsNode relatedNode = evt.getRelatedNode();
362             Element JavaDoc relatedElement = null;
363             if (relatedNode != null) {
364                 relatedElement = context.getElement(relatedNode);
365             }
366             return relatedElement;
367         }
368
369         /**
370          * Returns the mouse event button.
371          *
372          * @param evt the GVT GraphicsNodeMouseEvent
373          */

374         protected short getButton(GraphicsNodeMouseEvent evt) {
375             short button = 1;
376             if ((GraphicsNodeMouseEvent.BUTTON1_MASK & evt.getModifiers()) != 0) {
377                 button = 0;
378             } else if ((GraphicsNodeMouseEvent.BUTTON3_MASK & evt.getModifiers()) != 0) {
379                 button = 2;
380             }
381             return button;
382         }
383
384         /**
385          * Returns the element that is the target of the specified
386          * event or null if any.
387          *
388          * @param node the graphics node that received the event
389          * @param coords the mouse coordinates in the GVT tree space
390          */

391         protected Element JavaDoc getEventTarget(GraphicsNode node, Point2D JavaDoc coords) {
392             Element JavaDoc target = context.getElement(node);
393             // Lookup inside the text element children to see if the target
394
// is a tspan or textPath
395

396             if (target != null && node instanceof TextNode) {
397         TextNode textNode = (TextNode)node;
398         List JavaDoc list = textNode.getTextRuns();
399                 Point2D JavaDoc pt = (Point2D JavaDoc)coords.clone();
400                 // place coords in text node coordinate system
401
try {
402                     node.getGlobalTransform().createInverse().transform(pt, pt);
403                 } catch (NoninvertibleTransformException JavaDoc ex) {
404                 }
405                 if (list != null){
406                     for (int i = 0 ; i < list.size(); i++) {
407                         StrokingTextPainter.TextRun run =
408                             (StrokingTextPainter.TextRun)list.get(i);
409                         AttributedCharacterIterator JavaDoc aci = run.getACI();
410                         TextSpanLayout layout = run.getLayout();
411                         float x = (float)pt.getX();
412                         float y = (float)pt.getY();
413                         TextHit textHit = layout.hitTestChar(x, y);
414                         Rectangle2D JavaDoc bounds = layout.getBounds2D();
415                         if ((textHit != null) &&
416                             (bounds != null) && bounds.contains(x, y)) {
417                             Object JavaDoc delimiter = aci.getAttribute
418                                 (GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
419                             if (delimiter instanceof Element JavaDoc) {
420                                 return (Element JavaDoc)delimiter;
421                             }
422                         }
423                     }
424                 }
425             }
426             return target;
427         }
428     }
429 }
430
Popular Tags