FocusTraversal.java revision 13228:3468483150c6
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 @bug 8129940 8132770
26 @summary JRadioButton should run custom FocusTraversalKeys for all LaFs
27 @run main FocusTraversal
28 */
29import java.awt.BorderLayout;
30import java.awt.Component;
31import java.awt.KeyboardFocusManager;
32import java.awt.Robot;
33import java.awt.event.KeyEvent;
34import java.util.HashSet;
35import java.util.Set;
36import javax.swing.ButtonGroup;
37import javax.swing.FocusManager;
38import javax.swing.JButton;
39import javax.swing.JFrame;
40import javax.swing.JPanel;
41import javax.swing.JRadioButton;
42import javax.swing.JTextField;
43import javax.swing.KeyStroke;
44import javax.swing.LookAndFeel;
45import javax.swing.SwingUtilities;
46import javax.swing.UIManager;
47import javax.swing.UnsupportedLookAndFeelException;
48
49public class FocusTraversal {
50
51    private static JFrame frame;
52    private static JRadioButton a;
53    private static JRadioButton b;
54    private static JRadioButton c;
55    private static JRadioButton d;
56    private static JTextField next;
57    private static JTextField prev;
58    private static Robot robot;
59
60    public static void main(String[] args) throws Exception {
61
62        robot = new Robot();
63        robot.delay(2000);
64        UIManager.LookAndFeelInfo[] lookAndFeelArray
65                = UIManager.getInstalledLookAndFeels();
66        for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) {
67            executeCase(lookAndFeelItem.getClassName());
68        }
69    }
70
71    private static void executeCase(String lookAndFeelString)
72            throws Exception {
73        if (tryLookAndFeel(lookAndFeelString)) {
74            createUI(lookAndFeelString);
75            robot.delay(2000);
76            runTestCase();
77            robot.delay(2000);
78            cleanUp();
79            robot.delay(2000);
80        }
81    }
82
83    private static void createUI(final String lookAndFeelString)
84            throws Exception {
85        SwingUtilities.invokeAndWait(new Runnable() {
86            @Override
87            public void run() {
88                Set<KeyStroke> keystrokes = new HashSet<KeyStroke>();
89                keystrokes.add(KeyStroke.getKeyStroke("TAB"));
90                keystrokes.add(KeyStroke.getKeyStroke("ENTER"));
91                frame = new JFrame("FocusTraversalTest " + lookAndFeelString);
92                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
93                frame.setUndecorated(true);
94                frame.setFocusTraversalKeys(
95                        KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
96                        keystrokes);
97
98                a = new JRadioButton("a");
99                b = new JRadioButton("b");
100                c = new JRadioButton("c");
101                d = new JRadioButton("d");
102
103                ButtonGroup radioButtonGroup = new ButtonGroup();
104                radioButtonGroup.add(a);
105                radioButtonGroup.add(b);
106                radioButtonGroup.add(c);
107                radioButtonGroup.add(d);
108
109                JPanel panel = new JPanel();
110                prev = new JTextField("text");
111                panel.add(prev);
112                panel.add(a);
113                panel.add(b);
114                panel.add(c);
115                panel.add(d);
116                next = new JTextField("text");
117                panel.add(next);
118
119                JPanel root = new JPanel();
120                root.setLayout(new BorderLayout());
121                root.add(panel, BorderLayout.CENTER);
122                root.add(new JButton("OK"), BorderLayout.SOUTH);
123
124                frame.add(root);
125                frame.pack();
126                frame.setLocationRelativeTo(null);
127                frame.setVisible(true);
128                frame.toFront();
129            }
130        });
131    }
132
133    private static void runTestCase() throws Exception {
134        LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
135        focusOn(a);
136        if (isExcludedLookAndFeel(lookAndFeel)) {
137            robot.keyPress(KeyEvent.VK_ENTER);
138            robot.keyRelease(KeyEvent.VK_ENTER);
139            robot.waitForIdle();
140            isFocusOwner(b, "forward");
141            robot.keyPress(KeyEvent.VK_SHIFT);
142            robot.keyPress(KeyEvent.VK_TAB);
143            robot.keyRelease(KeyEvent.VK_TAB);
144            robot.keyRelease(KeyEvent.VK_SHIFT);
145            robot.waitForIdle();
146            isFocusOwner(a, "backward");
147
148        } else {
149
150            robot.keyPress(KeyEvent.VK_ENTER);
151            robot.keyRelease(KeyEvent.VK_ENTER);
152            robot.waitForIdle();
153            isFocusOwner(next, "forward");
154            robot.keyPress(KeyEvent.VK_SHIFT);
155            robot.keyPress(KeyEvent.VK_TAB);
156            robot.keyRelease(KeyEvent.VK_TAB);
157            robot.keyRelease(KeyEvent.VK_SHIFT);
158            robot.waitForIdle();
159            isFocusOwner(d, "backward");
160        }
161
162    }
163
164    private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) {
165
166        return lookAndFeel.toString().toLowerCase().contains("aqua")
167                || lookAndFeel.toString().toLowerCase().contains("nimbus")
168                || lookAndFeel.toString().toLowerCase().contains("gtk");
169    }
170
171    private static void focusOn(Component component)
172            throws Exception {
173        SwingUtilities.invokeAndWait(new Runnable() {
174            @Override
175            public void run() {
176                component.requestFocusInWindow();
177            }
178        });
179    }
180
181    private static void isFocusOwner(Component queriedFocusOwner,
182            String direction)
183            throws Exception {
184        SwingUtilities.invokeAndWait(new Runnable() {
185            @Override
186            public void run() {
187                Component actualFocusOwner
188                        = FocusManager.getCurrentManager().getFocusOwner();
189                if (actualFocusOwner != queriedFocusOwner) {
190                    frame.dispose();
191                    throw new RuntimeException(
192                            "Focus component is wrong after " + direction
193                            + " direction ");
194
195                }
196            }
197        });
198    }
199
200    private static boolean tryLookAndFeel(String lookAndFeelString)
201            throws Exception {
202
203        try {
204            UIManager.setLookAndFeel(
205                    lookAndFeelString);
206
207        } catch (UnsupportedLookAndFeelException
208                | ClassNotFoundException
209                | InstantiationException
210                | IllegalAccessException e) {
211            return false;
212        }
213        return true;
214    }
215
216    private static void cleanUp() throws Exception {
217        SwingUtilities.invokeAndWait(new Runnable() {
218            @Override
219            public void run() {
220                frame.dispose();
221            }
222        });
223    }
224}
225