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