Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: java/awt/Container.java


1   /* Container.java -- parent container class in AWT
2      Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005  Free Software Foundation
3   
4   This file is part of GNU Classpath.
5   
6   GNU Classpath is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10  
11  GNU Classpath is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15  
16  You should have received a copy of the GNU General Public License
17  along with GNU Classpath; see the file COPYING.  If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301 USA.
20  
21  Linking this library statically or dynamically with other modules is
22  making a combined work based on this library.  Thus, the terms and
23  conditions of the GNU General Public License cover the whole
24  combination.
25  
26  As a special exception, the copyright holders of this library give you
27  permission to link this library with independent modules to produce an
28  executable, regardless of the license terms of these independent
29  modules, and to copy and distribute the resulting executable under
30  terms of your choice, provided that you also meet, for each linked
31  independent module, the terms and conditions of the license of that
32  module.  An independent module is a module which is not derived from
33  or based on this library.  If you modify this library, you may extend
34  this exception to your version of the library, but you are not
35  obligated to do so.  If you do not wish to do so, delete this
36  exception statement from your version. */
37  
38  
39  package java.awt;
40  
41  import java.awt.event.ContainerEvent;
42  import java.awt.event.ContainerListener;
43  import java.awt.event.KeyEvent;
44  import java.awt.event.MouseEvent;
45  import java.awt.peer.ComponentPeer;
46  import java.awt.peer.ContainerPeer;
47  import java.awt.peer.LightweightPeer;
48  import java.beans.PropertyChangeListener;
49  import java.beans.PropertyChangeSupport;
50  import java.io.IOException;
51  import java.io.ObjectInputStream;
52  import java.io.ObjectOutputStream;
53  import java.io.PrintStream;
54  import java.io.PrintWriter;
55  import java.io.Serializable;
56  import java.util.Collections;
57  import java.util.EventListener;
58  import java.util.HashSet;
59  import java.util.Iterator;
60  import java.util.Set;
61  
62  import javax.accessibility.Accessible;
63  
64  import gnu.java.awt.AWTUtilities;
65  
66  /**
67   * A generic window toolkit object that acts as a container for other objects.
68   * Components are tracked in a list, and new elements are at the end of the
69   * list or bottom of the stacking order.
70   *
71   * @author original author unknown
72   * @author Eric Blake (ebb9@email.byu.edu)
73   *
74   * @since 1.0
75   *
76   * @status still missing 1.4 support
77   */
78  public class Container extends Component
79  {
80    /**
81     * Compatible with JDK 1.0+.
82     */
83    private static final long serialVersionUID = 4613797578919906343L;
84  
85    /* Serialized fields from the serialization spec. */
86    int ncomponents;
87    Component[] component;
88    LayoutManager layoutMgr;
89  
90    LightweightDispatcher dispatcher;
91  
92    Dimension maxSize;
93  
94    /**
95     * @since 1.4
96     */
97    boolean focusCycleRoot;
98  
99    int containerSerializedDataVersion;
100 
101   /* Anything else is non-serializable, and should be declared "transient". */
102   transient ContainerListener containerListener;
103   transient PropertyChangeSupport changeSupport; 
104 
105   /** The focus traversal policy that determines how focus is
106       transferred between this Container and its children. */
107   private FocusTraversalPolicy focusTraversalPolicy;
108 
109   /**
110    * The focus traversal keys, if not inherited from the parent or default
111    * keyboard manager. These sets will contain only AWTKeyStrokes that
112    * represent press and release events to use as focus control.
113    *
114    * @see #getFocusTraversalKeys(int)
115    * @see #setFocusTraversalKeys(int, Set)
116    * @since 1.4
117    */
118   transient Set[] focusTraversalKeys;
119 
120   /**
121    * Default constructor for subclasses.
122    */
123   public Container()
124   {
125   }
126 
127   /**
128    * Returns the number of components in this container.
129    *
130    * @return The number of components in this container.
131    */
132   public int getComponentCount()
133   {
134     return countComponents ();
135   }
136 
137   /**
138    * Returns the number of components in this container.
139    *
140    * @return The number of components in this container.
141    *
142    * @deprecated use {@link #getComponentCount()} instead
143    */
144   public int countComponents()
145   {
146     return ncomponents;
147   }
148 
149   /**
150    * Returns the component at the specified index.
151    *
152    * @param n The index of the component to retrieve.
153    *
154    * @return The requested component.
155    *
156    * @throws ArrayIndexOutOfBoundsException If the specified index is invalid
157    */
158   public Component getComponent(int n)
159   {
160     synchronized (getTreeLock ())
161       {
162         if (n < 0 || n >= ncomponents)
163           throw new ArrayIndexOutOfBoundsException("no such component");
164 
165         return component[n];
166       }
167   }
168 
169   /**
170    * Returns an array of the components in this container.
171    *
172    * @return The components in this container.
173    */
174   public Component[] getComponents()
175   {
176     synchronized (getTreeLock ())
177       {
178         Component[] result = new Component[ncomponents];
179 
180         if (ncomponents > 0)
181           System.arraycopy(component, 0, result, 0, ncomponents);
182 
183         return result;
184       }
185   }
186 
187   /**
188    * Swaps the components at position i and j, in the container.
189    */
190 
191   protected void swapComponents (int i, int j)
192   {   
193     synchronized (getTreeLock ())
194       {
195         if (i < 0 
196             || i >= component.length
197             || j < 0 
198             || j >= component.length)
199           throw new ArrayIndexOutOfBoundsException ();
200         Component tmp = component[i];
201         component[i] = component[j];
202         component[j] = tmp;
203       }
204   }
205 
206   /**
207    * Returns the insets for this container, which is the space used for
208    * borders, the margin, etc.
209    *
210    * @return The insets for this container.
211    */
212   public Insets getInsets()
213   {
214     return insets ();
215   }
216 
217   /**
218    * Returns the insets for this container, which is the space used for
219    * borders, the margin, etc.
220    *
221    * @return The insets for this container.
222    * @deprecated use {@link #getInsets()} instead
223    */
224   public Insets insets()
225   {
226     if (peer == null)
227       return new Insets (0, 0, 0, 0);
228 
229     return ((ContainerPeer) peer).getInsets ();
230   }
231 
232   /**
233    * Adds the specified component to this container at the end of the
234    * component list.
235    *
236    * @param comp The component to add to the container.
237    *
238    * @return The same component that was added.
239    */
240   public Component add(Component comp)
241   {
242     addImpl(comp, null, -1);
243     return comp;
244   }
245 
246   /**
247    * Adds the specified component to the container at the end of the
248    * component list.  This method should not be used. Instead, use
249    * <code>add(Component, Object)</code>.
250    *
251    * @param name The name of the component to be added.
252    * @param comp The component to be added.
253    *
254    * @return The same component that was added.
255    *
256    * @see #add(Component,Object)
257    */
258   public Component add(String name, Component comp)
259   {
260     addImpl(comp, name, -1);
261     return comp;
262   }
263 
264   /**
265    * Adds the specified component to this container at the specified index
266    * in the component list.
267    *
268    * @param comp The component to be added.
269    * @param index The index in the component list to insert this child
270    * at, or -1 to add at the end of the list.
271    *
272    * @return The same component that was added.
273    *
274    * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
275    */
276   public Component add(Component comp, int index)
277   {
278     addImpl(comp, null, index);
279     return comp;
280   }
281 
282   /**
283    * Adds the specified component to this container at the end of the
284    * component list.  The layout manager will use the specified constraints
285    * when laying out this component.
286    *
287    * @param comp The component to be added to this container.
288    * @param constraints The layout constraints for this component.
289    */
290   public void add(Component comp, Object constraints)
291   {
292     addImpl(comp, constraints, -1);
293   }
294 
295   /**
296    * Adds the specified component to this container at the specified index
297    * in the component list.  The layout manager will use the specified
298    * constraints when layout out this component.
299    *
300    * @param comp The component to be added.
301    * @param constraints The layout constraints for this component.
302    * @param index The index in the component list to insert this child
303    * at, or -1 to add at the end of the list.
304    *
305    * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
306    */
307   public void add(Component comp, Object constraints, int index)
308   {
309     addImpl(comp, constraints, index);
310   }
311 
312   /**
313    * This method is called by all the <code>add()</code> methods to perform
314    * the actual adding of the component.  Subclasses who wish to perform
315    * their own processing when a component is added should override this
316    * method.  Any subclass doing this must call the superclass version of
317    * this method in order to ensure proper functioning of the container.
318    *
319    * @param comp The component to be added.
320    * @param constraints The layout constraints for this component, or
321    * <code>null</code> if there are no constraints.
322    * @param index The index in the component list to insert this child
323    * at, or -1 to add at the end of the list.
324    *
325    * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
326    */
327   protected void addImpl(Component comp, Object constraints, int index)
328   {
329     synchronized (getTreeLock ())
330       {
331         if (index > ncomponents
332             || (index < 0 && index != -1)
333             || comp instanceof Window
334             || (comp instanceof Container
335                 && ((Container) comp).isAncestorOf(this)))
336           throw new IllegalArgumentException();
337 
338         // Reparent component, and make sure component is instantiated if
339         // we are.
340         if (comp.parent != null)
341           comp.parent.remove(comp);
342         comp.parent = this;
343 
344         if (peer != null)
345           {
346       // Notify the component that it has a new parent.
347       comp.addNotify();
348 
349             if (comp.isLightweight ())
350         {
351     enableEvents (comp.eventMask);
352     if (!isLightweight ())
353       enableEvents (AWTEvent.PAINT_EVENT_MASK);
354         }
355           }
356 
357         // Invalidate the layout of the added component and its ancestors.
358         comp.invalidate();
359 
360         if (component == null)
361           component = new Component[4]; // FIXME, better initial size?
362 
363         // This isn't the most efficient implementation.  We could do less
364         // copying when growing the array.  It probably doesn't matter.
365         if (ncomponents >= component.length)
366           {
367             int nl = component.length * 2;
368             Component[] c = new Component[nl];
369             System.arraycopy(component, 0, c, 0, ncomponents);
370             component = c;
371           }
372   
373         if (index == -1)
374           component[ncomponents++] = comp;
375         else
376           {
377             System.arraycopy(component, index, component, index + 1,
378                              ncomponents - index);
379             component[index] = comp;
380             ++ncomponents;
381           }
382 
383         // Notify the layout manager.
384         if (layoutMgr != null)
385           {
386             if (layoutMgr instanceof LayoutManager2)
387               {
388                 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
389                 lm2.addLayoutComponent(comp, constraints);
390               }
391             else if (constraints instanceof String)
392               layoutMgr.addLayoutComponent((String) constraints, comp);
393             else
394               layoutMgr.addLayoutComponent(null, comp);
395           }
396 
397         if (isShowing ())
398           {
399             // Post event to notify of adding the component.
400             ContainerEvent ce = new ContainerEvent(this,
401                                                    ContainerEvent.COMPONENT_ADDED,
402                                                    comp);
403             getToolkit().getSystemEventQueue().postEvent(ce);
404 
405             // Repaint this container.
406             repaint();
407           }
408       }
409   }
410 
411   /**
412    * Removes the component at the specified index from this container.
413    *
414    * @param index The index of the component to remove.
415    */
416   public void remove(int index)
417   {
418     synchronized (getTreeLock ())
419       {
420         Component r = component[index];
421 
422         r.removeNotify();
423 
424         System.arraycopy(component, index + 1, component, index,
425                          ncomponents - index - 1);
426         component[--ncomponents] = null;
427 
428         invalidate();
429 
430         if (layoutMgr != null)
431           layoutMgr.removeLayoutComponent(r);
432 
433         r.parent = null;
434 
435         if (isShowing ())
436           {
437             // Post event to notify of removing the component.
438             ContainerEvent ce = new ContainerEvent(this,
439                                                    ContainerEvent.COMPONENT_REMOVED,
440                                                    r);
441             getToolkit().getSystemEventQueue().postEvent(ce);
442 
443             // Repaint this container.
444             repaint();
445           }
446       }
447   }
448 
449   /**
450    * Removes the specified component from this container.
451    *
452    * @param comp The component to remove from this container.
453    */
454   public void remove(Component comp)
455   {
456     synchronized (getTreeLock ())
457       {
458         for (int i = 0; i < ncomponents; ++i)
459           {
460             if (component[i] == comp)
461               {
462                 remove(i);
463                 break;
464               }
465           }
466       }
467   }
468 
469   /**
470    * Removes all components from this container.
471    */
472   public void removeAll()
473   {
474     synchronized (getTreeLock ())
475       {
476         while (ncomponents > 0)
477           remove(0);
478       }
479   }
480 
481   /**
482    * Returns the current layout manager for this container.
483    *
484    * @return The layout manager for this container.
485    */
486   public LayoutManager getLayout()
487   {
488     return layoutMgr;
489   }
490 
491   /**
492    * Sets the layout manager for this container to the specified layout
493    * manager.
494    *
495    * @param mgr The new layout manager for this container.
496    */
497   public void setLayout(LayoutManager mgr)
498   {
499     layoutMgr = mgr;
500     invalidate();
501   }
502 
503   /**
504    * Layout the components in this container.
505    */
506   public void doLayout()
507   {
508     layout ();
509   }
510 
511   /**
512    * Layout the components in this container.
513    *
514    * @deprecated use {@link #doLayout()} instead
515    */
516   public void layout()
517   {
518     if (layoutMgr != null)
519       layoutMgr.layoutContainer (this);
520   }
521 
522   /**
523    * Invalidates this container to indicate that it (and all parent
524    * containers) need to be laid out.
525    */
526   public void invalidate()
527   {
528     super.invalidate();
529     if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
530       {
531         LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
532         lm2.invalidateLayout(this);
533       }
534   }
535 
536   /**
537    * Re-lays out the components in this container.
538    */
539   public void validate()
540   {
541     synchronized (getTreeLock ())
542       {
543         if (! isValid() && peer != null)
544           {
545             validateTree();
546           }
547       }
548   }
549 
550   /**
551    * Recursively invalidates the container tree.
552    */
553   void invalidateTree()
554   {
555     super.invalidate();  // Clean cached layout state.
556     for (int i = 0; i < ncomponents; i++)
557       {
558         Component comp = component[i];
559         comp.invalidate();
560         if (comp instanceof Container)
561           ((Container) comp).invalidateTree();
562       }
563 
564     if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
565       {
566         LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
567         lm2.invalidateLayout(this);
568       }
569   }
570 
571   /**
572    * Recursively validates the container tree, recomputing any invalid
573    * layouts.
574    */
575   protected void validateTree()
576   {
577     if (valid)
578       return;
579 
580     ContainerPeer cPeer = null;
581     if (peer != null && ! (peer instanceof LightweightPeer))
582       {
583         cPeer = (ContainerPeer) peer;
584         cPeer.beginValidate();
585       }
586 
587     for (int i = 0; i < ncomponents; ++i)
588       {
589         Component comp = component[i];
590 
591         if (comp.getPeer () == null)
592           comp.addNotify();
593       }
594 
595     doLayout ();
596     for (int i = 0; i < ncomponents; ++i)
597       {
598         Component comp = component[i];
599 
600         if (! comp.isValid())
601           {
602             if (comp instanceof Container)
603               {
604                 ((Container) comp).validateTree();
605               }
606             else
607               {
608                 component[i].validate();
609               }
610           }
611       }
612 
613     /* children will call invalidate() when they are layed out. It
614        is therefore important that valid is not set to true
615        until after the children have been layed out. */
616     valid = true;
617 
618     if (cPeer != null)
619       cPeer.endValidate();
620   }
621 
622   public void setFont(Font f)
623   {
624     if( (f != null && (font == null || !font.equals(f)))
625         || f == null)
626       {
627         super.setFont(f);
628         // FIXME: Although it might make more sense to invalidate only
629         // those children whose font == null, Sun invalidates all children.
630         // So we'll do the same.
631         invalidateTree();
632       }
633   }
634 
635   /**
636    * Returns the preferred size of this container.
637    *
638    * @return The preferred size of this container.
639    */
640   public Dimension getPreferredSize()
641   {
642     return preferredSize ();
643   }
644 
645   /**
646    * Returns the preferred size of this container.
647    *
648    * @return The preferred size of this container.
649    *
650    * @deprecated use {@link #getPreferredSize()} instead
651    */
652   public Dimension preferredSize()
653   {
654     synchronized(treeLock)
655       {  
656         if(valid && prefSize != null)
657           return new Dimension(prefSize);
658         LayoutManager layout = getLayout();
659         if (layout != null)
660           {
661             Dimension layoutSize = layout.preferredLayoutSize(this);
662             if(valid)
663               prefSize = layoutSize;
664             return new Dimension(layoutSize);
665           }
666         else
667           return super.preferredSize ();
668       }
669   }
670 
671   /**
672    * Returns the minimum size of this container.
673    *
674    * @return The minimum size of this container.
675    */
676   public Dimension getMinimumSize()
677   {
678     return minimumSize ();
679   }
680 
681   /**
682    * Returns the minimum size of this container.
683    *
684    * @return The minimum size of this container.
685    *
686    * @deprecated use {@link #getMinimumSize()} instead
687    */
688   public Dimension minimumSize()
689   {
690     if(valid && minSize != null)
691       return new Dimension(minSize);
692 
693     LayoutManager layout = getLayout();
694     if (layout != null)
695       {
696         minSize = layout.minimumLayoutSize (this);
697         return minSize;
698       }    
699     else
700       return super.minimumSize ();
701   }
702 
703   /**
704    * Returns the maximum size of this container.
705    *
706    * @return The maximum size of this container.
707    */
708   public Dimension getMaximumSize()
709   {
710     if (valid && maxSize != null)
711       return new Dimension(maxSize);
712 
713     LayoutManager layout = getLayout();
714     if (layout != null && layout instanceof LayoutManager2)
715       {
716         LayoutManager2 lm2 = (LayoutManager2) layout;
717         maxSize = lm2.maximumLayoutSize(this);
718         return maxSize;
719       }
720     else
721       return super.getMaximumSize();
722   }
723 
724   /**
725    * Returns the preferred alignment along the X axis.  This is a value
726    * between 0 and 1 where 0 represents alignment flush left and
727    * 1 means alignment flush right, and 0.5 means centered.
728    *
729    * @return The preferred alignment along the X axis.
730    */
731   public float getAlignmentX()
732   {
733     return super.getAlignmentX();
734   }
735 
736   /**
737    * Returns the preferred alignment along the Y axis.  This is a value
738    * between 0 and 1 where 0 represents alignment flush top and
739    * 1 means alignment flush bottom, and 0.5 means centered.
740    *
741    * @return The preferred alignment along the Y axis.
742    */
743   public float getAlignmentY()
744   {
745     return super.getAlignmentY();
746   }
747 
748   /**
749    * Paints this container.  The implementation of this method in this
750    * class forwards to any lightweight components in this container.  If
751    * this method is subclassed, this method should still be invoked as
752    * a superclass method so that lightweight components are properly
753    * drawn.
754    *
755    * @param g The graphics context for this paint job.
756    */
757   public void paint(Graphics g)
758   {
759     if (!isShowing())
760       return;
761 
762     // Visit heavyweights as well, in case they were
763     // erased when we cleared the background for this container.
764     visitChildren(g, GfxPaintVisitor.INSTANCE, false);
765   }
766 
767   /**
768    * Updates this container.  The implementation of this method in this
769    * class forwards to any lightweight components in this container.  If
770    * this method is subclassed, this method should still be invoked as
771    * a superclass method so that lightweight components are properly
772    * drawn.
773    *
774    * @param g The graphics context for this update.
775    *
776    * @specnote The specification suggests that this method forwards the
777    *           update() call to all its lightweight children. Tests show
778    *           that this is not done either in the JDK. The exact behaviour
779    *           seems to be that the background is cleared in heavyweight
780    *           Containers, and all other containers
781    *           directly call paint(), causing the (lightweight) children to
782    *           be painted.
783    */
784   public void update(Graphics g)
785   {
786     // It seems that the JDK clears the background of containers like Panel
787     // and Window (within this method) but not of 'plain' Containers or
788     // JComponents. This could
789     // lead to the assumption that it only clears heavyweight containers.
790     // However that is not quite true. In a test with a custom Container
791     // that overrides isLightweight() to return false, the background is
792     // also not cleared. So we do a check on !(peer instanceof LightweightPeer)
793     // instead.
794     ComponentPeer p = peer;
795     if (p != null && !(p instanceof LightweightPeer))
796       g.clearRect(0, 0, getWidth(), getHeight());
797 
798     paint(g);
799   }
800 
801   /**
802    * Prints this container.  The implementation of this method in this
803    * class forwards to any lightweight components in this container.  If
804    * this method is subclassed, this method should still be invoked as
805    * a superclass method so that lightweight components are properly
806    * drawn.
807    *
808    * @param g The graphics context for this print job.
809    */
810   public void print(Graphics g)
811   {
812     super.print(g);
813     visitChildren(g, GfxPrintVisitor.INSTANCE, true);
814   }
815 
816   /**
817    * Paints all of the components in this container.
818    *
819    * @param g The graphics context for this paint job.
820    */
821   public void paintComponents(Graphics g)
822   {
823     super.paint(g);
824     visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
825   }
826 
827   /**
828    * Prints all of the components in this container.
829    *
830    * @param g The graphics context for this print job.
831    */
832   public void printComponents(Graphics g)
833   {
834     super.paint(g);
835     visitChildren(g, GfxPrintAllVisitor.INSTANCE, true);
836   }
837 
838   /**
839    * Adds the specified container listener to this object's list of
840    * container listeners.
841    *
842    * @param listener The listener to add.
843    */
844   public synchronized void addContainerListener(ContainerListener listener)
845   {
846     containerListener = AWTEventMulticaster.add(containerListener, listener);
847   }
848 
849   /**
850    * Removes the specified container listener from this object's list of
851    * container listeners.
852    *
853    * @param listener The listener to remove.
854    */
855   public synchronized void removeContainerListener(ContainerListener listener)
856   {
857     containerListener = AWTEventMulticaster.remove(containerListener, listener);
858   }
859 
860   /**
861    * @since 1.4
862    */
863   public synchronized ContainerListener[] getContainerListeners()
864   {
865     return (ContainerListener[])
866       AWTEventMulticaster.getListeners(containerListener,
867                                        ContainerListener.class);
868   }
869 
870   /**
871    * Returns an array of all the objects currently registered as FooListeners
872    * upon this Container. FooListeners are registered using the addFooListener
873    * method.
874    *
875    * @exception ClassCastException If listenerType doesn't specify a class or
876    * interface that implements @see java.util.EventListener.
877    *
878    * @since 1.3
879    */
880   public EventListener[] getListeners(Class listenerType)
881   {
882     if (listenerType == ContainerListener.class)
883       return getContainerListeners();
884     return super.getListeners(listenerType);
885   }
886 
887   /**
888    * Processes the specified event.  This method calls
889    * <code>processContainerEvent()</code> if this method is a
890    * <code>ContainerEvent</code>, otherwise it calls the superclass
891    * method.
892    *
893    * @param e The event to be processed.
894    */
895   protected void processEvent(AWTEvent e)
896   {
897     if (e instanceof ContainerEvent)
898       processContainerEvent((ContainerEvent) e);
899     else
900       super.processEvent(e);
901   }
902 
903   /**
904    * Called when a container event occurs if container events are enabled.
905    * This method calls any registered listeners.
906    *
907    * @param e The event that occurred.
908    */
909   protected void processContainerEvent(ContainerEvent e)
910   {
911     if (containerListener == null)
912       return;
913     switch (e.id)
914       {
915       case ContainerEvent.COMPONENT_ADDED:
916         containerListener.componentAdded(e);
917         break;
918 
919       case ContainerEvent.COMPONENT_REMOVED:
920         containerListener.componentRemoved(e);
921         break;
922       }
923   }
924 
925   /**
926    * AWT 1.0 event processor.
927    *
928    * @param e The event that occurred.
929    *
930    * @deprecated use {@link #dispatchEvent(AWTEvent)} instead
931    */
932   public void deliverEvent(Event e)
933   {
934     if (!handleEvent (e))
935       {
936         synchronized (getTreeLock ())
937           {
938             Component parent = getParent ();
939 
940             if (parent != null)
941               parent.deliverEvent (e);
942           }
943       }
944   }
945 
946   /**
947    * Returns the component located at the specified point.  This is done
948    * by checking whether or not a child component claims to contain this
949    * point.  The first child component that does is returned.  If no
950    * child component claims the point, the container itself is returned,
951    * unless the point does not exist within this container, in which
952    * case <code>null</code> is returned.
953    *
954    * @param x The X coordinate of the point.
955    * @param y The Y coordinate of the point.
956    *
957    * @return The component containing the specified point, or
958    * <code>null</code> if there is no such point.
959    */
960   public Component getComponentAt(int x, int y)
961   {
962     return locate (x, y);
963   }
964 
965   /**
966    * Returns the component located at the specified point.  This is done
967    * by checking whether or not a child component claims to contain this
968    * point.  The first child component that does is returned.  If no
969    * child component claims the point, the container itself is returned,
970    * unless the point does not exist within this container, in which
971    * case <code>null</code> is returned.
972    *
973    * @param x The x position of the point to return the component at.
974    * @param y The y position of the point to return the component at.
975    *
976    * @return The component containing the specified point, or <code>null</code>
977    * if there is no such point.
978    *
979    * @deprecated use {@link #getComponentAt(int, int)} instead
980    */
981   public Component locate(int x, int y)
982   {
983     synchronized (getTreeLock ())
984       {
985         if (!contains (x, y))
986           return null;
987         for (int i = 0; i < ncomponents; ++i)
988           {
989             // Ignore invisible children...
990             if (!component[i].isVisible ())
991               continue;
992 
993             int x2 = x - component[i].x;
994             int y2 = y - component[i].y;
995             if (component[i].contains (x2, y2))
996               return component[i];
997           }
998         return this;
999       }
1000  }
1001
1002  /**
1003   * Returns the component located at the specified point.  This is done
1004   * by checking whether or not a child component claims to contain this
1005   * point.  The first child component that does is returned.  If no
1006   * child component claims the point, the container itself is returned,
1007   * unless the point does not exist within this container, in which
1008   * case <code>null</code> is returned.
1009   *
1010   * @param p The point to return the component at.
1011   * @return The component containing the specified point, or <code>null</code>
1012   * if there is no such point.
1013   */
1014  public Component getComponentAt(Point p)
1015  {
1016    return getComponentAt (p.x, p.y);
1017  }
1018
1019  public Component findComponentAt(int x, int y)
1020  {
1021    synchronized (getTreeLock ())
1022      {
1023        if (! contains(x, y))
1024          return null;
1025
1026        for (int i = 0; i < ncomponents; ++i)
1027          {
1028            // Ignore invisible children...
1029            if (!component[i].isVisible())
1030              continue;
1031
1032            int x2 = x - component[i].x;
1033            int y2 = y - component[i].y;
1034            // We don't do the contains() check right away because
1035            // findComponentAt would redundantly do it first thing.
1036            if (component[i] instanceof Container)
1037              {
1038                Container k = (Container) component[i];
1039                Component r = k.findComponentAt(x2, y2);
1040                if (r != null)
1041                  return r;
1042              }
1043            else if (component[i].contains(x2, y2))
1044              return component[i];
1045          }
1046
1047        return this;
1048      }
1049  }
1050
1051  public Component findComponentAt(Point p)
1052  {
1053    return findComponentAt(p.x, p.y);
1054  }
1055
1056  /**
1057   * Called when this container is added to another container to inform it
1058   * to create its peer.  Peers for any child components will also be
1059   * created.
1060   */
1061  public void addNotify()
1062  {
1063    super.addNotify();
1064    addNotifyContainerChildren();
1065  }
1066
1067  /**
1068   * Called when this container is removed from its parent container to
1069   * inform it to destroy its peer.  This causes the peers of all child
1070   * component to be destroyed as well.
1071   */
1072  public void removeNotify()
1073  {
1074    synchronized (getTreeLock ())
1075      {
1076        for (int i = 0; i < ncomponents; ++i)
1077          component[i].removeNotify();
1078        super.removeNotify();
1079      }
1080  }
1081
1082  /**
1083   * Tests whether or not the specified component is contained within
1084   * this components subtree.
1085   *
1086   * @param comp The component to test.
1087   *
1088   * @return <code>true</code> if this container is an ancestor of the
1089   * specified component, <code>false</code> otherwise.
1090   */
1091  public boolean isAncestorOf(Component comp)
1092  {
1093    synchronized (getTreeLock ())
1094      {
1095        while (true)
1096          {
1097            if (comp == null)
1098              return false;
1099            if (comp == this)
1100              return true;
1101            comp = comp.getParent();
1102          }
1103      }
1104  }
1105
1106  /**
1107   * Returns a string representing the state of this container for
1108   * debugging purposes.
1109   *
1110   * @return A string representing the state of this container.
1111   */
1112  protected String paramString()
1113  {
1114    if (layoutMgr == null)
1115      return super.paramString();
1116
1117    StringBuffer sb = new StringBuffer();
1118    sb.append(super.paramString());
1119    sb.append(",layout=");
1120    sb.append(layoutMgr.getClass().getName());
1121    return sb.toString();
1122  }
1123
1124  /**
1125   * Writes a listing of this container to the specified stream starting
1126   * at the specified indentation point.
1127   *
1128   * @param out The <code>PrintStream</code> to write to.
1129   * @param indent The indentation point.
1130   */
1131  public void list(PrintStream out, int indent)
1132  {
1133    synchronized (getTreeLock ())
1134      {
1135        super.list(out, indent);
1136        for (int i = 0; i < ncomponents; ++i)
1137          component[i].list(out, indent + 2);
1138      }
1139  }
1140
1141  /**
1142   * Writes a listing of this container to the specified stream starting
1143   * at the specified indentation point.
1144   *
1145   * @param out The <code>PrintWriter</code> to write to.
1146   * @param indent The indentation point.
1147   */
1148  public void list(PrintWriter out, int indent)
1149  {
1150    synchronized (getTreeLock ())
1151      {
1152        super.list(out, indent);
1153        for (int i = 0; i < ncomponents; ++i)
1154          component[i].list(out, indent + 2);
1155      }
1156  }
1157
1158  /**
1159   * Sets the focus traversal keys for a given traversal operation for this
1160   * Container.
1161   *
1162   * @exception IllegalArgumentException If id is not one of
1163   * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1164   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1165   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1166   * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS,
1167   * or if keystrokes contains null, or if any Object in keystrokes is not an
1168   * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any
1169   * keystroke already maps to another focus traversal operation for this
1170   * Container.
1171   *
1172   * @since 1.4
1173   */
1174  public void setFocusTraversalKeys(int id, Set keystrokes)
1175  {
1176    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1177        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1178        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1179        id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1180      throw new IllegalArgumentException ();
1181
1182    if (keystrokes == null)
1183      {
1184        Container parent = getParent ();
1185
1186        while (parent != null)
1187          {
1188            if (parent.areFocusTraversalKeysSet (id))
1189              {
1190                keystrokes = parent.getFocusTraversalKeys (id);
1191                break;
1192              }
1193            parent = parent.getParent ();
1194          }
1195
1196        if (keystrokes == null)
1197          keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
1198            getDefaultFocusTraversalKeys (id);
1199      }
1200
1201    Set sa;
1202    Set sb;
1203    Set sc;
1204    String name;
1205    switch (id)
1206      {
1207      case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
1208        sa = getFocusTraversalKeys
1209          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1210        sb = getFocusTraversalKeys
1211          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1212        sc = getFocusTraversalKeys
1213          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1214        name = "forwardFocusTraversalKeys";
1215        break;
1216      case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
1217        sa = getFocusTraversalKeys
1218          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1219        sb = getFocusTraversalKeys
1220          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1221        sc = getFocusTraversalKeys
1222          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1223        name = "backwardFocusTraversalKeys";
1224        break;
1225      case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
1226        sa = getFocusTraversalKeys
1227          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1228        sb = getFocusTraversalKeys
1229          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1230        sc = getFocusTraversalKeys
1231          (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1232        name = "upCycleFocusTraversalKeys";
1233        break;
1234      case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
1235        sa = getFocusTraversalKeys
1236          (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1237        sb = getFocusTraversalKeys
1238          (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1239        sc = getFocusTraversalKeys
1240          (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1241        name = "downCycleFocusTraversalKeys";
1242        break;
1243      default:
1244        throw new IllegalArgumentException ();
1245      }
1246
1247    int i = keystrokes.size ();
1248    Iterator iter = keystrokes.iterator ();
1249
1250    while (--i >= 0)
1251      {
1252        Object o = iter.next ();
1253        if (!(o instanceof AWTKeyStroke)
1254            || sa.contains (o) || sb.contains (o) || sc.contains (o)
1255            || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
1256          throw new IllegalArgumentException ();
1257      }
1258
1259    if (focusTraversalKeys == null)
1260      focusTraversalKeys = new Set[4];
1261
1262    keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
1263    firePropertyChange (name, focusTraversalKeys[id], keystrokes);
1264
1265    focusTraversalKeys[id] = keystrokes;
1266  }
1267  
1268  /**
1269   * Returns the Set of focus traversal keys for a given traversal operation for
1270   * this Container.
1271   *
1272   * @exception IllegalArgumentException If id is not one of
1273   * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1274   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1275   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1276   * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1277   *
1278   * @since 1.4
1279   */
1280  public Set getFocusTraversalKeys (int id)
1281  {
1282    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1283        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1284        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1285        id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1286      throw new IllegalArgumentException ();
1287
1288    Set s = null;
1289
1290    if (focusTraversalKeys != null)
1291      s = focusTraversalKeys[id];
1292
1293    if (s == null && parent != null)
1294      s = parent.getFocusTraversalKeys (id);
1295
1296    return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
1297                        .getDefaultFocusTraversalKeys(id)) : s;
1298  }
1299
1300  /**
1301   * Returns whether the Set of focus traversal keys for the given focus
1302   * traversal operation has been explicitly defined for this Container.
1303   * If this method returns false, this Container is inheriting the Set from
1304   * an ancestor, or from the current KeyboardFocusManager.
1305   *
1306   * @exception IllegalArgumentException If id is not one of
1307   * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1308   * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1309   * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1310   * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1311   *
1312   * @since 1.4
1313   */
1314  public boolean areFocusTraversalKeysSet (int id)
1315  {
1316    if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1317        id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1318        id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1319        id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1320      throw new IllegalArgumentException ();
1321
1322    return focusTraversalKeys != null && focusTraversalKeys[id] != null;
1323  }
1324
1325  /**
1326   * Check whether the given Container is the focus cycle root of this
1327   * Container's focus traversal cycle.  If this Container is a focus
1328   * cycle root itself, then it will be in two different focus cycles
1329   * -- it's own, and that of its ancestor focus cycle root's.  In
1330   * that case, if <code>c</code> is either of those containers, this
1331   * method will return true.
1332   *
1333   * @param c the candidate Container
1334   *
1335   * @return true if c is the focus cycle root of the focus traversal
1336   * cycle to which this Container belongs, false otherwise
1337   *
1338   * @since 1.4
1339   */
1340  public boolean isFocusCycleRoot (Container c)
1341  {
1342    if (this == c
1343        && isFocusCycleRoot ())
1344      return true;
1345
1346    Container ancestor = getFocusCycleRootAncestor ();
1347
1348    if (c == ancestor)
1349      return true;
1350
1351    return false;
1352  }
1353
1354  /**
1355   * If this Container is a focus cycle root, set the focus traversal
1356   * policy that determines the focus traversal order for its
1357   * children.  If non-null, this policy will be inherited by all
1358   * inferior focus cycle roots.  If <code>policy</code> is null, this
1359   * Container will inherit its policy from the closest ancestor focus
1360   * cycle root that's had its policy set.
1361   *
1362   * @param policy the new focus traversal policy for this Container or null
1363   *
1364   * @since 1.4
1365   */
1366  public void setFocusTraversalPolicy (FocusTraversalPolicy policy)
1367  {
1368    focusTraversalPolicy = policy;
1369  }
1370
1371  /**
1372   * Return the focus traversal policy that determines the focus
1373   * traversal order for this Container's children.  This method
1374   * returns null if this Container is not a focus cycle root.  If the
1375   * focus traversal policy has not been set explicitly, then this
1376   * method will return an ancestor focus cycle root's policy instead.
1377   *
1378   * @return this Container's focus traversal policy or null
1379   *
1380   * @since 1.4
1381   */
1382  public FocusTraversalPolicy getFocusTraversalPolicy ()
1383  {
1384    if (!isFocusCycleRoot ())
1385      return null;
1386
1387    if (focusTraversalPolicy == null)
1388      {
1389        Container ancestor = getFocusCycleRootAncestor ();
1390
1391  if (ancestor != this)
1392    return ancestor.getFocusTraversalPolicy ();
1393  else
1394    {
1395      KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
1396
1397      return manager.getDefaultFocusTraversalPolicy ();
1398    }
1399      }
1400    else
1401      return focusTraversalPolicy;
1402  }
1403
1404  /**
1405   * Check whether this Container's focus traversal policy has been
1406   * explicitly set.  If it has not, then this Container will inherit
1407   * its focus traversal policy from one of its ancestor focus cycle
1408   * roots.
1409   *
1410   * @return true if focus traversal policy is set, false otherwise
1411  */
1412  public boolean isFocusTraversalPolicySet ()
1413  {
1414    return focusTraversalPolicy == null;
1415  }
1416
1417  /**
1418   * Set whether or not this Container is the root of a focus
1419   * traversal cycle.  This Container's focus traversal policy
1420   * determines the order of focus traversal.  Some policies prevent
1421   * the focus from being transferred between two traversal cycles
1422   * until an up or down traversal operation is performed.  In that
1423   * case, normal traversal (not up or down) is limited to this
1424   * Container and all of this Container's descendents that are not
1425   * descendents of inferior focus cycle roots.  In the default case
1426   * however, ContainerOrderFocusTraversalPolicy is in effect, and it
1427   * supports implicit down-cycle traversal operations.
1428   *
1429   * @param focusCycleRoot true if this is a focus cycle root, false otherwise
1430   *
1431   * @since 1.4
1432   */
1433  public void setFocusCycleRoot (boolean focusCycleRoot)
1434  {
1435    this.focusCycleRoot = focusCycleRoot;
1436  }
1437
1438  /**
1439   * Check whether this Container is a focus cycle root.
1440   *
1441   * @return true if this is a focus cycle root, false otherwise
1442   *
1443   * @since 1.4
1444   */
1445  public boolean isFocusCycleRoot ()
1446  {
1447    return focusCycleRoot;
1448  }
1449
1450  /**
1451   * Transfer focus down one focus traversal cycle.  If this Container
1452   * is a focus cycle root, then its default component becomes the
1453   * focus owner, and this Container becomes the current focus cycle
1454   * root.  No traversal will occur if this Container is not a focus
1455   * cycle root.
1456   *
1457   * @since 1.4
1458   */
1459  public void transferFocusDownCycle ()
1460  {
1461    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
1462
1463    manager.downFocusCycle (this);
1464  }
1465
1466  /**
1467   * Sets the ComponentOrientation property of this container and all components
1468   * contained within it.
1469   *
1470   * @exception NullPointerException If orientation is null
1471   *
1472   * @since 1.4
1473   */
1474  public void applyComponentOrientation (ComponentOrientation orientation)
1475  {
1476    if (orientation == null)
1477      throw new NullPointerException ();
1478  }
1479  
1480  public void addPropertyChangeListener (PropertyChangeListener listener)
1481  {
1482    if (listener == null)
1483      return;
1484
1485    if (changeSupport == null)
1486      changeSupport = new PropertyChangeSupport (this);
1487
1488    changeSupport.addPropertyChangeListener (listener);
1489  }
1490  
1491  public void addPropertyChangeListener (String name,
1492                                         PropertyChangeListener listener)
1493  {
1494    if (listener == null)
1495      return;
1496    
1497    if (changeSupport == null)
1498      changeSupport = new PropertyChangeSupport (this);
1499
1500    changeSupport.addPropertyChangeListener (name, listener);
1501  }
1502
1503  // Hidden helper methods.
1504
1505  /**
1506   * Perform a graphics operation on the children of this container.
1507   * For each applicable child, the visitChild() method will be called
1508   * to perform the graphics operation.
1509   *
1510   * @param gfx The graphics object that will be used to derive new
1511   * graphics objects for the children.
1512   *
1513   * @param visitor Object encapsulating the graphics operation that
1514   * should be performed.
1515   *
1516   * @param lightweightOnly If true, only lightweight components will
1517   * be visited.
1518   */
1519  private void visitChildren(Graphics gfx, GfxVisitor visitor,
1520                             boolean lightweightOnly)
1521  {
1522    synchronized (getTreeLock ())
1523      {
1524        for (int i = ncomponents - 1; i >= 0; --i)
1525          {
1526            Component comp = component[i];
1527            boolean applicable = comp.isVisible()
1528              && (comp.isLightweight() || !lightweightOnly);
1529
1530            if (applicable)
1531              visitChild(gfx, visitor, comp);
1532    }
1533      }
1534  }
1535
1536  /**
1537   * Perform a graphics operation on a child. A translated and clipped
1538   * graphics object will be created, and the visit() method of the
1539   * visitor will be called to perform the operation.
1540   *
1541   * @param gfx The graphics object that will be used to derive new
1542   * graphics objects for the child.
1543   *
1544   * @param visitor Object encapsulating the graphics operation that
1545   * should be performed.
1546   *
1547   * @param comp The child component that should be visited.
1548   */
1549  private void visitChild(Graphics gfx, GfxVisitor visitor,
1550                          Component comp)
1551  {
1552    Rectangle bounds = comp.getBounds();
1553    Rectangle oldClip = gfx.getClipBounds();
1554    if (oldClip == null)
1555      oldClip = bounds;
1556
1557    Rectangle clip = oldClip.intersection(bounds);
1558
1559    if (clip.isEmpty()) return;
1560
1561    boolean clipped = false;
1562    boolean translated = false;
1563    try
1564      {
1565        gfx.setClip(clip.x, clip.y, clip.width, clip.height);
1566        clipped = true;
1567        gfx.translate(bounds.x, bounds.y);
1568        translated = true;
1569        visitor.visit(comp, gfx);
1570      }
1571    finally
1572      {
1573        if (translated)
1574          gfx.translate (-bounds.x, -bounds.y);
1575        if (clipped)
1576          gfx.setClip (oldClip.x, oldClip.y, oldClip.width, oldClip.height);
1577      }
1578  }
1579
1580  void dispatchEventImpl(AWTEvent e)
1581  {
1582    // Give lightweight dispatcher a chance to handle it.
1583    if (dispatcher != null && dispatcher.handleEvent (e))
1584      return;
1585
1586    if ((e.id <= ContainerEvent.CONTAINER_LAST
1587             && e.id >= ContainerEvent.CONTAINER_FIRST)
1588        && (containerListener != null
1589            || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
1590      processEvent(e);
1591    else
1592      super.dispatchEventImpl(e);
1593  }
1594
1595  /**
1596   * Tests if this container has an interest in the given event id.
1597   *
1598   * @param eventId The event id to check.
1599   *
1600   * @return <code>true</code> if a listener for the event id exists or
1601   *         if the eventMask is set for the event id.
1602   *
1603   * @see java.awt.Component#eventTypeEnabled(int)
1604   */
1605  boolean eventTypeEnabled(int eventId)
1606  {
1607    if(eventId <= ContainerEvent.CONTAINER_LAST 
1608       && eventId >= ContainerEvent.CONTAINER_FIRST)
1609