1 /* Container.java -- parent container class in AWT
2    Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006
3    Free Software Foundation
4 
5 This file is part of GNU Classpath.
6 
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11 
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21 
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26 
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38 
39 
40 package java.awt;
41 
42 import gnu.java.lang.CPStringBuilder;
43 
44 import java.awt.event.ContainerEvent;
45 import java.awt.event.ContainerListener;
46 import java.awt.event.HierarchyEvent;
47 import java.awt.event.KeyEvent;
48 import java.awt.event.MouseEvent;
49 import java.awt.peer.ComponentPeer;
50 import java.awt.peer.ContainerPeer;
51 import java.awt.peer.LightweightPeer;
52 import java.beans.PropertyChangeListener;
53 import java.io.IOException;
54 import java.io.ObjectInputStream;
55 import java.io.ObjectOutputStream;
56 import java.io.PrintStream;
57 import java.io.PrintWriter;
58 import java.io.Serializable;
59 import java.util.Collections;
60 import java.util.EventListener;
61 import java.util.HashSet;
62 import java.util.Iterator;
63 import java.util.Set;
64 
65 import javax.accessibility.Accessible;
66 
67 /**
68  * A generic window toolkit object that acts as a container for other objects.
69  * Components are tracked in a list, and new elements are at the end of the
70  * list or bottom of the stacking order.
71  *
72  * @author original author unknown
73  * @author Eric Blake (ebb9@email.byu.edu)
74  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
75  *
76  * @since 1.0
77  *
78  * @status still missing 1.4 support, some generics from 1.5
79  */
80 public class Container extends Component
81 {
82   /**
83    * Compatible with JDK 1.0+.
84    */
85   private static final long serialVersionUID = 4613797578919906343L;
86 
87   /* Serialized fields from the serialization spec. */
88   int ncomponents;
89   Component[] component;
90   LayoutManager layoutMgr;
91 
92   /**
93    * @since 1.4
94    */
95   boolean focusCycleRoot;
96 
97   /**
98    * Indicates if this container provides a focus traversal policy.
99    *
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    */
Container()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    */
getComponentCount()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    */
countComponents()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    */
getComponent(int n)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    */
getComponents()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    */
getInsets()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    */
insets()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    */
add(Component comp)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    */
add(String name, Component comp)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    */
add(Component comp, int index)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    */
add(Component comp, Object constraints)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    */
add(Component comp, Object constraints, int index)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    */
addImpl(Component comp, Object constraints, int index)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    */
remove(int index)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    */
remove(Component comp)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    */
removeAll()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    */
getLayout()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    */
setLayout(LayoutManager mgr)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    */
doLayout()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    */
layout()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    */
invalidate()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    */
validate()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    */
invalidateTree()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    */
validateTree()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 
setFont(Font f)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    */
getPreferredSize()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    */
preferredSize()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    */
getMinimumSize()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    */
minimumSize()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    */
getMaximumSize()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    */
getAlignmentX()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    */
getAlignmentY()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    */
paint(Graphics g)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    */
update(Graphics g)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    */
print(Graphics g)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    */
paintComponents(Graphics g)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    */
printComponents(Graphics g)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    */
addContainerListener(ContainerListener listener)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    */
removeContainerListener(ContainerListener listener)977   public synchronized void removeContainerListener(ContainerListener listener)
978   {
979     containerListener = AWTEventMulticaster.remove(containerListener, listener);
980   }
981 
982   /**
983    * @since 1.4
984    */
getContainerListeners()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    */
getListeners(Class<T> listenerType)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    */
processEvent(AWTEvent e)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    */
processContainerEvent(ContainerEvent e)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    */
deliverEvent(Event e)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    */
getComponentAt(int x, int y)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    */
getMousePosition(boolean allowChildren)1116   public Point getMousePosition(boolean allowChildren) throws HeadlessException
1117   {
1118     return super.getMousePositionHelper(allowChildren);
1119   }
1120 
mouseOverComponent(Component component, boolean allowChildren)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    */
locate(int x, int y)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    */
getComponentAt(Point p)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    */
findComponentAt(int x, int y)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    */
findComponentAt(Point p)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    */
addNotify()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    */
removeNotify()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    */
isAncestorOf(Component comp)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    */
paramString()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    */
list(PrintStream out, int indent)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    */
list(PrintWriter out, int indent)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    */
setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes)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    */
getFocusTraversalKeys(int id)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    */
areFocusTraversalKeysSet(int id)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    */
isFocusCycleRoot(Container c)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    */
setFocusTraversalPolicy(FocusTraversalPolicy policy)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    */
getFocusTraversalPolicy()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   */
isFocusTraversalPolicySet()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    */
setFocusCycleRoot(boolean focusCycleRoot)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    */
isFocusTraversalPolicyProvider()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    */
setFocusTraversalPolicyProvider(boolean b)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    */
isFocusCycleRoot()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    */
transferFocusDownCycle()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    */
applyComponentOrientation(ComponentOrientation orientation)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 
addPropertyChangeListener(PropertyChangeListener listener)1763   public void addPropertyChangeListener (PropertyChangeListener listener)
1764   {
1765     // TODO: Why is this overridden?
1766     super.addPropertyChangeListener(listener);
1767   }
1768 
addPropertyChangeListener(String propertyName, PropertyChangeListener listener)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    */
setComponentZOrder(Component comp, int index)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    */
getComponentZOrder(Component comp)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    */
visitChildren(Graphics gfx, GfxVisitor visitor, boolean lightweightOnly)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    */
visitChild(Graphics gfx, GfxVisitor visitor, Component comp)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    */
dispatchEventImpl(AWTEvent e)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    */
dispatchNoLightweight(AWTEvent e)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    */
eventTypeEnabled(int eventId)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.
findNextFocusComponent(Component child)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    */
fireHierarchyEvent(int id, Component changed, Container parent, long flags)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    */
updateHierarchyListenerCount(long type, int delta)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    */
notifyReshape(boolean resized, boolean moved)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 
addNotifyContainerChildren()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    */
readObject(ObjectInputStream s)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    */
writeObject(ObjectOutputStream s)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   {
visit(Component c, Graphics gfx)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 
visit(Component c, Graphics gfx)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 
visit(Component c, Graphics gfx)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 
visit(Component c, Graphics gfx)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 
visit(Component c, Graphics gfx)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      */
AccessibleAWTContainer()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      */
getAccessibleChildrenCount()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      */
getAccessibleChild(int i)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      */
getAccessibleAt(Point p)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        */
AccessibleContainerHandler()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        */
componentAdded(ContainerEvent e)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        */
componentRemoved(ContainerEvent e)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
2371