From 4fea31ec03e2afe1116438e88f4875898c32c2f6 Mon Sep 17 00:00:00 2001
From: "t.ogata" <ogata.toshitaka@fujitsu.com>
Date: Thu, 24 Oct 2024 07:51:59 +0000
Subject: [PATCH] 8328242: Add a log area to the PassFailJFrame

Backport-of: 9bc1b065db238b7c9d0562f9bd55d2f338c6ff3d
---
 .../awt/regtesthelpers/PassFailJFrame.java    | 108 +++++++++++++++++-
 1 file changed, 103 insertions(+), 5 deletions(-)

diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
index 1aa83339701..50656c0f2cc 100644
--- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
+++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java
@@ -54,6 +54,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.imageio.ImageIO;
+import javax.swing.Box;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
@@ -156,6 +157,7 @@ import static javax.swing.SwingUtilities.isEventDispatchThread;
  *     <li>the title of the instruction UI,</li>
  *     <li>the timeout of the test,</li>
  *     <li>the size of the instruction UI via rows and columns, and</li>
+ *     <li>to add a log area</li>,
  *     <li>to enable screenshots.</li>
  * </ul>
  */
@@ -205,6 +207,8 @@ public final class PassFailJFrame {
 
     private static Robot robot;
 
+    private static JTextArea logArea;
+
     public enum Position {HORIZONTAL, VERTICAL, TOP_LEFT_CORNER}
 
     public PassFailJFrame(String instructions) throws InterruptedException,
@@ -374,6 +378,20 @@ public final class PassFailJFrame {
         }
     }
 
+    /**
+     * Does the same as {@link #invokeOnEDT(Runnable)}, but does not throw
+     * any checked exceptions.
+     *
+     * @param doRun an operation to run on EDT
+     */
+    private static void invokeOnEDTUncheckedException(Runnable doRun) {
+        try {
+            invokeOnEDT(doRun);
+        } catch (InterruptedException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static void createUI(String title, String instructions,
                                  long testTimeOut, int rows, int columns,
                                  boolean enableScreenCapture) {
@@ -385,7 +403,8 @@ public final class PassFailJFrame {
         frame.add(createInstructionUIPanel(instructions,
                                            testTimeOut,
                                            rows, columns,
-                                           enableScreenCapture),
+                                           enableScreenCapture,
+                                           false, 0),
                   BorderLayout.CENTER);
         frame.pack();
         frame.setLocationRelativeTo(null);
@@ -402,8 +421,9 @@ public final class PassFailJFrame {
                 createInstructionUIPanel(builder.instructions,
                                          builder.testTimeOut,
                                          builder.rows, builder.columns,
-                                         builder.screenCapture);
-
+                                         builder.screenCapture,
+                                         builder.addLogArea,
+                                         builder.logAreaRows);
         if (builder.splitUI) {
             JSplitPane splitPane = new JSplitPane(
                     builder.splitUIOrientation,
@@ -422,7 +442,9 @@ public final class PassFailJFrame {
     private static JComponent createInstructionUIPanel(String instructions,
                                                        long testTimeOut,
                                                        int rows, int columns,
-                                                       boolean enableScreenCapture) {
+                                                       boolean enableScreenCapture,
+                                                       boolean addLogArea,
+                                                       int logAreaRows) {
         JPanel main = new JPanel(new BorderLayout());
         timeoutHandlerPanel = new TimeoutHandlerPanel(testTimeOut);
         main.add(timeoutHandlerPanel, BorderLayout.NORTH);
@@ -454,7 +476,20 @@ public final class PassFailJFrame {
             buttonsPanel.add(createCapturePanel());
         }
 
-        main.add(buttonsPanel, BorderLayout.SOUTH);
+        if (addLogArea) {
+            logArea = new JTextArea(logAreaRows, columns);
+            logArea.setEditable(false);
+
+            Box buttonsLogPanel = Box.createVerticalBox();
+
+            buttonsLogPanel.add(buttonsPanel);
+            buttonsLogPanel.add(new JScrollPane(logArea));
+
+            main.add(buttonsLogPanel, BorderLayout.SOUTH);
+        } else {
+            main.add(buttonsPanel, BorderLayout.SOUTH);
+        }
+
         main.setMinimumSize(main.getPreferredSize());
 
         return main;
@@ -1072,6 +1107,36 @@ public final class PassFailJFrame {
         latch.countDown();
     }
 
+    /**
+     * Adds a {@code message} to the log area, if enabled by
+     * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
+     *
+     * @param message to log
+     */
+    public static void log(String message) {
+        System.out.println("PassFailJFrame: " + message);
+        invokeOnEDTUncheckedException(() -> logArea.append(message + "\n"));
+    }
+
+    /**
+     * Clears the log area, if enabled by
+     * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
+     */
+    public static void logClear() {
+        System.out.println("\nPassFailJFrame: log cleared\n");
+        invokeOnEDTUncheckedException(() -> logArea.setText(""));
+    }
+
+    /**
+     * Replaces the log area content with provided {@code text}, if enabled by
+     * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
+     * @param text new text for the log area
+     */
+    public static void logSet(String text) {
+        System.out.println("\nPassFailJFrame: log set to:\n" + text + "\n");
+        invokeOnEDTUncheckedException(() -> logArea.setText(text));
+    }
+
     public static final class Builder {
         private String title;
         private String instructions;
@@ -1079,6 +1144,8 @@ public final class PassFailJFrame {
         private int rows;
         private int columns;
         private boolean screenCapture;
+        private boolean addLogArea;
+        private int logAreaRows = 10;
 
         private List<? extends Window> testWindows;
         private WindowListCreator windowListCreator;
@@ -1120,6 +1187,37 @@ public final class PassFailJFrame {
             return this;
         }
 
+        /**
+         * Adds a log area below the "Pass", "Fail" buttons.
+         * <p>
+         * The log area can be controlled by {@link #log(String)},
+         * {@link #logClear()} and {@link #logSet(String)}.
+         *
+         * @return this builder
+         */
+        public Builder logArea() {
+            this.addLogArea = true;
+            return this;
+        }
+
+        /**
+         * Adds a log area below the "Pass", "Fail" buttons.
+         * <p>
+         * The log area can be controlled by {@link #log(String)},
+         * {@link #logClear()} and {@link #logSet(String)}.
+         * <p>
+         * The number of columns is taken from the number of
+         * columns in the instructional JTextArea.
+         *
+         * @param rows of the log area
+         * @return this builder
+         */
+        public Builder logArea(int rows) {
+            this.addLogArea = true;
+            this.logAreaRows = rows;
+            return this;
+        }
+
         /**
          * Adds a {@code WindowCreator} which the framework will use
          * to create the test UI window.
-- 
GitLab