KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > swing > JSVGCanvas


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.swing;
19
20 import java.awt.Dimension JavaDoc;
21 import java.awt.EventQueue JavaDoc;
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.awt.event.InputEvent JavaDoc;
24 import java.awt.event.KeyEvent JavaDoc;
25 import java.awt.event.MouseAdapter JavaDoc;
26 import java.awt.event.MouseEvent JavaDoc;
27 import java.awt.event.MouseMotionAdapter JavaDoc;
28 import java.awt.geom.AffineTransform JavaDoc;
29 import java.beans.PropertyChangeListener JavaDoc;
30 import java.beans.PropertyChangeSupport JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.WeakHashMap JavaDoc;
35
36 import javax.swing.AbstractAction JavaDoc;
37 import javax.swing.ActionMap JavaDoc;
38 import javax.swing.InputMap JavaDoc;
39 import javax.swing.JComponent JavaDoc;
40 import javax.swing.JDialog JavaDoc;
41 import javax.swing.JOptionPane JavaDoc;
42 import javax.swing.KeyStroke JavaDoc;
43 import javax.swing.ToolTipManager JavaDoc;
44
45 import org.apache.batik.bridge.UserAgent;
46 import org.apache.batik.swing.gvt.AbstractImageZoomInteractor;
47 import org.apache.batik.swing.gvt.AbstractPanInteractor;
48 import org.apache.batik.swing.gvt.AbstractResetTransformInteractor;
49 import org.apache.batik.swing.gvt.AbstractRotateInteractor;
50 import org.apache.batik.swing.gvt.AbstractZoomInteractor;
51 import org.apache.batik.swing.gvt.Interactor;
52 import org.apache.batik.swing.svg.JSVGComponent;
53 import org.apache.batik.swing.svg.SVGDocumentLoaderEvent;
54 import org.apache.batik.swing.svg.SVGUserAgent;
55 import org.apache.batik.util.SVGConstants;
56 import org.apache.batik.util.XMLConstants;
57 import org.apache.batik.util.gui.JErrorPane;
58
59 import org.w3c.dom.Element JavaDoc;
60 import org.w3c.dom.Node JavaDoc;
61 import org.w3c.dom.events.Event JavaDoc;
62 import org.w3c.dom.events.EventListener JavaDoc;
63 import org.w3c.dom.events.EventTarget JavaDoc;
64 import org.w3c.dom.svg.SVGDocument;
65
66 /**
67  * This class represents a general-purpose swing SVG component. The
68  * <tt>JSVGCanvas</tt> does not provided additional functionalities compared to
69  * the <tt>JSVGComponent</tt> but simply provides an API conformed to the
70  * JavaBean specification. The only major change between the
71  * <tt>JSVGComponent</tt> and this component is that interactors and text
72  * selection are activated by default.
73  *
74  * @author <a HREF="mailto:tkormann@apache.org">Thierry Kormann</a>
75  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
76  * @version $Id: JSVGCanvas.java,v 1.52 2005/03/27 08:58:36 cam Exp $
77  */

78 public class JSVGCanvas extends JSVGComponent {
79
80     /**
81      * The key for the Action to scroll right.
82      */

83     public static final String JavaDoc SCROLL_RIGHT_ACTION = "ScrollRight";
84
85     /**
86      * The key for the Action to scroll left.
87      */

88     public static final String JavaDoc SCROLL_LEFT_ACTION = "ScrollLeft";
89
90     /**
91      * The key for the Action to scroll up.
92      */

93     public static final String JavaDoc SCROLL_UP_ACTION = "ScrollUp";
94
95     /**
96      * The key for the Action to scroll down.
97      */

98     public static final String JavaDoc SCROLL_DOWN_ACTION = "ScrollDown";
99
100     /**
101      * The key for the Action to quickly scroll right.
102      */

103     public static final String JavaDoc FAST_SCROLL_RIGHT_ACTION = "FastScrollRight";
104
105     /**
106      * The key for the Action to quickly scroll left.
107      */

108     public static final String JavaDoc FAST_SCROLL_LEFT_ACTION = "FastScrollLeft";
109
110     /**
111      * The key for the Action to quickly scroll up.
112      */

113     public static final String JavaDoc FAST_SCROLL_UP_ACTION = "FastScrollUp";
114
115     /**
116      * The key for the Action to quickly scroll down.
117      */

118     public static final String JavaDoc FAST_SCROLL_DOWN_ACTION = "FastScrollDown";
119
120     /**
121      * The key for the Action to zoom in.
122      */

123     public static final String JavaDoc ZOOM_IN_ACTION = "ZoomIn";
124
125     /**
126      * The key for the Action to zoom out.
127      */

128     public static final String JavaDoc ZOOM_OUT_ACTION = "ZoomOut";
129
130     /**
131      * The key for the Action to reset the transform.
132      */

133     public static final String JavaDoc RESET_TRANSFORM_ACTION = "ResetTransform";
134
135     /**
136      * This flag bit indicates whether or not the zoom interactor is
137      * enabled. True means the zoom interactor is functional.
138      */

139     private boolean isZoomInteractorEnabled = true;
140
141     /**
142      * This flag bit indicates whether or not the image zoom interactor is
143      * enabled. True means the image zoom interactor is functional.
144      */

145     private boolean isImageZoomInteractorEnabled = true;
146
147     /**
148      * This flag bit indicates whether or not the pan interactor is
149      * enabled. True means the pan interactor is functional.
150      */

151     private boolean isPanInteractorEnabled = true;
152
153     /**
154      * This flag bit indicates whether or not the rotate interactor is
155      * enabled. True means the rotate interactor is functional.
156      */

157     private boolean isRotateInteractorEnabled = true;
158
159     /**
160      * This flag bit indicates whether or not the reset transform interactor is
161      * enabled. True means the reset transform interactor is functional.
162      */

163     private boolean isResetTransformInteractorEnabled = true;
164
165     /**
166      * The <tt>PropertyChangeSupport</tt> used to fire
167      * <tt>PropertyChangeEvent</tt>.
168      */

169     protected PropertyChangeSupport JavaDoc pcs = new PropertyChangeSupport JavaDoc(this);
170
171     /**
172      * The URI of the current document being displayed.
173      */

174     protected String JavaDoc uri;
175
176     /**
177      * Keeps track of the last known mouse position over the canvas.
178      * This is used for displaying tooltips at the right location.
179      */

180     protected LocationListener locationListener = new LocationListener();
181
182     /**
183      * Mapping of elements to listeners so they can be removed,
184      * if the tooltip is removed.
185      */

186     protected Map JavaDoc toolTipMap = null;
187     protected EventListener JavaDoc toolTipListener = new ToolTipModifier();
188     protected EventTarget JavaDoc lastTarget = null;;
189     /**
190      * The time of the last tool tip event.
191      */

192     protected long lastToolTipEventTimeStamp;
193
194     /**
195      * The target for which the last tool tip event was fired.
196      */

197     protected EventTarget JavaDoc lastToolTipEventTarget;
198
199
200
201     /**
202      * Creates a new JSVGCanvas.
203      */

204     public JSVGCanvas() {
205         this(null, true, true);
206         addMouseMotionListener(locationListener);
207     }
208
209     /**
210      * Creates a new JSVGCanvas.
211      *
212      * @param ua a SVGUserAgent instance or null.
213      * @param eventsEnabled Whether the GVT tree should be reactive to mouse
214      * and key events.
215      * @param selectableText Whether the text should be selectable.
216      */

217     public JSVGCanvas(SVGUserAgent ua,
218                       boolean eventsEnabled,
219                       boolean selectableText) {
220
221         super(ua, eventsEnabled, selectableText);
222
223         setPreferredSize(new Dimension JavaDoc(200, 200));
224         setMinimumSize(new Dimension JavaDoc(100, 100));
225
226         List JavaDoc intl = getInteractors();
227         intl.add(zoomInteractor);
228         intl.add(imageZoomInteractor);
229         intl.add(panInteractor);
230         intl.add(rotateInteractor);
231         intl.add(resetTransformInteractor);
232
233         installActions();
234
235         if (eventsEnabled) {
236             addMouseListener(new MouseAdapter JavaDoc() {
237                 public void mousePressed(MouseEvent JavaDoc evt) {
238                     requestFocus();
239                 }
240             });
241
242             installKeyboardActions();
243         }
244         addMouseMotionListener(locationListener);
245     }
246
247     /**
248      * Builds the ActionMap of this canvas with a set of predefined
249      * <tt>Action</tt>s.
250      */

251     protected void installActions() {
252         ActionMap JavaDoc actionMap = getActionMap();
253
254         actionMap.put(SCROLL_RIGHT_ACTION, new ScrollRightAction(10));
255         actionMap.put(SCROLL_LEFT_ACTION, new ScrollLeftAction(10));
256         actionMap.put(SCROLL_UP_ACTION, new ScrollUpAction(10));
257         actionMap.put(SCROLL_DOWN_ACTION, new ScrollDownAction(10));
258
259         actionMap.put(FAST_SCROLL_RIGHT_ACTION, new ScrollRightAction(30));
260         actionMap.put(FAST_SCROLL_LEFT_ACTION, new ScrollLeftAction(30));
261         actionMap.put(FAST_SCROLL_UP_ACTION, new ScrollUpAction(30));
262         actionMap.put(FAST_SCROLL_DOWN_ACTION, new ScrollDownAction(30));
263
264         actionMap.put(ZOOM_IN_ACTION, new ZoomInAction());
265         actionMap.put(ZOOM_OUT_ACTION, new ZoomOutAction());
266
267         actionMap.put(RESET_TRANSFORM_ACTION, new ResetTransformAction());
268     }
269
270     public void setDisableInteractions(boolean b) {
271         super.setDisableInteractions(b);
272         ActionMap JavaDoc actionMap = getActionMap();
273
274         actionMap.get(SCROLL_RIGHT_ACTION) .setEnabled(!b);
275         actionMap.get(SCROLL_LEFT_ACTION) .setEnabled(!b);
276         actionMap.get(SCROLL_UP_ACTION) .setEnabled(!b);
277         actionMap.get(SCROLL_DOWN_ACTION) .setEnabled(!b);
278
279         actionMap.get(FAST_SCROLL_RIGHT_ACTION).setEnabled(!b);
280         actionMap.get(FAST_SCROLL_LEFT_ACTION) .setEnabled(!b);
281         actionMap.get(FAST_SCROLL_UP_ACTION) .setEnabled(!b);
282         actionMap.get(FAST_SCROLL_DOWN_ACTION) .setEnabled(!b);
283
284         actionMap.get(ZOOM_IN_ACTION) .setEnabled(!b);
285         actionMap.get(ZOOM_OUT_ACTION) .setEnabled(!b);
286         actionMap.get(RESET_TRANSFORM_ACTION) .setEnabled(!b);
287     }
288
289
290         /**
291      * Builds the InputMap of this canvas with a set of predefined
292      * <tt>Action</tt>s.
293      */

294     protected void installKeyboardActions() {
295
296         InputMap JavaDoc inputMap = getInputMap(JComponent.WHEN_FOCUSED);
297         KeyStroke JavaDoc key;
298
299         key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
300         inputMap.put(key, SCROLL_RIGHT_ACTION);
301
302         key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
303         inputMap.put(key, SCROLL_LEFT_ACTION);
304
305         key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
306         inputMap.put(key, SCROLL_UP_ACTION);
307
308         key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
309         inputMap.put(key, SCROLL_DOWN_ACTION);
310
311         key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_MASK);
312         inputMap.put(key, FAST_SCROLL_RIGHT_ACTION);
313
314         key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_MASK);
315         inputMap.put(key, FAST_SCROLL_LEFT_ACTION);
316
317         key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_MASK);
318         inputMap.put(key, FAST_SCROLL_UP_ACTION);
319
320         key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_MASK);
321         inputMap.put(key, FAST_SCROLL_DOWN_ACTION);
322
323         key = KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK);
324         inputMap.put(key, ZOOM_IN_ACTION);
325
326         key = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK);
327         inputMap.put(key, ZOOM_OUT_ACTION);
328
329         key = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK);
330         inputMap.put(key, RESET_TRANSFORM_ACTION);
331     }
332
333     /**
334      * Adds the specified <tt>PropertyChangeListener</tt>.
335      *
336      * @param pcl the property change listener to add
337      */

338     public void addPropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
339         pcs.addPropertyChangeListener(pcl);
340     }
341
342     /**
343      * Removes the specified <tt>PropertyChangeListener</tt>.
344      *
345      * @param pcl the property change listener to remove
346      */

347     public void removePropertyChangeListener(PropertyChangeListener JavaDoc pcl) {
348         pcs.removePropertyChangeListener(pcl);
349     }
350
351     /**
352      * Adds the specified <tt>PropertyChangeListener</tt> for the specified
353      * property.
354      *
355      * @param propertyName the name of the property to listen on
356      * @param pcl the property change listener to add
357      */

358     public void addPropertyChangeListener(String JavaDoc propertyName,
359                                           PropertyChangeListener JavaDoc pcl) {
360         pcs.addPropertyChangeListener(propertyName, pcl);
361     }
362
363     /**
364      * Removes the specified <tt>PropertyChangeListener</tt> for the specified
365      * property.
366      *
367      * @param propertyName the name of the property that was listened on
368      * @param pcl the property change listener to remove
369      */

370     public void removePropertyChangeListener(String JavaDoc propertyName,
371                                              PropertyChangeListener JavaDoc pcl) {
372         pcs.removePropertyChangeListener(propertyName, pcl);
373     }
374
375     /**
376      * Determines whether the zoom interactor is enabled or not.
377      */

378     public void setEnableZoomInteractor(boolean b) {
379         if (isZoomInteractorEnabled != b) {
380             boolean oldValue = isZoomInteractorEnabled;
381             isZoomInteractorEnabled = b;
382             if (isZoomInteractorEnabled) {
383                 getInteractors().add(zoomInteractor);
384             } else {
385                 getInteractors().remove(zoomInteractor);
386             }
387             pcs.firePropertyChange("enableZoomInteractor", oldValue, b);
388         }
389     }
390
391     /**
392      * Returns true if the zoom interactor is enabled, false otherwise.
393      */

394     public boolean getEnableZoomInteractor() {
395         return isZoomInteractorEnabled;
396     }
397
398     /**
399      * Determines whether the image zoom interactor is enabled or not.
400      */

401     public void setEnableImageZoomInteractor(boolean b) {
402         if (isImageZoomInteractorEnabled != b) {
403             boolean oldValue = isImageZoomInteractorEnabled;
404             isImageZoomInteractorEnabled = b;
405             if (isImageZoomInteractorEnabled) {
406                 getInteractors().add(imageZoomInteractor);
407             } else {
408                 getInteractors().remove(imageZoomInteractor);
409             }
410             pcs.firePropertyChange("enableImageZoomInteractor", oldValue, b);
411         }
412     }
413
414     /**
415      * Returns true if the image zoom interactor is enabled, false otherwise.
416      */

417     public boolean getEnableImageZoomInteractor() {
418         return isImageZoomInteractorEnabled;
419     }
420
421     /**
422      * Determines whether the pan interactor is enabled or not.
423      */

424     public void setEnablePanInteractor(boolean b) {
425         if (isPanInteractorEnabled != b) {
426             boolean oldValue = isPanInteractorEnabled;
427             isPanInteractorEnabled = b;
428             if (isPanInteractorEnabled) {
429                 getInteractors().add(panInteractor);
430             } else {
431                 getInteractors().remove(panInteractor);
432             }
433             pcs.firePropertyChange("enablePanInteractor", oldValue, b);
434         }
435     }
436
437     /**
438      * Returns true if the pan interactor is enabled, false otherwise.
439      */

440     public boolean getEnablePanInteractor() {
441         return isPanInteractorEnabled;
442     }
443
444     /**
445      * Determines whether the rotate interactor is enabled or not.
446      */

447     public void setEnableRotateInteractor(boolean b) {
448         if (isRotateInteractorEnabled != b) {
449             boolean oldValue = isRotateInteractorEnabled;
450             isRotateInteractorEnabled = b;
451             if (isRotateInteractorEnabled) {
452                 getInteractors().add(rotateInteractor);
453             } else {
454                 getInteractors().remove(rotateInteractor);
455             }
456             pcs.firePropertyChange("enableRotateInteractor", oldValue, b);
457         }
458     }
459
460     /**
461      * Returns true if the rotate interactor is enabled, false otherwise.
462      */

463     public boolean getEnableRotateInteractor() {
464         return isRotateInteractorEnabled;
465     }
466
467     /**
468      * Determines whether the reset transform interactor is enabled or not.
469      */

470     public void setEnableResetTransformInteractor(boolean b) {
471         if (isResetTransformInteractorEnabled != b) {
472             boolean oldValue = isResetTransformInteractorEnabled;
473             isResetTransformInteractorEnabled = b;
474             if (isResetTransformInteractorEnabled) {
475                 getInteractors().add(resetTransformInteractor);
476             } else {
477                 getInteractors().remove(resetTransformInteractor);
478             }
479             pcs.firePropertyChange("enableResetTransformInteractor",
480                                    oldValue,
481                                    b);
482         }
483     }
484
485     /**
486      * Returns true if the reset transform interactor is enabled, false
487      * otherwise.
488      */

489     public boolean getEnableResetTransformInteractor() {
490         return isResetTransformInteractorEnabled;
491     }
492
493     /**
494      * Returns the URI of the current document.
495      */

496     public String JavaDoc getURI() {
497         return uri;
498     }
499
500     /**
501      * Sets the URI to the specified uri. If the input 'newURI'
502      * string is null, then the canvas will display an empty
503      * document.
504      *
505      * @param newURI the new uri of the document to display
506      */

507     public void setURI(String JavaDoc newURI) {
508         String JavaDoc oldValue = uri;
509         this.uri = newURI;
510         if (uri != null) {
511             loadSVGDocument(uri);
512         } else {
513             setSVGDocument(null);
514         }
515
516         pcs.firePropertyChange("URI", oldValue, uri);
517     }
518
519     /**
520      * Creates a UserAgent.
521      */

522     protected UserAgent createUserAgent() {
523         return new CanvasUserAgent();
524     }
525
526     /**
527      * Creates an instance of Listener.
528      */

529     protected Listener JavaDoc createListener() {
530         return new CanvasSVGListener();
531     }
532
533     /**
534      * To hide the listener methods. This class just reset the tooltip.
535      */

536     protected class CanvasSVGListener extends JSVGComponent.SVGListener {
537
538         /**
539          * Called when the loading of a document was started.
540          */

541         public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
542             super.documentLoadingStarted(e);
543             JSVGCanvas.this.setToolTipText(null);
544         }
545
546     }
547
548     protected void installSVGDocument(SVGDocument doc) {
549         if (svgDocument != null) {
550             EventTarget JavaDoc root;
551             root = (EventTarget JavaDoc)svgDocument.getRootElement();
552             root.removeEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
553                                      toolTipListener, false);
554             root.removeEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
555                                      toolTipListener, false);
556             lastTarget = null;
557         }
558
559         if (toolTipMap != null) {
560             toolTipMap.clear();
561         }
562
563         if (doc != null) {
564             EventTarget JavaDoc root;
565             root = (EventTarget JavaDoc)doc.getRootElement();
566             // On mouseover, it sets the tooltip to the given value
567
root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
568                                   toolTipListener, false);
569             // On mouseout, it removes the tooltip
570
root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
571                                   toolTipListener, false);
572         }
573
574         super.installSVGDocument(doc);
575     }
576
577     // ----------------------------------------------------------------------
578
// Actions
579
// ----------------------------------------------------------------------
580

581     /**
582      * A swing action to reset the rendering transform of the canvas.
583      */

584     public class ResetTransformAction extends AbstractAction JavaDoc {
585         public void actionPerformed(ActionEvent JavaDoc evt) {
586             fragmentIdentifier = null;
587             resetRenderingTransform();
588         }
589     }
590
591     /**
592      * A swing action to append an affine transform to the current
593      * rendering transform. Before the rendering transform is
594      * applied the method translates the center of the display to
595      * 0,0 so scale and rotate occur around the middle of
596      * the display.
597      */

598     public class AffineAction extends AbstractAction JavaDoc {
599         AffineTransform JavaDoc at;
600         public AffineAction(AffineTransform JavaDoc at) {
601             this.at = at;
602         }
603
604         public void actionPerformed(ActionEvent JavaDoc evt) {
605             if (gvtRoot == null) {
606                 return;
607             }
608             AffineTransform JavaDoc rat = getRenderingTransform();
609             if (at != null) {
610                 Dimension JavaDoc dim = getSize();
611                 int x = dim.width / 2;
612                 int y = dim.height / 2;
613                 AffineTransform JavaDoc t = AffineTransform.getTranslateInstance(x, y);
614                 t.concatenate(at);
615                 t.translate(-x, -y);
616                 t.concatenate(rat);
617                 setRenderingTransform(t);
618             }
619         }
620     }
621
622     /**
623      * A swing action to apply a zoom factor to the canvas.
624      * This can be used to zoom in (scale > 1) and out (scale <1).
625      */

626     public class ZoomAction extends AffineAction {
627         public ZoomAction(double scale) {
628             super(AffineTransform.getScaleInstance(scale, scale));
629         }
630         public ZoomAction(double scaleX, double scaleY) {
631             super(AffineTransform.getScaleInstance(scaleX, scaleY));
632         }
633     }
634
635     /**
636      * A swing action to zoom in the canvas.
637      */

638     public class ZoomInAction extends ZoomAction {
639         ZoomInAction() { super(2); }
640     }
641
642     /**
643      * A swing action to zoom out the canvas.
644      */

645     public class ZoomOutAction extends ZoomAction {
646         ZoomOutAction() { super(.5); }
647     }
648
649     /**
650      * A swing action to Rotate the canvas.
651      */

652     public class RotateAction extends AffineAction {
653         public RotateAction(double theta) {
654             super(AffineTransform.getRotateInstance(theta));
655         }
656     }
657
658     /**
659      * A swing action to Pan/scroll the canvas.
660      */

661     public class ScrollAction extends AffineAction {
662         public ScrollAction(double tx, double ty) {
663             super(AffineTransform.getTranslateInstance(tx, ty));
664         }
665     }
666
667     /**
668      * A swing action to scroll the canvas to the right,
669      * by a fixed amount
670      */

671     public class ScrollRightAction extends ScrollAction {
672         public ScrollRightAction(int inc) {
673             super(-inc, 0);
674         }
675     }
676
677     /**
678      * A swing action to scroll the canvas to the left,
679      * by a fixed amount
680      */

681     public class ScrollLeftAction extends ScrollAction {
682         public ScrollLeftAction(int inc) {
683             super(inc, 0);
684         }
685     }
686
687     /**
688      * A swing action to scroll the canvas up,
689      * by a fixed amount
690      */

691     public class ScrollUpAction extends ScrollAction {
692         public ScrollUpAction(int inc) {
693             super(0, inc);
694         }
695     }
696
697     /**
698      * A swing action to scroll the canvas down,
699      * by a fixed amount
700      */

701     public class ScrollDownAction extends ScrollAction {
702         public ScrollDownAction(int inc) {
703             super(0, -inc);
704         }
705     }
706
707     // ----------------------------------------------------------------------
708
// Interactors
709
// ----------------------------------------------------------------------
710

711     /**
712      * An interactor to perform a zoom.
713      * <p>Binding: BUTTON1 + CTRL Key</p>
714      */

715     protected Interactor zoomInteractor = new AbstractZoomInteractor() {
716         public boolean startInteraction(InputEvent JavaDoc ie) {
717             int mods = ie.getModifiers();
718             return
719                 ie.getID() == MouseEvent.MOUSE_PRESSED &&
720                 (mods & InputEvent.BUTTON1_MASK) != 0 &&
721                 (mods & InputEvent.CTRL_MASK) != 0;
722         }
723     };
724
725     /**
726      * An interactor to perform a realtime zoom.
727      * <p>Binding: BUTTON3 + SHIFT Key</p>
728      */

729     protected Interactor imageZoomInteractor
730         = new AbstractImageZoomInteractor() {
731         public boolean startInteraction(InputEvent JavaDoc ie) {
732             int mods = ie.getModifiers();
733             return
734                 ie.getID() == MouseEvent.MOUSE_PRESSED &&
735                 (mods & InputEvent.BUTTON3_MASK) != 0 &&
736                 (mods & InputEvent.SHIFT_MASK) != 0;
737         }
738     };
739
740     /**
741      * An interactor to perform a translation.
742      * <p>Binding: BUTTON1 + SHIFT Key</p>
743      */

744     protected Interactor panInteractor = new AbstractPanInteractor() {
745         public boolean startInteraction(InputEvent JavaDoc ie) {
746             int mods = ie.getModifiers();
747             return
748                 ie.getID() == MouseEvent.MOUSE_PRESSED &&
749                 (mods & InputEvent.BUTTON1_MASK) != 0 &&
750                 (mods & InputEvent.SHIFT_MASK) != 0;
751         }
752     };
753
754     /**
755      * An interactor to perform a rotation.
756      * <p>Binding: BUTTON3 + CTRL Key</p>
757      */

758     protected Interactor rotateInteractor = new AbstractRotateInteractor() {
759         public boolean startInteraction(InputEvent JavaDoc ie) {
760             int mods = ie.getModifiers();
761             return
762                 ie.getID() == MouseEvent.MOUSE_PRESSED &&
763                 (mods & InputEvent.BUTTON3_MASK) != 0 &&
764                 (mods & InputEvent.CTRL_MASK) != 0;
765         }
766     };
767
768     /**
769      * An interactor to reset the rendering transform.
770      * <p>Binding: CTRL+SHIFT+BUTTON3</p>
771      */

772     protected Interactor resetTransformInteractor =
773         new AbstractResetTransformInteractor() {
774         public boolean startInteraction(InputEvent JavaDoc ie) {
775             int mods = ie.getModifiers();
776             return
777                 ie.getID() == MouseEvent.MOUSE_CLICKED &&
778                 (mods & InputEvent.BUTTON3_MASK) != 0 &&
779                 (mods & InputEvent.SHIFT_MASK) != 0 &&
780                 (mods & InputEvent.CTRL_MASK) != 0;
781         }
782     };
783
784     // ----------------------------------------------------------------------
785
// User agent implementation
786
// ----------------------------------------------------------------------
787

788     /**
789      * The <tt>CanvasUserAgent</tt> only adds tooltips to the behavior of the
790      * default <tt>BridgeUserAgent</tt>. A tooltip will be displayed
791      * wheneven the mouse lingers over an element which has a &lt;title&gt; or a
792      * &lt;desc&gt; child element.
793      */

794     protected class CanvasUserAgent extends BridgeUserAgent
795
796         implements XMLConstants {
797
798         final String JavaDoc TOOLTIP_TITLE_ONLY
799             = "JSVGCanvas.CanvasUserAgent.ToolTip.titleOnly";
800         final String JavaDoc TOOLTIP_DESC_ONLY
801             = "JSVGCanvas.CanvasUserAgent.ToolTip.descOnly";
802         final String JavaDoc TOOLTIP_TITLE_AND_TEXT
803             = "JSVGCanvas.CanvasUserAgent.ToolTip.titleAndDesc";
804
805         /**
806          * The handleElement method builds a tool tip from the
807          * content of a &lt;title&gt; element, a &lt;desc&gt;
808          * element or both. <br/>
809          * Because these elements can appear in any order, here
810          * is the algorithm used to build the tool tip:<br />
811          * <ul>
812          * <li>If a &lt;title&gt; is passed to <tt>handleElement</tt>
813          * the method checks if there is a &gt;desc&gt; peer. If
814          * there is one, nothing is done (because the desc will do
815          * it). If there in none, the tool tip is set to the value
816          * of the &lt;title&gt; element content.</li>
817          * <li>If a &lt;desc&gt; is passed to <tt>handleElement</tt>
818          * the method checks if there is a &lt;title&gt; peer. If there
819          * is one, the content of that peer is pre-pended to the
820          * content of the &lt;desc&gt; element.</li>
821          * </ul>
822          */

823         public void handleElement(Element JavaDoc elt, Object JavaDoc data){
824             super.handleElement(elt, data);
825
826             // Don't handle tool tips unless we are interactive.
827
if (!isInteractive()) return;
828             
829             if (!SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI()))
830                 return;
831
832             // Don't handle tool tips for the root SVG element.
833
if (elt.getParentNode() ==
834                 elt.getOwnerDocument().getDocumentElement()) {
835                 return;
836             }
837
838             Element JavaDoc parent;
839             // When node is removed data is old parent node
840
// since we can't get it otherwise.
841
if (data instanceof Element JavaDoc) parent = (Element JavaDoc)data;
842             else parent = (Element JavaDoc)elt.getParentNode();
843
844             Element JavaDoc descPeer = null;
845             Element JavaDoc titlePeer = null;
846             if (elt.getLocalName().equals(SVGConstants.SVG_TITLE_TAG)) {
847                 if (data == Boolean.TRUE)
848                     titlePeer = elt;
849                 descPeer = getPeerWithTag(parent,
850                                            SVGConstants.SVG_NAMESPACE_URI,
851                                            SVGConstants.SVG_DESC_TAG);
852             } else if (elt.getLocalName().equals(SVGConstants.SVG_DESC_TAG)) {
853                 if (data == Boolean.TRUE)
854                     descPeer = elt;
855                 titlePeer = getPeerWithTag(parent,
856                                            SVGConstants.SVG_NAMESPACE_URI,
857                                            SVGConstants.SVG_TITLE_TAG);
858             }
859
860             String JavaDoc titleTip = null;
861             if (titlePeer != null) {
862                 titlePeer.normalize();
863                 if (titlePeer.getFirstChild() != null)
864                     titleTip = titlePeer.getFirstChild().getNodeValue();
865             }
866
867             String JavaDoc descTip = null;
868             if (descPeer != null) {
869                 descPeer.normalize();
870                 if (descPeer.getFirstChild() != null)
871                     descTip = descPeer.getFirstChild().getNodeValue();
872             }
873
874             final String JavaDoc toolTip;
875             if ((titleTip != null) && (titleTip.length() != 0)) {
876                 if ((descTip != null) && (descTip.length() != 0)) {
877                     toolTip = Messages.formatMessage
878                         (TOOLTIP_TITLE_AND_TEXT,
879                          new Object JavaDoc[] { toFormattedHTML(titleTip),
880                                         toFormattedHTML(descTip)});
881                 } else {
882                     toolTip = Messages.formatMessage
883                         (TOOLTIP_TITLE_ONLY,
884                          new Object JavaDoc[]{toFormattedHTML(titleTip)});
885                 }
886             } else {
887                 if ((descTip != null) && (descTip.length() != 0)) {
888                     toolTip = Messages.formatMessage
889                         (TOOLTIP_DESC_ONLY,
890                          new Object JavaDoc[]{toFormattedHTML(descTip)});
891                 } else {
892                     toolTip = null;
893                 }
894             }
895
896             if (toolTip == null) {
897                 removeToolTip(parent);
898                 return;
899             }
900
901             if (lastTarget != parent) {
902                 setToolTip(parent, toolTip);
903             } else {
904                 // Already has focus check if it already has tip text.
905
Object JavaDoc o = null;
906                 if (toolTipMap != null) {
907                     o = toolTipMap.get(parent);
908                     toolTipMap.put(parent, toolTip);
909                 }
910
911                 if (o != null) {
912                     // Update components tooltip text now.
913
EventQueue.invokeLater(new Runnable JavaDoc() {
914                             public void run() {
915                                 setToolTipText(toolTip);
916                                 MouseEvent JavaDoc e = new MouseEvent JavaDoc
917                                     (JSVGCanvas.this,
918                                      MouseEvent.MOUSE_MOVED,
919                                      System.currentTimeMillis(),
920                                      0,
921                                      locationListener.getLastX(),
922                                      locationListener.getLastY(),
923                                      0,
924                                      false);
925                                 ToolTipManager.sharedInstance().mouseMoved(e);
926                             }
927                         });
928                 } else {
929                     EventQueue.invokeLater(new ToolTipRunnable(toolTip));
930                 }
931             }
932         }
933
934         /**
935          * Converts line breaks to HTML breaks and encodes special entities.
936          * Poor way of replacing '<', '>' and '&' in content.
937          */

938         public String JavaDoc toFormattedHTML(String JavaDoc str) {
939             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(str);
940             replace(sb, XML_CHAR_AMP, XML_ENTITY_AMP); // Must go first!
941
replace(sb, XML_CHAR_LT, XML_ENTITY_LT);
942             replace(sb, XML_CHAR_GT, XML_ENTITY_GT);
943             replace(sb, XML_CHAR_QUOT, XML_ENTITY_QUOT);
944             // Dont' quote "'" apostrphe since the display doesn't
945
// seem to understand it.
946
// replace(sb, XML_CHAR_APOS, XML_ENTITY_APOS);
947
replace(sb, '\n', "<br>");
948             return sb.toString();
949         }
950
951         protected void replace(StringBuffer JavaDoc sb, char c, String JavaDoc r) {
952             String JavaDoc v = sb.toString();
953             int i = v.length();
954
955             while( (i=v.lastIndexOf(c, i-1)) != -1 ) {
956                 sb.deleteCharAt(i);
957                 sb.insert(i, r);
958             }
959         }
960
961         /**
962          * Checks if there is a peer element of a given type. This returns the
963          * first occurence of the given type or null if none is found.
964          */

965         public Element JavaDoc getPeerWithTag(Element JavaDoc parent,
966                                       String JavaDoc nameSpaceURI,
967                                       String JavaDoc localName) {
968
969             Element JavaDoc p = (Element JavaDoc)parent;
970             if (p == null) {
971                 return null;
972             }
973
974             for (Node JavaDoc n=p.getFirstChild(); n!=null; n = n.getNextSibling()) {
975                 if (!nameSpaceURI.equals(n.getNamespaceURI())){
976                     continue;
977                 }
978                 if (!localName.equals(n.getLocalName())){
979                     continue;
980                 }
981                 if (n.getNodeType() == Node.ELEMENT_NODE) {
982                     return (Element JavaDoc)n;
983                 }
984             }
985             return null;
986         }
987
988         /**
989          * Returns a boolean defining whether or not there is a peer of
990          * <tt>elt</tt> with the given qualified tag.
991          */

992         public boolean hasPeerWithTag(Element JavaDoc elt,
993                                       String JavaDoc nameSpaceURI,
994                                       String JavaDoc localName){
995
996             return !(getPeerWithTag(elt, nameSpaceURI, localName) == null);
997         }
998
999         /**
1000         * Sets the tool tip on the input element.
1001         */

1002        public void setToolTip(Element JavaDoc elt, String JavaDoc toolTip){
1003            if (toolTipMap == null) {
1004                toolTipMap = new WeakHashMap JavaDoc();
1005            }
1006
1007            toolTipMap.put(elt, toolTip);
1008
1009            if (elt == lastTarget)
1010                EventQueue.invokeLater(new ToolTipRunnable(toolTip));
1011        }
1012
1013        public void removeToolTip(Element JavaDoc elt) {
1014            if (toolTipMap != null)
1015                toolTipMap.remove(elt);
1016            if (lastTarget == elt) { // clear ToolTip.
1017
EventQueue.invokeLater(new ToolTipRunnable(null));
1018            }
1019        }
1020
1021        /**
1022         * Displays an error message in the User Agent interface.
1023         */

1024        public void displayError(String JavaDoc message) {
1025            if (svgUserAgent != null) {
1026                super.displayError(message);
1027            } else {
1028                JOptionPane JavaDoc pane =
1029                    new JOptionPane JavaDoc(message, JOptionPane.ERROR_MESSAGE);
1030                JDialog JavaDoc dialog =
1031                    pane.createDialog(JSVGCanvas.this, "ERROR");
1032                dialog.setModal(false);
1033                dialog.setVisible(true); // Safe to be called from any thread
1034
}
1035        }
1036
1037        /**
1038         * Displays an error resulting from the specified Exception.
1039         */

1040        public void displayError(Exception JavaDoc ex) {
1041            if (svgUserAgent != null) {
1042                super.displayError(ex);
1043            } else {
1044                JErrorPane pane =
1045                    new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
1046                JDialog JavaDoc dialog = pane.createDialog(JSVGCanvas.this, "ERROR");
1047                dialog.setModal(false);
1048                dialog.setVisible(true); // Safe to be called from any thread
1049
}
1050        }
1051    }
1052
1053    // ----------------------------------------------------------------------
1054
// Tooltip
1055
// ----------------------------------------------------------------------
1056

1057    /**
1058     * Sets the time and element of the last tool tip event handled.
1059     */

1060    public void setLastToolTipEvent(long t, EventTarget JavaDoc et) {
1061        lastToolTipEventTimeStamp = t;
1062        lastToolTipEventTarget = et;
1063    }
1064
1065    /**
1066     * Checks if the specified event time and element are the same
1067     * as the last tool tip event.
1068     */

1069    public boolean matchLastToolTipEvent(long t, EventTarget JavaDoc et) {
1070        return lastToolTipEventTimeStamp == t
1071            && lastToolTipEventTarget == et;
1072    }
1073
1074    /**
1075     * Helper class. Simply keeps track of the last known mouse
1076     * position over the canvas.
1077     */

1078    protected class LocationListener extends MouseMotionAdapter JavaDoc {
1079
1080        protected int lastX, lastY;
1081
1082        public LocationListener () {
1083            lastX = 0; lastY = 0;
1084        }
1085
1086        public void mouseMoved(MouseEvent JavaDoc evt) {
1087            lastX = evt.getX();
1088            lastY = evt.getY();
1089        }
1090
1091        public int getLastX() {
1092            return lastX;
1093        }
1094
1095        public int getLastY() {
1096            return lastY;
1097        }
1098    }
1099
1100    /**
1101     * Sets a specific tooltip on the JSVGCanvas when a given event occurs.
1102     * This listener is used in the handleElement method to set, remove or
1103     * modify the JSVGCanvas tooltip on mouseover and on mouseout.<br/>
1104     *
1105     * Because we are on a single <tt>JComponent</tt> we trigger an artificial
1106     * <tt>MouseEvent</tt> when the toolTip is set to a non-null value, so as
1107     * to make sure it will show after the <tt>ToolTipManager</tt>'s default
1108     * delay.
1109     */

1110    protected class ToolTipModifier implements EventListener JavaDoc {
1111        /**
1112         * The CanvasUserAgent used to track the last tool tip event.
1113         */

1114        protected CanvasUserAgent canvasUserAgent;
1115
1116        /**
1117         * Creates a new ToolTipModifier object.
1118         */

1119        public ToolTipModifier() {
1120        }
1121
1122        public void handleEvent(Event JavaDoc evt){
1123            // Don't set the tool tip if another ToolTipModifier
1124
// has already handled this event (as it will have been
1125
// a higher priority tool tip).
1126
if (matchLastToolTipEvent(evt.getTimeStamp(), evt.getTarget())) {
1127                return;
1128            }
1129            setLastToolTipEvent(evt.getTimeStamp(), evt.getTarget());
1130            EventTarget JavaDoc prevLastTarget = lastTarget;
1131            if (SVGConstants.SVG_EVENT_MOUSEOVER.equals(evt.getType())) {
1132                lastTarget = evt.getTarget();
1133            } else if (SVGConstants.SVG_EVENT_MOUSEOUT.equals(evt.getType())) {
1134                // related target is one it is entering or null.
1135
org.w3c.dom.events.MouseEvent JavaDoc mouseEvt;
1136                mouseEvt = ((org.w3c.dom.events.MouseEvent JavaDoc)evt);
1137                lastTarget = mouseEvt.getRelatedTarget();
1138            }
1139
1140            if (toolTipMap != null) {
1141                Object JavaDoc o = toolTipMap.get(lastTarget);
1142                final String JavaDoc theToolTip;
1143                if (o == null) theToolTip = null;
1144                else theToolTip = (String JavaDoc)o;
1145                if (prevLastTarget != lastTarget)
1146                    EventQueue.invokeLater(new ToolTipRunnable(theToolTip));
1147            }
1148        }
1149    }
1150
1151    protected class ToolTipRunnable implements Runnable JavaDoc {
1152        String JavaDoc theToolTip;
1153        public ToolTipRunnable(String JavaDoc toolTip) {
1154            this.theToolTip = toolTip;
1155        }
1156
1157        public void run() {
1158            setToolTipText(theToolTip);
1159
1160            MouseEvent JavaDoc e;
1161            if (theToolTip != null) {
1162                e = new MouseEvent JavaDoc
1163                    (JSVGCanvas.this,
1164                     MouseEvent.MOUSE_ENTERED,
1165                     System.currentTimeMillis(),
1166                     0,
1167                     locationListener.getLastX(),
1168                     locationListener.getLastY(),
1169                     0,
1170                     false);
1171                ToolTipManager.sharedInstance().mouseEntered(e);
1172                e = new MouseEvent JavaDoc
1173                    (JSVGCanvas.this,
1174                     MouseEvent.MOUSE_MOVED,
1175                     System.currentTimeMillis(),
1176                     0,
1177                     locationListener.getLastX(),
1178                     locationListener.getLastY(),
1179                     0,
1180                     false);
1181                ToolTipManager.sharedInstance().mouseMoved(e);
1182            } else {
1183                e = new MouseEvent JavaDoc
1184                    (JSVGCanvas.this,
1185                     MouseEvent.MOUSE_MOVED,
1186                     System.currentTimeMillis(),
1187                     0,
1188                     locationListener.getLastX(),
1189                     locationListener.getLastY(),
1190                     0,
1191                     false);
1192                ToolTipManager.sharedInstance().mouseMoved(e);
1193            }
1194        }
1195    }
1196}
1197
Popular Tags