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