1 /* Container.java -- parent container class in AWT
2 Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor, 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. */
41 import java
.awt
.event
.ComponentListener
;
42 import java
.awt
.event
.ContainerEvent
;
43 import java
.awt
.event
.ContainerListener
;
44 import java
.awt
.event
.KeyEvent
;
45 import java
.awt
.event
.MouseEvent
;
46 import java
.awt
.peer
.ComponentPeer
;
47 import java
.awt
.peer
.ContainerPeer
;
48 import java
.awt
.peer
.LightweightPeer
;
49 import java
.beans
.PropertyChangeListener
;
50 import java
.beans
.PropertyChangeSupport
;
51 import java
.io
.IOException
;
52 import java
.io
.ObjectInputStream
;
53 import java
.io
.ObjectOutputStream
;
54 import java
.io
.PrintStream
;
55 import java
.io
.PrintWriter
;
56 import java
.io
.Serializable
;
57 import java
.util
.Collections
;
58 import java
.util
.EventListener
;
59 import java
.util
.HashSet
;
60 import java
.util
.Iterator
;
63 import javax
.accessibility
.Accessible
;
65 import gnu
.java
.awt
.AWTUtilities
;
68 * A generic window toolkit object that acts as a container for other objects.
69 * Components are tracked in a list, and new elements are at the end of the
70 * list or bottom of the stacking order.
72 * @author original author unknown
73 * @author Eric Blake (ebb9@email.byu.edu)
77 * @status still missing 1.4 support
79 public class Container
extends Component
82 * Compatible with JDK 1.0+.
84 private static final long serialVersionUID
= 4613797578919906343L;
86 /* Serialized fields from the serialization spec. */
88 Component
[] component
;
89 LayoutManager layoutMgr
;
91 LightweightDispatcher dispatcher
;
98 boolean focusCycleRoot
;
100 int containerSerializedDataVersion
;
102 /* Anything else is non-serializable, and should be declared "transient". */
103 transient ContainerListener containerListener
;
104 transient PropertyChangeSupport changeSupport
;
106 /** The focus traversal policy that determines how focus is
107 transferred between this Container and its children. */
108 private FocusTraversalPolicy focusTraversalPolicy
;
111 * The focus traversal keys, if not inherited from the parent or default
112 * keyboard manager. These sets will contain only AWTKeyStrokes that
113 * represent press and release events to use as focus control.
115 * @see #getFocusTraversalKeys(int)
116 * @see #setFocusTraversalKeys(int, Set)
119 transient Set
[] focusTraversalKeys
;
122 * Default constructor for subclasses.
126 // Nothing to do here.
130 * Returns the number of components in this container.
132 * @return The number of components in this container.
134 public int getComponentCount()
136 return countComponents ();
140 * Returns the number of components in this container.
142 * @return The number of components in this container.
144 * @deprecated use {@link #getComponentCount()} instead
146 public int countComponents()
152 * Returns the component at the specified index.
154 * @param n The index of the component to retrieve.
156 * @return The requested component.
158 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid
160 public Component
getComponent(int n
)
162 synchronized (getTreeLock ())
164 if (n
< 0 || n
>= ncomponents
)
165 throw new ArrayIndexOutOfBoundsException("no such component");
172 * Returns an array of the components in this container.
174 * @return The components in this container.
176 public Component
[] getComponents()
178 synchronized (getTreeLock ())
180 Component
[] result
= new Component
[ncomponents
];
183 System
.arraycopy(component
, 0, result
, 0, ncomponents
);
190 * Swaps the components at position i and j, in the container.
193 protected void swapComponents (int i
, int j
)
195 synchronized (getTreeLock ())
198 || i
>= component
.length
200 || j
>= component
.length
)
201 throw new ArrayIndexOutOfBoundsException ();
202 Component tmp
= component
[i
];
203 component
[i
] = component
[j
];
209 * Returns the insets for this container, which is the space used for
210 * borders, the margin, etc.
212 * @return The insets for this container.
214 public Insets
getInsets()
220 * Returns the insets for this container, which is the space used for
221 * borders, the margin, etc.
223 * @return The insets for this container.
224 * @deprecated use {@link #getInsets()} instead
226 public Insets
insets()
229 return new Insets (0, 0, 0, 0);
231 return ((ContainerPeer
) peer
).getInsets ();
235 * Adds the specified component to this container at the end of the
238 * @param comp The component to add to the container.
240 * @return The same component that was added.
242 public Component
add(Component comp
)
244 addImpl(comp
, null, -1);
249 * Adds the specified component to the container at the end of the
250 * component list. This method should not be used. Instead, use
251 * <code>add(Component, Object)</code>.
253 * @param name The name of the component to be added.
254 * @param comp The component to be added.
256 * @return The same component that was added.
258 * @see #add(Component,Object)
260 public Component
add(String name
, Component comp
)
262 addImpl(comp
, name
, -1);
267 * Adds the specified component to this container at the specified index
268 * in the component list.
270 * @param comp The component to be added.
271 * @param index The index in the component list to insert this child
272 * at, or -1 to add at the end of the list.
274 * @return The same component that was added.
276 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
278 public Component
add(Component comp
, int index
)
280 addImpl(comp
, null, index
);
285 * Adds the specified component to this container at the end of the
286 * component list. The layout manager will use the specified constraints
287 * when laying out this component.
289 * @param comp The component to be added to this container.
290 * @param constraints The layout constraints for this component.
292 public void add(Component comp
, Object constraints
)
294 addImpl(comp
, constraints
, -1);
298 * Adds the specified component to this container at the specified index
299 * in the component list. The layout manager will use the specified
300 * constraints when layout out this component.
302 * @param comp The component to be added.
303 * @param constraints The layout constraints for this component.
304 * @param index The index in the component list to insert this child
305 * at, or -1 to add at the end of the list.
307 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
309 public void add(Component comp
, Object constraints
, int index
)
311 addImpl(comp
, constraints
, index
);
315 * This method is called by all the <code>add()</code> methods to perform
316 * the actual adding of the component. Subclasses who wish to perform
317 * their own processing when a component is added should override this
318 * method. Any subclass doing this must call the superclass version of
319 * this method in order to ensure proper functioning of the container.
321 * @param comp The component to be added.
322 * @param constraints The layout constraints for this component, or
323 * <code>null</code> if there are no constraints.
324 * @param index The index in the component list to insert this child
325 * at, or -1 to add at the end of the list.
327 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid.
329 protected void addImpl(Component comp
, Object constraints
, int index
)
331 synchronized (getTreeLock ())
333 if (index
> ncomponents
334 || (index
< 0 && index
!= -1)
335 || comp
instanceof Window
336 || (comp
instanceof Container
337 && ((Container
) comp
).isAncestorOf(this)))
338 throw new IllegalArgumentException();
340 // Reparent component, and make sure component is instantiated if
342 if (comp
.parent
!= null)
343 comp
.parent
.remove(comp
);
348 // Notify the component that it has a new parent.
351 if (comp
.isLightweight ())
353 enableEvents (comp
.eventMask
);
354 if (!isLightweight ())
355 enableEvents (AWTEvent
.PAINT_EVENT_MASK
);
359 // Invalidate the layout of the added component and its ancestors.
362 if (component
== null)
363 component
= new Component
[4]; // FIXME, better initial size?
365 // This isn't the most efficient implementation. We could do less
366 // copying when growing the array. It probably doesn't matter.
367 if (ncomponents
>= component
.length
)
369 int nl
= component
.length
* 2;
370 Component
[] c
= new Component
[nl
];
371 System
.arraycopy(component
, 0, c
, 0, ncomponents
);
376 component
[ncomponents
++] = comp
;
379 System
.arraycopy(component
, index
, component
, index
+ 1,
380 ncomponents
- index
);
381 component
[index
] = comp
;
385 // Notify the layout manager.
386 if (layoutMgr
!= null)
388 if (layoutMgr
instanceof LayoutManager2
)
390 LayoutManager2 lm2
= (LayoutManager2
) layoutMgr
;
391 lm2
.addLayoutComponent(comp
, constraints
);
393 else if (constraints
instanceof String
)
394 layoutMgr
.addLayoutComponent((String
) constraints
, comp
);
396 layoutMgr
.addLayoutComponent(null, comp
);
399 // We previously only sent an event when this container is showing.
400 // Also, the event was posted to the event queue. A Mauve test shows
401 // that this event is not delivered using the event queue and it is
402 // also sent when the container is not showing.
403 ContainerEvent ce
= new ContainerEvent(this,
404 ContainerEvent
.COMPONENT_ADDED
,
406 ContainerListener
[] listeners
= getContainerListeners();
407 for (int i
= 0; i
< listeners
.length
; i
++)
408 listeners
[i
].componentAdded(ce
);
410 // Repaint this container.
411 repaint(comp
.getX(), comp
.getY(), comp
.getWidth(),
417 * Removes the component at the specified index from this container.
419 * @param index The index of the component to remove.
421 public void remove(int index
)
423 synchronized (getTreeLock ())
425 Component r
= component
[index
];
427 ComponentListener
[] list
= r
.getComponentListeners();
428 for (int j
= 0; j
< list
.length
; j
++)
429 r
.removeComponentListener(list
[j
]);
434 System
.arraycopy(component
, index
+ 1, component
, index
,
435 ncomponents
- index
- 1);
436 component
[--ncomponents
] = null;
440 if (layoutMgr
!= null)
441 layoutMgr
.removeLayoutComponent(r
);
447 // Post event to notify of removing the component.
448 ContainerEvent ce
= new ContainerEvent(this,
449 ContainerEvent
.COMPONENT_REMOVED
,
451 getToolkit().getSystemEventQueue().postEvent(ce
);
457 * Removes the specified component from this container.
459 * @param comp The component to remove from this container.
461 public void remove(Component comp
)
463 synchronized (getTreeLock ())
465 for (int i
= 0; i
< ncomponents
; ++i
)
467 if (component
[i
] == comp
)
477 * Removes all components from this container.
479 public void removeAll()
481 synchronized (getTreeLock ())
483 while (ncomponents
> 0)
489 * Returns the current layout manager for this container.
491 * @return The layout manager for this container.
493 public LayoutManager
getLayout()
499 * Sets the layout manager for this container to the specified layout
502 * @param mgr The new layout manager for this container.
504 public void setLayout(LayoutManager mgr
)
511 * Layout the components in this container.
513 public void doLayout()
519 * Layout the components in this container.
521 * @deprecated use {@link #doLayout()} instead
525 if (layoutMgr
!= null)
526 layoutMgr
.layoutContainer (this);
530 * Invalidates this container to indicate that it (and all parent
531 * containers) need to be laid out.
533 public void invalidate()
536 if (layoutMgr
!= null && layoutMgr
instanceof LayoutManager2
)
538 LayoutManager2 lm2
= (LayoutManager2
) layoutMgr
;
539 lm2
.invalidateLayout(this);
544 * Re-lays out the components in this container.
546 public void validate()
548 synchronized (getTreeLock ())
550 if (! isValid() && peer
!= null)
558 * Recursively invalidates the container tree.
560 void invalidateTree()
562 super.invalidate(); // Clean cached layout state.
563 for (int i
= 0; i
< ncomponents
; i
++)
565 Component comp
= component
[i
];
567 if (comp
instanceof Container
)
568 ((Container
) comp
).invalidateTree();
571 if (layoutMgr
!= null && layoutMgr
instanceof LayoutManager2
)
573 LayoutManager2 lm2
= (LayoutManager2
) layoutMgr
;
574 lm2
.invalidateLayout(this);
579 * Recursively validates the container tree, recomputing any invalid
582 protected void validateTree()
587 ContainerPeer cPeer
= null;
588 if (peer
!= null && ! (peer
instanceof LightweightPeer
))
590 cPeer
= (ContainerPeer
) peer
;
591 cPeer
.beginValidate();
594 for (int i
= 0; i
< ncomponents
; ++i
)
596 Component comp
= component
[i
];
598 if (comp
.getPeer () == null)
603 for (int i
= 0; i
< ncomponents
; ++i
)
605 Component comp
= component
[i
];
607 if (! comp
.isValid())
609 if (comp
instanceof Container
)
611 ((Container
) comp
).validateTree();
615 component
[i
].validate();
620 /* children will call invalidate() when they are layed out. It
621 is therefore important that valid is not set to true
622 until after the children have been layed out. */
629 public void setFont(Font f
)
631 if( (f
!= null && (font
== null || !font
.equals(f
)))
635 // FIXME: Although it might make more sense to invalidate only
636 // those children whose font == null, Sun invalidates all children.
637 // So we'll do the same.
643 * Returns the preferred size of this container.
645 * @return The preferred size of this container.
647 public Dimension
getPreferredSize()
649 return preferredSize ();
653 * Returns the preferred size of this container.
655 * @return The preferred size of this container.
657 * @deprecated use {@link #getPreferredSize()} instead
659 public Dimension
preferredSize()
661 synchronized(treeLock
)
663 if(valid
&& prefSize
!= null)
664 return new Dimension(prefSize
);
665 LayoutManager layout
= getLayout();
668 Dimension layoutSize
= layout
.preferredLayoutSize(this);
670 prefSize
= layoutSize
;
671 return new Dimension(layoutSize
);
674 return super.preferredSize ();
679 * Returns the minimum size of this container.
681 * @return The minimum size of this container.
683 public Dimension
getMinimumSize()
685 return minimumSize ();
689 * Returns the minimum size of this container.
691 * @return The minimum size of this container.
693 * @deprecated use {@link #getMinimumSize()} instead
695 public Dimension
minimumSize()
697 if(valid
&& minSize
!= null)
698 return new Dimension(minSize
);
700 LayoutManager layout
= getLayout();
703 minSize
= layout
.minimumLayoutSize (this);
707 return super.minimumSize ();
711 * Returns the maximum size of this container.
713 * @return The maximum size of this container.
715 public Dimension
getMaximumSize()
717 if (valid
&& maxSize
!= null)
718 return new Dimension(maxSize
);
720 LayoutManager layout
= getLayout();
721 if (layout
!= null && layout
instanceof LayoutManager2
)
723 LayoutManager2 lm2
= (LayoutManager2
) layout
;
724 maxSize
= lm2
.maximumLayoutSize(this);
728 return super.getMaximumSize();
732 * Returns the preferred alignment along the X axis. This is a value
733 * between 0 and 1 where 0 represents alignment flush left and
734 * 1 means alignment flush right, and 0.5 means centered.
736 * @return The preferred alignment along the X axis.
738 public float getAlignmentX()
740 LayoutManager layout
= getLayout();
741 float alignmentX
= 0.0F
;
742 if (layout
!= null && layout
instanceof LayoutManager2
)
744 LayoutManager2 lm2
= (LayoutManager2
) layout
;
745 alignmentX
= lm2
.getLayoutAlignmentX(this);
748 alignmentX
= super.getAlignmentX();
753 * Returns the preferred alignment along the Y axis. This is a value
754 * between 0 and 1 where 0 represents alignment flush top and
755 * 1 means alignment flush bottom, and 0.5 means centered.
757 * @return The preferred alignment along the Y axis.
759 public float getAlignmentY()
761 LayoutManager layout
= getLayout();
762 float alignmentY
= 0.0F
;
763 if (layout
!= null && layout
instanceof LayoutManager2
)
765 LayoutManager2 lm2
= (LayoutManager2
) layout
;
766 alignmentY
= lm2
.getLayoutAlignmentY(this);
769 alignmentY
= super.getAlignmentY();
774 * Paints this container. The implementation of this method in this
775 * class forwards to any lightweight components in this container. If
776 * this method is subclassed, this method should still be invoked as
777 * a superclass method so that lightweight components are properly
780 * @param g The graphics context for this paint job.
782 public void paint(Graphics g
)
787 // Visit heavyweights as well, in case they were
788 // erased when we cleared the background for this container.
789 visitChildren(g
, GfxPaintVisitor
.INSTANCE
, false);
793 * Updates this container. The implementation of this method in this
794 * class forwards to any lightweight components in this container. If
795 * this method is subclassed, this method should still be invoked as
796 * a superclass method so that lightweight components are properly
799 * @param g The graphics context for this update.
801 * @specnote The specification suggests that this method forwards the
802 * update() call to all its lightweight children. Tests show
803 * that this is not done either in the JDK. The exact behaviour
804 * seems to be that the background is cleared in heavyweight
805 * Containers, and all other containers
806 * directly call paint(), causing the (lightweight) children to
809 public void update(Graphics g
)
811 // It seems that the JDK clears the background of containers like Panel
812 // and Window (within this method) but not of 'plain' Containers or
813 // JComponents. This could
814 // lead to the assumption that it only clears heavyweight containers.
815 // However that is not quite true. In a test with a custom Container
816 // that overrides isLightweight() to return false, the background is
817 // also not cleared. So we do a check on !(peer instanceof LightweightPeer)
819 ComponentPeer p
= peer
;
820 if (p
!= null && !(p
instanceof LightweightPeer
))
821 g
.clearRect(0, 0, getWidth(), getHeight());
827 * Prints this container. The implementation of this method in this
828 * class forwards to any lightweight components in this container. If
829 * this method is subclassed, this method should still be invoked as
830 * a superclass method so that lightweight components are properly
833 * @param g The graphics context for this print job.
835 public void print(Graphics g
)
838 visitChildren(g
, GfxPrintVisitor
.INSTANCE
, true);
842 * Paints all of the components in this container.
844 * @param g The graphics context for this paint job.
846 public void paintComponents(Graphics g
)
849 visitChildren(g
, GfxPaintAllVisitor
.INSTANCE
, true);
853 * Prints all of the components in this container.
855 * @param g The graphics context for this print job.
857 public void printComponents(Graphics g
)
860 visitChildren(g
, GfxPrintAllVisitor
.INSTANCE
, true);
864 * Adds the specified container listener to this object's list of
865 * container listeners.
867 * @param listener The listener to add.
869 public synchronized void addContainerListener(ContainerListener listener
)
871 containerListener
= AWTEventMulticaster
.add(containerListener
, listener
);
875 * Removes the specified container listener from this object's list of
876 * container listeners.
878 * @param listener The listener to remove.
880 public synchronized void removeContainerListener(ContainerListener listener
)
882 containerListener
= AWTEventMulticaster
.remove(containerListener
, listener
);
888 public synchronized ContainerListener
[] getContainerListeners()
890 return (ContainerListener
[])
891 AWTEventMulticaster
.getListeners(containerListener
,
892 ContainerListener
.class);
896 * Returns all registered {@link EventListener}s of the given
897 * <code>listenerType</code>.
899 * @param listenerType the class of listeners to filter (<code>null</code>
902 * @return An array of registered listeners.
904 * @throws ClassCastException if <code>listenerType</code> does not implement
905 * the {@link EventListener} interface.
906 * @throws NullPointerException if <code>listenerType</code> is
909 * @see #getContainerListeners()
913 public EventListener
[] getListeners(Class listenerType
)
915 if (listenerType
== ContainerListener
.class)
916 return getContainerListeners();
917 return super.getListeners(listenerType
);
921 * Processes the specified event. This method calls
922 * <code>processContainerEvent()</code> if this method is a
923 * <code>ContainerEvent</code>, otherwise it calls the superclass
926 * @param e The event to be processed.
928 protected void processEvent(AWTEvent e
)
930 if (e
instanceof ContainerEvent
)
931 processContainerEvent((ContainerEvent
) e
);
933 super.processEvent(e
);
937 * Called when a container event occurs if container events are enabled.
938 * This method calls any registered listeners.
940 * @param e The event that occurred.
942 protected void processContainerEvent(ContainerEvent e
)
944 if (containerListener
== null)
948 case ContainerEvent
.COMPONENT_ADDED
:
949 containerListener
.componentAdded(e
);
952 case ContainerEvent
.COMPONENT_REMOVED
:
953 containerListener
.componentRemoved(e
);
959 * AWT 1.0 event processor.
961 * @param e The event that occurred.
963 * @deprecated use {@link #dispatchEvent(AWTEvent)} instead
965 public void deliverEvent(Event e
)
967 if (!handleEvent (e
))
969 synchronized (getTreeLock ())
971 Component parent
= getParent ();
974 parent
.deliverEvent (e
);
980 * Returns the component located at the specified point. This is done
981 * by checking whether or not a child component claims to contain this
982 * point. The first child component that does is returned. If no
983 * child component claims the point, the container itself is returned,
984 * unless the point does not exist within this container, in which
985 * case <code>null</code> is returned.
987 * @param x The X coordinate of the point.
988 * @param y The Y coordinate of the point.
990 * @return The component containing the specified point, or
991 * <code>null</code> if there is no such point.
993 public Component
getComponentAt(int x
, int y
)
995 return locate (x
, y
);
999 * Returns the component located at the specified point. This is done
1000 * by checking whether or not a child component claims to contain this
1001 * point. The first child component that does is returned. If no
1002 * child component claims the point, the container itself is returned,
1003 * unless the point does not exist within this container, in which
1004 * case <code>null</code> is returned.
1006 * @param x The x position of the point to return the component at.
1007 * @param y The y position of the point to return the component at.
1009 * @return The component containing the specified point, or <code>null</code>
1010 * if there is no such point.
1012 * @deprecated use {@link #getComponentAt(int, int)} instead
1014 public Component
locate(int x
, int y
)
1016 synchronized (getTreeLock ())
1018 if (!contains (x
, y
))
1020 for (int i
= 0; i
< ncomponents
; ++i
)
1022 // Ignore invisible children...
1023 if (!component
[i
].isVisible ())
1026 int x2
= x
- component
[i
].x
;
1027 int y2
= y
- component
[i
].y
;
1028 if (component
[i
].contains (x2
, y2
))
1029 return component
[i
];
1036 * Returns the component located at the specified point. This is done
1037 * by checking whether or not a child component claims to contain this
1038 * point. The first child component that does is returned. If no
1039 * child component claims the point, the container itself is returned,
1040 * unless the point does not exist within this container, in which
1041 * case <code>null</code> is returned.
1043 * @param p The point to return the component at.
1044 * @return The component containing the specified point, or <code>null</code>
1045 * if there is no such point.
1047 public Component
getComponentAt(Point p
)
1049 return getComponentAt (p
.x
, p
.y
);
1052 public Component
findComponentAt(int x
, int y
)
1054 synchronized (getTreeLock ())
1056 if (! contains(x
, y
))
1059 for (int i
= 0; i
< ncomponents
; ++i
)
1061 // Ignore invisible children...
1062 if (!component
[i
].isVisible())
1065 int x2
= x
- component
[i
].x
;
1066 int y2
= y
- component
[i
].y
;
1067 // We don't do the contains() check right away because
1068 // findComponentAt would redundantly do it first thing.
1069 if (component
[i
] instanceof Container
)
1071 Container k
= (Container
) component
[i
];
1072 Component r
= k
.findComponentAt(x2
, y2
);
1076 else if (component
[i
].contains(x2
, y2
))
1077 return component
[i
];
1085 * Finds the visible child component that contains the specified position.
1086 * The top-most child is returned in the case where there is overlap.
1087 * If the top-most child is transparent and has no MouseListeners attached,
1088 * we discard it and return the next top-most component containing the
1089 * specified position.
1090 * @param x the x coordinate
1091 * @param y the y coordinate
1092 * @return null if the <code>this</code> does not contain the position,
1093 * otherwise the top-most component (out of this container itself and
1094 * its descendants) meeting the criteria above.
1096 Component
findComponentForMouseEventAt(int x
, int y
)
1098 synchronized (getTreeLock())
1100 if (!contains(x
, y
))
1103 for (int i
= 0; i
< ncomponents
; ++i
)
1105 // Ignore invisible children...
1106 if (!component
[i
].isVisible())
1109 int x2
= x
- component
[i
].x
;
1110 int y2
= y
- component
[i
].y
;
1111 // We don't do the contains() check right away because
1112 // findComponentAt would redundantly do it first thing.
1113 if (component
[i
] instanceof Container
)
1115 Container k
= (Container
) component
[i
];
1116 Component r
= k
.findComponentForMouseEventAt(x2
, y2
);
1120 else if (component
[i
].contains(x2
, y2
))
1121 return component
[i
];
1124 //don't return transparent components with no MouseListeners
1125 if (getMouseListeners().length
== 0
1126 && getMouseMotionListeners().length
== 0)
1132 public Component
findComponentAt(Point p
)
1134 return findComponentAt(p
.x
, p
.y
);
1138 * Called when this container is added to another container to inform it
1139 * to create its peer. Peers for any child components will also be
1142 public void addNotify()
1145 addNotifyContainerChildren();
1149 * Called when this container is removed from its parent container to
1150 * inform it to destroy its peer. This causes the peers of all child
1151 * component to be destroyed as well.
1153 public void removeNotify()
1155 synchronized (getTreeLock ())
1157 for (int i
= 0; i
< ncomponents
; ++i
)
1158 component
[i
].removeNotify();
1159 super.removeNotify();
1164 * Tests whether or not the specified component is contained within
1165 * this components subtree.
1167 * @param comp The component to test.
1169 * @return <code>true</code> if this container is an ancestor of the
1170 * specified component, <code>false</code> otherwise.
1172 public boolean isAncestorOf(Component comp
)
1174 synchronized (getTreeLock ())
1182 comp
= comp
.getParent();
1188 * Returns a string representing the state of this container for
1189 * debugging purposes.
1191 * @return A string representing the state of this container.
1193 protected String
paramString()
1195 if (layoutMgr
== null)
1196 return super.paramString();
1198 StringBuffer sb
= new StringBuffer();
1199 sb
.append(super.paramString());
1200 sb
.append(",layout=");
1201 sb
.append(layoutMgr
.getClass().getName());
1202 return sb
.toString();
1206 * Writes a listing of this container to the specified stream starting
1207 * at the specified indentation point.
1209 * @param out The <code>PrintStream</code> to write to.
1210 * @param indent The indentation point.
1212 public void list(PrintStream out
, int indent
)
1214 synchronized (getTreeLock ())
1216 super.list(out
, indent
);
1217 for (int i
= 0; i
< ncomponents
; ++i
)
1218 component
[i
].list(out
, indent
+ 2);
1223 * Writes a listing of this container to the specified stream starting
1224 * at the specified indentation point.
1226 * @param out The <code>PrintWriter</code> to write to.
1227 * @param indent The indentation point.
1229 public void list(PrintWriter out
, int indent
)
1231 synchronized (getTreeLock ())
1233 super.list(out
, indent
);
1234 for (int i
= 0; i
< ncomponents
; ++i
)
1235 component
[i
].list(out
, indent
+ 2);
1240 * Sets the focus traversal keys for a given traversal operation for this
1243 * @exception IllegalArgumentException If id is not one of
1244 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1245 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1246 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1247 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS,
1248 * or if keystrokes contains null, or if any Object in keystrokes is not an
1249 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any
1250 * keystroke already maps to another focus traversal operation for this
1255 public void setFocusTraversalKeys(int id
, Set keystrokes
)
1257 if (id
!= KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
&&
1258 id
!= KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
&&
1259 id
!= KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
&&
1260 id
!= KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
)
1261 throw new IllegalArgumentException ();
1263 if (keystrokes
== null)
1265 Container parent
= getParent ();
1267 while (parent
!= null)
1269 if (parent
.areFocusTraversalKeysSet (id
))
1271 keystrokes
= parent
.getFocusTraversalKeys (id
);
1274 parent
= parent
.getParent ();
1277 if (keystrokes
== null)
1278 keystrokes
= KeyboardFocusManager
.getCurrentKeyboardFocusManager ().
1279 getDefaultFocusTraversalKeys (id
);
1288 case KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
:
1289 sa
= getFocusTraversalKeys
1290 (KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
);
1291 sb
= getFocusTraversalKeys
1292 (KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
);
1293 sc
= getFocusTraversalKeys
1294 (KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
);
1295 name
= "forwardFocusTraversalKeys";
1297 case KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
:
1298 sa
= getFocusTraversalKeys
1299 (KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
);
1300 sb
= getFocusTraversalKeys
1301 (KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
);
1302 sc
= getFocusTraversalKeys
1303 (KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
);
1304 name
= "backwardFocusTraversalKeys";
1306 case KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
:
1307 sa
= getFocusTraversalKeys
1308 (KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
);
1309 sb
= getFocusTraversalKeys
1310 (KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
);
1311 sc
= getFocusTraversalKeys
1312 (KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
);
1313 name
= "upCycleFocusTraversalKeys";
1315 case KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
:
1316 sa
= getFocusTraversalKeys
1317 (KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
);
1318 sb
= getFocusTraversalKeys
1319 (KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
);
1320 sc
= getFocusTraversalKeys
1321 (KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
);
1322 name
= "downCycleFocusTraversalKeys";
1325 throw new IllegalArgumentException ();
1328 int i
= keystrokes
.size ();
1329 Iterator iter
= keystrokes
.iterator ();
1333 Object o
= iter
.next ();
1334 if (!(o
instanceof AWTKeyStroke
)
1335 || sa
.contains (o
) || sb
.contains (o
) || sc
.contains (o
)
1336 || ((AWTKeyStroke
) o
).keyCode
== KeyEvent
.VK_UNDEFINED
)
1337 throw new IllegalArgumentException ();
1340 if (focusTraversalKeys
== null)
1341 focusTraversalKeys
= new Set
[4];
1343 keystrokes
= Collections
.unmodifiableSet (new HashSet (keystrokes
));
1344 firePropertyChange (name
, focusTraversalKeys
[id
], keystrokes
);
1346 focusTraversalKeys
[id
] = keystrokes
;
1350 * Returns the Set of focus traversal keys for a given traversal operation for
1353 * @exception IllegalArgumentException If id is not one of
1354 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1355 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1356 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1357 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1361 public Set
getFocusTraversalKeys (int id
)
1363 if (id
!= KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
&&
1364 id
!= KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
&&
1365 id
!= KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
&&
1366 id
!= KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
)
1367 throw new IllegalArgumentException ();
1371 if (focusTraversalKeys
!= null)
1372 s
= focusTraversalKeys
[id
];
1374 if (s
== null && parent
!= null)
1375 s
= parent
.getFocusTraversalKeys (id
);
1377 return s
== null ?
(KeyboardFocusManager
.getCurrentKeyboardFocusManager()
1378 .getDefaultFocusTraversalKeys(id
)) : s
;
1382 * Returns whether the Set of focus traversal keys for the given focus
1383 * traversal operation has been explicitly defined for this Container.
1384 * If this method returns false, this Container is inheriting the Set from
1385 * an ancestor, or from the current KeyboardFocusManager.
1387 * @exception IllegalArgumentException If id is not one of
1388 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1389 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1390 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1391 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1395 public boolean areFocusTraversalKeysSet (int id
)
1397 if (id
!= KeyboardFocusManager
.FORWARD_TRAVERSAL_KEYS
&&
1398 id
!= KeyboardFocusManager
.BACKWARD_TRAVERSAL_KEYS
&&
1399 id
!= KeyboardFocusManager
.UP_CYCLE_TRAVERSAL_KEYS
&&
1400 id
!= KeyboardFocusManager
.DOWN_CYCLE_TRAVERSAL_KEYS
)
1401 throw new IllegalArgumentException ();
1403 return focusTraversalKeys
!= null && focusTraversalKeys
[id
] != null;
1407 * Check whether the given Container is the focus cycle root of this
1408 * Container's focus traversal cycle. If this Container is a focus
1409 * cycle root itself, then it will be in two different focus cycles
1410 * -- it's own, and that of its ancestor focus cycle root's. In
1411 * that case, if <code>c</code> is either of those containers, this
1412 * method will return true.
1414 * @param c the candidate Container
1416 * @return true if c is the focus cycle root of the focus traversal
1417 * cycle to which this Container belongs, false otherwise
1421 public boolean isFocusCycleRoot (Container c
)
1424 && isFocusCycleRoot ())
1427 Container ancestor
= getFocusCycleRootAncestor ();
1436 * If this Container is a focus cycle root, set the focus traversal
1437 * policy that determines the focus traversal order for its
1438 * children. If non-null, this policy will be inherited by all
1439 * inferior focus cycle roots. If <code>policy</code> is null, this
1440 * Container will inherit its policy from the closest ancestor focus
1441 * cycle root that's had its policy set.
1443 * @param policy the new focus traversal policy for this Container or null
1447 public void setFocusTraversalPolicy (FocusTraversalPolicy policy
)
1449 focusTraversalPolicy
= policy
;
1453 * Return the focus traversal policy that determines the focus
1454 * traversal order for this Container's children. This method
1455 * returns null if this Container is not a focus cycle root. If the
1456 * focus traversal policy has not been set explicitly, then this
1457 * method will return an ancestor focus cycle root's policy instead.
1459 * @return this Container's focus traversal policy or null
1463 public FocusTraversalPolicy
getFocusTraversalPolicy ()
1465 if (!isFocusCycleRoot ())
1468 if (focusTraversalPolicy
== null)
1470 Container ancestor
= getFocusCycleRootAncestor ();
1472 if (ancestor
!= this)
1473 return ancestor
.getFocusTraversalPolicy ();
1476 KeyboardFocusManager manager
= KeyboardFocusManager
.getCurrentKeyboardFocusManager ();
1478 return manager
.getDefaultFocusTraversalPolicy ();
1482 return focusTraversalPolicy
;
1486 * Check whether this Container's focus traversal policy has been
1487 * explicitly set. If it has not, then this Container will inherit
1488 * its focus traversal policy from one of its ancestor focus cycle
1491 * @return true if focus traversal policy is set, false otherwise
1493 public boolean isFocusTraversalPolicySet ()
1495 return focusTraversalPolicy
== null;
1499 * Set whether or not this Container is the root of a focus
1500 * traversal cycle. This Container's focus traversal policy
1501 * determines the order of focus traversal. Some policies prevent
1502 * the focus from being transferred between two traversal cycles
1503 * until an up or down traversal operation is performed. In that
1504 * case, normal traversal (not up or down) is limited to this
1505 * Container and all of this Container's descendents that are not
1506 * descendents of inferior focus cycle roots. In the default case
1507 * however, ContainerOrderFocusTraversalPolicy is in effect, and it
1508 * supports implicit down-cycle traversal operations.
1510 * @param focusCycleRoot true if this is a focus cycle root, false otherwise
1514 public void setFocusCycleRoot (boolean focusCycleRoot
)
1516 this.focusCycleRoot
= focusCycleRoot
;
1520 * Check whether this Container is a focus cycle root.
1522 * @return true if this is a focus cycle root, false otherwise
1526 public boolean isFocusCycleRoot ()
1528 return focusCycleRoot
;
1532 * Transfer focus down one focus traversal cycle. If this Container
1533 * is a focus cycle root, then its default component becomes the
1534 * focus owner, and this Container becomes the current focus cycle
1535 * root. No traversal will occur if this Container is not a focus
1540 public void transferFocusDownCycle ()
1542 KeyboardFocusManager manager
= KeyboardFocusManager
.getCurrentKeyboardFocusManager ();
1544 manager
.downFocusCycle (this);
1548 * Sets the ComponentOrientation property of this container and all components
1549 * contained within it.
1551 * @exception NullPointerException If orientation is null
1555 public void applyComponentOrientation (ComponentOrientation orientation
)
1557 if (orientation
== null)
1558 throw new NullPointerException ();
1561 public void addPropertyChangeListener (PropertyChangeListener listener
)
1563 if (listener
== null)
1566 if (changeSupport
== null)
1567 changeSupport
= new PropertyChangeSupport (this);
1569 changeSupport
.addPropertyChangeListener (listener
);
1572 public void addPropertyChangeListener (String name
,
1573 PropertyChangeListener listener
)
1575 if (listener
== null)
1578 if (changeSupport
== null)
1579 changeSupport
= new PropertyChangeSupport (this);
1581 changeSupport
.addPropertyChangeListener (name
, listener
);
1584 // Hidden helper methods.
1587 * Perform a graphics operation on the children of this container.
1588 * For each applicable child, the visitChild() method will be called
1589 * to perform the graphics operation.
1591 * @param gfx The graphics object that will be used to derive new
1592 * graphics objects for the children.
1594 * @param visitor Object encapsulating the graphics operation that
1595 * should be performed.
1597 * @param lightweightOnly If true, only lightweight components will
1600 private void visitChildren(Graphics gfx
, GfxVisitor visitor
,
1601 boolean lightweightOnly
)
1603 synchronized (getTreeLock ())
1605 for (int i
= ncomponents
- 1; i
>= 0; --i
)
1607 Component comp
= component
[i
];
1608 boolean applicable
= comp
.isVisible()
1609 && (comp
.isLightweight() || !lightweightOnly
);
1612 visitChild(gfx
, visitor
, comp
);
1618 * Perform a graphics operation on a child. A translated and clipped
1619 * graphics object will be created, and the visit() method of the
1620 * visitor will be called to perform the operation.
1622 * @param gfx The graphics object that will be used to derive new
1623 * graphics objects for the child.
1625 * @param visitor Object encapsulating the graphics operation that
1626 * should be performed.
1628 * @param comp The child component that should be visited.
1630 private void visitChild(Graphics gfx
, GfxVisitor visitor
,
1633 Rectangle bounds
= comp
.getBounds();
1635 if(!gfx
.hitClip(bounds
.x
,bounds
.y
, bounds
.width
, bounds
.height
))
1638 Graphics g2
= gfx
.create(bounds
.x
, bounds
.y
, bounds
.width
,
1642 visitor
.visit(comp
, g2
);
1650 void dispatchEventImpl(AWTEvent e
)
1652 // Give lightweight dispatcher a chance to handle it.
1653 if (dispatcher
!= null && dispatcher
.handleEvent (e
))
1656 if ((e
.id
<= ContainerEvent
.CONTAINER_LAST
1657 && e
.id
>= ContainerEvent
.CONTAINER_FIRST
)
1658 && (containerListener
!= null
1659 || (eventMask
& AWTEvent
.CONTAINER_EVENT_MASK
) != 0))
1662 super.dispatchEventImpl(e
);
1666 * Tests if this container has an interest in the given event id.
1668 * @param eventId The event id to check.
1670 * @return <code>true</code> if a listener for the event id exists or
1671 * if the eventMask is set for the event id.
1673 * @see java.awt.Component#eventTypeEnabled(int)
1675 boolean eventTypeEnabled(int eventId
)
1677 if(eventId
<= ContainerEvent
.CONTAINER_LAST
1678 && eventId
>= ContainerEvent
.CONTAINER_FIRST
)
1679 return containerListener
!= null
1680 || (eventMask
& AWTEvent
.CONTAINER_EVENT_MASK
) != 0;
1682 return super.eventTypeEnabled(eventId
);
1685 // This is used to implement Component.transferFocus.
1686 Component
findNextFocusComponent(Component child
)
1688 synchronized (getTreeLock ())
1693 for (start
= 0; start
< ncomponents
; ++start
)
1695 if (component
[start
] == child
)
1699 // This special case lets us be sure to terminate.
1710 for (int j
= start
; j
!= end
; ++j
)
1712 if (j
>= ncomponents
)
1714 // The JCL says that we should wrap here. However, that
1715 // seems wrong. To me it seems that focus order should be
1716 // global within in given window. So instead if we reach
1717 // the end we try to look in our parent, if we have one.
1719 return parent
.findNextFocusComponent(this);
1722 if (component
[j
] instanceof Container
)
1724 Component c
= component
[j
];
1725 c
= c
.findNextFocusComponent(null);
1729 else if (component
[j
].isFocusTraversable())
1730 return component
[j
];
1737 private void addNotifyContainerChildren()
1739 synchronized (getTreeLock ())
1741 for (int i
= ncomponents
; --i
>= 0; )
1743 component
[i
].addNotify();
1744 if (component
[i
].isLightweight ())
1747 // If we're not lightweight, and we just got a lightweight
1748 // child, we need a lightweight dispatcher to feed it events.
1749 if (!this.isLightweight() && dispatcher
== null)
1750 dispatcher
= new LightweightDispatcher (this);
1752 if (dispatcher
!= null)
1753 dispatcher
.enableEvents(component
[i
].eventMask
);
1755 enableEvents(component
[i
].eventMask
);
1756 if (peer
!= null && !isLightweight ())
1757 enableEvents (AWTEvent
.PAINT_EVENT_MASK
);
1764 * Deserialize this Container:
1766 * <li>Read from the stream the default serializable fields.</li>
1767 * <li>Read a list of serializable ContainerListeners as optional
1768 * data. If the list is null, no listeners will be registered.</li>
1769 * <li>Read this Container's FocusTraversalPolicy as optional data.
1770 * If this is null, then this Container will use a
1771 * DefaultFocusTraversalPolicy.</li>
1774 * @param s the stream to read from
1775 * @throws ClassNotFoundException if deserialization fails
1776 * @throws IOException if the stream fails
1778 private void readObject (ObjectInputStream s
)
1779 throws ClassNotFoundException
, IOException
1781 s
.defaultReadObject ();
1782 String key
= (String
) s
.readObject ();
1785 Object object
= s
.readObject ();
1786 if ("containerL".equals (key
))
1787 addContainerListener((ContainerListener
) object
);
1788 // FIXME: under what key is the focus traversal policy stored?
1789 else if ("focusTraversalPolicy".equals (key
))
1790 setFocusTraversalPolicy ((FocusTraversalPolicy
) object
);
1792 key
= (String
) s
.readObject();
1797 * Serialize this Container:
1799 * <li>Write to the stream the default serializable fields.</li>
1800 * <li>Write the list of serializable ContainerListeners as optional
1802 * <li>Write this Container's FocusTraversalPolicy as optional data.</li>
1805 * @param s the stream to write to
1806 * @throws IOException if the stream fails
1808 private void writeObject (ObjectOutputStream s
) throws IOException
1810 s
.defaultWriteObject ();
1811 AWTEventMulticaster
.save (s
, "containerL", containerListener
);
1812 if (focusTraversalPolicy
instanceof Serializable
)
1813 s
.writeObject (focusTraversalPolicy
);
1815 s
.writeObject (null);
1820 /* The following classes are used in concert with the
1821 visitChildren() method to implement all the graphics operations
1822 that requires traversal of the containment hierarchy. */
1824 abstract static class GfxVisitor
1826 public abstract void visit(Component c
, Graphics gfx
);
1829 static class GfxPaintVisitor
extends GfxVisitor
1831 public static final GfxVisitor INSTANCE
= new GfxPaintVisitor();
1833 public void visit(Component c
, Graphics gfx
)
1839 static class GfxPrintVisitor
extends GfxVisitor
1841 public static final GfxVisitor INSTANCE
= new GfxPrintVisitor();
1843 public void visit(Component c
, Graphics gfx
)
1849 static class GfxPaintAllVisitor
extends GfxVisitor
1851 public static final GfxVisitor INSTANCE
= new GfxPaintAllVisitor();
1853 public void visit(Component c
, Graphics gfx
)
1859 static class GfxPrintAllVisitor
extends GfxVisitor
1861 public static final GfxVisitor INSTANCE
= new GfxPrintAllVisitor();
1863 public void visit(Component c
, Graphics gfx
)
1870 * This class provides accessibility support for subclasses of container.
1872 * @author Eric Blake (ebb9@email.byu.edu)
1876 protected class AccessibleAWTContainer
extends AccessibleAWTComponent
1879 * Compatible with JDK 1.4+.
1881 private static final long serialVersionUID
= 5081320404842566097L;
1884 * The handler to fire PropertyChange when children are added or removed.
1886 * @serial the handler for property changes
1888 protected ContainerListener accessibleContainerHandler
1889 = new AccessibleContainerHandler();
1892 * The default constructor.
1894 protected AccessibleAWTContainer()
1896 Container
.this.addContainerListener(accessibleContainerHandler
);
1900 * Return the number of accessible children of the containing accessible
1901 * object (at most the total number of its children).
1903 * @return the number of accessible children
1905 public int getAccessibleChildrenCount()
1907 synchronized (getTreeLock ())
1910 int i
= component
== null ?
0 : component
.length
;
1912 if (component
[i
] instanceof Accessible
)
1919 * Return the nth accessible child of the containing accessible object.
1921 * @param i the child to grab, zero-based
1922 * @return the accessible child, or null
1924 public Accessible
getAccessibleChild(int i
)
1926 synchronized (getTreeLock ())
1928 if (component
== null)
1931 while (i
>= 0 && ++index
< component
.length
)
1932 if (component
[index
] instanceof Accessible
)
1935 return (Accessible
) component
[index
];
1941 * Return the accessible child located at point (in the parent's
1942 * coordinates), if one exists.
1944 * @param p the point to look at
1946 * @return an accessible object at that point, or null
1948 * @throws NullPointerException if p is null
1950 public Accessible
getAccessibleAt(Point p
)
1952 Component c
= getComponentAt(p
.x
, p
.y
);
1953 return c
!= Container
.this && c
instanceof Accessible ?
(Accessible
) c
1958 * This class fires a <code>PropertyChange</code> listener, if registered,
1959 * when children are added or removed from the enclosing accessible object.
1961 * @author Eric Blake (ebb9@email.byu.edu)
1965 protected class AccessibleContainerHandler
implements ContainerListener
1968 * Default constructor.
1970 protected AccessibleContainerHandler()
1972 // Nothing to do here.
1976 * Fired when a component is added; forwards to the PropertyChange
1979 * @param e the container event for adding
1981 public void componentAdded(ContainerEvent e
)
1983 AccessibleAWTContainer
.this.firePropertyChange
1984 (ACCESSIBLE_CHILD_PROPERTY
, null, e
.getChild());
1988 * Fired when a component is removed; forwards to the PropertyChange
1991 * @param e the container event for removing
1993 public void componentRemoved(ContainerEvent e
)
1995 AccessibleAWTContainer
.this.firePropertyChange
1996 (ACCESSIBLE_CHILD_PROPERTY
, e
.getChild(), null);
1998 } // class AccessibleContainerHandler
1999 } // class AccessibleAWTContainer
2000 } // class Container
2003 * There is a helper class implied from stack traces called
2004 * LightweightDispatcher, but since it is not part of the public API,
2005 * rather than mimic it exactly we write something which does "roughly
2008 class LightweightDispatcher
implements Serializable
2010 private static final long serialVersionUID
= 5184291520170872969L;
2011 private Container nativeContainer
;
2012 private Cursor nativeCursor
;
2013 private long eventMask
;
2015 private transient Component pressedComponent
;
2016 private transient Component lastComponentEntered
;
2017 private transient int pressCount
;
2019 LightweightDispatcher(Container c
)
2021 nativeContainer
= c
;
2024 void enableEvents(long l
)
2030 * Returns the deepest visible descendent of parent that contains the
2031 * specified location and that is not transparent and MouseListener-less.
2032 * @param parent the root component to begin the search
2033 * @param x the x coordinate
2034 * @param y the y coordinate
2035 * @return null if <code>parent</code> doesn't contain the location,
2036 * parent if parent is not a container or has no child that contains the
2037 * location, otherwise the appropriate component from the conditions
2040 Component
getDeepestComponentForMouseEventAt(Component parent
, int x
, int y
)
2042 if (parent
== null || (! parent
.contains(x
, y
)))
2045 if (! (parent
instanceof Container
))
2048 Container c
= (Container
) parent
;
2049 return c
.findComponentForMouseEventAt(x
, y
);
2052 Component
acquireComponentForMouseEvent(MouseEvent me
)
2057 Component mouseEventTarget
= null;
2058 // Find the candidate which should receive this event.
2059 Component parent
= nativeContainer
;
2060 Component candidate
= null;
2061 Point p
= me
.getPoint();
2062 while (candidate
== null && parent
!= null)
2064 candidate
= getDeepestComponentForMouseEventAt(parent
, p
.x
, p
.y
);
2065 if (candidate
== null || (candidate
.eventMask
& me
.getID()) == 0)
2068 p
= AWTUtilities
.convertPoint(parent
, p
.x
, p
.y
, parent
.parent
);
2069 parent
= parent
.parent
;
2073 // If the only candidate we found was the native container itself,
2074 // don't dispatch any event at all. We only care about the lightweight
2076 if (candidate
== nativeContainer
)
2079 // If our candidate is new, inform the old target we're leaving.
2080 if (lastComponentEntered
!= null
2081 && lastComponentEntered
.isShowing()
2082 && lastComponentEntered
!= candidate
)
2084 // Old candidate could have been removed from
2085 // the nativeContainer so we check first.
2086 if (AWTUtilities
.isDescendingFrom(lastComponentEntered
,
2089 Point tp
= AWTUtilities
.convertPoint(nativeContainer
,
2090 x
, y
, lastComponentEntered
);
2091 MouseEvent exited
= new MouseEvent (lastComponentEntered
,
2092 MouseEvent
.MOUSE_EXITED
,
2094 me
.getModifiersEx (),
2096 me
.getClickCount (),
2097 me
.isPopupTrigger (),
2099 lastComponentEntered
.dispatchEvent (exited
);
2101 lastComponentEntered
= null;
2104 // If we have a candidate, maybe enter it.
2105 if (candidate
!= null)
2107 mouseEventTarget
= candidate
;
2108 if (candidate
.isLightweight()
2109 && candidate
.isShowing()
2110 && candidate
!= nativeContainer
2111 && candidate
!= lastComponentEntered
)
2113 lastComponentEntered
= mouseEventTarget
;
2114 Point cp
= AWTUtilities
.convertPoint(nativeContainer
,
2115 x
, y
, lastComponentEntered
);
2116 MouseEvent entered
= new MouseEvent (lastComponentEntered
,
2117 MouseEvent
.MOUSE_ENTERED
,
2119 me
.getModifiersEx (),
2121 me
.getClickCount (),
2122 me
.isPopupTrigger (),
2124 lastComponentEntered
.dispatchEvent (entered
);
2128 // Check which buttons where pressed except the last button that
2130 int modifiers
= me
.getModifiersEx() & (MouseEvent
.BUTTON1_DOWN_MASK
2131 | MouseEvent
.BUTTON2_DOWN_MASK
2132 | MouseEvent
.BUTTON3_DOWN_MASK
);
2133 switch(me
.getButton())
2135 case MouseEvent
.BUTTON1
:
2136 modifiers
&= ~MouseEvent
.BUTTON1_DOWN_MASK
;
2138 case MouseEvent
.BUTTON2
:
2139 modifiers
&= ~MouseEvent
.BUTTON2_DOWN_MASK
;
2141 case MouseEvent
.BUTTON3
:
2142 modifiers
&= ~MouseEvent
.BUTTON3_DOWN_MASK
;
2146 if (me
.getID() == MouseEvent
.MOUSE_RELEASED
2147 || me
.getID() == MouseEvent
.MOUSE_PRESSED
&& modifiers
> 0
2148 || me
.getID() == MouseEvent
.MOUSE_DRAGGED
)
2150 // If any of the following events occur while a button is held down,
2151 // they should be dispatched to the same component to which the
2152 // original MOUSE_PRESSED event was dispatched:
2153 // - MOUSE_RELEASED: This is important for correct dragging
2154 // behaviour, otherwise the release goes to an arbitrary component
2155 // outside of the dragged component. OTOH, if there is no mouse
2156 // drag while the mouse is pressed, the component under the mouse
2157 // is the same as the previously pressed component anyway.
2158 // - MOUSE_PRESSED: another button pressed while the first is held
2161 if (AWTUtilities
.isDescendingFrom(pressedComponent
, nativeContainer
))
2162 mouseEventTarget
= pressedComponent
;
2164 else if (me
.getID() == MouseEvent
.MOUSE_CLICKED
)
2166 // Don't dispatch CLICKED events whose target is not the same as the
2167 // target for the original PRESSED event.
2168 if (candidate
!= pressedComponent
)
2170 mouseEventTarget
= null;
2173 else if (pressCount
== 0)
2174 pressedComponent
= null;
2176 return mouseEventTarget
;
2179 boolean handleEvent(AWTEvent e
)
2181 if (e
instanceof MouseEvent
)
2183 MouseEvent me
= (MouseEvent
) e
;
2185 // Make the LightWeightDispatcher reentrant. This is necessary when
2186 // a lightweight component does its own modal event queue.
2187 Component mouseEventTarget
= acquireComponentForMouseEvent(me
);
2189 // Avoid dispatching ENTERED and EXITED events twice.
2190 if (mouseEventTarget
!= null
2191 && mouseEventTarget
.isShowing()
2192 && e
.getID() != MouseEvent
.MOUSE_ENTERED
2193 && e
.getID() != MouseEvent
.MOUSE_EXITED
)
2197 case MouseEvent
.MOUSE_PRESSED
:
2198 if (pressCount
++ == 0)
2199 pressedComponent
= mouseEventTarget
;
2201 case MouseEvent
.MOUSE_RELEASED
:
2202 // Clear our memory of the original PRESSED event, only if
2203 // we're not expecting a CLICKED event after this. If
2204 // there is a CLICKED event after this, it will do clean up.
2205 if (--pressCount
== 0
2206 && mouseEventTarget
!= pressedComponent
)
2208 pressedComponent
= null;
2215 AWTUtilities
.convertMouseEvent(nativeContainer
, me
,
2217 mouseEventTarget
.dispatchEvent(newEvt
);
2219 if (newEvt
.isConsumed())
2224 return e
.isConsumed();