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