FocusTraversal.java revision 15510:b209cf7b5b91
1/*
2 * Copyright (c) 2015, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/* @test
25 * @key headful
26 * @bug 8129940 8132770 8161470 8163169
27 * @summary JRadioButton should run custom FocusTraversalKeys for all LaFs
28 * @run main FocusTraversal
29 */
30import java.awt.BorderLayout;
31import java.awt.Component;
32import java.awt.KeyboardFocusManager;
33import java.awt.Robot;
34import java.awt.event.KeyEvent;
35import java.util.HashSet;
36import java.util.Set;
37import javax.swing.ButtonGroup;
38import javax.swing.FocusManager;
39import javax.swing.JButton;
40import javax.swing.JFrame;
41import javax.swing.JPanel;
42import javax.swing.JRadioButton;
43import javax.swing.JTextField;
44import javax.swing.KeyStroke;
45import javax.swing.LookAndFeel;
46import javax.swing.SwingUtilities;
47import javax.swing.UIManager;
48import javax.swing.UnsupportedLookAndFeelException;
49
50public class FocusTraversal {
51
52    private static JFrame frame;
53    private static JRadioButton a;
54    private static JRadioButton b;
55    private static JRadioButton c;
56    private static JRadioButton d;
57    private static JTextField next;
58    private static JTextField prev;
59    private static Robot robot;
60
61    public static void main(String[] args) throws Exception {
62
63        robot = new Robot();
64        robot.setAutoDelay(100);
65        robot.waitForIdle();
66        UIManager.LookAndFeelInfo[] lookAndFeelArray
67                = UIManager.getInstalledLookAndFeels();
68        for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) {
69            executeCase(lookAndFeelItem.getClassName());
70        }
71    }
72
73    private static void executeCase(String lookAndFeelString)
74            throws Exception {
75        if (tryLookAndFeel(lookAndFeelString)) {
76            createUI(lookAndFeelString);
77            robot.waitForIdle();
78            runTestCase();
79            robot.waitForIdle();
80            cleanUp();
81            robot.waitForIdle();
82        }
83    }
84
85    private static void createUI(final String lookAndFeelString)
86            throws Exception {
87        SwingUtilities.invokeAndWait(new Runnable() {
88            @Override
89            public void run() {
90                Set<KeyStroke> keystrokes = new HashSet<KeyStroke>();
91                keystrokes.add(KeyStroke.getKeyStroke("TAB"));
92                keystrokes.add(KeyStroke.getKeyStroke("ENTER"));
93                frame = new JFrame("FocusTraversalTest " + lookAndFeelString);
94                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
95                frame.setUndecorated(true);
96                frame.setFocusTraversalKeys(
97                        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
98                        keystrokes);
99
100                a = new JRadioButton("a");
101                b = new JRadioButton("b");
102                c = new JRadioButton("c");
103                d = new JRadioButton("d");
104
105                ButtonGroup radioButtonGroup = new ButtonGroup();
106                radioButtonGroup.add(a);
107                radioButtonGroup.add(b);
108                radioButtonGroup.add(c);
109                radioButtonGroup.add(d);
110
111                JPanel panel = new JPanel();
112                prev = new JTextField("text");
113                panel.add(prev);
114                panel.add(a);
115                panel.add(b);
116                panel.add(c);
117                panel.add(d);
118                next = new JTextField("text");
119                panel.add(next);
120
121                JPanel root = new JPanel();
122                root.setLayout(new BorderLayout());
123                root.add(panel, BorderLayout.CENTER);
124                root.add(new JButton("OK"), BorderLayout.SOUTH);
125
126                frame.add(root);
127                frame.pack();
128                frame.setLocationRelativeTo(null);
129                frame.setVisible(true);
130                frame.toFront();
131            }
132        });
133    }
134
135    private static void runTestCase() throws Exception {
136        LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
137        focusOn(a);
138        if (isExcludedLookAndFeel(lookAndFeel)) {
139            robot.keyPress(KeyEvent.VK_ENTER);
140            robot.keyRelease(KeyEvent.VK_ENTER);
141            robot.waitForIdle();
142            isFocusOwner(b, "forward");
143            robot.keyPress(KeyEvent.VK_SHIFT);
144            robot.keyPress(KeyEvent.VK_TAB);
145            robot.keyRelease(KeyEvent.VK_TAB);
146            robot.keyRelease(KeyEvent.VK_SHIFT);
147            robot.waitForIdle();
148            isFocusOwner(a, "backward");
149
150        } else {
151
152            robot.keyPress(KeyEvent.VK_ENTER);
153            robot.keyRelease(KeyEvent.VK_ENTER);
154            robot.waitForIdle();
155            isFocusOwner(next, "forward");
156            robot.keyPress(KeyEvent.VK_SHIFT);
157            robot.keyPress(KeyEvent.VK_TAB);
158            robot.keyRelease(KeyEvent.VK_TAB);
159            robot.keyRelease(KeyEvent.VK_SHIFT);
160            robot.waitForIdle();
161            isFocusOwner(d, "backward");
162        }
163
164    }
165
166    private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) {
167
168        return lookAndFeel.toString().toLowerCase().contains("aqua")
169                || lookAndFeel.toString().toLowerCase().contains("nimbus")
170                || lookAndFeel.toString().toLowerCase().contains("gtk");
171    }
172
173    private static void focusOn(Component component)
174            throws Exception {
175        SwingUtilities.invokeAndWait(new Runnable() {
176            @Override
177            public void run() {
178                component.requestFocusInWindow();
179            }
180        });
181    }
182
183    private static void isFocusOwner(Component queriedFocusOwner,
184            String direction)
185            throws Exception {
186        SwingUtilities.invokeAndWait(new Runnable() {
187            @Override
188            public void run() {
189                Component actualFocusOwner
190                        = FocusManager.getCurrentManager().getFocusOwner();
191                if (actualFocusOwner != queriedFocusOwner) {
192                    frame.dispose();
193                    throw new RuntimeException(
194                            "Focus component is wrong after " + direction
195                            + " direction ");
196
197                }
198            }
199        });
200    }
201
202    private static boolean tryLookAndFeel(String lookAndFeelString)
203            throws Exception {
204
205        try {
206            UIManager.setLookAndFeel(
207                    lookAndFeelString);
208
209        } catch (UnsupportedLookAndFeelException
210                | ClassNotFoundException
211                | InstantiationException
212                | IllegalAccessException e) {
213            return false;
214        }
215        return true;
216    }
217
218    private static void cleanUp() throws Exception {
219        SwingUtilities.invokeAndWait(new Runnable() {
220            @Override
221            public void run() {
222                frame.dispose();
223            }
224        });
225    }
226}
227