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