From e53a6793312ba624763943cbf6238e4d8a6fa5a4 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Sat, 18 Mar 2023 11:25:17 +0100 Subject: [PATCH] refactor: improve smetana support for JSON --- .../plantuml/elk/CucaDiagramFileMakerElk.java | 49 +++++++++++---- .../plantuml/jsondiagram/SmetanaForJson.java | 61 ++++++++++++------- .../plantuml/jsondiagram/TextBlockJson.java | 10 ++- .../sdot/CucaDiagramFileMakerSmetana.java | 34 ++++++++--- .../plantuml/style/FromSkinparamToStyle.java | 15 ++++- src/smetana/core/Macro.java | 22 +++---- 6 files changed, 136 insertions(+), 55 deletions(-) diff --git a/src/net/sourceforge/plantuml/elk/CucaDiagramFileMakerElk.java b/src/net/sourceforge/plantuml/elk/CucaDiagramFileMakerElk.java index 4f467fc1e..7b5372ae5 100644 --- a/src/net/sourceforge/plantuml/elk/CucaDiagramFileMakerElk.java +++ b/src/net/sourceforge/plantuml/elk/CucaDiagramFileMakerElk.java @@ -48,6 +48,7 @@ import java.util.Map.Entry; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.UmlDiagram; +import net.sourceforge.plantuml.abel.CucaNote; import net.sourceforge.plantuml.abel.Entity; import net.sourceforge.plantuml.abel.GroupType; import net.sourceforge.plantuml.abel.LeafType; @@ -108,6 +109,7 @@ import net.sourceforge.plantuml.klimt.font.StringBounder; import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; import net.sourceforge.plantuml.klimt.geom.MinMax; import net.sourceforge.plantuml.klimt.geom.RectangleArea; +import net.sourceforge.plantuml.klimt.geom.VerticalAlignment; import net.sourceforge.plantuml.klimt.geom.XDimension2D; import net.sourceforge.plantuml.klimt.geom.XPoint2D; import net.sourceforge.plantuml.klimt.shape.AbstractTextBlock; @@ -121,6 +123,7 @@ import net.sourceforge.plantuml.style.ISkinParam; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignatureBasic; import net.sourceforge.plantuml.svek.Bibliotekon; import net.sourceforge.plantuml.svek.Cluster; import net.sourceforge.plantuml.svek.ClusterDecoration; @@ -130,6 +133,8 @@ import net.sourceforge.plantuml.svek.GeneralImageBuilder; import net.sourceforge.plantuml.svek.GraphvizCrash; import net.sourceforge.plantuml.svek.IEntityImage; import net.sourceforge.plantuml.svek.PackageStyle; +import net.sourceforge.plantuml.svek.image.EntityImageNoteLink; +import net.sourceforge.plantuml.utils.Position; /* * Some notes: @@ -160,18 +165,40 @@ public class CucaDiagramFileMakerElk implements CucaDiagramFileMaker { } - private TextBlock getLabel(Link link) { - if (Display.isNull(link.getLabel())) { - return null; - } - final ISkinParam skinParam = diagram.getSkinParam(); - final FontConfiguration labelFont = FontConfiguration.create(skinParam, FontParam.ARROW, null); - final TextBlock label = link.getLabel().create(labelFont, - skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam); - if (TextBlockUtils.isEmpty(label, stringBounder)) - return null; + // Duplicate from CucaDiagramFileMakerSmetana + private Style getStyle() { + return StyleSignatureBasic + .of(SName.root, SName.element, diagram.getUmlDiagramType().getStyleName(), SName.arrow) + .getMergedStyle(diagram.getSkinParam().getCurrentStyleBuilder()); + } + + private TextBlock getLabel(Link link) { + ISkinParam skinParam = diagram.getSkinParam(); + final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1; + final Style style = getStyle(); + + final FontConfiguration labelFont = style.getFontConfiguration(skinParam.getIHtmlColorSet()); + TextBlock labelOnly = link.getLabel().create(labelFont, + skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam); + + final CucaNote note = link.getNote(); + if (note == null) { + if (TextBlockUtils.isEmpty(labelOnly, stringBounder) == false) + labelOnly = TextBlockUtils.withMargin(labelOnly, marginLabel, marginLabel); + return labelOnly; + } + final TextBlock noteOnly = new EntityImageNoteLink(note.getDisplay(), note.getColors(), skinParam, + link.getStyleBuilder()); + + if (note.getPosition() == Position.LEFT) + return TextBlockUtils.mergeLR(noteOnly, labelOnly, VerticalAlignment.CENTER); + else if (note.getPosition() == Position.RIGHT) + return TextBlockUtils.mergeLR(labelOnly, noteOnly, VerticalAlignment.CENTER); + else if (note.getPosition() == Position.TOP) + return TextBlockUtils.mergeTB(noteOnly, labelOnly, HorizontalAlignment.CENTER); + else + return TextBlockUtils.mergeTB(labelOnly, noteOnly, HorizontalAlignment.CENTER); - return label; } private TextBlock getQuantifier(Link link, int n) { diff --git a/src/net/sourceforge/plantuml/jsondiagram/SmetanaForJson.java b/src/net/sourceforge/plantuml/jsondiagram/SmetanaForJson.java index 42e2a0536..9b7c6b409 100644 --- a/src/net/sourceforge/plantuml/jsondiagram/SmetanaForJson.java +++ b/src/net/sourceforge/plantuml/jsondiagram/SmetanaForJson.java @@ -127,8 +127,9 @@ public class SmetanaForJson { private ST_Agnode_s manageOneNode(Globals zz, JsonValue current, List highlighted) { final TextBlockJson block = new TextBlockJson(skinParam, current, highlighted); - final ST_Agnode_s node1 = createNode(zz, block.calculateDimension(stringBounder), block.size(), - current.isArray(), (int) block.getWidthColA(stringBounder), (int) block.getWidthColB(stringBounder)); + final ST_Agnode_s node1 = createNode(zz, block.calculateDimension(stringBounder), current.isArray(), + block.getWidthColA(stringBounder), block.getWidthColB(stringBounder), + block.getAllHeights(stringBounder)); nodes.add(new InternalNode(block, node1)); final List children = block.children(); final List keys = block.keys(); @@ -222,16 +223,15 @@ public class SmetanaForJson { agsafeset(zz, edge, new CString("arrowhead"), new CString("normal"), new CString("")); agsafeset(zz, edge, new CString("tailport"), new CString("P" + num), new CString("")); - StringBuilder sb = new StringBuilder(); - sb.append("N" + a0.UID + " -> N" + a1.UID + " [tailport=\"P" + num + "\", arrowsize=.75]"); - if (NUM == 0 && printFirst) - System.err.println(sb); +// StringBuilder sb = new StringBuilder(); +// sb.append("N" + a0.UID + " -> N" + a1.UID + " [tailport=\"P" + num + "\", arrowsize=.75]"); +// System.err.println(sb); return edge; } - private ST_Agnode_s createNode(Globals zz, XDimension2D dim, int size, boolean isArray, int colAwidth, - int colBwidth) { + private ST_Agnode_s createNode(Globals zz, XDimension2D dim, boolean isArray, double colAwidth, double colBwidth, + double lineHeights[]) { final String width = "" + (dim.getWidth() / 72); final String height = "" + (dim.getHeight() / 72); @@ -243,25 +243,45 @@ public class SmetanaForJson { agsafeset(zz, node, new CString("height"), new CString("" + width), new CString("")); agsafeset(zz, node, new CString("width"), new CString("" + height), new CString("")); - final int lineHeight = 0; - final String dotLabel = getDotLabel(size, isArray, colAwidth - 8, colBwidth - 8, lineHeight); + final int size = lineHeights.length; + final String dotLabel; + if (isArray) + dotLabel = getDotLabelArray(colAwidth - 8, colBwidth - 8, lineHeights); + else + dotLabel = getDotLabelMap(colAwidth - 8, colBwidth - 8, lineHeights); + if (size > 0) agsafeset(zz, node, new CString("label"), new CString(dotLabel), new CString("")); - StringBuilder sb = new StringBuilder(); - sb.append("N" + node.UID + " ["); - sb.append("shape=record, height=" + width + ", width=" + height + ", label=\"" + dotLabel.replace('x', '.') - + "\"]"); - if (NUM == 0 && printFirst) - System.err.println(sb); +// StringBuilder sb = new StringBuilder(); +// sb.append("N" + node.UID + " ["); +// sb.append("shape=record, height=" + width + ", width=" + height + ", label=\"" + dotLabel.replace('x', '.') +// + "\"]"); +// System.err.println(sb); return node; } - private String getDotLabel(int size, boolean isArray, int widthA, int widthB, int height) { + private String getDotLabelArray(double widthA, double widthB, double[] lineHeights) { + final int size = lineHeights.length; + final double height = 0; final StringBuilder sb = new StringBuilder(""); - if (isArray == false) - sb.append("{_dim_" + height + "_" + widthA + "_|{"); + + for (int i = 0; i < size; i++) { + sb.append(""); + sb.append("_dim_" + height + "_" + widthA + "_"); + if (i < size - 1) + sb.append("|"); + } + + return sb.toString(); + } + + private String getDotLabelMap(double widthA, double widthB, double[] lineHeights) { + final int size = lineHeights.length; + final double height = 0; + final StringBuilder sb = new StringBuilder(""); + sb.append("{_dim_" + height + "_" + widthA + "_|{"); for (int i = 0; i < size; i++) { sb.append(""); @@ -269,8 +289,7 @@ public class SmetanaForJson { if (i < size - 1) sb.append("|"); } - if (isArray == false) - sb.append("}}"); + sb.append("}}"); return sb.toString(); } diff --git a/src/net/sourceforge/plantuml/jsondiagram/TextBlockJson.java b/src/net/sourceforge/plantuml/jsondiagram/TextBlockJson.java index 1d2654698..bb75bb367 100644 --- a/src/net/sourceforge/plantuml/jsondiagram/TextBlockJson.java +++ b/src/net/sourceforge/plantuml/jsondiagram/TextBlockJson.java @@ -70,7 +70,7 @@ import net.sourceforge.plantuml.yaml.Highlighted; //See TextBlockMap public class TextBlockJson extends AbstractTextBlock { - // ::remove folder when __HAXE__ + // ::remove folder when __HAXE__ private final List lines = new ArrayList<>(); @@ -323,6 +323,14 @@ public class TextBlockJson extends AbstractTextBlock { return height; } + public double[] getAllHeights(StringBounder stringBounder) { + final double result[] = new double[lines.size()]; + for (int i = 0; i < lines.size(); i++) + result[i] = lines.get(i).getHeightOfRow(stringBounder); + + return result; + } + private TextBlock getTextBlock(Style style, String key) { final Display display = Display.getWithNewlines(key); final FontConfiguration fontConfiguration = style.getFontConfiguration(skinParam.getIHtmlColorSet()); diff --git a/src/net/sourceforge/plantuml/sdot/CucaDiagramFileMakerSmetana.java b/src/net/sourceforge/plantuml/sdot/CucaDiagramFileMakerSmetana.java index 3f4bf61f2..2f700d8cf 100644 --- a/src/net/sourceforge/plantuml/sdot/CucaDiagramFileMakerSmetana.java +++ b/src/net/sourceforge/plantuml/sdot/CucaDiagramFileMakerSmetana.java @@ -62,6 +62,7 @@ import h.ST_GVC_s; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.UmlDiagram; +import net.sourceforge.plantuml.abel.CucaNote; import net.sourceforge.plantuml.abel.Entity; import net.sourceforge.plantuml.abel.GroupType; import net.sourceforge.plantuml.abel.LeafType; @@ -79,6 +80,7 @@ import net.sourceforge.plantuml.klimt.font.StringBounder; import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; import net.sourceforge.plantuml.klimt.geom.MinMaxMutable; import net.sourceforge.plantuml.klimt.geom.Rankdir; +import net.sourceforge.plantuml.klimt.geom.VerticalAlignment; import net.sourceforge.plantuml.klimt.geom.XDimension2D; import net.sourceforge.plantuml.klimt.geom.XPoint2D; import net.sourceforge.plantuml.klimt.shape.AbstractTextBlock; @@ -98,6 +100,8 @@ import net.sourceforge.plantuml.svek.GeneralImageBuilder; import net.sourceforge.plantuml.svek.GraphvizCrash; import net.sourceforge.plantuml.svek.IEntityImage; import net.sourceforge.plantuml.svek.SvekNode; +import net.sourceforge.plantuml.svek.image.EntityImageNoteLink; +import net.sourceforge.plantuml.utils.Position; import smetana.core.CString; import smetana.core.Globals; import smetana.core.JUtils; @@ -461,16 +465,32 @@ public class CucaDiagramFileMakerSmetana implements CucaDiagramFileMaker { } private TextBlock getLabel(Link link) { - final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1; ISkinParam skinParam = diagram.getSkinParam(); + final double marginLabel = 1; // startUid.equals(endUid) ? 6 : 1; final Style style = getStyle(); - final FontConfiguration labelFont = style.getFontConfiguration(skinParam.getIHtmlColorSet()); - final TextBlock label = link.getLabel().create(labelFont, - skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam); - if (TextBlockUtils.isEmpty(label, stringBounder)) - return label; - return TextBlockUtils.withMargin(label, marginLabel, marginLabel); + final FontConfiguration labelFont = style.getFontConfiguration(skinParam.getIHtmlColorSet()); + TextBlock labelOnly = link.getLabel().create(labelFont, + skinParam.getDefaultTextAlignment(HorizontalAlignment.CENTER), skinParam); + + final CucaNote note = link.getNote(); + if (note == null) { + if (TextBlockUtils.isEmpty(labelOnly, stringBounder) == false) + labelOnly = TextBlockUtils.withMargin(labelOnly, marginLabel, marginLabel); + return labelOnly; + } + final TextBlock noteOnly = new EntityImageNoteLink(note.getDisplay(), note.getColors(), skinParam, + link.getStyleBuilder()); + + if (note.getPosition() == Position.LEFT) + return TextBlockUtils.mergeLR(noteOnly, labelOnly, VerticalAlignment.CENTER); + else if (note.getPosition() == Position.RIGHT) + return TextBlockUtils.mergeLR(labelOnly, noteOnly, VerticalAlignment.CENTER); + else if (note.getPosition() == Position.TOP) + return TextBlockUtils.mergeTB(noteOnly, labelOnly, HorizontalAlignment.CENTER); + else + return TextBlockUtils.mergeTB(labelOnly, noteOnly, HorizontalAlignment.CENTER); + } private TextBlock getQuantifier(Link link, int n) { diff --git a/src/net/sourceforge/plantuml/style/FromSkinparamToStyle.java b/src/net/sourceforge/plantuml/style/FromSkinparamToStyle.java index f67bf84af..c45d0957d 100644 --- a/src/net/sourceforge/plantuml/style/FromSkinparamToStyle.java +++ b/src/net/sourceforge/plantuml/style/FromSkinparamToStyle.java @@ -46,7 +46,7 @@ import java.util.StringTokenizer; import net.sourceforge.plantuml.stereo.StereotypeDecoration; public class FromSkinparamToStyle { - // ::remove file when __HAXE__ + // ::remove file when __HAXE__ static class Data { final private SName[] styleNames; @@ -181,8 +181,17 @@ public class FromSkinparamToStyle { addConvert("classBackgroundColor", PName.BackGroundColor, SName.element, SName.class_); addConvert("classBorderColor", PName.LineColor, SName.element, SName.class_); - addConFont("class", SName.element, SName.class_); - addConFont("classAttribute", SName.element, SName.class_); + + addConvert("classFontSize", PName.FontSize, SName.element, SName.class_, SName.header); + addConvert("classFontStyle", PName.FontStyle, SName.element, SName.class_, SName.header); + addConvert("classFontColor", PName.FontColor, SName.element, SName.class_, SName.header); + addConvert("classFontName", PName.FontName, SName.element, SName.class_, SName.header); + + addConvert("classAttributeFontSize", PName.FontSize, SName.element, SName.class_); + addConvert("classAttributeFontStyle", PName.FontStyle, SName.element, SName.class_); + addConvert("classAttributeFontColor", PName.FontColor, SName.element, SName.class_); + addConvert("classAttributeFontName", PName.FontName, SName.element, SName.class_); + addConvert("classBorderThickness", PName.LineThickness, SName.element, SName.class_); addConvert("classHeaderBackgroundColor", PName.BackGroundColor, SName.element, SName.class_, SName.header); diff --git a/src/smetana/core/Macro.java b/src/smetana/core/Macro.java index e679d6694..5d9a5a69c 100644 --- a/src/smetana/core/Macro.java +++ b/src/smetana/core/Macro.java @@ -76,7 +76,7 @@ import h.ST_textlabel_t; import smetana.core.debug.SmetanaDebug; final public class Macro { - // ::remove folder when __HAXE__ + // ::remove folder when __HAXE__ public static void UNSURE_ABOUT(String comment) { System.err.println("UNSURE_ABOUT: " + comment); @@ -1290,19 +1290,16 @@ final public class Macro { } public static void hackInitDimensionFromLabel(ST_pointf size, String label) { - if (label.matches("_dim_\\d+_\\d+_")) { - Pattern p = Pattern.compile("_dim_(\\d+)_(\\d+)_"); - Matcher m = p.matcher(label); - if (m.matches() == false) { - throw new IllegalStateException(); - } - int ww = Integer.parseInt(m.group(1)); - int hh = Integer.parseInt(m.group(2)); + final Pattern p = Pattern.compile("_dim_([.\\d]+)_([\\d.]+)_"); + final Matcher m = p.matcher(label); + if (m.matches()) { + final double ww = Double.parseDouble(m.group(1)); + final double hh = Double.parseDouble(m.group(2)); size.x = ww; size.y = hh; JUtils.LOG2("Hacking dimension to width=" + ww + " height=" + hh); -// } else { -// throw new IllegalArgumentException(label); + } else { + JUtils.LOG2("Strange label " + label); } } @@ -1671,7 +1668,8 @@ final public class Macro { return (__ptr__) o.getTheField(ky); } - public static int _DTCMP(Globals zz, ST_dt_s dt, __ptr__ k1, __ptr__ k2, final ST_dtdisc_s dc, CFunction cmpf, int sz) { + public static int _DTCMP(Globals zz, ST_dt_s dt, __ptr__ k1, __ptr__ k2, final ST_dtdisc_s dc, CFunction cmpf, + int sz) { return cmpf != null ? (Integer) ((CFunction) cmpf).exe(zz, dt, k1, k2, dc) : (sz <= 0 ? strcmp((CString) k1, (CString) k2) : UNSUPPORTED_INT("memcmp(ok,nk,sz)")); }