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