8299123: [BACKOUT] 4512626 Non-editable JTextArea provides no visual indication of keyboard focus

Reviewed-by: tschatzl
This commit is contained in:
Daniel D. Daugherty 2022-12-20 16:20:50 +00:00
parent 03afec16f8
commit f4d7f43394
4 changed files with 166 additions and 163 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -366,8 +366,6 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
} }
} }
private int savedBlinkRate = 0;
private boolean isBlinkRateSaved = false;
// --- FocusListener methods -------------------------- // --- FocusListener methods --------------------------
/** /**
@ -381,21 +379,8 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
public void focusGained(FocusEvent e) { public void focusGained(FocusEvent e) {
if (component.isEnabled()) { if (component.isEnabled()) {
if (component.isEditable()) { if (component.isEditable()) {
if (isBlinkRateSaved) { setVisible(true);
setBlinkRate(savedBlinkRate);
savedBlinkRate = 0;
isBlinkRateSaved = false;
}
} else {
if (getBlinkRate() != 0) {
if (!isBlinkRateSaved) {
savedBlinkRate = getBlinkRate();
isBlinkRateSaved = true;
}
setBlinkRate(0);
}
} }
setVisible(true);
setSelectionVisible(true); setSelectionVisible(true);
updateSystemSelection(); updateSystemSelection();
} }
@ -1046,34 +1031,17 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
* @see Caret#setBlinkRate * @see Caret#setBlinkRate
*/ */
public void setBlinkRate(int rate) { public void setBlinkRate(int rate) {
if (rate < 0) {
throw new IllegalArgumentException("Invalid blink rate: " + rate);
}
if (rate != 0) { if (rate != 0) {
if (component.isEditable()) { if (flasher == null) {
if (flasher == null) { flasher = new Timer(rate, handler);
flasher = new Timer(rate, handler);
}
flasher.setDelay(rate);
if (!flasher.isRunning()){
flasher.restart();
}
} else {
savedBlinkRate = rate;
isBlinkRateSaved = true;
} }
flasher.setDelay(rate);
} else { } else {
if (flasher != null) { if (flasher != null) {
flasher.stop(); flasher.stop();
flasher.removeActionListener(handler); flasher.removeActionListener(handler);
flasher = null; flasher = null;
} }
if (component.isEditable()) {
if (isBlinkRateSaved) {
savedBlinkRate = 0;
isBlinkRateSaved = false;
}
}
} }
} }
@ -1085,9 +1053,6 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
* @see Caret#getBlinkRate * @see Caret#getBlinkRate
*/ */
public int getBlinkRate() { public int getBlinkRate() {
if (isBlinkRateSaved) {
return savedBlinkRate;
}
return (flasher == null) ? 0 : flasher.getDelay(); return (flasher == null) ? 0 : flasher.getDelay();
} }

View File

@ -657,6 +657,8 @@ javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all
javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all
javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all
javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all
javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java 8194048 windows-all
javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java 8213562 linux-all
javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all
javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all
javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-all javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-all

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,17 +21,10 @@
* questions. * questions.
*/ */
import javax.swing.JFrame; import javax.swing.*;
import javax.swing.JMenu; import java.awt.*;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
/** /**
* @test * @test
@ -46,6 +39,7 @@ public class HidingSelectionTest {
private static JTextField field1; private static JTextField field1;
private static JTextField field2; private static JTextField field2;
private static JFrame frame; private static JFrame frame;
private static Rectangle bounds;
private static JMenu menu; private static JMenu menu;
private static JTextField anotherWindow; private static JTextField anotherWindow;
private static Point menuLoc; private static Point menuLoc;
@ -73,9 +67,17 @@ public class HidingSelectionTest {
Robot robot = new Robot(); Robot robot = new Robot();
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
SwingUtilities.invokeAndWait(() -> {
bounds = field2.getBounds();
bounds.setLocation(field2.getLocationOnScreen());
});
BufferedImage nosel = robot.createScreenCapture(bounds);
SwingUtilities.invokeAndWait(field2::requestFocus); SwingUtilities.invokeAndWait(field2::requestFocus);
SwingUtilities.invokeAndWait(field2::selectAll); SwingUtilities.invokeAndWait(field2::selectAll);
robot.waitForIdle();
robot.delay(200);
BufferedImage sel = robot.createScreenCapture(bounds);
SwingUtilities.invokeAndWait(() -> { SwingUtilities.invokeAndWait(() -> {
menuLoc = menu.getLocationOnScreen(); menuLoc = menu.getLocationOnScreen();
@ -87,7 +89,7 @@ public class HidingSelectionTest {
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
if (!field2.getCaret().isSelectionVisible()) { if (!biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException("Test fails: menu hides selection"); throw new RuntimeException("Test fails: menu hides selection");
} }
@ -96,7 +98,7 @@ public class HidingSelectionTest {
SwingUtilities.invokeAndWait(field1::requestFocus); SwingUtilities.invokeAndWait(field1::requestFocus);
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
if (field2.getCaret().isSelectionVisible()) { if (!biEqual(robot.createScreenCapture(bounds), nosel)) {
throw new RuntimeException( throw new RuntimeException(
"Test fails: focus lost doesn't hide selection"); "Test fails: focus lost doesn't hide selection");
} }
@ -117,12 +119,35 @@ public class HidingSelectionTest {
SwingUtilities.invokeAndWait(anotherWindow::requestFocus); SwingUtilities.invokeAndWait(anotherWindow::requestFocus);
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
if (!field2.getCaret().isSelectionVisible()) { if (biEqual(robot.createScreenCapture(bounds), nosel)) {
throw new RuntimeException( throw new RuntimeException(
"Test fails: switch window hides selection"); "Test fails: switch window hides selection");
} }
SwingUtilities.invokeAndWait(anotherWindow::selectAll);
robot.waitForIdle();
robot.delay(200);
if (biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException(
"Test fails: selection ownership is lost selection is shown");
}
SwingUtilities.invokeLater(frame2::dispose); SwingUtilities.invokeLater(frame2::dispose);
SwingUtilities.invokeLater(frame::dispose); SwingUtilities.invokeLater(frame::dispose);
} }
static boolean biEqual(BufferedImage i1, BufferedImage i2) {
if (i1.getWidth() == i2.getWidth() &&
i1.getHeight() == i2.getHeight()) {
for (int x = 0; x < i1.getWidth(); x++) {
for (int y = 0; y < i1.getHeight(); y++) {
if (i1.getRGB(x, y) != i2.getRGB(x, y)) {
return false;
}
}
}
return true;
}
return false;
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,17 +21,10 @@
* questions. * questions.
*/ */
import javax.swing.JFrame; import javax.swing.*;
import javax.swing.JMenu; import java.awt.*;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
/** /**
* @test * @test
@ -47,113 +40,131 @@ public class MultiSelectionTest {
private static JTextField field1; private static JTextField field1;
private static JTextField field2; private static JTextField field2;
private static JFrame frame; private static JFrame frame;
private static Rectangle bounds;
private static JMenu menu; private static JMenu menu;
private static JTextField anotherWindow; private static JTextField anotherWindow;
private static Point menuLoc; private static Point menuLoc;
private static JFrame frame2; private static JFrame frame2;
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
try { SwingUtilities.invokeAndWait(() -> {
SwingUtilities.invokeAndWait(() -> { frame = new JFrame();
frame = new JFrame(); field1 = new JTextField("field1 ");
field1 = new JTextField("field1 "); field2 = new JTextField("field2 ");
field2 = new JTextField("field2 "); field1.setEditable(false);
field1.setEditable(false); field2.setEditable(false);
field2.setEditable(false); frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().setLayout(new FlowLayout()); frame.getContentPane().add(field1);
frame.getContentPane().add(field1); frame.getContentPane().add(field2);
frame.getContentPane().add(field2); JMenuBar menuBar = new JMenuBar();
JMenuBar menuBar = new JMenuBar(); menu = new JMenu("menu");
menu = new JMenu("menu"); menu.add(new JMenuItem("item"));
menu.add(new JMenuItem("item")); menuBar.add(menu);
menuBar.add(menu); frame.setJMenuBar(menuBar);
frame.setJMenuBar(menuBar); frame.pack();
frame.pack(); frame.setVisible(true);
frame.setVisible(true); });
});
Robot robot = new Robot(); Robot robot = new Robot();
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
SwingUtilities.invokeAndWait(() -> {
bounds = field2.getBounds();
bounds.setLocation(field2.getLocationOnScreen());
});
BufferedImage nosel = robot.createScreenCapture(bounds);
SwingUtilities.invokeAndWait(field2::requestFocus); SwingUtilities.invokeAndWait(field2::requestFocus);
SwingUtilities.invokeAndWait(field2::selectAll); SwingUtilities.invokeAndWait(field2::selectAll);
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
BufferedImage sel = robot.createScreenCapture(bounds);
SwingUtilities.invokeAndWait(() -> { SwingUtilities.invokeAndWait(() -> {
menuLoc = menu.getLocationOnScreen(); menuLoc = menu.getLocationOnScreen();
menuLoc.translate(10, 10); menuLoc.translate(10, 10);
}); });
robot.mouseMove(menuLoc.x, menuLoc.y); robot.mouseMove(menuLoc.x, menuLoc.y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(50); robot.delay(50);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle(); robot.waitForIdle();
robot.delay(200); robot.delay(200);
if (!field2.getCaret().isSelectionVisible()) { if (!biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException("Test fails: menu hides selection"); throw new RuntimeException("Test fails: menu hides selection");
}
SwingUtilities.invokeAndWait(
MenuSelectionManager.defaultManager()::clearSelectedPath);
SwingUtilities.invokeAndWait(field1::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (field2.getSelectedText() == null || field2.getSelectedText().length() == 0) {
throw new RuntimeException(
"Test fails: focus lost hides single selection");
}
SwingUtilities.invokeAndWait(field1::selectAll);
robot.waitForIdle();
robot.delay(200);
if (field2.getCaret().isSelectionVisible()) {
throw new RuntimeException(
"Test fails: focus lost doesn't hide selection upon multi selection");
}
SwingUtilities.invokeAndWait(field2::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (!field2.getCaret().isSelectionVisible()) {
throw new RuntimeException(
"Test fails: focus gain hides selection upon multi selection");
}
SwingUtilities.invokeAndWait(field2::requestFocus);
robot.waitForIdle();
SwingUtilities.invokeAndWait(() -> {
frame2 = new JFrame();
Point loc = frame.getLocationOnScreen();
loc.translate(0, frame.getHeight());
frame2.setLocation(loc);
anotherWindow = new JTextField("textField3");
frame2.add(anotherWindow);
frame2.pack();
frame2.setVisible(true);
});
robot.waitForIdle();
SwingUtilities.invokeAndWait(anotherWindow::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (!field2.getCaret().isSelectionVisible()) {
throw new RuntimeException(
"Test fails: switch window hides selection");
}
SwingUtilities.invokeAndWait(anotherWindow::selectAll);
robot.waitForIdle();
robot.delay(200);
if (field2.getCaret().isSelectionVisible()) {
throw new RuntimeException(
"Test fails: selection ownership is lost selection is shown");
}
} finally {
if (frame2 != null) {
SwingUtilities.invokeLater(frame2::dispose);
}
SwingUtilities.invokeLater(frame::dispose);
} }
SwingUtilities.invokeAndWait(
MenuSelectionManager.defaultManager()::clearSelectedPath);
SwingUtilities.invokeAndWait(field1::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (!biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException(
"Test fails: focus lost hides single selection");
}
SwingUtilities.invokeAndWait(field1::selectAll);
robot.waitForIdle();
robot.delay(200);
if (!biEqual(robot.createScreenCapture(bounds), nosel)) {
throw new RuntimeException(
"Test fails: focus lost doesn't hide selection upon multi selection");
}
SwingUtilities.invokeAndWait(field2::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (!biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException(
"Test fails: focus gain hides selection upon multi selection");
}
SwingUtilities.invokeAndWait(field2::requestFocus);
robot.waitForIdle();
SwingUtilities.invokeAndWait(() ->{
frame2 = new JFrame();
Point loc = frame.getLocationOnScreen();
loc.translate(0, frame.getHeight());
frame2.setLocation(loc);
anotherWindow = new JTextField("textField3");
frame2.add(anotherWindow);
frame2.pack();
frame2.setVisible(true);
});
robot.waitForIdle();
SwingUtilities.invokeAndWait(anotherWindow::requestFocus);
robot.waitForIdle();
robot.delay(200);
if (biEqual(robot.createScreenCapture(bounds), nosel)) {
throw new RuntimeException(
"Test fails: switch window hides selection");
}
SwingUtilities.invokeAndWait(anotherWindow::selectAll);
robot.waitForIdle();
robot.delay(200);
if (biEqual(robot.createScreenCapture(bounds), sel)) {
throw new RuntimeException(
"Test fails: selection ownership is lost selection is shown");
}
SwingUtilities.invokeLater(frame2::dispose);
SwingUtilities.invokeLater(frame::dispose);
}
static boolean biEqual(BufferedImage i1, BufferedImage i2) {
if (i1.getWidth() == i2.getWidth() &&
i1.getHeight() == i2.getHeight()) {
for (int x = 0; x < i1.getWidth(); x++) {
for (int y = 0; y < i1.getHeight(); y++) {
if (i1.getRGB(x, y) != i2.getRGB(x, y)) {
return false;
}
}
}
return true;
}
return false;
} }
} }