001    /* Container.java -- parent container class in AWT
002       Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006
003       Free Software Foundation
004    
005    This file is part of GNU Classpath.
006    
007    GNU Classpath is free software; you can redistribute it and/or modify
008    it under the terms of the GNU General Public License as published by
009    the Free Software Foundation; either version 2, or (at your option)
010    any later version.
011    
012    GNU Classpath is distributed in the hope that it will be useful, but
013    WITHOUT ANY WARRANTY; without even the implied warranty of
014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015    General Public License for more details.
016    
017    You should have received a copy of the GNU General Public License
018    along with GNU Classpath; see the file COPYING.  If not, write to the
019    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020    02110-1301 USA.
021    
022    Linking this library statically or dynamically with other modules is
023    making a combined work based on this library.  Thus, the terms and
024    conditions of the GNU General Public License cover the whole
025    combination.
026    
027    As a special exception, the copyright holders of this library give you
028    permission to link this library with independent modules to produce an
029    executable, regardless of the license terms of these independent
030    modules, and to copy and distribute the resulting executable under
031    terms of your choice, provided that you also meet, for each linked
032    independent module, the terms and conditions of the license of that
033    module.  An independent module is a module which is not derived from
034    or based on this library.  If you modify this library, you may extend
035    this exception to your version of the library, but you are not
036    obligated to do so.  If you do not wish to do so, delete this
037    exception statement from your version. */
038    
039    
040    package java.awt;
041    
042    import gnu.java.lang.CPStringBuilder;
043    
044    import java.awt.event.ContainerEvent;
045    import java.awt.event.ContainerListener;
046    import java.awt.event.HierarchyEvent;
047    import java.awt.event.KeyEvent;
048    import java.awt.event.MouseEvent;
049    import java.awt.peer.ComponentPeer;
050    import java.awt.peer.ContainerPeer;
051    import java.awt.peer.LightweightPeer;
052    import java.beans.PropertyChangeListener;
053    import java.io.IOException;
054    import java.io.ObjectInputStream;
055    import java.io.ObjectOutputStream;
056    import java.io.PrintStream;
057    import java.io.PrintWriter;
058    import java.io.Serializable;
059    import java.util.Collections;
060    import java.util.EventListener;
061    import java.util.HashSet;
062    import java.util.Iterator;
063    import java.util.Set;
064    
065    import 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     */
080    public 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