001 /* Container.java -- parent container class in AWT 002 Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006 003 Free Software Foundation 004 005 This file is part of GNU Classpath. 006 007 GNU Classpath is free software; you can redistribute it and/or modify 008 it under the terms of the GNU General Public License as published by 009 the Free Software Foundation; either version 2, or (at your option) 010 any later version. 011 012 GNU Classpath is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of 014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 General Public License for more details. 016 017 You should have received a copy of the GNU General Public License 018 along with GNU Classpath; see the file COPYING. If not, write to the 019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 020 02110-1301 USA. 021 022 Linking this library statically or dynamically with other modules is 023 making a combined work based on this library. Thus, the terms and 024 conditions of the GNU General Public License cover the whole 025 combination. 026 027 As a special exception, the copyright holders of this library give you 028 permission to link this library with independent modules to produce an 029 executable, regardless of the license terms of these independent 030 modules, and to copy and distribute the resulting executable under 031 terms of your choice, provided that you also meet, for each linked 032 independent module, the terms and conditions of the license of that 033 module. An independent module is a module which is not derived from 034 or based on this library. If you modify this library, you may extend 035 this exception to your version of the library, but you are not 036 obligated to do so. If you do not wish to do so, delete this 037 exception statement from your version. */ 038 039 040 package java.awt; 041 042 import java.awt.event.ContainerEvent; 043 import java.awt.event.ContainerListener; 044 import java.awt.event.HierarchyEvent; 045 import java.awt.event.KeyEvent; 046 import java.awt.event.MouseEvent; 047 import java.awt.peer.ComponentPeer; 048 import java.awt.peer.ContainerPeer; 049 import java.awt.peer.LightweightPeer; 050 import java.beans.PropertyChangeListener; 051 import java.io.IOException; 052 import java.io.ObjectInputStream; 053 import java.io.ObjectOutputStream; 054 import java.io.PrintStream; 055 import java.io.PrintWriter; 056 import java.io.Serializable; 057 import java.util.Collections; 058 import java.util.EventListener; 059 import java.util.HashSet; 060 import java.util.Iterator; 061 import java.util.Set; 062 063 import javax.accessibility.Accessible; 064 065 /** 066 * A generic window toolkit object that acts as a container for other objects. 067 * Components are tracked in a list, and new elements are at the end of the 068 * list or bottom of the stacking order. 069 * 070 * @author original author unknown 071 * @author Eric Blake (ebb9@email.byu.edu) 072 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 073 * 074 * @since 1.0 075 * 076 * @status still missing 1.4 support, some generics from 1.5 077 */ 078 public class Container extends Component 079 { 080 /** 081 * Compatible with JDK 1.0+. 082 */ 083 private static final long serialVersionUID = 4613797578919906343L; 084 085 /* Serialized fields from the serialization spec. */ 086 int ncomponents; 087 Component[] component; 088 LayoutManager layoutMgr; 089 090 /** 091 * @since 1.4 092 */ 093 boolean focusCycleRoot; 094 095 /** 096 * Indicates if this container provides a focus traversal policy. 097 * 098 * @since 1.5 099 */ 100 private boolean focusTraversalPolicyProvider; 101 102 int containerSerializedDataVersion; 103 104 /* Anything else is non-serializable, and should be declared "transient". */ 105 transient ContainerListener containerListener; 106 107 /** The focus traversal policy that determines how focus is 108 transferred between this Container and its children. */ 109 private FocusTraversalPolicy focusTraversalPolicy; 110 111 /** 112 * The focus traversal keys, if not inherited from the parent or default 113 * keyboard manager. These sets will contain only AWTKeyStrokes that 114 * represent press and release events to use as focus control. 115 * 116 * @see #getFocusTraversalKeys(int) 117 * @see #setFocusTraversalKeys(int, Set) 118 * @since 1.4 119 */ 120 transient Set[] focusTraversalKeys; 121 122 /** 123 * Default constructor for subclasses. 124 */ 125 public Container() 126 { 127 // Nothing to do here. 128 } 129 130 /** 131 * Returns the number of components in this container. 132 * 133 * @return The number of components in this container. 134 */ 135 public int getComponentCount() 136 { 137 return countComponents (); 138 } 139 140 /** 141 * Returns the number of components in this container. 142 * 143 * @return The number of components in this container. 144 * 145 * @deprecated use {@link #getComponentCount()} instead 146 */ 147 public int countComponents() 148 { 149 return ncomponents; 150 } 151 152 /** 153 * Returns the component at the specified index. 154 * 155 * @param n The index of the component to retrieve. 156 * 157 * @return The requested component. 158 * 159 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid 160 */ 161 public Component getComponent(int n) 162 { 163 synchronized (getTreeLock ()) 164 { 165 if (n < 0 || n >= ncomponents) 166 throw new ArrayIndexOutOfBoundsException("no such component"); 167 168 return component[n]; 169 } 170 } 171 172 /** 173 * Returns an array of the components in this container. 174 * 175 * @return The components in this container. 176 */ 177 public Component[] getComponents() 178 { 179 synchronized (getTreeLock ()) 180 { 181 Component[] result = new Component[ncomponents]; 182 183 if (ncomponents > 0) 184 System.arraycopy(component, 0, result, 0, ncomponents); 185 186 return result; 187 } 188 } 189 190 /** 191 * Returns the insets for this container, which is the space used for 192 * borders, the margin, etc. 193 * 194 * @return The insets for this container. 195 */ 196 public Insets getInsets() 197 { 198 return insets (); 199 } 200 201 /** 202 * Returns the insets for this container, which is the space used for 203 * borders, the margin, etc. 204 * 205 * @return The insets for this container. 206 * @deprecated use {@link #getInsets()} instead 207 */ 208 public Insets insets() 209 { 210 Insets i; 211 if (peer == null || peer instanceof LightweightPeer) 212 i = new Insets (0, 0, 0, 0); 213 else 214 i = ((ContainerPeer) peer).getInsets (); 215 return i; 216 } 217 218 /** 219 * Adds the specified component to this container at the end of the 220 * component list. 221 * 222 * @param comp The component to add to the container. 223 * 224 * @return The same component that was added. 225 */ 226 public Component add(Component comp) 227 { 228 addImpl(comp, null, -1); 229 return comp; 230 } 231 232 /** 233 * Adds the specified component to the container at the end of the 234 * component list. This method should not be used. Instead, use 235 * <code>add(Component, Object)</code>. 236 * 237 * @param name The name of the component to be added. 238 * @param comp The component to be added. 239 * 240 * @return The same component that was added. 241 * 242 * @see #add(Component,Object) 243 */ 244 public Component add(String name, Component comp) 245 { 246 addImpl(comp, name, -1); 247 return comp; 248 } 249 250 /** 251 * Adds the specified component to this container at the specified index 252 * in the component list. 253 * 254 * @param comp The component to be added. 255 * @param index The index in the component list to insert this child 256 * at, or -1 to add at the end of the list. 257 * 258 * @return The same component that was added. 259 * 260 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 261 */ 262 public Component add(Component comp, int index) 263 { 264 addImpl(comp, null, index); 265 return comp; 266 } 267 268 /** 269 * Adds the specified component to this container at the end of the 270 * component list. The layout manager will use the specified constraints 271 * when laying out this component. 272 * 273 * @param comp The component to be added to this container. 274 * @param constraints The layout constraints for this component. 275 */ 276 public void add(Component comp, Object constraints) 277 { 278 addImpl(comp, constraints, -1); 279 } 280 281 /** 282 * Adds the specified component to this container at the specified index 283 * in the component list. The layout manager will use the specified 284 * constraints when layout out this component. 285 * 286 * @param comp The component to be added. 287 * @param constraints The layout constraints for this component. 288 * @param index The index in the component list to insert this child 289 * at, or -1 to add at the end of the list. 290 * 291 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 292 */ 293 public void add(Component comp, Object constraints, int index) 294 { 295 addImpl(comp, constraints, index); 296 } 297 298 /** 299 * This method is called by all the <code>add()</code> methods to perform 300 * the actual adding of the component. Subclasses who wish to perform 301 * their own processing when a component is added should override this 302 * method. Any subclass doing this must call the superclass version of 303 * this method in order to ensure proper functioning of the container. 304 * 305 * @param comp The component to be added. 306 * @param constraints The layout constraints for this component, or 307 * <code>null</code> if there are no constraints. 308 * @param index The index in the component list to insert this child 309 * at, or -1 to add at the end of the list. 310 * 311 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid. 312 */ 313 protected void addImpl(Component comp, Object constraints, int index) 314 { 315 synchronized (getTreeLock ()) 316 { 317 if (index > ncomponents 318 || (index < 0 && index != -1) 319 || comp instanceof Window 320 || (comp instanceof Container 321 && ((Container) comp).isAncestorOf(this))) 322 throw new IllegalArgumentException(); 323 324 // Reparent component, and make sure component is instantiated if 325 // we are. 326 if (comp.parent != null) 327 comp.parent.remove(comp); 328 329 if (component == null) 330 component = new Component[4]; // FIXME, better initial size? 331 332 // This isn't the most efficient implementation. We could do less 333 // copying when growing the array. It probably doesn't matter. 334 if (ncomponents >= component.length) 335 { 336 int nl = component.length * 2; 337 Component[] c = new Component[nl]; 338 System.arraycopy(component, 0, c, 0, ncomponents); 339 component = c; 340 } 341 342 if (index == -1) 343 component[ncomponents++] = comp; 344 else 345 { 346 System.arraycopy(component, index, component, index + 1, 347 ncomponents - index); 348 component[index] = comp; 349 ++ncomponents; 350 } 351 352 // Give the new component a parent. 353 comp.parent = this; 354 355 // Update the counter for Hierarchy(Bounds)Listeners. 356 int childHierarchyListeners = comp.numHierarchyListeners; 357 if (childHierarchyListeners > 0) 358 updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 359 childHierarchyListeners); 360 int childHierarchyBoundsListeners = comp.numHierarchyBoundsListeners; 361 if (childHierarchyBoundsListeners > 0) 362 updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 363 childHierarchyListeners); 364 365 // Invalidate the layout of this container. 366 if (valid) 367 invalidate(); 368 369 // Create the peer _after_ the component has been added, so that 370 // the peer gets to know about the component hierarchy. 371 if (peer != null) 372 { 373 // Notify the component that it has a new parent. 374 comp.addNotify(); 375 } 376 377 // Notify the layout manager. 378 if (layoutMgr != null) 379 { 380 // If we have a LayoutManager2 the constraints are "real", 381 // otherwise they are the "name" of the Component to add. 382 if (layoutMgr instanceof LayoutManager2) 383 { 384 LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 385 lm2.addLayoutComponent(comp, constraints); 386 } 387 else if (constraints instanceof String) 388 layoutMgr.addLayoutComponent((String) constraints, comp); 389 else 390 layoutMgr.addLayoutComponent("", comp); 391 } 392 393 // We previously only sent an event when this container is showing. 394 // Also, the event was posted to the event queue. A Mauve test shows 395 // that this event is not delivered using the event queue and it is 396 // also sent when the container is not showing. 397 if (containerListener != null 398 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) 399 { 400 ContainerEvent ce = new ContainerEvent(this, 401 ContainerEvent.COMPONENT_ADDED, 402 comp); 403 dispatchEvent(ce); 404 } 405 406 // Notify hierarchy listeners. 407 comp.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, comp, 408 this, HierarchyEvent.PARENT_CHANGED); 409 } 410 } 411 412 /** 413 * Removes the component at the specified index from this container. 414 * 415 * @param index The index of the component to remove. 416 */ 417 public void remove(int index) 418 { 419 synchronized (getTreeLock ()) 420 { 421 if (index < 0 || index >= ncomponents) 422 throw new ArrayIndexOutOfBoundsException(); 423 424 Component r = component[index]; 425 if (peer != null) 426 r.removeNotify(); 427 428 if (layoutMgr != null) 429 layoutMgr.removeLayoutComponent(r); 430 431 // Update the counter for Hierarchy(Bounds)Listeners. 432 int childHierarchyListeners = r.numHierarchyListeners; 433 if (childHierarchyListeners > 0) 434 updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 435 -childHierarchyListeners); 436 int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners; 437 if (childHierarchyBoundsListeners > 0) 438 updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 439 -childHierarchyListeners); 440 441 r.parent = null; 442 443 System.arraycopy(component, index + 1, component, index, 444 ncomponents - index - 1); 445 component[--ncomponents] = null; 446 447 if (valid) 448 invalidate(); 449 450 if (containerListener != null 451 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) 452 { 453 // Post event to notify of removing the component. 454 ContainerEvent ce = new ContainerEvent(this, 455 ContainerEvent.COMPONENT_REMOVED, 456 r); 457 dispatchEvent(ce); 458 } 459 460 // Notify hierarchy listeners. 461 r.fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, 462 this, HierarchyEvent.PARENT_CHANGED); 463 } 464 } 465 466 /** 467 * Removes the specified component from this container. 468 * 469 * @param comp The component to remove from this container. 470 */ 471 public void remove(Component comp) 472 { 473 synchronized (getTreeLock ()) 474 { 475 for (int i = 0; i < ncomponents; ++i) 476 { 477 if (component[i] == comp) 478 { 479 remove(i); 480 break; 481 } 482 } 483 } 484 } 485 486 /** 487 * Removes all components from this container. 488 */ 489 public void removeAll() 490 { 491 synchronized (getTreeLock ()) 492 { 493 // In order to allow the same bad tricks to be used as in RI 494 // this code has to stay exactly that way: In a real-life app 495 // a Container subclass implemented its own vector for 496 // subcomponents, supplied additional addXYZ() methods 497 // and overrode remove(int) and removeAll (the latter calling 498 // super.removeAll() ). 499 // By doing it this way, user code cannot prevent the correct 500 // removal of components. 501 while (ncomponents > 0) 502 { 503 ncomponents--; 504 Component r = component[ncomponents]; 505 component[ncomponents] = null; 506 507 if (peer != null) 508 r.removeNotify(); 509 510 if (layoutMgr != null) 511 layoutMgr.removeLayoutComponent(r); 512 513 r.parent = null; 514 515 // Send ContainerEvent if necessary. 516 if (containerListener != null 517 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) 518 { 519 // Post event to notify of removing the component. 520 ContainerEvent ce 521 = new ContainerEvent(this, 522 ContainerEvent.COMPONENT_REMOVED, 523 r); 524 dispatchEvent(ce); 525 } 526 527 // Update the counter for Hierarchy(Bounds)Listeners. 528 int childHierarchyListeners = r.numHierarchyListeners; 529 if (childHierarchyListeners > 0) 530 updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 531 -childHierarchyListeners); 532 int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners; 533 if (childHierarchyBoundsListeners > 0) 534 updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 535 -childHierarchyListeners); 536 537 538 // Send HierarchyEvent if necessary. 539 fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, this, 540 HierarchyEvent.PARENT_CHANGED); 541 542 } 543 544 if (valid) 545 invalidate(); 546 } 547 } 548 549 /** 550 * Returns the current layout manager for this container. 551 * 552 * @return The layout manager for this container. 553 */ 554 public LayoutManager getLayout() 555 { 556 return layoutMgr; 557 } 558 559 /** 560 * Sets the layout manager for this container to the specified layout 561 * manager. 562 * 563 * @param mgr The new layout manager for this container. 564 */ 565 public void setLayout(LayoutManager mgr) 566 { 567 layoutMgr = mgr; 568 if (valid) 569 invalidate(); 570 } 571 572 /** 573 * Layout the components in this container. 574 */ 575 public void doLayout() 576 { 577 layout (); 578 } 579 580 /** 581 * Layout the components in this container. 582 * 583 * @deprecated use {@link #doLayout()} instead 584 */ 585 public void layout() 586 { 587 if (layoutMgr != null) 588 layoutMgr.layoutContainer (this); 589 } 590 591 /** 592 * Invalidates this container to indicate that it (and all parent 593 * containers) need to be laid out. 594 */ 595 public void invalidate() 596 { 597 super.invalidate(); 598 if (layoutMgr != null && layoutMgr instanceof LayoutManager2) 599 { 600 LayoutManager2 lm2 = (LayoutManager2) layoutMgr; 601 lm2.invalidateLayout(this); 602 } 603 } 604 605 /** 606 * Re-lays out the components in this container. 607 */ 608 public void validate() 609 { 610 ComponentPeer p = peer; 611 if (! valid && p != null) 612 { 613 ContainerPeer cPeer = null; 614 if (p instanceof ContainerPeer) 615 cPeer = (ContainerPeer) peer; 616 synchronized (getTreeLock ()) 617 { 618 if (cPeer != null) 619 cPeer.beginValidate(); 620 validateTree(); 621 valid = true; 622 if (cPeer != null) 623 cPeer.endValidate(); 624 } 625 } 626 } 627 628 /** 629 * Recursively invalidates the container tree. 630 */ 631 private final void invalidateTree() 632 { 633 synchronized (getTreeLock()) 634 { 635 for (int i = 0; i < ncomponents; i++) 636 { 637 Component comp = component[i]; 638 if (comp instanceof Container) 639 ((Container) comp).invalidateTree(); 640 else if (comp.valid) 641 comp.invalidate(); 642 } 643 if (valid) 644 invalidate(); 645 } 646 } 647 648 /** 649 * Recursively validates the container tree, recomputing any invalid 650 * layouts. 651 */ 652 protected void validateTree() 653 { 654 if (!valid) 655 { 656 ContainerPeer cPeer = null; 657 if (peer instanceof ContainerPeer) 658 { 659 cPeer = (ContainerPeer) peer; 660 cPeer.beginLayout(); 661 } 662 663 doLayout (); 664 for (int i = 0; i < ncomponents; ++i) 665 { 666 Component comp = component[i]; 667 668 if (comp instanceof Container && ! (comp instanceof Window) 669 && ! comp.valid) 670 { 671 ((Container) comp).validateTree(); 672 } 673 else 674 { 675 comp.validate(); 676 } 677 } 678 679 if (cPeer != null) 680 { 681 cPeer = (ContainerPeer) peer; 682 cPeer.endLayout(); 683 } 684 } 685 686 /* children will call invalidate() when they are layed out. It 687 is therefore important that valid is not set to true 688 until after the children have been layed out. */ 689 valid = true; 690 691 } 692 693 public void setFont(Font f) 694 { 695 Font oldFont = getFont(); 696 super.setFont(f); 697 Font newFont = getFont(); 698 if (newFont != oldFont && (oldFont == null || ! oldFont.equals(newFont))) 699 { 700 invalidateTree(); 701 } 702 } 703 704 /** 705 * Returns the preferred size of this container. 706 * 707 * @return The preferred size of this container. 708 */ 709 public Dimension getPreferredSize() 710 { 711 return preferredSize (); 712 } 713 714 /** 715 * Returns the preferred size of this container. 716 * 717 * @return The preferred size of this container. 718 * 719 * @deprecated use {@link #getPreferredSize()} instead 720 */ 721 public Dimension preferredSize() 722 { 723 Dimension size = prefSize; 724 // Try to return cached value if possible. 725 if (size == null || !(prefSizeSet || valid)) 726 { 727 // Need to lock here. 728 synchronized (getTreeLock()) 729 { 730 LayoutManager l = layoutMgr; 731 if (l != null) 732 prefSize = l.preferredLayoutSize(this); 733 else 734 prefSize = super.preferredSizeImpl(); 735 size = prefSize; 736 } 737 } 738 if (size != null) 739 return new Dimension(size); 740 else 741 return size; 742 } 743 744 /** 745 * Returns the minimum size of this container. 746 * 747 * @return The minimum size of this container. 748 */ 749 public Dimension getMinimumSize() 750 { 751 return minimumSize (); 752 } 753 754 /** 755 * Returns the minimum size of this container. 756 * 757 * @return The minimum size of this container. 758 * 759 * @deprecated use {@link #getMinimumSize()} instead 760 */ 761 public Dimension minimumSize() 762 { 763 Dimension size = minSize; 764 // Try to return cached value if possible. 765 if (size == null || !(minSizeSet || valid)) 766 { 767 // Need to lock here. 768 synchronized (getTreeLock()) 769 { 770 LayoutManager l = layoutMgr; 771 if (l != null) 772 minSize = l.minimumLayoutSize(this); 773 else 774 minSize = super.minimumSizeImpl(); 775 size = minSize; 776 } 777 } 778 if (size != null) 779 return new Dimension(size); 780 else 781 return size; 782 } 783 784 /** 785 * Returns the maximum size of this container. 786 * 787 * @return The maximum size of this container. 788 */ 789 public Dimension getMaximumSize() 790 { 791 Dimension size = maxSize; 792 // Try to return cached value if possible. 793 if (size == null || !(maxSizeSet || valid)) 794 { 795 // Need to lock here. 796 synchronized (getTreeLock()) 797 { 798 LayoutManager l = layoutMgr; 799 if (l instanceof LayoutManager2) 800 maxSize = ((LayoutManager2) l).maximumLayoutSize(this); 801 else { 802 maxSize = super.maximumSizeImpl(); 803 } 804 size = maxSize; 805 } 806 } 807 if (size != null) 808 return new Dimension(size); 809 else 810 return size; 811 } 812 813 /** 814 * Returns the preferred alignment along the X axis. This is a value 815 * between 0 and 1 where 0 represents alignment flush left and 816 * 1 means alignment flush right, and 0.5 means centered. 817 * 818 * @return The preferred alignment along the X axis. 819 */ 820 public float getAlignmentX() 821 { 822 LayoutManager layout = getLayout(); 823 float alignmentX = 0.0F; 824 if (layout != null && layout instanceof LayoutManager2) 825 { 826 synchronized (getTreeLock()) 827 { 828 LayoutManager2 lm2 = (LayoutManager2) layout; 829 alignmentX = lm2.getLayoutAlignmentX(this); 830 } 831 } 832 else 833 alignmentX = super.getAlignmentX(); 834 return alignmentX; 835 } 836 837 /** 838 * Returns the preferred alignment along the Y axis. This is a value 839 * between 0 and 1 where 0 represents alignment flush top and 840 * 1 means alignment flush bottom, and 0.5 means centered. 841 * 842 * @return The preferred alignment along the Y axis. 843 */ 844 public float getAlignmentY() 845 { 846 LayoutManager layout = getLayout(); 847 float alignmentY = 0.0F; 848 if (layout != null && layout instanceof LayoutManager2) 849 { 850 synchronized (getTreeLock()) 851 { 852 LayoutManager2 lm2 = (LayoutManager2) layout; 853 alignmentY = lm2.getLayoutAlignmentY(this); 854 } 855 } 856 else 857 alignmentY = super.getAlignmentY(); 858 return alignmentY; 859 } 860 861 /** 862 * Paints this container. The implementation of this method in this 863 * class forwards to any lightweight components in this container. If 864 * this method is subclassed, this method should still be invoked as 865 * a superclass method so that lightweight components are properly 866 * drawn. 867 * 868 * @param g - The graphics context for this paint job. 869 */ 870 public void paint(Graphics g) 871 { 872 if (isShowing()) 873 { 874 visitChildren(g, GfxPaintVisitor.INSTANCE, true); 875 } 876 } 877 878 /** 879 * Updates this container. The implementation of this method in this 880 * class forwards to any lightweight components in this container. If 881 * this method is subclassed, this method should still be invoked as 882 * a superclass method so that lightweight components are properly 883 * drawn. 884 * 885 * @param g The graphics context for this update. 886 * 887 * @specnote The specification suggests that this method forwards the 888 * update() call to all its lightweight children. Tests show 889 * that this is not done either in the JDK. The exact behaviour 890 * seems to be that the background is cleared in heavyweight 891 * Containers, and all other containers 892 * directly call paint(), causing the (lightweight) children to 893 * be painted. 894 */ 895 public void update(Graphics g) 896 { 897 // It seems that the JDK clears the background of containers like Panel 898 // and Window (within this method) but not of 'plain' Containers or 899 // JComponents. This could 900 // lead to the assumption that it only clears heavyweight containers. 901 // However that is not quite true. In a test with a custom Container 902 // that overrides isLightweight() to return false, the background is 903 // also not cleared. So we do a check on !(peer instanceof LightweightPeer) 904 // instead. 905 if (isShowing()) 906 { 907 ComponentPeer p = peer; 908 if (! (p instanceof LightweightPeer)) 909 { 910 g.clearRect(0, 0, getWidth(), getHeight()); 911 } 912 paint(g); 913 } 914 } 915 916 /** 917 * Prints this container. The implementation of this method in this 918 * class forwards to any lightweight components in this container. If 919 * this method is subclassed, this method should still be invoked as 920 * a superclass method so that lightweight components are properly 921 * drawn. 922 * 923 * @param g The graphics context for this print job. 924 */ 925 public void print(Graphics g) 926 { 927 super.print(g); 928 visitChildren(g, GfxPrintVisitor.INSTANCE, true); 929 } 930 931 /** 932 * Paints all of the components in this container. 933 * 934 * @param g The graphics context for this paint job. 935 */ 936 public void paintComponents(Graphics g) 937 { 938 if (isShowing()) 939 visitChildren(g, GfxPaintAllVisitor.INSTANCE, false); 940 } 941 942 /** 943 * Prints all of the components in this container. 944 * 945 * @param g The graphics context for this print job. 946 */ 947 public void printComponents(Graphics g) 948 { 949 super.paint(g); 950 visitChildren(g, GfxPrintAllVisitor.INSTANCE, true); 951 } 952 953 /** 954 * Adds the specified container listener to this object's list of 955 * container listeners. 956 * 957 * @param listener The listener to add. 958 */ 959 public synchronized void addContainerListener(ContainerListener listener) 960 { 961 if (listener != null) 962 { 963 containerListener = AWTEventMulticaster.add(containerListener, 964 listener); 965 newEventsOnly = true; 966 } 967 } 968 969 /** 970 * Removes the specified container listener from this object's list of 971 * container listeners. 972 * 973 * @param listener The listener to remove. 974 */ 975 public synchronized void removeContainerListener(ContainerListener listener) 976 { 977 containerListener = AWTEventMulticaster.remove(containerListener, listener); 978 } 979 980 /** 981 * @since 1.4 982 */ 983 public synchronized ContainerListener[] getContainerListeners() 984 { 985 return (ContainerListener[]) 986 AWTEventMulticaster.getListeners(containerListener, 987 ContainerListener.class); 988 } 989 990 /** 991 * Returns all registered {@link EventListener}s of the given 992 * <code>listenerType</code>. 993 * 994 * @param listenerType the class of listeners to filter (<code>null</code> 995 * not permitted). 996 * 997 * @return An array of registered listeners. 998 * 999 * @throws ClassCastException if <code>listenerType</code> does not implement 1000 * the {@link EventListener} interface. 1001 * @throws NullPointerException if <code>listenerType</code> is 1002 * <code>null</code>. 1003 * 1004 * @see #getContainerListeners() 1005 * 1006 * @since 1.3 1007 */ 1008 public <T extends EventListener> T[] getListeners(Class<T> listenerType) 1009 { 1010 if (listenerType == ContainerListener.class) 1011 return (T[]) getContainerListeners(); 1012 return super.getListeners(listenerType); 1013 } 1014 1015 /** 1016 * Processes the specified event. This method calls 1017 * <code>processContainerEvent()</code> if this method is a 1018 * <code>ContainerEvent</code>, otherwise it calls the superclass 1019 * method. 1020 * 1021 * @param e The event to be processed. 1022 */ 1023 protected void processEvent(AWTEvent e) 1024 { 1025 if (e instanceof ContainerEvent) 1026 processContainerEvent((ContainerEvent) e); 1027 else 1028 super.processEvent(e); 1029 } 1030 1031 /** 1032 * Called when a container event occurs if container events are enabled. 1033 * This method calls any registered listeners. 1034 * 1035 * @param e The event that occurred. 1036 */ 1037 protected void processContainerEvent(ContainerEvent e) 1038 { 1039 if (containerListener == null) 1040 return; 1041 switch (e.id) 1042 { 1043 case ContainerEvent.COMPONENT_ADDED: 1044 containerListener.componentAdded(e); 1045 break; 1046 1047 case ContainerEvent.COMPONENT_REMOVED: 1048 containerListener.componentRemoved(e); 1049 break; 1050 } 1051 } 1052 1053 /** 1054 * AWT 1.0 event processor. 1055 * 1056 * @param e The event that occurred. 1057 * 1058 * @deprecated use {@link #dispatchEvent(AWTEvent)} instead 1059 */ 1060 public void deliverEvent(Event e) 1061 { 1062 if (!handleEvent (e)) 1063 { 1064 synchronized (getTreeLock ()) 1065 { 1066 Component parent = getParent (); 1067 1068 if (parent != null) 1069 parent.deliverEvent (e); 1070 } 1071 } 1072 } 1073 1074 /** 1075 * Returns the component located at the specified point. This is done 1076 * by checking whether or not a child component claims to contain this 1077 * point. The first child component that does is returned. If no 1078 * child component claims the point, the container itself is returned, 1079 * unless the point does not exist within this container, in which 1080 * case <code>null</code> is returned. 1081 * 1082 * When components overlap, the first component is returned. The component 1083 * that is closest to (x, y), containing that location, is returned. 1084 * Heavyweight components take precedence of lightweight components. 1085 * 1086 * This function does not ignore invisible components. If there is an invisible 1087 * component at (x,y), it will be returned. 1088 * 1089 * @param x The X coordinate of the point. 1090 * @param y The Y coordinate of the point. 1091 * 1092 * @return The component containing the specified point, or 1093 * <code>null</code> if there is no such point. 1094 */ 1095 public Component getComponentAt(int x, int y) 1096 { 1097 return locate (x, y); 1098 } 1099 1100 /** 1101 * Returns the mouse pointer position relative to this Container's 1102 * top-left corner. If allowChildren is false, the mouse pointer 1103 * must be directly over this container. If allowChildren is true, 1104 * the mouse pointer may be over this container or any of its 1105 * descendents. 1106 * 1107 * @param allowChildren true to allow descendents, false if pointer 1108 * must be directly over Container. 1109 * 1110 * @return relative mouse pointer position 1111 * 1112 * @throws HeadlessException if in a headless environment 1113 */ 1114 public Point getMousePosition(boolean allowChildren) throws HeadlessException 1115 { 1116 return super.getMousePositionHelper(allowChildren); 1117 } 1118 1119 boolean mouseOverComponent(Component component, boolean allowChildren) 1120 { 1121 if (allowChildren) 1122 return isAncestorOf(component); 1123 else 1124 return component == this; 1125 } 1126 1127 /** 1128 * Returns the component located at the specified point. This is done 1129 * by checking whether or not a child component claims to contain this 1130 * point. The first child component that does is returned. If no 1131 * child component claims the point, the container itself is returned, 1132 * unless the point does not exist within this container, in which 1133 * case <code>null</code> is returned. 1134 * 1135 * When components overlap, the first component is returned. The component 1136 * that is closest to (x, y), containing that location, is returned. 1137 * Heavyweight components take precedence of lightweight components. 1138 * 1139 * This function does not ignore invisible components. If there is an invisible 1140 * component at (x,y), it will be returned. 1141 * 1142 * @param x The x position of the point to return the component at. 1143 * @param y The y position of the point to return the component at. 1144 * 1145 * @return The component containing the specified point, or <code>null</code> 1146 * if there is no such point. 1147 * 1148 * @deprecated use {@link #getComponentAt(int, int)} instead 1149 */ 1150 public Component locate(int x, int y) 1151 { 1152 synchronized (getTreeLock ()) 1153 { 1154 if (!contains (x, y)) 1155 return null; 1156 1157 // First find the component closest to (x,y) that is a heavyweight. 1158 for (int i = 0; i < ncomponents; ++i) 1159 { 1160 Component comp = component[i]; 1161 int x2 = x - comp.x; 1162 int y2 = y - comp.y; 1163 if (comp.contains (x2, y2) && !comp.isLightweight()) 1164 return comp; 1165 } 1166 1167 // if a heavyweight component is not found, look for a lightweight 1168 // closest to (x,y). 1169 for (int i = 0; i < ncomponents; ++i) 1170 { 1171 Component comp = component[i]; 1172 int x2 = x - comp.x; 1173 int y2 = y - comp.y; 1174 if (comp.contains (x2, y2) && comp.isLightweight()) 1175 return comp; 1176 } 1177 1178 return this; 1179 } 1180 } 1181 1182 /** 1183 * Returns the component located at the specified point. This is done 1184 * by checking whether or not a child component claims to contain this 1185 * point. The first child component that does is returned. If no 1186 * child component claims the point, the container itself is returned, 1187 * unless the point does not exist within this container, in which 1188 * case <code>null</code> is returned. 1189 * 1190 * The top-most child component is returned in the case where components overlap. 1191 * This is determined by finding the component closest to (x,y) and contains 1192 * that location. Heavyweight components take precedence of lightweight components. 1193 * 1194 * This function does not ignore invisible components. If there is an invisible 1195 * component at (x,y), it will be returned. 1196 * 1197 * @param p The point to return the component at. 1198 * @return The component containing the specified point, or <code>null</code> 1199 * if there is no such point. 1200 */ 1201 public Component getComponentAt(Point p) 1202 { 1203 return getComponentAt (p.x, p.y); 1204 } 1205 1206 /** 1207 * Locates the visible child component that contains the specified position. 1208 * The top-most child component is returned in the case where there is overlap 1209 * in the components. If the containing child component is a Container, 1210 * this method will continue searching for the deepest nested child 1211 * component. Components which are not visible are ignored during the search. 1212 * 1213 * findComponentAt differs from getComponentAt, because it recursively 1214 * searches a Container's children. 1215 * 1216 * @param x - x coordinate 1217 * @param y - y coordinate 1218 * @return null if the component does not contain the position. 1219 * If there is no child component at the requested point and the point is 1220 * within the bounds of the container the container itself is returned. 1221 */ 1222 public Component findComponentAt(int x, int y) 1223 { 1224 synchronized (getTreeLock ()) 1225 { 1226 if (! contains(x, y)) 1227 return null; 1228 1229 for (int i = 0; i < ncomponents; ++i) 1230 { 1231 // Ignore invisible children... 1232 if (!component[i].isVisible()) 1233 continue; 1234 1235 int x2 = x - component[i].x; 1236 int y2 = y - component[i].y; 1237 // We don't do the contains() check right away because 1238 // findComponentAt would redundantly do it first thing. 1239 if (component[i] instanceof Container) 1240 { 1241 Container k = (Container) component[i]; 1242 Component r = k.findComponentAt(x2, y2); 1243 if (r != null) 1244 return r; 1245 } 1246 else if (component[i].contains(x2, y2)) 1247 return component[i]; 1248 } 1249 1250 return this; 1251 } 1252 } 1253 1254 /** 1255 * Locates the visible child component that contains the specified position. 1256 * The top-most child component is returned in the case where there is overlap 1257 * in the components. If the containing child component is a Container, 1258 * this method will continue searching for the deepest nested child 1259 * component. Components which are not visible are ignored during the search. 1260 * 1261 * findComponentAt differs from getComponentAt, because it recursively 1262 * searches a Container's children. 1263 * 1264 * @param p - the component's location 1265 * @return null if the component does not contain the position. 1266 * If there is no child component at the requested point and the point is 1267 * within the bounds of the container the container itself is returned. 1268 */ 1269 public Component findComponentAt(Point p) 1270 { 1271 return findComponentAt(p.x, p.y); 1272 } 1273 1274 /** 1275 * Called when this container is added to another container to inform it 1276 * to create its peer. Peers for any child components will also be 1277 * created. 1278 */ 1279 public void addNotify() 1280 { 1281 synchronized (getTreeLock()) 1282 { 1283 super.addNotify(); 1284 addNotifyContainerChildren(); 1285 } 1286 } 1287 1288 /** 1289 * Called when this container is removed from its parent container to 1290 * inform it to destroy its peer. This causes the peers of all child 1291 * component to be destroyed as well. 1292 */ 1293 public void removeNotify() 1294 { 1295 synchronized (getTreeLock ()) 1296 { 1297 int ncomps = ncomponents; 1298 Component[] comps = component; 1299 for (int i = ncomps - 1; i >= 0; --i) 1300 { 1301 Component comp = comps[i]; 1302 if (comp != null) 1303 comp.removeNotify(); 1304 } 1305 super.removeNotify(); 1306 } 1307 } 1308 1309 /** 1310 * Tests whether or not the specified component is contained within 1311 * this components subtree. 1312 * 1313 * @param comp The component to test. 1314 * 1315 * @return <code>true</code> if this container is an ancestor of the 1316 * specified component, <code>false</code> otherwise. 1317 */ 1318 public boolean isAncestorOf(Component comp) 1319 { 1320 synchronized (getTreeLock ()) 1321 { 1322 while (true) 1323 { 1324 if (comp == null) 1325 return false; 1326 if (comp == this) 1327 return true; 1328 comp = comp.getParent(); 1329 } 1330 } 1331 } 1332 1333 /** 1334 * Returns a string representing the state of this container for 1335 * debugging purposes. 1336 * 1337 * @return A string representing the state of this container. 1338 */ 1339 protected String paramString() 1340 { 1341 if (layoutMgr == null) 1342 return super.paramString(); 1343 1344 StringBuffer sb = new StringBuffer(); 1345 sb.append(super.paramString()); 1346 sb.append(",layout="); 1347 sb.append(layoutMgr.getClass().getName()); 1348 return sb.toString(); 1349 } 1350 1351 /** 1352 * Writes a listing of this container to the specified stream starting 1353 * at the specified indentation point. 1354 * 1355 * @param out The <code>PrintStream</code> to write to. 1356 * @param indent The indentation point. 1357 */ 1358 public void list(PrintStream out, int indent) 1359 { 1360 synchronized (getTreeLock ()) 1361 { 1362 super.list(out, indent); 1363 for (int i = 0; i < ncomponents; ++i) 1364 component[i].list(out, indent + 2); 1365 } 1366 } 1367 1368 /** 1369 * Writes a listing of this container to the specified stream starting 1370 * at the specified indentation point. 1371 * 1372 * @param out The <code>PrintWriter</code> to write to. 1373 * @param indent The indentation point. 1374 */ 1375 public void list(PrintWriter out, int indent) 1376 { 1377 synchronized (getTreeLock ()) 1378 { 1379 super.list(out, indent); 1380 for (int i = 0; i < ncomponents; ++i) 1381 component[i].list(out, indent + 2); 1382 } 1383 } 1384 1385 /** 1386 * Sets the focus traversal keys for a given traversal operation for this 1387 * Container. 1388 * 1389 * @exception IllegalArgumentException If id is not one of 1390 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1391 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1392 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1393 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, 1394 * or if keystrokes contains null, or if any Object in keystrokes is not an 1395 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any 1396 * keystroke already maps to another focus traversal operation for this 1397 * Container. 1398 * 1399 * @since 1.4 1400 */ 1401 public void setFocusTraversalKeys(int id, 1402 Set<? extends AWTKeyStroke> keystrokes) 1403 { 1404 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1405 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1406 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1407 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1408 throw new IllegalArgumentException (); 1409 1410 if (keystrokes == null) 1411 { 1412 Container parent = getParent (); 1413 1414 while (parent != null) 1415 { 1416 if (parent.areFocusTraversalKeysSet (id)) 1417 { 1418 keystrokes = parent.getFocusTraversalKeys (id); 1419 break; 1420 } 1421 parent = parent.getParent (); 1422 } 1423 1424 if (keystrokes == null) 1425 keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). 1426 getDefaultFocusTraversalKeys (id); 1427 } 1428 1429 Set sa; 1430 Set sb; 1431 Set sc; 1432 String name; 1433 switch (id) 1434 { 1435 case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: 1436 sa = getFocusTraversalKeys 1437 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1438 sb = getFocusTraversalKeys 1439 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1440 sc = getFocusTraversalKeys 1441 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1442 name = "forwardFocusTraversalKeys"; 1443 break; 1444 case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: 1445 sa = getFocusTraversalKeys 1446 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1447 sb = getFocusTraversalKeys 1448 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1449 sc = getFocusTraversalKeys 1450 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1451 name = "backwardFocusTraversalKeys"; 1452 break; 1453 case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: 1454 sa = getFocusTraversalKeys 1455 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1456 sb = getFocusTraversalKeys 1457 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1458 sc = getFocusTraversalKeys 1459 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1460 name = "upCycleFocusTraversalKeys"; 1461 break; 1462 case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: 1463 sa = getFocusTraversalKeys 1464 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1465 sb = getFocusTraversalKeys 1466 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1467 sc = getFocusTraversalKeys 1468 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1469 name = "downCycleFocusTraversalKeys"; 1470 break; 1471 default: 1472 throw new IllegalArgumentException (); 1473 } 1474 1475 int i = keystrokes.size (); 1476 Iterator iter = keystrokes.iterator (); 1477 1478 while (--i >= 0) 1479 { 1480 Object o = iter.next (); 1481 if (!(o instanceof AWTKeyStroke) 1482 || sa.contains (o) || sb.contains (o) || sc.contains (o) 1483 || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) 1484 throw new IllegalArgumentException (); 1485 } 1486 1487 if (focusTraversalKeys == null) 1488 focusTraversalKeys = new Set[4]; 1489 1490 keystrokes = 1491 Collections.unmodifiableSet(new HashSet<AWTKeyStroke>(keystrokes)); 1492 firePropertyChange (name, focusTraversalKeys[id], keystrokes); 1493 1494 focusTraversalKeys[id] = keystrokes; 1495 } 1496 1497 /** 1498 * Returns the Set of focus traversal keys for a given traversal operation for 1499 * this Container. 1500 * 1501 * @exception IllegalArgumentException If id is not one of 1502 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1503 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1504 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1505 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1506 * 1507 * @since 1.4 1508 */ 1509 public Set<AWTKeyStroke> getFocusTraversalKeys (int id) 1510 { 1511 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1512 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1513 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1514 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1515 throw new IllegalArgumentException (); 1516 1517 Set s = null; 1518 1519 if (focusTraversalKeys != null) 1520 s = focusTraversalKeys[id]; 1521 1522 if (s == null && parent != null) 1523 s = parent.getFocusTraversalKeys (id); 1524 1525 return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() 1526 .getDefaultFocusTraversalKeys(id)) : s; 1527 } 1528 1529 /** 1530 * Returns whether the Set of focus traversal keys for the given focus 1531 * traversal operation has been explicitly defined for this Container. 1532 * If this method returns false, this Container is inheriting the Set from 1533 * an ancestor, or from the current KeyboardFocusManager. 1534 * 1535 * @exception IllegalArgumentException If id is not one of 1536 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1537 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1538 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1539 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1540 * 1541 * @since 1.4 1542 */ 1543 public boolean areFocusTraversalKeysSet (int id) 1544 { 1545 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1546 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1547 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1548 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1549 throw new IllegalArgumentException (); 1550 1551 return focusTraversalKeys != null && focusTraversalKeys[id] != null; 1552 } 1553 1554 /** 1555 * Check whether the given Container is the focus cycle root of this 1556 * Container's focus traversal cycle. If this Container is a focus 1557 * cycle root itself, then it will be in two different focus cycles 1558 * -- it's own, and that of its ancestor focus cycle root's. In 1559 * that case, if <code>c</code> is either of those containers, this 1560 * method will return true. 1561 * 1562 * @param c the candidate Container 1563 * 1564 * @return true if c is the focus cycle root of the focus traversal 1565 * cycle to which this Container belongs, false otherwise 1566 * 1567 * @since 1.4 1568 */ 1569 public boolean isFocusCycleRoot (Container c) 1570 { 1571 if (this == c 1572 && isFocusCycleRoot ()) 1573 return true; 1574 1575 Container ancestor = getFocusCycleRootAncestor (); 1576 1577 if (c == ancestor) 1578 return true; 1579 1580 return false; 1581 } 1582 1583 /** 1584 * If this Container is a focus cycle root, set the focus traversal 1585 * policy that determines the focus traversal order for its 1586 * children. If non-null, this policy will be inherited by all 1587 * inferior focus cycle roots. If <code>policy</code> is null, this 1588 * Container will inherit its policy from the closest ancestor focus 1589 * cycle root that's had its policy set. 1590 * 1591 * @param policy the new focus traversal policy for this Container or null 1592 * 1593 * @since 1.4 1594 */ 1595 public void setFocusTraversalPolicy (FocusTraversalPolicy policy) 1596 { 1597 focusTraversalPolicy = policy; 1598 } 1599 1600 /** 1601 * Return the focus traversal policy that determines the focus 1602 * traversal order for this Container's children. This method 1603 * returns null if this Container is not a focus cycle root. If the 1604 * focus traversal policy has not been set explicitly, then this 1605 * method will return an ancestor focus cycle root's policy instead. 1606 * 1607 * @return this Container's focus traversal policy or null 1608 * 1609 * @since 1.4 1610 */ 1611 public FocusTraversalPolicy getFocusTraversalPolicy () 1612 { 1613 if (!isFocusCycleRoot ()) 1614 return null; 1615 1616 if (focusTraversalPolicy == null) 1617 { 1618 Container ancestor = getFocusCycleRootAncestor (); 1619 1620 if (ancestor != this && ancestor != null) 1621 return ancestor.getFocusTraversalPolicy (); 1622 else 1623 { 1624 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); 1625 1626 return manager.getDefaultFocusTraversalPolicy (); 1627 } 1628 } 1629 else 1630 return focusTraversalPolicy; 1631 } 1632 1633 /** 1634 * Check whether this Container's focus traversal policy has been 1635 * explicitly set. If it has not, then this Container will inherit 1636 * its focus traversal policy from one of its ancestor focus cycle 1637 * roots. 1638 * 1639 * @return true if focus traversal policy is set, false otherwise 1640 */ 1641 public boolean isFocusTraversalPolicySet () 1642 { 1643 return focusTraversalPolicy == null; 1644 } 1645 1646 /** 1647 * Set whether or not this Container is the root of a focus 1648 * traversal cycle. This Container's focus traversal policy 1649 * determines the order of focus traversal. Some policies prevent 1650 * the focus from being transferred between two traversal cycles 1651 * until an up or down traversal operation is performed. In that 1652 * case, normal traversal (not up or down) is limited to this 1653 * Container and all of this Container's descendents that are not 1654 * descendents of inferior focus cycle roots. In the default case 1655 * however, ContainerOrderFocusTraversalPolicy is in effect, and it 1656 * supports implicit down-cycle traversal operations. 1657 * 1658 * @param focusCycleRoot true if this is a focus cycle root, false otherwise 1659 * 1660 * @since 1.4 1661 */ 1662 public void setFocusCycleRoot (boolean focusCycleRoot) 1663 { 1664 this.focusCycleRoot = focusCycleRoot; 1665 } 1666 1667 /** 1668 * Set to <code>true</code> if this container provides a focus traversal 1669 * policy, <code>false</code> when the root container's focus 1670 * traversal policy should be used. 1671 * 1672 * @return <code>true</code> if this container provides a focus traversal 1673 * policy, <code>false</code> when the root container's focus 1674 * traversal policy should be used 1675 * 1676 * @see #setFocusTraversalPolicyProvider(boolean) 1677 * 1678 * @since 1.5 1679 */ 1680 public final boolean isFocusTraversalPolicyProvider() 1681 { 1682 return focusTraversalPolicyProvider; 1683 } 1684 1685 /** 1686 * Set to <code>true</code> if this container provides a focus traversal 1687 * policy, <code>false</code> when the root container's focus 1688 * traversal policy should be used. 1689 * 1690 * @param b <code>true</code> if this container provides a focus traversal 1691 * policy, <code>false</code> when the root container's focus 1692 * traversal policy should be used 1693 * 1694 * @see #isFocusTraversalPolicyProvider() 1695 * 1696 * @since 1.5 1697 */ 1698 public final void setFocusTraversalPolicyProvider(boolean b) 1699 { 1700 focusTraversalPolicyProvider = b; 1701 } 1702 1703 /** 1704 * Check whether this Container is a focus cycle root. 1705 * 1706 * @return true if this is a focus cycle root, false otherwise 1707 * 1708 * @since 1.4 1709 */ 1710 public boolean isFocusCycleRoot () 1711 { 1712 return focusCycleRoot; 1713 } 1714 1715 /** 1716 * Transfer focus down one focus traversal cycle. If this Container 1717 * is a focus cycle root, then its default component becomes the 1718 * focus owner, and this Container becomes the current focus cycle 1719 * root. No traversal will occur if this Container is not a focus 1720 * cycle root. 1721 * 1722 * @since 1.4 1723 */ 1724 public void transferFocusDownCycle () 1725 { 1726 if (isFocusCycleRoot()) 1727 { 1728 KeyboardFocusManager fm = 1729 KeyboardFocusManager.getCurrentKeyboardFocusManager(); 1730 fm.setGlobalCurrentFocusCycleRoot(this); 1731 FocusTraversalPolicy policy = getFocusTraversalPolicy(); 1732 Component defaultComponent = policy.getDefaultComponent(this); 1733 if (defaultComponent != null) 1734 defaultComponent.requestFocus(); 1735 } 1736 } 1737 1738 /** 1739 * Sets the ComponentOrientation property of this container and all components 1740 * contained within it. 1741 * 1742 * @exception NullPointerException If orientation is null 1743 * 1744 * @since 1.4 1745 */ 1746 public void applyComponentOrientation (ComponentOrientation orientation) 1747 { 1748 if (orientation == null) 1749 throw new NullPointerException(); 1750 1751 setComponentOrientation(orientation); 1752 for (int i = 0; i < ncomponents; i++) 1753 { 1754 if (component[i] instanceof Container) 1755 ((Container) component[i]).applyComponentOrientation(orientation); 1756 else 1757 component[i].setComponentOrientation(orientation); 1758 } 1759 } 1760 1761 public void addPropertyChangeListener (PropertyChangeListener listener) 1762 { 1763 // TODO: Why is this overridden? 1764 super.addPropertyChangeListener(listener); 1765 } 1766 1767 public void addPropertyChangeListener (String propertyName, 1768 PropertyChangeListener listener) 1769 { 1770 // TODO: Why is this overridden? 1771 super.addPropertyChangeListener(propertyName, listener); 1772 } 1773 1774 1775 /** 1776 * Sets the Z ordering for the component <code>comp</code> to 1777 * <code>index</code>. Components with lower Z order paint above components 1778 * with higher Z order. 1779 * 1780 * @param comp the component for which to change the Z ordering 1781 * @param index the index to set 1782 * 1783 * @throws NullPointerException if <code>comp == null</code> 1784 * @throws IllegalArgumentException if comp is an ancestor of this container 1785 * @throws IllegalArgumentException if <code>index</code> is not in 1786 * <code>[0, getComponentCount()]</code> for moving between 1787 * containers or <code>[0, getComponentCount() - 1]</code> for moving 1788 * inside this container 1789 * @throws IllegalArgumentException if <code>comp == this</code> 1790 * @throws IllegalArgumentException if <code>comp</code> is a 1791 * <code>Window</code> 1792 * 1793 * @see #getComponentZOrder(Component) 1794 * 1795 * @since 1.5 1796 */ 1797 public final void setComponentZOrder(Component comp, int index) 1798 { 1799 if (comp == null) 1800 throw new NullPointerException("comp must not be null"); 1801 if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) 1802 throw new IllegalArgumentException("comp must not be an ancestor of " 1803 + "this"); 1804 if (comp instanceof Window) 1805 throw new IllegalArgumentException("comp must not be a Window"); 1806 1807 if (comp == this) 1808 throw new IllegalArgumentException("cannot add component to itself"); 1809 1810 synchronized (getTreeLock()) 1811 { 1812 // FIXME: Implement reparenting. 1813 if ( comp.getParent() != this) 1814 throw new AssertionError("Reparenting is not implemented yet"); 1815 else 1816 { 1817 // Find current component index. 1818 int currentIndex = getComponentZOrder(comp); 1819 if (currentIndex < index) 1820 { 1821 System.arraycopy(component, currentIndex + 1, component, 1822 currentIndex, index - currentIndex); 1823 } 1824 else 1825 { 1826 System.arraycopy(component, index, component, index + 1, 1827 currentIndex - index); 1828 } 1829 component[index] = comp; 1830 } 1831 } 1832 } 1833 1834 /** 1835 * Returns the Z ordering index of <code>comp</code>. If <code>comp</code> 1836 * is not a child component of this Container, this returns <code>-1</code>. 1837 * 1838 * @param comp the component for which to query the Z ordering 1839 * 1840 * @return the Z ordering index of <code>comp</code> or <code>-1</code> if 1841 * <code>comp</code> is not a child of this Container 1842 * 1843 * @see #setComponentZOrder(Component, int) 1844 * 1845 * @since 1.5 1846 */ 1847 public final int getComponentZOrder(Component comp) 1848 { 1849 synchronized (getTreeLock()) 1850 { 1851 int index = -1; 1852 if (component != null) 1853 { 1854 for (int i = 0; i < ncomponents; i++) 1855 { 1856 if (component[i] == comp) 1857 { 1858 index = i; 1859 break; 1860 } 1861 } 1862 } 1863 return index; 1864 } 1865 } 1866 1867 // Hidden helper methods. 1868 1869 /** 1870 * Perform a graphics operation on the children of this container. 1871 * For each applicable child, the visitChild() method will be called 1872 * to perform the graphics operation. 1873 * 1874 * @param gfx The graphics object that will be used to derive new 1875 * graphics objects for the children. 1876 * 1877 * @param visitor Object encapsulating the graphics operation that 1878 * should be performed. 1879 * 1880 * @param lightweightOnly If true, only lightweight components will 1881 * be visited. 1882 */ 1883 private void visitChildren(Graphics gfx, GfxVisitor visitor, 1884 boolean lightweightOnly) 1885 { 1886 synchronized (getTreeLock()) 1887 { 1888 for (int i = ncomponents - 1; i >= 0; --i) 1889 { 1890 Component comp = component[i]; 1891 boolean applicable = comp.isVisible() 1892 && (comp.isLightweight() || ! lightweightOnly); 1893 1894 if (applicable) 1895 visitChild(gfx, visitor, comp); 1896 } 1897 } 1898 } 1899 1900 /** 1901 * Perform a graphics operation on a child. A translated and clipped 1902 * graphics object will be created, and the visit() method of the 1903 * visitor will be called to perform the operation. 1904 * 1905 * @param gfx The graphics object that will be used to derive new 1906 * graphics objects for the child. 1907 * 1908 * @param visitor Object encapsulating the graphics operation that 1909 * should be performed. 1910 * 1911 * @param comp The child component that should be visited. 1912 */ 1913 private void visitChild(Graphics gfx, GfxVisitor visitor, 1914 Component comp) 1915 { 1916 Rectangle bounds = comp.getBounds(); 1917 1918 if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) 1919 return; 1920 Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, 1921 bounds.height); 1922 try 1923 { 1924 g2.setFont(comp.getFont()); 1925 visitor.visit(comp, g2); 1926 } 1927 finally 1928 { 1929 g2.dispose(); 1930 } 1931 } 1932 1933 /** 1934 * Overridden to dispatch events to lightweight descendents. 1935 * 1936 * @param e the event to dispatch. 1937 */ 1938 void dispatchEventImpl(AWTEvent e) 1939 { 1940 LightweightDispatcher dispatcher = LightweightDispatcher.getInstance(); 1941 if (! isLightweight() && dispatcher.dispatchEvent(e)) 1942 { 1943 // Some lightweight descendent got this event dispatched. Consume 1944 // it and let the peer handle it. 1945 e.consume(); 1946 ComponentPeer p = peer; 1947 if (p != null) 1948 p.handleEvent(e); 1949 } 1950 else 1951 { 1952 super.dispatchEventImpl(e); 1953 } 1954 } 1955 1956 /** 1957 * This is called by the lightweight dispatcher to avoid recursivly 1958 * calling into the lightweight dispatcher. 1959 * 1960 * @param e the event to dispatch 1961 * 1962 * @see LightweightDispatcher#redispatch(MouseEvent, Component, int) 1963 */ 1964 void dispatchNoLightweight(AWTEvent e) 1965 { 1966 super.dispatchEventImpl(e); 1967 } 1968 1969 /** 1970 * Tests if this container has an interest in the given event id. 1971 * 1972 * @param eventId The event id to check. 1973 * 1974 * @return <code>true</code> if a listener for the event id exists or 1975 * if the eventMask is set for the event id. 1976 * 1977 * @see java.awt.Component#eventTypeEnabled(int) 1978 */ 1979 boolean eventTypeEnabled(int eventId) 1980 { 1981 if(eventId <= ContainerEvent.CONTAINER_LAST 1982 && eventId >= ContainerEvent.CONTAINER_FIRST) 1983 return containerListener != null 1984 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0; 1985 else 1986 return super.eventTypeEnabled(eventId); 1987 } 1988 1989 // This is used to implement Component.transferFocus. 1990 Component findNextFocusComponent(Component child) 1991 { 1992 synchronized (getTreeLock ()) 1993 { 1994 int start, end; 1995 if (child != null) 1996 { 1997 for (start = 0; start < ncomponents; ++start) 1998 { 1999 if (component[start] == child) 2000 break; 2001 } 2002 end = start; 2003 // This special case lets us be sure to terminate. 2004 if (end == 0) 2005 end = ncomponents; 2006 ++start; 2007 } 2008 else 2009 { 2010 start = 0; 2011 end = ncomponents; 2012 } 2013 2014 for (int j = start; j != end; ++j) 2015 { 2016 if (j >= ncomponents) 2017 { 2018 // The JCL says that we should wrap here. However, that 2019 // seems wrong. To me it seems that focus order should be 2020 // global within in given window. So instead if we reach 2021 // the end we try to look in our parent, if we have one. 2022 if (parent != null) 2023 return parent.findNextFocusComponent(this); 2024 j -= ncomponents; 2025 } 2026 if (component[j] instanceof Container) 2027 { 2028 Component c = component[j]; 2029 c = c.findNextFocusComponent(null); 2030 if (c != null) 2031 return c; 2032 } 2033 else if (component[j].isFocusTraversable()) 2034 return component[j]; 2035 } 2036 2037 return null; 2038 } 2039 } 2040 2041 /** 2042 * Fires hierarchy events to the children of this container and this 2043 * container itself. This overrides {@link Component#fireHierarchyEvent} 2044 * in order to forward this event to all children. 2045 */ 2046 void fireHierarchyEvent(int id, Component changed, Container parent, 2047 long flags) 2048 { 2049 // Only propagate event if there is actually a listener waiting for it. 2050 if ((id == HierarchyEvent.HIERARCHY_CHANGED && numHierarchyListeners > 0) 2051 || ((id == HierarchyEvent.ANCESTOR_MOVED 2052 || id == HierarchyEvent.ANCESTOR_RESIZED) 2053 && numHierarchyBoundsListeners > 0)) 2054 { 2055 for (int i = 0; i < ncomponents; i++) 2056 component[i].fireHierarchyEvent(id, changed, parent, flags); 2057 super.fireHierarchyEvent(id, changed, parent, flags); 2058 } 2059 } 2060 2061 /** 2062 * Adjusts the number of hierarchy listeners of this container and all of 2063 * its parents. This is called by the add/remove listener methods and 2064 * structure changing methods in Container. 2065 * 2066 * @param type the type, either {@link AWTEvent#HIERARCHY_BOUNDS_EVENT_MASK} 2067 * or {@link AWTEvent#HIERARCHY_EVENT_MASK} 2068 * @param delta the number of listeners added or removed 2069 */ 2070 void updateHierarchyListenerCount(long type, int delta) 2071 { 2072 if (type == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) 2073 numHierarchyBoundsListeners += delta; 2074 else if (type == AWTEvent.HIERARCHY_EVENT_MASK) 2075 numHierarchyListeners += delta; 2076 else 2077 assert false : "Should not reach here"; 2078 2079 if (parent != null) 2080 parent.updateHierarchyListenerCount(type, delta); 2081 } 2082 2083 /** 2084 * Notifies interested listeners about resizing or moving the container. 2085 * This performs the super behaviour (sending component events) and 2086 * additionally notifies any hierarchy bounds listeners on child components. 2087 * 2088 * @param resized true if the component has been resized, false otherwise 2089 * @param moved true if the component has been moved, false otherwise 2090 */ 2091 void notifyReshape(boolean resized, boolean moved) 2092 { 2093 // Notify component listeners. 2094 super.notifyReshape(resized, moved); 2095 2096 if (ncomponents > 0) 2097 { 2098 // Notify hierarchy bounds listeners. 2099 if (resized) 2100 { 2101 for (int i = 0; i < getComponentCount(); i++) 2102 { 2103 Component child = getComponent(i); 2104 child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, 2105 this, parent, 0); 2106 } 2107 } 2108 if (moved) 2109 { 2110 for (int i = 0; i < getComponentCount(); i++) 2111 { 2112 Component child = getComponent(i); 2113 child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, 2114 this, parent, 0); 2115 } 2116 } 2117 } 2118 } 2119 2120 private void addNotifyContainerChildren() 2121 { 2122 synchronized (getTreeLock ()) 2123 { 2124 for (int i = ncomponents; --i >= 0; ) 2125 { 2126 component[i].addNotify(); 2127 } 2128 } 2129 } 2130 2131 /** 2132 * Deserialize this Container: 2133 * <ol> 2134 * <li>Read from the stream the default serializable fields.</li> 2135 * <li>Read a list of serializable ContainerListeners as optional 2136 * data. If the list is null, no listeners will be registered.</li> 2137 * <li>Read this Container's FocusTraversalPolicy as optional data. 2138 * If this is null, then this Container will use a 2139 * DefaultFocusTraversalPolicy.</li> 2140 * </ol> 2141 * 2142 * @param s the stream to read from 2143 * @throws ClassNotFoundException if deserialization fails 2144 * @throws IOException if the stream fails 2145 */ 2146 private void readObject (ObjectInputStream s) 2147 throws ClassNotFoundException, IOException 2148 { 2149 s.defaultReadObject (); 2150 String key = (String) s.readObject (); 2151 while (key != null) 2152 { 2153 Object object = s.readObject (); 2154 if ("containerL".equals (key)) 2155 addContainerListener((ContainerListener) object); 2156 // FIXME: under what key is the focus traversal policy stored? 2157 else if ("focusTraversalPolicy".equals (key)) 2158 setFocusTraversalPolicy ((FocusTraversalPolicy) object); 2159 2160 key = (String) s.readObject(); 2161 } 2162 } 2163 2164 /** 2165 * Serialize this Container: 2166 * <ol> 2167 * <li>Write to the stream the default serializable fields.</li> 2168 * <li>Write the list of serializable ContainerListeners as optional 2169 * data.</li> 2170 * <li>Write this Container's FocusTraversalPolicy as optional data.</li> 2171 * </ol> 2172 * 2173 * @param s the stream to write to 2174 * @throws IOException if the stream fails 2175 */ 2176 private void writeObject (ObjectOutputStream s) throws IOException 2177 { 2178 s.defaultWriteObject (); 2179 AWTEventMulticaster.save (s, "containerL", containerListener); 2180 if (focusTraversalPolicy instanceof Serializable) 2181 s.writeObject (focusTraversalPolicy); 2182 else 2183 s.writeObject (null); 2184 } 2185 2186 // Nested classes. 2187 2188 /* The following classes are used in concert with the 2189 visitChildren() method to implement all the graphics operations 2190 that requires traversal of the containment hierarchy. */ 2191 2192 abstract static class GfxVisitor 2193 { 2194 public abstract void visit(Component c, Graphics gfx); 2195 } 2196 2197 static class GfxPaintVisitor extends GfxVisitor 2198 { 2199 public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); 2200 2201 public void visit(Component c, Graphics gfx) 2202 { 2203 c.paint(gfx); 2204 } 2205 } 2206 2207 static class GfxPrintVisitor extends GfxVisitor 2208 { 2209 public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); 2210 2211 public void visit(Component c, Graphics gfx) 2212 { 2213 c.print(gfx); 2214 } 2215 } 2216 2217 static class GfxPaintAllVisitor extends GfxVisitor 2218 { 2219 public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); 2220 2221 public void visit(Component c, Graphics gfx) 2222 { 2223 c.paintAll(gfx); 2224 } 2225 } 2226 2227 static class GfxPrintAllVisitor extends GfxVisitor 2228 { 2229 public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); 2230 2231 public void visit(Component c, Graphics gfx) 2232 { 2233 c.printAll(gfx); 2234 } 2235 } 2236 2237 /** 2238 * This class provides accessibility support for subclasses of container. 2239 * 2240 * @author Eric Blake (ebb9@email.byu.edu) 2241 * 2242 * @since 1.3 2243 */ 2244 protected class AccessibleAWTContainer extends AccessibleAWTComponent 2245 { 2246 /** 2247 * Compatible with JDK 1.4+. 2248 */ 2249 private static final long serialVersionUID = 5081320404842566097L; 2250 2251 /** 2252 * The handler to fire PropertyChange when children are added or removed. 2253 * 2254 * @serial the handler for property changes 2255 */ 2256 protected ContainerListener accessibleContainerHandler 2257 = new AccessibleContainerHandler(); 2258 2259 /** 2260 * The default constructor. 2261 */ 2262 protected AccessibleAWTContainer() 2263 { 2264 Container.this.addContainerListener(accessibleContainerHandler); 2265 } 2266 2267 /** 2268 * Return the number of accessible children of the containing accessible 2269 * object (at most the total number of its children). 2270 * 2271 * @return the number of accessible children 2272 */ 2273 public int getAccessibleChildrenCount() 2274 { 2275 synchronized (getTreeLock ()) 2276 { 2277 int count = 0; 2278 int i = component == null ? 0 : component.length; 2279 while (--i >= 0) 2280 if (component[i] instanceof Accessible) 2281 count++; 2282 return count; 2283 } 2284 } 2285 2286 /** 2287 * Return the nth accessible child of the containing accessible object. 2288 * 2289 * @param i the child to grab, zero-based 2290 * @return the accessible child, or null 2291 */ 2292 public Accessible getAccessibleChild(int i) 2293 { 2294 synchronized (getTreeLock ()) 2295 { 2296 if (component == null) 2297 return null; 2298 int index = -1; 2299 while (i >= 0 && ++index < component.length) 2300 if (component[index] instanceof Accessible) 2301 i--; 2302 if (i < 0) 2303 return (Accessible) component[index]; 2304 return null; 2305 } 2306 } 2307 2308 /** 2309 * Return the accessible child located at point (in the parent's 2310 * coordinates), if one exists. 2311 * 2312 * @param p the point to look at 2313 * 2314 * @return an accessible object at that point, or null 2315 * 2316 * @throws NullPointerException if p is null 2317 */ 2318 public Accessible getAccessibleAt(Point p) 2319 { 2320 Component c = getComponentAt(p.x, p.y); 2321 return c != Container.this && c instanceof Accessible ? (Accessible) c 2322 : null; 2323 } 2324 2325 /** 2326 * This class fires a <code>PropertyChange</code> listener, if registered, 2327 * when children are added or removed from the enclosing accessible object. 2328 * 2329 * @author Eric Blake (ebb9@email.byu.edu) 2330 * 2331 * @since 1.3 2332 */ 2333 protected class AccessibleContainerHandler implements ContainerListener 2334 { 2335 /** 2336 * Default constructor. 2337 */ 2338 protected AccessibleContainerHandler() 2339 { 2340 // Nothing to do here. 2341 } 2342 2343 /** 2344 * Fired when a component is added; forwards to the PropertyChange 2345 * listener. 2346 * 2347 * @param e the container event for adding 2348 */ 2349 public void componentAdded(ContainerEvent e) 2350 { 2351 AccessibleAWTContainer.this.firePropertyChange 2352 (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); 2353 } 2354 2355 /** 2356 * Fired when a component is removed; forwards to the PropertyChange 2357 * listener. 2358 * 2359 * @param e the container event for removing 2360 */ 2361 public void componentRemoved(ContainerEvent e) 2362 { 2363 AccessibleAWTContainer.this.firePropertyChange 2364 (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); 2365 } 2366 } // class AccessibleContainerHandler 2367 } // class AccessibleAWTContainer 2368 } // class Container