Source for java.awt.Container

   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