GNU Classpath (0.95) | |
Frames | No Frames |
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 java.awt.event.ContainerEvent; 43: import java.awt.event.ContainerListener; 44: import java.awt.event.HierarchyEvent; 45: import java.awt.event.KeyEvent; 46: import java.awt.event.MouseEvent; 47: import java.awt.peer.ComponentPeer; 48: import java.awt.peer.ContainerPeer; 49: import java.awt.peer.LightweightPeer; 50: import java.beans.PropertyChangeListener; 51: import java.io.IOException; 52: import java.io.ObjectInputStream; 53: import java.io.ObjectOutputStream; 54: import java.io.PrintStream; 55: import java.io.PrintWriter; 56: import java.io.Serializable; 57: import java.util.Collections; 58: import java.util.EventListener; 59: import java.util.HashSet; 60: import java.util.Iterator; 61: import java.util.Set; 62: 63: import javax.accessibility.Accessible; 64: 65: /** 66: * A generic window toolkit object that acts as a container for other objects. 67: * Components are tracked in a list, and new elements are at the end of the 68: * list or bottom of the stacking order. 69: * 70: * @author original author unknown 71: * @author Eric Blake (ebb9@email.byu.edu) 72: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 73: * 74: * @since 1.0 75: * 76: * @status still missing 1.4 support, some generics from 1.5 77: */ 78: public class Container extends Component 79: { 80: /** 81: * Compatible with JDK 1.0+. 82: */ 83: private static final long serialVersionUID = 4613797578919906343L; 84: 85: /* Serialized fields from the serialization spec. */ 86: int ncomponents; 87: Component[] component; 88: LayoutManager layoutMgr; 89: 90: /** 91: * @since 1.4 92: */ 93: boolean focusCycleRoot; 94: 95: /** 96: * Indicates if this container provides a focus traversal policy. 97: * 98: * @since 1.5 99: */ 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 component located at the specified point. This is done 1102: * by checking whether or not a child component claims to contain this 1103: * point. The first child component that does is returned. If no 1104: * child component claims the point, the container itself is returned, 1105: * unless the point does not exist within this container, in which 1106: * case <code>null</code> is returned. 1107: * 1108: * When components overlap, the first component is returned. The component 1109: * that is closest to (x, y), containing that location, is returned. 1110: * Heavyweight components take precedence of lightweight components. 1111: * 1112: * This function does not ignore invisible components. If there is an invisible 1113: * component at (x,y), it will be returned. 1114: * 1115: * @param x The x position of the point to return the component at. 1116: * @param y The y position of the point to return the component at. 1117: * 1118: * @return The component containing the specified point, or <code>null</code> 1119: * if there is no such point. 1120: * 1121: * @deprecated use {@link #getComponentAt(int, int)} instead 1122: */ 1123: public Component locate(int x, int y) 1124: { 1125: synchronized (getTreeLock ()) 1126: { 1127: if (!contains (x, y)) 1128: return null; 1129: 1130: // First find the component closest to (x,y) that is a heavyweight. 1131: for (int i = 0; i < ncomponents; ++i) 1132: { 1133: Component comp = component[i]; 1134: int x2 = x - comp.x; 1135: int y2 = y - comp.y; 1136: if (comp.contains (x2, y2) && !comp.isLightweight()) 1137: return comp; 1138: } 1139: 1140: // if a heavyweight component is not found, look for a lightweight 1141: // closest to (x,y). 1142: for (int i = 0; i < ncomponents; ++i) 1143: { 1144: Component comp = component[i]; 1145: int x2 = x - comp.x; 1146: int y2 = y - comp.y; 1147: if (comp.contains (x2, y2) && comp.isLightweight()) 1148: return comp; 1149: } 1150: 1151: return this; 1152: } 1153: } 1154: 1155: /** 1156: * Returns the component located at the specified point. This is done 1157: * by checking whether or not a child component claims to contain this 1158: * point. The first child component that does is returned. If no 1159: * child component claims the point, the container itself is returned, 1160: * unless the point does not exist within this container, in which 1161: * case <code>null</code> is returned. 1162: * 1163: * The top-most child component is returned in the case where components overlap. 1164: * This is determined by finding the component closest to (x,y) and contains 1165: * that location. Heavyweight components take precedence of lightweight components. 1166: * 1167: * This function does not ignore invisible components. If there is an invisible 1168: * component at (x,y), it will be returned. 1169: * 1170: * @param p The point to return the component at. 1171: * @return The component containing the specified point, or <code>null</code> 1172: * if there is no such point. 1173: */ 1174: public Component getComponentAt(Point p) 1175: { 1176: return getComponentAt (p.x, p.y); 1177: } 1178: 1179: /** 1180: * Locates the visible child component that contains the specified position. 1181: * The top-most child component is returned in the case where there is overlap 1182: * in the components. If the containing child component is a Container, 1183: * this method will continue searching for the deepest nested child 1184: * component. Components which are not visible are ignored during the search. 1185: * 1186: * findComponentAt differs from getComponentAt, because it recursively 1187: * searches a Container's children. 1188: * 1189: * @param x - x coordinate 1190: * @param y - y coordinate 1191: * @return null if the component does not contain the position. 1192: * If there is no child component at the requested point and the point is 1193: * within the bounds of the container the container itself is returned. 1194: */ 1195: public Component findComponentAt(int x, int y) 1196: { 1197: synchronized (getTreeLock ()) 1198: { 1199: if (! contains(x, y)) 1200: return null; 1201: 1202: for (int i = 0; i < ncomponents; ++i) 1203: { 1204: // Ignore invisible children... 1205: if (!component[i].isVisible()) 1206: continue; 1207: 1208: int x2 = x - component[i].x; 1209: int y2 = y - component[i].y; 1210: // We don't do the contains() check right away because 1211: // findComponentAt would redundantly do it first thing. 1212: if (component[i] instanceof Container) 1213: { 1214: Container k = (Container) component[i]; 1215: Component r = k.findComponentAt(x2, y2); 1216: if (r != null) 1217: return r; 1218: } 1219: else if (component[i].contains(x2, y2)) 1220: return component[i]; 1221: } 1222: 1223: return this; 1224: } 1225: } 1226: 1227: /** 1228: * Locates the visible child component that contains the specified position. 1229: * The top-most child component is returned in the case where there is overlap 1230: * in the components. If the containing child component is a Container, 1231: * this method will continue searching for the deepest nested child 1232: * component. Components which are not visible are ignored during the search. 1233: * 1234: * findComponentAt differs from getComponentAt, because it recursively 1235: * searches a Container's children. 1236: * 1237: * @param p - the component's location 1238: * @return null if the component does not contain the position. 1239: * If there is no child component at the requested point and the point is 1240: * within the bounds of the container the container itself is returned. 1241: */ 1242: public Component findComponentAt(Point p) 1243: { 1244: return findComponentAt(p.x, p.y); 1245: } 1246: 1247: /** 1248: * Called when this container is added to another container to inform it 1249: * to create its peer. Peers for any child components will also be 1250: * created. 1251: */ 1252: public void addNotify() 1253: { 1254: synchronized (getTreeLock()) 1255: { 1256: super.addNotify(); 1257: addNotifyContainerChildren(); 1258: } 1259: } 1260: 1261: /** 1262: * Called when this container is removed from its parent container to 1263: * inform it to destroy its peer. This causes the peers of all child 1264: * component to be destroyed as well. 1265: */ 1266: public void removeNotify() 1267: { 1268: synchronized (getTreeLock ()) 1269: { 1270: int ncomps = ncomponents; 1271: Component[] comps = component; 1272: for (int i = ncomps - 1; i >= 0; --i) 1273: { 1274: Component comp = comps[i]; 1275: if (comp != null) 1276: comp.removeNotify(); 1277: } 1278: super.removeNotify(); 1279: } 1280: } 1281: 1282: /** 1283: * Tests whether or not the specified component is contained within 1284: * this components subtree. 1285: * 1286: * @param comp The component to test. 1287: * 1288: * @return <code>true</code> if this container is an ancestor of the 1289: * specified component, <code>false</code> otherwise. 1290: */ 1291: public boolean isAncestorOf(Component comp) 1292: { 1293: synchronized (getTreeLock ()) 1294: { 1295: while (true) 1296: { 1297: if (comp == null) 1298: return false; 1299: if (comp == this) 1300: return true; 1301: comp = comp.getParent(); 1302: } 1303: } 1304: } 1305: 1306: /** 1307: * Returns a string representing the state of this container for 1308: * debugging purposes. 1309: * 1310: * @return A string representing the state of this container. 1311: */ 1312: protected String paramString() 1313: { 1314: if (layoutMgr == null) 1315: return super.paramString(); 1316: 1317: StringBuffer sb = new StringBuffer(); 1318: sb.append(super.paramString()); 1319: sb.append(",layout="); 1320: sb.append(layoutMgr.getClass().getName()); 1321: return sb.toString(); 1322: } 1323: 1324: /** 1325: * Writes a listing of this container to the specified stream starting 1326: * at the specified indentation point. 1327: * 1328: * @param out The <code>PrintStream</code> to write to. 1329: * @param indent The indentation point. 1330: */ 1331: public void list(PrintStream out, int indent) 1332: { 1333: synchronized (getTreeLock ()) 1334: { 1335: super.list(out, indent); 1336: for (int i = 0; i < ncomponents; ++i) 1337: component[i].list(out, indent + 2); 1338: } 1339: } 1340: 1341: /** 1342: * Writes a listing of this container to the specified stream starting 1343: * at the specified indentation point. 1344: * 1345: * @param out The <code>PrintWriter</code> to write to. 1346: * @param indent The indentation point. 1347: */ 1348: public void list(PrintWriter out, int indent) 1349: { 1350: synchronized (getTreeLock ()) 1351: { 1352: super.list(out, indent); 1353: for (int i = 0; i < ncomponents; ++i) 1354: component[i].list(out, indent + 2); 1355: } 1356: } 1357: 1358: /** 1359: * Sets the focus traversal keys for a given traversal operation for this 1360: * Container. 1361: * 1362: * @exception IllegalArgumentException If id is not one of 1363: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1364: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1365: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1366: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, 1367: * or if keystrokes contains null, or if any Object in keystrokes is not an 1368: * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any 1369: * keystroke already maps to another focus traversal operation for this 1370: * Container. 1371: * 1372: * @since 1.4 1373: */ 1374: public void setFocusTraversalKeys(int id, 1375: Set<? extends AWTKeyStroke> keystrokes) 1376: { 1377: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1378: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1379: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1380: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1381: throw new IllegalArgumentException (); 1382: 1383: if (keystrokes == null) 1384: { 1385: Container parent = getParent (); 1386: 1387: while (parent != null) 1388: { 1389: if (parent.areFocusTraversalKeysSet (id)) 1390: { 1391: keystrokes = parent.getFocusTraversalKeys (id); 1392: break; 1393: } 1394: parent = parent.getParent (); 1395: } 1396: 1397: if (keystrokes == null) 1398: keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). 1399: getDefaultFocusTraversalKeys (id); 1400: } 1401: 1402: Set sa; 1403: Set sb; 1404: Set sc; 1405: String name; 1406: switch (id) 1407: { 1408: case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: 1409: sa = getFocusTraversalKeys 1410: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1411: sb = getFocusTraversalKeys 1412: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1413: sc = getFocusTraversalKeys 1414: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1415: name = "forwardFocusTraversalKeys"; 1416: break; 1417: case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: 1418: sa = getFocusTraversalKeys 1419: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1420: sb = getFocusTraversalKeys 1421: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1422: sc = getFocusTraversalKeys 1423: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1424: name = "backwardFocusTraversalKeys"; 1425: break; 1426: case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: 1427: sa = getFocusTraversalKeys 1428: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1429: sb = getFocusTraversalKeys 1430: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1431: sc = getFocusTraversalKeys 1432: (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); 1433: name = "upCycleFocusTraversalKeys"; 1434: break; 1435: case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: 1436: sa = getFocusTraversalKeys 1437: (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 1438: sb = getFocusTraversalKeys 1439: (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 1440: sc = getFocusTraversalKeys 1441: (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); 1442: name = "downCycleFocusTraversalKeys"; 1443: break; 1444: default: 1445: throw new IllegalArgumentException (); 1446: } 1447: 1448: int i = keystrokes.size (); 1449: Iterator iter = keystrokes.iterator (); 1450: 1451: while (--i >= 0) 1452: { 1453: Object o = iter.next (); 1454: if (!(o instanceof AWTKeyStroke) 1455: || sa.contains (o) || sb.contains (o) || sc.contains (o) 1456: || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) 1457: throw new IllegalArgumentException (); 1458: } 1459: 1460: if (focusTraversalKeys == null) 1461: focusTraversalKeys = new Set[4]; 1462: 1463: keystrokes = 1464: Collections.unmodifiableSet(new HashSet<AWTKeyStroke>(keystrokes)); 1465: firePropertyChange (name, focusTraversalKeys[id], keystrokes); 1466: 1467: focusTraversalKeys[id] = keystrokes; 1468: } 1469: 1470: /** 1471: * Returns the Set of focus traversal keys for a given traversal operation for 1472: * this Container. 1473: * 1474: * @exception IllegalArgumentException If id is not one of 1475: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1476: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1477: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1478: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1479: * 1480: * @since 1.4 1481: */ 1482: public Set<AWTKeyStroke> getFocusTraversalKeys (int id) 1483: { 1484: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1485: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1486: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1487: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1488: throw new IllegalArgumentException (); 1489: 1490: Set s = null; 1491: 1492: if (focusTraversalKeys != null) 1493: s = focusTraversalKeys[id]; 1494: 1495: if (s == null && parent != null) 1496: s = parent.getFocusTraversalKeys (id); 1497: 1498: return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() 1499: .getDefaultFocusTraversalKeys(id)) : s; 1500: } 1501: 1502: /** 1503: * Returns whether the Set of focus traversal keys for the given focus 1504: * traversal operation has been explicitly defined for this Container. 1505: * If this method returns false, this Container is inheriting the Set from 1506: * an ancestor, or from the current KeyboardFocusManager. 1507: * 1508: * @exception IllegalArgumentException If id is not one of 1509: * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 1510: * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, 1511: * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, 1512: * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS. 1513: * 1514: * @since 1.4 1515: */ 1516: public boolean areFocusTraversalKeysSet (int id) 1517: { 1518: if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && 1519: id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && 1520: id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && 1521: id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) 1522: throw new IllegalArgumentException (); 1523: 1524: return focusTraversalKeys != null && focusTraversalKeys[id] != null; 1525: } 1526: 1527: /** 1528: * Check whether the given Container is the focus cycle root of this 1529: * Container's focus traversal cycle. If this Container is a focus 1530: * cycle root itself, then it will be in two different focus cycles 1531: * -- it's own, and that of its ancestor focus cycle root's. In 1532: * that case, if <code>c</code> is either of those containers, this 1533: * method will return true. 1534: * 1535: * @param c the candidate Container 1536: * 1537: * @return true if c is the focus cycle root of the focus traversal 1538: * cycle to which this Container belongs, false otherwise 1539: * 1540: * @since 1.4 1541: */ 1542: public boolean isFocusCycleRoot (Container c) 1543: { 1544: if (this == c 1545: && isFocusCycleRoot ()) 1546: return true; 1547: 1548: Container ancestor = getFocusCycleRootAncestor (); 1549: 1550: if (c == ancestor) 1551: return true; 1552: 1553: return false; 1554: } 1555: 1556: /** 1557: * If this Container is a focus cycle root, set the focus traversal 1558: * policy that determines the focus traversal order for its 1559: * children. If non-null, this policy will be inherited by all 1560: * inferior focus cycle roots. If <code>policy</code> is null, this 1561: * Container will inherit its policy from the closest ancestor focus 1562: * cycle root that's had its policy set. 1563: * 1564: * @param policy the new focus traversal policy for this Container or null 1565: * 1566: * @since 1.4 1567: */ 1568: public void setFocusTraversalPolicy (FocusTraversalPolicy policy) 1569: { 1570: focusTraversalPolicy = policy; 1571: } 1572: 1573: /** 1574: * Return the focus traversal policy that determines the focus 1575: * traversal order for this Container's children. This method 1576: * returns null if this Container is not a focus cycle root. If the 1577: * focus traversal policy has not been set explicitly, then this 1578: * method will return an ancestor focus cycle root's policy instead. 1579: * 1580: * @return this Container's focus traversal policy or null 1581: * 1582: * @since 1.4 1583: */ 1584: public FocusTraversalPolicy getFocusTraversalPolicy () 1585: { 1586: if (!isFocusCycleRoot ()) 1587: return null; 1588: 1589: if (focusTraversalPolicy == null) 1590: { 1591: Container ancestor = getFocusCycleRootAncestor (); 1592: 1593: if (ancestor != this && ancestor != null) 1594: return ancestor.getFocusTraversalPolicy (); 1595: else 1596: { 1597: KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); 1598: 1599: return manager.getDefaultFocusTraversalPolicy (); 1600: } 1601: } 1602: else 1603: return focusTraversalPolicy; 1604: } 1605: 1606: /** 1607: * Check whether this Container's focus traversal policy has been 1608: * explicitly set. If it has not, then this Container will inherit 1609: * its focus traversal policy from one of its ancestor focus cycle 1610: * roots. 1611: * 1612: * @return true if focus traversal policy is set, false otherwise 1613: */ 1614: public boolean isFocusTraversalPolicySet () 1615: { 1616: return focusTraversalPolicy == null; 1617: } 1618: 1619: /** 1620: * Set whether or not this Container is the root of a focus 1621: * traversal cycle. This Container's focus traversal policy 1622: * determines the order of focus traversal. Some policies prevent 1623: * the focus from being transferred between two traversal cycles 1624: * until an up or down traversal operation is performed. In that 1625: * case, normal traversal (not up or down) is limited to this 1626: * Container and all of this Container's descendents that are not 1627: * descendents of inferior focus cycle roots. In the default case 1628: * however, ContainerOrderFocusTraversalPolicy is in effect, and it 1629: * supports implicit down-cycle traversal operations. 1630: * 1631: * @param focusCycleRoot true if this is a focus cycle root, false otherwise 1632: * 1633: * @since 1.4 1634: */ 1635: public void setFocusCycleRoot (boolean focusCycleRoot) 1636: { 1637: this.focusCycleRoot = focusCycleRoot; 1638: } 1639: 1640: /** 1641: * Set to <code>true</code> if this container provides a focus traversal 1642: * policy, <code>false</code> when the root container's focus 1643: * traversal policy should be used. 1644: * 1645: * @return <code>true</code> if this container provides a focus traversal 1646: * policy, <code>false</code> when the root container's focus 1647: * traversal policy should be used 1648: * 1649: * @see #setFocusTraversalPolicyProvider(boolean) 1650: * 1651: * @since 1.5 1652: */ 1653: public final boolean isFocusTraversalPolicyProvider() 1654: { 1655: return focusTraversalPolicyProvider; 1656: } 1657: 1658: /** 1659: * Set to <code>true</code> if this container provides a focus traversal 1660: * policy, <code>false</code> when the root container's focus 1661: * traversal policy should be used. 1662: * 1663: * @param b <code>true</code> if this container provides a focus traversal 1664: * policy, <code>false</code> when the root container's focus 1665: * traversal policy should be used 1666: * 1667: * @see #isFocusTraversalPolicyProvider() 1668: * 1669: * @since 1.5 1670: */ 1671: public final void setFocusTraversalPolicyProvider(boolean b) 1672: { 1673: focusTraversalPolicyProvider = b; 1674: } 1675: 1676: /** 1677: * Check whether this Container is a focus cycle root. 1678: * 1679: * @return true if this is a focus cycle root, false otherwise 1680: * 1681: * @since 1.4 1682: */ 1683: public boolean isFocusCycleRoot () 1684: { 1685: return focusCycleRoot; 1686: } 1687: 1688: /** 1689: * Transfer focus down one focus traversal cycle. If this Container 1690: * is a focus cycle root, then its default component becomes the 1691: * focus owner, and this Container becomes the current focus cycle 1692: * root. No traversal will occur if this Container is not a focus 1693: * cycle root. 1694: * 1695: * @since 1.4 1696: */ 1697: public void transferFocusDownCycle () 1698: { 1699: if (isFocusCycleRoot()) 1700: { 1701: KeyboardFocusManager fm = 1702: KeyboardFocusManager.getCurrentKeyboardFocusManager(); 1703: fm.setGlobalCurrentFocusCycleRoot(this); 1704: FocusTraversalPolicy policy = getFocusTraversalPolicy(); 1705: Component defaultComponent = policy.getDefaultComponent(this); 1706: if (defaultComponent != null) 1707: defaultComponent.requestFocus(); 1708: } 1709: } 1710: 1711: /** 1712: * Sets the ComponentOrientation property of this container and all components 1713: * contained within it. 1714: * 1715: * @exception NullPointerException If orientation is null 1716: * 1717: * @since 1.4 1718: */ 1719: public void applyComponentOrientation (ComponentOrientation orientation) 1720: { 1721: if (orientation == null) 1722: throw new NullPointerException(); 1723: 1724: setComponentOrientation(orientation); 1725: for (int i = 0; i < ncomponents; i++) 1726: { 1727: if (component[i] instanceof Container) 1728: ((Container) component[i]).applyComponentOrientation(orientation); 1729: else 1730: component[i].setComponentOrientation(orientation); 1731: } 1732: } 1733: 1734: public void addPropertyChangeListener (PropertyChangeListener listener) 1735: { 1736: // TODO: Why is this overridden? 1737: super.addPropertyChangeListener(listener); 1738: } 1739: 1740: public void addPropertyChangeListener (String propertyName, 1741: PropertyChangeListener listener) 1742: { 1743: // TODO: Why is this overridden? 1744: super.addPropertyChangeListener(propertyName, listener); 1745: } 1746: 1747: 1748: /** 1749: * Sets the Z ordering for the component <code>comp</code> to 1750: * <code>index</code>. Components with lower Z order paint above components 1751: * with higher Z order. 1752: * 1753: * @param comp the component for which to change the Z ordering 1754: * @param index the index to set 1755: * 1756: * @throws NullPointerException if <code>comp == null</code> 1757: * @throws IllegalArgumentException if comp is an ancestor of this container 1758: * @throws IllegalArgumentException if <code>index</code> is not in 1759: * <code>[0, getComponentCount()]</code> for moving between 1760: * containers or <code>[0, getComponentCount() - 1]</code> for moving 1761: * inside this container 1762: * @throws IllegalArgumentException if <code>comp == this</code> 1763: * @throws IllegalArgumentException if <code>comp</code> is a 1764: * <code>Window</code> 1765: * 1766: * @see #getComponentZOrder(Component) 1767: * 1768: * @since 1.5 1769: */ 1770: public final void setComponentZOrder(Component comp, int index) 1771: { 1772: if (comp == null) 1773: throw new NullPointerException("comp must not be null"); 1774: if (comp instanceof Container && ((Container) comp).isAncestorOf(this)) 1775: throw new IllegalArgumentException("comp must not be an ancestor of " 1776: + "this"); 1777: if (comp instanceof Window) 1778: throw new IllegalArgumentException("comp must not be a Window"); 1779: 1780: if (comp == this) 1781: throw new IllegalArgumentException("cannot add component to itself"); 1782: 1783: synchronized (getTreeLock()) 1784: { 1785: // FIXME: Implement reparenting. 1786: if ( comp.getParent() != this) 1787: throw new AssertionError("Reparenting is not implemented yet"); 1788: else 1789: { 1790: // Find current component index. 1791: int currentIndex = getComponentZOrder(comp); 1792: if (currentIndex < index) 1793: { 1794: System.arraycopy(component, currentIndex + 1, component, 1795: currentIndex, index - currentIndex); 1796: } 1797: else 1798: { 1799: System.arraycopy(component, index, component, index + 1, 1800: currentIndex - index); 1801: } 1802: component[index] = comp; 1803: } 1804: } 1805: } 1806: 1807: /** 1808: * Returns the Z ordering index of <code>comp</code>. If <code>comp</code> 1809: * is not a child component of this Container, this returns <code>-1</code>. 1810: * 1811: * @param comp the component for which to query the Z ordering 1812: * 1813: * @return the Z ordering index of <code>comp</code> or <code>-1</code> if 1814: * <code>comp</code> is not a child of this Container 1815: * 1816: * @see #setComponentZOrder(Component, int) 1817: * 1818: * @since 1.5 1819: */ 1820: public final int getComponentZOrder(Component comp) 1821: { 1822: synchronized (getTreeLock()) 1823: { 1824: int index = -1; 1825: if (component != null) 1826: { 1827: for (int i = 0; i < ncomponents; i++) 1828: { 1829: if (component[i] == comp) 1830: { 1831: index = i; 1832: break; 1833: } 1834: } 1835: } 1836: return index; 1837: } 1838: } 1839: 1840: // Hidden helper methods. 1841: 1842: /** 1843: * Perform a graphics operation on the children of this container. 1844: * For each applicable child, the visitChild() method will be called 1845: * to perform the graphics operation. 1846: * 1847: * @param gfx The graphics object that will be used to derive new 1848: * graphics objects for the children. 1849: * 1850: * @param visitor Object encapsulating the graphics operation that 1851: * should be performed. 1852: * 1853: * @param lightweightOnly If true, only lightweight components will 1854: * be visited. 1855: */ 1856: private void visitChildren(Graphics gfx, GfxVisitor visitor, 1857: boolean lightweightOnly) 1858: { 1859: synchronized (getTreeLock()) 1860: { 1861: for (int i = ncomponents - 1; i >= 0; --i) 1862: { 1863: Component comp = component[i]; 1864: boolean applicable = comp.isVisible() 1865: && (comp.isLightweight() || ! lightweightOnly); 1866: 1867: if (applicable) 1868: visitChild(gfx, visitor, comp); 1869: } 1870: } 1871: } 1872: 1873: /** 1874: * Perform a graphics operation on a child. A translated and clipped 1875: * graphics object will be created, and the visit() method of the 1876: * visitor will be called to perform the operation. 1877: * 1878: * @param gfx The graphics object that will be used to derive new 1879: * graphics objects for the child. 1880: * 1881: * @param visitor Object encapsulating the graphics operation that 1882: * should be performed. 1883: * 1884: * @param comp The child component that should be visited. 1885: */ 1886: private void visitChild(Graphics gfx, GfxVisitor visitor, 1887: Component comp) 1888: { 1889: Rectangle bounds = comp.getBounds(); 1890: 1891: if(!gfx.hitClip(bounds.x,bounds.y, bounds.width, bounds.height)) 1892: return; 1893: Graphics g2 = gfx.create(bounds.x, bounds.y, bounds.width, 1894: bounds.height); 1895: try 1896: { 1897: g2.setFont(comp.getFont()); 1898: visitor.visit(comp, g2); 1899: } 1900: finally 1901: { 1902: g2.dispose(); 1903: } 1904: } 1905: 1906: /** 1907: * Overridden to dispatch events to lightweight descendents. 1908: * 1909: * @param e the event to dispatch. 1910: */ 1911: void dispatchEventImpl(AWTEvent e) 1912: { 1913: LightweightDispatcher dispatcher = LightweightDispatcher.getInstance(); 1914: if (! isLightweight() && dispatcher.dispatchEvent(e)) 1915: { 1916: // Some lightweight descendent got this event dispatched. Consume 1917: // it and let the peer handle it. 1918: e.consume(); 1919: ComponentPeer p = peer; 1920: if (p != null) 1921: p.handleEvent(e); 1922: } 1923: else 1924: { 1925: super.dispatchEventImpl(e); 1926: } 1927: } 1928: 1929: /** 1930: * This is called by the lightweight dispatcher to avoid recursivly 1931: * calling into the lightweight dispatcher. 1932: * 1933: * @param e the event to dispatch 1934: * 1935: * @see LightweightDispatcher#redispatch(MouseEvent, Component, int) 1936: */ 1937: void dispatchNoLightweight(AWTEvent e) 1938: { 1939: super.dispatchEventImpl(e); 1940: } 1941: 1942: /** 1943: * Tests if this container has an interest in the given event id. 1944: * 1945: * @param eventId The event id to check. 1946: * 1947: * @return <code>true</code> if a listener for the event id exists or 1948: * if the eventMask is set for the event id. 1949: * 1950: * @see java.awt.Component#eventTypeEnabled(int) 1951: */ 1952: boolean eventTypeEnabled(int eventId) 1953: { 1954: if(eventId <= ContainerEvent.CONTAINER_LAST 1955: && eventId >= ContainerEvent.CONTAINER_FIRST) 1956: return containerListener != null 1957: || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0; 1958: else 1959: return super.eventTypeEnabled(eventId); 1960: } 1961: 1962: // This is used to implement Component.transferFocus. 1963: Component findNextFocusComponent(Component child) 1964: { 1965: synchronized (getTreeLock ()) 1966: { 1967: int start, end; 1968: if (child != null) 1969: { 1970: for (start = 0; start < ncomponents; ++start) 1971: { 1972: if (component[start] == child) 1973: break; 1974: } 1975: end = start; 1976: // This special case lets us be sure to terminate. 1977: if (end == 0) 1978: end = ncomponents; 1979: ++start; 1980: } 1981: else 1982: { 1983: start = 0; 1984: end = ncomponents; 1985: } 1986: 1987: for (int j = start; j != end; ++j) 1988: { 1989: if (j >= ncomponents) 1990: { 1991: // The JCL says that we should wrap here. However, that 1992: // seems wrong. To me it seems that focus order should be 1993: // global within in given window. So instead if we reach 1994: // the end we try to look in our parent, if we have one. 1995: if (parent != null) 1996: return parent.findNextFocusComponent(this); 1997: j -= ncomponents; 1998: } 1999: if (component[j] instanceof Container) 2000: { 2001: Component c = component[j]; 2002: c = c.findNextFocusComponent(null); 2003: if (c != null) 2004: return c; 2005: } 2006: else if (component[j].isFocusTraversable()) 2007: return component[j]; 2008: } 2009: 2010: return null; 2011: } 2012: } 2013: 2014: /** 2015: * Fires hierarchy events to the children of this container and this 2016: * container itself. This overrides {@link Component#fireHierarchyEvent} 2017: * in order to forward this event to all children. 2018: */ 2019: void fireHierarchyEvent(int id, Component changed, Container parent, 2020: long flags) 2021: { 2022: // Only propagate event if there is actually a listener waiting for it. 2023: if ((id == HierarchyEvent.HIERARCHY_CHANGED && numHierarchyListeners > 0) 2024: || ((id == HierarchyEvent.ANCESTOR_MOVED 2025: || id == HierarchyEvent.ANCESTOR_RESIZED) 2026: && numHierarchyBoundsListeners > 0)) 2027: { 2028: for (int i = 0; i < ncomponents; i++) 2029: component[i].fireHierarchyEvent(id, changed, parent, flags); 2030: super.fireHierarchyEvent(id, changed, parent, flags); 2031: } 2032: } 2033: 2034: /** 2035: * Adjusts the number of hierarchy listeners of this container and all of 2036: * its parents. This is called by the add/remove listener methods and 2037: * structure changing methods in Container. 2038: * 2039: * @param type the type, either {@link AWTEvent#HIERARCHY_BOUNDS_EVENT_MASK} 2040: * or {@link AWTEvent#HIERARCHY_EVENT_MASK} 2041: * @param delta the number of listeners added or removed 2042: */ 2043: void updateHierarchyListenerCount(long type, int delta) 2044: { 2045: if (type == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) 2046: numHierarchyBoundsListeners += delta; 2047: else if (type == AWTEvent.HIERARCHY_EVENT_MASK) 2048: numHierarchyListeners += delta; 2049: else 2050: assert false : "Should not reach here"; 2051: 2052: if (parent != null) 2053: parent.updateHierarchyListenerCount(type, delta); 2054: } 2055: 2056: /** 2057: * Notifies interested listeners about resizing or moving the container. 2058: * This performs the super behaviour (sending component events) and 2059: * additionally notifies any hierarchy bounds listeners on child components. 2060: * 2061: * @param resized true if the component has been resized, false otherwise 2062: * @param moved true if the component has been moved, false otherwise 2063: */ 2064: void notifyReshape(boolean resized, boolean moved) 2065: { 2066: // Notify component listeners. 2067: super.notifyReshape(resized, moved); 2068: 2069: if (ncomponents > 0) 2070: { 2071: // Notify hierarchy bounds listeners. 2072: if (resized) 2073: { 2074: for (int i = 0; i < getComponentCount(); i++) 2075: { 2076: Component child = getComponent(i); 2077: child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, 2078: this, parent, 0); 2079: } 2080: } 2081: if (moved) 2082: { 2083: for (int i = 0; i < getComponentCount(); i++) 2084: { 2085: Component child = getComponent(i); 2086: child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, 2087: this, parent, 0); 2088: } 2089: } 2090: } 2091: } 2092: 2093: private void addNotifyContainerChildren() 2094: { 2095: synchronized (getTreeLock ()) 2096: { 2097: for (int i = ncomponents; --i >= 0; ) 2098: { 2099: component[i].addNotify(); 2100: } 2101: } 2102: } 2103: 2104: /** 2105: * Deserialize this Container: 2106: * <ol> 2107: * <li>Read from the stream the default serializable fields.</li> 2108: * <li>Read a list of serializable ContainerListeners as optional 2109: * data. If the list is null, no listeners will be registered.</li> 2110: * <li>Read this Container's FocusTraversalPolicy as optional data. 2111: * If this is null, then this Container will use a 2112: * DefaultFocusTraversalPolicy.</li> 2113: * </ol> 2114: * 2115: * @param s the stream to read from 2116: * @throws ClassNotFoundException if deserialization fails 2117: * @throws IOException if the stream fails 2118: */ 2119: private void readObject (ObjectInputStream s) 2120: throws ClassNotFoundException, IOException 2121: { 2122: s.defaultReadObject (); 2123: String key = (String) s.readObject (); 2124: while (key != null) 2125: { 2126: Object object = s.readObject (); 2127: if ("containerL".equals (key)) 2128: addContainerListener((ContainerListener) object); 2129: // FIXME: under what key is the focus traversal policy stored? 2130: else if ("focusTraversalPolicy".equals (key)) 2131: setFocusTraversalPolicy ((FocusTraversalPolicy) object); 2132: 2133: key = (String) s.readObject(); 2134: } 2135: } 2136: 2137: /** 2138: * Serialize this Container: 2139: * <ol> 2140: * <li>Write to the stream the default serializable fields.</li> 2141: * <li>Write the list of serializable ContainerListeners as optional 2142: * data.</li> 2143: * <li>Write this Container's FocusTraversalPolicy as optional data.</li> 2144: * </ol> 2145: * 2146: * @param s the stream to write to 2147: * @throws IOException if the stream fails 2148: */ 2149: private void writeObject (ObjectOutputStream s) throws IOException 2150: { 2151: s.defaultWriteObject (); 2152: AWTEventMulticaster.save (s, "containerL", containerListener); 2153: if (focusTraversalPolicy instanceof Serializable) 2154: s.writeObject (focusTraversalPolicy); 2155: else 2156: s.writeObject (null); 2157: } 2158: 2159: // Nested classes. 2160: 2161: /* The following classes are used in concert with the 2162: visitChildren() method to implement all the graphics operations 2163: that requires traversal of the containment hierarchy. */ 2164: 2165: abstract static class GfxVisitor 2166: { 2167: public abstract void visit(Component c, Graphics gfx); 2168: } 2169: 2170: static class GfxPaintVisitor extends GfxVisitor 2171: { 2172: public static final GfxVisitor INSTANCE = new GfxPaintVisitor(); 2173: 2174: public void visit(Component c, Graphics gfx) 2175: { 2176: c.paint(gfx); 2177: } 2178: } 2179: 2180: static class GfxPrintVisitor extends GfxVisitor 2181: { 2182: public static final GfxVisitor INSTANCE = new GfxPrintVisitor(); 2183: 2184: public void visit(Component c, Graphics gfx) 2185: { 2186: c.print(gfx); 2187: } 2188: } 2189: 2190: static class GfxPaintAllVisitor extends GfxVisitor 2191: { 2192: public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor(); 2193: 2194: public void visit(Component c, Graphics gfx) 2195: { 2196: c.paintAll(gfx); 2197: } 2198: } 2199: 2200: static class GfxPrintAllVisitor extends GfxVisitor 2201: { 2202: public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor(); 2203: 2204: public void visit(Component c, Graphics gfx) 2205: { 2206: c.printAll(gfx); 2207: } 2208: } 2209: 2210: /** 2211: * This class provides accessibility support for subclasses of container. 2212: * 2213: * @author Eric Blake (ebb9@email.byu.edu) 2214: * 2215: * @since 1.3 2216: */ 2217: protected class AccessibleAWTContainer extends AccessibleAWTComponent 2218: { 2219: /** 2220: * Compatible with JDK 1.4+. 2221: */ 2222: private static final long serialVersionUID = 5081320404842566097L; 2223: 2224: /** 2225: * The handler to fire PropertyChange when children are added or removed. 2226: * 2227: * @serial the handler for property changes 2228: */ 2229: protected ContainerListener accessibleContainerHandler 2230: = new AccessibleContainerHandler(); 2231: 2232: /** 2233: * The default constructor. 2234: */ 2235: protected AccessibleAWTContainer() 2236: { 2237: Container.this.addContainerListener(accessibleContainerHandler); 2238: } 2239: 2240: /** 2241: * Return the number of accessible children of the containing accessible 2242: * object (at most the total number of its children). 2243: * 2244: * @return the number of accessible children 2245: */ 2246: public int getAccessibleChildrenCount() 2247: { 2248: synchronized (getTreeLock ()) 2249: { 2250: int count = 0; 2251: int i = component == null ? 0 : component.length; 2252: while (--i >= 0) 2253: if (component[i] instanceof Accessible) 2254: count++; 2255: return count; 2256: } 2257: } 2258: 2259: /** 2260: * Return the nth accessible child of the containing accessible object. 2261: * 2262: * @param i the child to grab, zero-based 2263: * @return the accessible child, or null 2264: */ 2265: public Accessible getAccessibleChild(int i) 2266: { 2267: synchronized (getTreeLock ()) 2268: { 2269: if (component == null) 2270: return null; 2271: int index = -1; 2272: while (i >= 0 && ++index < component.length) 2273: if (component[index] instanceof Accessible) 2274: i--; 2275: if (i < 0) 2276: return (Accessible) component[index]; 2277: return null; 2278: } 2279: } 2280: 2281: /** 2282: * Return the accessible child located at point (in the parent's 2283: * coordinates), if one exists. 2284: * 2285: * @param p the point to look at 2286: * 2287: * @return an accessible object at that point, or null 2288: * 2289: * @throws NullPointerException if p is null 2290: */ 2291: public Accessible getAccessibleAt(Point p) 2292: { 2293: Component c = getComponentAt(p.x, p.y); 2294: return c != Container.this && c instanceof Accessible ? (Accessible) c 2295: : null; 2296: } 2297: 2298: /** 2299: * This class fires a <code>PropertyChange</code> listener, if registered, 2300: * when children are added or removed from the enclosing accessible object. 2301: * 2302: * @author Eric Blake (ebb9@email.byu.edu) 2303: * 2304: * @since 1.3 2305: */ 2306: protected class AccessibleContainerHandler implements ContainerListener 2307: { 2308: /** 2309: * Default constructor. 2310: */ 2311: protected AccessibleContainerHandler() 2312: { 2313: // Nothing to do here. 2314: } 2315: 2316: /** 2317: * Fired when a component is added; forwards to the PropertyChange 2318: * listener. 2319: * 2320: * @param e the container event for adding 2321: */ 2322: public void componentAdded(ContainerEvent e) 2323: { 2324: AccessibleAWTContainer.this.firePropertyChange 2325: (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild()); 2326: } 2327: 2328: /** 2329: * Fired when a component is removed; forwards to the PropertyChange 2330: * listener. 2331: * 2332: * @param e the container event for removing 2333: */ 2334: public void componentRemoved(ContainerEvent e) 2335: { 2336: AccessibleAWTContainer.this.firePropertyChange 2337: (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null); 2338: } 2339: } // class AccessibleContainerHandler 2340: } // class AccessibleAWTContainer 2341: } // class Container
GNU Classpath (0.95) |