diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 15a914934e7..b7a0f58a2f8 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -63,6 +63,7 @@ import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; import javax.swing.text.JTextComponent; @@ -114,6 +115,13 @@ import static javax.swing.SwingUtilities.isEventDispatchThread; * or a list of windows if the test needs multiple windows, * or directly a single window, an array of windows or a list of windows. *
+ * For simple test UI, use {@code Builder.splitUI}, or explicitly + * {@code Builder.splitUIRight} or {@code Builder.splitUIBottom} with + * a {@code PanelCreator}. The framework will call the provided + * {@code createUIPanel} to create the component with test UI and + * will place it as the right or bottom component in a split pane + * along with instruction UI. + *
* Alternatively, use one of the {@code PassFailJFrame} constructors to * create an object, then create secondary test UI, register it * with {@code PassFailJFrame}, position it and make it visible. @@ -166,6 +174,14 @@ public final class PassFailJFrame { */ private static final String EMPTY_REASON = "(no reason provided)"; + /** + * List of windows or frames managed by the {@code PassFailJFrame} + * framework. These windows are automatically disposed of when the + * test is finished. + *
+ * Note: access to this field has to be synchronized by
+ * {@code PassFailJFrame.class}.
+ */
private static final List
+ * This method is called by the framework on the EDT.
+ * @return a component (panel) with test UI
+ */
+ JComponent createUIPanel();
+ }
+
/**
* Positions test UI windows.
*/
@@ -634,10 +731,12 @@ public final class PassFailJFrame {
break;
case WINDOWS:
- windowList.stream()
- .filter(Window::isShowing)
- .map(Window::getBounds)
- .forEach(PassFailJFrame::captureScreen);
+ synchronized (PassFailJFrame.class) {
+ windowList.stream()
+ .filter(Window::isShowing)
+ .map(Window::getBounds)
+ .forEach(PassFailJFrame::captureScreen);
+ }
break;
default:
@@ -950,6 +1049,9 @@ public final class PassFailJFrame {
private List extends Window> testWindows;
private WindowListCreator windowListCreator;
+ private PanelCreator panelCreator;
+ private boolean splitUI;
+ private int splitUIOrientation;
private PositionWindows positionWindows;
private InstructionUI instructionUIHandler;
@@ -1090,8 +1192,102 @@ public final class PassFailJFrame {
}
}
- public Builder positionTestUI(PositionWindows positionWindows) {
- this.positionWindows = positionWindows;
+ /**
+ * Adds a {@code PanelCreator} which the framework will use
+ * to create a component and place it into a dialog.
+ *
+ * @param panelCreator a {@code PanelCreator} to create a component
+ * with test UI
+ * @return this builder
+ * @throws IllegalStateException if split UI was enabled using
+ * a {@code splitUI} method
+ */
+ public Builder testUI(PanelCreator panelCreator) {
+ if (splitUI) {
+ throw new IllegalStateException("Can't combine splitUI and "
+ + "testUI with panelCreator");
+ }
+ this.panelCreator = panelCreator;
+ return this;
+ }
+
+ /**
+ * Adds a {@code PanelCreator} which the framework will use
+ * to create a component with test UI and display it in a split pane.
+ *
+ * By default, horizontal orientation is used,
+ * and test UI is displayed to the right of the instruction UI.
+ *
+ * @param panelCreator a {@code PanelCreator} to create a component
+ * with test UI
+ * @return this builder
+ *
+ * @throws IllegalStateException if a {@code PanelCreator} is
+ * already set
+ * @throws IllegalArgumentException if {panelCreator} is {@code null}
+ */
+ public Builder splitUI(PanelCreator panelCreator) {
+ return splitUIRight(panelCreator);
+ }
+
+ /**
+ * Adds a {@code PanelCreator} which the framework will use
+ * to create a component with test UI and display it
+ * to the right of instruction UI.
+ *
+ * @param panelCreator a {@code PanelCreator} to create a component
+ * with test UI
+ * @return this builder
+ *
+ * @throws IllegalStateException if a {@code PanelCreator} is
+ * already set
+ * @throws IllegalArgumentException if {panelCreator} is {@code null}
+ */
+ public Builder splitUIRight(PanelCreator panelCreator) {
+ return splitUI(panelCreator, JSplitPane.HORIZONTAL_SPLIT);
+ }
+
+ /**
+ * Adds a {@code PanelCreator} which the framework will use
+ * to create a component with test UI and display it
+ * in the bottom of instruction UI.
+ *
+ * @param panelCreator a {@code PanelCreator} to create a component
+ * with test UI
+ * @return this builder
+ *
+ * @throws IllegalStateException if a {@code PanelCreator} is
+ * already set
+ * @throws IllegalArgumentException if {panelCreator} is {@code null}
+ */
+ public Builder splitUIBottom(PanelCreator panelCreator) {
+ return splitUI(panelCreator, JSplitPane.VERTICAL_SPLIT);
+ }
+
+ /**
+ * Enables split UI and stores the orientation of the split pane.
+ *
+ * @param panelCreator a {@code PanelCreator} to create a component
+ * with test UI
+ * @param splitUIOrientation orientation of the split pane
+ * @return this builder
+ *
+ * @throws IllegalStateException if a {@code PanelCreator} is
+ * already set
+ * @throws IllegalArgumentException if {panelCreator} is {@code null}
+ */
+ private Builder splitUI(PanelCreator panelCreator,
+ int splitUIOrientation) {
+ if (panelCreator == null) {
+ throw new IllegalArgumentException("A PanelCreator cannot be null");
+ }
+ if (this.panelCreator != null) {
+ throw new IllegalStateException("A PanelCreator is already set");
+ }
+
+ splitUI = true;
+ this.splitUIOrientation = splitUIOrientation;
+ this.panelCreator = panelCreator;
return this;
}
@@ -1129,15 +1325,24 @@ public final class PassFailJFrame {
}
if (position == null
- && (testWindows != null || windowListCreator != null)) {
+ && (testWindows != null || windowListCreator != null
+ || (!splitUI && panelCreator != null))) {
position = Position.HORIZONTAL;
}
+ if (panelCreator != null) {
+ if (splitUI && (testWindows != null || windowListCreator != null)) {
+ // TODO Is it required? We can support both
+ throw new IllegalStateException("Split UI is not allowed "
+ + "with additional windows");
+ }
+ }
+
if (positionWindows != null) {
if (testWindows == null && windowListCreator == null) {
throw new IllegalStateException("To position windows, "
- + "provide an a list of windows to the builder");
+ + "provide a list of windows to the builder");
}
instructionUIHandler = new InstructionUIHandler();
}
@@ -1176,6 +1381,11 @@ public final class PassFailJFrame {
}
}
+ /**
+ * Creates a builder for configuring {@code PassFailJFrame}.
+ *
+ * @return the builder for configuring {@code PassFailJFrame}
+ */
public static Builder builder() {
return new Builder();
}