| 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: