History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/Container.java (1 of 18352 files). Show all

Unified · Split

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