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; settable int floatingPointDigits = 4; settable bool allowDescendingIntoListElements; settable double scriptTimeout = 10.0; settable int stringDisplayLength = 80; Set seen = identityHashSet(); transient settable O object; transient settable long nanos = -1; transient SingleComponentPanel scp = scp(); *(G22Utils *g22utils, O *object) {} // call after visualizeObject (so properties are filled) S objectInfos(O object default this.object) { new LS infos; infos.add(str(shortClassName2(object))); // shows "null" for null value for (key, val : mainVisualizer().properties) { S s = n2OrStrOrNull(val); if (nempty(s)) infos.add(key + " " + s); } if (nanos >= 0) { S timeDesc = nanos < 0 ? "" : formatElapsedTimeWithAppropriateUnit(nanosToSeconds(nanos)); infos.add(timeDesc); } ret joinNemptiesWithComma(infos); } cachedVisualize { //printVars("Visualizing", +this, +withTypeAndTime); scp.set(visualizeObjectWithExtras(object)); ret scp; } JComponent visualizeObject(O object) { ret mainVisualizer().visualize(object); } JComponent visualizeObjectWithExtras(O object, Component back default null) { JComponent c = visualizeObject(object); JButton btnBack = back == null ?: jimageButtonScaledToWidth(16, #1103102, -> scp.set(back)); JComponent lblType = null; if (withTypeAndTime) { S type = objectInfos(object); lblType = withLabel("Type:", jlabel(type)); } if (btnBack != null || lblType != null) { JComponent top = or(lblType, jpanel()); if (btnBack != null) top = westAndCenterWithMargin(btnBack, top); ret northAndCenterWithMargins(top, c); } ret c; } simplyCached ObjectVisualizer mainVisualizer() { ret new ObjectVisualizer().recurse(true).bigFont(true).horizontal(horizontal); } class ObjectVisualizer { settable bool recurse; settable bool bigFont; settable bool horizontal; settable bool scrollable = true; new LinkedHashMap properties; // only one recursion level so far ObjectVisualizer subVisualizer() { ret new ObjectVisualizer().horizontal(!horizontal); } ObjectVisualizer subVisualizerOnSameLevel() { ret new ObjectVisualizer().horizontal(horizontal) .recurse(recurse).bigFont(bigFont) .scrollable(false); } JComponent makeBig(JComponent c) { if (bigFont) ret fontSizePlus(10, c); ret c; } JComponent subVisualizeOnSameLevel(O o) { ret subVisualizerOnSameLevel().visualize(o); } JComponent visualize(O object) { try { ret visualize2(object); } catch e { ret g22utils.jErrorView(new RuntimeException("Visualization error", e)); } } JComponent visualize2(O object) { // exception if (object cast Throwable) ret g22utils.jErrorView(object); // null or empty string if (object == null || eq(object, "")) ret jpanel(); // array to list object = arrayToList(object); // 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 bigText(n2(object)); if (object cast Double) ret toolTip(str(object), bigText(formatDouble(object, floatingPointDigits))); if (object cast Number) ret bigText(object); if (object cast Pair) ret visualizeTuple(pairToList(object)); if (object cast T3) ret visualizeTuple(tripleToList(object)); // 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); } // FunctionDef if (object cast GazelleV_LeftArrowScript.FunctionDef) { var f = object; if (empty(f.args)) ret centerAndEastWithMargin(visualizeAsText(f), jverticalCenter(jThreadedButton("Call", -> inspectElement(callFunctionDef(f))))); } 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); } // array / collection if (object cast Collection) { propertyLength(l(object)); var sub = subVisualizer(); var elements = map(cloneTakeFirst(maxElements, object), element -> { var elementVis = sub.visualize(element); if (allowDescendingIntoListElements) elementVis = centerAndEastWithMargin( elementVis, new JPopDownButton().content("Inspect element" := rThread { inspectElement(element) })); ret elementVis; }); ret stackElements(elements); } } // end of if recurse ret visualizeAsText(object); } // end of visualize2 JComponent visualizeTuple(L tuple) { if (horizontal) ret jcenteredline(listCombine( jlabel("<"), intersperseF(-> jlabel(","), map visualize(tuple)), jlabel(">"))); else ret stackElements(listCombine( map subVisualizeOnSameLevel(tuple))); } JComponent visualizeAsText(Object object) { if (object cast S) { propertyLength(l(object)); } S string = str(object); if (containsNewLine(string)) ret jscroll_borderless(wordWrapTypeWriterTextArea(string)); if (recurse && l(string) > stringDisplayLength) ret jText(string); var lbl = jcenterNarrowLabel(shorten(string)); if (l(string) <= 10) ret makeBig(lbl); ret lbl; } // end of visualizeAsText void propertyLength(int l) { properties.put("size", l); } void propertyKeyCount(int l) { properties.put("keys", l); } JComponent bigText(O o) { ret makeBig(jcenteredLabel(str(o))); } O arrayToList(O object) { if (isArray(object)) object = wrapArrayAsImmutableList(object); ret object; } JComponent stackElements(L elements) { var c = horizontal ? hstackWithSpacing(elements) : vstackWithSpacing(elements); ret scrollable ? jscroll_centered_borderless(c) : c; } } // end of ObjectVisualizer selfType withType(bool b) { ret withTypeAndTime(b); } void inspectElement(O element) { var back = scp.getComponent(); scp.set(visualizeObjectWithExtras(element, back)); } O callFunctionDef(GazelleV_LeftArrowScript.FunctionDef f) { ret evalWithTimeoutOrFail(scriptTimeout, -> f.call(new FlexibleVarContext)); } }