55
55
import java .util .concurrent .atomic .AtomicInteger ;
56
56
57
57
import javax .imageio .ImageIO ;
58
+ import javax .swing .Box ;
58
59
import javax .swing .JButton ;
59
60
import javax .swing .JComboBox ;
60
61
import javax .swing .JComponent ;
157
158
* <li>the title of the instruction UI,</li>
158
159
* <li>the timeout of the test,</li>
159
160
* <li>the size of the instruction UI via rows and columns, and</li>
161
+ * <li>to add a log area</li>,
160
162
* <li>to enable screenshots.</li>
161
163
* </ul>
162
164
*/
@@ -206,6 +208,8 @@ public final class PassFailJFrame {
206
208
207
209
private static Robot robot ;
208
210
211
+ private static JTextArea logArea ;
212
+
209
213
public enum Position {HORIZONTAL , VERTICAL , TOP_LEFT_CORNER }
210
214
211
215
public PassFailJFrame (String instructions ) throws InterruptedException ,
@@ -375,6 +379,20 @@ private static void invokeOnEDT(Runnable doRun)
375
379
}
376
380
}
377
381
382
+ /**
383
+ * Does the same as {@link #invokeOnEDT(Runnable)}, but does not throw
384
+ * any checked exceptions.
385
+ *
386
+ * @param doRun an operation to run on EDT
387
+ */
388
+ private static void invokeOnEDTUncheckedException (Runnable doRun ) {
389
+ try {
390
+ invokeOnEDT (doRun );
391
+ } catch (InterruptedException | InvocationTargetException e ) {
392
+ throw new RuntimeException (e );
393
+ }
394
+ }
395
+
378
396
private static void createUI (String title , String instructions ,
379
397
long testTimeOut , int rows , int columns ,
380
398
boolean enableScreenCapture ) {
@@ -386,7 +404,8 @@ private static void createUI(String title, String instructions,
386
404
frame .add (createInstructionUIPanel (instructions ,
387
405
testTimeOut ,
388
406
rows , columns ,
389
- enableScreenCapture ),
407
+ enableScreenCapture ,
408
+ false , 0 ),
390
409
BorderLayout .CENTER );
391
410
frame .pack ();
392
411
frame .setLocationRelativeTo (null );
@@ -403,8 +422,9 @@ private static void createUI(Builder builder) {
403
422
createInstructionUIPanel (builder .instructions ,
404
423
builder .testTimeOut ,
405
424
builder .rows , builder .columns ,
406
- builder .screenCapture );
407
-
425
+ builder .screenCapture ,
426
+ builder .addLogArea ,
427
+ builder .logAreaRows );
408
428
if (builder .splitUI ) {
409
429
JSplitPane splitPane = new JSplitPane (
410
430
builder .splitUIOrientation ,
@@ -423,7 +443,9 @@ private static void createUI(Builder builder) {
423
443
private static JComponent createInstructionUIPanel (String instructions ,
424
444
long testTimeOut ,
425
445
int rows , int columns ,
426
- boolean enableScreenCapture ) {
446
+ boolean enableScreenCapture ,
447
+ boolean addLogArea ,
448
+ int logAreaRows ) {
427
449
JPanel main = new JPanel (new BorderLayout ());
428
450
timeoutHandlerPanel = new TimeoutHandlerPanel (testTimeOut );
429
451
main .add (timeoutHandlerPanel , BorderLayout .NORTH );
@@ -455,7 +477,20 @@ private static JComponent createInstructionUIPanel(String instructions,
455
477
buttonsPanel .add (createCapturePanel ());
456
478
}
457
479
458
- main .add (buttonsPanel , BorderLayout .SOUTH );
480
+ if (addLogArea ) {
481
+ logArea = new JTextArea (logAreaRows , columns );
482
+ logArea .setEditable (false );
483
+
484
+ Box buttonsLogPanel = Box .createVerticalBox ();
485
+
486
+ buttonsLogPanel .add (buttonsPanel );
487
+ buttonsLogPanel .add (new JScrollPane (logArea ));
488
+
489
+ main .add (buttonsLogPanel , BorderLayout .SOUTH );
490
+ } else {
491
+ main .add (buttonsPanel , BorderLayout .SOUTH );
492
+ }
493
+
459
494
main .setMinimumSize (main .getPreferredSize ());
460
495
461
496
return main ;
@@ -1074,13 +1109,45 @@ public static void forceFail(String reason) {
1074
1109
latch .countDown ();
1075
1110
}
1076
1111
1112
+ /**
1113
+ * Adds a {@code message} to the log area, if enabled by
1114
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1115
+ *
1116
+ * @param message to log
1117
+ */
1118
+ public static void log (String message ) {
1119
+ System .out .println ("PassFailJFrame: " + message );
1120
+ invokeOnEDTUncheckedException (() -> logArea .append (message + "\n " ));
1121
+ }
1122
+
1123
+ /**
1124
+ * Clears the log area, if enabled by
1125
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1126
+ */
1127
+ public static void logClear () {
1128
+ System .out .println ("\n PassFailJFrame: log cleared\n " );
1129
+ invokeOnEDTUncheckedException (() -> logArea .setText ("" ));
1130
+ }
1131
+
1132
+ /**
1133
+ * Replaces the log area content with provided {@code text}, if enabled by
1134
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1135
+ * @param text new text for the log area
1136
+ */
1137
+ public static void logSet (String text ) {
1138
+ System .out .println ("\n PassFailJFrame: log set to:\n " + text + "\n " );
1139
+ invokeOnEDTUncheckedException (() -> logArea .setText (text ));
1140
+ }
1141
+
1077
1142
public static final class Builder {
1078
1143
private String title ;
1079
1144
private String instructions ;
1080
1145
private long testTimeOut ;
1081
1146
private int rows ;
1082
1147
private int columns ;
1083
1148
private boolean screenCapture ;
1149
+ private boolean addLogArea ;
1150
+ private int logAreaRows = 10 ;
1084
1151
1085
1152
private List <? extends Window > testWindows ;
1086
1153
private WindowListCreator windowListCreator ;
@@ -1122,6 +1189,37 @@ public Builder screenCapture() {
1122
1189
return this ;
1123
1190
}
1124
1191
1192
+ /**
1193
+ * Adds a log area below the "Pass", "Fail" buttons.
1194
+ * <p>
1195
+ * The log area can be controlled by {@link #log(String)},
1196
+ * {@link #logClear()} and {@link #logSet(String)}.
1197
+ *
1198
+ * @return this builder
1199
+ */
1200
+ public Builder logArea () {
1201
+ this .addLogArea = true ;
1202
+ return this ;
1203
+ }
1204
+
1205
+ /**
1206
+ * Adds a log area below the "Pass", "Fail" buttons.
1207
+ * <p>
1208
+ * The log area can be controlled by {@link #log(String)},
1209
+ * {@link #logClear()} and {@link #logSet(String)}.
1210
+ * <p>
1211
+ * The number of columns is taken from the number of
1212
+ * columns in the instructional JTextArea.
1213
+ *
1214
+ * @param rows of the log area
1215
+ * @return this builder
1216
+ */
1217
+ public Builder logArea (int rows ) {
1218
+ this .addLogArea = true ;
1219
+ this .logAreaRows = rows ;
1220
+ return this ;
1221
+ }
1222
+
1125
1223
/**
1126
1224
* Adds a {@code WindowCreator} which the framework will use
1127
1225
* to create the test UI window.
0 commit comments