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