Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / awt / Container.java
blobcd7fec02ecbbfce0588957fb69bf6ef2b6126422
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)
9 any later version.
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
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
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. */
39 package java.awt;
41 import java.awt.event.ContainerEvent;
42 import java.awt.event.ContainerListener;
43 import java.awt.event.KeyEvent;
44 import java.awt.event.MouseEvent;
45 import java.awt.peer.ContainerPeer;
46 import java.awt.peer.LightweightPeer;
47 import java.beans.PropertyChangeListener;
48 import java.beans.PropertyChangeSupport;
49 import java.io.IOException;
50 import java.io.ObjectInputStream;
51 import java.io.ObjectOutputStream;
52 import java.io.PrintStream;
53 import java.io.PrintWriter;
54 import java.io.Serializable;
55 import java.util.Collections;
56 import java.util.EventListener;
57 import java.util.HashSet;
58 import java.util.Iterator;
59 import java.util.Set;
61 import javax.accessibility.Accessible;
62 import javax.swing.SwingUtilities;
64 /**
65 * A generic window toolkit object that acts as a container for other objects.
66 * Components are tracked in a list, and new elements are at the end of the
67 * list or bottom of the stacking order.
69 * @author original author unknown
70 * @author Eric Blake (ebb9@email.byu.edu)
72 * @since 1.0
74 * @status still missing 1.4 support
76 public class Container extends Component
78 /**
79 * Compatible with JDK 1.0+.
81 private static final long serialVersionUID = 4613797578919906343L;
83 /* Serialized fields from the serialization spec. */
84 int ncomponents;
85 Component[] component;
86 LayoutManager layoutMgr;
88 LightweightDispatcher dispatcher;
90 Dimension maxSize;
92 /**
93 * @since 1.4
95 boolean focusCycleRoot;
97 int containerSerializedDataVersion;
99 /* Anything else is non-serializable, and should be declared "transient". */
100 transient ContainerListener containerListener;
101 transient PropertyChangeSupport changeSupport;
103 /** The focus traversal policy that determines how focus is
104 transferred between this Container and its children. */
105 private FocusTraversalPolicy focusTraversalPolicy;
108 * The focus traversal keys, if not inherited from the parent or default
109 * keyboard manager. These sets will contain only AWTKeyStrokes that
110 * represent press and release events to use as focus control.
112 * @see #getFocusTraversalKeys(int)
113 * @see #setFocusTraversalKeys(int, Set)
114 * @since 1.4
116 transient Set[] focusTraversalKeys;
119 * Default constructor for subclasses.
121 public Container()
126 * Returns the number of components in this container.
128 * @return The number of components in this container.
130 public int getComponentCount()
132 return countComponents ();
136 * Returns the number of components in this container.
138 * @return The number of components in this container.
140 * @deprecated use {@link #getComponentCount()} instead
142 public int countComponents()
144 return ncomponents;
148 * Returns the component at the specified index.
150 * @param n The index of the component to retrieve.
152 * @return The requested component.
154 * @throws ArrayIndexOutOfBoundsException If the specified index is invalid
156 public Component getComponent(int n)
158 synchronized (getTreeLock ())
160 if (n < 0 || n >= ncomponents)
161 throw new ArrayIndexOutOfBoundsException("no such component");
163 return component[n];
168 * Returns an array of the components in this container.
170 * @return The components in this container.
172 public Component[] getComponents()
174 synchronized (getTreeLock ())
176 Component[] result = new Component[ncomponents];
178 if (ncomponents > 0)
179 System.arraycopy(component, 0, result, 0, ncomponents);
181 return result;
186 * Swaps the components at position i and j, in the container.
189 protected void swapComponents (int i, int j)
191 synchronized (getTreeLock ())
193 if (i < 0
194 || i >= component.length
195 || j < 0
196 || j >= component.length)
197 throw new ArrayIndexOutOfBoundsException ();
198 Component tmp = component[i];
199 component[i] = component[j];
200 component[j] = tmp;
205 * Returns the insets for this container, which is the space used for
206 * borders, the margin, etc.
208 * @return The insets for this container.
210 public Insets getInsets()
212 return insets ();
216 * Returns the insets for this container, which is the space used for
217 * borders, the margin, etc.
219 * @return The insets for this container.
220 * @deprecated use {@link #getInsets()} instead
222 public Insets insets()
224 if (peer == null)
225 return new Insets (0, 0, 0, 0);
227 return ((ContainerPeer) peer).getInsets ();
231 * Adds the specified component to this container at the end of the
232 * component list.
234 * @param comp The component to add to the container.
236 * @return The same component that was added.
238 public Component add(Component comp)
240 addImpl(comp, null, -1);
241 return comp;
245 * Adds the specified component to the container at the end of the
246 * component list. This method should not be used. Instead, use
247 * <code>add(Component, Object)</code>.
249 * @param name The name of the component to be added.
250 * @param comp The component to be added.
252 * @return The same component that was added.
254 * @see #add(Component,Object)
256 public Component add(String name, Component comp)
258 addImpl(comp, name, -1);
259 return comp;
263 * Adds the specified component to this container at the specified index
264 * in the component list.
266 * @param comp The component to be added.
267 * @param index The index in the component list to insert this child
268 * at, or -1 to add at the end of the list.
270 * @return The same component that was added.
272 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
274 public Component add(Component comp, int index)
276 addImpl(comp, null, index);
277 return comp;
281 * Adds the specified component to this container at the end of the
282 * component list. The layout manager will use the specified constraints
283 * when laying out this component.
285 * @param comp The component to be added to this container.
286 * @param constraints The layout constraints for this component.
288 public void add(Component comp, Object constraints)
290 addImpl(comp, constraints, -1);
294 * Adds the specified component to this container at the specified index
295 * in the component list. The layout manager will use the specified
296 * constraints when layout out this component.
298 * @param comp The component to be added.
299 * @param constraints The layout constraints for this component.
300 * @param index The index in the component list to insert this child
301 * at, or -1 to add at the end of the list.
303 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
305 public void add(Component comp, Object constraints, int index)
307 addImpl(comp, constraints, index);
311 * This method is called by all the <code>add()</code> methods to perform
312 * the actual adding of the component. Subclasses who wish to perform
313 * their own processing when a component is added should override this
314 * method. Any subclass doing this must call the superclass version of
315 * this method in order to ensure proper functioning of the container.
317 * @param comp The component to be added.
318 * @param constraints The layout constraints for this component, or
319 * <code>null</code> if there are no constraints.
320 * @param index The index in the component list to insert this child
321 * at, or -1 to add at the end of the list.
323 * @throws ArrayIndexOutOfBounds If the specified index is invalid.
325 protected void addImpl(Component comp, Object constraints, int index)
327 synchronized (getTreeLock ())
329 if (index > ncomponents
330 || (index < 0 && index != -1)
331 || comp instanceof Window
332 || (comp instanceof Container
333 && ((Container) comp).isAncestorOf(this)))
334 throw new IllegalArgumentException();
336 // Reparent component, and make sure component is instantiated if
337 // we are.
338 if (comp.parent != null)
339 comp.parent.remove(comp);
340 comp.parent = this;
341 if (peer != null)
343 if (comp.isLightweight ())
345 enableEvents (comp.eventMask);
346 if (!isLightweight ())
347 enableEvents (AWTEvent.PAINT_EVENT_MASK);
351 invalidate();
353 if (component == null)
354 component = new Component[4]; // FIXME, better initial size?
356 // This isn't the most efficient implementation. We could do less
357 // copying when growing the array. It probably doesn't matter.
358 if (ncomponents >= component.length)
360 int nl = component.length * 2;
361 Component[] c = new Component[nl];
362 System.arraycopy(component, 0, c, 0, ncomponents);
363 component = c;
366 if (index == -1)
367 component[ncomponents++] = comp;
368 else
370 System.arraycopy(component, index, component, index + 1,
371 ncomponents - index);
372 component[index] = comp;
373 ++ncomponents;
376 // Notify the layout manager.
377 if (layoutMgr != null)
379 if (layoutMgr instanceof LayoutManager2)
381 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
382 lm2.addLayoutComponent(comp, constraints);
384 else if (constraints instanceof String)
385 layoutMgr.addLayoutComponent((String) constraints, comp);
386 else
387 layoutMgr.addLayoutComponent(null, comp);
390 if (isShowing ())
392 // Post event to notify of adding the component.
393 ContainerEvent ce = new ContainerEvent(this,
394 ContainerEvent.COMPONENT_ADDED,
395 comp);
396 getToolkit().getSystemEventQueue().postEvent(ce);
402 * Removes the component at the specified index from this container.
404 * @param index The index of the component to remove.
406 public void remove(int index)
408 synchronized (getTreeLock ())
410 Component r = component[index];
412 r.removeNotify();
414 System.arraycopy(component, index + 1, component, index,
415 ncomponents - index - 1);
416 component[--ncomponents] = null;
418 invalidate();
420 if (layoutMgr != null)
421 layoutMgr.removeLayoutComponent(r);
423 r.parent = null;
425 if (isShowing ())
427 // Post event to notify of removing the component.
428 ContainerEvent ce = new ContainerEvent(this,
429 ContainerEvent.COMPONENT_REMOVED,
431 getToolkit().getSystemEventQueue().postEvent(ce);
437 * Removes the specified component from this container.
439 * @return component The component to remove from this container.
441 public void remove(Component comp)
443 synchronized (getTreeLock ())
445 for (int i = 0; i < ncomponents; ++i)
447 if (component[i] == comp)
449 remove(i);
450 break;
457 * Removes all components from this container.
459 public void removeAll()
461 synchronized (getTreeLock ())
463 while (ncomponents > 0)
464 remove(0);
469 * Returns the current layout manager for this container.
471 * @return The layout manager for this container.
473 public LayoutManager getLayout()
475 return layoutMgr;
479 * Sets the layout manager for this container to the specified layout
480 * manager.
482 * @param mgr The new layout manager for this container.
484 public void setLayout(LayoutManager mgr)
486 layoutMgr = mgr;
487 invalidate();
491 * Layout the components in this container.
493 public void doLayout()
495 layout ();
499 * Layout the components in this container.
501 * @deprecated use {@link #doLayout()} instead
503 public void layout()
505 if (layoutMgr != null)
506 layoutMgr.layoutContainer (this);
510 * Invalidates this container to indicate that it (and all parent
511 * containers) need to be laid out.
513 public void invalidate()
515 super.invalidate();
519 * Re-lays out the components in this container.
521 public void validate()
523 synchronized (getTreeLock ())
525 if (! isValid() && peer != null)
527 validateTree();
533 * Recursively invalidates the container tree.
535 void invalidateTree()
537 for (int i = 0; i < ncomponents; i++)
539 Component comp = component[i];
540 comp.invalidate();
541 if (comp instanceof Container)
542 ((Container) comp).invalidateTree();
547 * Recursively validates the container tree, recomputing any invalid
548 * layouts.
550 protected void validateTree()
552 if (valid)
553 return;
555 ContainerPeer cPeer = null;
556 if (peer != null && ! (peer instanceof LightweightPeer))
558 cPeer = (ContainerPeer) peer;
559 cPeer.beginValidate();
562 for (int i = 0; i < ncomponents; ++i)
564 Component comp = component[i];
566 if (comp.getPeer () == null)
567 comp.addNotify();
570 doLayout ();
571 for (int i = 0; i < ncomponents; ++i)
573 Component comp = component[i];
575 if (! comp.isValid())
577 if (comp instanceof Container)
579 ((Container) comp).validateTree();
581 else
583 component[i].validate();
588 /* children will call invalidate() when they are layed out. It
589 is therefore important that valid is not set to true
590 until after the children have been layed out. */
591 valid = true;
593 if (cPeer != null)
594 cPeer.endValidate();
597 public void setFont(Font f)
599 super.setFont(f);
600 // FIXME: Although it might make more sense to invalidate only
601 // those children whose font == null, Sun invalidates all children.
602 // So we'll do the same.
603 invalidateTree();
607 * Returns the preferred size of this container.
609 * @return The preferred size of this container.
611 public Dimension getPreferredSize()
613 return preferredSize ();
617 * Returns the preferred size of this container.
619 * @return The preferred size of this container.
621 * @deprecated use {@link #getPreferredSize()} instead
623 public Dimension preferredSize()
625 if (layoutMgr != null)
626 return layoutMgr.preferredLayoutSize (this);
627 else
628 return super.preferredSize ();
632 * Returns the minimum size of this container.
634 * @return The minimum size of this container.
636 public Dimension getMinimumSize()
638 return minimumSize ();
642 * Returns the minimum size of this container.
644 * @return The minimum size of this container.
646 * @deprecated use {@link #getMinimumSize()} instead
648 public Dimension minimumSize()
650 if (layoutMgr != null)
651 return layoutMgr.minimumLayoutSize (this);
652 else
653 return super.minimumSize ();
657 * Returns the maximum size of this container.
659 * @return The maximum size of this container.
661 public Dimension getMaximumSize()
663 if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
665 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
666 return lm2.maximumLayoutSize(this);
668 else
669 return super.getMaximumSize();
673 * Returns the preferred alignment along the X axis. This is a value
674 * between 0 and 1 where 0 represents alignment flush left and
675 * 1 means alignment flush right, and 0.5 means centered.
677 * @return The preferred alignment along the X axis.
679 public float getAlignmentX()
681 if (layoutMgr instanceof LayoutManager2)
683 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
684 return lm2.getLayoutAlignmentX(this);
686 else
687 return super.getAlignmentX();
691 * Returns the preferred alignment along the Y axis. This is a value
692 * between 0 and 1 where 0 represents alignment flush top and
693 * 1 means alignment flush bottom, and 0.5 means centered.
695 * @return The preferred alignment along the Y axis.
697 public float getAlignmentY()
699 if (layoutMgr instanceof LayoutManager2)
701 LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
702 return lm2.getLayoutAlignmentY(this);
704 else
705 return super.getAlignmentY();
709 * Paints this container. The implementation of this method in this
710 * class forwards to any lightweight components in this container. If
711 * this method is subclassed, this method should still be invoked as
712 * a superclass method so that lightweight components are properly
713 * drawn.
715 * @param g The graphics context for this paint job.
717 public void paint(Graphics g)
719 if (!isShowing())
720 return;
721 // Paint self first.
722 super.paint(g);
723 // Visit heavyweights as well, in case they were
724 // erased when we cleared the background for this container.
725 visitChildren(g, GfxPaintVisitor.INSTANCE, false);
729 * Updates this container. The implementation of this method in this
730 * class forwards to any lightweight components in this container. If
731 * this method is subclassed, this method should still be invoked as
732 * a superclass method so that lightweight components are properly
733 * drawn.
735 * @param g The graphics context for this update.
737 public void update(Graphics g)
739 super.update(g);
743 * Prints this container. The implementation of this method in this
744 * class forwards to any lightweight components in this container. If
745 * this method is subclassed, this method should still be invoked as
746 * a superclass method so that lightweight components are properly
747 * drawn.
749 * @param g The graphics context for this print job.
751 public void print(Graphics g)
753 super.print(g);
754 visitChildren(g, GfxPrintVisitor.INSTANCE, true);
758 * Paints all of the components in this container.
760 * @param g The graphics context for this paint job.
762 public void paintComponents(Graphics g)
764 super.paint(g);
765 visitChildren(g, GfxPaintAllVisitor.INSTANCE, true);
769 * Prints all of the components in this container.
771 * @param g The graphics context for this print job.
773 public void printComponents(Graphics g)
775 super.paint(g);
776 visitChildren(g, GfxPrintAllVisitor.INSTANCE, true);
780 * Adds the specified container listener to this object's list of
781 * container listeners.
783 * @param listener The listener to add.
785 public synchronized void addContainerListener(ContainerListener listener)
787 containerListener = AWTEventMulticaster.add(containerListener, listener);
791 * Removes the specified container listener from this object's list of
792 * container listeners.
794 * @param listener The listener to remove.
796 public synchronized void removeContainerListener(ContainerListener listener)
798 containerListener = AWTEventMulticaster.remove(containerListener, listener);
802 * @since 1.4
804 public synchronized ContainerListener[] getContainerListeners()
806 return (ContainerListener[])
807 AWTEventMulticaster.getListeners(containerListener,
808 ContainerListener.class);
812 * Returns an array of all the objects currently registered as FooListeners
813 * upon this Container. FooListeners are registered using the addFooListener
814 * method.
816 * @exception ClassCastException If listenerType doesn't specify a class or
817 * interface that implements @see java.util.EventListener.
819 * @since 1.3
821 public EventListener[] getListeners(Class listenerType)
823 if (listenerType == ContainerListener.class)
824 return getContainerListeners();
825 return super.getListeners(listenerType);
829 * Processes the specified event. This method calls
830 * <code>processContainerEvent()</code> if this method is a
831 * <code>ContainerEvent</code>, otherwise it calls the superclass
832 * method.
834 * @param e The event to be processed.
836 protected void processEvent(AWTEvent e)
838 if (e instanceof ContainerEvent)
839 processContainerEvent((ContainerEvent) e);
840 else
841 super.processEvent(e);
845 * Called when a container event occurs if container events are enabled.
846 * This method calls any registered listeners.
848 * @param e The event that occurred.
850 protected void processContainerEvent(ContainerEvent e)
852 if (containerListener == null)
853 return;
854 switch (e.id)
856 case ContainerEvent.COMPONENT_ADDED:
857 containerListener.componentAdded(e);
858 break;
860 case ContainerEvent.COMPONENT_REMOVED:
861 containerListener.componentRemoved(e);
862 break;
867 * AWT 1.0 event processor.
869 * @param e The event that occurred.
871 * @deprecated use {@link #dispatchEvent(AWTEvent)} instead
873 public void deliverEvent(Event e)
875 if (!handleEvent (e))
877 synchronized (getTreeLock ())
879 Component parent = getParent ();
881 if (parent != null)
882 parent.deliverEvent (e);
888 * Returns the component located at the specified point. This is done
889 * by checking whether or not a child component claims to contain this
890 * point. The first child component that does is returned. If no
891 * child component claims the point, the container itself is returned,
892 * unless the point does not exist within this container, in which
893 * case <code>null</code> is returned.
895 * @param x The X coordinate of the point.
896 * @param y The Y coordinate of the point.
898 * @return The component containing the specified point, or
899 * <code>null</code> if there is no such point.
901 public Component getComponentAt(int x, int y)
903 return locate (x, y);
907 * Returns the component located at the specified point. This is done
908 * by checking whether or not a child component claims to contain this
909 * point. The first child component that does is returned. If no
910 * child component claims the point, the container itself is returned,
911 * unless the point does not exist within this container, in which
912 * case <code>null</code> is returned.
914 * @param x The x position of the point to return the component at.
915 * @param y The y position of the point to return the component at.
917 * @return The component containing the specified point, or <code>null</code>
918 * if there is no such point.
920 * @deprecated use {@link #getComponentAt(int, int)} instead
922 public Component locate(int x, int y)
924 synchronized (getTreeLock ())
926 if (!contains (x, y))
927 return null;
928 for (int i = 0; i < ncomponents; ++i)
930 // Ignore invisible children...
931 if (!component[i].isVisible ())
932 continue;
934 int x2 = x - component[i].x;
935 int y2 = y - component[i].y;
936 if (component[i].contains (x2, y2))
937 return component[i];
939 return this;
944 * Returns the component located at the specified point. This is done
945 * by checking whether or not a child component claims to contain this
946 * point. The first child component that does is returned. If no
947 * child component claims the point, the container itself is returned,
948 * unless the point does not exist within this container, in which
949 * case <code>null</code> is returned.
951 * @param p The point to return the component at.
952 * @return The component containing the specified point, or <code>null</code>
953 * if there is no such point.
955 public Component getComponentAt(Point p)
957 return getComponentAt (p.x, p.y);
960 public Component findComponentAt(int x, int y)
962 synchronized (getTreeLock ())
964 if (! contains(x, y))
965 return null;
967 for (int i = 0; i < ncomponents; ++i)
969 // Ignore invisible children...
970 if (!component[i].isVisible())
971 continue;
973 int x2 = x - component[i].x;
974 int y2 = y - component[i].y;
975 // We don't do the contains() check right away because
976 // findComponentAt would redundantly do it first thing.
977 if (component[i] instanceof Container)
979 Container k = (Container) component[i];
980 Component r = k.findComponentAt(x2, y2);
981 if (r != null)
982 return r;
984 else if (component[i].contains(x2, y2))
985 return component[i];
988 return this;
992 public Component findComponentAt(Point p)
994 return findComponentAt(p.x, p.y);
998 * Called when this container is added to another container to inform it
999 * to create its peer. Peers for any child components will also be
1000 * created.
1002 public void addNotify()
1004 super.addNotify();
1005 addNotifyContainerChildren();
1009 * Called when this container is removed from its parent container to
1010 * inform it to destroy its peer. This causes the peers of all child
1011 * component to be destroyed as well.
1013 public void removeNotify()
1015 synchronized (getTreeLock ())
1017 for (int i = 0; i < ncomponents; ++i)
1018 component[i].removeNotify();
1019 super.removeNotify();
1024 * Tests whether or not the specified component is contained within
1025 * this components subtree.
1027 * @param comp The component to test.
1029 * @return <code>true</code> if this container is an ancestor of the
1030 * specified component, <code>false</code> otherwise.
1032 public boolean isAncestorOf(Component comp)
1034 synchronized (getTreeLock ())
1036 while (true)
1038 if (comp == null)
1039 return false;
1040 if (comp == this)
1041 return true;
1042 comp = comp.getParent();
1048 * Returns a string representing the state of this container for
1049 * debugging purposes.
1051 * @return A string representing the state of this container.
1053 protected String paramString()
1055 if (layoutMgr == null)
1056 return super.paramString();
1058 StringBuffer sb = new StringBuffer();
1059 sb.append(super.paramString());
1060 sb.append(",layout=");
1061 sb.append(layoutMgr.getClass().getName());
1062 return sb.toString();
1066 * Writes a listing of this container to the specified stream starting
1067 * at the specified indentation point.
1069 * @param out The <code>PrintStream</code> to write to.
1070 * @param indent The indentation point.
1072 public void list(PrintStream out, int indent)
1074 synchronized (getTreeLock ())
1076 super.list(out, indent);
1077 for (int i = 0; i < ncomponents; ++i)
1078 component[i].list(out, indent + 2);
1083 * Writes a listing of this container to the specified stream starting
1084 * at the specified indentation point.
1086 * @param out The <code>PrintWriter</code> to write to.
1087 * @param indent The indentation point.
1089 public void list(PrintWriter out, int indent)
1091 synchronized (getTreeLock ())
1093 super.list(out, indent);
1094 for (int i = 0; i < ncomponents; ++i)
1095 component[i].list(out, indent + 2);
1100 * Sets the focus traversal keys for a given traversal operation for this
1101 * Container.
1103 * @exception IllegalArgumentException If id is not one of
1104 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1105 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1106 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1107 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS,
1108 * or if keystrokes contains null, or if any Object in keystrokes is not an
1109 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event, or if any
1110 * keystroke already maps to another focus traversal operation for this
1111 * Container.
1113 * @since 1.4
1115 public void setFocusTraversalKeys(int id, Set keystrokes)
1117 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1118 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1119 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1120 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1121 throw new IllegalArgumentException ();
1123 if (keystrokes == null)
1125 Container parent = getParent ();
1127 while (parent != null)
1129 if (parent.areFocusTraversalKeysSet (id))
1131 keystrokes = parent.getFocusTraversalKeys (id);
1132 break;
1134 parent = parent.getParent ();
1137 if (keystrokes == null)
1138 keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager ().
1139 getDefaultFocusTraversalKeys (id);
1142 Set sa;
1143 Set sb;
1144 Set sc;
1145 String name;
1146 switch (id)
1148 case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS:
1149 sa = getFocusTraversalKeys
1150 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1151 sb = getFocusTraversalKeys
1152 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1153 sc = getFocusTraversalKeys
1154 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1155 name = "forwardFocusTraversalKeys";
1156 break;
1157 case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS:
1158 sa = getFocusTraversalKeys
1159 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1160 sb = getFocusTraversalKeys
1161 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1162 sc = getFocusTraversalKeys
1163 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1164 name = "backwardFocusTraversalKeys";
1165 break;
1166 case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS:
1167 sa = getFocusTraversalKeys
1168 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1169 sb = getFocusTraversalKeys
1170 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1171 sc = getFocusTraversalKeys
1172 (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1173 name = "upCycleFocusTraversalKeys";
1174 break;
1175 case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS:
1176 sa = getFocusTraversalKeys
1177 (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1178 sb = getFocusTraversalKeys
1179 (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1180 sc = getFocusTraversalKeys
1181 (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1182 name = "downCycleFocusTraversalKeys";
1183 break;
1184 default:
1185 throw new IllegalArgumentException ();
1188 int i = keystrokes.size ();
1189 Iterator iter = keystrokes.iterator ();
1191 while (--i >= 0)
1193 Object o = iter.next ();
1194 if (!(o instanceof AWTKeyStroke)
1195 || sa.contains (o) || sb.contains (o) || sc.contains (o)
1196 || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED)
1197 throw new IllegalArgumentException ();
1200 if (focusTraversalKeys == null)
1201 focusTraversalKeys = new Set[3];
1203 keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes));
1204 firePropertyChange (name, focusTraversalKeys[id], keystrokes);
1206 focusTraversalKeys[id] = keystrokes;
1210 * Returns the Set of focus traversal keys for a given traversal operation for
1211 * this Container.
1213 * @exception IllegalArgumentException If id is not one of
1214 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1215 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1216 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1217 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1219 * @since 1.4
1221 public Set getFocusTraversalKeys (int id)
1223 if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS &&
1224 id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS &&
1225 id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS &&
1226 id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS)
1227 throw new IllegalArgumentException ();
1229 Set s = null;
1231 if (focusTraversalKeys != null)
1232 s = focusTraversalKeys[id];
1234 if (s == null && parent != null)
1235 s = parent.getFocusTraversalKeys (id);
1237 return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager()
1238 .getDefaultFocusTraversalKeys(id)) : s;
1242 * Returns whether the Set of focus traversal keys for the given focus
1243 * traversal operation has been explicitly defined for this Container.
1244 * If this method returns false, this Container is inheriting the Set from
1245 * an ancestor, or from the current KeyboardFocusManager.
1247 * @exception IllegalArgumentException If id is not one of
1248 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
1249 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
1250 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
1251 * or KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS.
1253 * @since 1.4
1255 public boolean areFocusTraversalKeysSet (int id)
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 return focusTraversalKeys != null && focusTraversalKeys[id] != null;
1267 * Check whether the given Container is the focus cycle root of this
1268 * Container's focus traversal cycle. If this Container is a focus
1269 * cycle root itself, then it will be in two different focus cycles
1270 * -- it's own, and that of its ancestor focus cycle root's. In
1271 * that case, if <code>c</code> is either of those containers, this
1272 * method will return true.
1274 * @param c the candidate Container
1276 * @return true if c is the focus cycle root of the focus traversal
1277 * cycle to which this Container belongs, false otherwise
1279 * @since 1.4
1281 public boolean isFocusCycleRoot (Container c)
1283 if (this == c
1284 && isFocusCycleRoot ())
1285 return true;
1287 Container ancestor = getFocusCycleRootAncestor ();
1289 if (c == ancestor)
1290 return true;
1292 return false;
1296 * If this Container is a focus cycle root, set the focus traversal
1297 * policy that determines the focus traversal order for its
1298 * children. If non-null, this policy will be inherited by all
1299 * inferior focus cycle roots. If <code>policy</code> is null, this
1300 * Container will inherit its policy from the closest ancestor focus
1301 * cycle root that's had its policy set.
1303 * @param policy the new focus traversal policy for this Container or null
1305 * @since 1.4
1307 public void setFocusTraversalPolicy (FocusTraversalPolicy policy)
1309 focusTraversalPolicy = policy;
1313 * Return the focus traversal policy that determines the focus
1314 * traversal order for this Container's children. This method
1315 * returns null if this Container is not a focus cycle root. If the
1316 * focus traversal policy has not been set explicitly, then this
1317 * method will return an ancestor focus cycle root's policy instead.
1319 * @return this Container's focus traversal policy or null
1321 * @since 1.4
1323 public FocusTraversalPolicy getFocusTraversalPolicy ()
1325 if (!isFocusCycleRoot ())
1326 return null;
1328 if (focusTraversalPolicy == null)
1330 Container ancestor = getFocusCycleRootAncestor ();
1332 if (ancestor != this)
1333 return ancestor.getFocusTraversalPolicy ();
1334 else
1336 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
1338 return manager.getDefaultFocusTraversalPolicy ();
1341 else
1342 return focusTraversalPolicy;
1346 * Check whether this Container's focus traversal policy has been
1347 * explicitly set. If it has not, then this Container will inherit
1348 * its focus traversal policy from one of its ancestor focus cycle
1349 * roots.
1351 * @return true if focus traversal policy is set, false otherwise
1353 public boolean isFocusTraversalPolicySet ()
1355 return focusTraversalPolicy == null;
1359 * Set whether or not this Container is the root of a focus
1360 * traversal cycle. This Container's focus traversal policy
1361 * determines the order of focus traversal. Some policies prevent
1362 * the focus from being transferred between two traversal cycles
1363 * until an up or down traversal operation is performed. In that
1364 * case, normal traversal (not up or down) is limited to this
1365 * Container and all of this Container's descendents that are not
1366 * descendents of inferior focus cycle roots. In the default case
1367 * however, ContainerOrderFocusTraversalPolicy is in effect, and it
1368 * supports implicit down-cycle traversal operations.
1370 * @return true if this is a focus cycle root, false otherwise
1372 * @since 1.4
1374 public void setFocusCycleRoot (boolean focusCycleRoot)
1376 this.focusCycleRoot = focusCycleRoot;
1380 * Check whether this Container is a focus cycle root.
1382 * @return true if this is a focus cycle root, false otherwise
1384 * @since 1.4
1386 public boolean isFocusCycleRoot ()
1388 return focusCycleRoot;
1392 * Transfer focus down one focus traversal cycle. If this Container
1393 * is a focus cycle root, then its default component becomes the
1394 * focus owner, and this Container becomes the current focus cycle
1395 * root. No traversal will occur if this Container is not a focus
1396 * cycle root.
1398 * @since 1.4
1400 public void transferFocusDownCycle ()
1402 KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager ();
1404 manager.downFocusCycle (this);
1408 * Sets the ComponentOrientation property of this container and all components
1409 * contained within it.
1411 * @exception NullPointerException If orientation is null
1413 * @since 1.4
1415 public void applyComponentOrientation (ComponentOrientation orientation)
1417 if (orientation == null)
1418 throw new NullPointerException ();
1421 public void addPropertyChangeListener (PropertyChangeListener listener)
1423 if (listener == null)
1424 return;
1426 if (changeSupport == null)
1427 changeSupport = new PropertyChangeSupport (this);
1429 changeSupport.addPropertyChangeListener (listener);
1432 public void addPropertyChangeListener (String name,
1433 PropertyChangeListener listener)
1435 if (listener == null)
1436 return;
1438 if (changeSupport == null)
1439 changeSupport = new PropertyChangeSupport (this);
1441 changeSupport.addPropertyChangeListener (name, listener);
1444 // Hidden helper methods.
1447 * Perform a graphics operation on the children of this container.
1448 * For each applicable child, the visitChild() method will be called
1449 * to perform the graphics operation.
1451 * @param gfx The graphics object that will be used to derive new
1452 * graphics objects for the children.
1454 * @param visitor Object encapsulating the graphics operation that
1455 * should be performed.
1457 * @param lightweightOnly If true, only lightweight components will
1458 * be visited.
1460 private void visitChildren(Graphics gfx, GfxVisitor visitor,
1461 boolean lightweightOnly)
1463 synchronized (getTreeLock ())
1465 for (int i = ncomponents - 1; i >= 0; --i)
1467 Component comp = component[i];
1468 // If we're visiting heavyweights as well,
1469 // don't recurse into Containers here. This avoids
1470 // painting the same nested child multiple times.
1471 boolean applicable = comp.isVisible()
1472 && (comp.isLightweight()
1473 || !lightweightOnly && ! (comp instanceof Container));
1475 if (applicable)
1476 visitChild(gfx, visitor, comp);
1482 * Perform a graphics operation on a child. A translated and clipped
1483 * graphics object will be created, and the visit() method of the
1484 * visitor will be called to perform the operation.
1486 * @param gfx The graphics object that will be used to derive new
1487 * graphics objects for the child.
1489 * @param visitor Object encapsulating the graphics operation that
1490 * should be performed.
1492 * @param comp The child component that should be visited.
1494 private void visitChild(Graphics gfx, GfxVisitor visitor,
1495 Component comp)
1497 Rectangle bounds = comp.getBounds();
1498 Rectangle oldClip = gfx.getClipBounds();
1499 if (oldClip == null)
1500 oldClip = bounds;
1502 Rectangle clip = oldClip.intersection(bounds);
1504 if (clip.isEmpty()) return;
1506 boolean clipped = false;
1507 boolean translated = false;
1510 gfx.setClip(clip.x, clip.y, clip.width, clip.height);
1511 clipped = true;
1512 gfx.translate(bounds.x, bounds.y);
1513 translated = true;
1514 visitor.visit(comp, gfx);
1516 finally
1518 if (translated)
1519 gfx.translate (-bounds.x, -bounds.y);
1520 if (clipped)
1521 gfx.setClip (oldClip.x, oldClip.y, oldClip.width, oldClip.height);
1525 void dispatchEventImpl(AWTEvent e)
1527 // Give lightweight dispatcher a chance to handle it.
1528 if (eventTypeEnabled (e.id)
1529 && dispatcher != null
1530 && dispatcher.handleEvent (e))
1531 return;
1533 if ((e.id <= ContainerEvent.CONTAINER_LAST
1534 && e.id >= ContainerEvent.CONTAINER_FIRST)
1535 && (containerListener != null
1536 || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0))
1537 processEvent(e);
1538 else
1539 super.dispatchEventImpl(e);
1542 // This is used to implement Component.transferFocus.
1543 Component findNextFocusComponent(Component child)
1545 synchronized (getTreeLock ())
1547 int start, end;
1548 if (child != null)
1550 for (start = 0; start < ncomponents; ++start)
1552 if (component[start] == child)
1553 break;
1555 end = start;
1556 // This special case lets us be sure to terminate.
1557 if (end == 0)
1558 end = ncomponents;
1559 ++start;
1561 else
1563 start = 0;
1564 end = ncomponents;
1567 for (int j = start; j != end; ++j)
1569 if (j >= ncomponents)
1571 // The JCL says that we should wrap here. However, that
1572 // seems wrong. To me it seems that focus order should be
1573 // global within in given window. So instead if we reach
1574 // the end we try to look in our parent, if we have one.
1575 if (parent != null)
1576 return parent.findNextFocusComponent(this);
1577 j -= ncomponents;
1579 if (component[j] instanceof Container)
1581 Component c = component[j];
1582 c = c.findNextFocusComponent(null);
1583 if (c != null)
1584 return c;
1586 else if (component[j].isFocusTraversable())
1587 return component[j];
1590 return null;
1594 private void addNotifyContainerChildren()
1596 synchronized (getTreeLock ())
1598 for (int i = ncomponents; --i >= 0; )
1600 component[i].addNotify();
1601 if (component[i].isLightweight ())
1604 // If we're not lightweight, and we just got a lightweight
1605 // child, we need a lightweight dispatcher to feed it events.
1606 if (! this.isLightweight())
1608 if (dispatcher == null)
1609 dispatcher = new LightweightDispatcher (this);
1613 enableEvents(component[i].eventMask);
1614 if (peer != null && !isLightweight ())
1615 enableEvents (AWTEvent.PAINT_EVENT_MASK);
1622 * Deserialize this Container:
1623 * <ol>
1624 * <li>Read from the stream the default serializable fields.</li>
1625 * <li>Read a list of serializable ContainerListeners as optional
1626 * data. If the list is null, no listeners will be registered.</li>
1627 * <li>Read this Container's FocusTraversalPolicy as optional data.
1628 * If this is null, then this Container will use a
1629 * DefaultFocusTraversalPolicy.</li>
1630 * </ol>
1632 * @param s the stream to read from
1633 * @throws ClassNotFoundException if deserialization fails
1634 * @throws IOException if the stream fails
1636 private void readObject (ObjectInputStream s)
1637 throws ClassNotFoundException, IOException
1639 s.defaultReadObject ();
1640 String key = (String) s.readObject ();
1641 while (key != null)
1643 Object object = s.readObject ();
1644 if ("containerL".equals (key))
1645 addContainerListener((ContainerListener) object);
1646 // FIXME: under what key is the focus traversal policy stored?
1647 else if ("focusTraversalPolicy".equals (key))
1648 setFocusTraversalPolicy ((FocusTraversalPolicy) object);
1650 key = (String) s.readObject();
1655 * Serialize this Container:
1656 * <ol>
1657 * <li>Write to the stream the default serializable fields.</li>
1658 * <li>Write the list of serializable ContainerListeners as optional
1659 * data.</li>
1660 * <li>Write this Container's FocusTraversalPolicy as optional data.</li>
1661 * </ol>
1663 * @param s the stream to write to
1664 * @throws IOException if the stream fails
1666 private void writeObject (ObjectOutputStream s) throws IOException
1668 s.defaultWriteObject ();
1669 AWTEventMulticaster.save (s, "containerL", containerListener);
1670 if (focusTraversalPolicy instanceof Serializable)
1671 s.writeObject (focusTraversalPolicy);
1672 else
1673 s.writeObject (null);
1676 // Nested classes.
1678 /* The following classes are used in concert with the
1679 visitChildren() method to implement all the graphics operations
1680 that requires traversal of the containment hierarchy. */
1682 abstract static class GfxVisitor
1684 public abstract void visit(Component c, Graphics gfx);
1687 static class GfxPaintVisitor extends GfxVisitor
1689 public static final GfxVisitor INSTANCE = new GfxPaintVisitor();
1691 public void visit(Component c, Graphics gfx)
1693 c.paint(gfx);
1697 static class GfxPrintVisitor extends GfxVisitor
1699 public static final GfxVisitor INSTANCE = new GfxPrintVisitor();
1701 public void visit(Component c, Graphics gfx)
1703 c.print(gfx);
1707 static class GfxPaintAllVisitor extends GfxVisitor
1709 public static final GfxVisitor INSTANCE = new GfxPaintAllVisitor();
1711 public void visit(Component c, Graphics gfx)
1713 c.paintAll(gfx);
1717 static class GfxPrintAllVisitor extends GfxVisitor
1719 public static final GfxVisitor INSTANCE = new GfxPrintAllVisitor();
1721 public void visit(Component c, Graphics gfx)
1723 c.printAll(gfx);
1728 * This class provides accessibility support for subclasses of container.
1730 * @author Eric Blake (ebb9@email.byu.edu)
1732 * @since 1.3
1734 protected class AccessibleAWTContainer extends AccessibleAWTComponent
1737 * Compatible with JDK 1.4+.
1739 private static final long serialVersionUID = 5081320404842566097L;
1742 * The handler to fire PropertyChange when children are added or removed.
1744 * @serial the handler for property changes
1746 protected ContainerListener accessibleContainerHandler
1747 = new AccessibleContainerHandler();
1750 * The default constructor.
1752 protected AccessibleAWTContainer()
1754 Container.this.addContainerListener(accessibleContainerHandler);
1758 * Return the number of accessible children of the containing accessible
1759 * object (at most the total number of its children).
1761 * @return the number of accessible children
1763 public int getAccessibleChildrenCount()
1765 synchronized (getTreeLock ())
1767 int count = 0;
1768 int i = component == null ? 0 : component.length;
1769 while (--i >= 0)
1770 if (component[i] instanceof Accessible)
1771 count++;
1772 return count;
1777 * Return the nth accessible child of the containing accessible object.
1779 * @param i the child to grab, zero-based
1780 * @return the accessible child, or null
1782 public Accessible getAccessibleChild(int i)
1784 synchronized (getTreeLock ())
1786 if (component == null)
1787 return null;
1788 int index = -1;
1789 while (i >= 0 && ++index < component.length)
1790 if (component[index] instanceof Accessible)
1791 i--;
1792 if (i < 0)
1793 return (Accessible) component[index];
1794 return null;
1799 * Return the accessible child located at point (in the parent's
1800 * coordinates), if one exists.
1802 * @param p the point to look at
1804 * @return an accessible object at that point, or null
1806 * @throws NullPointerException if p is null
1808 public Accessible getAccessibleAt(Point p)
1810 Component c = getComponentAt(p.x, p.y);
1811 return c != Container.this && c instanceof Accessible ? (Accessible) c
1812 : null;
1816 * This class fires a <code>PropertyChange</code> listener, if registered,
1817 * when children are added or removed from the enclosing accessible object.
1819 * @author Eric Blake (ebb9@email.byu.edu)
1821 * @since 1.3
1823 protected class AccessibleContainerHandler implements ContainerListener
1826 * Default constructor.
1828 protected AccessibleContainerHandler()
1833 * Fired when a component is added; forwards to the PropertyChange
1834 * listener.
1836 * @param e the container event for adding
1838 public void componentAdded(ContainerEvent e)
1840 AccessibleAWTContainer.this.firePropertyChange
1841 (ACCESSIBLE_CHILD_PROPERTY, null, e.getChild());
1845 * Fired when a component is removed; forwards to the PropertyChange
1846 * listener.
1848 * @param e the container event for removing
1850 public void componentRemoved(ContainerEvent e)
1852 AccessibleAWTContainer.this.firePropertyChange
1853 (ACCESSIBLE_CHILD_PROPERTY, e.getChild(), null);
1855 } // class AccessibleContainerHandler
1856 } // class AccessibleAWTContainer
1857 } // class Container
1860 * There is a helper class implied from stack traces called
1861 * LightweightDispatcher, but since it is not part of the public API,
1862 * rather than mimic it exactly we write something which does "roughly
1863 * the same thing".
1866 class LightweightDispatcher implements Serializable
1868 private static final long serialVersionUID = 5184291520170872969L;
1869 private Container nativeContainer;
1870 private Cursor nativeCursor;
1871 private long eventMask;
1873 private transient Component mouseEventTarget;
1874 private transient Component pressedComponent;
1875 private transient Component lastComponentEntered;
1876 private transient int pressCount;
1878 LightweightDispatcher(Container c)
1880 nativeContainer = c;
1883 void acquireComponentForMouseEvent(MouseEvent me)
1885 int x = me.getX ();
1886 int y = me.getY ();
1888 // Find the candidate which should receive this event.
1889 Component parent = nativeContainer;
1890 Component candidate = null;
1891 Point p = me.getPoint();
1892 while (candidate == null && parent != null)
1894 candidate =
1895 SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
1896 if (candidate == null || (candidate.eventMask & me.getID()) == 0)
1898 candidate = null;
1899 p = SwingUtilities.convertPoint(parent, p.x, p.y, parent.parent);
1900 parent = parent.parent;
1904 // If the only candidate we found was the native container itself,
1905 // don't dispatch any event at all. We only care about the lightweight
1906 // children here.
1907 if (candidate == nativeContainer)
1908 candidate = null;
1910 // If our candidate is new, inform the old target we're leaving.
1911 if (lastComponentEntered != null
1912 && lastComponentEntered.isShowing()
1913 && lastComponentEntered != candidate)
1915 // Old candidate could have been removed from
1916 // the nativeContainer so we check first.
1917 if (SwingUtilities.isDescendingFrom(lastComponentEntered, nativeContainer))
1919 Point tp =
1920 SwingUtilities.convertPoint(nativeContainer,
1921 x, y, lastComponentEntered);
1922 MouseEvent exited = new MouseEvent (lastComponentEntered,
1923 MouseEvent.MOUSE_EXITED,
1924 me.getWhen (),
1925 me.getModifiersEx (),
1926 tp.x, tp.y,
1927 me.getClickCount (),
1928 me.isPopupTrigger (),
1929 me.getButton ());
1930 lastComponentEntered.dispatchEvent (exited);
1932 lastComponentEntered = null;
1934 // If we have a candidate, maybe enter it.
1935 if (candidate != null)
1937 mouseEventTarget = candidate;
1938 if (candidate.isLightweight()
1939 && candidate.isShowing()
1940 && candidate != nativeContainer
1941 && candidate != lastComponentEntered)
1943 lastComponentEntered = mouseEventTarget;
1944 Point cp = SwingUtilities.convertPoint(nativeContainer,
1945 x, y, lastComponentEntered);
1946 MouseEvent entered = new MouseEvent (lastComponentEntered,
1947 MouseEvent.MOUSE_ENTERED,
1948 me.getWhen (),
1949 me.getModifiersEx (),
1950 cp.x, cp.y,
1951 me.getClickCount (),
1952 me.isPopupTrigger (),
1953 me.getButton ());
1954 lastComponentEntered.dispatchEvent (entered);
1958 if (me.getID() == MouseEvent.MOUSE_RELEASED
1959 || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
1960 || me.getID() == MouseEvent.MOUSE_DRAGGED)
1961 // If any of the following events occur while a button is held down,
1962 // they should be dispatched to the same component to which the
1963 // original MOUSE_PRESSED event was dispatched:
1964 // - MOUSE_RELEASED
1965 // - MOUSE_PRESSED: another button pressed while the first is held down
1966 // - MOUSE_DRAGGED
1967 if (SwingUtilities.isDescendingFrom(pressedComponent, nativeContainer))
1968 mouseEventTarget = pressedComponent;
1969 else if (me.getID() == MouseEvent.MOUSE_CLICKED)
1971 // Don't dispatch CLICKED events whose target is not the same as the
1972 // target for the original PRESSED event.
1973 if (candidate != pressedComponent)
1974 mouseEventTarget = null;
1975 else if (pressCount == 0)
1976 pressedComponent = null;
1980 boolean handleEvent(AWTEvent e)
1982 if (e instanceof MouseEvent)
1984 MouseEvent me = (MouseEvent) e;
1986 acquireComponentForMouseEvent(me);
1988 // Avoid dispatching ENTERED and EXITED events twice.
1989 if (mouseEventTarget != null
1990 && mouseEventTarget.isShowing()
1991 && e.getID() != MouseEvent.MOUSE_ENTERED
1992 && e.getID() != MouseEvent.MOUSE_EXITED)
1994 MouseEvent newEvt =
1995 SwingUtilities.convertMouseEvent(nativeContainer, me,
1996 mouseEventTarget);
1997 mouseEventTarget.dispatchEvent(newEvt);
1999 switch (e.getID())
2001 case MouseEvent.MOUSE_PRESSED:
2002 if (pressCount++ == 0)
2003 pressedComponent = mouseEventTarget;
2004 break;
2006 case MouseEvent.MOUSE_RELEASED:
2007 // Clear our memory of the original PRESSED event, only if
2008 // we're not expecting a CLICKED event after this. If
2009 // there is a CLICKED event after this, it will do clean up.
2010 if (--pressCount == 0
2011 && mouseEventTarget != pressedComponent)
2012 pressedComponent = null;
2013 break;
2015 if (newEvt.isConsumed())
2016 e.consume();
2020 return e.isConsumed();
2023 } // class LightweightDispatcher