Skip to content

Commit 447f10d

Browse files
committed
interaction: improve textual visualization of the model
1 parent 4a3d27d commit 447f10d

File tree

1 file changed

+74
-4
lines changed

1 file changed

+74
-4
lines changed

lib/src/main/java/jtamaro/interaction/ModelFrame.java

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,42 @@
11
package jtamaro.interaction;
22

3+
import java.awt.Font;
4+
import java.awt.Insets;
35
import java.awt.event.WindowAdapter;
46
import java.awt.event.WindowEvent;
7+
import java.lang.reflect.InvocationTargetException;
8+
import java.lang.reflect.Method;
9+
import java.util.Arrays;
10+
import java.util.logging.Level;
11+
import java.util.logging.Logger;
12+
import java.util.stream.Collectors;
13+
import javax.swing.BorderFactory;
514
import javax.swing.JFrame;
615
import javax.swing.JScrollPane;
716
import javax.swing.JTextArea;
817
import jtamaro.data.Sequence;
918

1019
final class ModelFrame<M> extends JFrame {
1120

12-
private final JTextArea textArea;
21+
private static final Logger LOGGER = Logger.getLogger(ModelFrame.class.getName());
22+
23+
private static final String EOL = System.lineSeparator();
1324

1425
public ModelFrame(Interaction<M> bang, Trace<M> trace) {
1526
super();
1627
setTitle("Model");
17-
textArea = new JTextArea(3, 40);
18-
add(new JScrollPane(textArea));
28+
final JTextArea textArea = new JTextArea();
29+
textArea.setMargin(new Insets(8, 8, 8, 8));
30+
textArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
31+
textArea.setEditable(false);
32+
textArea.setFocusable(false);
33+
final JScrollPane scrollPane = new JScrollPane(textArea);
34+
scrollPane.setBorder(BorderFactory.createEmptyBorder());
35+
add(scrollPane);
1936

2037
final TraceListener tl = ev -> {
2138
final M model = getLastModel(trace.getEventSequence(), bang.getInitialModel());
22-
textArea.setText(model.toString());
39+
textArea.setText(prettyPrint(model, 0));
2340
};
2441
// Load current model
2542
tl.eventAppended(null);
@@ -40,4 +57,57 @@ private M getLastModel(Sequence<TraceEvent<M>> events, M model) {
4057
? model
4158
: events.first().process(getLastModel(events.rest(), model));
4259
}
60+
61+
private String prettyPrint(Object obj, int indent) {
62+
return switch (obj) {
63+
case Sequence<?> seq -> prettyPrintSequence(seq, indent + 1);
64+
case Record rec -> prettyPrintRecord(rec, indent + 1);
65+
default -> obj.toString();
66+
};
67+
}
68+
69+
private String prettyPrintSequence(Sequence<?> seq, int indent) {
70+
final String prefix = " ".repeat(indent) + "• ";
71+
return seq.map(it -> prefix + prettyPrint(it, indent))
72+
.reduce("", (it, acc) -> acc + EOL + it);
73+
}
74+
75+
private String prettyPrintRecord(Record rec, int indent) {
76+
final Class<?> clazz = rec.getClass();
77+
final String recName = clazz.getSimpleName();
78+
final String prefix = " ".repeat(indent) + "• ";
79+
80+
final String contents = Arrays.stream(clazz.getRecordComponents()).map(component -> {
81+
final String compName = component.getName();
82+
final StringBuilder compSb = new StringBuilder()
83+
.append(prefix)
84+
.append(compName)
85+
.append(": ");
86+
try {
87+
final Method accessor = component.getAccessor();
88+
final boolean isAccessible = accessor.canAccess(rec);
89+
if (!isAccessible) {
90+
accessor.setAccessible(true);
91+
}
92+
93+
compSb.append(prettyPrint(accessor.invoke(rec), indent));
94+
95+
if (!isAccessible) {
96+
accessor.setAccessible(false);
97+
}
98+
} catch (IllegalAccessException | InvocationTargetException e) {
99+
LOGGER.log(Level.WARNING, "Failed to read component"
100+
+ compName
101+
+ " of record class "
102+
+ recName, e);
103+
compSb.append("???");
104+
}
105+
106+
return compSb.toString();
107+
}).collect(Collectors.joining(EOL));
108+
109+
return recName
110+
+ EOL
111+
+ contents;
112+
}
43113
}

0 commit comments

Comments
 (0)