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