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