54
54
import java .util .concurrent .atomic .AtomicInteger ;
55
55
56
56
import javax .imageio .ImageIO ;
57
+ import javax .swing .Box ;
57
58
import javax .swing .JButton ;
58
59
import javax .swing .JComboBox ;
59
60
import javax .swing .JComponent ;
156
157
* <li>the title of the instruction UI,</li>
157
158
* <li>the timeout of the test,</li>
158
159
* <li>the size of the instruction UI via rows and columns, and</li>
160
+ * <li>to add a log area</li>,
159
161
* <li>to enable screenshots.</li>
160
162
* </ul>
161
163
*/
@@ -205,6 +207,8 @@ public final class PassFailJFrame {
205
207
206
208
private static Robot robot ;
207
209
210
+ private static JTextArea logArea ;
211
+
208
212
public enum Position {HORIZONTAL , VERTICAL , TOP_LEFT_CORNER }
209
213
210
214
public PassFailJFrame (String instructions ) throws InterruptedException ,
@@ -374,6 +378,20 @@ private static void invokeOnEDT(Runnable doRun)
374
378
}
375
379
}
376
380
381
+ /**
382
+ * Does the same as {@link #invokeOnEDT(Runnable)}, but does not throw
383
+ * any checked exceptions.
384
+ *
385
+ * @param doRun an operation to run on EDT
386
+ */
387
+ private static void invokeOnEDTUncheckedException (Runnable doRun ) {
388
+ try {
389
+ invokeOnEDT (doRun );
390
+ } catch (InterruptedException | InvocationTargetException e ) {
391
+ throw new RuntimeException (e );
392
+ }
393
+ }
394
+
377
395
private static void createUI (String title , String instructions ,
378
396
long testTimeOut , int rows , int columns ,
379
397
boolean enableScreenCapture ) {
@@ -385,7 +403,8 @@ private static void createUI(String title, String instructions,
385
403
frame .add (createInstructionUIPanel (instructions ,
386
404
testTimeOut ,
387
405
rows , columns ,
388
- enableScreenCapture ),
406
+ enableScreenCapture ,
407
+ false , 0 ),
389
408
BorderLayout .CENTER );
390
409
frame .pack ();
391
410
frame .setLocationRelativeTo (null );
@@ -402,8 +421,9 @@ private static void createUI(Builder builder) {
402
421
createInstructionUIPanel (builder .instructions ,
403
422
builder .testTimeOut ,
404
423
builder .rows , builder .columns ,
405
- builder .screenCapture );
406
-
424
+ builder .screenCapture ,
425
+ builder .addLogArea ,
426
+ builder .logAreaRows );
407
427
if (builder .splitUI ) {
408
428
JSplitPane splitPane = new JSplitPane (
409
429
builder .splitUIOrientation ,
@@ -422,7 +442,9 @@ private static void createUI(Builder builder) {
422
442
private static JComponent createInstructionUIPanel (String instructions ,
423
443
long testTimeOut ,
424
444
int rows , int columns ,
425
- boolean enableScreenCapture ) {
445
+ boolean enableScreenCapture ,
446
+ boolean addLogArea ,
447
+ int logAreaRows ) {
426
448
JPanel main = new JPanel (new BorderLayout ());
427
449
428
450
JLabel testTimeoutLabel = new JLabel ("" , JLabel .CENTER );
@@ -456,7 +478,20 @@ private static JComponent createInstructionUIPanel(String instructions,
456
478
buttonsPanel .add (createCapturePanel ());
457
479
}
458
480
459
- main .add (buttonsPanel , BorderLayout .SOUTH );
481
+ if (addLogArea ) {
482
+ logArea = new JTextArea (logAreaRows , columns );
483
+ logArea .setEditable (false );
484
+
485
+ Box buttonsLogPanel = Box .createVerticalBox ();
486
+
487
+ buttonsLogPanel .add (buttonsPanel );
488
+ buttonsLogPanel .add (new JScrollPane (logArea ));
489
+
490
+ main .add (buttonsLogPanel , BorderLayout .SOUTH );
491
+ } else {
492
+ main .add (buttonsPanel , BorderLayout .SOUTH );
493
+ }
494
+
460
495
main .setMinimumSize (main .getPreferredSize ());
461
496
462
497
return main ;
@@ -1041,13 +1076,45 @@ public static void forceFail(String reason) {
1041
1076
latch .countDown ();
1042
1077
}
1043
1078
1079
+ /**
1080
+ * Adds a {@code message} to the log area, if enabled by
1081
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1082
+ *
1083
+ * @param message to log
1084
+ */
1085
+ public static void log (String message ) {
1086
+ System .out .println ("PassFailJFrame: " + message );
1087
+ invokeOnEDTUncheckedException (() -> logArea .append (message + "\n " ));
1088
+ }
1089
+
1090
+ /**
1091
+ * Clears the log area, if enabled by
1092
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1093
+ */
1094
+ public static void logClear () {
1095
+ System .out .println ("\n PassFailJFrame: log cleared\n " );
1096
+ invokeOnEDTUncheckedException (() -> logArea .setText ("" ));
1097
+ }
1098
+
1099
+ /**
1100
+ * Replaces the log area content with provided {@code text}, if enabled by
1101
+ * {@link Builder#logArea()} or {@link Builder#logArea(int)}.
1102
+ * @param text new text for the log area
1103
+ */
1104
+ public static void logSet (String text ) {
1105
+ System .out .println ("\n PassFailJFrame: log set to:\n " + text + "\n " );
1106
+ invokeOnEDTUncheckedException (() -> logArea .setText (text ));
1107
+ }
1108
+
1044
1109
public static final class Builder {
1045
1110
private String title ;
1046
1111
private String instructions ;
1047
1112
private long testTimeOut ;
1048
1113
private int rows ;
1049
1114
private int columns ;
1050
1115
private boolean screenCapture ;
1116
+ private boolean addLogArea ;
1117
+ private int logAreaRows = 10 ;
1051
1118
1052
1119
private List <? extends Window > testWindows ;
1053
1120
private WindowListCreator windowListCreator ;
@@ -1097,6 +1164,37 @@ public Builder screenCapture() {
1097
1164
return this ;
1098
1165
}
1099
1166
1167
+ /**
1168
+ * Adds a log area below the "Pass", "Fail" buttons.
1169
+ * <p>
1170
+ * The log area can be controlled by {@link #log(String)},
1171
+ * {@link #logClear()} and {@link #logSet(String)}.
1172
+ *
1173
+ * @return this builder
1174
+ */
1175
+ public Builder logArea () {
1176
+ this .addLogArea = true ;
1177
+ return this ;
1178
+ }
1179
+
1180
+ /**
1181
+ * Adds a log area below the "Pass", "Fail" buttons.
1182
+ * <p>
1183
+ * The log area can be controlled by {@link #log(String)},
1184
+ * {@link #logClear()} and {@link #logSet(String)}.
1185
+ * <p>
1186
+ * The number of columns is taken from the number of
1187
+ * columns in the instructional JTextArea.
1188
+ *
1189
+ * @param rows of the log area
1190
+ * @return this builder
1191
+ */
1192
+ public Builder logArea (int rows ) {
1193
+ this .addLogArea = true ;
1194
+ this .logAreaRows = rows ;
1195
+ return this ;
1196
+ }
1197
+
1100
1198
/**
1101
1199
* Adds a {@code WindowCreator} which the framework will use
1102
1200
* to create the test UI window.
0 commit comments