| 1 18 package org.apache.batik.gvt; 19 20 import java.awt.Graphics2D ; 21 import java.awt.Rectangle ; 22 import java.awt.Shape ; 23 import java.awt.geom.AffineTransform ; 24 import java.awt.geom.GeneralPath ; 25 import java.awt.geom.Point2D ; 26 import java.awt.geom.Rectangle2D ; 27 import java.util.Collection ; 28 import java.util.ConcurrentModificationException ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.ListIterator ; 32 import java.util.NoSuchElementException ; 33 34 import org.apache.batik.util.HaltingThread; 35 36 42 public class CompositeGraphicsNode extends AbstractGraphicsNode 43 implements List { 44 45 public static final Rectangle2D VIEWPORT = new Rectangle (); 46 public static final Rectangle2D NULL_RECT = new Rectangle (); 47 48 51 protected GraphicsNode [] children; 52 53 56 protected int count; 57 58 61 protected int modCount; 62 63 67 protected Rectangle2D backgroundEnableRgn = null; 68 69 73 private Rectangle2D geometryBounds; 74 75 78 private Rectangle2D primitiveBounds; 79 80 83 private Rectangle2D sensitiveBounds; 84 85 88 private Shape outline; 89 90 93 public CompositeGraphicsNode() {} 94 95 99 102 public List getChildren() { 103 return this; 104 } 105 106 111 public void setBackgroundEnable(Rectangle2D bgRgn) { 112 backgroundEnableRgn = bgRgn; 113 } 114 115 118 public Rectangle2D getBackgroundEnable() { 119 return backgroundEnableRgn; 120 } 121 122 129 public void setVisible(boolean isVisible) { 130 this.isVisible = isVisible; 132 } 134 135 136 140 145 public void primitivePaint(Graphics2D g2d) { 146 if (count == 0) { 147 return; 148 } 149 150 for (int i=0; i < count; ++i) { 152 if (HaltingThread.hasBeenHalted()) 153 return; 154 155 GraphicsNode node = children[i]; 156 if (node == null) { 157 continue; 158 } 159 node.paint(g2d); 160 161 } 162 } 163 164 168 169 173 178 protected void invalidateGeometryCache() { 179 super.invalidateGeometryCache(); 180 geometryBounds = null; 181 primitiveBounds = null; 182 sensitiveBounds = null; 183 outline = null; 184 } 185 186 189 public Rectangle2D getPrimitiveBounds() { 190 if (primitiveBounds != null) { 191 if (primitiveBounds == NULL_RECT) return null; 192 return primitiveBounds; 193 } 194 195 int i=0; 196 Rectangle2D bounds = null; 197 while ((bounds == null) && i < count) { 198 bounds = children[i++].getTransformedBounds(IDENTITY); 199 if (((i & 0x0F) == 0) && HaltingThread.hasBeenHalted()) 200 break; } 202 if (HaltingThread.hasBeenHalted()) { 203 invalidateGeometryCache(); 204 return null; 205 } 206 207 if (bounds == null) { 208 primitiveBounds = NULL_RECT; 209 return null; 210 } 211 212 primitiveBounds = bounds; 213 Rectangle2D ctb = null; 214 while (i < count) { 215 ctb = children[i++].getTransformedBounds(IDENTITY); 216 if (ctb != null) { 217 if (primitiveBounds == null) { 218 return null; 221 } else { 222 primitiveBounds.add(ctb); 223 } 224 } 225 226 if (((i & 0x0F) == 0) && HaltingThread.hasBeenHalted()) 227 break; } 229 230 if (HaltingThread.hasBeenHalted()) { 232 invalidateGeometryCache(); 235 } 236 return primitiveBounds; 237 } 238 239 244 public static Rectangle2D getTransformedBBox(Rectangle2D r2d, AffineTransform t) { 245 if ((t == null) || (r2d == null)) return r2d; 246 247 double x = r2d.getX(); 248 double w = r2d.getWidth(); 249 double y = r2d.getY(); 250 double h = r2d.getHeight(); 251 252 double sx = t.getScaleX(); 253 double sy = t.getScaleY(); 254 if (sx < 0) { 255 x = -(x + w); 256 sx = -sx; 257 } 258 if (sy < 0) { 259 y = -(y + h); 260 sy = -sy; 261 } 262 263 return new Rectangle2D.Float  264 ((float)(x*sx+t.getTranslateX()), 265 (float)(y*sy+t.getTranslateY()), 266 (float)(w*sx), (float)(h*sy)); 267 } 268 269 276 public Rectangle2D getTransformedPrimitiveBounds(AffineTransform txf) { 277 AffineTransform t = txf; 278 if (transform != null) { 279 t = new AffineTransform (txf); 280 t.concatenate(transform); 281 } 282 283 if ((t == null) || ((t.getShearX() == 0) && (t.getShearY() == 0))) { 284 return getTransformedBBox(getPrimitiveBounds(), t); 286 } 287 288 int i = 0; 289 Rectangle2D tpb = null; 290 while (tpb == null && i < count) { 291 tpb = children[i++].getTransformedBounds(t); 292 } 293 294 Rectangle2D ctb = null; 295 while (i < count) { 296 ctb = children[i++].getTransformedBounds(t); 297 if(ctb != null){ 298 tpb.add(ctb); 299 } 300 } 301 302 return tpb; 303 } 304 305 311 public Rectangle2D getGeometryBounds() { 312 if (geometryBounds == null) { 313 int i=0; 315 while(geometryBounds == null && i < count){ 316 geometryBounds = 317 children[i++].getTransformedGeometryBounds (IDENTITY); 318 } 319 320 Rectangle2D cgb = null; 321 while (i<count) { 322 cgb = children[i++].getTransformedGeometryBounds(IDENTITY); 323 if (cgb != null) { 324 if (geometryBounds == null) { 325 return getGeometryBounds(); 328 } else { 329 geometryBounds.add(cgb); 330 } 331 } 332 } 333 } 334 335 return geometryBounds; 336 } 337 338 348 public Rectangle2D getTransformedGeometryBounds(AffineTransform txf) { 349 AffineTransform t = txf; 350 if (transform != null) { 351 t = new AffineTransform (txf); 352 t.concatenate(transform); 353 } 354 355 if ((t == null) || ((t.getShearX() == 0) && (t.getShearY() == 0))) { 356 return getTransformedBBox(getGeometryBounds(), t); 358 } 359 360 Rectangle2D gb = null; 361 int i=0; 362 while (gb == null && i < count) { 363 gb = children[i++].getTransformedGeometryBounds(t); 364 } 365 366 Rectangle2D cgb = null; 367 while (i < count) { 368 cgb = children[i++].getTransformedGeometryBounds(t); 369 if (cgb != null) { 370 gb.add(cgb); 371 } 372 } 373 374 return gb; 375 } 376 377 382 public Rectangle2D getSensitiveBounds() { 383 if (sensitiveBounds != null) 384 return sensitiveBounds; 385 386 int i=0; 388 while(sensitiveBounds == null && i < count){ 389 sensitiveBounds = 390 children[i++].getTransformedSensitiveBounds(IDENTITY); 391 } 392 393 Rectangle2D cgb = null; 394 while (i<count) { 395 cgb = children[i++].getTransformedSensitiveBounds(IDENTITY); 396 if (cgb != null) { 397 if (sensitiveBounds == null) 398 return getSensitiveBounds(); 401 402 sensitiveBounds.add(cgb); 403 } 404 } 405 406 return sensitiveBounds; 407 } 408 409 419 public Rectangle2D getTransformedSensitiveBounds(AffineTransform txf) { 420 AffineTransform t = txf; 421 if (transform != null) { 422 t = new AffineTransform (txf); 423 t.concatenate(transform); 424 } 425 426 if ((t == null) || ((t.getShearX() == 0) && (t.getShearY() == 0))) { 427 return getTransformedBBox(getSensitiveBounds(), t); 429 } 430 431 Rectangle2D sb = null; 432 int i=0; 433 while (sb == null && i < count) { 434 sb = children[i++].getTransformedSensitiveBounds(t); 435 } 436 437 Rectangle2D csb = null; 438 while (i < count) { 439 csb = children[i++].getTransformedSensitiveBounds(t); 440 if (csb != null) { 441 sb.add(csb); 442 } 443 } 444 445 return sb; 446 } 447 448 454 public boolean contains(Point2D p) { 455 Rectangle2D bounds = getSensitiveBounds(); 456 if (count > 0 && bounds != null && bounds.contains(p)) { 457 Point2D pt = null; 458 Point2D cp = null; for (int i=0; i < count; ++i) { 460 AffineTransform t = children[i].getInverseTransform(); 461 if(t != null){ 462 pt = t.transform(p, pt); 463 cp = pt; 464 } else { 465 cp = p; 466 } 467 if (children[i].contains(cp)) { 468 return true; 469 } 470 } 471 } 472 473 return false; 474 } 475 476 477 483 public GraphicsNode nodeHitAt(Point2D p) { 484 Rectangle2D bounds = getSensitiveBounds(); 485 if (count > 0 && bounds != null && bounds.contains(p)) { 486 Point2D pt = null; 488 Point2D cp = null; for (int i=count-1; i >= 0; --i) { 490 AffineTransform t = children[i].getInverseTransform(); 491 if(t != null){ 492 pt = t.transform(p, pt); 493 cp = pt; 494 } else { 495 cp = p; 496 } 497 GraphicsNode node = children[i].nodeHitAt(cp); 498 if (node != null) { 499 return node; 500 } 501 } 502 } 503 504 return null; 505 } 506 507 510 public Shape getOutline() { 511 if (outline != null) 512 return outline; 513 514 outline = new GeneralPath (); 515 for (int i = 0; i < count; i++) { 516 Shape childOutline = children[i].getOutline(); 517 if (childOutline != null) { 518 AffineTransform tr = children[i].getTransform(); 519 if (tr != null) { 520 ((GeneralPath )outline).append(tr.createTransformedShape(childOutline), false); 521 } else { 522 ((GeneralPath )outline).append(childOutline, false); 523 } 524 } 525 } 526 527 return outline; 528 } 529 530 534 537 protected void setRoot(RootGraphicsNode newRoot) { 538 super.setRoot(newRoot); 539 for (int i=0; i < count; ++i) { 540 GraphicsNode node = children[i]; 541 ((AbstractGraphicsNode)node).setRoot(newRoot); 542 } 543 } 544 545 549 552 public int size() { 553 return count; 554 } 555 556 560 public boolean isEmpty() { 561 return (count == 0); 562 } 563 564 569 public boolean contains(Object node) { 570 return (indexOf(node) >= 0); 571 } 572 573 576 public Iterator iterator() { 577 return new Itr(); 578 } 579 580 586 public Object [] toArray() { 587 GraphicsNode [] result = new GraphicsNode[count]; 588 for (int i=0; i < count; ++i) { 589 result[i] = children[i]; 590 } 591 return result; 592 } 593 594 600 public Object [] toArray(Object [] a) { 601 if (a.length < count) { 602 a = new GraphicsNode[count]; 603 } 604 System.arraycopy(children, 0, a, 0, count); 605 if (a.length > count) { 606 a[count] = null; 607 } 608 return a; 609 } 610 611 617 public Object get(int index) { 618 checkRange(index); 619 return children[index]; 620 } 621 622 624 635 public Object set(int index, Object o) { 636 if (!(o instanceof GraphicsNode)) { 638 throw new IllegalArgumentException (o+" is not a GraphicsNode"); 639 } 640 checkRange(index); 641 GraphicsNode node = (GraphicsNode) o; 642 { 643 fireGraphicsNodeChangeStarted(node); 644 } 645 if (node.getParent() != null) { 647 node.getParent().getChildren().remove(node); 648 } 649 GraphicsNode oldNode = children[index]; 651 children[index] = node; 652 ((AbstractGraphicsNode) node).setParent(this); 654 ((AbstractGraphicsNode) oldNode).setParent(null); 655 ((AbstractGraphicsNode) node).setRoot(this.getRoot()); 657 ((AbstractGraphicsNode) oldNode).setRoot(null); 658 invalidateGeometryCache(); 660 fireGraphicsNodeChangeCompleted(); 666 return oldNode; 667 } 668 669 677 public boolean add(Object o) { 678 if (!(o instanceof GraphicsNode)) { 680 throw new IllegalArgumentException (o+" is not a GraphicsNode"); 681 } 682 GraphicsNode node = (GraphicsNode) o; 683 { 684 fireGraphicsNodeChangeStarted(node); 685 } 686 if (node.getParent() != null) { 688 node.getParent().getChildren().remove(node); 689 } 690 ensureCapacity(count + 1); children[count++] = node; 693 ((AbstractGraphicsNode) node).setParent(this); 695 ((AbstractGraphicsNode) node).setRoot(this.getRoot()); 697 invalidateGeometryCache(); 699 fireGraphicsNodeChangeCompleted(); 703 return true; 704 } 705 706 719 public void add(int index, Object o) { 720 if (!(o instanceof GraphicsNode)) { 722 throw new IllegalArgumentException (o+" is not a GraphicsNode"); 723 } 724 if (index > count || index < 0) { 725 throw new IndexOutOfBoundsException ( 726 "Index: "+index+", Size: "+count); 727 } 728 GraphicsNode node = (GraphicsNode) o; 729 { 730 fireGraphicsNodeChangeStarted(node); 731 } 732 if (node.getParent() != null) { 734 node.getParent().getChildren().remove(node); 735 } 736 ensureCapacity(count+1); System.arraycopy(children, index, children, index+1, count-index); 739 children[index] = node; 740 count++; 741 ((AbstractGraphicsNode) node).setParent(this); 743 ((AbstractGraphicsNode) node).setRoot(this.getRoot()); 745 invalidateGeometryCache(); 747 fireGraphicsNodeChangeCompleted(); 751 } 752 753 757 public boolean addAll(Collection c) { 758 throw new UnsupportedOperationException (); 759 } 760 761 765 public boolean addAll(int index, Collection c) { 766 throw new UnsupportedOperationException (); 767 } 768 769 777 public boolean remove(Object o) { 778 if (!(o instanceof GraphicsNode)) { 780 throw new IllegalArgumentException (o+" is not a GraphicsNode"); 781 } 782 GraphicsNode node = (GraphicsNode) o; 783 if (node.getParent() != this) { 784 return false; 785 } 786 int index = 0; 788 for (; node != children[index]; index++); 789 remove(index); 790 return true; 791 } 792 793 802 public Object remove(int index) { 803 checkRange(index); 805 GraphicsNode oldNode = children[index]; 806 { 807 fireGraphicsNodeChangeStarted(oldNode); 808 } 809 modCount++; 811 int numMoved = count - index - 1; 812 if (numMoved > 0) { 813 System.arraycopy(children, index+1, children, index, numMoved); 814 } 815 children[--count] = null; if (count == 0) { 817 children = null; 818 } 819 ((AbstractGraphicsNode) oldNode).setParent(null); 821 ((AbstractGraphicsNode) oldNode).setRoot(null); 823 invalidateGeometryCache(); 825 fireGraphicsNodeChangeCompleted(); 829 return oldNode; 830 } 831 832 836 public boolean removeAll(Collection c) { 837 throw new UnsupportedOperationException (); 838 } 839 840 844 public boolean retainAll(Collection c) { 845 throw new UnsupportedOperationException (); 846 } 847 848 852 public void clear() { 853 throw new UnsupportedOperationException (); 854 } 855 856 862 public boolean containsAll(Collection c) { 863 Iterator i = c.iterator(); 864 while (i.hasNext()) { 865 if (!contains(i.next())) { 866 return false; 867 |