1 /*
2 * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package java.awt;
26
27 import java.awt.dnd.DropTarget;
28
29 import java.awt.event;
30
31 import java.awt.peer.ContainerPeer;
32 import java.awt.peer.ComponentPeer;
33 import java.awt.peer.LightweightPeer;
34
35 import java.beans.PropertyChangeListener;
36
37 import java.io.IOException;
38 import java.io.ObjectInputStream;
39 import java.io.ObjectOutputStream;
40 import java.io.ObjectStreamField;
41 import java.io.PrintStream;
42 import java.io.PrintWriter;
43
44 import java.util.Arrays;
45 import java.util.EventListener;
46 import java.util.HashSet;
47 import java.util.Iterator;
48 import java.util.LinkedList;
49 import java.util.Set;
50
51 import java.util.logging;
52
53 import javax.accessibility;
54
55 import sun.awt.AppContext;
56 import sun.awt.CausedFocusEvent;
57 import sun.awt.PeerEvent;
58 import sun.awt.SunToolkit;
59
60 import sun.awt.dnd.SunDropTargetEvent;
61
62 import sun.java2d.pipe.Region;
63
64 /**
65 * A generic Abstract Window Toolkit(AWT) container object is a component
66 * that can contain other AWT components.
67 * <p>
68 * Components added to a container are tracked in a list. The order
69 * of the list will define the components' front-to-back stacking order
70 * within the container. If no index is specified when adding a
71 * component to a container, it will be added to the end of the list
72 * (and hence to the bottom of the stacking order).
73 * <p>
74 * <b>Note</b>: For details on the focus subsystem, see
75 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
76 * How to Use the Focus Subsystem</a>,
77 * a section in <em>The Java Tutorial</em>, and the
78 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
79 * for more information.
80 *
81 * @author Arthur van Hoff
82 * @author Sami Shaio
83 * @see #add(java.awt.Component, int)
84 * @see #getComponent(int)
85 * @see LayoutManager
86 * @since JDK1.0
87 */
88 public class Container extends Component {
89
90 private static final Logger log = Logger.getLogger("java.awt.Container");
91 private static final Logger eventLog = Logger.getLogger("java.awt.event.Container");
92
93 /**
94 * The number of components in this container.
95 * This value can be null.
96 * @see #getComponent
97 * @see #getComponents
98 * @see #getComponentCount
99 */
100 int ncomponents;
101
102 /**
103 * The components in this container.
104 * @see #add
105 * @see #getComponents
106 */
107 Component component[] = new Component[0];
108
109 /**
110 * Layout manager for this container.
111 * @see #doLayout
112 * @see #setLayout
113 * @see #getLayout
114 */
115 LayoutManager layoutMgr;
116
117 /**
118 * Event router for lightweight components. If this container
119 * is native, this dispatcher takes care of forwarding and
120 * retargeting the events to lightweight components contained
121 * (if any).
122 */
123 private LightweightDispatcher dispatcher;
124
125 /**
126 * The focus traversal policy that will manage keyboard traversal of this
127 * Container's children, if this Container is a focus cycle root. If the
128 * value is null, this Container inherits its policy from its focus-cycle-
129 * root ancestor. If all such ancestors of this Container have null
130 * policies, then the current KeyboardFocusManager's default policy is
131 * used. If the value is non-null, this policy will be inherited by all
132 * focus-cycle-root children that have no keyboard-traversal policy of
133 * their own (as will, recursively, their focus-cycle-root children).
134 * <p>
135 * If this Container is not a focus cycle root, the value will be
136 * remembered, but will not be used or inherited by this or any other
137 * Containers until this Container is made a focus cycle root.
138 *
139 * @see #setFocusTraversalPolicy
140 * @see #getFocusTraversalPolicy
141 * @since 1.4
142 */
143 private transient FocusTraversalPolicy focusTraversalPolicy;
144
145 /**
146 * Indicates whether this Component is the root of a focus traversal cycle.
147 * Once focus enters a traversal cycle, typically it cannot leave it via
148 * focus traversal unless one of the up- or down-cycle keys is pressed.
149 * Normal traversal is limited to this Container, and all of this
150 * Container's descendants that are not descendants of inferior focus cycle
151 * roots.
152 *
153 * @see #setFocusCycleRoot
154 * @see #isFocusCycleRoot
155 * @since 1.4
156 */
157 private boolean focusCycleRoot = false;
158
159
160 /**
161 * Stores the value of focusTraversalPolicyProvider property.
162 * @since 1.5
163 * @see #setFocusTraversalPolicyProvider
164 */
165 private boolean focusTraversalPolicyProvider;
166
167 // keeps track of the threads that are printing this component
168 private transient Set printingThreads;
169 // True if there is at least one thread that's printing this component
170 private transient boolean printing = false;
171
172 transient ContainerListener containerListener;
173
174 /* HierarchyListener and HierarchyBoundsListener support */
175 transient int listeningChildren;
176 transient int listeningBoundsChildren;
177 transient int descendantsCount;
178
179 /**
180 * JDK 1.1 serialVersionUID
181 */
182 private static final long serialVersionUID = 4613797578919906343L;
183
184 /**
185 * A constant which toggles one of the controllable behaviors
186 * of <code>getMouseEventTarget</code>. It is used to specify whether
187 * the method can return the Container on which it is originally called
188 * in case if none of its children are the current mouse event targets.
189 *
190 * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
191 */
192 static final boolean INCLUDE_SELF = true;
193
194 /**
195 * A constant which toggles one of the controllable behaviors
196 * of <code>getMouseEventTarget</code>. It is used to specify whether
197 * the method should search only lightweight components.
198 *
199 * @see #getMouseEventTarget(int, int, boolean, boolean, boolean)
200 */
201 static final boolean SEARCH_HEAVYWEIGHTS = true;
202
203 /*
204 * Number of HW or LW components in this container (including
205 * all descendant containers).
206 */
207 private transient int numOfHWComponents = 0;
208 private transient int numOfLWComponents = 0;
209
210 private static final Logger mixingLog = Logger.getLogger("java.awt.mixing.Container");
211
212 /**
213 * @serialField ncomponents int
214 * The number of components in this container.
215 * This value can be null.
216 * @serialField component Component[]
217 * The components in this container.
218 * @serialField layoutMgr LayoutManager
219 * Layout manager for this container.
220 * @serialField dispatcher LightweightDispatcher
221 * Event router for lightweight components. If this container
222 * is native, this dispatcher takes care of forwarding and
223 * retargeting the events to lightweight components contained
224 * (if any).
225 * @serialField maxSize Dimension
226 * Maximum size of this Container.
227 * @serialField focusCycleRoot boolean
228 * Indicates whether this Component is the root of a focus traversal cycle.
229 * Once focus enters a traversal cycle, typically it cannot leave it via
230 * focus traversal unless one of the up- or down-cycle keys is pressed.
231 * Normal traversal is limited to this Container, and all of this
232 * Container's descendants that are not descendants of inferior focus cycle
233 * roots.
234 * @serialField containerSerializedDataVersion int
235 * Container Serial Data Version.
236 * @serialField focusTraversalPolicyProvider boolean
237 * Stores the value of focusTraversalPolicyProvider property.
238 */
239 private static final ObjectStreamField[] serialPersistentFields = {
240 new ObjectStreamField("ncomponents", Integer.TYPE),
241 new ObjectStreamField("component", Component[].class),
242 new ObjectStreamField("layoutMgr", LayoutManager.class),
243 new ObjectStreamField("dispatcher", LightweightDispatcher.class),
244 new ObjectStreamField("maxSize", Dimension.class),
245 new ObjectStreamField("focusCycleRoot", Boolean.TYPE),
246 new ObjectStreamField("containerSerializedDataVersion", Integer.TYPE),
247 new ObjectStreamField("focusTraversalPolicyProvider", Boolean.TYPE),
248 };
249
250 static {
251 /* ensure that the necessary native libraries are loaded */
252 Toolkit.loadLibraries();
253 if (!GraphicsEnvironment.isHeadless()) {
254 initIDs();
255 }
256 }
257
258 /**
259 * Initialize JNI field and method IDs for fields that may be
260 called from C.
261 */
262 private static native void initIDs();
263
264 /**
265 * Constructs a new Container. Containers can be extended directly,
266 * but are lightweight in this case and must be contained by a parent
267 * somewhere higher up in the component tree that is native.
268 * (such as Frame for example).
269 */
270 public Container() {
271 }
272
273 void initializeFocusTraversalKeys() {
274 focusTraversalKeys = new Set[4];
275 }
276
277 /**
278 * Gets the number of components in this panel.
279 * @return the number of components in this panel.
280 * @see #getComponent
281 * @since JDK1.1
282 */
283 public int getComponentCount() {
284 return countComponents();
285 }
286
287 /**
288 * @deprecated As of JDK version 1.1,
289 * replaced by getComponentCount().
290 */
291 @Deprecated
292 public int countComponents() {
293 return ncomponents;
294 }
295
296 /**
297 * Gets the nth component in this container.
298 * @param n the index of the component to get.
299 * @return the n<sup>th</sup> component in this container.
300 * @exception ArrayIndexOutOfBoundsException
301 * if the n<sup>th</sup> value does not exist.
302 */
303 public Component getComponent(int n) {
304 synchronized (getTreeLock()) {
305 if ((n < 0) || (n >= ncomponents)) {
306 throw new ArrayIndexOutOfBoundsException("No such child: " + n);
307 }
308 return component[n];
309 }
310 }
311
312 /**
313 * Gets all the components in this container.
314 * @return an array of all the components in this container.
315 */
316 public Component[] getComponents() {
317 return getComponents_NoClientCode();
318 }
319 // NOTE: This method may be called by privileged threads.
320 // This functionality is implemented in a package-private method
321 // to insure that it cannot be overridden by client subclasses.
322 // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
323 final Component[] getComponents_NoClientCode() {
324 synchronized (getTreeLock()) {
325 return Arrays.copyOf(component, ncomponents);
326 }
327 } // getComponents_NoClientCode()
328
329 /**
330 * Determines the insets of this container, which indicate the size
331 * of the container's border.
332 * <p>
333 * A <code>Frame</code> object, for example, has a top inset that
334 * corresponds to the height of the frame's title bar.
335 * @return the insets of this container.
336 * @see Insets
337 * @see LayoutManager
338 * @since JDK1.1
339 */
340 public Insets getInsets() {
341 return insets();
342 }
343
344 /**
345 * @deprecated As of JDK version 1.1,
346 * replaced by <code>getInsets()</code>.
347 */
348 @Deprecated
349 public Insets insets() {
350 ComponentPeer peer = this.peer;
351 if (peer instanceof ContainerPeer) {
352 ContainerPeer cpeer = (ContainerPeer)peer;
353 return (Insets)cpeer.insets().clone();
354 }
355 return new Insets(0, 0, 0, 0);
356 }
357
358 /**
359 * Appends the specified component to the end of this container.
360 * This is a convenience method for {@link #addImpl}.
361 * <p>
362 * Note: If a component has been added to a container that
363 * has been displayed, <code>validate</code> must be
364 * called on that container to display the new component.
365 * If multiple components are being added, you can improve
366 * efficiency by calling <code>validate</code> only once,
367 * after all the components have been added.
368 *
369 * @param comp the component to be added
370 * @exception NullPointerException if {@code comp} is {@code null}
371 * @see #addImpl
372 * @see #validate
373 * @see javax.swing.JComponent#revalidate()
374 * @return the component argument
375 */
376 public Component add(Component comp) {
377 addImpl(comp, null, -1);
378 return comp;
379 }
380
381 /**
382 * Adds the specified component to this container.
383 * This is a convenience method for {@link #addImpl}.
384 * <p>
385 * This method is obsolete as of 1.1. Please use the
386 * method <code>add(Component, Object)</code> instead.
387 * @exception NullPointerException if {@code comp} is {@code null}
388 * @see #add(Component, Object)
389 */
390 public Component add(String name, Component comp) {
391 addImpl(comp, name, -1);
392 return comp;
393 }
394
395 /**
396 * Adds the specified component to this container at the given
397 * position.
398 * This is a convenience method for {@link #addImpl}.
399 * <p>
400 * Note: If a component has been added to a container that
401 * has been displayed, <code>validate</code> must be
402 * called on that container to display the new component.
403 * If multiple components are being added, you can improve
404 * efficiency by calling <code>validate</code> only once,
405 * after all the components have been added.
406 *
407 * @param comp the component to be added
408 * @param index the position at which to insert the component,
409 * or <code>-1</code> to append the component to the end
410 * @exception NullPointerException if {@code comp} is {@code null}
411 * @exception IllegalArgumentException if {@code index} is invalid (see
412 * {@link #addImpl} for details)
413 * @return the component <code>comp</code>
414 * @see #addImpl
415 * @see #remove
416 * @see #validate
417 * @see javax.swing.JComponent#revalidate()
418 */
419 public Component add(Component comp, int index) {
420 addImpl(comp, null, index);
421 return comp;
422 }
423
424 /**
425 * Checks that the component comp can be added to this container
426 * Checks : index in bounds of container's size,
427 * comp is not one of this container's parents,
428 * and comp is not a window.
429 * Comp and container must be on the same GraphicsDevice.
430 * if comp is container, all sub-components must be on
431 * same GraphicsDevice.
432 *
433 * @since 1.5
434 */
435 private void checkAdding(Component comp, int index) {
436 checkTreeLock();
437
438 GraphicsConfiguration thisGC = getGraphicsConfiguration();
439
440 if (index > ncomponents || index < 0) {
441 throw new IllegalArgumentException("illegal component position");
442 }
443 if (comp.parent == this) {
444 if (index == ncomponents) {
445 throw new IllegalArgumentException("illegal component position " +
446 index + " should be less then " + ncomponents);
447 }
448 }
449 if (comp instanceof Container) {
450 for (Container cn = this; cn != null; cn=cn.parent) {
451 if (cn == comp) {
452 throw new IllegalArgumentException("adding container's parent to itself");
453 }
454 }
455
456 if (comp instanceof Window) {
457 throw new IllegalArgumentException("adding a window to a container");
458 }
459 }
460 Window thisTopLevel = getContainingWindow();
461 Window compTopLevel = comp.getContainingWindow();
462 if (thisTopLevel != compTopLevel) {
463 throw new IllegalArgumentException("component and container should be in the same top-level window");
464 }
465 if (thisGC != null) {
466 comp.checkGD(thisGC.getDevice().getIDstring());
467 }
468 }
469
470 /**
471 * Removes component comp from this container without making unneccessary changes
472 * and generating unneccessary events. This function intended to perform optimized
473 * remove, for example, if newParent and current parent are the same it just changes
474 * index without calling removeNotify.
475 * Note: Should be called while holding treeLock
476 * Returns whether removeNotify was invoked
477 * @since: 1.5
478 */
479 private boolean removeDelicately(Component comp, Container newParent, int newIndex) {
480 checkTreeLock();
481
482 int index = getComponentZOrder(comp);
483 boolean needRemoveNotify = isRemoveNotifyNeeded(comp, this, newParent);
484 if (needRemoveNotify) {
485 comp.removeNotify();
486 }
487 if (newParent != this) {
488 if (layoutMgr != null) {
489 layoutMgr.removeLayoutComponent(comp);
490 }
491 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
492 -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
493 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
494 -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
495 adjustDescendants(-(comp.countHierarchyMembers()));
496
497 comp.parent = null;
498 System.arraycopy(component, index + 1,
499 component, index,
500 ncomponents - index - 1);
501 component[--ncomponents] = null;
502
503 if (valid) {
504 invalidate();
505 }
506 } else {
507 if (newIndex > index) { // 2->4: 012345 -> 013425, 2->5: 012345 -> 013452
508 if (newIndex-index > 0) {
509 System.arraycopy(component, index+1, component, index, newIndex-index);
510 }
511 } else { // 4->2: 012345 -> 014235
512 if (index-newIndex > 0) {
513 System.arraycopy(component, newIndex, component, newIndex+1, index-newIndex);
514 }
515 }
516 component[newIndex] = comp;
517 }
518 if (comp.parent == null) { // was actually removed
519 if (containerListener != null ||
520 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
521 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
522 ContainerEvent e = new ContainerEvent(this,
523 ContainerEvent.COMPONENT_REMOVED,
524 comp);
525 dispatchEvent(e);
526
527 }
528 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
529 this, HierarchyEvent.PARENT_CHANGED,
530 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
531 if (peer != null && layoutMgr == null && isVisible()) {
532 updateCursorImmediately();
533 }
534 }
535 return needRemoveNotify;
536 }
537
538 /**
539 * Checks whether this container can contain component which is focus owner.
540 * Verifies that container is enable and showing, and if it is focus cycle root
541 * its FTP allows component to be focus owner
542 * @since 1.5
543 */
544 boolean canContainFocusOwner(Component focusOwnerCandidate) {
545 if (!(isEnabled() && isDisplayable()
546 && isVisible() && isFocusable()))
547 {
548 return false;
549 }
550 if (isFocusCycleRoot()) {
551 FocusTraversalPolicy policy = getFocusTraversalPolicy();
552 if (policy instanceof DefaultFocusTraversalPolicy) {
553 if (!((DefaultFocusTraversalPolicy)policy).accept(focusOwnerCandidate)) {
554 return false;
555 }
556 }
557 }
558 synchronized(getTreeLock()) {
559 if (parent != null) {
560 return parent.canContainFocusOwner(focusOwnerCandidate);
561 }
562 }
563 return true;
564 }
565
566 /**
567 * Checks whether or not this container has heavyweight children.
568 * Note: Should be called while holding tree lock
569 * @return true if there is at least one heavyweight children in a container, false otherwise
570 * @since 1.5
571 */
572 private boolean hasHeavyweightDescendants() {
573 checkTreeLock();
574 return numOfHWComponents > 0;
575 }
576
577 /**
578 * Checks whether or not this container has lightweight children.
579 * Note: Should be called while holding tree lock
580 * @return true if there is at least one lightweight children in a container, false otherwise
581 * @since 1.7
582 */
583 private boolean hasLightweightDescendants() {
584 checkTreeLock();
585 return numOfLWComponents > 0;
586 }
587
588 /**
589 * Returns closest heavyweight component to this container. If this container is heavyweight
590 * returns this.
591 * @since 1.5
592 */
593 Container getHeavyweightContainer() {
594 checkTreeLock();
595 if (peer != null && !(peer instanceof LightweightPeer)) {
596 return this;
597 } else {
598 return getNativeContainer();
599 }
600 }
601
602 /**
603 * Detects whether or not remove from current parent and adding to new parent requires call of
604 * removeNotify on the component. Since removeNotify destroys native window this might (not)
605 * be required. For example, if new container and old containers are the same we don't need to
606 * destroy native window.
607 * @since: 1.5
608 */
609 private static boolean isRemoveNotifyNeeded(Component comp, Container oldContainer, Container newContainer) {
610 if (oldContainer == null) { // Component didn't have parent - no removeNotify
611 return false;
612 }
613 if (comp.peer == null) { // Component didn't have peer - no removeNotify
614 return false;
615 }
616 if (newContainer.peer == null) {
617 // Component has peer but new Container doesn't - call removeNotify
618 return true;
619 }
620
621 // If component is lightweight non-Container or lightweight Container with all but heavyweight
622 // children there is no need to call remove notify
623 if (comp.isLightweight()) {
624 boolean isContainer = comp instanceof Container;
625
626 if (!isContainer || (isContainer && !((Container)comp).hasHeavyweightDescendants())) {
627 return false;
628 }
629 }
630
631 // If this point is reached, then the comp is either a HW or a LW container with HW descendants.
632
633 // All three components have peers, check for peer change
634 Container newNativeContainer = oldContainer.getHeavyweightContainer();
635 Container oldNativeContainer = newContainer.getHeavyweightContainer();
636 if (newNativeContainer != oldNativeContainer) {
637 // Native containers change - check whether or not current platform supports
638 // changing of widget hierarchy on native level without recreation.
639 // The current implementation forbids reparenting of LW containers with HW descendants
640 // into another native container w/o destroying the peers. Actually such an operation
641 // is quite rare. If we ever need to save the peers, we'll have to slightly change the
642 // addDelicately() method in order to handle such LW containers recursively, reparenting
643 // each HW descendant independently.
644 return !comp.peer.isReparentSupported();
645 } else {
646 // if container didn't change we still might need to recreate component's window as
647 // changes to zorder should be reflected in native window stacking order and it might
648 // not be supported by the platform. This is important only for heavyweight child
649 return !((ContainerPeer)(newNativeContainer.peer)).isRestackSupported();
650 }
651 }
652
653 /**
654 * Moves the specified component to the specified z-order index in
655 * the container. The z-order determines the order that components
656 * are painted; the component with the highest z-order paints first
657 * and the component with the lowest z-order paints last.
658 * Where components overlap, the component with the lower
659 * z-order paints over the component with the higher z-order.
660 * <p>
661 * If the component is a child of some other container, it is
662 * removed from that container before being added to this container.
663 * The important difference between this method and
664 * <code>java.awt.Container.add(Component, int)</code> is that this method
665 * doesn't call <code>removeNotify</code> on the component while
666 * removing it from its previous container unless necessary and when
667 * allowed by the underlying native windowing system. This way, if the
668 * component has the keyboard focus, it maintains the focus when
669 * moved to the new position.
670 * <p>
671 * This property is guaranteed to apply only to lightweight
672 * non-<code>Container</code> components.
673 * <p>
674 * <b>Note</b>: Not all platforms support changing the z-order of
675 * heavyweight components from one container into another without
676 * the call to <code>removeNotify</code>. There is no way to detect
677 * whether a platform supports this, so developers shouldn't make
678 * any assumptions.
679 *
680 * @param comp the component to be moved
681 * @param index the position in the container's list to
682 * insert the component, where <code>getComponentCount()</code>
683 * appends to the end
684 * @exception NullPointerException if <code>comp</code> is
685 * <code>null</code>
686 * @exception IllegalArgumentException if <code>comp</code> is one of the
687 * container's parents
688 * @exception IllegalArgumentException if <code>index</code> is not in
689 * the range <code>[0, getComponentCount()]</code> for moving
690 * between containers, or not in the range
691 * <code>[0, getComponentCount()-1]</code> for moving inside
692 * a container
693 * @exception IllegalArgumentException if adding a container to itself
694 * @exception IllegalArgumentException if adding a <code>Window</code>
695 * to a container
696 * @see #getComponentZOrder(java.awt.Component)
697 * @since 1.5
698 */
699 public void setComponentZOrder(Component comp, int index) {
700 synchronized (getTreeLock()) {
701 // Store parent because remove will clear it
702 Container curParent = comp.parent;
703 int oldZindex = getComponentZOrder(comp);
704
705 if (curParent == this && index == oldZindex) {
706 return;
707 }
708 checkAdding(comp, index);
709
710 boolean peerRecreated = (curParent != null) ?
711 curParent.removeDelicately(comp, this, index) : false;
712
713 addDelicately(comp, curParent, index);
714
715 // If the oldZindex == -1, the component gets inserted,
716 // rather than it changes its z-order.
717 if (!peerRecreated && oldZindex != -1) {
718 // The new 'index' cannot be == -1.
719 // It gets checked at the checkAdding() method.
720 // Therefore both oldZIndex and index denote
721 // some existing positions at this point and
722 // this is actually a Z-order changing.
723 comp.mixOnZOrderChanging(oldZindex, index);
724 }
725 }
726 }
727
728 /**
729 * Traverses the tree of components and reparents children heavyweight component
730 * to new heavyweight parent.
731 * @since 1.5
732 */
733 private void reparentTraverse(ContainerPeer parentPeer, Container child) {
734 checkTreeLock();
735
736 for (int i = 0; i < child.getComponentCount(); i++) {
737 Component comp = child.getComponent(i);
738 if (comp.isLightweight()) {
739 // If components is lightweight check if it is container
740 // If it is container it might contain heavyweight children we need to reparent
741 if (comp instanceof Container) {
742 reparentTraverse(parentPeer, (Container)comp);
743 }
744 } else {
745 // Q: Need to update NativeInLightFixer?
746 comp.getPeer().reparent(parentPeer);
747 }
748 }
749 }
750
751 /**
752 * Reparents child component peer to this container peer.
753 * Container must be heavyweight.
754 * @since 1.5
755 */
756 private void reparentChild(Component comp) {
757 checkTreeLock();
758 if (comp == null) {
759 return;
760 }
761 if (comp.isLightweight()) {
762 // If component is lightweight container we need to reparent all its explicit heavyweight children
763 if (comp instanceof Container) {
764 // Traverse component's tree till depth-first until encountering heavyweight component
765 reparentTraverse((ContainerPeer)getPeer(), (Container)comp);
766 }
767 } else {
768 comp.getPeer().reparent((ContainerPeer)getPeer());
769 }
770 }
771
772 /**
773 * Adds component to this container. Tries to minimize side effects of this adding -
774 * doesn't call remove notify if it is not required.
775 * @since 1.5
776 */
777 private void addDelicately(Component comp, Container curParent, int index) {
778 checkTreeLock();
779
780 // Check if moving between containers
781 if (curParent != this) {
782 /* Add component to list; allocate new array if necessary. */
783 if (ncomponents == component.length) {
784 component = Arrays.copyOf(component, ncomponents * 2 + 1);
785 }
786 if (index == -1 || index == ncomponents) {
787 component[ncomponents++] = comp;
788 } else {
789 System.arraycopy(component, index, component,
790 index + 1, ncomponents - index);
791 component[index] = comp;
792 ncomponents++;
793 }
794 comp.parent = this;
795
796 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
797 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
798 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
799 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
800 adjustDescendants(comp.countHierarchyMembers());
801 } else {
802 if (index < ncomponents) {
803 component[index] = comp;
804 }
805 }
806
807 if (valid) {
808 invalidate();
809 }
810 if (peer != null) {
811 if (comp.peer == null) { // Remove notify was called or it didn't have peer - create new one
812 comp.addNotify();
813 // New created peer creates component on top of the stacking order
814 Container newNativeContainer = getHeavyweightContainer();
815 if (((ContainerPeer)newNativeContainer.getPeer()).isRestackSupported()) {
816 ((ContainerPeer)newNativeContainer.getPeer()).restack();
817 }
818 } else { // Both container and child have peers, it means child peer should be reparented.
819 // In both cases we need to reparent native widgets.
820 Container newNativeContainer = getHeavyweightContainer();
821 Container oldNativeContainer = curParent.getHeavyweightContainer();
822 if (oldNativeContainer != newNativeContainer) {
823 // Native container changed - need to reparent native widgets
824 newNativeContainer.reparentChild(comp);
825 }
826 // If component still has a peer and it is either container or heavyweight
827 // and restack is supported we have to restack native windows since order might have changed
828 if ((!comp.isLightweight() || (comp instanceof Container))
829 && ((ContainerPeer)newNativeContainer.getPeer()).isRestackSupported())
830 {
831 ((ContainerPeer)newNativeContainer.getPeer()).restack();
832 }
833 if (!comp.isLightweight() && isLightweight()) {
834 // If component is heavyweight and one of the containers is lightweight
835 // the location of the component should be fixed.
836 comp.relocateComponent();
837 }
838 }
839 }
840 if (curParent != this) {
841 /* Notify the layout manager of the added component. */
842 if (layoutMgr != null) {
843 if (layoutMgr instanceof LayoutManager2) {
844 ((LayoutManager2)layoutMgr).addLayoutComponent(comp, null);
845 } else {
846 layoutMgr.addLayoutComponent(null, comp);
847 }
848 }
849 if (containerListener != null ||
850 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
851 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
852 ContainerEvent e = new ContainerEvent(this,
853 ContainerEvent.COMPONENT_ADDED,
854 comp);
855 dispatchEvent(e);
856 }
857 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
858 this, HierarchyEvent.PARENT_CHANGED,
859 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
860
861 // If component is focus owner or parent container of focus owner check that after reparenting
862 // focus owner moved out if new container prohibit this kind of focus owner.
863 if (comp.isFocusOwner() && !comp.canBeFocusOwner()) {
864 comp.transferFocus();
865 } else if (comp instanceof Container) {
866 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
867 if (focusOwner != null && isParentOf(focusOwner) && !focusOwner.canBeFocusOwner()) {
868 focusOwner.transferFocus();
869 }
870 }
871 } else {
872 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
873 this, HierarchyEvent.HIERARCHY_CHANGED,
874 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
875 }
876
877 if (peer != null && layoutMgr == null && isVisible()) {
878 updateCursorImmediately();
879 }
880 }
881
882 /**
883 * Returns the z-order index of the component inside the container.
884 * The higher a component is in the z-order hierarchy, the lower
885 * its index. The component with the lowest z-order index is
886 * painted last, above all other child components.
887 *
888 * @param comp the component being queried
889 * @return the z-order index of the component; otherwise
890 * returns -1 if the component is <code>null</code>
891 * or doesn't belong to the container
892 * @see #setComponentZOrder(java.awt.Component, int)
893 * @since 1.5
894 */
895 public int getComponentZOrder(Component comp) {
896 if (comp == null) {
897 return -1;
898 }
899 synchronized(getTreeLock()) {
900 // Quick check - container should be immediate parent of the component
901 if (comp.parent != this) {
902 return -1;
903 }
904 for (int i = 0; i < ncomponents; i++) {
905 if (component[i] == comp) {
906 return i;
907 }
908 }
909 }
910 // To please javac
911 return -1;
912 }
913
914 /**
915 * Adds the specified component to the end of this container.
916 * Also notifies the layout manager to add the component to
917 * this container's layout using the specified constraints object.
918 * This is a convenience method for {@link #addImpl}.
919 * <p>
920 * Note: If a component has been added to a container that
921 * has been displayed, <code>validate</code> must be
922 * called on that container to display the new component.
923 * If multiple components are being added, you can improve
924 * efficiency by calling <code>validate</code> only once,
925 * after all the components have been added.
926 *
927 * @param comp the component to be added
928 * @param constraints an object expressing
929 * layout contraints for this component
930 * @exception NullPointerException if {@code comp} is {@code null}
931 * @see #addImpl
932 * @see #validate
933 * @see javax.swing.JComponent#revalidate()
934 * @see LayoutManager
935 * @since JDK1.1
936 */
937 public void add(Component comp, Object constraints) {
938 addImpl(comp, constraints, -1);
939 }
940
941 /**
942 * Adds the specified component to this container with the specified
943 * constraints at the specified index. Also notifies the layout
944 * manager to add the component to the this container's layout using
945 * the specified constraints object.
946 * This is a convenience method for {@link #addImpl}.
947 * <p>
948 * Note: If a component has been added to a container that
949 * has been displayed, <code>validate</code> must be
950 * called on that container to display the new component.
951 * If multiple components are being added, you can improve
952 * efficiency by calling <code>validate</code> only once,
953 * after all the components have been added.
954 *
955 * @param comp the component to be added
956 * @param constraints an object expressing layout contraints for this
957 * @param index the position in the container's list at which to insert
958 * the component; <code>-1</code> means insert at the end
959 * component
960 * @exception NullPointerException if {@code comp} is {@code null}
961 * @exception IllegalArgumentException if {@code index} is invalid (see
962 * {@link #addImpl} for details)
963 * @see #addImpl
964 * @see #validate
965 * @see javax.swing.JComponent#revalidate()
966 * @see #remove
967 * @see LayoutManager
968 */
969 public void add(Component comp, Object constraints, int index) {
970 addImpl(comp, constraints, index);
971 }
972
973 /**
974 * Adds the specified component to this container at the specified
975 * index. This method also notifies the layout manager to add
976 * the component to this container's layout using the specified
977 * constraints object via the <code>addLayoutComponent</code>
978 * method.
979 * <p>
980 * The constraints are
981 * defined by the particular layout manager being used. For
982 * example, the <code>BorderLayout</code> class defines five
983 * constraints: <code>BorderLayout.NORTH</code>,
984 * <code>BorderLayout.SOUTH</code>, <code>BorderLayout.EAST</code>,
985 * <code>BorderLayout.WEST</code>, and <code>BorderLayout.CENTER</code>.
986 * <p>
987 * The <code>GridBagLayout</code> class requires a
988 * <code>GridBagConstraints</code> object. Failure to pass
989 * the correct type of constraints object results in an
990 * <code>IllegalArgumentException</code>.
991 * <p>
992 * If the current layout manager implements {@code LayoutManager2}, then
993 * {@link LayoutManager2#addLayoutComponent(Component,Object)} is invoked on
994 * it. If the current layout manager does not implement
995 * {@code LayoutManager2}, and constraints is a {@code String}, then
996 * {@link LayoutManager#addLayoutComponent(String,Component)} is invoked on it.
997 * <p>
998 * If the component is not an ancestor of this container and has a non-null
999 * parent, it is removed from its current parent before it is added to this
1000 * container.
1001 * <p>
1002 * This is the method to override if a program needs to track
1003 * every add request to a container as all other add methods defer
1004 * to this one. An overriding method should
1005 * usually include a call to the superclass's version of the method:
1006 * <p>
1007 * <blockquote>
1008 * <code>super.addImpl(comp, constraints, index)</code>
1009 * </blockquote>
1010 * <p>
1011 * @param comp the component to be added
1012 * @param constraints an object expressing layout constraints
1013 * for this component
1014 * @param index the position in the container's list at which to
1015 * insert the component, where <code>-1</code>
1016 * means append to the end
1017 * @exception IllegalArgumentException if {@code index} is invalid;
1018 * if {@code comp} is a child of this container, the valid
1019 * range is {@code [-1, getComponentCount()-1]}; if component is
1020 * not a child of this container, the valid range is
1021 * {@code [-1, getComponentCount()]}
1022 *
1023 * @exception IllegalArgumentException if {@code comp} is an ancestor of
1024 * this container
1025 * @exception IllegalArgumentException if adding a window to a container
1026 * @exception NullPointerException if {@code comp} is {@code null}
1027 * @see #add(Component)
1028 * @see #add(Component, int)
1029 * @see #add(Component, java.lang.Object)
1030 * @see LayoutManager
1031 * @see LayoutManager2
1032 * @since JDK1.1
1033 */
1034 protected void addImpl(Component comp, Object constraints, int index) {
1035 synchronized (getTreeLock()) {
1036 /* Check for correct arguments: index in bounds,
1037 * comp cannot be one of this container's parents,
1038 * and comp cannot be a window.
1039 * comp and container must be on the same GraphicsDevice.
1040 * if comp is container, all sub-components must be on
1041 * same GraphicsDevice.
1042 */
1043 GraphicsConfiguration thisGC = this.getGraphicsConfiguration();
1044
1045 if (index > ncomponents || (index < 0 && index != -1)) {
1046 throw new IllegalArgumentException(
1047 "illegal component position");
1048 }
1049 if (comp instanceof Container) {
1050 for (Container cn = this; cn != null; cn=cn.parent) {
1051 if (cn == comp) {
1052 throw new IllegalArgumentException(
1053 "adding container's parent to itself");
1054 }
1055 }
1056 if (comp instanceof Window) {
1057 throw new IllegalArgumentException(
1058 "adding a window to a container");
1059 }
1060 }
1061 if (thisGC != null) {
1062 comp.checkGD(thisGC.getDevice().getIDstring());
1063 }
1064
1065 /* Reparent the component and tidy up the tree's state. */
1066 if (comp.parent != null) {
1067 comp.parent.remove(comp);
1068 if (index > ncomponents) {
1069 throw new IllegalArgumentException("illegal component position");
1070 }
1071 }
1072
1073 /* Add component to list; allocate new array if necessary. */
1074 if (ncomponents == component.length) {
1075 component = Arrays.copyOf(component, ncomponents * 2 + 1);
1076 }
1077 if (index == -1 || index == ncomponents) {
1078 component[ncomponents++] = comp;
1079 } else {
1080 System.arraycopy(component, index, component,
1081 index + 1, ncomponents - index);
1082 component[index] = comp;
1083 ncomponents++;
1084 }
1085 comp.parent = this;
1086
1087 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1088 comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1089 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1090 comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1091 adjustDescendants(comp.countHierarchyMembers());
1092
1093 if (valid) {
1094 invalidate();
1095 }
1096 if (peer != null) {
1097 comp.addNotify();
1098 }
1099
1100 /* Notify the layout manager of the added component. */
1101 if (layoutMgr != null) {
1102 if (layoutMgr instanceof LayoutManager2) {
1103 ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);
1104 } else if (constraints instanceof String) {
1105 layoutMgr.addLayoutComponent((String)constraints, comp);
1106 }
1107 }
1108 if (containerListener != null ||
1109 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1110 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1111 ContainerEvent e = new ContainerEvent(this,
1112 ContainerEvent.COMPONENT_ADDED,
1113 comp);
1114 dispatchEvent(e);
1115 }
1116
1117 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
1118 this, HierarchyEvent.PARENT_CHANGED,
1119 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1120 if (peer != null && layoutMgr == null && isVisible()) {
1121 updateCursorImmediately();
1122 }
1123 }
1124 }
1125
1126 /**
1127 * Checks that all Components that this Container contains are on
1128 * the same GraphicsDevice as this Container. If not, throws an
1129 * IllegalArgumentException.
1130 */
1131 void checkGD(String stringID) {
1132 Component tempComp;
1133 for (int i = 0; i < component.length; i++) {
1134 tempComp= component[i];
1135 if (tempComp != null) {
1136 tempComp.checkGD(stringID);
1137 }
1138 }
1139 }
1140
1141 /**
1142 * Removes the component, specified by <code>index</code>,
1143 * from this container.
1144 * This method also notifies the layout manager to remove the
1145 * component from this container's layout via the
1146 * <code>removeLayoutComponent</code> method.
1147 *
1148 * <p>
1149 * Note: If a component has been removed from a container that
1150 * had been displayed, {@link #validate} must be
1151 * called on that container to reflect changes.
1152 * If multiple components are being removed, you can improve
1153 * efficiency by calling {@link #validate} only once,
1154 * after all the components have been removed.
1155 *
1156 * @param index the index of the component to be removed
1157 * @throws ArrayIndexOutOfBoundsException if {@code index} is not in
1158 * range {@code [0, getComponentCount()-1]}
1159 * @see #add
1160 * @see #validate
1161 * @see #getComponentCount
1162 * @since JDK1.1
1163 */
1164 public void remove(int index) {
1165 synchronized (getTreeLock()) {
1166 if (index < 0 || index >= ncomponents) {
1167 throw new ArrayIndexOutOfBoundsException(index);
1168 }
1169 Component comp = component[index];
1170 if (peer != null) {
1171 comp.removeNotify();
1172 }
1173 if (layoutMgr != null) {
1174 layoutMgr.removeLayoutComponent(comp);
1175 }
1176
1177 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1178 -comp.numListening(AWTEvent.HIERARCHY_EVENT_MASK));
1179 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1180 -comp.numListening(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1181 adjustDescendants(-(comp.countHierarchyMembers()));
1182
1183 comp.parent = null;
1184 System.arraycopy(component, index + 1,
1185 component, index,
1186 ncomponents - index - 1);
1187 component[--ncomponents] = null;
1188
1189 if (valid) {
1190 invalidate();
1191 }
1192 if (containerListener != null ||
1193 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1194 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1195 ContainerEvent e = new ContainerEvent(this,
1196 ContainerEvent.COMPONENT_REMOVED,
1197 comp);
1198 dispatchEvent(e);
1199 }
1200
1201 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, comp,
1202 this, HierarchyEvent.PARENT_CHANGED,
1203 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1204 if (peer != null && layoutMgr == null && isVisible()) {
1205 updateCursorImmediately();
1206 }
1207 }
1208 }
1209
1210 /**
1211 * Removes the specified component from this container.
1212 * This method also notifies the layout manager to remove the
1213 * component from this container's layout via the
1214 * <code>removeLayoutComponent</code> method.
1215 *
1216 * <p>
1217 * Note: If a component has been removed from a container that
1218 * had been displayed, {@link #validate} must be
1219 * called on that container to reflect changes.
1220 * If multiple components are being removed, you can improve
1221 * efficiency by calling {@link #validate} only once,
1222 * after all the components have been removed.
1223 *
1224 * @param comp the component to be removed
1225 * @see #add
1226 * @see #validate
1227 * @see #remove(int)
1228 */
1229 public void remove(Component comp) {
1230 synchronized (getTreeLock()) {
1231 if (comp.parent == this) {
1232 /* Search backwards, expect that more recent additions
1233 * are more likely to be removed.
1234 */
1235 Component component[] = this.component;
1236 for (int i = ncomponents; --i >= 0; ) {
1237 if (component[i] == comp) {
1238 remove(i);
1239 }
1240 }
1241 }
1242 }
1243 }
1244
1245 /**
1246 * Removes all the components from this container.
1247 * This method also notifies the layout manager to remove the
1248 * components from this container's layout via the
1249 * <code>removeLayoutComponent</code> method.
1250 * @see #add
1251 * @see #remove
1252 */
1253 public void removeAll() {
1254 synchronized (getTreeLock()) {
1255 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
1256 -listeningChildren);
1257 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
1258 -listeningBoundsChildren);
1259 adjustDescendants(-descendantsCount);
1260
1261 while (ncomponents > 0) {
1262 Component comp = component[--ncomponents];
1263 component[ncomponents] = null;
1264
1265 if (peer != null) {
1266 comp.removeNotify();
1267 }
1268 if (layoutMgr != null) {
1269 layoutMgr.removeLayoutComponent(comp);
1270 }
1271 comp.parent = null;
1272 if (containerListener != null ||
1273 (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
1274 Toolkit.enabledOnToolkit(AWTEvent.CONTAINER_EVENT_MASK)) {
1275 ContainerEvent e = new ContainerEvent(this,
1276 ContainerEvent.COMPONENT_REMOVED,
1277 comp);
1278 dispatchEvent(e);
1279 }
1280
1281 comp.createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
1282 comp, this,
1283 HierarchyEvent.PARENT_CHANGED,
1284 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
1285 }
1286 if (peer != null && layoutMgr == null && isVisible()) {
1287 updateCursorImmediately();
1288 }
1289 if (valid) {
1290 invalidate();
1291 }
1292 }
1293 }
1294
1295 // Should only be called while holding tree lock
1296 int numListening(long mask) {
1297 int superListening = super.numListening(mask);
1298
1299 if (mask == AWTEvent.HIERARCHY_EVENT_MASK) {
1300 if (eventLog.isLoggable(Level.FINE)) {
1301 // Verify listeningChildren is correct
1302 int sum = 0;
1303 for (int i = 0; i < ncomponents; i++) {
1304 sum += component[i].numListening(mask);
1305 }
1306 if (listeningChildren != sum) {
1307 eventLog.log(Level.FINE, "Assertion (listeningChildren == sum) failed");
1308 }
1309 }
1310 return listeningChildren + superListening;
1311 } else if (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) {
1312 if (eventLog.isLoggable(Level.FINE)) {
1313 // Verify listeningBoundsChildren is correct
1314 int sum = 0;
1315 for (int i = 0; i < ncomponents; i++) {
1316 sum += component[i].numListening(mask);
1317 }
1318 if (listeningBoundsChildren != sum) {
1319 eventLog.log(Level.FINE, "Assertion (listeningBoundsChildren == sum) failed");
1320 }
1321 }
1322 return listeningBoundsChildren + superListening;
1323 } else {
1324 // assert false;
1325 if (eventLog.isLoggable(Level.FINE)) {
1326 eventLog.log(Level.FINE, "This code must never be reached");
1327 }
1328 return superListening;
1329 }
1330 }
1331
1332 // Should only be called while holding tree lock
1333 void adjustListeningChildren(long mask, int num) {
1334 if (eventLog.isLoggable(Level.FINE)) {
1335 boolean toAssert = (mask == AWTEvent.HIERARCHY_EVENT_MASK ||
1336 mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK ||
1337 mask == (AWTEvent.HIERARCHY_EVENT_MASK |
1338 AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
1339 if (!toAssert) {
1340 eventLog.log(Level.FINE, "Assertion failed");
1341 }
1342 }
1343
1344 if (num == 0)
1345 return;
1346
1347 if ((mask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) {
1348 listeningChildren += num;
1349 }
1350 if ((mask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) {
1351 listeningBoundsChildren += num;
1352 }
1353
1354 adjustListeningChildrenOnParent(mask, num);
1355 }
1356
1357 // Should only be called while holding tree lock
1358 void adjustDescendants(int num) {
1359 if (num == 0)
1360 return;
1361
1362 descendantsCount += num;
1363 adjustDecendantsOnParent(num);
1364 }
1365
1366 // Should only be called while holding tree lock
1367 void adjustDecendantsOnParent(int num) {
1368 if (parent != null) {
1369 parent.adjustDescendants(num);
1370 }
1371 }
1372
1373 // Should only be called while holding tree lock
1374 int countHierarchyMembers() {
1375 if (log.isLoggable(Level.FINE)) {
1376 // Verify descendantsCount is correct
1377 int sum = 0;
1378 for (int i = 0; i < ncomponents; i++) {
1379 sum += component[i].countHierarchyMembers();
1380 }
1381 if (descendantsCount != sum) {
1382 log.log(Level.FINE, "Assertion (descendantsCount == sum) failed");
1383 }
1384 }
1385 return descendantsCount + 1;
1386 }
1387
1388 private int getListenersCount(int id, boolean enabledOnToolkit) {
1389 assert Thread.holdsLock(getTreeLock());
1390 if (enabledOnToolkit) {
1391 return descendantsCount;
1392 }
1393 switch (id) {
1394 case HierarchyEvent.HIERARCHY_CHANGED:
1395 return listeningChildren;
1396 case HierarchyEvent.ANCESTOR_MOVED:
1397 case HierarchyEvent.ANCESTOR_RESIZED:
1398 return listeningBoundsChildren;
1399 default:
1400 return 0;
1401 }
1402 }
1403
1404 final int createHierarchyEvents(int id, Component changed,
1405 Container changedParent, long changeFlags, boolean enabledOnToolkit)
1406 {
1407 assert Thread.holdsLock(getTreeLock());
1408 int listeners = getListenersCount(id, enabledOnToolkit);
1409
1410 for (int count = listeners, i = 0; count > 0; i++) {
1411 count -= component[i].createHierarchyEvents(id, changed,
1412 changedParent, changeFlags, enabledOnToolkit);
1413 }
1414 return listeners +
1415 super.createHierarchyEvents(id, changed, changedParent,
1416 changeFlags, enabledOnToolkit);
1417 }
1418
1419 final void createChildHierarchyEvents(int id, long changeFlags,
1420 boolean enabledOnToolkit)
1421 {
1422 assert Thread.holdsLock(getTreeLock());
1423 if (ncomponents == 0) {
1424 return;
1425 }
1426 int listeners = getListenersCount(id, enabledOnToolkit);
1427
1428 for (int count = listeners, i = 0; count > 0; i++) {
1429 count -= component[i].createHierarchyEvents(id, this, parent,
1430 changeFlags, enabledOnToolkit);
1431 }
1432 }
1433
1434 /**
1435 * Gets the layout manager for this container.
1436 * @see #doLayout
1437 * @see #setLayout
1438 */
1439 public LayoutManager getLayout() {
1440 return layoutMgr;
1441 }
1442
1443 /**
1444 * Sets the layout manager for this container.
1445 * @param mgr the specified layout manager
1446 * @see #doLayout
1447 * @see #getLayout
1448 */
1449 public void setLayout(LayoutManager mgr) {
1450 layoutMgr = mgr;
1451 if (valid) {
1452 invalidate();
1453 }
1454 }
1455
1456 /**
1457 * Causes this container to lay out its components. Most programs
1458 * should not call this method directly, but should invoke
1459 * the <code>validate</code> method instead.
1460 * @see LayoutManager#layoutContainer
1461 * @see #setLayout
1462 * @see #validate
1463 * @since JDK1.1
1464 */
1465 public void doLayout() {
1466 layout();
1467 }
1468
1469 /**
1470 * @deprecated As of JDK version 1.1,
1471 * replaced by <code>doLayout()</code>.
1472 */
1473 @Deprecated
1474 public void layout() {
1475 LayoutManager layoutMgr = this.layoutMgr;
1476 if (layoutMgr != null) {
1477 layoutMgr.layoutContainer(this);
1478 }
1479 }
1480
1481 /**
1482 * Invalidates the container. The container and all parents
1483 * above it are marked as needing to be laid out. This method can
1484 * be called often, so it needs to execute quickly.
1485 *
1486 * <p> If the {@code LayoutManager} installed on this container is
1487 * an instance of {@code LayoutManager2}, then
1488 * {@link LayoutManager2#invalidateLayout(Container)} is invoked on
1489 * it supplying this {@code Container} as the argument.
1490 *
1491 * @see #validate
1492 * @see #layout
1493 * @see LayoutManager
1494 * @see LayoutManager2#invalidateLayout(Container)
1495 */
1496 public void invalidate() {
1497 LayoutManager layoutMgr = this.layoutMgr;
1498 if (layoutMgr instanceof LayoutManager2) {
1499 LayoutManager2 lm = (LayoutManager2) layoutMgr;
1500 lm.invalidateLayout(this);
1501 }
1502 super.invalidate();
1503 }
1504
1505 /**
1506 * Validates this container and all of its subcomponents.
1507 * <p>
1508 * The <code>validate</code> method is used to cause a container
1509 * to lay out its subcomponents again. It should be invoked when
1510 * this container's subcomponents are modified (added to or
1511 * removed from the container, or layout-related information
1512 * changed) after the container has been displayed.
1513 *
1514 * <p>If this {@code Container} is not valid, this method invokes
1515 * the {@code validateTree} method and marks this {@code Container}
1516 * as valid. Otherwise, no action is performed.
1517 *
1518 * @see #add(java.awt.Component)
1519 * @see Component#invalidate
1520 * @see javax.swing.JComponent#revalidate()
1521 * @see #validateTree
1522 */
1523 public void validate() {
1524 /* Avoid grabbing lock unless really necessary. */
1525 if (!valid) {
1526 boolean updateCur = false;
1527 synchronized (getTreeLock()) {
1528 if (!valid && peer != null) {
1529 ContainerPeer p = null;
1530 if (peer instanceof ContainerPeer) {
1531 p = (ContainerPeer) peer;
1532 }
1533 if (p != null) {
1534 p.beginValidate();
1535 }
1536 validateTree();
1537 valid = true;
1538 if (p != null) {
1539 p.endValidate();
1540 updateCur = isVisible();
1541 }
1542 }
1543 }
1544 if (updateCur) {
1545 updateCursorImmediately();
1546 }
1547 }
1548 }
1549
1550 /**
1551 * Recursively descends the container tree and recomputes the
1552 * layout for any subtrees marked as needing it (those marked as
1553 * invalid). Synchronization should be provided by the method
1554 * that calls this one: <code>validate</code>.
1555 *
1556 * @see #doLayout
1557 * @see #validate
1558 */
1559 protected void validateTree() {
1560 if (!valid) {
1561 if (peer instanceof ContainerPeer) {
1562 ((ContainerPeer)peer).beginLayout();
1563 }
1564 doLayout();
1565 Component component[] = this.component;
1566 for (int i = 0 ; i < ncomponents ; ++i) {
1567 Component comp = component[i];
1568 if ( (comp instanceof Container)
1569 && !(comp instanceof Window)
1570 && !comp.valid) {
1571 ((Container)comp).validateTree();
1572 } else {
1573 comp.validate();
1574 }
1575 }
1576 if (peer instanceof ContainerPeer) {
1577 ((ContainerPeer)peer).endLayout();
1578 }
1579 }
1580 valid = true;
1581 }
1582
1583 /**
1584 * Recursively descends the container tree and invalidates all
1585 * contained components.
1586 */
1587 void invalidateTree() {
1588 synchronized (getTreeLock()) {
1589 for (int i = 0; i < ncomponents; ++i) {
1590 Component comp = component[i];
1591 if (comp instanceof Container) {
1592 ((Container)comp).invalidateTree();
1593 }
1594 else {
1595 if (comp.valid) {
1596 comp.invalidate();
1597 }
1598 }
1599 }
1600 if (valid) {
1601 invalidate();
1602 }
1603 }
1604 }
1605
1606 /**
1607 * Sets the font of this container.
1608 * @param f The font to become this container's font.
1609 * @see Component#getFont
1610 * @since JDK1.0
1611 */
1612 public void setFont(Font f) {
1613 boolean shouldinvalidate = false;
1614
1615 Font oldfont = getFont();
1616 super.setFont(f);
1617 Font newfont = getFont();
1618 if (newfont != oldfont && (oldfont == null ||
1619 !oldfont.equals(newfont))) {
1620 invalidateTree();
1621 }
1622 }
1623
1624 /**
1625 * Returns the preferred size of this container. If the preferred size has
1626 * not been set explicitly by {@link Component#setPreferredSize(Dimension)}
1627 * and this {@code Container} has a {@code non-null} {@link LayoutManager},
1628 * then {@link LayoutManager#preferredLayoutSize(Container)}
1629 * is used to calculate the preferred size.
1630 *
1631 * <p>Note: some implementations may cache the value returned from the
1632 * {@code LayoutManager}. Implementations that cache need not invoke
1633 * {@code preferredLayoutSize} on the {@code LayoutManager} every time
1634 * this method is invoked, rather the {@code LayoutManager} will only
1635 * be queried after the {@code Container} becomes invalid.
1636 *
1637 * @return an instance of <code>Dimension</code> that represents
1638 * the preferred size of this container.
1639 * @see #getMinimumSize
1640 * @see #getMaximumSize
1641 * @see #getLayout
1642 * @see LayoutManager#preferredLayoutSize(Container)
1643 * @see Component#getPreferredSize
1644 */
1645 public Dimension getPreferredSize() {
1646 return preferredSize();
1647 }
1648
1649 /**
1650 * @deprecated As of JDK version 1.1,
1651 * replaced by <code>getPreferredSize()</code>.
1652 */
1653 @Deprecated
1654 public Dimension preferredSize() {
1655 /* Avoid grabbing the lock if a reasonable cached size value
1656 * is available.
1657 */
1658 Dimension dim = prefSize;
1659 if (dim == null || !(isPreferredSizeSet() || isValid())) {
1660 synchronized (getTreeLock()) {
1661 prefSize = (layoutMgr != null) ?
1662 layoutMgr.preferredLayoutSize(this) :
1663 super.preferredSize();
1664 dim = prefSize;
1665 }
1666 }
1667 if (dim != null){
1668 return new Dimension(dim);
1669 }
1670 else{
1671 return dim;
1672 }
1673 }
1674
1675 /**
1676 * Returns the minimum size of this container. If the minimum size has
1677 * not been set explicitly by {@link Component#setMinimumSize(Dimension)}
1678 * and this {@code Container} has a {@code non-null} {@link LayoutManager},
1679 * then {@link LayoutManager#minimumLayoutSize(Container)}
1680 * is used to calculate the minimum size.
1681 *
1682 * <p>Note: some implementations may cache the value returned from the
1683 * {@code LayoutManager}. Implementations that cache need not invoke
1684 * {@code minimumLayoutSize} on the {@code LayoutManager} every time
1685 * this method is invoked, rather the {@code LayoutManager} will only
1686 * be queried after the {@code Container} becomes invalid.
1687 *
1688 * @return an instance of <code>Dimension</code> that represents
1689 * the minimum size of this container.
1690 * @see #getPreferredSize
1691 * @see #getMaximumSize
1692 * @see #getLayout
1693 * @see LayoutManager#minimumLayoutSize(Container)
1694 * @see Component#getMinimumSize
1695 * @since JDK1.1
1696 */
1697 public Dimension getMinimumSize() {
1698 return minimumSize();
1699 }
1700
1701 /**
1702 * @deprecated As of JDK version 1.1,
1703 * replaced by <code>getMinimumSize()</code>.
1704 */
1705 @Deprecated
1706 public Dimension minimumSize() {
1707 /* Avoid grabbing the lock if a reasonable cached size value
1708 * is available.
1709 */
1710 Dimension dim = minSize;
1711 if (dim == null || !(isMinimumSizeSet() || isValid())) {
1712 synchronized (getTreeLock()) {
1713 minSize = (layoutMgr != null) ?
1714 layoutMgr.minimumLayoutSize(this) :
1715 super.minimumSize();
1716 dim = minSize;
1717 }
1718 }
1719 if (dim != null){
1720 return new Dimension(dim);
1721 }
1722 else{
1723 return dim;
1724 }
1725 }
1726
1727 /**
1728 * Returns the maximum size of this container. If the maximum size has
1729 * not been set explicitly by {@link Component#setMaximumSize(Dimension)}
1730 * and the {@link LayoutManager} installed on this {@code Container}
1731 * is an instance of {@link LayoutManager2}, then
1732 * {@link LayoutManager2#maximumLayoutSize(Container)}
1733 * is used to calculate the maximum size.
1734 *
1735 * <p>Note: some implementations may cache the value returned from the
1736 * {@code LayoutManager2}. Implementations that cache need not invoke
1737 * {@code maximumLayoutSize} on the {@code LayoutManager2} every time
1738 * this method is invoked, rather the {@code LayoutManager2} will only
1739 * be queried after the {@code Container} becomes invalid.
1740 *
1741 * @return an instance of <code>Dimension</code> that represents
1742 * the maximum size of this container.
1743 * @see #getPreferredSize
1744 * @see #getMinimumSize
1745 * @see #getLayout
1746 * @see LayoutManager2#maximumLayoutSize(Container)
1747 * @see Component#getMaximumSize
1748 */
1749 public Dimension getMaximumSize() {
1750 /* Avoid grabbing the lock if a reasonable cached size value
1751 * is available.
1752 */
1753 Dimension dim = maxSize;
1754 if (dim == null || !(isMaximumSizeSet() || isValid())) {
1755 synchronized (getTreeLock()) {
1756 if (layoutMgr instanceof LayoutManager2) {
1757 LayoutManager2 lm = (LayoutManager2) layoutMgr;
1758 maxSize = lm.maximumLayoutSize(this);
1759 } else {
1760 maxSize = super.getMaximumSize();
1761 }
1762 dim = maxSize;
1763 }
1764 }
1765 if (dim != null){
1766 return new Dimension(dim);
1767 }
1768 else{
1769 return dim;
1770 }
1771 }
1772
1773 /**
1774 * Returns the alignment along the x axis. This specifies how
1775 * the component would like to be aligned relative to other
1776 * components. The value should be a number between 0 and 1
1777 * where 0 represents alignment along the origin, 1 is aligned
1778 * the furthest away from the origin, 0.5 is centered, etc.
1779 */
1780 public float getAlignmentX() {
1781 float xAlign;
1782 if (layoutMgr instanceof LayoutManager2) {
1783 synchronized (getTreeLock()) {
1784 LayoutManager2 lm = (LayoutManager2) layoutMgr;
1785 xAlign = lm.getLayoutAlignmentX(this);
1786 }
1787 } else {
1788 xAlign = super.getAlignmentX();
1789 }
1790 return xAlign;
1791 }
1792
1793 /**
1794 * Returns the alignment along the y axis. This specifies how
1795 * the component would like to be aligned relative to other
1796 * components. The value should be a number between 0 and 1
1797 * where 0 represents alignment along the origin, 1 is aligned
1798 * the furthest away from the origin, 0.5 is centered, etc.
1799 */
1800 public float getAlignmentY() {
1801 float yAlign;
1802 if (layoutMgr instanceof LayoutManager2) {
1803 synchronized (getTreeLock()) {
1804 LayoutManager2 lm = (LayoutManager2) layoutMgr;
1805 yAlign = lm.getLayoutAlignmentY(this);
1806 }
1807 } else {
1808 yAlign = super.getAlignmentY();
1809 }
1810 return yAlign;
1811 }
1812
1813 /**
1814 * Paints the container. This forwards the paint to any lightweight
1815 * components that are children of this container. If this method is
1816 * reimplemented, super.paint(g) should be called so that lightweight
1817 * components are properly rendered. If a child component is entirely
1818 * clipped by the current clipping setting in g, paint() will not be
1819 * forwarded to that child.
1820 *
1821 * @param g the specified Graphics window
1822 * @see Component#update(Graphics)
1823 */
1824 public void paint(Graphics g) {
1825 if (isShowing()) {
1826 synchronized (this) {
1827 if (printing) {
1828 if (printingThreads.contains(Thread.currentThread())) {
1829 return;
1830 }
1831 }
1832 }
1833
1834 // The container is showing on screen and
1835 // this paint() is not called from print().
1836 // Paint self and forward the paint to lightweight subcomponents.
1837
1838 // super.paint(); -- Don't bother, since it's a NOP.
1839
1840 GraphicsCallback.PaintCallback.getInstance().
1841 runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS);
1842 }
1843 }
1844
1845 /**
1846 * Updates the container. This forwards the update to any lightweight
1847 * components that are children of this container. If this method is
1848 * reimplemented, super.update(g) should be called so that lightweight
1849 * components are properly rendered. If a child component is entirely
1850 * clipped by the current clipping setting in g, update() will not be
1851 * forwarded to that child.
1852 *
1853 * @param g the specified Graphics window
1854 * @see Component#update(Graphics)
1855 */
1856 public void update(Graphics g) {
1857 if (isShowing()) {
1858 if (! (peer instanceof LightweightPeer)) {
1859 g.clearRect(0, 0, width, height);
1860 }
1861 paint(g);
1862 }
1863 }
1864
1865 /**
1866 * Prints the container. This forwards the print to any lightweight
1867 * components that are children of this container. If this method is
1868 * reimplemented, super.print(g) should be called so that lightweight
1869 * components are properly rendered. If a child component is entirely
1870 * clipped by the current clipping setting in g, print() will not be
1871 * forwarded to that child.
1872 *
1873 * @param g the specified Graphics window
1874 * @see Component#update(Graphics)
1875 */
1876 public void print(Graphics g) {
1877 if (isShowing()) {
1878 Thread t = Thread.currentThread();
1879 try {
1880 synchronized (this) {
1881 if (printingThreads == null) {
1882 printingThreads = new HashSet();
1883 }
1884 printingThreads.add(t);
1885 printing = true;
1886 }
1887 super.print(g); // By default, Component.print() calls paint()
1888 } finally {
1889 synchronized (this) {
1890 printingThreads.remove(t);
1891 printing = !printingThreads.isEmpty();
1892 }
1893 }
1894
1895 GraphicsCallback.PrintCallback.getInstance().
1896 runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS);
1897 }
1898 }
1899
1900 /**
1901 * Paints each of the components in this container.
1902 * @param g the graphics context.
1903 * @see Component#paint
1904 * @see Component#paintAll
1905 */
1906 public void paintComponents(Graphics g) {
1907 if (isShowing()) {
1908 GraphicsCallback.PaintAllCallback.getInstance().
1909 runComponents(component, g, GraphicsCallback.TWO_PASSES);
1910 }
1911 }
1912
1913 /**
1914 * Simulates the peer callbacks into java.awt for printing of
1915 * lightweight Containers.
1916 * @param g the graphics context to use for printing.
1917 * @see Component#printAll
1918 * @see #printComponents
1919 */
1920 void lightweightPaint(Graphics g) {
1921 super.lightweightPaint(g);
1922 paintHeavyweightComponents(g);
1923 }
1924
1925 /**
1926 * Prints all the heavyweight subcomponents.
1927 */
1928 void paintHeavyweightComponents(Graphics g) {
1929 if (isShowing()) {
1930 GraphicsCallback.PaintHeavyweightComponentsCallback.getInstance().
1931 runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS |
1932 GraphicsCallback.HEAVYWEIGHTS);
1933 }
1934 }
1935
1936 /**
1937 * Prints each of the components in this container.
1938 * @param g the graphics context.
1939 * @see Component#print
1940 * @see Component#printAll
1941 */
1942 public void printComponents(Graphics g) {
1943 if (isShowing()) {
1944 GraphicsCallback.PrintAllCallback.getInstance().
1945 runComponents(component, g, GraphicsCallback.TWO_PASSES);
1946 }
1947 }
1948
1949 /**
1950 * Simulates the peer callbacks into java.awt for printing of
1951 * lightweight Containers.
1952 * @param g the graphics context to use for printing.
1953 * @see Component#printAll
1954 * @see #printComponents
1955 */
1956 void lightweightPrint(Graphics g) {
1957 super.lightweightPrint(g);
1958 printHeavyweightComponents(g);
1959 }
1960
1961 /**
1962 * Prints all the heavyweight subcomponents.
1963 */
1964 void printHeavyweightComponents(Graphics g) {
1965 if (isShowing()) {
1966 GraphicsCallback.PrintHeavyweightComponentsCallback.getInstance().
1967 runComponents(component, g, GraphicsCallback.LIGHTWEIGHTS |
1968 GraphicsCallback.HEAVYWEIGHTS);
1969 }
1970 }
1971
1972 /**
1973 * Adds the specified container listener to receive container events
1974 * from this container.
1975 * If l is null, no exception is thrown and no action is performed.
1976 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
1977 * >AWT Threading Issues</a> for details on AWT's threading model.
1978 *
1979 * @param l the container listener
1980 *
1981 * @see #removeContainerListener
1982 * @see #getContainerListeners
1983 */
1984 public synchronized void addContainerListener(ContainerListener l) {
1985 if (l == null) {
1986 return;
1987 }
1988 containerListener = AWTEventMulticaster.add(containerListener, l);
1989 newEventsOnly = true;
1990 }
1991
1992 /**
1993 * Removes the specified container listener so it no longer receives
1994 * container events from this container.
1995 * If l is null, no exception is thrown and no action is performed.
1996 * <p>Refer to <a href="doc-files/AWTThreadIssues.html#ListenersThreads"
1997 * >AWT Threading Issues</a> for details on AWT's threading model.
1998 *
1999 * @param l the container listener
2000 *
2001 * @see #addContainerListener
2002 * @see #getContainerListeners
2003 */
2004 public synchronized void removeContainerListener(ContainerListener l) {
2005 if (l == null) {
2006 return;
2007 }
2008 containerListener = AWTEventMulticaster.remove(containerListener, l);
2009 }
2010
2011 /**
2012 * Returns an array of all the container listeners
2013 * registered on this container.
2014 *
2015 * @return all of this container's <code>ContainerListener</code>s
2016 * or an empty array if no container
2017 * listeners are currently registered
2018 *
2019 * @see #addContainerListener
2020 * @see #removeContainerListener
2021 * @since 1.4
2022 */
2023 public synchronized ContainerListener[] getContainerListeners() {
2024 return (ContainerListener[]) (getListeners(ContainerListener.class));
2025 }
2026
2027 /**
2028 * Returns an array of all the objects currently registered
2029 * as <code><em>Foo</em>Listener</code>s
2030 * upon this <code>Container</code>.
2031 * <code><em>Foo</em>Listener</code>s are registered using the
2032 * <code>add<em>Foo</em>Listener</code> method.
2033 *
2034 * <p>
2035 * You can specify the <code>listenerType</code> argument
2036 * with a class literal, such as
2037 * <code><em>Foo</em>Listener.class</code>.
2038 * For example, you can query a
2039 * <code>Container</code> <code>c</code>
2040 * for its container listeners with the following code:
2041 *
2042 * <pre>ContainerListener[] cls = (ContainerListener[])(c.getListeners(ContainerListener.class));</pre>
2043 *
2044 * If no such listeners exist, this method returns an empty array.
2045 *
2046 * @param listenerType the type of listeners requested; this parameter
2047 * should specify an interface that descends from
2048 * <code>java.util.EventListener</code>
2049 * @return an array of all objects registered as
2050 * <code><em>Foo</em>Listener</code>s on this container,
2051 * or an empty array if no such listeners have been added
2052 * @exception ClassCastException if <code>listenerType</code>
2053 * doesn't specify a class or interface that implements
2054 * <code>java.util.EventListener</code>
2055 *
2056 * @see #getContainerListeners
2057 *
2058 * @since 1.3
2059 */
2060 public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
2061 EventListener l = null;
2062 if (listenerType == ContainerListener.class) {
2063 l = containerListener;
2064 } else {
2065 return super.getListeners(listenerType);
2066 }
2067 return AWTEventMulticaster.getListeners(l, listenerType);
2068 }
2069
2070 // REMIND: remove when filtering is done at lower level
2071 boolean eventEnabled(AWTEvent e) {
2072 int id = e.getID();
2073
2074 if (id == ContainerEvent.COMPONENT_ADDED ||
2075 id == ContainerEvent.COMPONENT_REMOVED) {
2076 if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
2077 containerListener != null) {
2078 return true;
2079 }
2080 return false;
2081 }
2082 return super.eventEnabled(e);
2083 }
2084
2085 /**
2086 * Processes events on this container. If the event is a
2087 * <code>ContainerEvent</code>, it invokes the
2088 * <code>processContainerEvent</code> method, else it invokes
2089 * its superclass's <code>processEvent</code>.
2090 * <p>Note that if the event parameter is <code>null</code>
2091 * the behavior is unspecified and may result in an
2092 * exception.
2093 *
2094 * @param e the event
2095 */
2096 protected void processEvent(AWTEvent e) {
2097 if (e instanceof ContainerEvent) {
2098 processContainerEvent((ContainerEvent)e);
2099 return;
2100 }
2101 super.processEvent(e);
2102 }
2103
2104 /**
2105 * Processes container events occurring on this container by
2106 * dispatching them to any registered ContainerListener objects.
2107 * NOTE: This method will not be called unless container events
2108 * are enabled for this component; this happens when one of the
2109 * following occurs:
2110 * <ul>
2111 * <li>A ContainerListener object is registered via
2112 * <code>addContainerListener</code>
2113 * <li>Container events are enabled via <code>enableEvents</code>
2114 * </ul>
2115 * <p>Note that if the event parameter is <code>null</code>
2116 * the behavior is unspecified and may result in an
2117 * exception.
2118 *
2119 * @param e the container event
2120 * @see Component#enableEvents
2121 */
2122 protected void processContainerEvent(ContainerEvent e) {
2123 ContainerListener listener = containerListener;
2124 if (listener != null) {
2125 switch(e.getID()) {
2126 case ContainerEvent.COMPONENT_ADDED:
2127 listener.componentAdded(e);
2128 break;
2129 case ContainerEvent.COMPONENT_REMOVED:
2130 listener.componentRemoved(e);
2131 break;
2132 }
2133 }
2134 }
2135
2136 /*
2137 * Dispatches an event to this component or one of its sub components.
2138 * Create ANCESTOR_RESIZED and ANCESTOR_MOVED events in response to
2139 * COMPONENT_RESIZED and COMPONENT_MOVED events. We have to do this
2140 * here instead of in processComponentEvent because ComponentEvents
2141 * may not be enabled for this Container.
2142 * @param e the event
2143 */
2144 void dispatchEventImpl(AWTEvent e) {
2145 if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
2146 // event was sent to a lightweight component. The
2147 // native-produced event sent to the native container
2148 // must be properly disposed of by the peer, so it
2149 // gets forwarded. If the native host has been removed
2150 // as a result of the sending the lightweight event,
2151 // the peer reference will be null.
2152 e.consume();
2153 if (peer != null) {
2154 peer.handleEvent(e);
2155 }
2156 return;
2157 }
2158
2159 super.dispatchEventImpl(e);
2160
2161 synchronized (getTreeLock()) {
2162 switch (e.getID()) {
2163 case ComponentEvent.COMPONENT_RESIZED:
2164 createChildHierarchyEvents(HierarchyEvent.ANCESTOR_RESIZED, 0,
2165 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2166 break;
2167 case ComponentEvent.COMPONENT_MOVED:
2168 createChildHierarchyEvents(HierarchyEvent.ANCESTOR_MOVED, 0,
2169 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
2170 break;
2171 default:
2172 break;
2173 }
2174 }
2175 }
2176
2177 /*
2178 * Dispatches an event to this component, without trying to forward
2179 * it to any subcomponents
2180 * @param e the event
2181 */
2182 void dispatchEventToSelf(AWTEvent e) {
2183 super.dispatchEventImpl(e);
2184 }
2185
2186 /**
2187 * Fetchs the top-most (deepest) lightweight component that is interested
2188 * in receiving mouse events.
2189 */
2190 Component getMouseEventTarget(int x, int y, boolean includeSelf) {
2191 return getMouseEventTarget(x, y, includeSelf,
2192 MouseEventTargetFilter.FILTER,
2193 !SEARCH_HEAVYWEIGHTS);
2194 }
2195
2196 /**
2197 * Fetches the top-most (deepest) component to receive SunDropTargetEvents.
2198 */
2199 Component getDropTargetEventTarget(int x, int y, boolean includeSelf) {
2200 return getMouseEventTarget(x, y, includeSelf,
2201 DropTargetEventTargetFilter.FILTER,
2202 SEARCH_HEAVYWEIGHTS);
2203 }
2204
2205 /**
2206 * A private version of getMouseEventTarget which has two additional
2207 * controllable behaviors. This method searches for the top-most
2208 * descendant of this container that contains the given coordinates
2209 * and is accepted by the given filter. The search will be constrained to
2210 * lightweight descendants if the last argument is <code>false</code>.
2211 *
2212 * @param filter EventTargetFilter instance to determine whether the
2213 * given component is a valid target for this event.
2214 * @param searchHeavyweights if <code>false</code>, the method
2215 * will bypass heavyweight components during the search.
2216 */
2217 private Component getMouseEventTarget(int x, int y, boolean includeSelf,
2218 EventTargetFilter filter,
2219 boolean searchHeavyweights) {
2220 Component comp = null;
2221 if (searchHeavyweights) {
2222 comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2223 SEARCH_HEAVYWEIGHTS,
2224 searchHeavyweights);
2225 }
2226
2227 if (comp == null || comp == this) {
2228 comp = getMouseEventTargetImpl(x, y, includeSelf, filter,
2229 !SEARCH_HEAVYWEIGHTS,
2230 searchHeavyweights);
2231 }
2232
2233 return comp;
2234 }
2235
2236 /**
2237 * A private version of getMouseEventTarget which has three additional
2238 * controllable behaviors. This method searches for the top-most
2239 * descendant of this container that contains the given coordinates
2240 * and is accepted by the given filter. The search will be constrained to
2241 * descendants of only lightweight children or only heavyweight children
2242 * of this container depending on searchHeavyweightChildren. The search will
2243 * be constrained to only lightweight descendants of the searched children
2244 * of this container if searchHeavyweightDescendants is <code>false</code>.
2245 *
2246 * @param filter EventTargetFilter instance to determine whether the
2247 * selected component is a valid target for this event.
2248 * @param searchHeavyweightChildren if <code>true</code>, the method
2249 * will bypass immediate lightweight children during the search.
2250 * If <code>false</code>, the methods will bypass immediate
2251 * heavyweight children during the search.
2252 * @param searchHeavyweightDescendants if <code>false</code>, the method
2253 * will bypass heavyweight descendants which are not immediate
2254 * children during the search. If <code>true</code>, the method
2255 * will traverse both lightweight and heavyweight descendants during
2256 * the search.
2257 */
2258 private Component getMouseEventTargetImpl(int x, int y, boolean includeSelf,
2259 EventTargetFilter filter,
2260 boolean searchHeavyweightChildren,
2261 boolean searchHeavyweightDescendants) {
2262 synchronized (getTreeLock()) {
2263 int ncomponents = this.ncomponents;
2264 Component component[] = this.component;
2265
2266 for (int i = 0 ; i < ncomponents ; i++) {
2267 Component comp = component[i];
2268 if (comp != null && comp.visible &&
2269 ((!searchHeavyweightChildren &&
2270 comp.peer instanceof LightweightPeer) ||
2271 (searchHeavyweightChildren &&
2272 !(comp.peer instanceof LightweightPeer))) &&
2273 comp.contains(x - comp.x, y - comp.y)) {
2274
2275 // found a component that intersects the point, see if there
2276 // is a deeper possibility.
2277 if (comp instanceof Container) {
2278 Container child = (Container) comp;
2279 Component deeper = child.getMouseEventTarget(
2280 x - child.x,
2281 y - child.y,
2282 includeSelf,
2283 filter,
2284 searchHeavyweightDescendants);
2285 if (deeper != null) {
2286 return deeper;
2287 }
2288 } else {
2289 if (filter.accept(comp)) {
2290 // there isn't a deeper target, but this component
2291 // is a target
2292 return comp;
2293 }
2294 }
2295 }
2296 }
2297
2298 boolean isPeerOK;
2299 boolean isMouseOverMe;
2300
2301 isPeerOK = (peer instanceof LightweightPeer) || includeSelf;
2302 isMouseOverMe = contains(x,y);
2303
2304 // didn't find a child target, return this component if it's
2305 // a possible target
2306 if (isMouseOverMe && isPeerOK && filter.accept(this)) {
2307 return this;
2308 }
2309 // no possible target
2310 return null;
2311 }
2312 }
2313
2314 static interface EventTargetFilter {
2315 boolean accept(final Component comp);
2316 }
2317
2318 static class MouseEventTargetFilter implements EventTargetFilter {
2319 static final EventTargetFilter FILTER = new MouseEventTargetFilter();
2320
2321 private MouseEventTargetFilter() {}
2322
2323 public boolean accept(final Component comp) {
2324 return (comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0
2325 || (comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0
2326 || (comp.eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0
2327 || comp.mouseListener != null
2328 || comp.mouseMotionListener != null
2329 || comp.mouseWheelListener != null;
2330 }
2331 }
2332
2333 static class DropTargetEventTargetFilter implements EventTargetFilter {
2334 static final EventTargetFilter FILTER = new DropTargetEventTargetFilter();
2335
2336 private DropTargetEventTargetFilter() {}
2337
2338 public boolean accept(final Component comp) {
2339 DropTarget dt = comp.getDropTarget();
2340 return dt != null && dt.isActive();
2341 }
2342 }
2343
2344 /**
2345 * This is called by lightweight components that want the containing
2346 * windowed parent to enable some kind of events on their behalf.
2347 * This is needed for events that are normally only dispatched to
2348 * windows to be accepted so that they can be forwarded downward to
2349 * the lightweight component that has enabled them.
2350 */
2351 void proxyEnableEvents(long events) {
2352 if (peer instanceof LightweightPeer) {
2353 // this container is lightweight.... continue sending it
2354 // upward.
2355 if (parent != null) {
2356 parent.proxyEnableEvents(events);
2357 }
2358 } else {
2359 // This is a native container, so it needs to host
2360 // one of it's children. If this function is called before
2361 // a peer has been created we don't yet have a dispatcher
2362 // because it has not yet been determined if this instance
2363 // is lightweight.
2364 if (dispatcher != null) {
2365 dispatcher.enableEvents(events);
2366 }
2367 }
2368 }
2369
2370 /**
2371 * @deprecated As of JDK version 1.1,
2372 * replaced by <code>dispatchEvent(AWTEvent e)</code>
2373 */
2374 @Deprecated
2375 public void deliverEvent(Event e) {
2376 Component comp = getComponentAt(e.x, e.y);
2377 if ((comp != null) && (comp != this)) {
2378 e.translate(-comp.x, -comp.y);
2379 comp.deliverEvent(e);
2380 } else {
2381 postEvent(e);
2382 }
2383 }
2384
2385 /**
2386 * Locates the component that contains the x,y position. The
2387 * top-most child component is returned in the case where there
2388 * is overlap in the components. This is determined by finding
2389 * the component closest to the index 0 that claims to contain
2390 * the given point via Component.contains(), except that Components
2391 * which have native peers take precedence over those which do not
2392 * (i.e., lightweight Components).
2393 *
2394 * @param x the <i>x</i> coordinate
2395 * @param y the <i>y</i> coordinate
2396 * @return null if the component does not contain the position.
2397 * If there is no child component at the requested point and the
2398 * point is within the bounds of the container the container itself
2399 * is returned; otherwise the top-most child is returned.
2400 * @see Component#contains
2401 * @since JDK1.1
2402 */
2403 public Component getComponentAt(int x, int y) {
2404 return locate(x, y);
2405 }
2406
2407 /**
2408 * @deprecated As of JDK version 1.1,
2409 * replaced by <code>getComponentAt(int, int)</code>.
2410 */
2411 @Deprecated
2412 public Component locate(int x, int y) {
2413 if (!contains(x, y)) {
2414 return null;
2415 }
2416 synchronized (getTreeLock()) {
2417 // Two passes: see comment in sun.awt.SunGraphicsCallback
2418 for (int i = 0 ; i < ncomponents ; i++) {
2419 Component comp = component[i];
2420 if (comp != null &&
2421 !(comp.peer instanceof LightweightPeer)) {
2422 if (comp.contains(x - comp.x, y - comp.y)) {
2423 return comp;
2424 }
2425 }
2426 }
2427 for (int i = 0 ; i < ncomponents ; i++) {
2428 Component comp = component[i];
2429 if (comp != null &&
2430 comp.peer instanceof LightweightPeer) {
2431 if (comp.contains(x - comp.x, y - comp.y)) {
2432 return comp;
2433 }
2434 }
2435 }
2436 }
2437 return this;
2438 }
2439
2440 /**
2441 * Gets the component that contains the specified point.
2442 * @param p the point.
2443 * @return returns the component that contains the point,
2444 * or <code>null</code> if the component does
2445 * not contain the point.
2446 * @see Component#contains
2447 * @since JDK1.1
2448 */
2449 public Component getComponentAt(Point p) {
2450 return getComponentAt(p.x, p.y);
2451 }
2452
2453 /**
2454 * Returns the position of the mouse pointer in this <code>Container</code>'s
2455 * coordinate space if the <code>Container</code> is under the mouse pointer,
2456 * otherwise returns <code>null</code>.
2457 * This method is similar to {@link Component#getMousePosition()} with the exception
2458 * that it can take the <code>Container</code>'s children into account.
2459 * If <code>allowChildren</code> is <code>false</code>, this method will return
2460 * a non-null value only if the mouse pointer is above the <code>Container</code>
2461 * directly, not above the part obscured by children.
2462 * If <code>allowChildren</code> is <code>true</code>, this method returns
2463 * a non-null value if the mouse pointer is above <code>Container</code> or any
2464 * of its descendants.
2465 *
2466 * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true
2467 * @param allowChildren true if children should be taken into account
2468 * @see Component#getMousePosition
2469 * @return mouse coordinates relative to this <code>Component</code>, or null
2470 * @since 1.5
2471 */
2472 public Point getMousePosition(boolean allowChildren) throws HeadlessException {
2473 if (GraphicsEnvironment.isHeadless()) {
2474 throw new HeadlessException();
2475 }
2476 PointerInfo pi = (PointerInfo)java.security.AccessController.doPrivileged(
2477 new java.security.PrivilegedAction() {
2478 public Object run() {
2479 return MouseInfo.getPointerInfo();
2480 }
2481 }
2482 );
2483 synchronized (getTreeLock()) {
2484 Component inTheSameWindow = findUnderMouseInWindow(pi);
2485 if (isSameOrAncestorOf(inTheSameWindow, allowChildren)) {
2486 return pointRelativeToComponent(pi.getLocation());
2487 }
2488 return null;
2489 }
2490 }
2491
2492 boolean isSameOrAncestorOf(Component comp, boolean allowChildren) {
2493 return this == comp || (allowChildren && isParentOf(comp));
2494 }
2495
2496 /**
2497 * Locates the visible child component that contains the specified
2498 * position. The top-most child component is returned in the case
2499 * where there is overlap in the components. If the containing child
2500 * component is a Container, this method will continue searching for
2501 * the deepest nested child component. Components which are not
2502 * visible are ignored during the search.<p>
2503 *
2504 * The findComponentAt method is different from getComponentAt in
2505 * that getComponentAt only searches the Container's immediate
2506 * children; if the containing component is a Container,
2507 * findComponentAt will search that child to find a nested component.
2508 *
2509 * @param x the <i>x</i> coordinate
2510 * @param y the <i>y</i> coordinate
2511 * @return null if the component does not contain the position.
2512 * If there is no child component at the requested point and the
2513 * point is within the bounds of the container the container itself
2514 * is returned.
2515 * @see Component#contains
2516 * @see #getComponentAt
2517 * @since 1.2
2518 */
2519 public Component findComponentAt(int x, int y) {
2520 synchronized (getTreeLock()) {
2521 return findComponentAt(x, y, true);
2522 }
2523 }
2524
2525 /**
2526 * Private version of findComponentAt which has a controllable
2527 * behavior. Setting 'ignoreEnabled' to 'false' bypasses disabled
2528 * Components during the search. This behavior is used by the
2529 * lightweight cursor support in sun.awt.GlobalCursorManager.
2530 * The cursor code calls this function directly via native code.
2531 *
2532 * The addition of this feature is temporary, pending the
2533 * adoption of new, public API which exports this feature.
2534 */
2535 final Component findComponentAt(int x, int y, boolean ignoreEnabled)
2536 {
2537 if (isRecursivelyVisible()){
2538 return findComponentAtImpl(x, y, ignoreEnabled);
2539 }
2540 return null;
2541 }
2542
2543 final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled){
2544 if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) {
2545 return null;
2546 }
2547 int ncomponents = this.ncomponents;
2548 Component component[] = this.component;
2549
2550 // Two passes: see comment in sun.awt.SunGraphicsCallback
2551 for (int i = 0 ; i < ncomponents ; i++) {
2552 Component comp = component[i];
2553 if (comp != null &&
2554 !(comp.peer instanceof LightweightPeer)) {
2555 if (comp instanceof Container) {
2556 comp = ((Container)comp).findComponentAtImpl(x - comp.x,
2557 y - comp.y,
2558 ignoreEnabled);
2559 } else {
2560 comp = comp.locate(x - comp.x, y - comp.y);
2561 }
2562 if (comp != null && comp.visible &&
2563 (ignoreEnabled || comp.enabled))
2564 {
2565 return comp;
2566 }
2567 }
2568 }
2569 for (int i = 0 ; i < ncomponents ; i++) {
2570 Component comp = component[i];
2571 if (comp != null &&
2572 comp.peer instanceof LightweightPeer) {
2573 if (comp instanceof Container) {
2574 comp = ((Container)comp).findComponentAtImpl(x - comp.x,
2575 y - comp.y,
2576 ignoreEnabled);
2577 } else {
2578 comp = comp.locate(x - comp.x, y - comp.y);
2579 }
2580 if (comp != null && comp.visible &&
2581 (ignoreEnabled || comp.enabled))
2582 {
2583 return comp;
2584 }
2585 }
2586 }
2587 return this;
2588 }
2589
2590 /**
2591 * Locates the visible child component that contains the specified
2592 * point. The top-most child component is returned in the case
2593 * where there is overlap in the components. If the containing child
2594 * component is a Container, this method will continue searching for
2595 * the deepest nested child component. Components which are not
2596 * visible are ignored during the search.<p>
2597 *
2598 * The findComponentAt method is different from getComponentAt in
2599 * that getComponentAt only searches the Container's immediate
2600 * children; if the containing component is a Container,
2601 * findComponentAt will search that child to find a nested component.
2602 *
2603 * @param p the point.
2604 * @return null if the component does not contain the position.
2605 * If there is no child component at the requested point and the
2606 * point is within the bounds of the container the container itself
2607 * is returned.
2608 * @see Component#contains
2609 * @see #getComponentAt
2610 * @since 1.2
2611 */
2612 public Component findComponentAt(Point p) {
2613 return findComponentAt(p.x, p.y);
2614 }
2615
2616 /**
2617 * Makes this Container displayable by connecting it to
2618 * a native screen resource. Making a container displayable will
2619 * cause all of its children to be made displayable.
2620 * This method is called internally by the toolkit and should
2621 * not be called directly by programs.
2622 * @see Component#isDisplayable
2623 * @see #removeNotify
2624 */
2625 public void addNotify() {
2626 synchronized (getTreeLock()) {
2627 // addNotify() on the children may cause proxy event enabling
2628 // on this instance, so we first call super.addNotify() and
2629 // possibly create an lightweight event dispatcher before calling
2630 // addNotify() on the children which may be lightweight.
2631 super.addNotify();
2632 if (! (peer instanceof LightweightPeer)) {
2633 dispatcher = new LightweightDispatcher(this);
2634 }
2635 int ncomponents = this.ncomponents;
2636 Component component[] = this.component;
2637 for (int i = 0 ; i < ncomponents ; i++) {
2638 component[i].addNotify();
2639 }
2640 // Update stacking order if native platform allows
2641 ContainerPeer cpeer = (ContainerPeer)peer;
2642 if (cpeer.isRestackSupported()) {
2643 cpeer.restack();
2644 }
2645
2646
2647 }
2648 }
2649
2650 /**
2651 * Makes this Container undisplayable by removing its connection
2652 * to its native screen resource. Making a container undisplayable
2653 * will cause all of its children to be made undisplayable.
2654 * This method is called by the toolkit internally and should
2655 * not be called directly by programs.
2656 * @see Component#isDisplayable
2657 * @see #addNotify
2658 */
2659 public void removeNotify() {
2660 synchronized (getTreeLock()) {
2661 int ncomponents = this.ncomponents;
2662 Component component[] = this.component;
2663 for (int i = ncomponents - 1; i >= 0; i--) {
2664 if( component[i] != null ) {
2665 // Fix for 6607170.
2666 // We want to suppress focus change on disposal
2667 // of the focused component. But because of focus
2668 // is asynchronous, we should suppress focus change
2669 // on every component in case it receives native focus
2670 // in the process of disposal.
2671 component[i].setAutoFocusTransferOnDisposal(false);
2672 component[i].removeNotify();
2673 component[i].setAutoFocusTransferOnDisposal(true);
2674 }
2675 }
2676 // If some of the children had focus before disposal then it still has.
2677 // Auto-transfer focus to the next (or previous) component if auto-transfer
2678 // is enabled.
2679 if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
2680 if (!transferFocus(false)) {
2681 transferFocusBackward(true);
2682 }
2683 }
2684 if ( dispatcher != null ) {
2685 dispatcher.dispose();
2686 dispatcher = null;
2687 }
2688 super.removeNotify();
2689 }
2690 }
2691
2692 /**
2693 * Checks if the component is contained in the component hierarchy of
2694 * this container.
2695 * @param c the component
2696 * @return <code>true</code> if it is an ancestor;
2697 * <code>false</code> otherwise.
2698 * @since JDK1.1
2699 */
2700 public boolean isAncestorOf(Component c) {
2701 Container p;
2702 if (c == null || ((p = c.getParent()) == null)) {
2703 return false;
2704 }
2705 while (p != null) {
2706 if (p == this) {
2707 return true;
2708 }
2709 p = p.getParent();
2710 }
2711 return false;
2712 }
2713
2714 /*
2715 * The following code was added to support modal JInternalFrames
2716 * Unfortunately this code has to be added here so that we can get access to
2717 * some private AWT classes like SequencedEvent.
2718 *
2719 * The native container of the LW component has this field set
2720 * to tell it that it should block Mouse events for all LW
2721 * children except for the modal component.
2722 *
2723 * In the case of nested Modal components, we store the previous
2724 * modal component in the new modal components value of modalComp;
2725 */
2726
2727 transient Component modalComp;
2728 transient AppContext modalAppContext;
2729
2730 private void startLWModal() {
2731 // Store the app context on which this component is being shown.
2732 // Event dispatch thread of this app context will be sleeping until
2733 // we wake it by any event from hideAndDisposeHandler().
2734 modalAppContext = AppContext.getAppContext();
2735
2736 // keep the KeyEvents from being dispatched
2737 // until the focus has been transfered
2738 long time = Toolkit.getEventQueue().getMostRecentEventTime();
2739 Component predictedFocusOwner = (Component.isInstanceOf(this, "javax.swing.JInternalFrame")) ? ((javax.swing.JInternalFrame)(this)).getMostRecentFocusOwner() : null;
2740 if (predictedFocusOwner != null) {
2741 KeyboardFocusManager.getCurrentKeyboardFocusManager().
2742 enqueueKeyEvents(time, predictedFocusOwner);
2743 }
2744 // We have two mechanisms for blocking: 1. If we're on the
2745 // EventDispatchThread, start a new event pump. 2. If we're
2746 // on any other thread, call wait() on the treelock.
2747 final Container nativeContainer;
2748 synchronized (getTreeLock()) {
2749 nativeContainer = getHeavyweightContainer();
2750 if (nativeContainer.modalComp != null) {
2751 this.modalComp = nativeContainer.modalComp;
2752 nativeContainer.modalComp = this;
2753 return;
2754 }
2755 else {
2756 nativeContainer.modalComp = this;
2757 }
2758 }
2759
2760 Runnable pumpEventsForHierarchy = new Runnable() {
2761 public void run() {
2762 EventDispatchThread dispatchThread =
2763 (EventDispatchThread)Thread.currentThread();
2764 dispatchThread.pumpEventsForHierarchy(
2765 new Conditional() {
2766 public boolean evaluate() {
2767 return ((windowClosingException == null) && (nativeContainer.modalComp != null)) ;
2768 }
2769 }, Container.this);
2770 }
2771 };
2772
2773 if (EventQueue.isDispatchThread()) {
2774 SequencedEvent currentSequencedEvent =
2775 KeyboardFocusManager.getCurrentKeyboardFocusManager().
2776 getCurrentSequencedEvent();
2777 if (currentSequencedEvent != null) {
2778 currentSequencedEvent.dispose();
2779 }
2780
2781 pumpEventsForHierarchy.run();
2782 } else {
2783 synchronized (getTreeLock()) {
2784 Toolkit.getEventQueue().
2785 postEvent(new PeerEvent(this,
2786 pumpEventsForHierarchy,
2787 PeerEvent.PRIORITY_EVENT));
2788 while ((windowClosingException == null) &&
2789 (nativeContainer.modalComp != null))
2790 {
2791 try {
2792 getTreeLock().wait();
2793 } catch (InterruptedException e) {
2794 break;
2795 }
2796 }
2797 }
2798 }
2799 if (windowClosingException != null) {
2800 windowClosingException.fillInStackTrace();
2801 throw windowClosingException;
2802 }
2803 if (predictedFocusOwner != null) {
2804 KeyboardFocusManager.getCurrentKeyboardFocusManager().
2805 dequeueKeyEvents(time, predictedFocusOwner);
2806 }
2807 }
2808
2809 private void stopLWModal() {
2810 synchronized (getTreeLock()) {
2811 if (modalAppContext != null) {
2812 Container nativeContainer = getHeavyweightContainer();
2813 if(nativeContainer != null) {
2814 if (this.modalComp != null) {
2815 nativeContainer.modalComp = this.modalComp;
2816 this.modalComp = null;
2817 return;
2818 }
2819 else {
2820 nativeContainer.modalComp = null;
2821 }
2822 }
2823 // Wake up event dispatch thread on which the dialog was
2824 // initially shown
2825 SunToolkit.postEvent(modalAppContext,
2826 new PeerEvent(this,
2827 new WakingRunnable(),
2828 PeerEvent.PRIORITY_EVENT));
2829 }
2830 EventQueue.invokeLater(new WakingRunnable());
2831 getTreeLock().notifyAll();
2832 }
2833 }
2834
2835 final static class WakingRunnable implements Runnable {
2836 public void run() {
2837 }
2838 }
2839
2840 /* End of JOptionPane support code */
2841
2842 /**
2843 * Returns a string representing the state of this <code>Container</code>.
2844 * This method is intended to be used only for debugging purposes, and the
2845 * content and format of the returned string may vary between
2846 * implementations. The returned string may be empty but may not be
2847 * <code>null</code>.
2848 *
2849 * @return the parameter string of this container
2850 */
2851 protected String paramString() {
2852 String str = super.paramString();
2853 LayoutManager layoutMgr = this.layoutMgr;
2854 if (layoutMgr != null) {
2855 str += ",layout=" + layoutMgr.getClass().getName();
2856 }
2857 return str;
2858 }
2859
2860 /**
2861 * Prints a listing of this container to the specified output
2862 * stream. The listing starts at the specified indentation.
2863 * <p>
2864 * The immediate children of the container are printed with
2865 * an indentation of <code>indent+1</code>. The children
2866 * of those children are printed at <code>indent+2</code>
2867 * and so on.
2868 *
2869 * @param out a print stream
2870 * @param indent the number of spaces to indent
2871 * @see Component#list(java.io.PrintStream, int)
2872 * @since JDK1.0
2873 */
2874 public void list(PrintStream out, int indent) {
2875 super.list(out, indent);
2876 int ncomponents = this.ncomponents;
2877 Component component[] = this.component;
2878 for (int i = 0 ; i < ncomponents ; i++) {
2879 Component comp = component[i];
2880 if (comp != null) {
2881 comp.list(out, indent+1);
2882 }
2883 }
2884 }
2885
2886 /**
2887 * Prints out a list, starting at the specified indentation,
2888 * to the specified print writer.
2889 * <p>
2890 * The immediate children of the container are printed with
2891 * an indentation of <code>indent+1</code>. The children
2892 * of those children are printed at <code>indent+2</code>
2893 * and so on.
2894 *
2895 * @param out a print writer
2896 * @param indent the number of spaces to indent
2897 * @see Component#list(java.io.PrintWriter, int)
2898 * @since JDK1.1
2899 */
2900 public void list(PrintWriter out, int indent) {
2901 super.list(out, indent);
2902 int ncomponents = this.ncomponents;
2903 Component component[] = this.component;
2904 for (int i = 0 ; i < ncomponents ; i++) {
2905 Component comp = component[i];
2906 if (comp != null) {
2907 comp.list(out, indent+1);
2908 }
2909 }
2910 }
2911
2912 /**
2913 * Sets the focus traversal keys for a given traversal operation for this
2914 * Container.
2915 * <p>
2916 * The default values for a Container's focus traversal keys are
2917 * implementation-dependent. Sun recommends that all implementations for a
2918 * particular native platform use the same default values. The
2919 * recommendations for Windows and Unix are listed below. These
2920 * recommendations are used in the Sun AWT implementations.
2921 *
2922 * <table border=1 summary="Recommended default values for a Container's focus traversal keys">
2923 * <tr>
2924 * <th>Identifier</th>
2925 * <th>Meaning</th>
2926 * <th>Default</th>
2927 * </tr>
2928 * <tr>
2929 * <td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td>
2930 * <td>Normal forward keyboard traversal</td>
2931 * <td>TAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED</td>
2932 * </tr>
2933 * <tr>
2934 * <td>KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS</td>
2935 * <td>Normal reverse keyboard traversal</td>
2936 * <td>SHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED</td>
2937 * </tr>
2938 * <tr>
2939 * <td>KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS</td>
2940 * <td>Go up one focus traversal cycle</td>
2941 * <td>none</td>
2942 * </tr>
2943 * <tr>
2944 * <td>KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS<td>
2945 * <td>Go down one focus traversal cycle</td>
2946 * <td>none</td>
2947 * </tr>
2948 * </table>
2949 *
2950 * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is
2951 * recommended.
2952 * <p>
2953 * Using the AWTKeyStroke API, client code can specify on which of two
2954 * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal
2955 * operation will occur. Regardless of which KeyEvent is specified,
2956 * however, all KeyEvents related to the focus traversal key, including the
2957 * associated KEY_TYPED event, will be consumed, and will not be dispatched
2958 * to any Container. It is a runtime error to specify a KEY_TYPED event as
2959 * mapping to a focus traversal operation, or to map the same event to
2960 * multiple default focus traversal operations.
2961 * <p>
2962 * If a value of null is specified for the Set, this Container inherits the
2963 * Set from its parent. If all ancestors of this Container have null
2964 * specified for the Set, then the current KeyboardFocusManager's default
2965 * Set is used.
2966 *
2967 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
2968 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
2969 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
2970 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
2971 * @param keystrokes the Set of AWTKeyStroke for the specified operation
2972 * @see #getFocusTraversalKeys
2973 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
2974 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
2975 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
2976 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
2977 * @throws IllegalArgumentException if id is not one of
2978 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
2979 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
2980 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
2981 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS, or if keystrokes
2982 * contains null, or if any Object in keystrokes is not an
2983 * AWTKeyStroke, or if any keystroke represents a KEY_TYPED event,
2984 * or if any keystroke already maps to another focus traversal
2985 * operation for this Container
2986 * @since 1.4
2987 * @beaninfo
2988 * bound: true
2989 */
2990 public void setFocusTraversalKeys(int id,
2991 Set<? extends AWTKeyStroke> keystrokes)
2992 {
2993 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
2994 throw new IllegalArgumentException("invalid focus traversal key identifier");
2995 }
2996
2997 // Don't call super.setFocusTraversalKey. The Component parameter check
2998 // does not allow DOWN_CYCLE_TRAVERSAL_KEYS, but we do.
2999 setFocusTraversalKeys_NoIDCheck(id, keystrokes);
3000 }
3001
3002 /**
3003 * Returns the Set of focus traversal keys for a given traversal operation
3004 * for this Container. (See
3005 * <code>setFocusTraversalKeys</code> for a full description of each key.)
3006 * <p>
3007 * If a Set of traversal keys has not been explicitly defined for this
3008 * Container, then this Container's parent's Set is returned. If no Set
3009 * has been explicitly defined for any of this Container's ancestors, then
3010 * the current KeyboardFocusManager's default Set is returned.
3011 *
3012 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3013 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3014 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3015 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3016 * @return the Set of AWTKeyStrokes for the specified operation. The Set
3017 * will be unmodifiable, and may be empty. null will never be
3018 * returned.
3019 * @see #setFocusTraversalKeys
3020 * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS
3021 * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS
3022 * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS
3023 * @see KeyboardFocusManager#DOWN_CYCLE_TRAVERSAL_KEYS
3024 * @throws IllegalArgumentException if id is not one of
3025 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3026 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3027 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3028 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3029 * @since 1.4
3030 */
3031 public Set<AWTKeyStroke> getFocusTraversalKeys(int id) {
3032 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3033 throw new IllegalArgumentException("invalid focus traversal key identifier");
3034 }
3035
3036 // Don't call super.getFocusTraversalKey. The Component parameter check
3037 // does not allow DOWN_CYCLE_TRAVERSAL_KEY, but we do.
3038 return getFocusTraversalKeys_NoIDCheck(id);
3039 }
3040
3041 /**
3042 * Returns whether the Set of focus traversal keys for the given focus
3043 * traversal operation has been explicitly defined for this Container. If
3044 * this method returns <code>false</code>, this Container is inheriting the
3045 * Set from an ancestor, or from the current KeyboardFocusManager.
3046 *
3047 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3048 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3049 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3050 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3051 * @return <code>true</code> if the the Set of focus traversal keys for the
3052 * given focus traversal operation has been explicitly defined for
3053 * this Component; <code>false</code> otherwise.
3054 * @throws IllegalArgumentException if id is not one of
3055 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
3056 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
3057 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or
3058 * KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS
3059 * @since 1.4
3060 */
3061 public boolean areFocusTraversalKeysSet(int id) {
3062 if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH) {
3063 throw new IllegalArgumentException("invalid focus traversal key identifier");
3064 }
3065
3066 return (focusTraversalKeys != null && focusTraversalKeys[id] != null);
3067 }
3068
3069 /**
3070 * Returns whether the specified Container is the focus cycle root of this
3071 * Container's focus traversal cycle. Each focus traversal cycle has only
3072 * a single focus cycle root and each Container which is not a focus cycle
3073 * root belongs to only a single focus traversal cycle. Containers which
3074 * are focus cycle roots belong to two cycles: one rooted at the Container
3075 * itself, and one rooted at the Container's nearest focus-cycle-root
3076 * ancestor. This method will return <code>true</code> for both such
3077 * Containers in this case.
3078 *
3079 * @param container the Container to be tested
3080 * @return <code>true</code> if the specified Container is a focus-cycle-
3081 * root of this Container; <code>false</code> otherwise
3082 * @see #isFocusCycleRoot()
3083 * @since 1.4
3084 */
3085 public boolean isFocusCycleRoot(Container container) {
3086 if (isFocusCycleRoot() && container == this) {
3087 return true;
3088 } else {
3089 return super.isFocusCycleRoot(container);
3090 }
3091 }
3092
3093 private Container findTraversalRoot() {
3094 // I potentially have two roots, myself and my root parent
3095 // If I am the current root, then use me
3096 // If none of my parents are roots, then use me
3097 // If my root parent is the current root, then use my root parent
3098 // If neither I nor my root parent is the current root, then
3099 // use my root parent (a guess)
3100
3101 Container currentFocusCycleRoot = KeyboardFocusManager.
3102 getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot();
3103 Container root;
3104
3105 if (currentFocusCycleRoot == this) {
3106 root = this;
3107 } else {
3108 root = getFocusCycleRootAncestor();
3109 if (root == null) {
3110 root = this;
3111 }
3112 }
3113
3114 if (root != currentFocusCycleRoot) {
3115 KeyboardFocusManager.getCurrentKeyboardFocusManager().
3116 setGlobalCurrentFocusCycleRoot(root);
3117 }
3118 return root;
3119 }
3120
3121 final boolean containsFocus() {
3122 final Component focusOwner = KeyboardFocusManager.
3123 getCurrentKeyboardFocusManager().getFocusOwner();
3124 return isParentOf(focusOwner);
3125 }
3126
3127 /**
3128 * Check if this component is the child of this container or its children.
3129 * Note: this function acquires treeLock
3130 * Note: this function traverses children tree only in one Window.
3131 * @param comp a component in test, must not be null
3132 */
3133 private boolean isParentOf(Component comp) {
3134 synchronized(getTreeLock()) {
3135 while (comp != null && comp != this && !(comp instanceof Window)) {
3136 comp = comp.getParent();
3137 }
3138 return (comp == this);
3139 }
3140 }
3141
3142 void clearMostRecentFocusOwnerOnHide() {
3143 boolean reset = false;
3144 Window window = null;
3145
3146 synchronized (getTreeLock()) {
3147 window = getContainingWindow();
3148 if (window != null) {
3149 Component comp = KeyboardFocusManager.getMostRecentFocusOwner(window);
3150 reset = ((comp == this) || isParentOf(comp));
3151 // This synchronized should always be the second in a pair
3152 // (tree lock, KeyboardFocusManager.class)
3153 synchronized(KeyboardFocusManager.class) {
3154 Component storedComp = window.getTemporaryLostComponent();
3155 if (isParentOf(storedComp) || storedComp == this) {
3156 window.setTemporaryLostComponent(null);
3157 }
3158 }
3159 }
3160 }
3161
3162 if (reset) {
3163 KeyboardFocusManager.setMostRecentFocusOwner(window, null);
3164 }
3165 }
3166
3167 void clearCurrentFocusCycleRootOnHide() {
3168 KeyboardFocusManager kfm =
3169 KeyboardFocusManager.getCurrentKeyboardFocusManager();
3170 Container cont = kfm.getCurrentFocusCycleRoot();
3171
3172 if (cont == this || isParentOf(cont)) {
3173 kfm.setGlobalCurrentFocusCycleRoot(null);
3174 }
3175 }
3176
3177 final Container getTraversalRoot() {
3178 if (isFocusCycleRoot()) {
3179 return findTraversalRoot();
3180 }
3181
3182 return super.getTraversalRoot();
3183 }
3184
3185 /**
3186 * Sets the focus traversal policy that will manage keyboard traversal of
3187 * this Container's children, if this Container is a focus cycle root. If
3188 * the argument is null, this Container inherits its policy from its focus-
3189 * cycle-root ancestor. If the argument is non-null, this policy will be
3190 * inherited by all focus-cycle-root children that have no keyboard-
3191 * traversal policy of their own (as will, recursively, their focus-cycle-
3192 * root children).
3193 * <p>
3194 * If this Container is not a focus cycle root, the policy will be
3195 * remembered, but will not be used or inherited by this or any other
3196 * Containers until this Container is made a focus cycle root.
3197 *
3198 * @param policy the new focus traversal policy for this Container
3199 * @see #getFocusTraversalPolicy
3200 * @see #setFocusCycleRoot
3201 * @see #isFocusCycleRoot
3202 * @since 1.4
3203 * @beaninfo
3204 * bound: true
3205 */
3206 public void setFocusTraversalPolicy(FocusTraversalPolicy policy) {
3207 FocusTraversalPolicy oldPolicy;
3208 synchronized (this) {
3209 oldPolicy = this.focusTraversalPolicy;
3210 this.focusTraversalPolicy = policy;
3211 }
3212 firePropertyChange("focusTraversalPolicy", oldPolicy, policy);
3213 }
3214
3215 /**
3216 * Returns the focus traversal policy that will manage keyboard traversal
3217 * of this Container's children, or null if this Container is not a focus
3218 * cycle root. If no traversal policy has been explicitly set for this
3219 * Container, then this Container's focus-cycle-root ancestor's policy is
3220 * returned.
3221 *
3222 * @return this Container's focus traversal policy, or null if this
3223 * Container is not a focus cycle root.
3224 * @see #setFocusTraversalPolicy
3225 * @see #setFocusCycleRoot
3226 * @see #isFocusCycleRoot
3227 * @since 1.4
3228 */
3229 public FocusTraversalPolicy getFocusTraversalPolicy() {
3230 if (!isFocusTraversalPolicyProvider() && !isFocusCycleRoot()) {
3231 return null;
3232 }
3233
3234 FocusTraversalPolicy policy = this.focusTraversalPolicy;
3235 if (policy != null) {
3236 return policy;
3237 }
3238
3239 Container rootAncestor = getFocusCycleRootAncestor();
3240 if (rootAncestor != null) {
3241 return rootAncestor.getFocusTraversalPolicy();
3242 } else {
3243 return KeyboardFocusManager.getCurrentKeyboardFocusManager().
3244 getDefaultFocusTraversalPolicy();
3245 }
3246 }
3247
3248 /**
3249 * Returns whether the focus traversal policy has been explicitly set for
3250 * this Container. If this method returns <code>false</code>, this
3251 * Container will inherit its focus traversal policy from an ancestor.
3252 *
3253 * @return <code>true</code> if the focus traversal policy has been
3254 * explicitly set for this Container; <code>false</code> otherwise.
3255 * @since 1.4
3256 */
3257 public boolean isFocusTraversalPolicySet() {
3258 return (focusTraversalPolicy != null);
3259 }
3260
3261 /**
3262 * Sets whether this Container is the root of a focus traversal cycle. Once
3263 * focus enters a traversal cycle, typically it cannot leave it via focus
3264 * traversal unless one of the up- or down-cycle keys is pressed. Normal
3265 * traversal is limited to this Container, and all of this Container's
3266 * descendants that are not descendants of inferior focus cycle roots. Note
3267 * that a FocusTraversalPolicy may bend these restrictions, however. For
3268 * example, ContainerOrderFocusTraversalPolicy supports implicit down-cycle
3269 * traversal.
3270 * <p>
3271 * The alternative way to specify the traversal order of this Container's
3272 * children is to make this Container a
3273 * <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy provider</a>.
3274 *
3275 * @param focusCycleRoot indicates whether this Container is the root of a
3276 * focus traversal cycle
3277 * @see #isFocusCycleRoot()
3278 * @see #setFocusTraversalPolicy
3279 * @see #getFocusTraversalPolicy
3280 * @see ContainerOrderFocusTraversalPolicy
3281 * @see #setFocusTraversalPolicyProvider
3282 * @since 1.4
3283 * @beaninfo
3284 * bound: true
3285 */
3286 public void setFocusCycleRoot(boolean focusCycleRoot) {
3287 boolean oldFocusCycleRoot;
3288 synchronized (this) {
3289 oldFocusCycleRoot = this.focusCycleRoot;
3290 this.focusCycleRoot = focusCycleRoot;
3291 }
3292 firePropertyChange("focusCycleRoot", oldFocusCycleRoot,
3293 focusCycleRoot);
3294 }
3295
3296 /**
3297 * Returns whether this Container is the root of a focus traversal cycle.
3298 * Once focus enters a traversal cycle, typically it cannot leave it via
3299 * focus traversal unless one of the up- or down-cycle keys is pressed.
3300 * Normal traversal is limited to this Container, and all of this
3301 * Container's descendants that are not descendants of inferior focus
3302 * cycle roots. Note that a FocusTraversalPolicy may bend these
3303 * restrictions, however. For example, ContainerOrderFocusTraversalPolicy
3304 * supports implicit down-cycle traversal.
3305 *
3306 * @return whether this Container is the root of a focus traversal cycle
3307 * @see #setFocusCycleRoot
3308 * @see #setFocusTraversalPolicy
3309 * @see #getFocusTraversalPolicy
3310 * @see ContainerOrderFocusTraversalPolicy
3311 * @since 1.4
3312 */
3313 public boolean isFocusCycleRoot() {
3314 return focusCycleRoot;
3315 }
3316
3317 /**
3318 * Sets whether this container will be used to provide focus
3319 * traversal policy. Container with this property as
3320 * <code>true</code> will be used to acquire focus traversal policy
3321 * instead of closest focus cycle root ancestor.
3322 * @param provider indicates whether this container will be used to
3323 * provide focus traversal policy
3324 * @see #setFocusTraversalPolicy
3325 * @see #getFocusTraversalPolicy
3326 * @see #isFocusTraversalPolicyProvider
3327 * @since 1.5
3328 * @beaninfo
3329 * bound: true
3330 */
3331 public final void setFocusTraversalPolicyProvider(boolean provider) {
3332 boolean oldProvider;
3333 synchronized(this) {
3334 oldProvider = focusTraversalPolicyProvider;
3335 focusTraversalPolicyProvider = provider;
3336 }
3337 firePropertyChange("focusTraversalPolicyProvider", oldProvider, provider);
3338 }
3339
3340 /**
3341 * Returns whether this container provides focus traversal
3342 * policy. If this property is set to <code>true</code> then when
3343 * keyboard focus manager searches container hierarchy for focus
3344 * traversal policy and encounters this container before any other
3345 * container with this property as true or focus cycle roots then
3346 * its focus traversal policy will be used instead of focus cycle
3347 * root's policy.
3348 * @see #setFocusTraversalPolicy
3349 * @see #getFocusTraversalPolicy
3350 * @see #setFocusCycleRoot
3351 * @see #setFocusTraversalPolicyProvider
3352 * @return <code>true</code> if this container provides focus traversal
3353 * policy, <code>false</code> otherwise
3354 * @since 1.5
3355 * @beaninfo
3356 * bound: true
3357 */
3358 public final boolean isFocusTraversalPolicyProvider() {
3359 return focusTraversalPolicyProvider;
3360 }
3361
3362 /**
3363 * Transfers the focus down one focus traversal cycle. If this Container is
3364 * a focus cycle root, then the focus owner is set to this Container's
3365 * default Component to focus, and the current focus cycle root is set to
3366 * this Container. If this Container is not a focus cycle root, then no
3367 * focus traversal operation occurs.
3368 *
3369 * @see Component#requestFocus()
3370 * @see #isFocusCycleRoot
3371 * @see #setFocusCycleRoot
3372 * @since 1.4
3373 */
3374 public void transferFocusDownCycle() {
3375 if (isFocusCycleRoot()) {
3376 KeyboardFocusManager.getCurrentKeyboardFocusManager().
3377 setGlobalCurrentFocusCycleRoot(this);
3378 Component toFocus = getFocusTraversalPolicy().
3379 getDefaultComponent(this);
3380 if (toFocus != null) {
3381 toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_DOWN);
3382 }
3383 }
3384 }
3385
3386 void preProcessKeyEvent(KeyEvent e) {
3387 Container parent = this.parent;
3388 if (parent != null) {
3389 parent.preProcessKeyEvent(e);
3390 }
3391 }
3392
3393 void postProcessKeyEvent(KeyEvent e) {
3394 Container parent = this.parent;
3395 if (parent != null) {
3396 parent.postProcessKeyEvent(e);
3397 }
3398 }
3399
3400 boolean postsOldMouseEvents() {
3401 return true;
3402 }
3403
3404 /**
3405 * Sets the <code>ComponentOrientation</code> property of this container
3406 * and all components contained within it.
3407 *
3408 * @param o the new component orientation of this container and
3409 * the components contained within it.
3410 * @exception NullPointerException if <code>orientation</code> is null.
3411 * @see Component#setComponentOrientation
3412 * @see Component#getComponentOrientation
3413 * @since 1.4
3414 */
3415 public void applyComponentOrientation(ComponentOrientation o) {
3416 super.applyComponentOrientation(o);
3417
3418 for (int i = 0 ; i < ncomponents ; ++i) {
3419 component[i].applyComponentOrientation(o);
3420 }
3421 }
3422
3423 /**
3424 * Adds a PropertyChangeListener to the listener list. The listener is
3425 * registered for all bound properties of this class, including the
3426 * following:
3427 * <ul>
3428 * <li>this Container's font ("font")</li>
3429 * <li>this Container's background color ("background")</li>
3430 * <li>this Container's foreground color ("foreground")</li>
3431 * <li>this Container's focusability ("focusable")</li>
3432 * <li>this Container's focus traversal keys enabled state
3433 * ("focusTraversalKeysEnabled")</li>
3434 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3435 * ("forwardFocusTraversalKeys")</li>
3436 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3437 * ("backwardFocusTraversalKeys")</li>
3438 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3439 * ("upCycleFocusTraversalKeys")</li>
3440 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3441 * ("downCycleFocusTraversalKeys")</li>
3442 * <li>this Container's focus traversal policy ("focusTraversalPolicy")
3443 * </li>
3444 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3445 * </ul>
3446 * Note that if this Container is inheriting a bound property, then no
3447 * event will be fired in response to a change in the inherited property.
3448 * <p>
3449 * If listener is null, no exception is thrown and no action is performed.
3450 *
3451 * @param listener the PropertyChangeListener to be added
3452 *
3453 * @see Component#removePropertyChangeListener
3454 * @see #addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
3455 */
3456 public void addPropertyChangeListener(PropertyChangeListener listener) {
3457 super.addPropertyChangeListener(listener);
3458 }
3459
3460 /**
3461 * Adds a PropertyChangeListener to the listener list for a specific
3462 * property. The specified property may be user-defined, or one of the
3463 * following defaults:
3464 * <ul>
3465 * <li>this Container's font ("font")</li>
3466 * <li>this Container's background color ("background")</li>
3467 * <li>this Container's foreground color ("foreground")</li>
3468 * <li>this Container's focusability ("focusable")</li>
3469 * <li>this Container's focus traversal keys enabled state
3470 * ("focusTraversalKeysEnabled")</li>
3471 * <li>this Container's Set of FORWARD_TRAVERSAL_KEYS
3472 * ("forwardFocusTraversalKeys")</li>
3473 * <li>this Container's Set of BACKWARD_TRAVERSAL_KEYS
3474 * ("backwardFocusTraversalKeys")</li>
3475 * <li>this Container's Set of UP_CYCLE_TRAVERSAL_KEYS
3476 * ("upCycleFocusTraversalKeys")</li>
3477 * <li>this Container's Set of DOWN_CYCLE_TRAVERSAL_KEYS
3478 * ("downCycleFocusTraversalKeys")</li>
3479 * <li>this Container's focus traversal policy ("focusTraversalPolicy")
3480 * </li>
3481 * <li>this Container's focus-cycle-root state ("focusCycleRoot")</li>
3482 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3483 * <li>this Container's focus-traversal-policy-provider state("focusTraversalPolicyProvider")</li>
3484 * </ul>
3485 * Note that if this Container is inheriting a bound property, then no
3486 * event will be fired in response to a change in the inherited property.
3487 * <p>
3488 * If listener is null, no exception is thrown and no action is performed.
3489 *
3490 * @param propertyName one of the property names listed above
3491 * @param listener the PropertyChangeListener to be added
3492 *
3493 * @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
3494 * @see Component#removePropertyChangeListener
3495 */
3496 public void addPropertyChangeListener(String propertyName,
3497 PropertyChangeListener listener) {
3498 super.addPropertyChangeListener(propertyName, listener);
3499 }
3500
3501 // Serialization support. A Container is responsible for restoring the
3502 // parent fields of its component children.
3503
3504 /**
3505 * Container Serial Data Version.
3506 */
3507 private int containerSerializedDataVersion = 1;
3508
3509 /**
3510 * Serializes this <code>Container</code> to the specified
3511 * <code>ObjectOutputStream</code>.
3512 * <ul>
3513 * <li>Writes default serializable fields to the stream.</li>
3514 * <li>Writes a list of serializable ContainerListener(s) as optional
3515 * data. The non-serializable ContainerListner(s) are detected and
3516 * no attempt is made to serialize them.</li>
3517 * <li>Write this Container's FocusTraversalPolicy if and only if it
3518 * is Serializable; otherwise, <code>null</code> is written.</li>
3519 * </ul>
3520 *
3521 * @param s the <code>ObjectOutputStream</code> to write
3522 * @serialData <code>null</code> terminated sequence of 0 or more pairs;
3523 * the pair consists of a <code>String</code> and <code>Object</code>;
3524 * the <code>String</code> indicates the type of object and
3525 * is one of the following:
3526 * <code>containerListenerK</code> indicating an
3527 * <code>ContainerListener</code> object;
3528 * the <code>Container</code>'s <code>FocusTraversalPolicy</code>,
3529 * or <code>null</code>
3530 *
3531 * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener)
3532 * @see Container#containerListenerK
3533 * @see #readObject(ObjectInputStream)
3534 */
3535 private void writeObject(ObjectOutputStream s) throws IOException {
3536 ObjectOutputStream.PutField f = s.putFields();
3537 f.put("ncomponents", ncomponents);
3538 f.put("component", component);
3539 f.put("layoutMgr", layoutMgr);
3540 f.put("dispatcher", dispatcher);
3541 f.put("maxSize", maxSize);
3542 f.put("focusCycleRoot", focusCycleRoot);
3543 f.put("containerSerializedDataVersion", containerSerializedDataVersion);
3544 f.put("focusTraversalPolicyProvider", focusTraversalPolicyProvider);
3545 s.writeFields();
3546
3547 AWTEventMulticaster.save(s, containerListenerK, containerListener);
3548 s.writeObject(null);
3549
3550 if (focusTraversalPolicy instanceof java.io.Serializable) {
3551 s.writeObject(focusTraversalPolicy);
3552 } else {
3553 s.writeObject(null);
3554 }
3555 }
3556
3557 /**
3558 * Deserializes this <code>Container</code> from the specified
3559 * <code>ObjectInputStream</code>.
3560 * <ul>
3561 * <li>Reads default serializable fields from the stream.</li>
3562 * <li>Reads a list of serializable ContainerListener(s) as optional
3563 * data. If the list is null, no Listeners are installed.</li>
3564 * <li>Reads this Container's FocusTraversalPolicy, which may be null,
3565 * as optional data.</li>
3566 * </ul>
3567 *
3568 * @param s the <code>ObjectInputStream</code> to read
3569 * @serial
3570 * @see #addContainerListener
3571 * @see #writeObject(ObjectOutputStream)
3572 */
3573 private void readObject(ObjectInputStream s)
3574 throws ClassNotFoundException, IOException
3575 {
3576 ObjectInputStream.GetField f = s.readFields();
3577 ncomponents = f.get("ncomponents", 0);
3578 component = (Component[])f.get("component", new Component[0]);
3579 layoutMgr = (LayoutManager)f.get("layoutMgr", null);
3580 dispatcher = (LightweightDispatcher)f.get("dispatcher", null);
3581 // Old stream. Doesn't contain maxSize among Component's fields.
3582 if (maxSize == null) {
3583 maxSize = (Dimension)f.get("maxSize", null);
3584 }
3585 focusCycleRoot = f.get("focusCycleRoot", false);
3586 containerSerializedDataVersion = f.get("containerSerializedDataVersion", 1);
3587 focusTraversalPolicyProvider = f.get("focusTraversalPolicyProvider", false);
3588
3589 Component component[] = this.component;
3590 for(int i = 0; i < ncomponents; i++) {
3591 component[i].parent = this;
3592 adjustListeningChildren(AWTEvent.HIERARCHY_EVENT_MASK,
3593 component[i].numListening(AWTEvent.HIERARCHY_EVENT_MASK));
3594 adjustListeningChildren(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
3595 component[i].numListening(
3596 AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK));
3597 adjustDescendants(component[i].countHierarchyMembers());
3598 }
3599
3600 Object keyOrNull;
3601 while(null != (keyOrNull = s.readObject())) {
3602 String key = ((String)keyOrNull).intern();
3603
3604 if (containerListenerK == key) {
3605 addContainerListener((ContainerListener)(s.readObject()));
3606 } else {
3607 // skip value for unrecognized key
3608 s.readObject();
3609 }
3610 }
3611
3612 try {
3613 Object policy = s.readObject();
3614 if (policy instanceof FocusTraversalPolicy) {
3615 focusTraversalPolicy = (FocusTraversalPolicy)policy;
3616 }
3617 } catch (java.io.OptionalDataException e) {
3618 // JDK 1.1/1.2/1.3 instances will not have this optional data.
3619 // e.eof will be true to indicate that there is no more data
3620 // available for this object. If e.eof is not true, throw the
3621 // exception as it might have been caused by reasons unrelated to
3622 // focusTraversalPolicy.
3623
3624 if (!e.eof) {
3625 throw e;
3626 }
3627 }
3628 }
3629
3630 /*
3631 * --- Accessibility Support ---
3632 */
3633
3634 /**
3635 * Inner class of Container used to provide default support for
3636 * accessibility. This class is not meant to be used directly by
3637 * application developers, but is instead meant only to be
3638 * subclassed by container developers.
3639 * <p>
3640 * The class used to obtain the accessible role for this object,
3641 * as well as implementing many of the methods in the
3642 * AccessibleContainer interface.
3643 * @since 1.3
3644 */
3645 protected class AccessibleAWTContainer extends AccessibleAWTComponent {
3646
3647 /**
3648 * JDK1.3 serialVersionUID
3649 */
3650 private static final long serialVersionUID = 5081320404842566097L;
3651
3652 /**
3653 * Returns the number of accessible children in the object. If all
3654 * of the children of this object implement <code>Accessible</code>,
3655 * then this method should return the number of children of this object.
3656 *
3657 * @return the number of accessible children in the object
3658 */
3659 public int getAccessibleChildrenCount() {
3660 return Container.this.getAccessibleChildrenCount();
3661 }
3662
3663 /**
3664 * Returns the nth <code>Accessible</code> child of the object.
3665 *
3666 * @param i zero-based index of child
3667 * @return the nth <code>Accessible</code> child of the object
3668 */
3669 public Accessible getAccessibleChild(int i) {
3670 return Container.this.getAccessibleChild(i);
3671 }
3672
3673 /**
3674 * Returns the <code>Accessible</code> child, if one exists,
3675 * contained at the local coordinate <code>Point</code>.
3676 *
3677 * @param p the point defining the top-left corner of the
3678 * <code>Accessible</code>, given in the coordinate space
3679 * of the object's parent
3680 * @return the <code>Accessible</code>, if it exists,
3681 * at the specified location; else <code>null</code>
3682 */
3683 public Accessible getAccessibleAt(Point p) {
3684 return Container.this.getAccessibleAt(p);
3685 }
3686
3687 protected ContainerListener accessibleContainerHandler = null;
3688
3689 /**
3690 * Fire <code>PropertyChange</code> listener, if one is registered,
3691 * when children are added or removed.
3692 * @since 1.3
3693 */
3694 protected class AccessibleContainerHandler
3695 implements ContainerListener {
3696 public void componentAdded(ContainerEvent e) {
3697 Component c = e.getChild();
3698 if (c != null && c instanceof Accessible) {
3699 AccessibleAWTContainer.this.firePropertyChange(
3700 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3701 null, ((Accessible) c).getAccessibleContext());
3702 }
3703 }
3704 public void componentRemoved(ContainerEvent e) {
3705 Component c = e.getChild();
3706 if (c != null && c instanceof Accessible) {
3707 AccessibleAWTContainer.this.firePropertyChange(
3708 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY,
3709 ((Accessible) c).getAccessibleContext(), null);
3710 }
3711 }
3712 }
3713
3714 /**
3715 * Adds a PropertyChangeListener to the listener list.
3716 *
3717 * @param listener the PropertyChangeListener to be added
3718 */
3719 public void addPropertyChangeListener(PropertyChangeListener listener) {
3720 if (accessibleContainerHandler == null) {
3721 accessibleContainerHandler = new AccessibleContainerHandler();
3722 Container.this.addContainerListener(accessibleContainerHandler);
3723 }
3724 super.addPropertyChangeListener(listener);
3725 }
3726
3727 } // inner class AccessibleAWTContainer
3728
3729 /**
3730 * Returns the <code>Accessible</code> child contained at the local
3731 * coordinate <code>Point</code>, if one exists. Otherwise
3732 * returns <code>null</code>.
3733 *
3734 * @param p the point defining the top-left corner of the
3735 * <code>Accessible</code>, given in the coordinate space
3736 * of the object's parent
3737 * @return the <code>Accessible</code> at the specified location,
3738 * if it exists; otherwise <code>null</code>
3739 */
3740 Accessible getAccessibleAt(Point p) {
3741 synchronized (getTreeLock()) {
3742 if (this instanceof Accessible) {
3743 Accessible a = (Accessible)this;
3744 AccessibleContext ac = a.getAccessibleContext();
3745 if (ac != null) {
3746 AccessibleComponent acmp;
3747 Point location;
3748 int nchildren = ac.getAccessibleChildrenCount();
3749 for (int i=0; i < nchildren; i++) {
3750 a = ac.getAccessibleChild(i);
3751 if ((a != null)) {
3752 ac = a.getAccessibleContext();
3753 if (ac != null) {
3754 acmp = ac.getAccessibleComponent();
3755 if ((acmp != null) && (acmp.isShowing())) {
3756 location = acmp.getLocation();
3757 Point np = new Point(p.x-location.x,
3758 p.y-location.y);
3759 if (acmp.contains(np)){
3760 return a;
3761 }
3762 }
3763 }
3764 }
3765 }
3766 }
3767 return (Accessible)this;
3768 } else {
3769 Component ret = this;
3770 if (!this.contains(p.x,p.y)) {
3771 ret = null;
3772 } else {
3773 int ncomponents = this.getComponentCount();
3774 for (int i=0; i < ncomponents; i++) {
3775 Component comp = this.getComponent(i);
3776 if ((comp != null) && comp.isShowing()) {
3777 Point location = comp.getLocation();
3778 if (comp.contains(p.x-location.x,p.y-location.y)) {
3779 ret = comp;
3780 }
3781 }
3782 }
3783 }
3784 if (ret instanceof Accessible) {
3785 return (Accessible) ret;
3786 }
3787 }
3788 return null;
3789 }
3790 }
3791
3792 /**
3793 * Returns the number of accessible children in the object. If all
3794 * of the children of this object implement <code>Accessible</code>,
3795 * then this method should return the number of children of this object.
3796 *
3797 * @return the number of accessible children in the object
3798 */
3799 int getAccessibleChildrenCount() {
3800 synchronized (getTreeLock()) {
3801 int count = 0;
3802 Component[] children = this.getComponents();
3803 for (int i = 0; i < children.length; i++) {
3804 if (children[i] instanceof Accessible) {
3805 count++;
3806 }
3807 }
3808 return count;
3809 }
3810 }
3811
3812 /**
3813 * Returns the nth <code>Accessible</code> child of the object.
3814 *
3815 * @param i zero-based index of child
3816 * @return the nth <code>Accessible</code> child of the object
3817 */
3818 Accessible getAccessibleChild(int i) {
3819 synchronized (getTreeLock()) {
3820 Component[] children = this.getComponents();
3821 int count = 0;
3822 for (int j = 0; j < children.length; j++) {
3823 if (children[j] instanceof Accessible) {
3824 if (count == i) {
3825 return (Accessible) children[j];
3826 } else {
3827 count++;
3828 }
3829 }
3830 }
3831 return null;
3832 }
3833 }
3834
3835 // ************************** MIXING CODE *******************************
3836
3837 final void increaseComponentCount(Component c) {
3838 synchronized (getTreeLock()) {
3839 if (!c.isDisplayable()) {
3840 throw new IllegalStateException(
3841 "Peer does not exist while invoking the increaseComponentCount() method"
3842 );
3843 }
3844
3845 int addHW = 0;
3846 int addLW = 0;
3847
3848 if (c instanceof Container) {
3849 addLW = ((Container)c).numOfLWComponents;
3850 addHW = ((Container)c).numOfHWComponents;
3851 }
3852 if (c.isLightweight()) {
3853 addLW++;
3854 } else {
3855 addHW++;
3856 }
3857
3858 for (Container cont = this; cont != null; cont = cont.getContainer()) {
3859 cont.numOfLWComponents += addLW;
3860 cont.numOfHWComponents += addHW;
3861 }
3862 }
3863 }
3864
3865 final void decreaseComponentCount(Component c) {
3866 synchronized (getTreeLock()) {
3867 if (!c.isDisplayable()) {
3868 throw new IllegalStateException(
3869 "Peer does not exist while invoking the decreaseComponentCount() method"
3870 );
3871 }
3872
3873 int subHW = 0;
3874 int subLW = 0;
3875
3876 if (c instanceof Container) {
3877 subLW = ((Container)c).numOfLWComponents;
3878 subHW = ((Container)c).numOfHWComponents;
3879 }
3880 if (c.isLightweight()) {
3881 subLW++;
3882 } else {
3883 subHW++;
3884 }
3885
3886 for (Container cont = this; cont != null; cont = cont.getContainer()) {
3887 cont.numOfLWComponents -= subLW;
3888 cont.numOfHWComponents -= subHW;
3889 }
3890 }
3891 }
3892
3893 private int getTopmostComponentIndex() {
3894 checkTreeLock();
3895 if (getComponentCount() > 0) {
3896 return 0;
3897 }
3898 return -1;
3899 }
3900
3901 private int getBottommostComponentIndex() {
3902 checkTreeLock();
3903 if (getComponentCount() > 0) {
3904 return getComponentCount() - 1;
3905 }
3906 return -1;
3907 }
3908
3909 final void recursiveSubtractAndApplyShape(Region shape) {
3910 recursiveSubtractAndApplyShape(shape, getTopmostComponentIndex(), getBottommostComponentIndex());
3911 }
3912
3913 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder) {
3914 recursiveSubtractAndApplyShape(shape, fromZorder, getBottommostComponentIndex());
3915 }
3916
3917 final void recursiveSubtractAndApplyShape(Region shape, int fromZorder, int toZorder) {
3918 checkTreeLock();
3919 if (mixingLog.isLoggable(Level.FINE)) {
3920 mixingLog.fine("this = " + this +
3921 "; shape=" + shape + "; fromZ=" + fromZorder + "; toZ=" + toZorder);
3922 }
3923 if (fromZorder == -1) {
3924 return;
3925 }
3926 for (int index = fromZorder; index <= toZorder; index++) {
3927 Component comp = getComponent(index);
3928 if (!comp.isLightweight()) {
3929 comp.subtractAndApplyShape(shape);
3930 } else if (comp instanceof Container &&
3931 ((Container)comp).hasHeavyweightDescendants() && comp.isShowing()) {
3932 ((Container)comp).recursiveSubtractAndApplyShape(shape);
3933 }
3934 }
3935 }
3936
3937 final void recursiveApplyCurrentShape() {
3938 recursiveApplyCurrentShape(getTopmostComponentIndex(), getBottommostComponentIndex());
3939 }
3940
3941 final void recursiveApplyCurrentShape(int fromZorder) {
3942 recursiveApplyCurrentShape(fromZorder, getBottommostComponentIndex());
3943 }
3944
3945 final void recursiveApplyCurrentShape(int fromZorder, int toZorder) {
3946 checkTreeLock();
3947 if (mixingLog.isLoggable(Level.FINE)) {
3948 mixingLog.fine("this = " + this +
3949 "; fromZ=" + fromZorder + "; toZ=" + toZorder);
3950 }
3951 if (fromZorder == -1) {
3952 return;
3953 }
3954 for (int index = fromZorder; index <= toZorder; index++) {
3955 Component comp = getComponent(index);
3956 if (!comp.isLightweight()) {
3957 comp.applyCurrentShape();
3958 } else if (comp instanceof Container &&
3959 ((Container)comp).hasHeavyweightDescendants()) {
3960 ((Container)comp).recursiveApplyCurrentShape();
3961 }
3962 }
3963 }
3964
3965 private void recursiveShowHeavyweightChildren() {
3966 if (!hasHeavyweightDescendants() || !isVisible()) {
3967 return;
3968 }
3969 for (int index = 0; index < getComponentCount(); index++) {
3970 Component comp = getComponent(index);
3971 if (comp.isLightweight()) {
3972 if (comp instanceof Container) {
3973 ((Container)comp).recursiveShowHeavyweightChildren();
3974 }
3975 } else {
3976 if (comp.isVisible()) {
3977 ComponentPeer peer = comp.getPeer();
3978 if (peer != null) {
3979 peer.show();
3980 }
3981 }
3982 }
3983 }
3984 }
3985
3986 private void recursiveHideHeavyweightChildren() {
3987 if (!hasHeavyweightDescendants()) {
3988 return;
3989 }
3990 for (int index = 0; index < getComponentCount(); index++) {
3991 Component comp = getComponent(index);
3992 if (comp.isLightweight()) {
3993 if (comp instanceof Container) {
3994 ((Container)comp).recursiveHideHeavyweightChildren();
3995 }
3996 } else {
3997 if (comp.isVisible()) {
3998 ComponentPeer peer = comp.getPeer();
3999 if (peer != null) {
4000 peer.hide();
4001 }
4002 }
4003 }
4004 }
4005 }
4006
4007 private void recursiveRelocateHeavyweightChildren(Point origin) {
4008 for (int index = 0; index < getComponentCount(); index++) {
4009 Component comp = getComponent(index);
4010 if (comp.isLightweight()) {
4011 if (comp instanceof Container &&
4012 ((Container)comp).hasHeavyweightDescendants())
4013 {
4014 final Point newOrigin = new Point(origin);
4015 newOrigin.translate(comp.getX(), comp.getY());
4016 ((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin);
4017 }
4018 } else {
4019 ComponentPeer peer = comp.getPeer();
4020 if (peer != null) {
4021 peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(),
4022 comp.getWidth(), comp.getHeight(),
4023 ComponentPeer.SET_LOCATION);
4024 }
4025 }
4026 }
4027 }
4028
4029 /*
4030 * Consider the heavyweight container hides or shows the HW descendants
4031 * automatically. Therefore we care of LW containers' visibility only.
4032 */
4033 private boolean isRecursivelyVisibleUpToHeavyweightContainer() {
4034 if (!isLightweight()) {
4035 return true;
4036 }
4037 return isVisible() && (getContainer() == null ||
4038 getContainer().isRecursivelyVisibleUpToHeavyweightContainer());
4039 }
4040
4041 @Override
4042 void mixOnShowing() {
4043 synchronized (getTreeLock()) {
4044 if (mixingLog.isLoggable(Level.FINE)) {
4045 mixingLog.fine("this = " + this);
4046 }
4047
4048 boolean isLightweight = isLightweight();
4049
4050 if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) {
4051 recursiveShowHeavyweightChildren();
4052 }
4053
4054 if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) {
4055 recursiveApplyCurrentShape();
4056 }
4057
4058 super.mixOnShowing();
4059 }
4060 }
4061
4062 @Override
4063 void mixOnHiding(boolean isLightweight) {
4064 synchronized (getTreeLock()) {
4065 if (mixingLog.isLoggable(Level.FINE)) {
4066 mixingLog.fine("this = " + this +
4067 "; isLightweight=" + isLightweight);
4068 }
4069 if (isLightweight) {
4070 recursiveHideHeavyweightChildren();
4071 }
4072 super.mixOnHiding(isLightweight);
4073 }
4074 }
4075
4076 @Override
4077 void mixOnReshaping() {
4078 synchronized (getTreeLock()) {
4079 if (mixingLog.isLoggable(Level.FINE)) {
4080 mixingLog.fine("this = " + this);
4081 }
4082 if (isLightweight() && hasHeavyweightDescendants()) {
4083 final Point origin = new Point(getX(), getY());
4084 for (Container cont = getContainer();
4085 cont != null && cont.isLightweight();
4086 cont = cont.getContainer())
4087 {
4088 origin.translate(cont.getX(), cont.getY());
4089 }
4090
4091 recursiveRelocateHeavyweightChildren(origin);
4092 }
4093 super.mixOnReshaping();
4094 }
4095 }
4096
4097 @Override
4098 void mixOnZOrderChanging(int oldZorder, int newZorder) {
4099 synchronized (getTreeLock()) {
4100 if (mixingLog.isLoggable(Level.FINE)) {
4101 mixingLog.fine("this = " + this +
4102 "; oldZ=" + oldZorder + "; newZ=" + newZorder);
4103 }
4104
4105 boolean becameHigher = newZorder < oldZorder;
4106
4107 if (becameHigher && isLightweight() && hasHeavyweightDescendants()) {
4108 recursiveApplyCurrentShape();
4109 }
4110 super.mixOnZOrderChanging(oldZorder, newZorder);
4111 }
4112 }
4113
4114 // ****************** END OF MIXING CODE ********************************
4115 }
4116
4117
4118 /**
4119 * Class to manage the dispatching of MouseEvents to the lightweight descendants
4120 * and SunDropTargetEvents to both lightweight and heavyweight descendants
4121 * contained by a native container.
4122 *
4123 * NOTE: the class name is not appropriate anymore, but we cannot change it
4124 * because we must keep serialization compatibility.
4125 *
4126 * @author Timothy Prinzing
4127 */
4128 class LightweightDispatcher implements java.io.Serializable, AWTEventListener {
4129
4130 /*
4131 * JDK 1.1 serialVersionUID
4132 */
4133 private static final long serialVersionUID = 5184291520170872969L;
4134 /*
4135 * Our own mouse event for when we're dragged over from another hw
4136 * container
4137 */
4138 private static final int LWD_MOUSE_DRAGGED_OVER = 1500;
4139
4140 private static final Logger eventLog = Logger.getLogger("java.awt.event.LightweightDispatcher");
4141
4142 LightweightDispatcher(Container nativeContainer) {
4143 this.nativeContainer = nativeContainer;
4144 mouseEventTarget = null;
4145 eventMask = 0;
4146 }
4147
4148 /*
4149 * Clean up any resources allocated when dispatcher was created;
4150 * should be called from Container.removeNotify
4151 */
4152 void dispose() {
4153 //System.out.println("Disposing lw dispatcher");
4154 stopListeningForOtherDrags();
4155 mouseEventTarget = null;
4156 }
4157
4158 /**
4159 * Enables events to subcomponents.
4160 */
4161 void enableEvents(long events) {
4162 eventMask |= events;
4163 }
4164
4165 /**
4166 * Dispatches an event to a sub-component if necessary, and
4167 * returns whether or not the event was forwarded to a
4168 * sub-component.
4169 *
4170 * @param e the event
4171 */
4172 boolean dispatchEvent(AWTEvent e) {
4173 boolean ret = false;
4174
4175 /*
4176 * Fix for BugTraq Id 4389284.
4177 * Dispatch SunDropTargetEvents regardless of eventMask value.
4178 * Do not update cursor on dispatching SunDropTargetEvents.
4179 */
4180 if (e instanceof SunDropTargetEvent) {
4181
4182 SunDropTargetEvent sdde = (SunDropTargetEvent) e;
4183 ret = processDropTargetEvent(sdde);
4184
4185 } else {
4186 if (e instanceof MouseEvent && (eventMask & MOUSE_MASK) != 0) {
4187 MouseEvent me = (MouseEvent) e;
4188 ret = processMouseEvent(me);
4189 }
4190
4191 if (e.getID() == MouseEvent.MOUSE_MOVED) {
4192 nativeContainer.updateCursorImmediately();
4193 }
4194 }
4195
4196 return ret;
4197 }
4198
4199 /* This method effectively returns whether or not a mouse button was down
4200 * just BEFORE the event happened. A better method name might be
4201 * wasAMouseButtonDownBeforeThisEvent().
4202 */
4203 private boolean isMouseGrab(MouseEvent e) {
4204 int modifiers = e.getModifiersEx();
4205
4206 if(e.getID() == MouseEvent.MOUSE_PRESSED
4207 || e.getID() == MouseEvent.MOUSE_RELEASED)
4208 {
4209 switch (e.getButton()) {
4210 case MouseEvent.BUTTON1:
4211 modifiers ^= InputEvent.BUTTON1_DOWN_MASK;
4212 break;
4213 case MouseEvent.BUTTON2:
4214 modifiers ^= InputEvent.BUTTON2_DOWN_MASK;
4215 break;
4216 case MouseEvent.BUTTON3:
4217 modifiers ^= InputEvent.BUTTON3_DOWN_MASK;
4218 break;
4219 }
4220 }
4221 /* modifiers now as just before event */
4222 return ((modifiers & (InputEvent.BUTTON1_DOWN_MASK
4223 | InputEvent.BUTTON2_DOWN_MASK
4224 | InputEvent.BUTTON3_DOWN_MASK)) != 0);
4225 }
4226
4227 /**
4228 * This method attempts to distribute a mouse event to a lightweight
4229 * component. It tries to avoid doing any unnecessary probes down
4230 * into the component tree to minimize the overhead of determining
4231 * where to route the event, since mouse movement events tend to
4232 * come in large and frequent amounts.
4233 */
4234 private boolean processMouseEvent(MouseEvent e) {
4235 int id = e.getID();
4236 Component mouseOver = // sensitive to mouse events
4237 nativeContainer.getMouseEventTarget(e.getX(), e.getY(),
4238 Container.INCLUDE_SELF);
4239
4240 trackMouseEnterExit(mouseOver, e);
4241
4242 // 4508327 : MOUSE_CLICKED should only go to the recipient of
4243 // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a
4244 // MOUSE_CLICKED.
4245 if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) {
4246 mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver: null;
4247 }
4248
4249 if (mouseEventTarget != null) {
4250 switch (id) {
4251 case MouseEvent.MOUSE_ENTERED:
4252 case MouseEvent.MOUSE_EXITED:
4253 break;
4254 case MouseEvent.MOUSE_PRESSED:
4255 retargetMouseEvent(mouseEventTarget, id, e);
4256 break;
4257 case MouseEvent.MOUSE_RELEASED:
4258 retargetMouseEvent(mouseEventTarget, id, e);
4259 break;
4260 case MouseEvent.MOUSE_CLICKED:
4261 // 4508327: MOUSE_CLICKED should never be dispatched to a Component
4262 // other than that which received the MOUSE_PRESSED event. If the
4263 // mouse is now over a different Component, don't dispatch the event.
4264 // The previous fix for a similar problem was associated with bug
4265 // 4155217.
4266 if (mouseOver == mouseEventTarget) {
4267 retargetMouseEvent(mouseOver, id, e);
4268 }
4269 break;
4270 case MouseEvent.MOUSE_MOVED:
4271 retargetMouseEvent(mouseEventTarget, id, e);
4272 break;
4273 case MouseEvent.MOUSE_DRAGGED:
4274 if (isMouseGrab(e)) {
4275 retargetMouseEvent(mouseEventTarget, id, e);
4276 }
4277 break;
4278 case MouseEvent.MOUSE_WHEEL:
4279 // This may send it somewhere that doesn't have MouseWheelEvents
4280 // enabled. In this case, Component.dispatchEventImpl() will
4281 // retarget the event to a parent that DOES have the events enabled.
4282 if (eventLog.isLoggable(Level.FINEST) && (mouseOver != null)) {
4283 eventLog.log(Level.FINEST, "retargeting mouse wheel to " +
4284 mouseOver.getName() + ", " +
4285 mouseOver.getClass());
4286 }
4287 retargetMouseEvent(mouseOver, id, e);
4288 break;
4289 }
4290 e.consume();
4291 }
4292 return e.isConsumed();
4293 }
4294
4295 private boolean processDropTargetEvent(SunDropTargetEvent e) {
4296 int id = e.getID();
4297 int x = e.getX();
4298 int y = e.getY();
4299
4300 /*
4301 * Fix for BugTraq ID 4395290.
4302 * It is possible that SunDropTargetEvent's Point is outside of the
4303 * native container bounds. In this case we truncate coordinates.
4304 */
4305 if (!nativeContainer.contains(x, y)) {
4306 final Dimension d = nativeContainer.getSize();
4307 if (d.width <= x) {
4308 x = d.width - 1;
4309 } else if (x < 0) {
4310 x = 0;
4311 }
4312 if (d.height <= y) {
4313 y = d.height - 1;
4314 } else if (y < 0) {
4315 y = 0;
4316 }
4317 }
4318 Component mouseOver = // not necessarily sensitive to mouse events
4319 nativeContainer.getDropTargetEventTarget(x, y,
4320 Container.INCLUDE_SELF);
4321 trackMouseEnterExit(mouseOver, e);
4322
4323 if (mouseOver != nativeContainer && mouseOver != null) {
4324 switch (id) {
4325 case SunDropTargetEvent.MOUSE_ENTERED:
4326 case SunDropTargetEvent.MOUSE_EXITED:
4327 break;
4328 default:
4329 retargetMouseEvent(mouseOver, id, e);
4330 e.consume();
4331 break;
4332 }
4333 }
4334 return e.isConsumed();
4335 }
4336
4337 /*
4338 * Generates enter/exit events as mouse moves over lw components
4339 * @param targetOver Target mouse is over (including native container)
4340 * @param e Mouse event in native container
4341 */
4342 private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
4343 Component targetEnter = null;
4344 int id = e.getID();
4345
4346 if (e instanceof SunDropTargetEvent &&
4347 id == MouseEvent.MOUSE_ENTERED &&
4348 isMouseInNativeContainer == true) {
4349 // This can happen if a lightweight component which initiated the
4350 // drag has an associated drop target. MOUSE_ENTERED comes when the
4351 // mouse is in the native container already. To propagate this event
4352 // properly we should null out targetLastEntered.
4353 targetLastEntered = null;
4354 } else if ( id != MouseEvent.MOUSE_EXITED &&
4355 id != MouseEvent.MOUSE_DRAGGED &&
4356 id != LWD_MOUSE_DRAGGED_OVER &&
4357 isMouseInNativeContainer == false ) {
4358 // any event but an exit or drag means we're in the native container
4359 isMouseInNativeContainer = true;
4360 startListeningForOtherDrags();
4361 } else if ( id == MouseEvent.MOUSE_EXITED ) {
4362 isMouseInNativeContainer = false;
4363 stopListeningForOtherDrags();
4364 }
4365
4366 if (isMouseInNativeContainer) {
4367 targetEnter = targetOver;
4368 }
4369
4370 if (targetLastEntered == targetEnter) {
4371 return;
4372 }
4373
4374 if (targetLastEntered != null) {
4375 retargetMouseEvent(targetLastEntered, MouseEvent.MOUSE_EXITED, e);
4376 }
4377 if (id == MouseEvent.MOUSE_EXITED) {
4378 // consume native exit event if we generate one
4379 e.consume();
4380 }
4381
4382 if (targetEnter != null) {
4383 retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
4384 }
4385 if (id == MouseEvent.MOUSE_ENTERED) {
4386 // consume native enter event if we generate one
4387 e.consume();
4388 }
4389
4390 targetLastEntered = targetEnter;
4391 }
4392
4393 /*
4394 * Listens to global mouse drag events so even drags originating
4395 * from other heavyweight containers will generate enter/exit
4396 * events in this container
4397 */
4398 private void startListeningForOtherDrags() {
4399 //System.out.println("Adding AWTEventListener");
4400 java.security.AccessController.doPrivileged(
4401 new java.security.PrivilegedAction() {
4402 public Object run() {
4403 nativeContainer.getToolkit().addAWTEventListener(
4404 LightweightDispatcher.this,
4405 AWTEvent.MOUSE_EVENT_MASK |
4406 AWTEvent.MOUSE_MOTION_EVENT_MASK);
4407 return null;
4408 }
4409 }
4410 );
4411 }
4412
4413 private void stopListeningForOtherDrags() {
4414 //System.out.println("Removing AWTEventListener");
4415 java.security.AccessController.doPrivileged(
4416 new java.security.PrivilegedAction() {
4417 public Object run() {
4418 nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this);
4419 return null;
4420 }
4421 }
4422 );
4423 }
4424
4425 /*
4426 * (Implementation of AWTEventListener)
4427 * Listen for drag events posted in other hw components so we can
4428 * track enter/exit regardless of where a drag originated
4429 */
4430 public void eventDispatched(AWTEvent e) {
4431 boolean isForeignDrag = (e instanceof MouseEvent) &&
4432 !(e instanceof SunDropTargetEvent) &&
4433 (e.id == MouseEvent.MOUSE_DRAGGED) &&
4434 (e.getSource() != nativeContainer);
4435
4436 if (!isForeignDrag) {
4437 // only interested in drags from other hw components
4438 return;
4439 }
4440
4441 MouseEvent srcEvent = (MouseEvent)e;
4442 MouseEvent me;
4443
4444 synchronized (nativeContainer.getTreeLock()) {
4445 Component srcComponent = srcEvent.getComponent();
4446
4447 // component may have disappeared since drag event posted
4448 // (i.e. Swing hierarchical menus)
4449 if ( !srcComponent.isShowing() ) {
4450 return;
4451 }
4452
4453 // see 5083555
4454 // check if srcComponent is in any modal blocked window
4455 Component c = nativeContainer;
4456 while ((c != null) && !(c instanceof Window)) {
4457 c = c.getParent_NoClientCode();
4458 }
4459 if ((c == null) || ((Window)c).isModalBlocked()) {
4460 return;
4461 }
4462
4463 //
4464 // create an internal 'dragged-over' event indicating
4465 // we are being dragged over from another hw component
4466 //
4467 me = new MouseEvent(nativeContainer,
4468 LWD_MOUSE_DRAGGED_OVER,
4469 srcEvent.getWhen(),
4470 srcEvent.getModifiersEx() | srcEvent.getModifiers(),
4471 srcEvent.getX(),
4472 srcEvent.getY(),
4473 srcEvent.getXOnScreen(),
4474 srcEvent.getYOnScreen(),
4475 srcEvent.getClickCount(),
4476 srcEvent.isPopupTrigger(),
4477 srcEvent.getButton());
4478 ((AWTEvent)srcEvent).copyPrivateDataInto(me);
4479 // translate coordinates to this native container
4480 final Point ptSrcOrigin = srcComponent.getLocationOnScreen();
4481
4482 if (AppContext.getAppContext() != nativeContainer.appContext) {
4483 final MouseEvent mouseEvent = me;
4484 Runnable r = new Runnable() {
4485 public void run() {
4486 if (!nativeContainer.isShowing() ) {
4487 return;
4488 }
4489
4490 Point ptDstOrigin = nativeContainer.getLocationOnScreen();
4491 mouseEvent.translatePoint(ptSrcOrigin.x - ptDstOrigin.x,
4492 ptSrcOrigin.y - ptDstOrigin.y );
4493 Component targetOver =
4494 nativeContainer.getMouseEventTarget(mouseEvent.getX(),
4495 mouseEvent.getY(),
4496 Container.INCLUDE_SELF);
4497 trackMouseEnterExit(targetOver, mouseEvent);
4498 }
4499 };
4500 SunToolkit.executeOnEventHandlerThread(nativeContainer, r);
4501 return;
4502 } else {
4503 if (!nativeContainer.isShowing() ) {
4504 return;
4505 }
4506
4507 Point ptDstOrigin = nativeContainer.getLocationOnScreen();
4508 me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y );
4509 }
4510 }
4511 //System.out.println("Track event: " + me);
4512 // feed the 'dragged-over' event directly to the enter/exit
4513 // code (not a real event so don't pass it to dispatchEvent)
4514 Component targetOver =
4515 nativeContainer.getMouseEventTarget(me.getX(), me.getY(),
4516 Container.INCLUDE_SELF);
4517 trackMouseEnterExit(targetOver, me);
4518 }
4519
4520 /**
4521 * Sends a mouse event to the current mouse event recipient using
4522 * the given event (sent to the windowed host) as a srcEvent. If
4523 * the mouse event target is still in the component tree, the
4524 * coordinates of the event are translated to those of the target.
4525 * If the target has been removed, we don't bother to send the
4526 * message.
4527 */
4528 void retargetMouseEvent(Component target, int id, MouseEvent e) {
4529 if (target == null) {
4530 return; // mouse is over another hw component or target is disabled
4531 }
4532
4533 int x = e.getX(), y = e.getY();
4534 Component component;
4535
4536 for(component = target;
4537 component != null && component != nativeContainer;
4538 component = component.getParent()) {
4539 x -= component.x;
4540 y -= component.y;
4541 }
4542 MouseEvent retargeted;
4543 if (component != null) {
4544 if (e instanceof SunDropTargetEvent) {
4545 retargeted = new SunDropTargetEvent(target,
4546 id,
4547 x,
4548 y,
4549 ((SunDropTargetEvent)e).getDispatcher());
4550 } else if (id == MouseEvent.MOUSE_WHEEL) {
4551 retargeted = new MouseWheelEvent(target,
4552 id,
4553 e.getWhen(),
4554 e.getModifiersEx() | e.getModifiers(),
4555 x,
4556 y,
4557 e.getXOnScreen(),
4558 e.getYOnScreen(),
4559 e.getClickCount(),
4560 e.isPopupTrigger(),
4561 ((MouseWheelEvent)e).getScrollType(),
4562 ((MouseWheelEvent)e).getScrollAmount(),
4563 ((MouseWheelEvent)e).getWheelRotation(),
4564 ((MouseWheelEvent)e).getPreciseWheelRotation());
4565 }
4566 else {
4567 retargeted = new MouseEvent(target,
4568 id,
4569 e.getWhen(),
4570 e.getModifiersEx() | e.getModifiers(),
4571 x,
4572 y,
4573 e.getXOnScreen(),
4574 e.getYOnScreen(),
4575 e.getClickCount(),
4576 e.isPopupTrigger(),
4577 e.getButton());
4578 }
4579
4580 ((AWTEvent)e).copyPrivateDataInto(retargeted);
4581
4582 if (target == nativeContainer) {
4583 // avoid recursively calling LightweightDispatcher...
4584 ((Container)target).dispatchEventToSelf(retargeted);
4585 } else {
4586 assert AppContext.getAppContext() == target.appContext;
4587
4588 if (nativeContainer.modalComp != null) {
4589 if (((Container)nativeContainer.modalComp).isAncestorOf(target)) {
4590 target.dispatchEvent(retargeted);
4591 } else {
4592 e.consume();
4593 }
4594 } else {
4595 target.dispatchEvent(retargeted);
4596 }
4597 }
4598 }
4599 }
4600
4601 // --- member variables -------------------------------
4602
4603 /**
4604 * The windowed container that might be hosting events for
4605 * subcomponents.
4606 */
4607 private Container nativeContainer;
4608
4609 /**
4610 * This variable is not used, but kept for serialization compatibility
4611 */
4612 private Component focus;
4613
4614 /**
4615 * The current subcomponent being hosted by this windowed
4616 * component that has events being forwarded to it. If this
4617 * is null, there are currently no events being forwarded to
4618 * a subcomponent.
4619 */
4620 private transient Component mouseEventTarget;
4621
4622 /**
4623 * The last component entered
4624 */
4625 private transient Component targetLastEntered;
4626
4627 /**
4628 * Is the mouse over the native container
4629 */
4630 private transient boolean isMouseInNativeContainer = false;
4631
4632 /**
4633 * This variable is not used, but kept for serialization compatibility
4634 */
4635 private Cursor nativeCursor;
4636
4637 /**
4638 * The event mask for contained lightweight components. Lightweight
4639 * components need a windowed container to host window-related
4640 * events. This separate mask indicates events that have been
4641 * requested by contained lightweight components without effecting
4642 * the mask of the windowed component itself.
4643 */
4644 private long eventMask;
4645
4646 /**
4647 * The kind of events routed to lightweight components from windowed
4648 * hosts.
4649 */
4650 private static final long PROXY_EVENT_MASK =
4651 AWTEvent.FOCUS_EVENT_MASK |
4652 AWTEvent.KEY_EVENT_MASK |
4653 AWTEvent.MOUSE_EVENT_MASK |
4654 AWTEvent.MOUSE_MOTION_EVENT_MASK |
4655 AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4656
4657 private static final long MOUSE_MASK =
4658 AWTEvent.MOUSE_EVENT_MASK |
4659 AWTEvent.MOUSE_MOTION_EVENT_MASK |
4660 AWTEvent.MOUSE_WHEEL_EVENT_MASK;
4661 }