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