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