1 /* Container.java -- parent container class in AWT
2 Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation
4 This file is part of GNU Classpath.
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)
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.
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., 59 Temple Place, Suite 330, Boston, MA
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
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. */
40 import java.awt.event.AWTEventListener;
41 import java.awt.event.ContainerEvent;
42 import java.awt.event.ContainerListener;
43 import java.awt.event.MouseEvent;
44 import java.awt.event.KeyEvent;
45 import java.awt.peer.ContainerPeer;
46 import java.awt.peer.LightweightPeer;
47 import java.beans.PropertyChangeListener;
48 import java.beans.PropertyChangeSupport;
49 import java.io.PrintStream;
50 import java.io.PrintWriter;
51 import java.io.Serializable;
52 import java.util.EventListener;
54 import javax.accessibility.Accessible;
55 import javax.swing.SwingUtilities;
58 * A generic window toolkit object that acts as a container for other objects.
59 * Components are tracked in a list, and new elements are at the end of the
60 * list or bottom of the stacking order.
62 * @author original author unknown
63 * @author Eric Blake <ebb9@email.byu.edu>
67 * @status still missing 1.4 support
69 public class Container extends Component
72 * Compatible with JDK 1.0+.
74 private static final long serialVersionUID = 4613797578919906343L;
76 /* Serialized fields from the serialization spec. */
78 Component[] component;
79 LayoutManager layoutMgr;
81 LightweightDispatcher dispatcher;
88 boolean focusCycleRoot;
90 int containerSerializedDataVersion;
92 /* Anything else is non-serializable, and should be declared "transient". */
93 transient ContainerListener containerListener;
94 transient PropertyChangeSupport changeSupport;
97 * Default constructor for subclasses.
104 * Returns the number of components in this container.
106 * @return The number of components in this container.
108 public int getComponentCount()
110 return countComponents ();
114 * Returns the number of components in this container.
116 * @return The number of components in this container.
118 * @deprecated use {@link #getComponentCount()} instead
120 public int countComponents()
126 * Returns the component at the specified index.
128 * @param index The index of the component to retrieve.
130 * @return The requested component.
132 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid
134 public Component getComponent(int n)
136 synchronized (getTreeLock ())
138 if (n < 0 || n >= ncomponents)
139 throw new ArrayIndexOutOfBoundsException("no such component");
146 * Returns an array of the components in this container.
148 * @return The components in this container.
150 public Component[] getComponents()
152 synchronized (getTreeLock ())
154 Component[] result = new Component[ncomponents];
157 System.arraycopy(component, 0, result, 0, ncomponents);
164 * Swaps the components at position i and j, in the container.
167 protected void swapComponents (int i, int j)
169 synchronized (getTreeLock ())
172 || i >= component.length
174 || j >= component.length)
175 throw new ArrayIndexOutOfBoundsException ();
176 Component tmp = component[i];
177 component[i] = component[j];
183 * Returns the insets for this container, which is the space used for
184 * borders, the margin, etc.
186 * @return The insets for this container.
188 public Insets getInsets()
194 * Returns the insets for this container, which is the space used for
195 * borders, the margin, etc.
197 * @return The insets for this container.
198 * @deprecated use {@link #getInsets()} instead
200 public Insets insets()
203 return new Insets (0, 0, 0, 0);
205 return ((ContainerPeer) peer).getInsets ();
209 * Adds the specified component to this container at the end of the
212 * @param component The component to add to the container.
214 * @return The same component that was added.
216 public Component add(Component comp)
218 addImpl(comp, null, -1);
223 * Adds the specified component to the container at the end of the
224 * component list. This method should not be used. Instead, use
225 * <code>add(Component, Object)</code>.
227 * @param name The name of the component to be added.
228 * @param component The component to be added.
230 * @return The same component that was added.
232 * @see #add(Component,Object)
234 public Component add(String name, Component comp)
236 addImpl(comp, name, -1);
241 * Adds the specified component to this container at the specified index
242 * in the component list.
244 * @param component The component to be added.
245 * @param index The index in the component list to insert this child
246 * at, or -1 to add at the end of the list.
248 * @return The same component that was added.
250 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
252 public Component add(Component comp, int index)
254 addImpl(comp, null, index);
259 * Adds the specified component to this container at the end of the
260 * component list. The layout manager will use the specified constraints
261 * when laying out this component.
263 * @param component The component to be added to this container.
264 * @param constraints The layout constraints for this component.
266 public void add(Component comp, Object constraints)
268 addImpl(comp, constraints, -1);
272 * Adds the specified component to this container at the specified index
273 * in the component list. The layout manager will use the specified
274 * constraints when layout out this component.
276 * @param component The component to be added.
277 * @param constraints The layout constraints for this component.
278 * @param index The index in the component list to insert this child
279 * at, or -1 to add at the end of the list.
281 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
283 public void add(Component comp, Object constraints, int index)
285 addImpl(comp, constraints, index);
289 * This method is called by all the <code>add()</code> methods to perform
290 * the actual adding of the component. Subclasses who wish to perform
291 * their own processing when a component is added should override this
292 * method. Any subclass doing this must call the superclass version of
293 * this method in order to ensure proper functioning of the container.
295 * @param component The component to be added.
296 * @param constraints The layout constraints for this component, or
297 * <code>null</code> if there are no constraints.
298 * @param index The index in the component list to insert this child
299 * at, or -1 to add at the end of the list.
301 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
303 protected void addImpl(Component comp, Object constraints, int index)
305 synchronized (getTreeLock ())
307 if (index > ncomponents
308 || (index < 0 && index != -1)
309 || comp instanceof Window
310 || (comp instanceof Container
311 && ((Container) comp).isAncestorOf(this)))
312 throw new IllegalArgumentException();
314 // Reparent component, and make sure component is instantiated if
316 if (comp.parent != null)
317 comp.parent.remove(comp);
323 if (comp.isLightweight ())
325 enableEvents (comp.eventMask);
326 if (!isLightweight ())
327 enableEvents (AWTEvent.PAINT_EVENT_MASK);
333 if (component == null)
334 component = new Component[4]; // FIXME, better initial size?
336 // This isn't the most efficient implementation. We could do less
337 // copying when growing the array. It probably doesn't matter.
338 if (ncomponents >= component.length)
340 int nl = component.length * 2;
341 Component[] c = new Component[nl];
342 System.arraycopy(component, 0, c, 0, ncomponents);
347 component[ncomponents++] = comp;
350 System.arraycopy(component, index, component, index + 1,
351 ncomponents - index);
352 component[index] = comp;
356 // Notify the layout manager.
357 if (layoutMgr != null)
359 if (layoutMgr instanceof LayoutManager2)
361 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
362 lm2.addLayoutComponent(comp, constraints);
364 else if (constraints instanceof String)
365 layoutMgr.addLayoutComponent((String) constraints, comp);
367 layoutMgr.addLayoutComponent(null, comp);
370 // Post event to notify of adding the container.
371 ContainerEvent ce = new ContainerEvent(this,
372 ContainerEvent.COMPONENT_ADDED,
374 getToolkit().getSystemEventQueue().postEvent(ce);
379 * Removes the component at the specified index from this container.
381 * @param index The index of the component to remove.
383 public void remove(int index)
385 synchronized (getTreeLock ())
387 Component r = component[index];
391 System.arraycopy(component, index + 1, component, index,
392 ncomponents - index - 1);
393 component[--ncomponents] = null;
397 if (layoutMgr != null)
398 layoutMgr.removeLayoutComponent(r);
400 // Post event to notify of adding the container.
401 ContainerEvent ce = new ContainerEvent(this,
402 ContainerEvent.COMPONENT_REMOVED,
404 getToolkit().getSystemEventQueue().postEvent(ce);
409 * Removes the specified component from this container.
411 * @return component The component to remove from this container.
413 public void remove(Component comp)
415 synchronized (getTreeLock ())
417 for (int i = 0; i < ncomponents; ++i)
419 if (component[i] == comp)
429 * Removes all components from this container.
431 public void removeAll()
433 synchronized (getTreeLock ())
435 while (ncomponents > 0)
441 * Returns the current layout manager for this container.
443 * @return The layout manager for this container.
445 public LayoutManager getLayout()
451 * Sets the layout manager for this container to the specified layout
454 * @param mgr The new layout manager for this container.
456 public void setLayout(LayoutManager mgr)
463 * Layout the components in this container.
465 public void doLayout()
471 * Layout the components in this container.
473 * @deprecated use {@link #doLayout()} instead
477 if (layoutMgr != null)
478 layoutMgr.layoutContainer (this);
482 * Invalidates this container to indicate that it (and all parent
483 * containers) need to be laid out.
485 public void invalidate()
491 * Re-lays out the components in this container.
493 public void validate()
495 synchronized (getTreeLock ())
497 if (! isValid() && peer != null)
505 * Recursively validates the container tree, recomputing any invalid
508 protected void validateTree()
513 ContainerPeer cPeer = null;
514 if (peer != null && ! (peer instanceof LightweightPeer))
516 cPeer = (ContainerPeer) peer;
517 cPeer.beginValidate();
521 for (int i = 0; i < ncomponents; ++i)
523 Component comp = component[i];
524 if (! comp.isValid())
526 if (comp instanceof Container)
528 ((Container) comp).validateTree();
532 component[i].validate();
537 /* children will call invalidate() when they are layed out. It
538 is therefore imporant that valid is not set to true
539 before after the children has been layed out. */
546 public void setFont(Font f)
549 // FIXME, should invalidate all children with font == null
553 * Returns the preferred size of this container.
555 * @return The preferred size of this container.
557 public Dimension getPreferredSize()
559 return preferredSize ();
563 * Returns the preferred size of this container.
565 * @return The preferred size of this container.
567 * @deprecated use {@link #getPreferredSize()} instead
569 public Dimension preferredSize()
571 if (layoutMgr != null)
572 return layoutMgr.preferredLayoutSize (this);
574 return super.preferredSize ();
578 * Returns the minimum size of this container.
580 * @return The minimum size of this container.
582 public Dimension getMinimumSize()
584 return minimumSize ();
588 * Returns the minimum size of this container.
590 * @return The minimum size of this container.
592 * @deprecated use {@link #getMinimumSize()} instead
594 public Dimension minimumSize()
596 if (layoutMgr != null)
597 return layoutMgr.minimumLayoutSize (this);
599 return super.minimumSize ();
603 * Returns the maximum size of this container.
605 * @return The maximum size of this container.
607 public Dimension getMaximumSize()
609 if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
611 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
612 return lm2.maximumLayoutSize(this);
615 return super.getMaximumSize();
619 * Returns the preferred alignment along the X axis. This is a value
620 * between 0 and 1 where 0 represents alignment flush left and
621 * 1 means alignment flush right, and 0.5 means centered.
623 * @return The preferred alignment along the X axis.
625 public float getAlignmentX()
627 if (layoutMgr instanceof LayoutManager2)
629 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
630 return lm2.getLayoutAlignmentX(this);
633 return super.getAlignmentX();
637 * Returns the preferred alignment along the Y axis. This is a value
638 * between 0 and 1 where 0 represents alignment flush top and
639 * 1 means alignment flush bottom, and 0.5 means centered.
641 * @return The preferred alignment along the Y axis.
643 public float getAlignmentY()
645 if (layoutMgr instanceof LayoutManager2)
647 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
648 return lm2.getLayoutAlignmentY(this);
651 return super.getAlignmentY();
655 * Paints this container. The implementation of this method in this
656 * class forwards to any lightweight components in this container. If
657 * this method is subclassed, this method should still be invoked as
658 * a superclass method so that lightweight components are properly
661 * @param graphics The graphics context for this paint job.
663 public void paint(Graphics g)
667 // Visit heavyweights as well, in case they were
668 // erased when we cleared the background for this container.
669 visitChildren(g, GfxPaintVisitor.INSTANCE, false);
673 * Updates this container. The implementation of this method in this
674 * class forwards to any lightweight components in this container. If
675 * this method is subclassed, this method should still be invoked as
676 * a superclass method so that lightweight components are properly
679 * @param graphics The graphics context for this update.
681 public void update(Graphics g)
687 * Prints this container. The implementation of this method in this
688 * class forwards to any lightweight components in this container. If
689 * this method is subclassed, this method should still be invoked as
690 * a superclass method so that lightweight components are properly
693 * @param graphics The graphics context for this print job.
695 public void print(Graphics g)
698 visitChildren(g, GfxPrintVisitor.INSTANCE, true);
702 * Paints all of the components in this container.
704 * @param graphics The graphics context for this paint job.
706 public void paintComponents(Graphics g)
709 visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
713 * Prints all of the components in this container.
715 * @param graphics The graphics context for this print job.
717 public void printComponents(Graphics g)
720 visitChildren(g, GfxPrintAllVisitor.INSTANCE, true);
724 * Adds the specified container listener to this object's list of
725 * container listeners.
727 * @param listener The listener to add.
729 public synchronized void addContainerListener(ContainerListener l)
731 containerListener = AWTEventMulticaster.add(containerListener, l);
735 * Removes the specified container listener from this object's list of
736 * container listeners.
738 * @param listener The listener to remove.
740 public synchronized void removeContainerListener(ContainerListener l)
742 containerListener = AWTEventMulticaster.remove(containerListener, l);
748 public synchronized ContainerListener[] getContainerListeners()
750 return (ContainerListener[])
751 AWTEventMulticaster.getListeners(containerListener,
752 ContainerListener.class);
756 * Returns an array of all the objects currently registered as FooListeners
757 * upon this Container. FooListeners are registered using the addFooListener
760 * @exception ClassCastException If listenerType doesn't specify a class or
761 * interface that implements @see java.util.EventListener.
765 public EventListener[] getListeners(Class listenerType)
767 if (listenerType == ContainerListener.class)
768 return getContainerListeners();
769 return super.getListeners(listenerType);
773 * Processes the specified event. This method calls
774 * <code>processContainerEvent()</code> if this method is a
775 * <code>ContainerEvent</code>, otherwise it calls the superclass
778 * @param event The event to be processed.
780 protected void processEvent(AWTEvent e)
782 if (e instanceof ContainerEvent)
783 processContainerEvent((ContainerEvent) e);
785 super.processEvent(e);
789 * Called when a container event occurs if container events are enabled.
790 * This method calls any registered listeners.
792 * @param event The event that occurred.
794 protected void processContainerEvent(ContainerEvent e)
796 if (containerListener == null)
800 case ContainerEvent.COMPONENT_ADDED:
801 containerListener.componentAdded(e);
804 case ContainerEvent.COMPONENT_REMOVED:
805 containerListener.componentRemoved(e);
811 * AWT 1.0 event processor.
813 * @param event The event that occurred.
815 * @deprecated use {@link #dispatchEvent(AWTEvent)} instead
817 public void deliverEvent(Event e)
822 * Returns the component located at the specified point. This is done
823 * by checking whether or not a child component claims to contain this
824 * point. The first child component that does is returned. If no
825 * child component claims the point, the container itself is returned,
826 * unless the point does not exist within this container, in which
827 * case <code>null</code> is returned.
829 * @param x The X coordinate of the point.
830 * @param y The Y coordinate of the point.
832 * @return The component containing the specified point, or
833 * <code>null</code> if there is no such point.
835 public Component getComponentAt(int x, int y)
837 return locate (x, y);
841 * Returns the component located at the specified point. This is done
842 * by checking whether or not a child component claims to contain this
843 * point. The first child component that does is returned. If no
844 * child component claims the point, the container itself is returned,
845 * unless the point does not exist within this container, in which
846 * case <code>null</code> is returned.
848 * @param point The point to return the component at.
850 * @return The component containing the specified point, or <code>null</code>
851 * if there is no such point.
853 * @deprecated use {@link #getComponentAt(int, int)} instead
855 public Component locate(int x, int y)
857 synchronized (getTreeLock ())
859 if (!contains (x, y))
861 for (int i = 0; i < ncomponents; ++i)
863 // Ignore invisible children...
864 if (!component[i].isVisible ())
867 int x2 = x - component[i].x;
868 int y2 = y - component[i].y;
869 if (component[i].contains (x2, y2))
877 * Returns the component located at the specified point. This is done
878 * by checking whether or not a child component claims to contain this
879 * point. The first child component that does is returned. If no
880 * child component claims the point, the container itself is returned,
881 * unless the point does not exist within this container, in which
882 * case <code>null</code> is returned.
884 * @param point The point to return the component at.
885 * @return The component containing the specified point, or <code>null</code>
886 * if there is no such point.
888 public Component getComponentAt(Point p)
890 return getComponentAt (p.x, p.y);
893 public Component findComponentAt(int x, int y)
895 synchronized (getTreeLock ())
897 if (! contains(x, y))
900 for (int i = 0; i < ncomponents; ++i)
902 // Ignore invisible children...
903 if (!component[i].isVisible())
906 int x2 = x - component[i].x;
907 int y2 = y - component[i].y;
908 // We don't do the contains() check right away because
909 // findComponentAt would redundantly do it first thing.
910 if (component[i] instanceof Container)
912 Container k = (Container) component[i];
913 Component r = k.findComponentAt(x2, y2);
917 else if (component[i].contains(x2, y2))
925 public Component findComponentAt(Point p)
927 return findComponentAt(p.x, p.y);
931 * Called when this container is added to another container to inform it
932 * to create its peer. Peers for any child components will also be
935 public void addNotify()
938 addNotifyContainerChildren();
942 * Called when this container is removed from its parent container to
943 * inform it to destroy its peer. This causes the peers of all child
944 * component to be destroyed as well.
946 public void removeNotify()
948 synchronized (getTreeLock ())
950 for (int i = 0; i < ncomponents; ++i)
951 component[i].removeNotify();
952 super.removeNotify();
957 * Tests whether or not the specified component is contained within
958 * this components subtree.
960 * @param component The component to test.
962 * @return <code>true</code> if this container is an ancestor of the
963 * specified component, <code>false</code> otherwise.
965 public boolean isAncestorOf(Component comp)
967 synchronized (getTreeLock ())
975 comp = comp.getParent();
981 * Returns a string representing the state of this container for
982 * debugging purposes.
984 * @return A string representing the state of this container.
986 protected String paramString()
988 String param = super.paramString();
989 if (layoutMgr != null)
990 param = param + "," + layoutMgr.getClass().getName();
996 * Writes a listing of this container to the specified stream starting
997 * at the specified indentation point.
999 * @param stream The <code>PrintStream</code> to write to.
1000 * @param indent The indentation point.
1002 public void list(PrintStream out, int indent)
1004 synchronized (getTreeLock ())
1006 super.list(out, indent);
1007 for (int i = 0; i < ncomponents; ++i)
1008 component[i].list(out, indent + 2);
1013 * Writes a listing of this container to the specified stream starting
1014 * at the specified indentation point.
1016 * @param stream The <code>PrintWriter</code> to write to.
1017 * @param indent The indentation point.
1019 public void list(PrintWriter out, int indent)
1021 synchronized (getTreeLock ())
1023 super.list(out, indent);
1024 for (int i = 0; i < ncomponents; ++i)
1025 component[i].list(out, indent + 2);
1030 * Sets the focus traversal keys for a given traversal operation for this
1033 * @exception IllegalArgumentException If id is not one of
1034 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1035 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1036 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1037 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS,
1038 * or if keystrokes contains null, or if any Object in keystrokes is not an
1039 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any
1040 * keystroke already maps to another focus traversal operation for this
1045 public void setFocusTraversalKeys(int id, Set keystrokes)
1047 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1048 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1049 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1050 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1051 throw new IllegalArgumentException ();
1053 if (keystrokes == null)
1054 throw new IllegalArgumentException ();
1056 throw new Error ("not implemented");
1060 * Returns the Set of focus traversal keys for a given traversal operation for
1063 * @exception IllegalArgumentException If id is not one of
1064 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1065 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1066 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1067 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1071 public Set getFocusTraversalKeys(int id)
1073 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1074 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1075 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1076 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1077 throw new IllegalArgumentException ();
1083 * Returns whether the Set of focus traversal keys for the given focus
1084 * traversal operation has been explicitly defined for this Container.
1085 * If this method returns false, this Container is inheriting the Set from
1086 * an ancestor, or from the current KeyboardFocusManager.
1088 * @exception IllegalArgumentException If id is not one of
1089 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1090 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1091 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1092 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1096 public boolean areFocusTraversalKeysSet(int id)
1098 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1099 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1100 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1101 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1102 throw new IllegalArgumentException ();
1107 public boolean isFocusCycleRoot(Container c)
1112 public void transferFocusBackward()
1116 public void setFocusTraversalPolicy(FocusTraversalPolicy policy)
1120 public FocusTraversalPolicy getFocusTraversalPolicy()
1125 public boolean isFocusTraversalPolicySet()
1130 public void setFocusCycleRoot(boolean focusCycleRoot)
1134 public boolean isFocusCycleRoot()
1139 public void transferFocusDownCycle()
1144 * Sets the ComponentOrientation property of this container and all components
1145 * contained within it.
1147 * @exception NullPointerException If orientation is null
1151 public void applyComponentOrientation (ComponentOrientation orientation)
1153 if (orientation == null)
1154 throw new NullPointerException ();
1157 public void addPropertyChangeListener (PropertyChangeListener listener)
1159 if (listener == null)
1162 if (changeSupport == null)
1163 changeSupport = new PropertyChangeSupport (this);
1165 changeSupport.addPropertyChangeListener (listener);
1168 public void addPropertyChangeListener (String name,
1169 PropertyChangeListener listener)
1171 if (listener == null)
1174 if (changeSupport == null)
1175 changeSupport = new PropertyChangeSupport (this);
1177 changeSupport.addPropertyChangeListener (name, listener);
1180 // Hidden helper methods.
1183 * Perform a graphics operation on the children of this container.
1184 * For each applicable child, the visitChild() method will be called
1185 * to perform the graphics operation.
1187 * @param gfx The graphics object that will be used to derive new
1188 * graphics objects for the children.
1190 * @param visitor Object encapsulating the graphics operation that
1191 * should be performed.
1193 * @param lightweightOnly If true, only lightweight components will
1196 private void visitChildren(Graphics gfx, GfxVisitor visitor,
1197 boolean lightweightOnly)
1199 synchronized (getTreeLock ())
1201 for (int i = ncomponents - 1; i >= 0; --i)
1203 Component comp = component[i];
1204 // If we're visiting heavyweights as well,
1205 // don't recurse into Containers here. This avoids
1206 // painting the same nested child multiple times.
1207 boolean applicable = comp.isVisible()
1208 && (comp.isLightweight()
1209 || !lightweightOnly && ! (comp instanceof Container));
1212 visitChild(gfx, visitor, comp);
1218 * Perform a graphics operation on a child. A translated and clipped
1219 * graphics object will be created, and the visit() method of the
1220 * visitor will be called to perform the operation.
1222 * @param gfx The graphics object that will be used to derive new
1223 * graphics objects for the child.
1225 * @param visitor Object encapsulating the graphics operation that
1226 * should be performed.
1228 * @param comp The child component that should be visited.
1230 private void visitChild(Graphics gfx, GfxVisitor visitor,
1233 Rectangle bounds = comp.getBounds();
1234 Rectangle oldClip = gfx.getClipBounds();
1235 if (oldClip == null)
1237 Rectangle clip = oldClip.intersection(bounds);
1239 if (clip.isEmpty()) return;
1241 boolean clipped = false;
1242 boolean translated = false;
1245 gfx.setClip(clip.x, clip.y, clip.width, clip.height);
1247 gfx.translate(bounds.x, bounds.y);
1249 visitor.visit(comp, gfx);
1254 gfx.translate (-bounds.x, -bounds.y);
1256 gfx.setClip (oldClip.x, oldClip.y, oldClip.width, oldClip.height);
1260 void dispatchEventImpl(AWTEvent e)
1262 // Give lightweight dispatcher a chance to handle it.
1263 if (dispatcher != null
1264 && dispatcher.handleEvent (e))
1267 if ((e.id <= ContainerEvent.CONTAINER_LAST
1268 && e.id >= ContainerEvent.CONTAINER_FIRST)
1269 && (containerListener != null
1270 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
1273 super.dispatchEventImpl(e);
1276 // This is used to implement Component.transferFocus.
1277 Component findNextFocusComponent(Component child)
1279 synchronized (getTreeLock ())
1284 for (start = 0; start < ncomponents; ++start)
1286 if (component[start] == child)
1290 // This special case lets us be sure to terminate.
1301 for (int j = start; j != end; ++j)
1303 if (j >= ncomponents)
1305 // The JCL says that we should wrap here. However, that
1306 // seems wrong. To me it seems that focus order should be
1307 // global within in given window. So instead if we reach
1308 // the end we try to look in our parent, if we have one.
1310 return parent.findNextFocusComponent(this);
1313 if (component[j] instanceof Container)
1315 Component c = component[j];
1316 c = c.findNextFocusComponent(null);
1320 else if (component[j].isFocusTraversable())
1321 return component[j];
1328 private void addNotifyContainerChildren()
1330 synchronized (getTreeLock ())
1332 for (int i = ncomponents; --i >= 0; )
1334 component[i].addNotify();
1335 if (component[i].isLightweight ())
1338 // If we're not lightweight, and we just got a lightweight
1339 // child, we need a lightweight dispatcher to feed it events.
1340 if (! this.isLightweight()
1341 && dispatcher == null)
1343 dispatcher = new LightweightDispatcher (this);
1344 dispatcher.enableEvents (component[i].eventMask);
1348 enableEvents(component[i].eventMask);
1349 if (peer != null && !isLightweight ())
1350 enableEvents (AWTEvent.PAINT_EVENT_MASK);
1358 /* The following classes are used in concert with the
1359 visitChildren() method to implement all the graphics operations
1360 that requires traversal of the containment hierarchy. */
1362 abstract static class GfxVisitor
1364 public abstract void visit(Component c, Graphics gfx);
1367 static class GfxPaintVisitor extends GfxVisitor
1369 public void visit(Component c, Graphics gfx) { c.paint(gfx); }
1370 public static final GfxVisitor INSTANCE = new GfxPaintVisitor();
1373 static class GfxPrintVisitor extends GfxVisitor
1375 public void visit(Component c, Graphics gfx) { c.print(gfx); }
1376 public static final GfxVisitor INSTANCE = new GfxPrintVisitor();
1379 static class GfxPaintAllVisitor extends GfxVisitor
1381 public void visit(Component c, Graphics gfx) { c.paintAll(gfx); }
1382 public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor();
1385 static class GfxPrintAllVisitor extends GfxVisitor
1387 public void visit(Component c, Graphics gfx) { c.printAll(gfx); }
1388 public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor();
1392 * This class provides accessibility support for subclasses of container.
1394 * @author Eric Blake <ebb9@email.byu.edu>
1398 protected class AccessibleAWTContainer extends AccessibleAWTComponent
1401 * Compatible with JDK 1.4+.
1403 private static final long serialVersionUID = 5081320404842566097L;
1406 * The handler to fire PropertyChange when children are added or removed.
1408 * @serial the handler for property changes
1410 protected ContainerListener accessibleContainerHandler
1411 = new AccessibleContainerHandler();
1414 * The default constructor.
1416 protected AccessibleAWTContainer()
1418 Container.this.addContainerListener(accessibleContainerHandler);
1422 * Return the number of accessible children of the containing accessible
1423 * object (at most the total number of its children).
1425 * @return the number of accessible children
1427 public int getAccessibleChildrenCount()
1429 synchronized (getTreeLock ())
1432 int i = component == null ? 0 : component.length;
1434 if (component[i] instanceof Accessible)
1441 * Return the nth accessible child of the containing accessible object.
1443 * @param i the child to grab, zero-based
1444 * @return the accessible child, or null
1446 public Accessible getAccessibleChild(int i)
1448 synchronized (getTreeLock ())
1450 if (component == null)
1453 while (i >= 0 && ++index < component.length)
1454 if (component[index] instanceof Accessible)
1457 return (Accessible) component[index];
1463 * Return the accessible child located at point (in the parent's
1464 * coordinates), if one exists.
1466 * @param p the point to look at
1468 * @return an accessible object at that point, or null
1470 * @throws NullPointerException if p is null
1472 public Accessible getAccessibleAt(Point p)
1474 Component c = getComponentAt(p.x, p.y);
1475 return c != Container.this && c instanceof Accessible ? (Accessible) c
1480 * This class fires a <code>PropertyChange</code> listener, if registered,
1481 * when children are added or removed from the enclosing accessible object.
1483 * @author Eric Blake <ebb9@email.byu.edu>
1487 protected class AccessibleContainerHandler implements ContainerListener
1490 * Default constructor.
1492 protected AccessibleContainerHandler()
1497 * Fired when a component is added; forwards to the PropertyChange
1500 * @param e the container event for adding
1502 public void componentAdded(ContainerEvent e)
1504 AccessibleAWTContainer.this.firePropertyChange
1505 (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild());
1509 * Fired when a component is removed; forwards to the PropertyChange
1512 * @param e the container event for removing
1514 public void componentRemoved(ContainerEvent e)
1516 AccessibleAWTContainer.this.firePropertyChange
1517 (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null);
1519 } // class AccessibleContainerHandler
1520 } // class AccessibleAWTContainer
1521 } // class Container
1524 * There is a helper class implied from stack traces called
1525 * LightweightDispatcher, but since it is not part of the public API,
1526 * rather than mimic it exactly we write something which does "roughly
1530 class LightweightDispatcher implements Serializable
1532 private static final long serialVersionUID = 5184291520170872969L;
1533 private Container nativeContainer;
1534 private Component focus;
1535 private Cursor nativeCursor;
1536 private long eventMask;
1538 private transient Component mouseEventTarget;
1540 LightweightDispatcher(Container c)
1542 nativeContainer = c;
1545 void enableEvents(long l)
1550 void acquireComponentForMouseEvent(MouseEvent me)
1554 Component candidate = mouseEventTarget;
1556 while(candidate != null)
1558 if (candidate.isShowing())
1560 // Convert our point to the candidate's parent's space.
1561 Point cp = SwingUtilities.convertPoint(nativeContainer, x, y, candidate);
1563 // If the event lands inside candidate, we have a hit.
1564 if (candidate.contains(cp.x, cp.y))
1566 // If candidate has children, we refine the hit.
1567 if (candidate instanceof Container &&
1568 ((Container)candidate).getComponentCount() > 0)
1569 candidate = SwingUtilities.getDeepestComponentAt(candidate, cp.x, cp.y);
1573 // If candidate isn't showing or doesn't contain point, we back out a level.
1574 candidate = candidate.getParent();
1577 if (candidate == null)
1579 // We either lost, or never had, a candidate; acquire from our native.
1581 SwingUtilities.getDeepestComponentAt(nativeContainer, x, y);
1585 // If our candidate is new, inform the old target we're leaving.
1586 if (mouseEventTarget != null
1587 && mouseEventTarget.isShowing()
1588 && mouseEventTarget != candidate)
1591 SwingUtilities.convertPoint(nativeContainer,
1592 x, y, mouseEventTarget);
1593 MouseEvent exited = new MouseEvent (mouseEventTarget,
1594 MouseEvent.MOUSE_EXITED,
1598 me.getClickCount (),
1599 me.isPopupTrigger (),
1601 mouseEventTarget.dispatchEvent (exited);
1602 mouseEventTarget = null;
1605 // If we have a candidate, maybe enter it.
1606 if (candidate != null)
1608 if (candidate.isLightweight()
1609 && candidate.isShowing()
1610 && candidate != nativeContainer
1611 && candidate != mouseEventTarget)
1613 mouseEventTarget = candidate;
1614 Point cp = SwingUtilities.convertPoint(nativeContainer,
1616 MouseEvent entered = new MouseEvent (mouseEventTarget,
1617 MouseEvent.MOUSE_ENTERED,
1621 me.getClickCount (),
1622 me.isPopupTrigger (),
1624 mouseEventTarget.dispatchEvent (entered);
1629 boolean handleEvent(AWTEvent e)
1631 if ((eventMask & e.getID()) == 0)
1634 if (e instanceof MouseEvent)
1636 MouseEvent me = (MouseEvent) e;
1637 acquireComponentForMouseEvent(me);
1639 // Avoid dispatching an ENTERED event twice.
1640 if (mouseEventTarget != null
1641 && mouseEventTarget.isShowing()
1642 && e.getID() != MouseEvent.MOUSE_ENTERED)
1645 SwingUtilities.convertMouseEvent(nativeContainer, me,
1647 mouseEventTarget.dispatchEvent(newEvt);
1650 else if (e instanceof KeyEvent && focus != null)
1652 focus.processKeyEvent((KeyEvent) e);
1655 return e.isConsumed();
1658 } // class LightweightDispatcher