Skip to content

Commit

Permalink
Backport 57af52c57390f6f7413b5d3ffe64921c9b83aae4
Browse files Browse the repository at this point in the history
  • Loading branch information
duke committed Jan 24, 2025
1 parent 96bd21d commit 430a4d0
Showing 1 changed file with 111 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -28,26 +28,53 @@
* @run main ButtonGroupFocusTest
*/

import javax.swing.*;
import java.awt.*;
import java.awt.AWTEvent;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.CountDownLatch;

public class ButtonGroupFocusTest {
import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;

import static java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

public final class ButtonGroupFocusTest {

private static JRadioButton button1;
private static JRadioButton button2;
private static JRadioButton button3;
private static JRadioButton button4;
private static JRadioButton button5;
private static Robot robot;

private static final CountDownLatch button2FocusLatch = new CountDownLatch(1);
private static final CountDownLatch button3FocusLatch = new CountDownLatch(1);
private static final CountDownLatch button4FocusLatch = new CountDownLatch(1);

private static final CountDownLatch button2FocusLatch2 = new CountDownLatch(2);

private static final long FOCUS_TIMEOUT = 4;

private static JFrame frame;

public static void main(String[] args) throws Exception {
robot = new Robot();
robot.setAutoDelay(100);
final Robot robot = new Robot();

SwingUtilities.invokeAndWait(() -> {
frame = new JFrame();
frame = new JFrame("ButtonGroupFocusTest");
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
button1 = new JRadioButton("Button 1");
Expand All @@ -60,6 +87,7 @@ public static void main(String[] args) throws Exception {
contentPane.add(button4);
button5 = new JRadioButton("Button 5");
contentPane.add(button5);

ButtonGroup group = new ButtonGroup();
group.add(button1);
group.add(button2);
Expand All @@ -69,52 +97,96 @@ public static void main(String[] args) throws Exception {
group.add(button4);
group.add(button5);

button2.addFocusListener(new LatchFocusListener(button2FocusLatch));
button3.addFocusListener(new LatchFocusListener(button3FocusLatch));
button4.addFocusListener(new LatchFocusListener(button4FocusLatch));

button2.addFocusListener(new LatchFocusListener(button2FocusLatch2));

button2.setSelected(true);

// Debugging aid: log focus owner changes...
KeyboardFocusManager focusManager = getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener("focusOwner",
e -> System.out.println(e.getPropertyName()
+ "\n\t" + e.getOldValue()
+ "\n\t" + e.getNewValue()));

// ...and dispatched key events
Toolkit.getDefaultToolkit().addAWTEventListener(
e -> System.out.println("Dispatched " + e),
AWTEvent.KEY_EVENT_MASK);

frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});

robot.waitForIdle();
robot.delay(200);

SwingUtilities.invokeAndWait(() -> {
if( !button2.hasFocus() ) {
frame.dispose();
throw new RuntimeException(
"Button 2 should get focus after activation");
try {
if (!button2FocusLatch.await(FOCUS_TIMEOUT, SECONDS)) {
throw new RuntimeException("Button 2 should get focus "
+ "after activation");
}
});
robot.waitForIdle();
robot.delay(200);

robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
System.out.println("\n\n*** Tab 1st");
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);

robot.waitForIdle();
robot.delay(200);
if (!button4FocusLatch.await(FOCUS_TIMEOUT, SECONDS)) {
throw new RuntimeException("Button 4 should get focus");
}
robot.waitForIdle();
robot.delay(200);

SwingUtilities.invokeAndWait(() -> {
if( !button4.hasFocus() ) {
frame.dispose();
throw new RuntimeException(
"Button 4 should get focus");
if (button2FocusLatch2.await(1, MILLISECONDS)) {
throw new RuntimeException("Focus moved back to Button 2");
}
button3.setSelected(true);
});

robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
SwingUtilities.invokeAndWait(() -> button3.setSelected(true));
robot.waitForIdle();
robot.delay(200);

robot.waitForIdle();
robot.delay(200);
System.out.println("\n\n*** Tab 2nd");
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);

SwingUtilities.invokeAndWait(() -> {
if( !button3.hasFocus() ) {
frame.dispose();
throw new RuntimeException(
"selected Button 3 should get focus");
if (!button3FocusLatch.await(FOCUS_TIMEOUT, SECONDS)) {
throw new RuntimeException("Selected Button 3 should get focus");
}
});
} catch (Exception e) {
BufferedImage image = robot.createScreenCapture(getFrameBounds());
ImageIO.write(image, "png",
new File("image.png"));

SwingUtilities.invokeAndWait(() ->
System.err.println("Current focus owner: "
+ getCurrentKeyboardFocusManager()
.getFocusOwner()));

throw e;
} finally {
SwingUtilities.invokeAndWait(frame::dispose);
}
}

private static Rectangle getFrameBounds() throws Exception {
Rectangle[] bounds = new Rectangle[1];
SwingUtilities.invokeAndWait(() -> bounds[0] = frame.getBounds());
return bounds[0];
}

private static final class LatchFocusListener extends FocusAdapter {
private final CountDownLatch focusGainedLatch;

private LatchFocusListener(CountDownLatch focusGainedLatch) {
this.focusGainedLatch = focusGainedLatch;
}

SwingUtilities.invokeLater(frame::dispose);
@Override
public void focusGained(FocusEvent e) {
focusGainedLatch.countDown();
}
}
}

0 comments on commit 430a4d0

Please sign in to comment.