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