Add nested box in sequence diagram

This commit is contained in:
Arnaud Roques 2022-01-04 18:21:17 +01:00
parent 16fd392308
commit d36de19c99
7 changed files with 181 additions and 88 deletions

View File

@ -37,56 +37,57 @@ package net.sourceforge.plantuml.sequencediagram;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.PaddingParam;
import net.sourceforge.plantuml.SkinParamBackcolored;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.real.Real;
import net.sourceforge.plantuml.real.RealUtils;
import net.sourceforge.plantuml.sequencediagram.teoz.LivingSpace;
import net.sourceforge.plantuml.sequencediagram.teoz.TileArguments;
import net.sourceforge.plantuml.skin.Area;
import net.sourceforge.plantuml.skin.Component;
import net.sourceforge.plantuml.skin.ComponentType;
import net.sourceforge.plantuml.skin.Context2D;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.style.StyleBuilder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class DollLeaf extends DollAbstract {
public class Doll extends DollAbstract {
final private List<Participant> participants = new ArrayList<>();
final private TileArguments tileArguments;
private final List<Doll> leafs = new ArrayList<>();
final private Real core1;
final private Real core2;
private double marginX = 0;
public static DollLeaf createPuma(ParticipantEnglober englober, Participant first, ISkinParam skinParam, Rose skin,
StringBounder stringBounder, StyleBuilder styleBuilder) {
return new DollLeaf(englober, styleBuilder, false, first,
convertFunctionToBeRemoved(skinParam, skin, stringBounder));
public static Doll createGroup(ParticipantEnglober englober, TileArguments tileArguments, StyleBuilder styleBuilder,
boolean isTeoz) {
return new Doll(englober, tileArguments, styleBuilder, isTeoz);
}
public static DollLeaf createTeoz(ParticipantEnglober englober, Participant first, TileArguments tileArguments,
public static Doll createPuma(ParticipantEnglober englober, Participant first, ISkinParam skinParam, Rose skin,
StringBounder stringBounder, StyleBuilder styleBuilder) {
return new Doll(englober, convertFunctionToBeRemoved(skinParam, skin, stringBounder), styleBuilder, false,
first);
}
public static Doll createTeoz(ParticipantEnglober englober, Participant first, TileArguments tileArguments,
StyleBuilder styleBuilder) {
return new DollLeaf(englober, styleBuilder, true, first, tileArguments);
final Doll result = new Doll(englober, tileArguments, styleBuilder, true, first);
return result;
}
private static TileArguments convertFunctionToBeRemoved(ISkinParam skinParam, Rose skin,
StringBounder stringBounder) {
final TileArguments result = new TileArguments(stringBounder, null, skin, skinParam, null);
return result;
return new TileArguments(stringBounder, null, skin, skinParam, null);
}
private DollLeaf(ParticipantEnglober englober, StyleBuilder styleBuilder, boolean isTeoz, Participant first,
TileArguments tileArguments) {
super(englober, styleBuilder, isTeoz);
private Doll(ParticipantEnglober englober, TileArguments tileArguments, StyleBuilder styleBuilder, boolean isTeoz,
Participant first) {
super(englober, tileArguments, styleBuilder, isTeoz);
this.participants.add(first);
this.tileArguments = Objects.requireNonNull(tileArguments);
final double preferredWidth = getPreferredWidth();
if (tileArguments.getLivingSpaces() == null) {
this.core1 = null;
@ -97,6 +98,12 @@ public class DollLeaf extends DollAbstract {
}
}
private Doll(ParticipantEnglober englober, TileArguments tileArguments, StyleBuilder styleBuilder, boolean isTeoz) {
super(englober, tileArguments, styleBuilder, isTeoz);
this.core1 = null;
this.core2 = null;
}
public final Participant getFirst2TOBEPRIVATE() {
return participants.get(0);
}
@ -142,28 +149,24 @@ public class DollLeaf extends DollAbstract {
return tileArguments.getLivingSpace(getLast2TOBEPRIVATE());
}
private Component getComponent() {
final ParticipantEnglober englober = getParticipantEnglober();
final ISkinParam s = englober.getBoxColor() == null ? tileArguments.getSkinParam()
: new SkinParamBackcolored(tileArguments.getSkinParam(), englober.getBoxColor());
return tileArguments.getSkin().createComponent(getUsedStyles(), ComponentType.ENGLOBER, null, s,
englober.getTitle());
}
public boolean contains(Participant p) {
return participants.contains(p);
}
public void add(Participant p) {
if (participants.contains(p)) {
public void addParticipant(Participant p) {
if (participants.contains(p))
throw new IllegalArgumentException();
}
participants.add(p);
}
public void addDoll(Doll doll) {
this.leafs.add(doll);
}
@Override
public String toString() {
return "ParticipantEngloberContexted:" + englober.getTitle().toString() + " " + participants;
return "DollLeaf:" + englober.getTitle().toString() + " " + participants;
}
private double getPreferredWidth() {
@ -177,26 +180,53 @@ public class DollLeaf extends DollAbstract {
return getComponent().getPreferredWidth(tileArguments.getStringBounder());
}
public double getPreferredHeight() {
final Component comp = tileArguments.getSkin().createComponent(getUsedStyles(), ComponentType.ENGLOBER, null,
tileArguments.getSkinParam(), getParticipantEnglober().getTitle());
return comp.getPreferredHeight(tileArguments.getStringBounder());
public void drawGroup(UGraphic ug, double height, Context2D context) {
if (leafs.size() == 0)
throw new IllegalArgumentException();
final double x1 = getGroupX1();
final double x2 = getGroupX2();
final Dimension2DDouble dim = new Dimension2DDouble(x2 - x1, height);
getComponent().drawU(ug.apply(new UTranslate(x1, 1)), new Area(dim), context);
}
public void drawMe(UGraphic ug, double height, Context2D context) {
private double getGroupX1() {
double result = leafs.get(0).getX1().getCurrentValue() - 6;
if (participants.size() > 0)
result = Math.min(result, getX1().getCurrentValue() - 6);
return result;
}
private double getGroupX2() {
double result = leafs.get(leafs.size() - 1).getX2().getCurrentValue() + 6;
if (participants.size() > 0)
result = Math.max(result, getX2().getCurrentValue() + 6);
return result;
}
public void drawMe(UGraphic ug, double height, Context2D context, Doll group) {
final double x1 = getX1().getCurrentValue() - 4;
final double x2 = getX2().getCurrentValue() + 4;
if (group != null) {
final double titlePreferredHeight = group.getTitlePreferredHeight();
ug = ug.apply(UTranslate.dy(titlePreferredHeight));
height -= titlePreferredHeight;
}
final Dimension2DDouble dim = new Dimension2DDouble(x2 - x1, height);
getComponent().drawU(ug.apply(new UTranslate(x1, 1)), new Area(dim), context);
}
private Real getX2() {
return RealUtils.max(getPosD(), core2).addFixed(marginX);
private Real getX1() {
if (core1 == null)
return getPosB().addFixed(-marginX);
return RealUtils.min(getPosB(), core1).addFixed(-marginX);
}
private Real getX1() {
return RealUtils.min(getPosB(), core1).addFixed(-marginX);
private Real getX2() {
if (core2 == null)
return getPosD().addFixed(marginX);
return RealUtils.max(getPosD(), core2).addFixed(marginX);
}
public void addInternalConstraints() {
@ -205,22 +235,22 @@ public class DollLeaf extends DollAbstract {
final double x1 = getX1().getCurrentValue();
final double x2 = getX2().getCurrentValue();
final double actualWidth = x2 - x1;
if (titleWidth > actualWidth + 20) {
if (titleWidth > actualWidth + 20)
this.marginX = (titleWidth - actualWidth - 20) / 2;
}
getX1().ensureBiggerThan(getPosAA().addFixed(10 + padding()));
final Real posZZ = getPosZZ();
final Real limit = getX2().addFixed(10 + padding());
if (posZZ != null) {
if (posZZ != null)
posZZ.ensureBiggerThan(limit);
}
}
private double padding() {
return tileArguments.getSkinParam().getPadding(PaddingParam.BOX);
}
public void addConstraintAfter(DollLeaf current) {
public void addConstraintAfter(Doll current) {
current.getX1().ensureBiggerThan(getX2().addFixed(10 + 2 * padding()));
}

View File

@ -35,11 +35,13 @@
*/
package net.sourceforge.plantuml.sequencediagram;
import java.util.Objects;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.SkinParamBackcolored;
import net.sourceforge.plantuml.sequencediagram.teoz.TileArguments;
import net.sourceforge.plantuml.skin.Component;
import net.sourceforge.plantuml.skin.ComponentType;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleBuilder;
@ -52,11 +54,13 @@ public abstract class DollAbstract implements WithStyle {
final protected ParticipantEnglober englober;
final protected StyleBuilder styleBuilder;
final protected boolean isTeoz;
final protected TileArguments tileArguments;
DollAbstract(ParticipantEnglober englober, StyleBuilder styleBuilder, boolean isTeoz) {
this.englober = englober;
DollAbstract(ParticipantEnglober englober, TileArguments tileArguments, StyleBuilder styleBuilder, boolean isTeoz) {
this.englober = Objects.requireNonNull(englober);
this.styleBuilder = styleBuilder;
this.isTeoz = isTeoz;
this.tileArguments = Objects.requireNonNull(tileArguments);
}
final public StyleSignature getDefaultStyleDefinition() {
@ -66,20 +70,29 @@ public abstract class DollAbstract implements WithStyle {
final public Style[] getUsedStyles() {
Style tmp = getDefaultStyleDefinition().with(englober.getStereotype()).getMergedStyle(styleBuilder);
final HColor backColor = englober.getBoxColor();
if (tmp != null) {
if (tmp != null)
tmp = tmp.eventuallyOverride(PName.BackGroundColor, backColor);
}
return new Style[] { tmp };
}
private static TileArguments convertFunctionToBeRemoved(ISkinParam skinParam, Rose skin,
StringBounder stringBounder) {
final TileArguments result = new TileArguments(stringBounder, null, skin, skinParam, null);
return result;
return new Style[] { tmp };
}
final public ParticipantEnglober getParticipantEnglober() {
return englober;
}
final protected Component getComponent() {
final ParticipantEnglober englober = getParticipantEnglober();
final ISkinParam s = englober.getBoxColor() == null ? tileArguments.getSkinParam()
: new SkinParamBackcolored(tileArguments.getSkinParam(), englober.getBoxColor());
return tileArguments.getSkin().createComponent(getUsedStyles(), ComponentType.ENGLOBER, null, s,
englober.getTitle());
}
public double getTitlePreferredHeight() {
final Component comp = tileArguments.getSkin().createComponent(getUsedStyles(), ComponentType.ENGLOBER, null,
tileArguments.getSkinParam(), getParticipantEnglober().getTitle());
return comp.getPreferredHeight(tileArguments.getStringBounder());
}
}

View File

@ -45,6 +45,11 @@ public class ParticipantEnglober {
final private Display title;
final private HColor boxColor;
final private Stereotype stereotype;
@Override
public String toString() {
return title.toString();
}
public static ParticipantEnglober build(Display title, HColor boxColor, Stereotype stereotype) {
return new ParticipantEnglober(null, title, boxColor, stereotype);

View File

@ -55,7 +55,7 @@ import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.graphic.InnerStrategy;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.sequencediagram.DollLeaf;
import net.sourceforge.plantuml.sequencediagram.Doll;
import net.sourceforge.plantuml.sequencediagram.Event;
import net.sourceforge.plantuml.sequencediagram.Newpage;
import net.sourceforge.plantuml.sequencediagram.Participant;
@ -142,7 +142,7 @@ public class DrawableSet {
public double getHeadAndEngloberHeight(Participant p, StringBounder stringBounder) {
final LivingParticipantBox box = participants.get(p);
final double height = box.getParticipantBox().getHeadHeight(stringBounder);
final DollLeaf doll = getParticipantEnglober(p, stringBounder);
final Doll doll = getParticipantEnglober(p, stringBounder);
if (doll == null)
return height;
@ -152,9 +152,9 @@ public class DrawableSet {
return height + heightEnglober;
}
public List<DollLeaf> getExistingParticipantEnglober(StringBounder stringBounder) {
final List<DollLeaf> result = new ArrayList<>();
DollLeaf pending = null;
public List<Doll> getExistingParticipantEnglober(StringBounder stringBounder) {
final List<Doll> result = new ArrayList<>();
Doll pending = null;
for (Map.Entry<Participant, ParticipantEnglober> ent : participantEnglobers2.entrySet()) {
final ParticipantEnglober englober = ent.getValue();
if (englober == null) {
@ -163,10 +163,10 @@ public class DrawableSet {
}
assert englober != null;
if (pending != null && englober == pending.getParticipantEnglober()) {
pending.add(ent.getKey());
pending.addParticipant(ent.getKey());
continue;
}
pending = DollLeaf.createPuma(englober, ent.getKey(), getSkinParam(), skin, stringBounder,
pending = Doll.createPuma(englober, ent.getKey(), getSkinParam(), skin, stringBounder,
skinParam.getCurrentStyleBuilder());
result.add(pending);
}
@ -175,7 +175,7 @@ public class DrawableSet {
public double getOffsetForEnglobers(StringBounder stringBounder) {
double result = 0;
for (DollLeaf englober : getExistingParticipantEnglober(stringBounder)) {
for (Doll englober : getExistingParticipantEnglober(stringBounder)) {
final Component comp = skin.createComponent(null, ComponentType.ENGLOBER, null, skinParam,
englober.getParticipantEnglober().getTitle());
final double height = comp.getPreferredHeight(stringBounder);
@ -363,7 +363,7 @@ public class DrawableSet {
}
private void drawDolls(UGraphic ug, double height, Context2D context) {
for (DollLeaf doll : getExistingParticipantEnglober(ug.getStringBounder())) {
for (Doll doll : getExistingParticipantEnglober(ug.getStringBounder())) {
double x1 = getX1(doll);
final double x2 = getX2(ug.getStringBounder(), doll);
@ -384,11 +384,11 @@ public class DrawableSet {
}
}
public double getEngloberPreferedWidth(StringBounder stringBounder, DollLeaf doll) {
public double getEngloberPreferedWidth(StringBounder stringBounder, Doll doll) {
return getEngloberComponent(doll).getPreferredWidth(stringBounder);
}
private Component getEngloberComponent(DollLeaf doll) {
private Component getEngloberComponent(Doll doll) {
final ParticipantEnglober participantEnglober = doll.getParticipantEnglober();
final ISkinParam s = participantEnglober.getBoxColor() == null ? skinParam
: new SkinParamBackcolored(skinParam, participantEnglober.getBoxColor());
@ -396,13 +396,13 @@ public class DrawableSet {
participantEnglober.getTitle());
}
public double getX1(DollLeaf doll) {
public double getX1(Doll doll) {
final Participant first = doll.getFirst2TOBEPRIVATE();
final ParticipantBox firstBox = participants.get(first).getParticipantBox();
return firstBox.getStartingX() + 1;
}
public double getX2(StringBounder stringBounder, DollLeaf doll) {
public double getX2(StringBounder stringBounder, Doll doll) {
final Participant last = doll.getLast2TOBEPRIVATE();
final ParticipantBox lastBox = participants.get(last).getParticipantBox();
return lastBox.getMaxX(stringBounder) - 1;
@ -415,8 +415,8 @@ public class DrawableSet {
line.drawU(ug, getSkin(), skinParam);
}
private DollLeaf getParticipantEnglober(Participant p, StringBounder stringBounder) {
for (DollLeaf pe : getExistingParticipantEnglober(stringBounder))
private Doll getParticipantEnglober(Participant p, StringBounder stringBounder) {
for (Doll pe : getExistingParticipantEnglober(stringBounder))
if (pe.contains(p))
return pe;

View File

@ -52,7 +52,7 @@ import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.sequencediagram.AbstractMessage;
import net.sourceforge.plantuml.sequencediagram.Delay;
import net.sourceforge.plantuml.sequencediagram.Divider;
import net.sourceforge.plantuml.sequencediagram.DollLeaf;
import net.sourceforge.plantuml.sequencediagram.Doll;
import net.sourceforge.plantuml.sequencediagram.Event;
import net.sourceforge.plantuml.sequencediagram.GroupingLeaf;
import net.sourceforge.plantuml.sequencediagram.GroupingStart;
@ -214,7 +214,7 @@ class DrawableSetInitializer {
if (padding == 0)
return;
for (DollLeaf pe : drawableSet.getExistingParticipantEnglober(stringBounder)) {
for (Doll pe : drawableSet.getExistingParticipantEnglober(stringBounder)) {
final ParticipantBox first = drawableSet.getLivingParticipantBox(pe.getFirst2TOBEPRIVATE())
.getParticipantBox();
final ParticipantBox last = drawableSet.getLivingParticipantBox(pe.getLast2TOBEPRIVATE())
@ -225,7 +225,7 @@ class DrawableSetInitializer {
}
private void takeParticipantEngloberTitleWidth(StringBounder stringBounder) {
for (DollLeaf doll : drawableSet.getExistingParticipantEnglober(stringBounder)) {
for (Doll doll : drawableSet.getExistingParticipantEnglober(stringBounder)) {
final double preferredWidth = drawableSet.getEngloberPreferedWidth(stringBounder, doll);
final ParticipantBox first = drawableSet.getLivingParticipantBox(doll.getFirst2TOBEPRIVATE())
.getParticipantBox();

View File

@ -36,12 +36,14 @@
package net.sourceforge.plantuml.sequencediagram.teoz;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.real.Real;
import net.sourceforge.plantuml.real.RealUtils;
import net.sourceforge.plantuml.sequencediagram.DollLeaf;
import net.sourceforge.plantuml.sequencediagram.Doll;
import net.sourceforge.plantuml.sequencediagram.Participant;
import net.sourceforge.plantuml.sequencediagram.ParticipantEnglober;
import net.sourceforge.plantuml.skin.Context2D;
@ -49,10 +51,12 @@ import net.sourceforge.plantuml.ugraphic.UGraphic;
public class Dolls {
private final List<DollLeaf> dolls = new ArrayList<>();
private final List<Doll> dolls = new ArrayList<>();
private final Map<ParticipantEnglober, Doll> groups = new HashMap<>();
public Dolls(TileArguments tileArguments) {
DollLeaf pending = null;
Doll pending = null;
for (Participant p : tileArguments.getLivingSpaces().participants()) {
final ParticipantEnglober englober = tileArguments.getLivingSpaces().get(p).getEnglober();
if (englober == null) {
@ -61,11 +65,25 @@ public class Dolls {
}
assert englober != null;
if (pending != null && englober == pending.getParticipantEnglober()) {
pending.add(p);
pending.addParticipant(p);
continue;
}
pending = DollLeaf.createTeoz(englober, p, tileArguments,
if (groups.containsKey(englober)) {
groups.get(englober).addParticipant(p);
continue;
}
final ParticipantEnglober parent = englober.getParent();
pending = Doll.createTeoz(englober, p, tileArguments,
tileArguments.getSkinParam().getCurrentStyleBuilder());
if (parent != null && groups.containsKey(parent) == false)
groups.put(parent, Doll.createGroup(parent, tileArguments,
tileArguments.getSkinParam().getCurrentStyleBuilder(), true));
if (parent != null)
getParent(pending).addDoll(pending);
dolls.add(pending);
}
}
@ -76,8 +94,12 @@ public class Dolls {
public double getOffsetForEnglobers(StringBounder stringBounder) {
double result = 0;
for (DollLeaf doll : dolls) {
final double height = doll.getPreferredHeight();
for (Doll doll : dolls) {
double height = doll.getTitlePreferredHeight();
final Doll group = getParent(doll);
if (group != null)
height += group.getTitlePreferredHeight();
if (height > result)
result = height;
@ -86,8 +108,8 @@ public class Dolls {
}
public void addConstraints(StringBounder stringBounder) {
DollLeaf last = null;
for (DollLeaf doll : dolls) {
Doll last = null;
for (Doll doll : dolls) {
doll.addInternalConstraints();
if (last != null)
last.addConstraintAfter(doll);
@ -96,9 +118,32 @@ public class Dolls {
}
}
private Doll getParent(Doll doll) {
final ParticipantEnglober parent = doll.getParticipantEnglober().getParent();
if (parent == null)
return null;
return groups.get(parent);
}
public void drawEnglobers(UGraphic ug, double height, Context2D context) {
for (DollLeaf doll : dolls)
doll.drawMe(ug, height, context);
for (Doll group : groups.values()) {
group.drawGroup(ug, height, context);
}
// DollGroup pending = null;
// for (DollLeaf doll : dolls) {
// final DollGroup group = doll.getGroup();
// if (group==null) {
//
// }
// // if (pending==null || pending.equals(group))
// if (group != null) {
// // group.drawMe(ug, height, context, doll.getX1().getCurrentValue(), doll.getX2().getCurrentValue());
// }
// }
for (Doll doll : dolls)
doll.drawMe(ug, height, context, getParent(doll));
}
@ -107,7 +152,7 @@ public class Dolls {
throw new IllegalStateException();
final List<Real> result = new ArrayList<>();
for (DollLeaf doll : dolls)
for (Doll doll : dolls)
result.add(doll.getMinX(stringBounder));
return RealUtils.min(result);
@ -118,7 +163,7 @@ public class Dolls {
throw new IllegalStateException();
final List<Real> result = new ArrayList<>();
for (DollLeaf doll : dolls)
for (Doll doll : dolls)
result.add(doll.getMaxX(stringBounder));
return RealUtils.max(result);

View File

@ -80,7 +80,7 @@ public class Version {
}
public static int beta() {
final int beta = 8;
final int beta = 9;
return beta;
}