jdk/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java
changeset 40995 c096d4be5b5e
parent 32865 f9cb6e427f9e
equal deleted inserted replaced
40994:43ee03955b10 40995:c096d4be5b5e
     1 /*
     1 /*
     2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    24  */
    24  */
    25 package javax.swing;
    25 package javax.swing;
    26 
    26 
    27 import java.awt.Component;
    27 import java.awt.Component;
    28 import java.awt.Container;
    28 import java.awt.Container;
    29 import java.awt.Window;
       
    30 import java.util.*;
    29 import java.util.*;
    31 import java.awt.FocusTraversalPolicy;
    30 import java.awt.FocusTraversalPolicy;
    32 import sun.util.logging.PlatformLogger;
    31 import sun.util.logging.PlatformLogger;
    33 import java.lang.reflect.InvocationTargetException;
       
    34 import java.lang.reflect.Method;
       
    35 import sun.security.action.GetPropertyAction;
    32 import sun.security.action.GetPropertyAction;
    36 import java.security.AccessController;
    33 import java.security.AccessController;
    37 import java.security.PrivilegedAction;
       
    38 
    34 
    39 /**
    35 /**
    40  * A FocusTraversalPolicy that determines traversal order by sorting the
    36  * A FocusTraversalPolicy that determines traversal order by sorting the
    41  * Components of a focus traversal cycle based on a given Comparator. Portions
    37  * 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
    38  * of the Component hierarchy that are not visible and displayable will not be
    98      * When true (by default), the legacy merge-sort algo is used to sort an FTP cycle.
    94      * 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.
    95      * When false, the default (tim-sort) algo is used, which may lead to an exception.
   100      * See: JDK-8048887
    96      * See: JDK-8048887
   101      */
    97      */
   102     private static final boolean legacySortingFTPEnabled;
    98     private static final boolean legacySortingFTPEnabled;
   103     private static final Method legacyMergeSortMethod;
       
   104 
    99 
   105     static {
   100     static {
   106         legacySortingFTPEnabled = "true".equals(AccessController.doPrivileged(
   101         legacySortingFTPEnabled = "true".equals(AccessController.doPrivileged(
   107             new GetPropertyAction("swing.legacySortingFTPEnabled", "true")));
   102             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     }
   103     }
   125 
   104 
   126     /**
   105     /**
   127      * Constructs a SortingFocusTraversalPolicy without a Comparator.
   106      * Constructs a SortingFocusTraversalPolicy without a Comparator.
   128      * Subclasses must set the Comparator using <code>setComparator</code>
   107      * Subclasses must set the Comparator using <code>setComparator</code>
   167     }
   146     }
   168 
   147 
   169     private void enumerateAndSortCycle(Container focusCycleRoot, List<Component> cycle) {
   148     private void enumerateAndSortCycle(Container focusCycleRoot, List<Component> cycle) {
   170         if (focusCycleRoot.isShowing()) {
   149         if (focusCycleRoot.isShowing()) {
   171             enumerateCycle(focusCycleRoot, cycle);
   150             enumerateCycle(focusCycleRoot, cycle);
   172             if (!legacySortingFTPEnabled ||
   151             if (legacySortingFTPEnabled) {
   173                 !legacySort(cycle, comparator))
   152                 legacySort(cycle, comparator);
   174             {
   153             } else {
   175                 Collections.sort(cycle, comparator);
   154                 cycle.sort(comparator);
   176             }
   155             }
   177         }
   156         }
   178     }
   157     }
   179 
   158 
   180     private boolean legacySort(List<Component> l, Comparator<? super Component> c) {
   159     private void legacySort(List<Component> l,
   181         if (legacyMergeSortMethod == null)
   160                                               Comparator<? super Component> c) {
   182             return false;
   161         if (c != null && l.size() > 1) {
   183 
   162             Component[] a = l.toArray(new Component[l.size()]);
   184         Object[] a = l.toArray();
   163             mergeSort(a.clone(), a, 0, a.length, 0, c);
   185         try {
   164             ListIterator<Component> i = l.listIterator();
   186             legacyMergeSortMethod.invoke(null, a, c);
   165             for (Component e : a) {
   187         } catch (IllegalAccessException | InvocationTargetException e) {
   166                 i.next();
   188             return false;
   167                 i.set(e);
   189         }
   168             }
   190         ListIterator<Component> i = l.listIterator();
   169         }
   191         for (Object e : a) {
       
   192             i.next();
       
   193             i.set((Component)e);
       
   194         }
       
   195         return true;
       
   196     }
   170     }
   197 
   171 
   198     @SuppressWarnings("deprecation")
   172     @SuppressWarnings("deprecation")
   199     private void enumerateCycle(Container container, List<Component> cycle) {
   173     private void enumerateCycle(Container container, List<Component> cycle) {
   200         if (!(container.isVisible() && container.isDisplayable())) {
   174         if (!(container.isVisible() && container.isDisplayable())) {
   663      *         enabled, and focusable; <code>false</code> otherwise
   637      *         enabled, and focusable; <code>false</code> otherwise
   664      */
   638      */
   665     protected boolean accept(Component aComponent) {
   639     protected boolean accept(Component aComponent) {
   666         return fitnessTestPolicy.accept(aComponent);
   640         return fitnessTestPolicy.accept(aComponent);
   667     }
   641     }
       
   642 
       
   643     // merge sort implementation copied from java.utils.Arrays
       
   644     private <T> void mergeSort(T[] src, T[] dest,
       
   645                                int low, int high, int off,
       
   646                                Comparator<? super T> c) {
       
   647         int length = high - low;
       
   648 
       
   649         // Insertion sort on smallest arrays
       
   650         if (length < 7) {
       
   651             for (int i=low; i<high; i++)
       
   652                 for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--) {
       
   653                     T t = dest[j];
       
   654                     dest[j] = dest[j-1];
       
   655                     dest[j-1] = t;
       
   656                 }
       
   657             return;
       
   658         }
       
   659 
       
   660         // Recursively sort halves of dest into src
       
   661         int destLow  = low;
       
   662         int destHigh = high;
       
   663         low  += off;
       
   664         high += off;
       
   665         int mid = (low + high) >>> 1;
       
   666         mergeSort(dest, src, low, mid, -off, c);
       
   667         mergeSort(dest, src, mid, high, -off, c);
       
   668 
       
   669         // If list is already sorted, just copy from src to dest.  This is an
       
   670         // optimization that results in faster sorts for nearly ordered lists.
       
   671         if (c.compare(src[mid-1], src[mid]) <= 0) {
       
   672             System.arraycopy(src, low, dest, destLow, length);
       
   673             return;
       
   674         }
       
   675 
       
   676         // Merge sorted halves (now in src) into dest
       
   677         for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
       
   678             if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
       
   679                 dest[i] = src[p++];
       
   680             else
       
   681                 dest[i] = src[q++];
       
   682         }
       
   683     }
   668 }
   684 }
   669 
   685 
   670 // Create our own subclass and change accept to public so that we can call
   686 // Create our own subclass and change accept to public so that we can call
   671 // accept.
   687 // accept.
   672 @SuppressWarnings("serial") // JDK-implementation class
   688 @SuppressWarnings("serial") // JDK-implementation class