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 }