1 /*
   2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 
  27 import java.awt.Component;
  28 import java.awt.Container;
  29 import java.awt.Window;
  30 import java.util.*;
  31 import java.awt.FocusTraversalPolicy;
  32 import sun.util.logging.PlatformLogger;
  33 import java.lang.reflect.InvocationTargetException;
  34 import java.lang.reflect.Method;
  35 import sun.security.action.GetPropertyAction;
  36 import java.security.AccessController;
  37 import java.security.PrivilegedAction;
  38 
  39 /**
  40  * A FocusTraversalPolicy that determines traversal order by sorting the
  41  * Components of a focus traversal cycle based on a given Comparator. Portions
  42  * of the Component hierarchy that are not visible and displayable will not be
  43  * included.
  44  * <p>
  45  * By default, SortingFocusTraversalPolicy implicitly transfers focus down-
  46  * cycle. That is, during normal focus traversal, the Component
  47  * traversed after a focus cycle root will be the focus-cycle-root's default
  48  * Component to focus. This behavior can be disabled using the
  49  * <code>setImplicitDownCycleTraversal</code> method.
  50  * <p>
  51  * By default, methods of this class with return a Component only if it is
  52  * visible, displayable, enabled, and focusable. Subclasses can modify this
  53  * behavior by overriding the <code>accept</code> method.
  54  * <p>
  55  * This policy takes into account <a
  56  * href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus traversal
  57  * policy providers</a>.  When searching for first/last/next/previous Component,
  58  * if a focus traversal policy provider is encountered, its focus traversal
  59  * policy is used to perform the search operation.
  60  *
  61  * @author David Mendenhall
  62  *
  63  * @see java.util.Comparator
  64  * @since 1.4
  65  */
  66 public class SortingFocusTraversalPolicy
  67     extends InternalFrameFocusTraversalPolicy
  68 {
  69     private Comparator<? super Component> comparator;
  70     private boolean implicitDownCycleTraversal = true;
  71 
  72     private PlatformLogger log = PlatformLogger.getLogger("javax.swing.SortingFocusTraversalPolicy");
  73 
  74     /**
  75      * Used by getComponentAfter and getComponentBefore for efficiency. In
  76      * order to maintain compliance with the specification of
  77      * FocusTraversalPolicy, if traversal wraps, we should invoke
  78      * getFirstComponent or getLastComponent. These methods may be overriden in
  79      * subclasses to behave in a non-generic way. However, in the generic case,
  80      * these methods will simply return the first or last Components of the
  81      * sorted list, respectively. Since getComponentAfter and
  82      * getComponentBefore have already built the sorted list before determining
  83      * that they need to invoke getFirstComponent or getLastComponent, the
  84      * sorted list should be reused if possible.
  85      */
  86     transient private Container cachedRoot;
  87     transient private List<Component> cachedCycle;
  88 
  89     // Delegate our fitness test to ContainerOrder so that we only have to
  90     // code the algorithm once.
  91     private static final SwingContainerOrderFocusTraversalPolicy
  92         fitnessTestPolicy = new SwingContainerOrderFocusTraversalPolicy();
  93 
  94     final private int FORWARD_TRAVERSAL = 0;
  95     final private int BACKWARD_TRAVERSAL = 1;
  96 
  97     /*
  98      * When true (by default), the legacy merge-sort algo is used to sort an FTP cycle.
  99      * When false, the default (tim-sort) algo is used, which may lead to an exception.
 100      * See: JDK-8048887
 101      */
 102     private static final boolean legacySortingFTPEnabled;
 103     private static final Method legacyMergeSortMethod;
 104 
 105     static {
 106         legacySortingFTPEnabled = "true".equals(AccessController.doPrivileged(
 107             new GetPropertyAction("swing.legacySortingFTPEnabled", "true")));
 108         legacyMergeSortMethod = legacySortingFTPEnabled ?
 109             AccessController.doPrivileged(new PrivilegedAction<Method>() {
 110                 public Method run() {
 111                     try {
 112                         Method m = java.util.Arrays.class.getDeclaredMethod("legacyMergeSort",
 113                                                                             new Class<?>[]{Object[].class,
 114                                                                                     Comparator.class});
 115                         m.setAccessible(true);
 116                         return m;
 117                     } catch (NoSuchMethodException e) {
 118                         // using default sorting algo
 119                         return null;
 120                     }
 121                 }
 122             }) :
 123             null;
 124     }
 125 
 126     /**
 127      * Constructs a SortingFocusTraversalPolicy without a Comparator.
 128      * Subclasses must set the Comparator using <code>setComparator</code>
 129      * before installing this FocusTraversalPolicy on a focus cycle root or
 130      * KeyboardFocusManager.
 131      */
 132     protected SortingFocusTraversalPolicy() {
 133     }
 134 
 135     /**
 136      * Constructs a SortingFocusTraversalPolicy with the specified Comparator.
 137      *
 138      * @param comparator the {@code Comparator} to sort by
 139      */
 140     public SortingFocusTraversalPolicy(Comparator<? super Component> comparator) {
 141         this.comparator = comparator;
 142     }
 143 
 144     private List<Component> getFocusTraversalCycle(Container aContainer) {
 145         List<Component> cycle = new ArrayList<Component>();
 146         enumerateAndSortCycle(aContainer, cycle);
 147         return cycle;
 148     }
 149     private int getComponentIndex(List<Component> cycle, Component aComponent) {
 150         int index;
 151         try {
 152             index = Collections.binarySearch(cycle, aComponent, comparator);
 153         } catch (ClassCastException e) {
 154             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 155                 log.fine("### During the binary search for " + aComponent + " the exception occurred: ", e);
 156             }
 157             return -1;
 158         }
 159         if (index < 0) {
 160             // Fix for 5070991.
 161             // A workaround for a transitivity problem caused by ROW_TOLERANCE,
 162             // because of that the component may be missed in the binary search.
 163             // Try to search it again directly.
 164             index = cycle.indexOf(aComponent);
 165         }
 166         return index;
 167     }
 168 
 169     private void enumerateAndSortCycle(Container focusCycleRoot, List<Component> cycle) {
 170         if (focusCycleRoot.isShowing()) {
 171             enumerateCycle(focusCycleRoot, cycle);
 172             if (!legacySortingFTPEnabled ||
 173                 !legacySort(cycle, comparator))
 174             {
 175                 Collections.sort(cycle, comparator);
 176             }
 177         }
 178     }
 179 
 180     private boolean legacySort(List<Component> l, Comparator<? super Component> c) {
 181         if (legacyMergeSortMethod == null)
 182             return false;
 183 
 184         Object[] a = l.toArray();
 185         try {
 186             legacyMergeSortMethod.invoke(null, a, c);
 187         } catch (IllegalAccessException | InvocationTargetException e) {
 188             return false;
 189         }
 190         ListIterator<Component> i = l.listIterator();
 191         for (Object e : a) {
 192             i.next();
 193             i.set((Component)e);
 194         }
 195         return true;
 196     }
 197 
 198     @SuppressWarnings("deprecation")
 199     private void enumerateCycle(Container container, List<Component> cycle) {
 200         if (!(container.isVisible() && container.isDisplayable())) {
 201             return;
 202         }
 203 
 204         cycle.add(container);
 205 
 206         Component[] components = container.getComponents();
 207         for (Component comp : components) {
 208             if (comp instanceof Container) {
 209                 Container cont = (Container)comp;
 210 
 211                 if (!cont.isFocusCycleRoot() &&
 212                     !cont.isFocusTraversalPolicyProvider() &&
 213                     !((cont instanceof JComponent) && ((JComponent)cont).isManagingFocus()))
 214                 {
 215                     enumerateCycle(cont, cycle);
 216                     continue;
 217                 }
 218             }
 219             cycle.add(comp);
 220         }
 221     }
 222 
 223     Container getTopmostProvider(Container focusCycleRoot, Component aComponent) {
 224         Container aCont = aComponent.getParent();
 225         Container ftp = null;
 226         while (aCont  != focusCycleRoot && aCont != null) {
 227             if (aCont.isFocusTraversalPolicyProvider()) {
 228                 ftp = aCont;
 229             }
 230             aCont = aCont.getParent();
 231         }
 232         if (aCont == null) {
 233             return null;
 234         }
 235         return ftp;
 236     }
 237 
 238     /*
 239      * Checks if a new focus cycle takes place and returns a Component to traverse focus to.
 240      * @param comp a possible focus cycle root or policy provider
 241      * @param traversalDirection the direction of the traversal
 242      * @return a Component to traverse focus to if {@code comp} is a root or provider
 243      *         and implicit down-cycle is set, otherwise {@code null}
 244      */
 245     private Component getComponentDownCycle(Component comp, int traversalDirection) {
 246         Component retComp = null;
 247 
 248         if (comp instanceof Container) {
 249             Container cont = (Container)comp;
 250 
 251             if (cont.isFocusCycleRoot()) {
 252                 if (getImplicitDownCycleTraversal()) {
 253                     retComp = cont.getFocusTraversalPolicy().getDefaultComponent(cont);
 254 
 255                     if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 256                         log.fine("### Transfered focus down-cycle to " + retComp +
 257                                  " in the focus cycle root " + cont);
 258                     }
 259                 } else {
 260                     return null;
 261                 }
 262             } else if (cont.isFocusTraversalPolicyProvider()) {
 263                 retComp = (traversalDirection == FORWARD_TRAVERSAL ?
 264                            cont.getFocusTraversalPolicy().getDefaultComponent(cont) :
 265                            cont.getFocusTraversalPolicy().getLastComponent(cont));
 266 
 267                 if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 268                     log.fine("### Transfered focus to " + retComp + " in the FTP provider " + cont);
 269                 }
 270             }
 271         }
 272         return retComp;
 273     }
 274 
 275     /**
 276      * Returns the Component that should receive the focus after aComponent.
 277      * aContainer must be a focus cycle root of aComponent or a focus traversal policy provider.
 278      * <p>
 279      * By default, SortingFocusTraversalPolicy implicitly transfers focus down-
 280      * cycle. That is, during normal focus traversal, the Component
 281      * traversed after a focus cycle root will be the focus-cycle-root's
 282      * default Component to focus. This behavior can be disabled using the
 283      * <code>setImplicitDownCycleTraversal</code> method.
 284      * <p>
 285      * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
 286      * traversal policy provider</a>, the focus is always transferred down-cycle.
 287      *
 288      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
 289      * @param aComponent a (possibly indirect) child of aContainer, or
 290      *        aContainer itself
 291      * @return the Component that should receive the focus after aComponent, or
 292      *         null if no suitable Component can be found
 293      * @throws IllegalArgumentException if aContainer is not a focus cycle
 294      *         root of aComponent or a focus traversal policy provider, or if either aContainer or
 295      *         aComponent is null
 296      */
 297     public Component getComponentAfter(Container aContainer, Component aComponent) {
 298         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 299             log.fine("### Searching in " + aContainer + " for component after " + aComponent);
 300         }
 301 
 302         if (aContainer == null || aComponent == null) {
 303             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 304         }
 305         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 306             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 307 
 308         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 309             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 310         }
 311 
 312         // Before all the ckecks below we first see if it's an FTP provider or a focus cycle root.
 313         // If it's the case just go down cycle (if it's set to "implicit").
 314         Component comp = getComponentDownCycle(aComponent, FORWARD_TRAVERSAL);
 315         if (comp != null) {
 316             return comp;
 317         }
 318 
 319         // See if the component is inside of policy provider.
 320         Container provider = getTopmostProvider(aContainer, aComponent);
 321         if (provider != null) {
 322             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 323                 log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 324             }
 325 
 326             // FTP knows how to find component after the given. We don't.
 327             FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 328             Component afterComp = policy.getComponentAfter(provider, aComponent);
 329 
 330             // Null result means that we overstepped the limit of the FTP's cycle.
 331             // In that case we must quit the cycle, otherwise return the component found.
 332             if (afterComp != null) {
 333                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 334                     log.fine("### FTP returned " + afterComp);
 335                 }
 336                 return afterComp;
 337             }
 338             aComponent = provider;
 339         }
 340 
 341         List<Component> cycle = getFocusTraversalCycle(aContainer);
 342 
 343         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 344             log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 345         }
 346 
 347         int index = getComponentIndex(cycle, aComponent);
 348 
 349         if (index < 0) {
 350             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 351                 log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 352             }
 353             return getFirstComponent(aContainer);
 354         }
 355 
 356         for (index++; index < cycle.size(); index++) {
 357             comp = cycle.get(index);
 358             if (accept(comp)) {
 359                 return comp;
 360             } else if ((comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null) {
 361                 return comp;
 362             }
 363         }
 364 
 365         if (aContainer.isFocusCycleRoot()) {
 366             this.cachedRoot = aContainer;
 367             this.cachedCycle = cycle;
 368 
 369             comp = getFirstComponent(aContainer);
 370 
 371             this.cachedRoot = null;
 372             this.cachedCycle = null;
 373 
 374             return comp;
 375         }
 376         return null;
 377     }
 378 
 379     /**
 380      * Returns the Component that should receive the focus before aComponent.
 381      * aContainer must be a focus cycle root of aComponent or a focus traversal policy provider.
 382      * <p>
 383      * By default, SortingFocusTraversalPolicy implicitly transfers focus down-
 384      * cycle. That is, during normal focus traversal, the Component
 385      * traversed after a focus cycle root will be the focus-cycle-root's
 386      * default Component to focus. This behavior can be disabled using the
 387      * <code>setImplicitDownCycleTraversal</code> method.
 388      * <p>
 389      * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
 390      * traversal policy provider</a>, the focus is always transferred down-cycle.
 391      *
 392      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
 393      * @param aComponent a (possibly indirect) child of aContainer, or
 394      *        aContainer itself
 395      * @return the Component that should receive the focus before aComponent,
 396      *         or null if no suitable Component can be found
 397      * @throws IllegalArgumentException if aContainer is not a focus cycle
 398      *         root of aComponent or a focus traversal policy provider, or if either aContainer or
 399      *         aComponent is null
 400      */
 401     public Component getComponentBefore(Container aContainer, Component aComponent) {
 402         if (aContainer == null || aComponent == null) {
 403             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 404         }
 405         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 406             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 407 
 408         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 409             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 410         }
 411 
 412         // See if the component is inside of policy provider.
 413         Container provider = getTopmostProvider(aContainer, aComponent);
 414         if (provider != null) {
 415             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 416                 log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 417             }
 418 
 419             // FTP knows how to find component after the given. We don't.
 420             FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 421             Component beforeComp = policy.getComponentBefore(provider, aComponent);
 422 
 423             // Null result means that we overstepped the limit of the FTP's cycle.
 424             // In that case we must quit the cycle, otherwise return the component found.
 425             if (beforeComp != null) {
 426                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 427                     log.fine("### FTP returned " + beforeComp);
 428                 }
 429                 return beforeComp;
 430             }
 431             aComponent = provider;
 432 
 433             // If the provider is traversable it's returned.
 434             if (accept(aComponent)) {
 435                 return aComponent;
 436             }
 437         }
 438 
 439         List<Component> cycle = getFocusTraversalCycle(aContainer);
 440 
 441         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 442             log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 443         }
 444 
 445         int index = getComponentIndex(cycle, aComponent);
 446 
 447         if (index < 0) {
 448             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 449                 log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 450             }
 451             return getLastComponent(aContainer);
 452         }
 453 
 454         Component comp;
 455         Component tryComp;
 456 
 457         for (index--; index>=0; index--) {
 458             comp = cycle.get(index);
 459             if (comp != aContainer && (tryComp = getComponentDownCycle(comp, BACKWARD_TRAVERSAL)) != null) {
 460                 return tryComp;
 461             } else if (accept(comp)) {
 462                 return comp;
 463             }
 464         }
 465 
 466         if (aContainer.isFocusCycleRoot()) {
 467             this.cachedRoot = aContainer;
 468             this.cachedCycle = cycle;
 469 
 470             comp = getLastComponent(aContainer);
 471 
 472             this.cachedRoot = null;
 473             this.cachedCycle = null;
 474 
 475             return comp;
 476         }
 477         return null;
 478     }
 479 
 480     /**
 481      * Returns the first Component in the traversal cycle. This method is used
 482      * to determine the next Component to focus when traversal wraps in the
 483      * forward direction.
 484      *
 485      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 486      *        first Component is to be returned
 487      * @return the first Component in the traversal cycle of aContainer,
 488      *         or null if no suitable Component can be found
 489      * @throws IllegalArgumentException if aContainer is null
 490      */
 491     public Component getFirstComponent(Container aContainer) {
 492         List<Component> cycle;
 493 
 494         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 495             log.fine("### Getting first component in " + aContainer);
 496         }
 497         if (aContainer == null) {
 498             throw new IllegalArgumentException("aContainer cannot be null");
 499         }
 500 
 501         if (this.cachedRoot == aContainer) {
 502             cycle = this.cachedCycle;
 503         } else {
 504             cycle = getFocusTraversalCycle(aContainer);
 505         }
 506 
 507         if (cycle.size() == 0) {
 508             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 509                 log.fine("### Cycle is empty");
 510             }
 511             return null;
 512         }
 513         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 514             log.fine("### Cycle is " + cycle);
 515         }
 516 
 517         for (Component comp : cycle) {
 518             if (accept(comp)) {
 519                 return comp;
 520             } else if (comp != aContainer &&
 521                        (comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null)
 522             {
 523                 return comp;
 524             }
 525         }
 526         return null;
 527     }
 528 
 529     /**
 530      * Returns the last Component in the traversal cycle. This method is used
 531      * to determine the next Component to focus when traversal wraps in the
 532      * reverse direction.
 533      *
 534      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 535      *        last Component is to be returned
 536      * @return the last Component in the traversal cycle of aContainer,
 537      *         or null if no suitable Component can be found
 538      * @throws IllegalArgumentException if aContainer is null
 539      */
 540     public Component getLastComponent(Container aContainer) {
 541         List<Component> cycle;
 542         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 543             log.fine("### Getting last component in " + aContainer);
 544         }
 545 
 546         if (aContainer == null) {
 547             throw new IllegalArgumentException("aContainer cannot be null");
 548         }
 549 
 550         if (this.cachedRoot == aContainer) {
 551             cycle = this.cachedCycle;
 552         } else {
 553             cycle = getFocusTraversalCycle(aContainer);
 554         }
 555 
 556         if (cycle.size() == 0) {
 557             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 558                 log.fine("### Cycle is empty");
 559             }
 560             return null;
 561         }
 562         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 563             log.fine("### Cycle is " + cycle);
 564         }
 565 
 566         for (int i= cycle.size() - 1; i >= 0; i--) {
 567             Component comp = cycle.get(i);
 568             if (accept(comp)) {
 569                 return comp;
 570             } else if (comp instanceof Container && comp != aContainer) {
 571                 Container cont = (Container)comp;
 572                 if (cont.isFocusTraversalPolicyProvider()) {
 573                     return cont.getFocusTraversalPolicy().getLastComponent(cont);
 574                 }
 575             }
 576         }
 577         return null;
 578     }
 579 
 580     /**
 581      * Returns the default Component to focus. This Component will be the first
 582      * to receive focus when traversing down into a new focus traversal cycle
 583      * rooted at aContainer. The default implementation of this method
 584      * returns the same Component as <code>getFirstComponent</code>.
 585      *
 586      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 587      *        default Component is to be returned
 588      * @return the default Component in the traversal cycle of aContainer,
 589      *         or null if no suitable Component can be found
 590      * @see #getFirstComponent
 591      * @throws IllegalArgumentException if aContainer is null
 592      */
 593     public Component getDefaultComponent(Container aContainer) {
 594         return getFirstComponent(aContainer);
 595     }
 596 
 597     /**
 598      * Sets whether this SortingFocusTraversalPolicy transfers focus down-cycle
 599      * implicitly. If <code>true</code>, during normal focus traversal,
 600      * the Component traversed after a focus cycle root will be the focus-
 601      * cycle-root's default Component to focus. If <code>false</code>, the
 602      * next Component in the focus traversal cycle rooted at the specified
 603      * focus cycle root will be traversed instead. The default value for this
 604      * property is <code>true</code>.
 605      *
 606      * @param implicitDownCycleTraversal whether this
 607      *        SortingFocusTraversalPolicy transfers focus down-cycle implicitly
 608      * @see #getImplicitDownCycleTraversal
 609      * @see #getFirstComponent
 610      */
 611     public void setImplicitDownCycleTraversal(boolean implicitDownCycleTraversal) {
 612         this.implicitDownCycleTraversal = implicitDownCycleTraversal;
 613     }
 614 
 615     /**
 616      * Returns whether this SortingFocusTraversalPolicy transfers focus down-
 617      * cycle implicitly. If <code>true</code>, during normal focus
 618      * traversal, the Component traversed after a focus cycle root will be the
 619      * focus-cycle-root's default Component to focus. If <code>false</code>,
 620      * the next Component in the focus traversal cycle rooted at the specified
 621      * focus cycle root will be traversed instead.
 622      *
 623      * @return whether this SortingFocusTraversalPolicy transfers focus down-
 624      *         cycle implicitly
 625      * @see #setImplicitDownCycleTraversal
 626      * @see #getFirstComponent
 627      */
 628     public boolean getImplicitDownCycleTraversal() {
 629         return implicitDownCycleTraversal;
 630     }
 631 
 632     /**
 633      * Sets the Comparator which will be used to sort the Components in a
 634      * focus traversal cycle.
 635      *
 636      * @param comparator the Comparator which will be used for sorting
 637      */
 638     protected void setComparator(Comparator<? super Component> comparator) {
 639         this.comparator = comparator;
 640     }
 641 
 642     /**
 643      * Returns the Comparator which will be used to sort the Components in a
 644      * focus traversal cycle.
 645      *
 646      * @return the Comparator which will be used for sorting
 647      */
 648     protected Comparator<? super Component> getComparator() {
 649         return comparator;
 650     }
 651 
 652     /**
 653      * Determines whether a Component is an acceptable choice as the new
 654      * focus owner. By default, this method will accept a Component if and
 655      * only if it is visible, displayable, enabled, and focusable.
 656      *
 657      * @param aComponent the Component whose fitness as a focus owner is to
 658      *        be tested
 659      * @return <code>true</code> if aComponent is visible, displayable,
 660      *         enabled, and focusable; <code>false</code> otherwise
 661      */
 662     protected boolean accept(Component aComponent) {
 663         return fitnessTestPolicy.accept(aComponent);
 664     }
 665 }
 666 
 667 // Create our own subclass and change accept to public so that we can call
 668 // accept.
 669 @SuppressWarnings("serial") // JDK-implementation class
 670 class SwingContainerOrderFocusTraversalPolicy
 671     extends java.awt.ContainerOrderFocusTraversalPolicy
 672 {
 673     public boolean accept(Component aComponent) {
 674         return super.accept(aComponent);
 675     }
 676 }