From 094cd261aef11446c9a50819bb29f37570467dd1 Mon Sep 17 00:00:00 2001 From: Andrew Lu Date: Thu, 24 Aug 2023 17:01:58 +0000 Subject: [PATCH] 8307078: Opensource and clean up five more AWT Focus related tests Backport-of: 6d6f726b74f7fcd3e7c37d50bd2476b3e921662b --- .../Focus/FocusForRemovedComponentTest.java | 154 +++++++ .../awt/Focus/FocusTraversalPolicyIAE.java | 73 +++ test/jdk/java/awt/Focus/InitialFocusTest.java | 144 ++++++ .../java/awt/Focus/LabelScrollBarFocus.java | 180 ++++++++ .../Focus/ModalDialogInFocusEventTest.java | 414 ++++++++++++++++++ 5 files changed, 965 insertions(+) create mode 100644 test/jdk/java/awt/Focus/FocusForRemovedComponentTest.java create mode 100644 test/jdk/java/awt/Focus/FocusTraversalPolicyIAE.java create mode 100644 test/jdk/java/awt/Focus/InitialFocusTest.java create mode 100644 test/jdk/java/awt/Focus/LabelScrollBarFocus.java create mode 100644 test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java diff --git a/test/jdk/java/awt/Focus/FocusForRemovedComponentTest.java b/test/jdk/java/awt/Focus/FocusForRemovedComponentTest.java new file mode 100644 index 0000000000..c53db9c20d --- /dev/null +++ b/test/jdk/java/awt/Focus/FocusForRemovedComponentTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004, 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4722671 + @summary Accessibility problem in JRE Finder + @key headful + @run main FocusForRemovedComponentTest +*/ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class FocusForRemovedComponentTest + implements ActionListener { + static int ACTIVATION_TIMEOUT = 2000; + static long WAIT_TIMEOUT = 3000; + volatile Frame frame; + volatile Button btnFirst; + volatile Button btnSecond; + volatile Button btnThird; + + public void start() throws InterruptedException, InvocationTargetException { + try { + EventQueue.invokeAndWait(() -> { + frame = new Frame("FocusForRemovedComponentTest"); + btnFirst = new Button("First Button"); + btnSecond = new Button("Second Button"); + btnThird = new Button("Third Button"); + frame.add(btnFirst, BorderLayout.NORTH); + frame.add(btnSecond, BorderLayout.CENTER); + btnFirst.addActionListener(this); + btnFirst.requestFocusInWindow(); + frame.pack(); + frame.setVisible(true); + }); + + try { + Robot robot = new Robot(); + robot.delay(ACTIVATION_TIMEOUT); + int[] location = new int[2]; + EventQueue.invokeAndWait(() -> { + Point button_location = btnFirst.getLocationOnScreen(); + Dimension button_size = btnFirst.getSize(); + location[0] = button_location.x + button_size.width / 2; + location[1] = button_location.y + button_size.height / 2; + }); + robot.mouseMove(location[0], location[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + Object monitor = new Object(); + final MonitoredFocusListener monitorer = new MonitoredFocusListener(monitor); + AtomicBoolean isFocused = new AtomicBoolean(false); + synchronized (monitor) { + EventQueue.invokeAndWait(() -> { + btnThird.addFocusListener(monitorer); + isFocused.set(btnThird.isFocusOwner()); + }); + + if (!isFocused.get()) { + monitor.wait(WAIT_TIMEOUT); + EventQueue.invokeAndWait(() -> { + isFocused.set(btnThird.isFocusOwner()); + }); + } + } + + if (!isFocused.get()) { + throw new RuntimeException("TEST FAILED. The third button is not focus owner."); + } else { + System.out.println("TEST PASSED."); + } + } catch (AWTException e) { + e.printStackTrace(); + throw new RuntimeException("Some AWTException occurred."); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException("Test was interrupted."); + } + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } + + public void actionPerformed(ActionEvent e) { + if (btnSecond.isVisible()) { + btnFirst.setEnabled(false); + frame.remove(btnSecond); + frame.add(btnThird, BorderLayout.CENTER); + btnThird.requestFocusInWindow(); + btnFirst.setEnabled(true); + frame.validate(); + frame.repaint(); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + FocusForRemovedComponentTest test = new FocusForRemovedComponentTest(); + test.start(); + } +} + +class MonitoredFocusListener extends FocusAdapter { + Object monitor; + + public MonitoredFocusListener(Object monitor) { + this.monitor = monitor; + } + + public void focusGained(FocusEvent fe) { + synchronized (monitor) { + monitor.notify(); + } + } +} diff --git a/test/jdk/java/awt/Focus/FocusTraversalPolicyIAE.java b/test/jdk/java/awt/Focus/FocusTraversalPolicyIAE.java new file mode 100644 index 0000000000..c48fe83d81 --- /dev/null +++ b/test/jdk/java/awt/Focus/FocusTraversalPolicyIAE.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 6225100 + @summary FocusTraversalPolicy.getInitialComponent does not work as expected + @run main FocusTraversalPolicyIAE +*/ + +import java.awt.Component; +import java.awt.Container; +import java.awt.FocusTraversalPolicy; + +public class FocusTraversalPolicyIAE { + public static void main(String[] args) { + CustomFocusTraversalPolicy cftp = new CustomFocusTraversalPolicy(); + try { + cftp.getInitialComponent(null); + throw new RuntimeException("Test failed. No exceptions thrown."); + } catch (IllegalArgumentException iae) { + System.out.println("Test passed."); + } catch (NullPointerException npe) { + throw new RuntimeException("Test failed. Unexpected NPE thrown: " + npe); + } catch (Exception e) { + throw new RuntimeException("Test failed. Unexpected exception thrown: " + e); + } + } +} + +class CustomFocusTraversalPolicy extends FocusTraversalPolicy { + public Component getComponentAfter(Container focusCycleRoot, + Component aComponent) { + return null; + } + + public Component getComponentBefore(Container focusCycleRoot, + Component aComponent) { + return null; + } + + public Component getDefaultComponent(Container focusCycleRoot) { + return null; + } + + public Component getFirstComponent(Container focusCycleRoot) { + return null; + } + + public Component getLastComponent(Container focusCycleRoot) { + return null; + } +} diff --git a/test/jdk/java/awt/Focus/InitialFocusTest.java b/test/jdk/java/awt/Focus/InitialFocusTest.java new file mode 100644 index 0000000000..489cdd7c7f --- /dev/null +++ b/test/jdk/java/awt/Focus/InitialFocusTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2002, 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4150021 + @summary if user requests focus on some component, it must become a focus owner after activation + @key headful + @run main InitialFocusTest +*/ + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.DefaultKeyboardFocusManager; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class InitialFocusTest implements PropertyChangeListener { + //Declare things used in the test, like buttons and labels here + final static String FOCUSED_WINDOW_PROP = "focusedWindow"; + final static int ACTION_TIMEOUT = 2000; + + volatile Frame frame; + volatile Button btn1; + volatile Button btn2; + + public void start() throws InterruptedException, InvocationTargetException { + DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager(). + addPropertyChangeListener(FOCUSED_WINDOW_PROP, this); + try { + EventQueue.invokeAndWait(() -> { + frame = new Frame("InitialFocusTest"); + frame.setLayout(new FlowLayout()); + btn1 = new Button("First Button"); + frame.add(btn1); + btn2 = new Button("Second Button"); + frame.add(btn2); + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setVisible(true); + }); + try { + Robot robot = new Robot(); + robot.delay(ACTION_TIMEOUT); + if (!activateFrame(frame, robot, ACTION_TIMEOUT)) { + throw new RuntimeException("Frame was not activated."); + } + robot.delay(ACTION_TIMEOUT); + AtomicBoolean isFocused = new AtomicBoolean(false); + EventQueue.invokeAndWait(() -> { + isFocused.set(frame.isFocused()); + }); + if (!isFocused.get()) { + throw new RuntimeException("Frame didn't become focused."); + } + EventQueue.invokeAndWait(() -> { + isFocused.set(btn2.isFocusOwner()); + }); + if (!isFocused.get()) { + throw new RuntimeException("Btn2 didn't receive focus."); + } + } catch (AWTException e) { + e.printStackTrace(); + } + System.out.printf("Test passed."); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } + + public void propertyChange(PropertyChangeEvent pce) { + if (FOCUSED_WINDOW_PROP.equals(pce.getPropertyName())) { + if (pce.getNewValue() == frame) { + System.out.println("requesting focus on btn2"); + btn2.requestFocusInWindow(); + } + } + } + + boolean activateFrame(Frame frame, Robot robot, int timeout) + throws InterruptedException, InvocationTargetException { + AtomicBoolean isActive = new AtomicBoolean(false); + EventQueue.invokeAndWait(() -> { + isActive.set(frame.isActive()); + }); + if (!isActive.get()) { + int[] point = new int[2]; + EventQueue.invokeAndWait(() -> { + Point origin = frame.getLocationOnScreen(); + Dimension dim = frame.getSize(); + Insets insets = frame.getInsets(); + point[0] = origin.x + dim.width / 2; + point[1] = origin.y + insets.top / 2; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(timeout); + EventQueue.invokeAndWait(() -> { + isActive.set(frame.isActive()); + }); + } + return frame.isActive(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + InitialFocusTest test = new InitialFocusTest(); + test.start(); + } +} diff --git a/test/jdk/java/awt/Focus/LabelScrollBarFocus.java b/test/jdk/java/awt/Focus/LabelScrollBarFocus.java new file mode 100644 index 0000000000..c69d9406ea --- /dev/null +++ b/test/jdk/java/awt/Focus/LabelScrollBarFocus.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2002, 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4027897 + @summary Test that Label can't be made focused by the mouse, while ScrollBar should become focused. + @key headful + @run main LabelScrollBarFocus +*/ + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class LabelScrollBarFocus extends Panel { + static final Semaphore sema = new Semaphore(); + Label lab; + Scrollbar scr; + static Frame frame; + + public void init() { + this.setLayout(new FlowLayout()); + FocusAdapter fa = new FocusAdapter() { + public void focusGained(FocusEvent e) { + sema.raise(); + } + }; + + lab = new Label("Label"); + scr = new Scrollbar(Scrollbar.HORIZONTAL); + lab.addFocusListener(fa); + scr.addFocusListener(fa); + add(lab); + add(scr); + setSize(200, 200); + validate(); + setVisible(true); + } + + public void start() throws InterruptedException, + InvocationTargetException { + Robot robot = null; + try { + robot = new Robot(); + } catch (Exception e) { + throw new RuntimeException("Can't create robot instance"); + } + int[] point = new int[2]; + EventQueue.invokeAndWait(() -> { + Point labLoc = lab.getLocationOnScreen(); + point[0] = labLoc.x + 5; + point[1] = labLoc.y + 5; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.waitForIdle(); + try { + sema.doWait(2000); + } catch (InterruptedException ie) { + throw new RuntimeException("Interrupted"); + } + + AtomicBoolean isFocusOwner = new AtomicBoolean(false); + EventQueue.invokeAndWait(() -> { + isFocusOwner.set(lab.isFocusOwner()); + }); + if (isFocusOwner.get()) { + throw new RuntimeException("Label is focused"); + } + + EventQueue.invokeAndWait(() -> { + Point scrLoc = scr.getLocationOnScreen(); + point[0] = scrLoc.x + 20; + point[1] = scrLoc.y + 5; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.waitForIdle(); + try { + sema.doWait(2000); + } catch (InterruptedException ie) { + throw new RuntimeException("Interrupted"); + } + + EventQueue.invokeAndWait(() -> { + isFocusOwner.set(scr.isFocusOwner()); + }); + if (!isFocusOwner.get()) { + throw new RuntimeException("Scroll bar is not focused"); + } + System.out.println("Test passed"); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + try { + LabelScrollBarFocus test = new LabelScrollBarFocus(); + EventQueue.invokeAndWait(() -> { + frame = new Frame("LabelScrollBarFocus"); + test.init(); + frame.setLayout(new BorderLayout()); + frame.add(test, BorderLayout.CENTER); + frame.setLocationRelativeTo(null); + frame.pack(); + frame.setVisible(true); + }); + test.start(); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } +} + +class Semaphore { + boolean state = false; + Object lock = new Object(); + int waiting = 0; + + public Semaphore() { + } + + public void doWait(int timeout) throws InterruptedException { + synchronized (lock) { + waiting++; + synchronized (this) { + wait(timeout); + } + waiting--; + } + } + + public void raise() { + synchronized (lock) { + state = true; + if (waiting > 0) { + synchronized (this) { + notifyAll(); + } + } + } + } +} diff --git a/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java b/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java new file mode 100644 index 0000000000..d4f0d65f07 --- /dev/null +++ b/test/jdk/java/awt/Focus/ModalDialogInFocusEventTest.java @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2002, 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + test + @bug 4531693 4636269 4681908 4688142 4691646 4721470 + @summary Showing modal dialog during dispatching SequencedEvent + @key headful + @run main AutomaticAppletTest +*/ + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import java.awt.event.WindowListener; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ModalDialogInFocusEventTest + implements ActionListener, Runnable, WindowListener, + WindowFocusListener, FocusListener { + static final int CLICK_DELAY = 50; + static final int ACTIVATION_TIMEOUT = 2000; + static final long STAGE_TIMEOUT = 3 * ACTIVATION_TIMEOUT; + static final StageInfo[] stages = { + new StageInfo(WindowEvent.WINDOW_ACTIVATED, "Window Activated", false), + new StageInfo(WindowEvent.WINDOW_GAINED_FOCUS, "Window Gained Focus", false), + new StageInfo(FocusEvent.FOCUS_GAINED, "Focus Gained", false), + new StageInfo(FocusEvent.FOCUS_LOST, "Focus Lost", true), + new StageInfo(WindowEvent.WINDOW_LOST_FOCUS, "Window Lost Focus", true), + new StageInfo(WindowEvent.WINDOW_DEACTIVATED, "Window Deactivated", true) + }; + static final int MAX_STAGE_NUM = stages.length; + static final Object stageMonitor = new Object(); + + Robot robot = null; + Frame frame; + Frame oppositeFrame; + Dialog dialog; + Button closeButton; + int nStage = MAX_STAGE_NUM; + + public void start() throws InterruptedException, InvocationTargetException { + try { + FocusListener focusEventTracker = new FocusListener() { + public void focusGained(FocusEvent e) { + System.out.println(e); + } + + public void focusLost(FocusEvent e) { + System.out.println(e); + } + }; + + WindowAdapter windowEventTracker = new WindowAdapter() { + public void windowActivated(WindowEvent e) { + System.out.println(e); + } + + public void windowDeactivated(WindowEvent e) { + System.out.println(e); + } + + public void windowGainedFocus(WindowEvent e) { + System.out.println(e); + } + + public void windowLostFocus(WindowEvent e) { + System.out.println(e); + } + }; + EventQueue.invokeAndWait(() -> { + frame = new Frame("ModalDialogInFocusEventTest Main Frame"); + oppositeFrame = new Frame("ModalDialogInFocusEventTest Opposite Frame"); + dialog = new Dialog(frame, "ModalDialogInFocusEventTest Modal Dialog", true); + closeButton = new Button("Close Button"); + closeButton.addActionListener(this); + dialog.add(closeButton); + dialog.setBounds(10, 200, 300, 100); + + dialog.addFocusListener(focusEventTracker); + dialog.addWindowListener(windowEventTracker); + dialog.addWindowFocusListener(windowEventTracker); + oppositeFrame.addFocusListener(focusEventTracker); + oppositeFrame.addWindowListener(windowEventTracker); + oppositeFrame.addWindowFocusListener(windowEventTracker); + + frame.setName("ModalDialogInFocusEventTest MainFrame"); + frame.addFocusListener(this); + frame.addWindowListener(this); + frame.addWindowFocusListener(this); + frame.setSize(300, 100); + + oppositeFrame.setName("ModalDialogInFocusEventTest OppositeName"); + oppositeFrame.setBounds(350, 200, 300, 100); + }); + + + try { + robot = new Robot(); + robot.setAutoDelay(CLICK_DELAY); + + for (int i = 0; i < MAX_STAGE_NUM; i++) { + StageInfo stage = stages[i]; + if (stage.shouldActivateOpposite()) { + EventQueue.invokeAndWait(() -> { + oppositeFrame.setVisible(true); + frame.setVisible(true); + }); + robot.delay(ACTIVATION_TIMEOUT); + AtomicBoolean isActive = new AtomicBoolean(false); + EventQueue.invokeAndWait(() -> { + isActive.set(frame.isActive()); + }); + if (!isActive.get()) { + clickOnFrameTitle(frame); + robot.delay(ACTIVATION_TIMEOUT); + } + } else { + EventQueue.invokeAndWait(() -> { + frame.setVisible(true); + oppositeFrame.setVisible(true); + }); + robot.delay(ACTIVATION_TIMEOUT); + AtomicBoolean isActive = new AtomicBoolean(false); + EventQueue.invokeAndWait(() -> { + isActive.set(oppositeFrame.isActive()); + }); + if (!isActive.get()) { + clickOnFrameTitle(oppositeFrame); + robot.delay(ACTIVATION_TIMEOUT); + } + } + + nStage = i; + System.out.println("Stage " + i + " started."); + + synchronized (stageMonitor) { + if (stage.shouldActivateOpposite()) { + clickOnFrameTitle(oppositeFrame); + } else { + clickOnFrameTitle(frame); + } + stageMonitor.wait(STAGE_TIMEOUT); + if (!stage.isFinished()) { + throw new RuntimeException(stages[nStage].toString()); + } + } + EventQueue.invokeAndWait(() -> { + oppositeFrame.setVisible(false); + frame.setVisible(false); + }); + robot.delay(ACTIVATION_TIMEOUT); + } + } catch (AWTException e) { + throw new RuntimeException("Some AWT-Robot problem occurred", e); + } catch (InterruptedException ie) { + ie.printStackTrace(); + throw new RuntimeException("Test was interrupted"); + } + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + if (oppositeFrame != null) { + EventQueue.invokeAndWait(oppositeFrame::dispose); + } + if (dialog != null) { + EventQueue.invokeAndWait(dialog::dispose); + } + } + System.out.println("Test passed."); + } + + void clickOnFrameTitle(Frame frame) throws InterruptedException, + InvocationTargetException { + System.out.println("click on title of " + frame.getName()); + int[] point = new int[2]; + EventQueue.invokeAndWait(() -> { + Point location = frame.getLocationOnScreen(); + Insets insets = frame.getInsets(); + int width = frame.getWidth(); + point[0] = location.x + width / 2; + point[1] = location.y + insets.top / 2; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + EventQueue.invokeAndWait(frame::requestFocusInWindow); + } + + void openAndCloseModalDialog() throws InterruptedException, + InvocationTargetException { + (new Thread(this)).start(); + dialog.setVisible(true); + } + + void performStage(AWTEvent e) throws InterruptedException, + InvocationTargetException { + if (nStage < MAX_STAGE_NUM && + e.getID() == stages[nStage].getEventID() && + !stages[nStage].isStarted()) { + stages[nStage].start(); + openAndCloseModalDialog(); + stages[nStage].finish(); + synchronized (stageMonitor) { + stageMonitor.notifyAll(); + } + } + } + + public void actionPerformed(ActionEvent ae) { + System.out.println(ae); + dialog.setVisible(false); + } + + public void run() { + try { + Thread.sleep(ACTIVATION_TIMEOUT); + int[] point = new int[2]; + EventQueue.invokeAndWait(() -> { + Point location = closeButton.getLocationOnScreen(); + Dimension dim = closeButton.getSize(); + point[0] = location.x + dim.width / 2; + point[1] = location.y + dim.height / 2; + }); + robot.mouseMove(point[0], point[1]); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + System.out.println("click"); + } catch (InterruptedException | InvocationTargetException ie) { + throw new RuntimeException("Test was interrupted", ie); + } + } + + public void windowOpened(WindowEvent e) { + /* Empty. Unneeded for this test */ + } + + public void windowClosing(WindowEvent e) { + /* Empty. Unneeded for this test */ + } + + public void windowClosed(WindowEvent e) { + /* Empty. Unneeded for this test */ + } + + public void windowIconified(WindowEvent e) { + /* Empty. Unneeded for this test */ + } + + public void windowDeiconified(WindowEvent e) { + /* Empty. Unneeded for this test */ + } + + public void windowActivated(WindowEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public void windowDeactivated(WindowEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public void windowGainedFocus(WindowEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public void windowLostFocus(WindowEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public void focusGained(FocusEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public void focusLost(FocusEvent e) { + System.out.println(e); + try { + performStage(e); + } catch (InterruptedException | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + ModalDialogInFocusEventTest test = new ModalDialogInFocusEventTest(); + test.start(); + } +} + +class StageInfo { + private String name; + private int eventID; + private boolean started = false; + private boolean finished = false; + + /* + * whether we should activate opposite frame during this stage. + * Note: we need to activate "another" frame BEFORE stage + * i.e. if we should activate frame during stage then we + * need to activate oppositeFrame before it and vice versa. + */ + private boolean activateOpposite; + + StageInfo(int eventID, String name, boolean activateOpposite) { + this.eventID = eventID; + this.name = name; + this.activateOpposite = activateOpposite; + } + + public String toString() { + String str = "Stage [\"" + name + "\""; + if (!started) { + str += " not"; + } + str += " started, "; + if (!finished) { + str += " not"; + } + str += " finished"; + if (activateOpposite) { + str += ", activate opposite"; + } + str += "]"; + return str; + } + + int getEventID() { + return eventID; + } + + boolean isStarted() { + return started; + } + + void start() { + started = true; + System.out.println(this.toString()); + } + + boolean isFinished() { + return finished; + } + + void finish() { + finished = true; + System.out.println(this.toString()); + } + + boolean shouldActivateOpposite() { + return activateOpposite; + } +}