srecord noeq G22JavaObjectVisualizer(G22Utils g22utils) is Swingable { settable bool withTypeAndTime = true; settable bool singleLineLayout; // TODO settable int maxElements = 1000; // max elements of collection to show settable bool horizontal; Set seen = identityHashSet(); transient settable O object; transient settable long nanos = -1; transient new LinkedHashMap properties; *(G22Utils *g22utils, O *object) {} cachedVisualize { new LS infos; JComponent c = visualizeObject(object); if (withTypeAndTime) { infos.add(shortClassName(object)); for (key, val : properties) { S s = n2OrStrOrNull(val); if (nempty(s)) infos.add(key + " " + s); } } if (withTypeAndTime) { S type = joinNemptiesWithComma(infos); S timeDesc = nanos < 0 ? "" : formatElapsedTimeWithAppropriateUnit(nanosToSeconds(nanos)); c = northAndCenterWithMargins( westAndEastWithMargin( withLabel("Type:", jlabel(type)), empty(timeDesc) ? jpanel() : withLabel("Execution time:", jlabel(timeDesc)) ), c); } ret c; } JComponent visualizeObject(O object) { ret mainVisualizer().visualize(object); } ObjectVisualizer mainVisualizer() { ret new ObjectVisualizer().recurse(true).bigFont(true).horizontal(horizontal); } class ObjectVisualizer { settable bool recurse; settable bool bigFont; settable bool horizontal; // only one recursion level so far ObjectVisualizer subVisualizer() { ret new ObjectVisualizer; } JComponent makeBig(JComponent c) { if (bigFont) ret fontSizePlus(10, c); ret c; } JComponent visualize(O object) { try { ret visualize2(object); } catch e { ret jErrorView(new RuntimeException("Visualization error", e)); } } JComponent visualize2(O object) { // exception if (object cast Throwable) ret jErrorView(object); // null or empty string if (object == null || eq(object, "")) ret jpanel(); // Swing component if (object cast Swingable) object = object.visualize(); if (object cast JComponent && getParent(object) == null) ret object; // number if (object cast Int) object = toLong(object); if (object cast Long) ret makeBig(jcenteredLabel(n2(object))); if (object cast Number) ret makeBig(jcenteredLabel(str(object))); if (object cast Pair) { ret jcenteredline(jlabel("<"), visualize(object.a), jlabel(","), visualize(object.b), jlabel("<")); } // image if (object cast MakesBufferedImage) object = toBufferedImage(object); if (object cast BufferedImage) { var is = g22utils.stdImageSurface(object); if (!recurse) is.setAutoZoomToDisplay(false); ret jscroll_centered_borderless(is); } if (recurse) { // TODO if (!seen.add(object)) ret jlabel("Object already seen"); // multi-map ifclass MultiMap if (object cast MultiMap) { propertyLength(l(object)); propertyKeyCount(object.keyCount()); object = multiMapToMapPairs(object); } endif ifclass MultiSetMap if (object cast MultiSetMap) { propertyLength(l(object)); propertyKeyCount(object.keyCount()); object = multiSetMapToMapPairs(object); } endif // map if (object cast Map) { propertyLength(l(object)); object = mapToPairs(object); } // collection if (object cast Collection) { propertyLength(l(object)); var sub = subVisualizer(); var elements = map(cloneTakeFirst(maxElements, object), element -> sub.visualize(element)); ret jscroll_centered_borderless(horizontal ? hstackWithSpacing(elements) : vstackWithSpacing(elements); } } if (object cast S) { propertyLength(l(object)); } S string = str(object); if (containsNewLine(string)) ret jscroll_borderless(wordWrapTypeWriterTextArea(string)); ret jcenteredlabel(shorten(string)); } // end of visualize2 } // end of ObjectVisualizer void propertyLength(int l) { properties.put("size", l); } void propertyKeyCount(int l) { properties.put("keys", l); } }