| 1 18 package org.apache.batik.swing; 19 20 import java.awt.Dimension ; 21 import java.awt.EventQueue ; 22 import java.awt.event.ActionEvent ; 23 import java.awt.event.InputEvent ; 24 import java.awt.event.KeyEvent ; 25 import java.awt.event.MouseAdapter ; 26 import java.awt.event.MouseEvent ; 27 import java.awt.event.MouseMotionAdapter ; 28 import java.awt.geom.AffineTransform ; 29 import java.beans.PropertyChangeListener ; 30 import java.beans.PropertyChangeSupport ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.WeakHashMap ; 35 36 import javax.swing.AbstractAction ; 37 import javax.swing.ActionMap ; 38 import javax.swing.InputMap ; 39 import javax.swing.JComponent ; 40 import javax.swing.JDialog ; 41 import javax.swing.JOptionPane ; 42 import javax.swing.KeyStroke ; 43 import javax.swing.ToolTipManager ; 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 ; 60 import org.w3c.dom.Node ; 61 import org.w3c.dom.events.Event ; 62 import org.w3c.dom.events.EventListener ; 63 import org.w3c.dom.events.EventTarget ; 64 import org.w3c.dom.svg.SVGDocument; 65 66 78 public class JSVGCanvas extends JSVGComponent { 79 80 83 public static final String SCROLL_RIGHT_ACTION = "ScrollRight"; 84 85 88 public static final String SCROLL_LEFT_ACTION = "ScrollLeft"; 89 90 93 public static final String SCROLL_UP_ACTION = "ScrollUp"; 94 95 98 public static final String SCROLL_DOWN_ACTION = "ScrollDown"; 99 100 103 public static final String FAST_SCROLL_RIGHT_ACTION = "FastScrollRight"; 104 105 108 public static final String FAST_SCROLL_LEFT_ACTION = "FastScrollLeft"; 109 110 113 public static final String FAST_SCROLL_UP_ACTION = "FastScrollUp"; 114 115 118 public static final String FAST_SCROLL_DOWN_ACTION = "FastScrollDown"; 119 120 123 public static final String ZOOM_IN_ACTION = "ZoomIn"; 124 125 128 public static final String ZOOM_OUT_ACTION = "ZoomOut"; 129 130 133 public static final String RESET_TRANSFORM_ACTION = "ResetTransform"; 134 135 139 private boolean isZoomInteractorEnabled = true; 140 141 145 private boolean isImageZoomInteractorEnabled = true; 146 147 151 private boolean isPanInteractorEnabled = true; 152 153 157 private boolean isRotateInteractorEnabled = true; 158 159 163 private boolean isResetTransformInteractorEnabled = true; 164 165 169 protected PropertyChangeSupport pcs = new PropertyChangeSupport (this); 170 171 174 protected String uri; 175 176 180 protected LocationListener locationListener = new LocationListener(); 181 182 186 protected Map toolTipMap = null; 187 protected EventListener toolTipListener = new ToolTipModifier(); 188 protected EventTarget lastTarget = null;; 189 192 protected long lastToolTipEventTimeStamp; 193 194 197 protected EventTarget lastToolTipEventTarget; 198 199 200 201 204 public JSVGCanvas() { 205 this(null, true, true); 206 addMouseMotionListener(locationListener); 207 } 208 209 217 public JSVGCanvas(SVGUserAgent ua, 218 boolean eventsEnabled, 219 boolean selectableText) { 220 221 super(ua, eventsEnabled, selectableText); 222 223 setPreferredSize(new Dimension (200, 200)); 224 setMinimumSize(new Dimension (100, 100)); 225 226 List 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 () { 237 public void mousePressed(MouseEvent evt) { 238 requestFocus(); 239 } 240 }); 241 242 installKeyboardActions(); 243 } 244 addMouseMotionListener(locationListener); 245 } 246 247 251 protected void installActions() { 252 ActionMap 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 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 294 protected void installKeyboardActions() { 295 296 InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED); 297 KeyStroke 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 338 public void addPropertyChangeListener(PropertyChangeListener pcl) { 339 pcs.addPropertyChangeListener(pcl); 340 } 341 342 347 public void removePropertyChangeListener(PropertyChangeListener pcl) { 348 pcs.removePropertyChangeListener(pcl); 349 } 350 351 358 public void addPropertyChangeListener(String propertyName, 359 PropertyChangeListener pcl) { 360 pcs.addPropertyChangeListener(propertyName, pcl); 361 } 362 363 370 public void removePropertyChangeListener(String propertyName, 371 PropertyChangeListener pcl) { 372 pcs.removePropertyChangeListener(propertyName, pcl); 373 } 374 375 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 394 public boolean getEnableZoomInteractor() { 395 return isZoomInteractorEnabled; 396 } 397 398 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 417 public boolean getEnableImageZoomInteractor() { 418 return isImageZoomInteractorEnabled; 419 } 420 421 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 440 public boolean getEnablePanInteractor() { 441 return isPanInteractorEnabled; 442 } 443 444 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 463 public boolean getEnableRotateInteractor() { 464 return isRotateInteractorEnabled; 465 } 466 467 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 489 public boolean getEnableResetTransformInteractor() { 490 return isResetTransformInteractorEnabled; 491 } 492 493 496 public String getURI() { 497 return uri; 498 } 499 500 507 public void setURI(String newURI) { 508 String 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 522 protected UserAgent createUserAgent() { 523 return new CanvasUserAgent(); 524 } 525 526 529 protected Listener createListener() { 530 return new CanvasSVGListener(); 531 } 532 533 536 protected class CanvasSVGListener extends JSVGComponent.SVGListener { 537 538 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 root; 551 root = (EventTarget )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 root; 565 root = (EventTarget )doc.getRootElement(); 566 root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOVER, 568 toolTipListener, false); 569 root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT, 571 toolTipListener, false); 572 } 573 574 super.installSVGDocument(doc); 575 } 576 577 581 584 public class ResetTransformAction extends AbstractAction { 585 public void actionPerformed(ActionEvent evt) { 586 fragmentIdentifier = null; 587 resetRenderingTransform(); 588 } 589 } 590 591 598 public class AffineAction extends AbstractAction { 599 AffineTransform at; 600 public AffineAction(AffineTransform at) { 601 this.at = at; 602 } 603 604 public void actionPerformed(ActionEvent evt) { 605 if (gvtRoot == null) { 606 return; 607 } 608 AffineTransform rat = getRenderingTransform(); 609 if (at != null) { 610 Dimension dim = getSize(); 611 int x = dim.width / 2; 612 int y = dim.height / 2; 613 AffineTransform 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 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 638 public class ZoomInAction extends ZoomAction { 639 ZoomInAction() { super(2); } 640 } 641 642 645 public class ZoomOutAction extends ZoomAction { 646 ZoomOutAction() { super(.5); } 647 } 648 649 652 public class RotateAction extends AffineAction { 653 public RotateAction(double theta) { 654 super(AffineTransform.getRotateInstance(theta)); 655 } 656 } 657 658 661 public class ScrollAction extends AffineAction { 662 public ScrollAction(double tx, double ty) { 663 super(AffineTransform.getTranslateInstance(tx, ty)); 664 } 665 } 666 667 671 public class ScrollRightAction extends ScrollAction { 672 public ScrollRightAction(int inc) { 673 super(-inc, 0); 674 } 675 } 676 677 681 public class ScrollLeftAction extends ScrollAction { 682 public ScrollLeftAction(int inc) { 683 super(inc, 0); 684 } 685 } 686 687 691 public class ScrollUpAction extends ScrollAction { 692 public ScrollUpAction(int inc) { 693 super(0, inc); 694 } 695 } 696 697 701 public class ScrollDownAction extends ScrollAction { 702 public ScrollDownAction(int inc) { 703 super(0, -inc); 704 } 705 } 706 707 711 715 protected Interactor zoomInteractor = new AbstractZoomInteractor() { 716 public boolean startInteraction(InputEvent 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 729 protected Interactor imageZoomInteractor 730 = new AbstractImageZoomInteractor() { 731 public boolean startInteraction(InputEvent 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 744 protected Interactor panInteractor = new AbstractPanInteractor() { 745 public boolean startInteraction(InputEvent 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 758 protected Interactor rotateInteractor = new AbstractRotateInteractor() { 759 public boolean startInteraction(InputEvent 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 772 protected Interactor resetTransformInteractor = 773 new AbstractResetTransformInteractor() { 774 public boolean startInteraction(InputEvent 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 788 794 protected class CanvasUserAgent extends BridgeUserAgent 795 796 implements XMLConstants { 797 798 final String TOOLTIP_TITLE_ONLY 799 = "JSVGCanvas.CanvasUserAgent.ToolTip.titleOnly"; 800 final String TOOLTIP_DESC_ONLY 801 = "JSVGCanvas.CanvasUserAgent.ToolTip.descOnly"; 802 final String TOOLTIP_TITLE_AND_TEXT 803 = "JSVGCanvas.CanvasUserAgent.ToolTip.titleAndDesc"; 804 805 823 public void handleElement(Element elt, Object data){ 824 super.handleElement(elt, data); 825 826 if (!isInteractive()) return; 828 829 if (!SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI())) 830 return; 831 832 if (elt.getParentNode() == 834 elt.getOwnerDocument().getDocumentElement()) { 835 return; 836 } 837 838 Element parent; 839 if (data instanceof Element ) parent = (Element )data; 842 else parent = (Element )elt.getParentNode(); 843 844 Element descPeer = null; 845 Element 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 titleTip = null; 861 if (titlePeer != null) { 862 titlePeer.normalize(); 863 if (titlePeer.getFirstChild() != null) 86
|