diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 45cd191ae39..5a9e7671e39 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -170,6 +170,11 @@ public final class PassFailJFrame { private static final int ROWS = 10; private static final int COLUMNS = 40; + /** + * A gap between windows. + */ + public static final int WINDOW_GAP = 8; + /** * Prefix for the user-provided failure reason. */ @@ -1007,13 +1012,13 @@ private static void positionInstructionFrame(final Position position) { switch (position) { case HORIZONTAL: - int newX = ((screenSize.width / 2) - frame.getWidth()); + int newX = (((screenSize.width + WINDOW_GAP) / 2) - frame.getWidth()); frame.setLocation((newX + screenInsets.left), (frame.getY() + screenInsets.top)); break; case VERTICAL: - int newY = ((screenSize.height / 2) - frame.getHeight()); + int newY = (((screenSize.height + WINDOW_GAP) / 2) - frame.getHeight()); frame.setLocation((frame.getX() + screenInsets.left), (newY + screenInsets.top)); break; @@ -1061,13 +1066,13 @@ public static void positionTestWindow(Window testWindow, Position position) { switch (position) { case HORIZONTAL: case TOP_LEFT_CORNER: - testWindow.setLocation((frame.getX() + frame.getWidth() + 5), + testWindow.setLocation((frame.getX() + frame.getWidth() + WINDOW_GAP), frame.getY()); break; case VERTICAL: testWindow.setLocation(frame.getX(), - (frame.getY() + frame.getHeight() + 5)); + (frame.getY() + frame.getHeight() + WINDOW_GAP)); break; } } @@ -1370,6 +1375,7 @@ public Builder testUI(WindowCreator windowCreator) { return this; } + /** * Adds an implementation of {@link PositionWindows PositionWindows} * which the framework will use to position multiple test UI windows. @@ -1393,6 +1399,77 @@ public Builder positionTestUI(PositionWindows positionWindows) { return this; } + /** + * Positions the test UI windows in a row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightRow() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneRow); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightColumn() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumn); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame centering the stack of the windows. + * + * @return this builder + */ + public Builder positionTestUIRightColumnCentered() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumnCentered); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomRow() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRow); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame centering the row of the windows. + * + * @return this builder + */ + public Builder positionTestUIBottomRowCentered() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRowCentered); + } + + /** + * Positions the test UI windows in a column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomColumn() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneColumn); + } + + /** * Adds a {@code WindowListCreator} which the framework will use * to create a list of test UI windows. @@ -1495,6 +1572,7 @@ public Builder testUI(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. diff --git a/test/jdk/java/awt/regtesthelpers/WindowLayouts.java b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java new file mode 100644 index 00000000000..4368e3a5943 --- /dev/null +++ b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, 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.Component; +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Window; +import java.util.List; + +import static java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment; +import static java.awt.Toolkit.getDefaultToolkit; + +/** + * A utility class which provides standard window layouts for multi-window + * manual tests using the {@link PassFailJFrame} framework. + * The layout methods {@code right-} and {@code bottom-} implement the + * {@link PassFailJFrame.PositionWindows PositionWindows} interface and + * can be used directly or via builder methods. + *

+ * There are several helper methods, such as + * {@link #getScreenCenter() getScreenCenter}, which could help you + * implement customized windows layouts. + */ +public final class WindowLayouts { + + /** Private constructor to prevent instantiating the utility class. */ + private WindowLayouts() { + } + + /** A gap between windows. (Local copy makes expressions shorter.) */ + private static final int WINDOW_GAP = PassFailJFrame.WINDOW_GAP; + + /** + * Lays out the window list in one row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame centering the stack of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumnCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + getScreenCenter().y + - getWindowListHeight(windows) / 2, + windows); + } + + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame centering the row of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRowCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(getScreenCenter().x + - getWindowListWidth(windows) / 2, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + + /** + * Lays out the window list in one row starting at + * ({@code x0}, {@code y}). + * + * @param x0 the starting x coordinate of the windows + * @param y the y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutRow(final int x0, + final int y, + final List windows) { + int x = x0; + for (Window w : windows) { + w.setLocation(x, y); + x += w.getWidth() + WINDOW_GAP; + } + } + + /** + * Lays out the window list in one column starting at + * ({@code x}, {@code y0}). + * + * @param x the x coordinate of the windows + * @param y0 the starting y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutColumn(final int x, + final int y0, + final List windows) { + int y = y0; + for (Window w : windows) { + w.setLocation(x, y); + y += w.getHeight() + WINDOW_GAP; + } + } + + + /** + * {@return the center point of the main screen} + */ + public static Point getScreenCenter() { + GraphicsConfiguration gc = getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + Dimension size = gc.getBounds() + .getSize(); + Insets insets = getDefaultToolkit() + .getScreenInsets(gc); + + return new Point((size.width - insets.left - insets.right) / 2, + (size.height - insets.top - insets.bottom) / 2); + } + + /** + * {@return width of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the width of + */ + public static int getWindowListWidth(final List windows) { + return windows.stream() + .mapToInt(Component::getWidth) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } + + /** + * {@return height of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the height of + */ + public static int getWindowListHeight(final List windows) { + return windows.stream() + .mapToInt(Component::getHeight) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } +}