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