diff --git a/test/jdk/java/awt/Component/ComponentEventTest.java b/test/jdk/java/awt/Component/ComponentEventTest.java new file mode 100644 index 00000000000..bfbfed336a0 --- /dev/null +++ b/test/jdk/java/awt/Component/ComponentEventTest.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2024, 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. + */ + +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; + +import jdk.test.lib.Platform; + +/* + * @test + * @key headful + * @bug 8333403 + * @summary Test performs various operations to check components events are triggered properly. + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main ComponentEventTest + */ +public class ComponentEventTest { + + private static final int DELAY = 500; + + private static Frame frame; + private static Robot robot; + + private static Component[] components; + + private static volatile Point centerPoint; + + private static volatile boolean componentHidden; + private static volatile boolean componentShown; + private static volatile boolean componentMoved; + private static volatile boolean componentResized; + + private static final ComponentListener componentListener = + new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + System.out.println("ComponentShown: " + e.getSource()); + componentShown = true; + } + + @Override + public void componentResized(ComponentEvent e) { + System.out.println("ComponentResized: " + e.getSource()); + componentResized = true; + } + + @Override + public void componentMoved(ComponentEvent e) { + System.out.println("ComponentMoved: " + e.getSource()); + componentMoved = true; + } + + @Override + public void componentHidden(ComponentEvent e) { + System.out.println("ComponentHidden: " + e.getSource()); + componentHidden = true; + } + }; + + private static void initializeGUI() { + frame = new Frame("Component Event Test"); + frame.setLayout(new FlowLayout()); + + Panel panel = new Panel(); + Button button = new Button("Button"); + Label label = new Label("Label"); + List list = new List(); + list.add("One"); + list.add("Two"); + list.add("Three"); + Choice choice = new Choice(); + choice.add("Red"); + choice.add("Orange"); + choice.add("Yellow"); + Checkbox checkbox = new Checkbox("Checkbox"); + Scrollbar scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255); + TextField textfield = new TextField(15); + TextArea textarea = new TextArea(5, 15); + + components = new Component[] { panel, button, label, list, choice, + checkbox, scrollbar, textfield, textarea, frame }; + + for (int i = 0; i < components.length - 1; i++) { + components[i].addComponentListener(componentListener); + frame.add(components[i]); + } + frame.addComponentListener(componentListener); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + + EventQueue.invokeAndWait(ComponentEventTest::initializeGUI); + robot.waitForIdle(); + robot.delay(DELAY); + + doTest(); + + System.out.println("Test PASSED"); + } finally { + EventQueue.invokeAndWait(ComponentEventTest::disposeFrame); + } + } + + private static void doTest() + throws InvocationTargetException, InterruptedException { + // Click the frame to ensure it gains focus + clickFrame(); + + robot.delay(DELAY); + + for (int i = 0; i < components.length; i++) { + for (boolean state : new boolean[] { true, false }) { + doTest(components[i], state); + } + } + + robot.delay(DELAY); + + System.out.println("Iconify frame"); + resetValues(); + testIconifyFrame(); + + System.out.println("Deiconify frame"); + resetValues(); + testDeiconifyFrame(); + } + + private static void clickFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> { + Point location = frame.getLocationOnScreen(); + Dimension size = frame.getSize(); + centerPoint = new Point(location.x + size.width / 2, + location.y + size.height / 2); + }); + + robot.mouseMove(centerPoint.x, centerPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + private static void testIconifyFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.ICONIFIED)); + + robot.waitForIdle(); + robot.delay(DELAY); + if (componentShown || componentHidden || componentMoved + || componentResized) { + throw new RuntimeException( + "ComponentEvent triggered when frame is iconified"); + } + } + + private static void testDeiconifyFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.NORMAL)); + + robot.waitForIdle(); + robot.delay(DELAY); + + /* + * Because of the different behavior between MS Windows and other OS, we + * receive native events WM_SIZE and WM_MOVE on Windows when the frame + * state changes from iconified to normal. AWT sends these events to + * components when it receives the events from the native system. See + * JDK-6754618 for more information. + */ + + if (componentShown || componentHidden) { + throw new RuntimeException( + "FAIL: componentShown or componentHidden triggered " + + "when frame set to normal"); + } + + if (Platform.isWindows() && (!componentMoved || !componentResized)) { + throw new RuntimeException( + "FAIL: componentMoved or componentResized wasn't triggered " + + "when frame set to normal"); + } + if (!Platform.isWindows() && (componentMoved || componentResized)) { + throw new RuntimeException( + "FAIL: componentMoved or componentResized triggered " + + "when frame set to normal"); + } + } + + private static void doTest(final Component currentComponent, boolean enable) + throws InvocationTargetException, InterruptedException { + + System.out.println("Component " + currentComponent); + System.out.println(" enabled " + enable); + + EventQueue.invokeAndWait(() -> { + currentComponent.setEnabled(enable); + revalidateFrame(); + }); + + robot.delay(DELAY); + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(false); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentHidden) { + throw new RuntimeException("FAIL: ComponentHidden not triggered for" + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(false); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (componentHidden) { + throw new RuntimeException("FAIL: ComponentHidden triggered when " + + "setVisible(false) called for a hidden " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(true); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentShown) { + throw new RuntimeException("FAIL: ComponentShown not triggered for " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(true); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (componentShown) { + throw new RuntimeException("FAIL: ComponentShown triggered when " + + "setVisible(true) called for a shown " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setLocation(currentComponent.getLocation().x + 1, + currentComponent.getLocation().y); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentMoved) { + throw new RuntimeException("FAIL: ComponentMoved not triggered for " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setSize(currentComponent.getSize().width + 1, + currentComponent.getSize().height); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentResized) { + throw new RuntimeException("FAIL: ComponentResized not triggered " + + "when size increases for " + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setSize(currentComponent.getSize().width - 1, + currentComponent.getSize().height); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentResized) { + throw new RuntimeException("FAIL: ComponentResized not triggered " + + "when size decreases for " + currentComponent.getClass()); + } + + System.out.println("\n"); + } + + private static void revalidateFrame() { + frame.invalidate(); + frame.validate(); + } + + private static void resetValues() { + componentShown = false; + componentHidden = false; + componentMoved = false; + componentResized = false; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + } + } +}