Source for java.awt.Container

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