1 /*
   2  * Copyright (c) 2014, 2016, 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  /*
  25  * @test
  26  * @key headful
  27  * @library ../../regtesthelpers
  28  * @build Util
  29  * @bug 8033699 8154043
  30  * @summary  Incorrect radio button behavior when pressing tab key
  31  * @author Vivi An
  32  * @run main bug8033699
  33  */
  34 
  35 import javax.swing.*;
  36 import javax.swing.event.*;
  37 import java.awt.event.*;
  38 import java.awt.*;
  39 
  40 public class bug8033699 {
  41     private static Robot robot;
  42 
  43     private static JButton btnStart;
  44     private static ButtonGroup btnGrp;
  45     private static JButton btnEnd;
  46     private static JButton btnMiddle;
  47     private static JRadioButton radioBtn1;
  48     private static JRadioButton radioBtn2;
  49     private static JRadioButton radioBtn3;
  50     private static JRadioButton radioBtnSingle;
  51 
  52     public static void main(String args[]) throws Throwable {
  53         SwingUtilities.invokeAndWait(new Runnable() {
  54             public void run() {
  55                 createAndShowGUI();
  56             }
  57         });
  58 
  59         robot = new Robot();
  60         Thread.sleep(100);
  61 
  62         robot.setAutoDelay(100);
  63 
  64         // tab key test grouped radio button
  65         runTest1();
  66 
  67         // tab key test non-grouped radio button
  68         runTest2();
  69 
  70         // shift tab key test grouped and non grouped radio button
  71         runTest3();
  72 
  73         // left/up key test in grouped radio button
  74         runTest4();
  75 
  76         // down/right key test in grouped radio button
  77         runTest5();
  78 
  79         // tab from radio button in group to next component in the middle of button group layout
  80         runTest6();
  81 
  82         // tab to radio button in group from component in the middle of button group layout
  83         runTest7();
  84 
  85         // down key circle back to first button in grouped radio button
  86         runTest8();
  87     }
  88 
  89     private static void createAndShowGUI() {
  90         JFrame mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
  91 
  92         btnStart = new JButton("Start");
  93         btnEnd = new JButton("End");
  94         btnMiddle = new JButton("Middle");
  95 
  96         JPanel box = new JPanel();
  97         box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
  98         box.setBorder(BorderFactory.createTitledBorder("Grouped Radio Buttons"));
  99         radioBtn1 = new JRadioButton("A");
 100         radioBtn2 = new JRadioButton("B");
 101         radioBtn3 = new JRadioButton("C");
 102 
 103         ButtonGroup btnGrp = new ButtonGroup();
 104         btnGrp.add(radioBtn1);
 105         btnGrp.add(radioBtn2);
 106         btnGrp.add(radioBtn3);
 107         radioBtn1.setSelected(true);
 108 
 109         box.add(radioBtn1);
 110         box.add(radioBtn2);
 111         box.add(btnMiddle);
 112         box.add(radioBtn3);
 113 
 114         radioBtnSingle = new JRadioButton("Not Grouped");
 115         radioBtnSingle.setSelected(true);
 116 
 117         mainFrame.getContentPane().add(btnStart);
 118         mainFrame.getContentPane().add(box);
 119         mainFrame.getContentPane().add(radioBtnSingle);
 120         mainFrame.getContentPane().add(btnEnd);
 121 
 122         mainFrame.getRootPane().setDefaultButton(btnStart);
 123         btnStart.requestFocus();
 124 
 125         mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 126         mainFrame.setLayout(new BoxLayout(mainFrame.getContentPane(), BoxLayout.Y_AXIS));
 127 
 128         mainFrame.setSize(300, 300);
 129         mainFrame.setLocation(200, 200);
 130         mainFrame.setVisible(true);
 131         mainFrame.toFront();
 132     }
 133 
 134     // Radio button Group as a single component when traversing through tab key
 135     private static void runTest1() throws Exception{
 136         hitKey(robot, KeyEvent.VK_TAB);
 137         hitKey(robot, KeyEvent.VK_TAB);
 138         hitKey(robot, KeyEvent.VK_TAB);
 139 
 140         SwingUtilities.invokeAndWait(new Runnable() {
 141             public void run() {
 142                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
 143                     System.out.println("Radio Button Group Go To Next Component through Tab Key failed");
 144                     throw new RuntimeException("Focus is not on Radio Button Single as Expected");
 145                 }
 146             }
 147         });
 148     }
 149 
 150     // Non-Grouped Radio button as a single component when traversing through tab key
 151     private static void runTest2() throws Exception{
 152         hitKey(robot, KeyEvent.VK_TAB);
 153         SwingUtilities.invokeAndWait(new Runnable() {
 154             public void run() {
 155                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) {
 156                     System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed");
 157                     throw new RuntimeException("Focus is not on Button End as Expected");
 158                 }
 159             }
 160         });
 161     }
 162 
 163     // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key
 164     private static void runTest3() throws Exception{
 165         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
 166         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
 167         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
 168         SwingUtilities.invokeAndWait(new Runnable() {
 169             public void run() {
 170                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
 171                     System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed");
 172                     throw new RuntimeException("Focus is not on Radio Button A as Expected");
 173                 }
 174             }
 175         });
 176     }
 177 
 178     // Using arrow key to move focus in radio button group
 179     private static void runTest4() throws Exception{
 180         hitKey(robot, KeyEvent.VK_DOWN);
 181         hitKey(robot, KeyEvent.VK_RIGHT);
 182         SwingUtilities.invokeAndWait(new Runnable() {
 183             public void run() {
 184                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) {
 185                     System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed");
 186                     throw new RuntimeException("Focus is not on Radio Button C as Expected");
 187                 }
 188             }
 189         });
 190     }
 191 
 192     private static void runTest5() throws Exception{
 193         hitKey(robot, KeyEvent.VK_UP);
 194         hitKey(robot, KeyEvent.VK_LEFT);
 195         SwingUtilities.invokeAndWait(new Runnable() {
 196             public void run() {
 197                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
 198                     System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed");
 199                     throw new RuntimeException("Focus is not on Radio Button A as Expected");
 200                 }
 201             }
 202         });
 203     }
 204 
 205     private static void runTest6() throws Exception{
 206         hitKey(robot, KeyEvent.VK_UP);
 207         hitKey(robot, KeyEvent.VK_UP);
 208         SwingUtilities.invokeAndWait(new Runnable() {
 209             public void run() {
 210                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) {
 211                     System.out.println("Radio button Group Circle Back To First Button Test");
 212                     throw new RuntimeException("Focus is not on Radio Button B as Expected");
 213                 }
 214             }
 215         });
 216     }
 217 
 218     private static void runTest7() throws Exception{
 219         hitKey(robot, KeyEvent.VK_TAB);
 220         SwingUtilities.invokeAndWait(new Runnable() {
 221             public void run() {
 222                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) {
 223                     System.out.println("Separate Component added in button group layout");
 224                     throw new RuntimeException("Focus is not on Middle Button as Expected");
 225                 }
 226             }
 227         });
 228     }
 229 
 230     private static void runTest8() throws Exception{
 231         hitKey(robot, KeyEvent.VK_TAB);
 232         SwingUtilities.invokeAndWait(new Runnable() {
 233             public void run() {
 234                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
 235                     System.out.println("Separate Component added in button group layout");
 236                     throw new RuntimeException("Focus is not on Radio Button Single as Expected");
 237                 }
 238             }
 239         });
 240     }
 241 
 242     private static void hitKey(Robot robot, int keycode) {
 243         robot.keyPress(keycode);
 244         robot.keyRelease(keycode);
 245         robot.waitForIdle();
 246     }
 247 
 248     private static void hitKey(Robot robot, int mode, int keycode) {
 249         robot.keyPress(mode);
 250         robot.keyPress(keycode);
 251         robot.keyRelease(mode);
 252         robot.keyRelease(keycode);
 253         robot.waitForIdle();
 254     }
 255 }