1 /*
   2  * Copyright (c) 2000, 2020, 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.util.List;
  28 import java.util.ArrayList;
  29 import sun.util.logging.PlatformLogger;
  30 
  31 /**
  32  * A FocusTraversalPolicy that determines traversal order based on the order
  33  * of child Components in a Container. From a particular focus cycle root, the
  34  * policy makes a pre-order traversal of the Component hierarchy, and traverses
  35  * a Container's children according to the ordering of the array returned by
  36  * {@code Container.getComponents()}. Portions of the hierarchy that are
  37  * not visible and displayable will not be searched.
  38  * <p>
  39  * By default, ContainerOrderFocusTraversalPolicy implicitly transfers focus
  40  * down-cycle. That is, during normal forward focus traversal, the Component
  41  * traversed after a focus cycle root will be the focus-cycle-root's default
  42  * Component to focus. This behavior can be disabled using the
  43  * {@code setImplicitDownCycleTraversal} method.
  44  * <p>
  45  * By default, methods of this class will return a Component only if it is
  46  * visible, displayable, enabled, and focusable. Subclasses can modify this
  47  * behavior by overriding the {@code accept} method.
  48  * <p>
  49  * This policy takes into account <a
  50  * href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal
  51  * policy providers</a>.  When searching for first/last/next/previous Component,
  52  * if a focus traversal policy provider is encountered, its focus traversal
  53  * policy is used to perform the search operation.
  54  *
  55  * @author David Mendenhall
  56  *
  57  * @see Container#getComponents
  58  * @since 1.4
  59  */
  60 public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy
  61     implements java.io.Serializable
  62 {
  63     private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.ContainerOrderFocusTraversalPolicy");
  64 
  65     private final int FORWARD_TRAVERSAL = 0;
  66     private final int BACKWARD_TRAVERSAL = 1;
  67 
  68     /*
  69      * JDK 1.4 serialVersionUID
  70      */
  71     private static final long serialVersionUID = 486933713763926351L;
  72 
  73     private boolean implicitDownCycleTraversal = true;
  74 
  75     /**
  76      * Used by getComponentAfter and getComponentBefore for efficiency. In
  77      * order to maintain compliance with the specification of
  78      * FocusTraversalPolicy, if traversal wraps, we should invoke
  79      * getFirstComponent or getLastComponent. These methods may be overriden in
  80      * subclasses to behave in a non-generic way. However, in the generic case,
  81      * these methods will simply return the first or last Components of the
  82      * sorted list, respectively. Since getComponentAfter and
  83      * getComponentBefore have already built the list before determining
  84      * that they need to invoke getFirstComponent or getLastComponent, the
  85      * list should be reused if possible.
  86      */
  87     private transient Container cachedRoot;
  88     private transient List<Component> cachedCycle;
  89 
  90     /**
  91      * Constructs a {@code ContainerOrderFocusTraversalPolicy}.
  92      */
  93     public ContainerOrderFocusTraversalPolicy() {}
  94 
  95     /*
  96      * We suppose to use getFocusTraversalCycle & getComponentIndex methods in order
  97      * to divide the policy into two parts:
  98      * 1) Making the focus traversal cycle.
  99      * 2) Traversing the cycle.
 100      * The 1st point assumes producing a list of components representing the focus
 101      * traversal cycle. The two methods mentioned above should implement this logic.
 102      * The 2nd point assumes implementing the common concepts of operating on the
 103      * cycle: traversing back and forth, retrieving the initial/default/first/last
 104      * component. These concepts are described in the AWT Focus Spec and they are
 105      * applied to the FocusTraversalPolicy in general.
 106      * Thus, a descendant of this policy may wish to not reimplement the logic of
 107      * the 2nd point but just override the implementation of the 1st one.
 108      * A striking example of such a descendant is the javax.swing.SortingFocusTraversalPolicy.
 109      */
 110     /*protected*/ private List<Component> getFocusTraversalCycle(Container aContainer) {
 111         List<Component> cycle = new ArrayList<Component>();
 112         enumerateCycle(aContainer, cycle);
 113         return cycle;
 114     }
 115     /*protected*/ private int getComponentIndex(List<Component> cycle, Component aComponent) {
 116         return cycle.indexOf(aComponent);
 117     }
 118 
 119     private void enumerateCycle(Container container, List<Component> cycle) {
 120         if (!(container.isVisible() && container.isDisplayable())) {
 121             return;
 122         }
 123 
 124         cycle.add(container);
 125 
 126         Component[] components = container.getComponents();
 127         for (int i = 0; i < components.length; i++) {
 128             Component comp = components[i];
 129             if (comp instanceof Container) {
 130                 Container cont = (Container)comp;
 131 
 132                 if (!cont.isFocusCycleRoot() && !cont.isFocusTraversalPolicyProvider()) {
 133                     enumerateCycle(cont, cycle);
 134                     continue;
 135                 }
 136             }
 137             cycle.add(comp);
 138         }
 139     }
 140 
 141     private Container getTopmostProvider(Container focusCycleRoot, Component aComponent) {
 142         Container aCont = aComponent.getParent();
 143         Container ftp = null;
 144         while (aCont  != focusCycleRoot && aCont != null) {
 145             if (aCont.isFocusTraversalPolicyProvider()) {
 146                 ftp = aCont;
 147             }
 148             aCont = aCont.getParent();
 149         }
 150         if (aCont == null) {
 151             return null;
 152         }
 153         return ftp;
 154     }
 155 
 156     /*
 157      * Checks if a new focus cycle takes place and returns a Component to traverse focus to.
 158      * @param comp a possible focus cycle root or policy provider
 159      * @param traversalDirection the direction of the traversal
 160      * @return a Component to traverse focus to if {@code comp} is a root or provider
 161      *         and implicit down-cycle is set, otherwise {@code null}
 162      */
 163     private Component getComponentDownCycle(Component comp, int traversalDirection) {
 164         Component retComp = null;
 165 
 166         if (comp instanceof Container) {
 167             Container cont = (Container)comp;
 168 
 169             if (cont.isFocusCycleRoot()) {
 170                 if (getImplicitDownCycleTraversal()) {
 171                     retComp = cont.getFocusTraversalPolicy().getDefaultComponent(cont);
 172 
 173                     if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 174                         log.fine("### Transferred focus down-cycle to " + retComp +
 175                                  " in the focus cycle root " + cont);
 176                     }
 177                 } else {
 178                     return null;
 179                 }
 180             } else if (cont.isFocusTraversalPolicyProvider()) {
 181                 retComp = (traversalDirection == FORWARD_TRAVERSAL ?
 182                            cont.getFocusTraversalPolicy().getDefaultComponent(cont) :
 183                            cont.getFocusTraversalPolicy().getLastComponent(cont));
 184 
 185                 if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 186                     log.fine("### Transferred focus to " + retComp + " in the FTP provider " + cont);
 187                 }
 188             }
 189         }
 190         return retComp;
 191     }
 192 
 193     /**
 194      * Returns the Component that should receive the focus after aComponent.
 195      * aContainer must be a focus cycle root of aComponent or a focus traversal policy provider.
 196      * <p>
 197      * By default, ContainerOrderFocusTraversalPolicy implicitly transfers
 198      * focus down-cycle. That is, during normal forward focus traversal, the
 199      * Component traversed after a focus cycle root will be the focus-cycle-
 200      * root's default Component to focus. This behavior can be disabled using
 201      * the {@code setImplicitDownCycleTraversal} method.
 202      * <p>
 203      * If aContainer is <a href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
 204      * traversal policy provider</a>, the focus is always transferred down-cycle.
 205      *
 206      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
 207      * @param aComponent a (possibly indirect) child of aContainer, or
 208      *        aContainer itself
 209      * @return the Component that should receive the focus after aComponent, or
 210      *         null if no suitable Component can be found
 211      * @throws IllegalArgumentException if aContainer is not a focus cycle
 212      *         root of aComponent or focus traversal policy provider, or if either aContainer or
 213      *         aComponent is null
 214      */
 215     public Component getComponentAfter(Container aContainer, Component aComponent) {
 216         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 217             log.fine("### Searching in " + aContainer + " for component after " + aComponent);
 218         }
 219 
 220         if (aContainer == null || aComponent == null) {
 221             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 222         }
 223         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 224             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 225 
 226         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 227             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 228         }
 229 
 230         synchronized(aContainer.getTreeLock()) {
 231 
 232             if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
 233                 return null;
 234             }
 235 
 236             // Before all the checks below we first see if it's an FTP provider or a focus cycle root.
 237             // If it's the case just go down cycle (if it's set to "implicit").
 238             Component comp = getComponentDownCycle(aComponent, FORWARD_TRAVERSAL);
 239             // Check if aComponent is focus-cycle-root's default Component, i.e.
 240             // focus cycle root & focus-cycle-root's default Component is same.
 241             if (comp != null && comp != aComponent) {
 242                 return comp;
 243             }
 244 
 245             // See if the component is inside of policy provider.
 246             Container provider = getTopmostProvider(aContainer, aComponent);
 247             if (provider != null) {
 248                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 249                     log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 250                 }
 251 
 252                 // FTP knows how to find component after the given. We don't.
 253                 FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 254                 Component afterComp = policy.getComponentAfter(provider, aComponent);
 255 
 256                 // Null result means that we overstepped the limit of the FTP's cycle.
 257                 // In that case we must quit the cycle, otherwise return the component found.
 258                 if (afterComp != null) {
 259                     if (log.isLoggable(PlatformLogger.Level.FINE)) {
 260                         log.fine("### FTP returned " + afterComp);
 261                     }
 262                     return afterComp;
 263                 }
 264                 aComponent = provider;
 265             }
 266 
 267             List<Component> cycle = getFocusTraversalCycle(aContainer);
 268 
 269             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 270                 log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 271             }
 272 
 273             int index = getComponentIndex(cycle, aComponent);
 274 
 275             if (index < 0) {
 276                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 277                     log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 278                 }
 279                 return getFirstComponent(aContainer);
 280             }
 281 
 282             for (index++; index < cycle.size(); index++) {
 283                 comp = cycle.get(index);
 284                 if (accept(comp)) {
 285                     return comp;
 286                 } else if ((comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null) {
 287                     return comp;
 288                 }
 289             }
 290 
 291             if (aContainer.isFocusCycleRoot()) {
 292                 this.cachedRoot = aContainer;
 293                 this.cachedCycle = cycle;
 294 
 295                 comp = getFirstComponent(aContainer);
 296 
 297                 this.cachedRoot = null;
 298                 this.cachedCycle = null;
 299 
 300                 return comp;
 301             }
 302         }
 303         return null;
 304     }
 305 
 306     /**
 307      * Returns the Component that should receive the focus before aComponent.
 308      * aContainer must be a focus cycle root of aComponent or a <a
 309      * href="doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal policy
 310      * provider</a>.
 311      *
 312      * @param aContainer a focus cycle root of aComponent or focus traversal policy provider
 313      * @param aComponent a (possibly indirect) child of aContainer, or
 314      *        aContainer itself
 315      * @return the Component that should receive the focus before aComponent,
 316      *         or null if no suitable Component can be found
 317      * @throws IllegalArgumentException if aContainer is not a focus cycle
 318      *         root of aComponent or focus traversal policy provider, or if either aContainer or
 319      *         aComponent is null
 320      */
 321     public Component getComponentBefore(Container aContainer, Component aComponent) {
 322         if (aContainer == null || aComponent == null) {
 323             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 324         }
 325         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 326             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 327 
 328         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 329             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 330         }
 331 
 332         synchronized(aContainer.getTreeLock()) {
 333 
 334             if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
 335                 return null;
 336             }
 337 
 338             // See if the component is inside of policy provider.
 339             Container provider = getTopmostProvider(aContainer, aComponent);
 340             if (provider != null) {
 341                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 342                     log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 343                 }
 344 
 345                 // FTP knows how to find component after the given. We don't.
 346                 FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 347                 Component beforeComp = policy.getComponentBefore(provider, aComponent);
 348 
 349                 // Null result means that we overstepped the limit of the FTP's cycle.
 350                 // In that case we must quit the cycle, otherwise return the component found.
 351                 if (beforeComp != null) {
 352                     if (log.isLoggable(PlatformLogger.Level.FINE)) {
 353                         log.fine("### FTP returned " + beforeComp);
 354                     }
 355                     return beforeComp;
 356                 }
 357                 aComponent = provider;
 358 
 359                 // If the provider is traversable it's returned.
 360                 if (accept(aComponent)) {
 361                     return aComponent;
 362                 }
 363             }
 364 
 365             List<Component> cycle = getFocusTraversalCycle(aContainer);
 366 
 367             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 368                 log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 369             }
 370 
 371             int index = getComponentIndex(cycle, aComponent);
 372 
 373             if (index < 0) {
 374                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 375                     log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 376                 }
 377                 return getLastComponent(aContainer);
 378             }
 379 
 380             Component comp = null;
 381             Component tryComp = null;
 382 
 383             for (index--; index>=0; index--) {
 384                 comp = cycle.get(index);
 385                 if (comp != aContainer && (tryComp = getComponentDownCycle(comp, BACKWARD_TRAVERSAL)) != null) {
 386                     return tryComp;
 387                 } else if (accept(comp)) {
 388                     return comp;
 389                 }
 390             }
 391 
 392             if (aContainer.isFocusCycleRoot()) {
 393                 this.cachedRoot = aContainer;
 394                 this.cachedCycle = cycle;
 395 
 396                 comp = getLastComponent(aContainer);
 397 
 398                 this.cachedRoot = null;
 399                 this.cachedCycle = null;
 400 
 401                 return comp;
 402             }
 403         }
 404         return null;
 405     }
 406 
 407     /**
 408      * Returns the first Component in the traversal cycle. This method is used
 409      * to determine the next Component to focus when traversal wraps in the
 410      * forward direction.
 411      *
 412      * @param aContainer the focus cycle root or focus traversal policy provider whose first
 413      *        Component is to be returned
 414      * @return the first Component in the traversal cycle of aContainer,
 415      *         or null if no suitable Component can be found
 416      * @throws IllegalArgumentException if aContainer is null
 417      */
 418     public Component getFirstComponent(Container aContainer) {
 419         List<Component> cycle;
 420 
 421         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 422             log.fine("### Getting first component in " + aContainer);
 423         }
 424         if (aContainer == null) {
 425             throw new IllegalArgumentException("aContainer cannot be null");
 426 
 427         }
 428 
 429         synchronized(aContainer.getTreeLock()) {
 430 
 431             if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
 432                 return null;
 433             }
 434 
 435             if (this.cachedRoot == aContainer) {
 436                 cycle = this.cachedCycle;
 437             } else {
 438                 cycle = getFocusTraversalCycle(aContainer);
 439             }
 440 
 441             if (cycle.size() == 0) {
 442                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 443                     log.fine("### Cycle is empty");
 444                 }
 445                 return null;
 446             }
 447             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 448                 log.fine("### Cycle is " + cycle);
 449             }
 450 
 451             for (Component comp : cycle) {
 452                 if (accept(comp)) {
 453                     return comp;
 454                 } else if (comp != aContainer &&
 455                            (comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null)
 456                 {
 457                     return comp;
 458                 }
 459             }
 460         }
 461         return null;
 462     }
 463 
 464     /**
 465      * Returns the last Component in the traversal cycle. This method is used
 466      * to determine the next Component to focus when traversal wraps in the
 467      * reverse direction.
 468      *
 469      * @param aContainer the focus cycle root or focus traversal policy provider whose last
 470      *        Component is to be returned
 471      * @return the last Component in the traversal cycle of aContainer,
 472      *         or null if no suitable Component can be found
 473      * @throws IllegalArgumentException if aContainer is null
 474      */
 475     public Component getLastComponent(Container aContainer) {
 476         List<Component> cycle;
 477         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 478             log.fine("### Getting last component in " + aContainer);
 479         }
 480 
 481         if (aContainer == null) {
 482             throw new IllegalArgumentException("aContainer cannot be null");
 483         }
 484 
 485         synchronized(aContainer.getTreeLock()) {
 486 
 487             if (!(aContainer.isVisible() && aContainer.isDisplayable())) {
 488                 return null;
 489             }
 490 
 491             if (this.cachedRoot == aContainer) {
 492                 cycle = this.cachedCycle;
 493             } else {
 494                 cycle = getFocusTraversalCycle(aContainer);
 495             }
 496 
 497             if (cycle.size() == 0) {
 498                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 499                     log.fine("### Cycle is empty");
 500                 }
 501                 return null;
 502             }
 503             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 504                 log.fine("### Cycle is " + cycle);
 505             }
 506 
 507             for (int i= cycle.size() - 1; i >= 0; i--) {
 508                 Component comp = cycle.get(i);
 509                 if (accept(comp)) {
 510                     return comp;
 511                 } else if (comp instanceof Container && comp != aContainer) {
 512                     Container cont = (Container)comp;
 513                     if (cont.isFocusTraversalPolicyProvider()) {
 514                         Component retComp = cont.getFocusTraversalPolicy().getLastComponent(cont);
 515                         if (retComp != null) {
 516                             return retComp;
 517                         }
 518                     }
 519                 }
 520             }
 521         }
 522         return null;
 523     }
 524 
 525     /**
 526      * Returns the default Component to focus. This Component will be the first
 527      * to receive focus when traversing down into a new focus traversal cycle
 528      * rooted at aContainer. The default implementation of this method
 529      * returns the same Component as {@code getFirstComponent}.
 530      *
 531      * @param aContainer the focus cycle root or focus traversal policy provider whose default
 532      *        Component is to be returned
 533      * @return the default Component in the traversal cycle of aContainer,
 534      *         or null if no suitable Component can be found
 535      * @see #getFirstComponent
 536      * @throws IllegalArgumentException if aContainer is null
 537      */
 538     public Component getDefaultComponent(Container aContainer) {
 539         return getFirstComponent(aContainer);
 540     }
 541 
 542     /**
 543      * Sets whether this ContainerOrderFocusTraversalPolicy transfers focus
 544      * down-cycle implicitly. If {@code true}, during normal forward focus
 545      * traversal, the Component traversed after a focus cycle root will be the
 546      * focus-cycle-root's default Component to focus. If {@code false},
 547      * the next Component in the focus traversal cycle rooted at the specified
 548      * focus cycle root will be traversed instead. The default value for this
 549      * property is {@code true}.
 550      *
 551      * @param implicitDownCycleTraversal whether this
 552      *        ContainerOrderFocusTraversalPolicy transfers focus down-cycle
 553      *        implicitly
 554      * @see #getImplicitDownCycleTraversal
 555      * @see #getFirstComponent
 556      */
 557     public void setImplicitDownCycleTraversal(boolean implicitDownCycleTraversal) {
 558         this.implicitDownCycleTraversal = implicitDownCycleTraversal;
 559     }
 560 
 561     /**
 562      * Returns whether this ContainerOrderFocusTraversalPolicy transfers focus
 563      * down-cycle implicitly. If {@code true}, during normal forward focus
 564      * traversal, the Component traversed after a focus cycle root will be the
 565      * focus-cycle-root's default Component to focus. If {@code false},
 566      * the next Component in the focus traversal cycle rooted at the specified
 567      * focus cycle root will be traversed instead.
 568      *
 569      * @return whether this ContainerOrderFocusTraversalPolicy transfers focus
 570      *         down-cycle implicitly
 571      * @see #setImplicitDownCycleTraversal
 572      * @see #getFirstComponent
 573      */
 574     public boolean getImplicitDownCycleTraversal() {
 575         return implicitDownCycleTraversal;
 576     }
 577 
 578     /**
 579      * Determines whether a Component is an acceptable choice as the new
 580      * focus owner. By default, this method will accept a Component if and
 581      * only if it is visible, displayable, enabled, and focusable.
 582      *
 583      * @param aComponent the Component whose fitness as a focus owner is to
 584      *        be tested
 585      * @return {@code true} if aComponent is visible, displayable,
 586      *         enabled, and focusable; {@code false} otherwise
 587      */
 588     protected boolean accept(Component aComponent) {
 589         if (!aComponent.canBeFocusOwner()) {
 590             return false;
 591         }
 592 
 593         // Verify that the Component is recursively enabled. Disabling a
 594         // heavyweight Container disables its children, whereas disabling
 595         // a lightweight Container does not.
 596         if (!(aComponent instanceof Window)) {
 597             for (Container enableTest = aComponent.getParent();
 598                  enableTest != null;
 599                  enableTest = enableTest.getParent())
 600             {
 601                 if (!(enableTest.isEnabled() || enableTest.isLightweight())) {
 602                     return false;
 603                 }
 604                 if (enableTest instanceof Window) {
 605                     break;
 606                 }
 607             }
 608         }
 609 
 610         return true;
 611     }
 612 }