Skip to content

Commit fead629

Browse files
author
duke
committed
Backport 4b7906375b4bd11a480665110561180825c2dd9c
1 parent 682c939 commit fead629

File tree

4 files changed

+701
-0
lines changed

4 files changed

+701
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright (c) 2002, 2024, 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 4060975
26+
* @summary tests that a component doesn't lose focus on resize
27+
* @library /java/awt/regtesthelpers
28+
* @build PassFailJFrame
29+
* @run main/manual FocusChangeOnResizeTest
30+
*/
31+
32+
import java.util.List;
33+
34+
import java.awt.Button;
35+
import java.awt.Dialog;
36+
import java.awt.Frame;
37+
import java.awt.GridLayout;
38+
import java.awt.Panel;
39+
import java.awt.TextField;
40+
import java.awt.Window;
41+
import java.awt.event.ActionEvent;
42+
import java.awt.event.ActionListener;
43+
import java.awt.event.FocusEvent;
44+
import java.awt.event.FocusListener;
45+
46+
public class FocusChangeOnResizeTest {
47+
48+
private static final String INSTRUCTIONS = """
49+
For the Frame and the Dialog:
50+
Press the LOWER BUTTON to resize the Frame or Dialog programmatically.
51+
Give the focus to the LOWER BUTTON and resize the Frame or Dialog manually.
52+
If the LOWER BUTTON always has focus after resize
53+
(for both frame and dialog) the test passes.""";
54+
55+
public static void main(String[] args) throws Exception {
56+
PassFailJFrame.builder()
57+
.title("PopupMenu Instructions")
58+
.instructions(INSTRUCTIONS)
59+
.rows((int) INSTRUCTIONS.lines().count() + 2)
60+
.columns(35)
61+
.testUI(FocusChangeOnResizeTest::createTestUI)
62+
.logArea()
63+
.build()
64+
.awaitAndCheck();
65+
}
66+
67+
private static List<Window> createTestUI() {
68+
Frame frame = new Frame("FocusChangeOnResizeTest frame");
69+
Dialog dialog = new Dialog(frame, "Test dialog");
70+
frame.add(new TestPanel(frame));
71+
dialog.add(new TestPanel(dialog));
72+
frame.setBounds (150, 200, 200, 200);
73+
dialog.setBounds (150, 500, 200, 200);
74+
return List.of(frame, dialog);
75+
}
76+
77+
static FocusListener eventLogger = new FocusListener() {
78+
public void focusGained(FocusEvent e) {
79+
PassFailJFrame.log(e.toString());
80+
}
81+
public void focusLost(FocusEvent e) {
82+
PassFailJFrame.log(e.toString());
83+
}
84+
};
85+
}
86+
87+
class TestPanel extends Panel {
88+
89+
TextField textField = new TextField("TEXT FIELD");
90+
Button button1 = new Button("UPPER BUTTON");
91+
Button button2 = new Button("LOWER BUTTON");
92+
93+
public TestPanel(Window parent) {
94+
setLayout(new GridLayout(3, 1));
95+
add(textField);
96+
add(button1);
97+
add(button2);
98+
textField.setName("TEXT FIELD");
99+
button1.setName("UPPER BUTTON");
100+
button2.setName("LOWER BUTTON");
101+
textField.addFocusListener(FocusChangeOnResizeTest.eventLogger);
102+
button1.addFocusListener(FocusChangeOnResizeTest.eventLogger);
103+
button2.addFocusListener(FocusChangeOnResizeTest.eventLogger);
104+
105+
button2.addActionListener(new Resizer(parent));
106+
}
107+
}
108+
109+
class Resizer implements ActionListener {
110+
Window target;
111+
112+
public Resizer(Window window) {
113+
target = window;
114+
}
115+
116+
public void actionPerformed(ActionEvent e) {
117+
target.setSize(200, 100);
118+
target.doLayout();
119+
target.pack();
120+
}
121+
}
122+
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/*
2+
* Copyright (c) 1999, 2024, 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 4124119
26+
* @summary Checks that lightweight components do not lose focus after
27+
dragging the frame by using the mouse.
28+
* @library /java/awt/regtesthelpers
29+
* @build PassFailJFrame
30+
* @run main/manual LightweightFocusLostTest
31+
*/
32+
33+
import java.awt.AWTEvent;
34+
import java.awt.AWTEventMulticaster;
35+
import java.awt.BorderLayout;
36+
import java.awt.Component;
37+
import java.awt.Cursor;
38+
import java.awt.Label;
39+
import java.awt.Dimension;
40+
import java.awt.Font;
41+
import java.awt.FontMetrics;
42+
import java.awt.Frame;
43+
import java.awt.Graphics;
44+
import java.awt.SystemColor;
45+
import java.awt.event.ActionEvent;
46+
import java.awt.event.ActionListener;
47+
import java.awt.event.FocusAdapter;
48+
import java.awt.event.FocusEvent;
49+
import java.awt.event.KeyAdapter;
50+
import java.awt.event.KeyEvent;
51+
import java.awt.event.MouseAdapter;
52+
import java.awt.event.MouseEvent;
53+
54+
55+
public class LightweightFocusLostTest {
56+
57+
private static final String INSTRUCTIONS = """
58+
Steps to try to reproduce this problem:
59+
When this test is run a window will display (Test Focus).
60+
Click in the text field to give it the focus (a blinking cursor
61+
will appear) and then move the frame with the mouse. The text field
62+
(component which uses a lightweight component) should still have focus.
63+
You should still see the blinking cursor in the text field after the
64+
frame has been moved. If this is the behavior that you observe, the
65+
test has passed, Press the Pass button. Otherwise the test has failed,
66+
Press the Fail button.""";
67+
68+
69+
public static void main(String[] args) throws Exception {
70+
PassFailJFrame.builder()
71+
.title("LightweightFocusLostTest Instructions")
72+
.instructions(INSTRUCTIONS)
73+
.rows((int) INSTRUCTIONS.lines().count() + 5)
74+
.columns(35)
75+
.testUI(LightweightFocusLostTest::createTestUI)
76+
.logArea()
77+
.build()
78+
.awaitAndCheck();
79+
}
80+
81+
private static Frame createTestUI() {
82+
Frame f = new Frame("LightweightFocusLostTest");
83+
f.setLayout(new BorderLayout());
84+
String sLabel = "Lightweight component below (text field)";
85+
Label TFL = new Label(sLabel, Label.LEFT);
86+
f.add(TFL, BorderLayout.NORTH);
87+
SimpleTextField canvas = new SimpleTextField(30, 5);
88+
f.add(canvas, BorderLayout.CENTER);
89+
f.setSize(new Dimension(300,125));
90+
f.requestFocus();
91+
return f;
92+
93+
}
94+
95+
}
96+
97+
class SimpleTextField extends Component implements Runnable {
98+
int border;
99+
int length;
100+
Font font;
101+
FontMetrics fontM;
102+
char[] buffer;
103+
int bufferIx;
104+
105+
boolean hasFocus;
106+
boolean cursorOn;
107+
108+
SimpleTextField(int len, int bor) {
109+
super();
110+
border = bor;
111+
length = len;
112+
buffer = new char[len];
113+
font = getFont();
114+
if (font == null) {
115+
font = new Font("Dialog", Font.PLAIN, 20);
116+
}
117+
fontM = getFontMetrics(font);
118+
119+
// Listen for key and mouse events.
120+
this.addMouseListener(new MouseEventHandler());
121+
this.addFocusListener(new FocusEventHandler());
122+
this.addKeyListener(new KeyEventHandler());
123+
124+
// Set text cursor.
125+
setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
126+
127+
// Start the thread that blinks the cursor.
128+
(new Thread(this)).start();
129+
}
130+
131+
public Dimension getMinimumSize() {
132+
// The minimum height depends on the point size.
133+
int w = fontM.charWidth('m') * length;
134+
return new Dimension(w + 2 * border, fontM.getHeight() + 2 * border);
135+
}
136+
public Dimension getPreferredSize() {
137+
return getMinimumSize();
138+
}
139+
public Dimension getMaximumSize() {
140+
return new Dimension(Short.MAX_VALUE, getPreferredSize().height);
141+
}
142+
143+
public boolean isFocusTraversable() {
144+
return true;
145+
}
146+
147+
public void paint(Graphics g) {
148+
int y = (getSize().height-fontM.getHeight())/2;
149+
150+
// Clear the background using the text background color.
151+
g.setColor(SystemColor.text);
152+
g.fillRect(0, 0, getSize().width, getSize().height);
153+
154+
g.setFont(font);
155+
g.setColor(SystemColor.textText);
156+
g.drawChars(buffer, 0, bufferIx, border, y + fontM.getAscent());
157+
158+
// Draw blinking cursor.
159+
int x = fontM.charsWidth(buffer, 0, bufferIx) + border;
160+
int w = fontM.charWidth('c');
161+
if (hasFocus) {
162+
g.setColor(getForeground());
163+
g.fillRect(x, y, w, fontM.getHeight());
164+
if (cursorOn) {
165+
if (bufferIx < buffer.length) {
166+
g.setColor(SystemColor.text);
167+
g.fillRect(x + 2, y + 2, w - 4, fontM.getHeight() - 4);
168+
}
169+
}
170+
}
171+
}
172+
173+
// Event handlers
174+
class MouseEventHandler extends MouseAdapter {
175+
public void mousePressed(MouseEvent evt) {
176+
requestFocus();
177+
}
178+
}
179+
class FocusEventHandler extends FocusAdapter {
180+
public void focusGained(FocusEvent evt) {
181+
PassFailJFrame.log("Focus gained: " + evt);
182+
183+
hasFocus = true;
184+
repaint();
185+
}
186+
public void focusLost(FocusEvent evt) {
187+
PassFailJFrame.log("Focus lost: " + evt);
188+
hasFocus = false;
189+
repaint();
190+
}
191+
}
192+
class KeyEventHandler extends KeyAdapter {
193+
public void keyPressed(KeyEvent evt) {
194+
switch (evt.getKeyCode()) {
195+
case KeyEvent.VK_DELETE:
196+
case KeyEvent.VK_BACK_SPACE:
197+
if (bufferIx > 0) {
198+
bufferIx--;
199+
repaint();
200+
}
201+
break;
202+
case KeyEvent.VK_ENTER:
203+
ActionEvent action =
204+
new ActionEvent(SimpleTextField.this,
205+
ActionEvent.ACTION_PERFORMED,
206+
String.valueOf(buffer, 0, bufferIx));
207+
// Send contents of buffer to listeners
208+
processEvent(action);
209+
break;
210+
default:
211+
repaint();
212+
}
213+
}
214+
public void keyTyped(KeyEvent evt) {
215+
if (bufferIx < buffer.length
216+
&& !evt.isActionKey()
217+
&& !Character.isISOControl(evt.getKeyChar())) {
218+
buffer[bufferIx++] = evt.getKeyChar();
219+
}
220+
}
221+
}
222+
223+
// Support for Action Listener.
224+
ActionListener actionListener;
225+
226+
public void addActionListener(ActionListener l) {
227+
actionListener = AWTEventMulticaster.add(actionListener, l);
228+
}
229+
230+
// Override processEvent() to deal with ActionEvent.
231+
protected void processEvent(AWTEvent evt) {
232+
if (evt instanceof ActionEvent) {
233+
processActionEvent((ActionEvent)evt);
234+
} else {
235+
super.processEvent(evt);
236+
}
237+
}
238+
239+
// Supply method to process Action event.
240+
protected void processActionEvent(ActionEvent evt) {
241+
if (actionListener != null) {
242+
actionListener.actionPerformed(evt);
243+
}
244+
}
245+
246+
public void run() {
247+
while (true) {
248+
try {
249+
// If component has focus, blink the cursor every 1/2 second.
250+
Thread.sleep(500);
251+
cursorOn = !cursorOn;
252+
if (hasFocus) {
253+
repaint();
254+
}
255+
} catch (Exception e) {
256+
e.printStackTrace();
257+
}
258+
}
259+
}
260+
}
261+

0 commit comments

Comments
 (0)