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 |