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