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 } 868 } 869 return true; 870 } 871 872 874 880 public int indexOf(Object node) { 881 if (node == null || !(node instanceof GraphicsNode)) { 882 return -1; 883 } 884 if (((GraphicsNode) node).getParent() == this) { 885 for (int i = 0; i < count; i++) { 886 if (node == children[i]) { 887 return i; 888 } 889 } 890 } 891 return -1; 892 } 893 894 901 public int lastIndexOf(Object node) { 902 if (node == null || !(node instanceof GraphicsNode)) { 903 return -1; 904 } 905 if (((GraphicsNode) node).getParent() == this) { 906 for (int i = count-1; i >= 0; i--) { 907 if (node == children[i]) { 908 return i; 909 } 910 } 911 } 912 return -1; 913 } 914 915 917 920 public ListIterator listIterator() { 921 return listIterator(0); 922 } 923 924 931 public ListIterator listIterator(int index) { 932 if (index < 0 || index > count) { 933 throw new IndexOutOfBoundsException ("Index: "+index); 934 } 935 return new ListItr(index); 936 } 937 938 940 944 public List subList(int fromIndex, int toIndex) { 945 throw new UnsupportedOperationException (); 946 } 947 948 954 private void checkRange(int index) { 955 if (index >= count || index < 0) { 956 throw new IndexOutOfBoundsException ( 957 "Index: "+index+", Size: "+count); 958 } 959 } 960 961 968 public void ensureCapacity(int minCapacity) { 969 if (children == null) { 970 children = new GraphicsNode[4]; 971 } 972 modCount++; 973 int oldCapacity = children.length; 974 if (minCapacity > oldCapacity) { 975 GraphicsNode [] oldData = children; 976 int newCapacity = (oldCapacity * 3)/2 + 1; 977 if (newCapacity < minCapacity) { 978 newCapacity = minCapacity; 979 } 980 children = new GraphicsNode[newCapacity]; 981 System.arraycopy(oldData, 0, children, 0, count); 982 } 983 } 984 985 988 private class Itr implements Iterator { 989 990 993 int cursor = 0; 994 995 1000 int lastRet = -1; 1001 1002 1007 int expectedModCount = modCount; 1008 1009 public boolean hasNext() { 1010 return cursor != count; 1011 } 1012 1013 public Object next() { 1014 try { 1015 Object next = get(cursor); 1016 checkForComodification(); 1017 lastRet = cursor++; 1018 return next; 1019 } catch(IndexOutOfBoundsException e) { 1020 checkForComodification(); 1021 throw new NoSuchElementException (); 1022 } 1023 } 1024 1025 public void remove() { 1026 if (lastRet == -1) { 1027 throw new IllegalStateException (); 1028 } 1029 checkForComodification(); 1030 1031 try { 1032 CompositeGraphicsNode.this.remove(lastRet); 1033 if (lastRet < cursor) { 1034 cursor--; 1035 } 1036 lastRet = -1; 1037 expectedModCount = modCount; 1038 } catch(IndexOutOfBoundsException e) { 1039 throw new ConcurrentModificationException (); 1040 } 1041 } 1042 1043 final void checkForComodification() { 1044 if (modCount != expectedModCount) { 1045 throw new ConcurrentModificationException (); 1046 } 1047 } 1048 } 1049 1050 1051 1054 private class ListItr extends Itr implements ListIterator { 1055 1056 ListItr(int index) { 1057 cursor = index; 1058 } 1059 1060 public boolean hasPrevious() { 1061 return cursor != 0; 1062 } 1063 1064 public Object previous() { 1065 try { 1066 Object previous = get(--cursor); 1067 checkForComodification(); 1068 lastRet = cursor; 1069 return previous; 1070 } catch(IndexOutOfBoundsException e) { 1071 checkForComodification(); 1072 throw new NoSuchElementException (); 1073 } 1074 } 1075 1076 public int nextIndex() { 1077 return cursor; 1078 } 1079 1080 public int previousIndex() { 1081 return cursor-1; 1082 } 1083 1084 public void set(Object o) { 1085 if (lastRet == -1) { 1086 throw new IllegalStateException (); 1087 } 1088 checkForComodification(); 1089 try { 1090 CompositeGraphicsNode.this.set(lastRet, o); 1091 expectedModCount = modCount; 1092 } catch(IndexOutOfBoundsException e) { 1093 throw new ConcurrentModificationException (); 1094 } 1095 } 1096 1097 public void add(Object o) { 1098 checkForComodification(); 1099 try { 1100 CompositeGraphicsNode.this.add(cursor++, o); 1101 lastRet = -1; 1102 expectedModCount = modCount; 1103 } catch(IndexOutOfBoundsException e) { 1104 throw new ConcurrentModificationException (); 1105 } 1106 } 1107 } 1108} 1109 | Popular Tags |