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