OSDN Git Service

5fd9e9420982172590d9cb76a86540796388900b
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / Container.java
1 /* Copyright (C) 1999, 2000, 2002  Free Software Foundation
2
3 This file is part of GNU Classpath.
4
5 GNU Classpath is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 GNU Classpath is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Classpath; see the file COPYING.  If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA.
19
20 As a special exception, if you link this library with other files to
21 produce an executable, this library does not by itself cause the
22 resulting executable to be covered by the GNU General Public License.
23 This exception does not however invalidate any other reasons why the
24 executable file might be covered by the GNU General Public License. */
25
26 package java.awt;
27
28 import java.awt.event.*;
29 import java.io.PrintStream;
30 import java.io.PrintWriter;
31 import java.util.EventListener;
32 import java.awt.peer.ComponentPeer;
33 import java.awt.peer.ContainerPeer;
34 import java.awt.peer.LightweightPeer;
35
36 /* A somewhat incomplete class. */
37
38 public class Container extends Component
39 {
40   /* Serialized fields from the serialization spec. */
41   int ncomponents;
42   Component[] component;
43   LayoutManager layoutMgr;
44   /* LightweightDispatcher dispatcher; */ // wtf?
45   Dimension maxSize;
46   int containerSerializedDataVersion;
47
48   /* Anything else is non-serializable, and should be declared "transient". */
49   transient ContainerListener containerListener;  
50
51   /**
52    * Default constructor for subclasses.
53    */
54   public Container()
55   {
56   }
57
58   /**
59    * Returns the number of components in this container.
60    *
61    * @return The number of components in this container.
62    */
63   public int getComponentCount()
64   {
65     return ncomponents;
66   }
67
68   /**
69    * Returns the number of components in this container.
70    *
71    * @return The number of components in this container.
72    *
73    * @deprecated This method is deprecated in favor of 
74    * <code>getComponentCount()</code>.
75    */
76   public int countComponents()
77   {
78     return ncomponents;
79   }
80
81   /**
82    * Returns the component at the specified index.
83    *
84    * @param index The index of the component to retrieve.
85    *
86    * @return The requested component.
87    *
88    * @exception ArrayIndexOutOfBoundsException If the specified index is not
89    * valid.
90    */
91   public Component getComponent (int n)
92   {
93     if (n < 0 || n >= ncomponents)
94       throw new ArrayIndexOutOfBoundsException("no such component");
95     return component[n];
96   }
97
98   /**
99    * Returns an array of the components in this container.
100    *
101    * @return The components in this container.
102    */
103   public Component[] getComponents()
104   {
105     Component[] result = new Component[ncomponents];
106     if (ncomponents > 0)
107       System.arraycopy(component, 0, result, 0, ncomponents);
108     return result;
109   }
110
111   /**
112    * Returns the insets for this container, which is the space used for
113    * borders, the margin, etc.
114    *
115    * @return The insets for this container.
116    */
117   public Insets getInsets()
118   {
119     if (peer == null)
120       return new Insets(0, 0, 0, 0);
121     return ((ContainerPeer) peer).getInsets();
122   }
123
124   /**
125    * Returns the insets for this container, which is the space used for
126    * borders, the margin, etc.
127    *
128    * @return The insets for this container.
129    *
130    * @deprecated This method is deprecated in favor of
131    * <code>getInsets()</code>.
132    */
133   public Insets insets()
134   {
135     return getInsets();
136   }
137
138   /**
139    * Adds the specified component to this container at the end of the
140    * component list.
141    *
142    * @param component The component to add to the container.
143    *
144    * @return The same component that was added.
145    */
146   public Component add (Component comp)
147   {
148     addImpl (comp, null, -1);
149     return comp;
150   }
151
152   /**
153    * Adds the specified component to the container at the end of the
154    * component list.  This method should not be used. Instead, use
155    * <code>add(Component, Object</code>.
156    *
157    * @param name FIXME
158    * @param component The component to be added.
159    *
160    * @return The same component that was added.
161    */
162   public Component add (String name, Component comp)
163   {
164     addImpl (comp, name, -1);
165     return comp;
166   }
167
168   /**
169    * Adds the specified component to this container at the specified index
170    * in the component list.
171    *
172    * @param component The component to be added.
173    * @param index The index in the component list to insert this child
174    * at, or -1 to add at the end of the list.
175    *
176    * @return The same component that was added.
177    *
178    * @param throws ArrayIndexOutOfBounds If the specified index is invalid.
179    */
180   public Component add (Component comp, int index)
181   {
182     addImpl (comp, null, index);
183     return comp;
184   }
185
186   /**
187    * Adds the specified component to this container at the end of the
188    * component list.  The layout manager will use the specified constraints
189    * when laying out this component.
190    *
191    * @param component The component to be added to this container.
192    * @param constraints The layout constraints for this component.
193    */
194   public void add (Component comp, Object constraints)
195   {
196     addImpl (comp, constraints, -1);
197   }
198
199   /**
200    * Adds the specified component to this container at the specified index
201    * in the component list.  The layout manager will use the specified
202    * constraints when layout out this component.
203    *
204    * @param component The component to be added.
205    * @param constraints The layout constraints for this component.
206    * @param index The index in the component list to insert this child
207    * at, or -1 to add at the end of the list.
208    *
209    * @param throws ArrayIndexOutOfBounds If the specified index is invalid.
210    */
211   public void add (Component comp, Object constraints, int index)
212   {
213     addImpl (comp, constraints, index);
214   }
215
216   /**
217    * This method is called by all the <code>add()</code> methods to perform
218    * the actual adding of the component.  Subclasses who wish to perform
219    * their own processing when a component is added should override this
220    * method.  Any subclass doing this must call the superclass version of
221    * this method in order to ensure proper functioning of the container.
222    *
223    * @param component The component to be added.
224    * @param constraints The layout constraints for this component, or
225    * <code>null</code> if there are no constraints.
226    * @param index The index in the component list to insert this child
227    * at, or -1 to add at the end of the list.
228    *
229    * @param throws ArrayIndexOutOfBounds If the specified index is invalid.
230    */
231   protected void addImpl (Component comp, Object constraints, int index)
232   {
233     if (index > ncomponents
234         || (index < 0 && index != -1)
235         || comp instanceof Window
236         || (comp instanceof Container
237             && ((Container) comp).isAncestorOf (this)))
238       throw new IllegalArgumentException ();
239
240     // Reparent component, and make sure component is instantiated if
241     // we are.
242     if (comp.parent != null)
243       comp.parent.remove (comp);
244     comp.parent = this;
245     if (peer != null)
246       {
247         comp.addNotify ();
248
249         if (comp.isLightweight())
250           enableEvents(comp.eventMask);
251       }
252
253     invalidate ();
254
255     if (component == null)
256       component = new Component[4]; // FIXME, better initial size?
257
258     // This isn't the most efficient implementation.  We could do less
259     // copying when growing the array.  It probably doesn't matter.
260     if (ncomponents >= component.length)
261       {
262         int nl = component.length * 2;
263         Component[] c = new Component[nl];
264         System.arraycopy (component, 0, c, 0, ncomponents);
265         component = c;
266       }
267     if (index == -1)
268       component[ncomponents++] = comp;
269     else
270       {
271         System.arraycopy (component, index, component, index + 1,
272                           ncomponents - index);
273         component[index] = comp;
274         ++ncomponents;
275       }
276
277     // Notify the layout manager.
278     if (layoutMgr != null)
279       {
280         if (layoutMgr instanceof LayoutManager2)
281           {
282             LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
283             lm2.addLayoutComponent (comp, constraints);
284           }
285         else if (constraints instanceof String)
286           layoutMgr.addLayoutComponent ((String) constraints, comp);
287         else
288           layoutMgr.addLayoutComponent (null, comp);
289       }
290
291     // Post event to notify of adding the container.
292     ContainerEvent ce = new ContainerEvent (this,
293                                             ContainerEvent.COMPONENT_ADDED,
294                                             comp);
295     getToolkit().getSystemEventQueue().postEvent(ce);
296   }
297
298   /**
299    * Removes the component at the specified index from this container.
300    *
301    * @param index The index of the component to remove.
302    */
303   public void remove (int index)
304   {
305     Component r = component[index];
306
307     r.removeNotify ();
308
309     System.arraycopy (component, index + 1, component, index,
310                       ncomponents - index - 1);
311     component[--ncomponents] = null;
312
313     invalidate ();
314
315     if (layoutMgr != null)
316       layoutMgr.removeLayoutComponent (r);
317
318     // Post event to notify of adding the container.
319     ContainerEvent ce = new ContainerEvent (this,
320                                             ContainerEvent.COMPONENT_REMOVED,
321                                             r);
322     getToolkit().getSystemEventQueue().postEvent(ce);
323   }
324
325   /**
326    * Removes the specified component from this container.
327    *
328    * @return component The component to remove from this container.
329    */
330   public void remove (Component comp)
331   {
332     for (int i = 0; i < ncomponents; ++i)
333       {
334         if (component[i] == comp)
335           {
336             remove (i);
337             break;
338           }
339       }
340   }
341
342   /**
343    * Removes all components from this container.
344    */
345   public void removeAll()
346   {
347     while (ncomponents > 0)
348       remove (0);
349   }
350
351   /**
352    * Returns the current layout manager for this container.
353    *
354    * @return The layout manager for this container.
355    */
356   public LayoutManager getLayout()
357   {
358     return layoutMgr;
359   }
360
361   /**
362    * Sets the layout manager for this container to the specified layout
363    * manager.
364    *
365    * @param mgr The new layout manager for this container.
366    */
367   public void setLayout(LayoutManager mgr)
368   {
369     layoutMgr = mgr;
370     invalidate ();
371   }
372
373   /**
374    * Layout the components in this container.
375    */
376   public void doLayout()
377   {
378     if (layoutMgr != null)
379       layoutMgr.layoutContainer (this);
380   }
381
382   /**
383    * Layout the components in this container.
384    *
385    * @deprecated This method is deprecated in favor of
386    * <code>doLayout()</code>.
387    */
388   public void layout()
389   {
390     doLayout();
391   }
392
393   /**
394    * Invalidates this container to indicate that it (and all parent
395    * containers) need to be laid out.
396    */
397   public void invalidate()
398   {
399     super.invalidate ();
400   }
401
402   /**
403    * Re-lays out the components in this container.
404    */
405   public void validate()
406   {
407     // FIXME: use the tree lock?
408     synchronized (this)
409       {
410         if (! isValid ())
411           {
412             validateTree ();
413           }
414       }
415   }
416
417   /**
418    * Recursively validates the container tree, recomputing any invalid
419    * layouts.
420    */
421   protected void validateTree()
422   {
423     if (valid)
424       return; 
425
426     ContainerPeer cPeer = null;
427     if ((peer != null) && !(peer instanceof LightweightPeer))
428       {
429         cPeer = (ContainerPeer) peer;
430         cPeer.beginValidate();
431       }
432
433     doLayout ();
434     for (int i = 0; i < ncomponents; ++i)
435       {
436         Component comp = component[i];
437         if (! comp.isValid ())
438           {
439             if (comp instanceof Container)
440               {
441                 ((Container) comp).validateTree();
442               }
443             else
444               {
445                 component[i].validate();
446               }
447           }
448       }
449
450     /* children will call invalidate() when they are layed out. It
451        is therefore imporant that valid is not set to true
452        before after the children has been layed out. */
453     valid = true;
454
455     if (cPeer != null)
456       cPeer.endValidate();
457   }
458
459   public void setFont(Font f)
460   {
461     super.setFont(f);
462     // FIXME, should invalidate all children with font == null
463   }
464
465   /**
466    * Returns the preferred size of this container.
467    *
468    * @return The preferred size of this container.
469    */
470   public Dimension getPreferredSize()
471   {
472     if (layoutMgr != null)
473       return layoutMgr.preferredLayoutSize (this);
474     else
475       return super.getPreferredSize ();
476   }
477
478   /**
479    * Returns the preferred size of this container.
480    *
481    * @return The preferred size of this container.
482    * 
483    * @deprecated This method is deprecated in favor of 
484    * <code>getPreferredSize()</code>.
485    */
486   public Dimension preferredSize()
487   {
488     return getPreferredSize();
489   }
490
491   /**
492    * Returns the minimum size of this container.
493    *
494    * @return The minimum size of this container.
495    */
496   public Dimension getMinimumSize()
497   {
498     if (layoutMgr != null)
499       return layoutMgr.minimumLayoutSize (this);
500     else
501       return super.getMinimumSize ();
502   }
503
504   /**
505    * Returns the minimum size of this container.
506    *
507    * @return The minimum size of this container.
508    * 
509    * @deprecated This method is deprecated in favor of 
510    * <code>getMinimumSize()</code>.
511    */
512   public Dimension minimumSize()
513   {
514     return getMinimumSize();
515   }
516
517   /**
518    * Returns the maximum size of this container.
519    *
520    * @return The maximum size of this container.
521    */
522   public Dimension getMaximumSize()
523   {
524     if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
525       {
526         LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
527         return lm2.maximumLayoutSize (this);
528       }
529     else
530       return super.getMaximumSize ();
531   }
532
533   /**
534    * Returns the preferred alignment along the X axis.  This is a value
535    * between 0 and 1 where 0 represents alignment flush left and
536    * 1 means alignment flush right, and 0.5 means centered.
537    *
538    * @return The preferred alignment along the X axis.
539    */
540   public float getAlignmentX()
541   {
542     if (layoutMgr instanceof LayoutManager2)
543       {
544         LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
545         return lm2.getLayoutAlignmentX (this);
546       }
547     else
548       return super.getAlignmentX();
549   }
550
551   /**
552    * Returns the preferred alignment along the Y axis.  This is a value
553    * between 0 and 1 where 0 represents alignment flush top and
554    * 1 means alignment flush bottom, and 0.5 means centered.
555    *
556    * @return The preferred alignment along the Y axis.
557    */
558   public float getAlignmentY()
559   {
560     if (layoutMgr instanceof LayoutManager2)
561       {
562         LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
563         return lm2.getLayoutAlignmentY (this);
564       }
565     else
566       return super.getAlignmentY();
567   }
568
569   /**
570    * Paints this container.  The implementation of this method in this
571    * class forwards to any lightweight components in this container.  If
572    * this method is subclassed, this method should still be invoked as
573    * a superclass method so that lightweight components are properly
574    * drawn.
575    *
576    * @param graphics The graphics context for this paint job.
577    */
578   public void paint(Graphics g)
579   {
580     if (!isShowing())
581       return;
582     super.paint(g);
583     visitChildren(g, GfxPaintVisitor.INSTANCE, true);
584   }
585
586   /** 
587    * Perform a graphics operation on the children of this container.
588    * For each applicable child, the visitChild() method will be called
589    * to perform the graphics operation.
590    *
591    * @param gfx The graphics object that will be used to derive new
592    * graphics objects for the children.
593    *
594    * @param visitor Object encapsulating the graphics operation that
595    * should be performed.
596    *
597    * @param lightweightOnly If true, only lightweight components will
598    * be visited.
599    */
600   private void visitChildren(Graphics gfx, GfxVisitor visitor,
601                              boolean lightweightOnly)
602   {
603     // FIXME: do locking
604
605     for (int i = 0; i < ncomponents; ++i)
606       {
607         Component comp = component[i];
608         boolean applicable = comp.isVisible()
609           && (comp.isLightweight() || !lightweightOnly);
610
611         if (applicable)
612           visitChild(gfx, visitor, comp);
613       }
614   }
615
616   /**
617    * Perform a graphics operation on a child. A translated and clipped
618    * graphics object will be created, and the visit() method of the
619    * visitor will be called to perform the operation.
620    *
621    * @param gfx The graphics object that will be used to derive new
622    * graphics objects for the child.
623    *
624    * @param visitor Object encapsulating the graphics operation that
625    * should be performed.
626    *
627    * @param comp The child component that should be visited.
628    */
629   private void visitChild(Graphics gfx, GfxVisitor visitor,
630                           Component comp)
631   {
632     Rectangle bounds = comp.getBounds();
633     Rectangle clip = gfx.getClipBounds().intersection(bounds);
634     
635     if (clip.isEmpty()) return;
636
637     Graphics gfx2 = gfx.create();
638     gfx2.setClip(clip.x, clip.y, clip.width, clip.height);
639     gfx2.translate(bounds.x, bounds.y);
640     
641     visitor.visit(comp, gfx2);
642   }
643
644   /**
645    * Updates this container.  The implementation of this method in this
646    * class forwards to any lightweight components in this container.  If
647    * this method is subclassed, this method should still be invoked as
648    * a superclass method so that lightweight components are properly
649    * drawn.
650    *
651    * @param graphics The graphics context for this update.
652    */
653   public void update(Graphics g)
654   {
655     super.update(g);
656   }
657
658   /**
659    * Prints this container.  The implementation of this method in this
660    * class forwards to any lightweight components in this container.  If
661    * this method is subclassed, this method should still be invoked as
662    * a superclass method so that lightweight components are properly
663    * drawn.
664    *
665    * @param graphics The graphics context for this print job.
666    */
667   public void print(Graphics g)
668   {
669     super.print(g);
670     visitChildren(g, GfxPrintVisitor.INSTANCE, true);
671   }
672
673   /**
674    * Paints all of the components in this container.
675    *
676    * @param graphics The graphics context for this paint job.
677    */
678   public void paintComponents(Graphics g)
679   {
680     super.paint(g);
681     visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
682   }
683
684   /**
685    * Prints all of the components in this container.
686    *
687    * @param graphics The graphics context for this print job.
688    */
689   public void printComponents(Graphics g)
690   {
691     super.paint(g);
692     visitChildren(g, GfxPrintAllVisitor.INSTANCE, true);
693   }
694
695   void dispatchEventImpl(AWTEvent e)
696   {
697     if ((e.id <= ContainerEvent.CONTAINER_LAST
698              && e.id >= ContainerEvent.CONTAINER_FIRST)
699         && (containerListener != null
700             || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
701       processEvent(e); 
702     else
703       super.dispatchEventImpl(e);
704   }  
705
706   /**
707    * Adds the specified container listener to this object's list of
708    * container listeners.
709    *
710    * @param listener The listener to add.
711    */
712   public synchronized void addContainerListener(ContainerListener l)
713   {
714     containerListener = AWTEventMulticaster.add (containerListener, l);
715   }
716
717   /**
718    * Removes the specified container listener from this object's list of
719    * container listeners.
720    *
721    * @param listener The listener to remove.
722    */
723   public synchronized void removeContainerListener(ContainerListener l)
724   {
725     containerListener = AWTEventMulticaster.remove(containerListener, l);
726   }
727
728   /** @since 1.3 */
729   public EventListener[] getListeners(Class listenerType)
730   {
731     if (listenerType == ContainerListener.class)
732       return getListenersImpl(listenerType, containerListener);
733     else return super.getListeners(listenerType);
734   }
735
736   /**
737    * Processes the specified event.  This method calls
738    * <code>processContainerEvent()</code> if this method is a
739    * <code>ContainerEvent</code>, otherwise it calls the superclass
740    * method.
741    *
742    * @param event The event to be processed.
743    */
744   protected void processEvent(AWTEvent e)
745   {
746     if (e instanceof ContainerEvent)
747       processContainerEvent((ContainerEvent) e);
748     else super.processEvent(e);
749   }
750
751   /**
752    * Called when a container event occurs if container events are enabled.
753    * This method calls any registered listeners.
754    *
755    * @param event The event that occurred.
756    */
757   protected void processContainerEvent(ContainerEvent e)
758   {
759     if (containerListener == null)
760       return;
761     switch (e.id)
762       {
763       case ContainerEvent.COMPONENT_ADDED:
764         containerListener.componentAdded(e);
765         break;
766
767       case ContainerEvent.COMPONENT_REMOVED:
768         containerListener.componentRemoved(e);
769         break;    
770       }
771   }
772
773   /**
774    * AWT 1.0 event processor.
775    *
776    * @param event The event that occurred.
777    *
778    * @deprecated This method is deprecated in favor of 
779    * <code>dispatchEvent()</code>.
780    */
781   public void deliverEvent(Event e)
782   {
783   }
784
785   /**
786    * Returns the component located at the specified point.  This is done
787    * by checking whether or not a child component claims to contain this
788    * point.  The first child component that does is returned.  If no
789    * child component claims the point, the container itself is returned,
790    * unless the point does not exist within this container, in which
791    * case <code>null</code> is returned.
792    *
793    * @param x The X coordinate of the point.
794    * @param y The Y coordinate of the point.
795    *
796    * @return The component containing the specified point, or
797    * <code>null</code> if there is no such point.
798    */
799   public Component getComponentAt (int x, int y)
800   {
801     if (! contains (x, y))
802       return null;
803     for (int i = 0; i < ncomponents; ++i)
804       {
805         // Ignore invisible children...
806         if (!component[i].isVisible())
807           continue;
808
809         int x2 = x - component[i].x;
810         int y2 = y - component[i].y;
811         if (component[i].contains (x2, y2))
812           return component[i];
813       }
814     return this;
815   }
816
817   /**
818    * Returns the component located at the specified point.  This is done
819    * by checking whether or not a child component claims to contain this
820    * point.  The first child component that does is returned.  If no
821    * child component claims the point, the container itself is returned,
822    * unless the point does not exist within this container, in which
823    * case <code>null</code> is returned.
824    *
825    * @param point The point to return the component at.
826    *
827    * @return The component containing the specified point, or <code>null</code>
828    * if there is no such point.
829    *
830    * @deprecated This method is deprecated in favor of
831    * <code>getComponentAt(int, int)</code>.
832    */
833   public Component locate(int x, int y)
834   {
835     return getComponentAt(x, y);
836   }
837
838   /**
839    * Returns the component located at the specified point.  This is done
840    * by checking whether or not a child component claims to contain this
841    * point.  The first child component that does is returned.  If no
842    * child component claims the point, the container itself is returned,
843    * unless the point does not exist within this container, in which
844    * case <code>null</code> is returned.
845    *
846    * @param point The point to return the component at.
847    *
848    * @return The component containing the specified point, or <code>null</code>
849    * if there is no such point.
850    */
851   public Component getComponentAt(Point p)
852   {
853     return getComponentAt(p.x, p.y);
854   }
855
856   public Component findComponentAt (int x, int y)
857   {
858     if (! contains (x, y))
859       return null;
860
861     for (int i = 0; i < ncomponents; ++i)
862       {
863         // Ignore invisible children...
864         if (!component[i].isVisible())
865           continue;
866
867         int x2 = x - component[i].x;
868         int y2 = y - component[i].y;
869         // We don't do the contains() check right away because
870         // findComponentAt would redundantly do it first thing.
871         if (component[i] instanceof Container)
872           {
873             Container k = (Container) component[i];
874             Component r = k.findComponentAt (x2, y2);
875             if (r != null)
876               return r;
877           }
878         else if (component[i].contains (x2, y2))
879           return component[i];
880       }
881
882     return this;
883   }
884
885   public Component findComponentAt(Point p)
886   {
887     return findComponentAt(p.x, p.y);
888   }
889
890   /**
891    * Called when this container is added to another container to inform it
892    * to create its peer.  Peers for any child components will also be
893    * created.
894    */
895   public void addNotify ()
896   {
897     if (peer == null)
898       {
899         addNotifyContainerChildren ();
900         super.addNotify();
901       }
902   }
903
904   private void addNotifyContainerChildren()
905   {
906     for (int i = ncomponents;  --i >= 0; )
907       {
908         component[i].addNotify();
909         if (component[i].isLightweight())
910           enableEvents(component[i].eventMask);
911       }
912   }
913
914   /**
915    * Called when this container is removed from its parent container to
916    * inform it to destroy its peer.  This causes the peers of all child
917    * component to be destroyed as well.
918    */
919   public void removeNotify()
920   {
921     for (int i = 0; i < ncomponents; ++i)
922       component[i].removeNotify ();
923     super.removeNotify();
924   }
925
926   /**
927    * Tests whether or not the specified component is contained within
928    * this components subtree.
929    *
930    * @param component The component to test.
931    *
932    * @return <code>true</code> if this container is an ancestor of the
933    * specified component, <code>false</code>.
934    */
935   public boolean isAncestorOf (Component comp)
936   {
937     for (;;)
938       {
939         if (comp == null)
940           return false;
941         if (comp == this)
942           return true;
943         comp = comp.getParent();
944       }
945   }
946
947   /**
948    * Returns a string representing the state of this container for
949    * debugging purposes.
950    *
951    * @return A string representing the state of this container.
952    */
953   protected String paramString()
954   {
955     String param = super.paramString();
956     if (layoutMgr != null)
957       param = param + "," + layoutMgr.getClass().getName();
958
959     return param;
960   }
961
962   /**
963    * Writes a listing of this container to the specified stream starting
964    * at the specified indentation point.
965    *
966    * @param stream The <code>PrintStream</code> to write to.
967    * @param indent The indentation point.
968    */
969   public void list (PrintStream out, int indent)
970   {
971     super.list (out, indent);
972     for (int i = 0; i < ncomponents; ++i)
973       component[i].list (out, indent + 2);
974   }
975
976   /**
977    * Writes a listing of this container to the specified stream starting
978    * at the specified indentation point.
979    *
980    * @param stream The <code>PrintWriter</code> to write to.
981    * @param indent The indentation point.
982    */
983   public void list(PrintWriter out, int indent)
984   {
985     super.list (out, indent);
986     for (int i = 0; i < ncomponents; ++i)
987       component[i].list (out, indent + 2);
988   }
989
990
991   /* The following classes are used in concert with the
992      visitChildren() method to implement all the graphics operations
993      that requires traversal of the containment hierarchy. */
994
995   abstract static class GfxVisitor
996   {
997     public abstract void visit(Component c, Graphics gfx);
998   }
999
1000   static class GfxPaintVisitor extends GfxVisitor
1001   {
1002     public void visit(Component c, Graphics gfx) { c.paint(gfx); }
1003     public static final GfxVisitor INSTANCE = new GfxPaintVisitor();
1004   }
1005
1006   static class GfxPrintVisitor extends GfxVisitor
1007   {
1008     public void visit(Component c, Graphics gfx) { c.print(gfx); }
1009     public static final GfxVisitor INSTANCE = new GfxPrintVisitor();
1010   }
1011
1012   static class GfxPaintAllVisitor extends GfxVisitor
1013   {
1014     public void visit(Component c, Graphics gfx) { c.paintAll(gfx); }
1015     public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor();
1016   }
1017
1018   static class GfxPrintAllVisitor extends GfxVisitor
1019   {
1020     public void visit(Component c, Graphics gfx) { c.printAll(gfx); }
1021     public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor();
1022   }
1023
1024   // This is used to implement Component.transferFocus.
1025   Component findNextFocusComponent (Component child)
1026   {
1027     int start, end;
1028     if (child != null)
1029       {
1030         for (start = 0; start < ncomponents; ++start)
1031           {
1032             if (component[start] == child)
1033               break;
1034           }
1035         end = start;
1036         // This special case lets us be sure to terminate.
1037         if (end == 0)
1038           end = ncomponents;
1039         ++start;
1040       }
1041     else
1042       {
1043         start = 0;
1044         end = ncomponents;
1045       }
1046
1047     for (int j = start; j != end; ++j)
1048       {
1049         if (j >= ncomponents)
1050           {
1051             // The JCL says that we should wrap here.  However, that
1052             // seems wrong.  To me it seems that focus order should be
1053             // global within in given window.  So instead if we reach
1054             // the end we try to look in our parent, if we have one.
1055             if (parent != null)
1056               return parent.findNextFocusComponent (this);
1057             j -= ncomponents;
1058           }
1059         if (component[j] instanceof Container)
1060           {
1061             Component c = component[j];
1062             c = c.findNextFocusComponent (null);
1063             if (c != null)
1064               return c;
1065           }
1066         else if (component[j].isFocusTraversable ())
1067           return component[j];
1068       }
1069
1070     return null;
1071   }
1072 }