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