1 /** 2 * Copyright (c) 2008, Gaudenz Alder 3 */ 4 package com.mxgraph.swing; 5 6 import java.awt.BasicStroke; 7 import java.awt.Color; 8 import java.awt.Cursor; 9 import java.awt.Dimension; 10 import java.awt.Graphics; 11 import java.awt.Graphics2D; 12 import java.awt.Point; 13 import java.awt.Rectangle; 14 import java.awt.Stroke; 15 import java.awt.event.AdjustmentEvent; 16 import java.awt.event.AdjustmentListener; 17 import java.awt.event.ComponentAdapter; 18 import java.awt.event.ComponentEvent; 19 import java.awt.event.ComponentListener; 20 import java.awt.event.MouseEvent; 21 import java.awt.event.MouseListener; 22 import java.awt.event.MouseMotionListener; 23 import java.awt.geom.AffineTransform; 24 import java.awt.image.BufferedImage; 25 import java.util.logging.Level; 26 import java.util.logging.Logger; 27 28 import javax.swing.JComponent; 29 import javax.swing.JScrollBar; 30 31 import com.mxgraph.util.mxEvent; 32 import com.mxgraph.util.mxEventObject; 33 import com.mxgraph.util.mxEventSource.mxIEventListener; 34 import com.mxgraph.util.mxPoint; 35 import com.mxgraph.util.mxRectangle; 36 import com.mxgraph.util.mxUtils; 37 import com.mxgraph.view.mxGraphView; 38 39 /** 40 * An outline view for a specific graph component. 41 */ 42 public class mxGraphOutline extends JComponent 43 { 44 45 private static final Logger log = Logger.getLogger(mxGraphOutline.class.getName()); 46 47 /** 48 * 49 */ 50 private static final long serialVersionUID = -2521103946905154267L; 51 52 /** 53 * 54 */ 55 public static Color DEFAULT_ZOOMHANDLE_FILL = new Color(0, 255, 255); 56 57 /** 58 * 59 */ 60 protected mxGraphComponent graphComponent; 61 62 /** 63 * TODO: Not yet implemented. 64 */ 65 protected BufferedImage tripleBuffer; 66 67 /** 68 * Holds the graphics of the triple buffer. 69 */ 70 protected Graphics2D tripleBufferGraphics; 71 72 /** 73 * True if the triple buffer needs a full repaint. 74 */ 75 protected boolean repaintBuffer = false; 76 77 /** 78 * Clip of the triple buffer to be repainted. 79 */ 80 protected mxRectangle repaintClip = null; 81 82 /** 83 * 84 */ 85 protected boolean tripleBuffered = true; 86 87 /** 88 * 89 */ 90 protected Rectangle finderBounds = new Rectangle(); 91 92 /** 93 * 94 */ 95 protected Point zoomHandleLocation = null; 96 97 /** 98 * 99 */ 100 protected boolean finderVisible = true; 101 102 /** 103 * 104 */ 105 protected boolean zoomHandleVisible = true; 106 107 /** 108 * 109 */ 110 protected boolean useScaledInstance = false; 111 112 /** 113 * 114 */ 115 protected boolean antiAlias = false; 116 117 /** 118 * 119 */ 120 protected boolean drawLabels = false; 121 122 /** 123 * Specifies if the outline should be zoomed to the page if the graph 124 * component is in page layout mode. Default is true. 125 */ 126 protected boolean fitPage = true; 127 128 /** 129 * Not yet implemented. 130 * 131 * Border to add around the page bounds if wholePage is true. 132 * Default is 4. 133 */ 134 protected int outlineBorder = 10; 135 136 /** 137 * 138 */ 139 protected MouseTracker tracker = new MouseTracker(); 140 141 /** 142 * 143 */ 144 protected double scale = 1; 145 146 /** 147 * 148 */ 149 protected Point translate = new Point(); 150 151 /** 152 * 153 */ 154 protected transient boolean zoomGesture = false; 155 156 /** 157 * 158 */ 159 protected mxIEventListener repaintHandler = new mxIEventListener() 160 { 161 public void invoke(Object source, mxEventObject evt) 162 { 163 updateScaleAndTranslate(); 164 mxRectangle dirty = (mxRectangle) evt.getProperty("region"); 165 166 if (dirty != null) 167 { 168 repaintClip = new mxRectangle(dirty); 169 } 170 else 171 { 172 repaintBuffer = true; 173 } 174 175 if (dirty != null) 176 { 177 updateFinder(true); 178 179 dirty.grow(1 / scale); 180 181 dirty.setX(dirty.getX() * scale + translate.x); 182 dirty.setY(dirty.getY() * scale + translate.y); 183 dirty.setWidth(dirty.getWidth() * scale); 184 dirty.setHeight(dirty.getHeight() * scale); 185 186 repaint(dirty.getRectangle()); 187 } 188 else 189 { 190 updateFinder(false); 191 repaint(); 192 } 193 } 194 }; 195 196 /** 197 * 198 */ 199 protected ComponentListener componentHandler = new ComponentAdapter() 200 { 201 public void componentResized(ComponentEvent e) 202 { 203 if (updateScaleAndTranslate()) 204 { 205 repaintBuffer = true; 206 updateFinder(false); 207 repaint(); 208 } 209 else 210 { 211 updateFinder(true); 212 } 213 } 214 }; 215 216 /** 217 * 218 */ 219 protected AdjustmentListener adjustmentHandler = new AdjustmentListener() 220 { 221 222 /** 223 * 224 */ 225 public void adjustmentValueChanged(AdjustmentEvent e) 226 { 227 if (updateScaleAndTranslate()) 228 { 229 repaintBuffer = true; 230 updateFinder(false); 231 repaint(); 232 } 233 else 234 { 235 updateFinder(true); 236 } 237 } 238 239 }; 240 241 /** 242 * 243 */ mxGraphOutline(mxGraphComponent graphComponent)244 public mxGraphOutline(mxGraphComponent graphComponent) 245 { 246 addComponentListener(componentHandler); 247 addMouseMotionListener(tracker); 248 addMouseListener(tracker); 249 setGraphComponent(graphComponent); 250 setEnabled(true); 251 setOpaque(true); 252 } 253 254 /** 255 * Fires a property change event for <code>tripleBuffered</code>. 256 * 257 * @param tripleBuffered the tripleBuffered to set 258 */ setTripleBuffered(boolean tripleBuffered)259 public void setTripleBuffered(boolean tripleBuffered) 260 { 261 boolean oldValue = this.tripleBuffered; 262 this.tripleBuffered = tripleBuffered; 263 264 if (!tripleBuffered) 265 { 266 destroyTripleBuffer(); 267 } 268 269 firePropertyChange("tripleBuffered", oldValue, tripleBuffered); 270 } 271 272 /** 273 * 274 */ isTripleBuffered()275 public boolean isTripleBuffered() 276 { 277 return tripleBuffered; 278 } 279 280 /** 281 * Fires a property change event for <code>drawLabels</code>. 282 * 283 * @param drawLabels the drawLabels to set 284 */ setDrawLabels(boolean drawLabels)285 public void setDrawLabels(boolean drawLabels) 286 { 287 boolean oldValue = this.drawLabels; 288 this.drawLabels = drawLabels; 289 repaintTripleBuffer(null); 290 291 firePropertyChange("drawLabels", oldValue, drawLabels); 292 } 293 294 /** 295 * 296 */ isDrawLabels()297 public boolean isDrawLabels() 298 { 299 return drawLabels; 300 } 301 302 /** 303 * Fires a property change event for <code>antiAlias</code>. 304 * 305 * @param antiAlias the antiAlias to set 306 */ setAntiAlias(boolean antiAlias)307 public void setAntiAlias(boolean antiAlias) 308 { 309 boolean oldValue = this.antiAlias; 310 this.antiAlias = antiAlias; 311 repaintTripleBuffer(null); 312 313 firePropertyChange("antiAlias", oldValue, antiAlias); 314 } 315 316 /** 317 * @return the antiAlias 318 */ isAntiAlias()319 public boolean isAntiAlias() 320 { 321 return antiAlias; 322 } 323 324 /** 325 * 326 */ setVisible(boolean visible)327 public void setVisible(boolean visible) 328 { 329 super.setVisible(visible); 330 331 // Frees memory if the outline is hidden 332 if (!visible) 333 { 334 destroyTripleBuffer(); 335 } 336 } 337 338 /** 339 * 340 */ setFinderVisible(boolean visible)341 public void setFinderVisible(boolean visible) 342 { 343 finderVisible = visible; 344 } 345 346 /** 347 * 348 */ setZoomHandleVisible(boolean visible)349 public void setZoomHandleVisible(boolean visible) 350 { 351 zoomHandleVisible = visible; 352 } 353 354 /** 355 * Fires a property change event for <code>fitPage</code>. 356 * 357 * @param fitPage the fitPage to set 358 */ setFitPage(boolean fitPage)359 public void setFitPage(boolean fitPage) 360 { 361 boolean oldValue = this.fitPage; 362 this.fitPage = fitPage; 363 364 if (updateScaleAndTranslate()) 365 { 366 repaintBuffer = true; 367 updateFinder(false); 368 } 369 370 firePropertyChange("fitPage", oldValue, fitPage); 371 } 372 373 /** 374 * 375 */ isFitPage()376 public boolean isFitPage() 377 { 378 return fitPage; 379 } 380 381 /** 382 * 383 */ getGraphComponent()384 public mxGraphComponent getGraphComponent() 385 { 386 return graphComponent; 387 } 388 389 /** 390 * Fires a property change event for <code>graphComponent</code>. 391 * 392 * @param graphComponent the graphComponent to set 393 */ setGraphComponent(mxGraphComponent graphComponent)394 public void setGraphComponent(mxGraphComponent graphComponent) 395 { 396 mxGraphComponent oldValue = this.graphComponent; 397 398 if (this.graphComponent != null) 399 { 400 this.graphComponent.getGraph().removeListener(repaintHandler); 401 this.graphComponent.getGraphControl().removeComponentListener( 402 componentHandler); 403 this.graphComponent.getHorizontalScrollBar() 404 .removeAdjustmentListener(adjustmentHandler); 405 this.graphComponent.getVerticalScrollBar() 406 .removeAdjustmentListener(adjustmentHandler); 407 } 408 409 this.graphComponent = graphComponent; 410 411 if (this.graphComponent != null) 412 { 413 this.graphComponent.getGraph().addListener(mxEvent.REPAINT, 414 repaintHandler); 415 this.graphComponent.getGraphControl().addComponentListener( 416 componentHandler); 417 this.graphComponent.getHorizontalScrollBar().addAdjustmentListener( 418 adjustmentHandler); 419 this.graphComponent.getVerticalScrollBar().addAdjustmentListener( 420 adjustmentHandler); 421 } 422 423 if (updateScaleAndTranslate()) 424 { 425 repaintBuffer = true; 426 repaint(); 427 } 428 429 firePropertyChange("graphComponent", oldValue, graphComponent); 430 } 431 432 /** 433 * Checks if the triple buffer exists and creates a new one if 434 * it does not. Also compares the size of the buffer with the 435 * size of the graph and drops the buffer if it has a 436 * different size. 437 */ checkTripleBuffer()438 public void checkTripleBuffer() 439 { 440 if (tripleBuffer != null) 441 { 442 if (tripleBuffer.getWidth() != getWidth() 443 || tripleBuffer.getHeight() != getHeight()) 444 { 445 // Resizes the buffer (destroys existing and creates new) 446 destroyTripleBuffer(); 447 } 448 } 449 450 if (tripleBuffer == null) 451 { 452 createTripleBuffer(getWidth(), getHeight()); 453 } 454 } 455 456 /** 457 * Creates the tripleBufferGraphics and tripleBuffer for the given 458 * dimension and draws the complete graph onto the triplebuffer. 459 * 460 * @param width 461 * @param height 462 */ createTripleBuffer(int width, int height)463 protected void createTripleBuffer(int width, int height) 464 { 465 try 466 { 467 tripleBuffer = mxUtils.createBufferedImage(width, height, null); 468 tripleBufferGraphics = tripleBuffer.createGraphics(); 469 470 // Repaints the complete buffer 471 repaintTripleBuffer(null); 472 } 473 catch (OutOfMemoryError error) 474 { 475 log.log(Level.SEVERE, "Failed to create a triple buffer", error); 476 } 477 } 478 479 /** 480 * Destroys the tripleBuffer and tripleBufferGraphics objects. 481 */ destroyTripleBuffer()482 public void destroyTripleBuffer() 483 { 484 if (tripleBuffer != null) 485 { 486 tripleBuffer = null; 487 tripleBufferGraphics.dispose(); 488 tripleBufferGraphics = null; 489 } 490 } 491 492 /** 493 * Clears and repaints the triple buffer at the given rectangle or repaints 494 * the complete buffer if no rectangle is specified. 495 * 496 * @param clip 497 */ repaintTripleBuffer(Rectangle clip)498 public void repaintTripleBuffer(Rectangle clip) 499 { 500 if (tripleBuffered && tripleBufferGraphics != null) 501 { 502 if (clip == null) 503 { 504 clip = new Rectangle(tripleBuffer.getWidth(), 505 tripleBuffer.getHeight()); 506 } 507 508 // Clears and repaints the dirty rectangle using the 509 // graphics canvas of the graph component as a renderer 510 mxUtils.clearRect(tripleBufferGraphics, clip, null); 511 tripleBufferGraphics.setClip(clip); 512 paintGraph(tripleBufferGraphics); 513 tripleBufferGraphics.setClip(null); 514 515 repaintBuffer = false; 516 repaintClip = null; 517 } 518 } 519 520 /** 521 * 522 */ updateFinder(boolean repaint)523 public void updateFinder(boolean repaint) 524 { 525 Rectangle rect = graphComponent.getViewport().getViewRect(); 526 527 int x = (int) Math.round(rect.x * scale); 528 int y = (int) Math.round(rect.y * scale); 529 int w = (int) Math.round((rect.x + rect.width) * scale) - x; 530 int h = (int) Math.round((rect.y + rect.height) * scale) - y; 531 532 updateFinderBounds(new Rectangle(x + translate.x, y + translate.y, 533 w + 1, h + 1), repaint); 534 } 535 536 /** 537 * 538 */ updateFinderBounds(Rectangle bounds, boolean repaint)539 public void updateFinderBounds(Rectangle bounds, boolean repaint) 540 { 541 if (bounds != null && !bounds.equals(finderBounds)) 542 { 543 Rectangle old = new Rectangle(finderBounds); 544 finderBounds = bounds; 545 546 // LATER: Fix repaint region to be smaller 547 if (repaint) 548 { 549 old = old.union(finderBounds); 550 old.grow(3, 3); 551 repaint(old); 552 } 553 } 554 } 555 556 /** 557 * 558 */ paintComponent(Graphics g)559 public void paintComponent(Graphics g) 560 { 561 super.paintComponent(g); 562 paintBackground(g); 563 564 if (graphComponent != null) 565 { 566 // Creates or destroys the triple buffer as needed 567 if (tripleBuffered) 568 { 569 checkTripleBuffer(); 570 } 571 else if (tripleBuffer != null) 572 { 573 destroyTripleBuffer(); 574 } 575 576 // Updates the dirty region from the buffered graph image 577 if (tripleBuffer != null) 578 { 579 if (repaintBuffer) 580 { 581 repaintTripleBuffer(null); 582 } 583 else if (repaintClip != null) 584 { 585 repaintClip.grow(1 / scale); 586 587 repaintClip.setX(repaintClip.getX() * scale + translate.x); 588 repaintClip.setY(repaintClip.getY() * scale + translate.y); 589 repaintClip.setWidth(repaintClip.getWidth() * scale); 590 repaintClip.setHeight(repaintClip.getHeight() * scale); 591 592 repaintTripleBuffer(repaintClip.getRectangle()); 593 } 594 595 mxUtils.drawImageClip(g, tripleBuffer, this); 596 } 597 598 // Paints the graph directly onto the graphics 599 else 600 { 601 paintGraph(g); 602 } 603 604 paintForeground(g); 605 } 606 } 607 608 /** 609 * Paints the background. 610 */ paintBackground(Graphics g)611 protected void paintBackground(Graphics g) 612 { 613 if (graphComponent != null) 614 { 615 Graphics2D g2 = (Graphics2D) g; 616 AffineTransform tx = g2.getTransform(); 617 618 try 619 { 620 // Draws the background of the outline if a graph exists 621 g.setColor(graphComponent.getPageBackgroundColor()); 622 mxUtils.fillClippedRect(g, 0, 0, getWidth(), getHeight()); 623 624 g2.translate(translate.x, translate.y); 625 g2.scale(scale, scale); 626 627 // Draws the scaled page background 628 if (!graphComponent.isPageVisible()) 629 { 630 Color bg = graphComponent.getBackground(); 631 632 if (graphComponent.getViewport().isOpaque()) 633 { 634 bg = graphComponent.getViewport().getBackground(); 635 } 636 637 g.setColor(bg); 638 Dimension size = graphComponent.getGraphControl().getSize(); 639 640 // Paints the background of the drawing surface 641 mxUtils.fillClippedRect(g, 0, 0, size.width, size.height); 642 g.setColor(g.getColor().darker().darker()); 643 g.drawRect(0, 0, size.width, size.height); 644 } 645 else 646 { 647 // Paints the page background using the graphics scaling 648 graphComponent.paintBackgroundPage(g); 649 } 650 } 651 finally 652 { 653 g2.setTransform(tx); 654 } 655 } 656 else 657 { 658 // Draws the background of the outline if no graph exists 659 g.setColor(getBackground()); 660 mxUtils.fillClippedRect(g, 0, 0, getWidth(), getHeight()); 661 } 662 } 663 664 /** 665 * Paints the graph outline. 666 */ paintGraph(Graphics g)667 public void paintGraph(Graphics g) 668 { 669 if (graphComponent != null) 670 { 671 Graphics2D g2 = (Graphics2D) g; 672 AffineTransform tx = g2.getTransform(); 673 674 try 675 { 676 Point tr = graphComponent.getGraphControl().getTranslate(); 677 g2.translate(translate.x + tr.getX() * scale, 678 translate.y + tr.getY() * scale); 679 g2.scale(scale, scale); 680 681 // Draws the scaled graph 682 graphComponent.getGraphControl().drawGraph(g2, drawLabels); 683 } 684 finally 685 { 686 g2.setTransform(tx); 687 } 688 } 689 } 690 691 /** 692 * Paints the foreground. Foreground is dynamic and should never be made 693 * part of the triple buffer. It is painted on top of the buffer. 694 */ paintForeground(Graphics g)695 protected void paintForeground(Graphics g) 696 { 697 if (graphComponent != null) 698 { 699 Graphics2D g2 = (Graphics2D) g; 700 701 Stroke stroke = g2.getStroke(); 702 g.setColor(Color.BLUE); 703 g2.setStroke(new BasicStroke(3)); 704 g.drawRect(finderBounds.x, finderBounds.y, finderBounds.width, 705 finderBounds.height); 706 707 if (zoomHandleVisible) 708 { 709 g2.setStroke(stroke); 710 g.setColor(DEFAULT_ZOOMHANDLE_FILL); 711 g.fillRect(finderBounds.x + finderBounds.width - 6, finderBounds.y 712 + finderBounds.height - 6, 8, 8); 713 g.setColor(Color.BLACK); 714 g.drawRect(finderBounds.x + finderBounds.width - 6, finderBounds.y 715 + finderBounds.height - 6, 8, 8); 716 } 717 } 718 } 719 720 /** 721 * Returns true if the scale or translate has changed. 722 */ updateScaleAndTranslate()723 public boolean updateScaleAndTranslate() 724 { 725 double newScale = 1; 726 int dx = 0; 727 int dy = 0; 728 729 if (this.graphComponent != null) 730 { 731 Dimension graphSize = graphComponent.getGraphControl().getSize(); 732 Dimension outlineSize = getSize(); 733 734 int gw = (int) graphSize.getWidth(); 735 int gh = (int) graphSize.getHeight(); 736 737 if (gw > 0 && gh > 0) 738 { 739 boolean magnifyPage = graphComponent.isPageVisible() 740 && isFitPage() 741 && graphComponent.getHorizontalScrollBar().isVisible() 742 && graphComponent.getVerticalScrollBar().isVisible(); 743 double graphScale = graphComponent.getGraph().getView() 744 .getScale(); 745 mxPoint trans = graphComponent.getGraph().getView() 746 .getTranslate(); 747 748 int w = (int) outlineSize.getWidth() - 2 * outlineBorder; 749 int h = (int) outlineSize.getHeight() - 2 * outlineBorder; 750 751 if (magnifyPage) 752 { 753 gw -= 2 * Math.round(trans.getX() * graphScale); 754 gh -= 2 * Math.round(trans.getY() * graphScale); 755 } 756 757 newScale = Math.min((double) w / gw, (double) h / gh); 758 759 dx += (int) Math 760 .round((outlineSize.getWidth() - gw * newScale) / 2); 761 dy += (int) Math 762 .round((outlineSize.getHeight() - gh * newScale) / 2); 763 764 if (magnifyPage) 765 { 766 dx -= Math.round(trans.getX() * newScale * graphScale); 767 dy -= Math.round(trans.getY() * newScale * graphScale); 768 } 769 } 770 } 771 772 if (newScale != scale || translate.x != dx || translate.y != dy) 773 { 774 scale = newScale; 775 translate.setLocation(dx, dy); 776 777 return true; 778 } 779 else 780 { 781 return false; 782 } 783 } 784 785 /** 786 * 787 */ 788 public class MouseTracker implements MouseListener, MouseMotionListener 789 { 790 /** 791 * 792 */ 793 protected Point start = null; 794 795 /* 796 * (non-Javadoc) 797 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) 798 */ mousePressed(MouseEvent e)799 public void mousePressed(MouseEvent e) 800 { 801 zoomGesture = hitZoomHandle(e.getX(), e.getY()); 802 803 if (graphComponent != null && !e.isConsumed() 804 && !e.isPopupTrigger() 805 && (finderBounds.contains(e.getPoint()) || zoomGesture)) 806 { 807 start = e.getPoint(); 808 } 809 } 810 811 /* 812 * (non-Javadoc) 813 * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent) 814 */ mouseDragged(MouseEvent e)815 public void mouseDragged(MouseEvent e) 816 { 817 if (isEnabled() && start != null) 818 { 819 if (zoomGesture) 820 { 821 Rectangle bounds = graphComponent.getViewport() 822 .getViewRect(); 823 double viewRatio = bounds.getWidth() / bounds.getHeight(); 824 825 bounds = new Rectangle(finderBounds); 826 bounds.width = (int) Math 827 .max(0, (e.getX() - bounds.getX())); 828 bounds.height = (int) Math.max(0, 829 (bounds.getWidth() / viewRatio)); 830 831 updateFinderBounds(bounds, true); 832 } 833 else 834 { 835 // TODO: To enable constrained moving, that is, moving 836 // into only x- or y-direction when shift is pressed, 837 // we need the location of the first mouse event, since 838 // the movement can not be constrained for incremental 839 // steps as used below. 840 int dx = (int) ((e.getX() - start.getX()) / scale); 841 int dy = (int) ((e.getY() - start.getY()) / scale); 842 843 // Keeps current location as start for delta movement 844 // of the scrollbars 845 start = e.getPoint(); 846 847 graphComponent.getHorizontalScrollBar().setValue( 848 graphComponent.getHorizontalScrollBar().getValue() 849 + dx); 850 graphComponent.getVerticalScrollBar().setValue( 851 graphComponent.getVerticalScrollBar().getValue() 852 + dy); 853 } 854 } 855 } 856 857 /* 858 * (non-Javadoc) 859 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) 860 */ mouseReleased(MouseEvent e)861 public void mouseReleased(MouseEvent e) 862 { 863 if (start != null) 864 { 865 if (zoomGesture) 866 { 867 double dx = e.getX() - start.getX(); 868 double w = finderBounds.getWidth(); 869 870 final JScrollBar hs = graphComponent 871 .getHorizontalScrollBar(); 872 final double sx; 873 874 if (hs != null) 875 { 876 sx = (double) hs.getValue() / hs.getMaximum(); 877 } 878 else 879 { 880 sx = 0; 881 } 882 883 final JScrollBar vs = graphComponent.getVerticalScrollBar(); 884 final double sy; 885 886 if (vs != null) 887 { 888 sy = (double) vs.getValue() / vs.getMaximum(); 889 } 890 else 891 { 892 sy = 0; 893 } 894 895 mxGraphView view = graphComponent.getGraph().getView(); 896 double scale = view.getScale(); 897 double newScale = scale - (dx * scale) / w; 898 double factor = newScale / scale; 899 view.setScale(newScale); 900 901 if (hs != null) 902 { 903 hs.setValue((int) (sx * hs.getMaximum() * factor)); 904 } 905 906 if (vs != null) 907 { 908 vs.setValue((int) (sy * vs.getMaximum() * factor)); 909 } 910 } 911 912 zoomGesture = false; 913 start = null; 914 } 915 } 916 917 /** 918 * 919 */ hitZoomHandle(int x, int y)920 public boolean hitZoomHandle(int x, int y) 921 { 922 return new Rectangle(finderBounds.x + finderBounds.width - 6, 923 finderBounds.y + finderBounds.height - 6, 8, 8).contains(x, 924 y); 925 } 926 927 /* 928 * (non-Javadoc) 929 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent) 930 */ mouseMoved(MouseEvent e)931 public void mouseMoved(MouseEvent e) 932 { 933 if (hitZoomHandle(e.getX(), e.getY())) 934 { 935 setCursor(new Cursor(Cursor.HAND_CURSOR)); 936 } 937 else if (finderBounds.contains(e.getPoint())) 938 { 939 setCursor(new Cursor(Cursor.MOVE_CURSOR)); 940 } 941 else 942 { 943 setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 944 } 945 } 946 947 /* 948 * (non-Javadoc) 949 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) 950 */ mouseClicked(MouseEvent e)951 public void mouseClicked(MouseEvent e) 952 { 953 // ignore 954 } 955 956 /* 957 * (non-Javadoc) 958 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) 959 */ mouseEntered(MouseEvent e)960 public void mouseEntered(MouseEvent e) 961 { 962 // ignore 963 } 964 965 /* 966 * (non-Javadoc) 967 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) 968 */ mouseExited(MouseEvent e)969 public void mouseExited(MouseEvent e) 970 { 971 // ignore 972 } 973 974 } 975 976 } 977