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     private void enumerateCycle(Container container, List<Component> cycle) {
 199         if (!(container.isVisible() && container.isDisplayable())) {
 200             return;
 201         }
 202 
 203         cycle.add(container);
 204 
 205         Component[] components = container.getComponents();
 206         for (Component comp : components) {
 207             if (comp instanceof Container) {
 208                 Container cont = (Container)comp;
 209 
 210                 if (!cont.isFocusCycleRoot() &&
 211                     !cont.isFocusTraversalPolicyProvider() &&
 212                     !((cont instanceof JComponent) && ((JComponent)cont).isManagingFocus()))
 213                 {
 214                     enumerateCycle(cont, cycle);
 215                     continue;
 216                 }
 217             }
 218             cycle.add(comp);
 219         }
 220     }
 221 
 222     Container getTopmostProvider(Container focusCycleRoot, Component aComponent) {
 223         Container aCont = aComponent.getParent();
 224         Container ftp = null;
 225         while (aCont  != focusCycleRoot && aCont != null) {
 226             if (aCont.isFocusTraversalPolicyProvider()) {
 227                 ftp = aCont;
 228             }
 229             aCont = aCont.getParent();
 230         }
 231         if (aCont == null) {
 232             return null;
 233         }
 234         return ftp;
 235     }
 236 
 237     /*
 238      * Checks if a new focus cycle takes place and returns a Component to traverse focus to.
 239      * @param comp a possible focus cycle root or policy provider
 240      * @param traversalDirection the direction of the traversal
 241      * @return a Component to traverse focus to if {@code comp} is a root or provider
 242      *         and implicit down-cycle is set, otherwise {@code null}
 243      */
 244     private Component getComponentDownCycle(Component comp, int traversalDirection) {
 245         Component retComp = null;
 246 
 247         if (comp instanceof Container) {
 248             Container cont = (Container)comp;
 249 
 250             if (cont.isFocusCycleRoot()) {
 251                 if (getImplicitDownCycleTraversal()) {
 252                     retComp = cont.getFocusTraversalPolicy().getDefaultComponent(cont);
 253 
 254                     if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 255                         log.fine("### Transfered focus down-cycle to " + retComp +
 256                                  " in the focus cycle root " + cont);
 257                     }
 258                 } else {
 259                     return null;
 260                 }
 261             } else if (cont.isFocusTraversalPolicyProvider()) {
 262                 retComp = (traversalDirection == FORWARD_TRAVERSAL ?
 263                            cont.getFocusTraversalPolicy().getDefaultComponent(cont) :
 264                            cont.getFocusTraversalPolicy().getLastComponent(cont));
 265 
 266                 if (retComp != null && log.isLoggable(PlatformLogger.Level.FINE)) {
 267                     log.fine("### Transfered focus to " + retComp + " in the FTP provider " + cont);
 268                 }
 269             }
 270         }
 271         return retComp;
 272     }
 273 
 274     /**
 275      * Returns the Component that should receive the focus after aComponent.
 276      * aContainer must be a focus cycle root of aComponent or a focus traversal policy provider.
 277      * <p>
 278      * By default, SortingFocusTraversalPolicy implicitly transfers focus down-
 279      * cycle. That is, during normal focus traversal, the Component
 280      * traversed after a focus cycle root will be the focus-cycle-root's
 281      * default Component to focus. This behavior can be disabled using the
 282      * <code>setImplicitDownCycleTraversal</code> method.
 283      * <p>
 284      * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
 285      * traversal policy provider</a>, the focus is always transferred down-cycle.
 286      *
 287      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
 288      * @param aComponent a (possibly indirect) child of aContainer, or
 289      *        aContainer itself
 290      * @return the Component that should receive the focus after aComponent, or
 291      *         null if no suitable Component can be found
 292      * @throws IllegalArgumentException if aContainer is not a focus cycle
 293      *         root of aComponent or a focus traversal policy provider, or if either aContainer or
 294      *         aComponent is null
 295      */
 296     public Component getComponentAfter(Container aContainer, Component aComponent) {
 297         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 298             log.fine("### Searching in " + aContainer + " for component after " + aComponent);
 299         }
 300 
 301         if (aContainer == null || aComponent == null) {
 302             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 303         }
 304         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 305             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 306 
 307         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 308             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 309         }
 310 
 311         // Before all the ckecks below we first see if it's an FTP provider or a focus cycle root.
 312         // If it's the case just go down cycle (if it's set to "implicit").
 313         Component comp = getComponentDownCycle(aComponent, FORWARD_TRAVERSAL);
 314         if (comp != null) {
 315             return comp;
 316         }
 317 
 318         // See if the component is inside of policy provider.
 319         Container provider = getTopmostProvider(aContainer, aComponent);
 320         if (provider != null) {
 321             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 322                 log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 323             }
 324 
 325             // FTP knows how to find component after the given. We don't.
 326             FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 327             Component afterComp = policy.getComponentAfter(provider, aComponent);
 328 
 329             // Null result means that we overstepped the limit of the FTP's cycle.
 330             // In that case we must quit the cycle, otherwise return the component found.
 331             if (afterComp != null) {
 332                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 333                     log.fine("### FTP returned " + afterComp);
 334                 }
 335                 return afterComp;
 336             }
 337             aComponent = provider;
 338         }
 339 
 340         List<Component> cycle = getFocusTraversalCycle(aContainer);
 341 
 342         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 343             log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 344         }
 345 
 346         int index = getComponentIndex(cycle, aComponent);
 347 
 348         if (index < 0) {
 349             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 350                 log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 351             }
 352             return getFirstComponent(aContainer);
 353         }
 354 
 355         for (index++; index < cycle.size(); index++) {
 356             comp = cycle.get(index);
 357             if (accept(comp)) {
 358                 return comp;
 359             } else if ((comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null) {
 360                 return comp;
 361             }
 362         }
 363 
 364         if (aContainer.isFocusCycleRoot()) {
 365             this.cachedRoot = aContainer;
 366             this.cachedCycle = cycle;
 367 
 368             comp = getFirstComponent(aContainer);
 369 
 370             this.cachedRoot = null;
 371             this.cachedCycle = null;
 372 
 373             return comp;
 374         }
 375         return null;
 376     }
 377 
 378     /**
 379      * Returns the Component that should receive the focus before aComponent.
 380      * aContainer must be a focus cycle root of aComponent or a focus traversal policy provider.
 381      * <p>
 382      * By default, SortingFocusTraversalPolicy implicitly transfers focus down-
 383      * cycle. That is, during normal focus traversal, the Component
 384      * traversed after a focus cycle root will be the focus-cycle-root's
 385      * default Component to focus. This behavior can be disabled using the
 386      * <code>setImplicitDownCycleTraversal</code> method.
 387      * <p>
 388      * If aContainer is <a href="../../java/awt/doc-files/FocusSpec.html#FocusTraversalPolicyProviders">focus
 389      * traversal policy provider</a>, the focus is always transferred down-cycle.
 390      *
 391      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider
 392      * @param aComponent a (possibly indirect) child of aContainer, or
 393      *        aContainer itself
 394      * @return the Component that should receive the focus before aComponent,
 395      *         or null if no suitable Component can be found
 396      * @throws IllegalArgumentException if aContainer is not a focus cycle
 397      *         root of aComponent or a focus traversal policy provider, or if either aContainer or
 398      *         aComponent is null
 399      */
 400     public Component getComponentBefore(Container aContainer, Component aComponent) {
 401         if (aContainer == null || aComponent == null) {
 402             throw new IllegalArgumentException("aContainer and aComponent cannot be null");
 403         }
 404         if (!aContainer.isFocusTraversalPolicyProvider() && !aContainer.isFocusCycleRoot()) {
 405             throw new IllegalArgumentException("aContainer should be focus cycle root or focus traversal policy provider");
 406 
 407         } else if (aContainer.isFocusCycleRoot() && !aComponent.isFocusCycleRoot(aContainer)) {
 408             throw new IllegalArgumentException("aContainer is not a focus cycle root of aComponent");
 409         }
 410 
 411         // See if the component is inside of policy provider.
 412         Container provider = getTopmostProvider(aContainer, aComponent);
 413         if (provider != null) {
 414             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 415                 log.fine("### Asking FTP " + provider + " for component after " + aComponent);
 416             }
 417 
 418             // FTP knows how to find component after the given. We don't.
 419             FocusTraversalPolicy policy = provider.getFocusTraversalPolicy();
 420             Component beforeComp = policy.getComponentBefore(provider, aComponent);
 421 
 422             // Null result means that we overstepped the limit of the FTP's cycle.
 423             // In that case we must quit the cycle, otherwise return the component found.
 424             if (beforeComp != null) {
 425                 if (log.isLoggable(PlatformLogger.Level.FINE)) {
 426                     log.fine("### FTP returned " + beforeComp);
 427                 }
 428                 return beforeComp;
 429             }
 430             aComponent = provider;
 431 
 432             // If the provider is traversable it's returned.
 433             if (accept(aComponent)) {
 434                 return aComponent;
 435             }
 436         }
 437 
 438         List<Component> cycle = getFocusTraversalCycle(aContainer);
 439 
 440         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 441             log.fine("### Cycle is " + cycle + ", component is " + aComponent);
 442         }
 443 
 444         int index = getComponentIndex(cycle, aComponent);
 445 
 446         if (index < 0) {
 447             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 448                 log.fine("### Didn't find component " + aComponent + " in a cycle " + aContainer);
 449             }
 450             return getLastComponent(aContainer);
 451         }
 452 
 453         Component comp;
 454         Component tryComp;
 455 
 456         for (index--; index>=0; index--) {
 457             comp = cycle.get(index);
 458             if (comp != aContainer && (tryComp = getComponentDownCycle(comp, BACKWARD_TRAVERSAL)) != null) {
 459                 return tryComp;
 460             } else if (accept(comp)) {
 461                 return comp;
 462             }
 463         }
 464 
 465         if (aContainer.isFocusCycleRoot()) {
 466             this.cachedRoot = aContainer;
 467             this.cachedCycle = cycle;
 468 
 469             comp = getLastComponent(aContainer);
 470 
 471             this.cachedRoot = null;
 472             this.cachedCycle = null;
 473 
 474             return comp;
 475         }
 476         return null;
 477     }
 478 
 479     /**
 480      * Returns the first Component in the traversal cycle. This method is used
 481      * to determine the next Component to focus when traversal wraps in the
 482      * forward direction.
 483      *
 484      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 485      *        first Component is to be returned
 486      * @return the first Component in the traversal cycle of aContainer,
 487      *         or null if no suitable Component can be found
 488      * @throws IllegalArgumentException if aContainer is null
 489      */
 490     public Component getFirstComponent(Container aContainer) {
 491         List<Component> cycle;
 492 
 493         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 494             log.fine("### Getting first component in " + aContainer);
 495         }
 496         if (aContainer == null) {
 497             throw new IllegalArgumentException("aContainer cannot be null");
 498         }
 499 
 500         if (this.cachedRoot == aContainer) {
 501             cycle = this.cachedCycle;
 502         } else {
 503             cycle = getFocusTraversalCycle(aContainer);
 504         }
 505 
 506         if (cycle.size() == 0) {
 507             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 508                 log.fine("### Cycle is empty");
 509             }
 510             return null;
 511         }
 512         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 513             log.fine("### Cycle is " + cycle);
 514         }
 515 
 516         for (Component comp : cycle) {
 517             if (accept(comp)) {
 518                 return comp;
 519             } else if (comp != aContainer &&
 520                        (comp = getComponentDownCycle(comp, FORWARD_TRAVERSAL)) != null)
 521             {
 522                 return comp;
 523             }
 524         }
 525         return null;
 526     }
 527 
 528     /**
 529      * Returns the last Component in the traversal cycle. This method is used
 530      * to determine the next Component to focus when traversal wraps in the
 531      * reverse direction.
 532      *
 533      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 534      *        last Component is to be returned
 535      * @return the last Component in the traversal cycle of aContainer,
 536      *         or null if no suitable Component can be found
 537      * @throws IllegalArgumentException if aContainer is null
 538      */
 539     public Component getLastComponent(Container aContainer) {
 540         List<Component> cycle;
 541         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 542             log.fine("### Getting last component in " + aContainer);
 543         }
 544 
 545         if (aContainer == null) {
 546             throw new IllegalArgumentException("aContainer cannot be null");
 547         }
 548 
 549         if (this.cachedRoot == aContainer) {
 550             cycle = this.cachedCycle;
 551         } else {
 552             cycle = getFocusTraversalCycle(aContainer);
 553         }
 554 
 555         if (cycle.size() == 0) {
 556             if (log.isLoggable(PlatformLogger.Level.FINE)) {
 557                 log.fine("### Cycle is empty");
 558             }
 559             return null;
 560         }
 561         if (log.isLoggable(PlatformLogger.Level.FINE)) {
 562             log.fine("### Cycle is " + cycle);
 563         }
 564 
 565         for (int i= cycle.size() - 1; i >= 0; i--) {
 566             Component comp = cycle.get(i);
 567             if (accept(comp)) {
 568                 return comp;
 569             } else if (comp instanceof Container && comp != aContainer) {
 570                 Container cont = (Container)comp;
 571                 if (cont.isFocusTraversalPolicyProvider()) {
 572                     return cont.getFocusTraversalPolicy().getLastComponent(cont);
 573                 }
 574             }
 575         }
 576         return null;
 577     }
 578 
 579     /**
 580      * Returns the default Component to focus. This Component will be the first
 581      * to receive focus when traversing down into a new focus traversal cycle
 582      * rooted at aContainer. The default implementation of this method
 583      * returns the same Component as <code>getFirstComponent</code>.
 584      *
 585      * @param aContainer a focus cycle root of aComponent or a focus traversal policy provider whose
 586      *        default Component is to be returned
 587      * @return the default Component in the traversal cycle of aContainer,
 588      *         or null if no suitable Component can be found
 589      * @see #getFirstComponent
 590      * @throws IllegalArgumentException if aContainer is null
 591      */
 592     public Component getDefaultComponent(Container aContainer) {
 593         return getFirstComponent(aContainer);
 594     }
 595 
 596     /**
 597      * Sets whether this SortingFocusTraversalPolicy transfers focus down-cycle
 598      * implicitly. If <code>true</code>, during normal focus traversal,
 599      * the Component traversed after a focus cycle root will be the focus-
 600      * cycle-root's default Component to focus. If <code>false</code>, the
 601      * next Component in the focus traversal cycle rooted at the specified
 602      * focus cycle root will be traversed instead. The default value for this
 603      * property is <code>true</code>.
 604      *
 605      * @param implicitDownCycleTraversal whether this
 606      *        SortingFocusTraversalPolicy transfers focus down-cycle implicitly
 607      * @see #getImplicitDownCycleTraversal
 608      * @see #getFirstComponent
 609      */
 610     public void setImplicitDownCycleTraversal(boolean implicitDownCycleTraversal) {
 611         this.implicitDownCycleTraversal = implicitDownCycleTraversal;
 612     }
 613 
 614     /**
 615      * Returns whether this SortingFocusTraversalPolicy transfers focus down-
 616      * cycle implicitly. If <code>true</code>, during normal focus
 617      * traversal, the Component traversed after a focus cycle root will be the
 618      * focus-cycle-root's default Component to focus. If <code>false</code>,
 619      * the next Component in the focus traversal cycle rooted at the specified
 620      * focus cycle root will be traversed instead.
 621      *
 622      * @return whether this SortingFocusTraversalPolicy transfers focus down-
 623      *         cycle implicitly
 624      * @see #setImplicitDownCycleTraversal
 625      * @see #getFirstComponent
 626      */
 627     public boolean getImplicitDownCycleTraversal() {
 628         return implicitDownCycleTraversal;
 629     }
 630 
 631     /**
 632      * Sets the Comparator which will be used to sort the Components in a
 633      * focus traversal cycle.
 634      *
 635      * @param comparator the Comparator which will be used for sorting
 636      */
 637     protected void setComparator(Comparator<? super Component> comparator) {
 638         this.comparator = comparator;
 639     }
 640 
 641     /**
 642      * Returns the Comparator which will be used to sort the Components in a
 643      * focus traversal cycle.
 644      *
 645      * @return the Comparator which will be used for sorting
 646      */
 647     protected Comparator<? super Component> getComparator() {
 648         return comparator;
 649     }
 650 
 651     /**
 652      * Determines whether a Component is an acceptable choice as the new
 653      * focus owner. By default, this method will accept a Component if and
 654      * only if it is visible, displayable, enabled, and focusable.
 655      *
 656      * @param aComponent the Component whose fitness as a focus owner is to
 657      *        be tested
 658      * @return <code>true</code> if aComponent is visible, displayable,
 659      *         enabled, and focusable; <code>false</code> otherwise
 660      */
 661     protected boolean accept(Component aComponent) {
 662         return fitnessTestPolicy.accept(aComponent);
 663     }
 664 }
 665 
 666 // Create our own subclass and change accept to public so that we can call
 667 // accept.
 668 @SuppressWarnings("serial") // JDK-implementation class
 669 class SwingContainerOrderFocusTraversalPolicy
 670     extends java.awt.ContainerOrderFocusTraversalPolicy
 671 {
 672     public boolean accept(Component aComponent) {
 673         return super.accept(aComponent);
 674     }
 675 }