1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-24 22:07:33 +00:00

ScXml improvement

This commit is contained in:
Arnaud Roques 2022-09-01 19:40:58 +02:00
parent 0dd8e23270
commit a562d24aa4
25 changed files with 347 additions and 264 deletions

View File

@ -183,7 +183,7 @@ public class CommandCreateElementFull2 extends SingleLineCommand2<ClassDiagram>
type = LeafType.DESCRIPTION;
usymbol = diagram.getSkinParam().actorStyle().toUSymbol();
} else if (symbol.equalsIgnoreCase("port")) {
type = LeafType.PORT;
type = LeafType.PORTIN;
usymbol = null;
} else if (symbol.equalsIgnoreCase("portin")) {
type = LeafType.PORTIN;

View File

@ -211,9 +211,9 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
final IEntity cl1;
if (idShort == null) {
cl1 = diagram.getLastEntity();
if (cl1 == null) {
if (cl1 == null)
return CommandExecutionResult.error("Nothing to note to");
}
} else {
final Ident ident = diagram.buildLeafIdent(idShort);
final Code code = diagram.V1972() ? ident : diagram.buildCode(idShort);
@ -247,9 +247,9 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
}
note.setColors(colors);
if (url != null) {
if (url != null)
note.addUrl(url);
}
CommandCreateClassMultilines.addTags(note, line0.get("TAGS", 0));
final Position position = Position.valueOf(StringUtils.goUpperCase(pos))
@ -258,19 +258,15 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
final LinkType type = new LinkType(LinkDecor.NONE, LinkDecor.NONE).goDashed();
if (position == Position.RIGHT) {
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), cl1, note, type,
LinkArg.noDisplay(1));
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), cl1, note, type, LinkArg.noDisplay(1));
link.setHorizontalSolitary(true);
} else if (position == Position.LEFT) {
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), note, cl1, type,
LinkArg.noDisplay(1));
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), note, cl1, type, LinkArg.noDisplay(1));
link.setHorizontalSolitary(true);
} else if (position == Position.BOTTOM) {
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), cl1, note, type,
LinkArg.noDisplay(2));
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), cl1, note, type, LinkArg.noDisplay(2));
} else if (position == Position.TOP) {
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), note, cl1, type,
LinkArg.noDisplay(2));
link = new Link(diagram.getSkinParam().getCurrentStyleBuilder(), note, cl1, type, LinkArg.noDisplay(2));
} else {
throw new IllegalArgumentException();
}

View File

@ -42,9 +42,17 @@ public class EntityPort {
private final String entityUid;
private final String portId;
public EntityPort(String entityUid, String portName) {
private EntityPort(String entityUid, String portId) {
this.entityUid = entityUid;
this.portId = portName == null ? null : Ports.encodePortNameToId(portName);
this.portId = portId;
}
public static EntityPort create(String entityUid, String portName) {
return new EntityPort(entityUid, portName == null ? null : Ports.encodePortNameToId(portName));
}
public static EntityPort forPort(String entityUid) {
return new EntityPort(entityUid, "P");
}
public String getFullString() {
@ -72,4 +80,5 @@ public class EntityPort {
public boolean equalsId(EntityPort other) {
return this.entityUid.equals(other.entityUid);
}
}

View File

@ -51,7 +51,7 @@ import net.sourceforge.plantuml.ugraphic.UTranslate;
public enum EntityPosition {
NORMAL, ENTRY_POINT, EXIT_POINT, INPUT_PIN, OUTPUT_PIN, EXPANSION_INPUT, EXPANSION_OUTPUT, PORT, PORTIN, PORTOUT;
NORMAL, ENTRY_POINT, EXIT_POINT, INPUT_PIN, OUTPUT_PIN, EXPANSION_INPUT, EXPANSION_OUTPUT, PORTIN, PORTOUT;
public static final double RADIUS = 6;
@ -70,7 +70,7 @@ public enum EntityPosition {
drawLine(ug, getPointOnCircle(xc, yc, -Math.PI / 4, radius),
getPointOnCircle(xc, yc, Math.PI - Math.PI / 4, radius));
}
} else if (this == INPUT_PIN || this == OUTPUT_PIN || this == PORT) {
} else if (this == INPUT_PIN || this == OUTPUT_PIN /*|| this == PORT*/) {
final Shadowable rectangle = new URectangle(RADIUS * 2, RADIUS * 2);
ug.draw(rectangle);
} else if (this == EXPANSION_INPUT || this == EXPANSION_OUTPUT) {
@ -121,14 +121,14 @@ public enum EntityPosition {
throw new IllegalStateException();
if (this == ENTRY_POINT || this == EXIT_POINT)
return ShapeType.CIRCLE;
return ShapeType.RECTANGLE_PORT;
return ShapeType.RECTANGLE;
}
public static EntityPosition fromStereotype(String label) {
if ("<<port>>".equalsIgnoreCase(label))
return PORT;
throw new UnsupportedOperationException();
if ("<<entrypoint>>".equalsIgnoreCase(label))
return ENTRY_POINT;
@ -159,12 +159,16 @@ public enum EntityPosition {
return EnumSet.of(EXIT_POINT, OUTPUT_PIN, EXPANSION_OUTPUT, PORTOUT);
}
public static EnumSet<EntityPosition> getSame() {
return EnumSet.of(PORT);
// public static EnumSet<EntityPosition> getSame() {
// return EnumSet.of(PORT);
// }
//
public boolean isPort() {
return /*this == PORT ||*/ this == PORTIN || this == PORTOUT;
}
public boolean isPort() {
return this == PORT || this == PORTIN || this == PORTOUT;
public boolean usePortP() {
return isPort() || this == EXIT_POINT || this == ENTRY_POINT;
}
}

View File

@ -67,11 +67,10 @@ public class GroupRoot implements IGroup {
@Override
public Collection<ILeaf> getLeafsDirect() {
final List<ILeaf> result = new ArrayList<>();
for (ILeaf ent : entityFactory.leafs()) {
if (ent.getParentContainer() == this) {
for (ILeaf ent : entityFactory.leafs())
if (ent.getParentContainer() == this)
result.add(ent);
}
}
return Collections.unmodifiableCollection(result);
}
@ -157,18 +156,13 @@ public class GroupRoot implements IGroup {
public Collection<IGroup> getChildren() {
final List<IGroup> result = new ArrayList<>();
if (entityFactory.namespaceSeparator.V1972()) {
for (IGroup ent : entityFactory.groups()) {
if (ent.getIdent().size() == 1) {
for (IGroup ent : entityFactory.groups())
if (ent.getIdent().size() == 1)
result.add(ent);
}
}
} else {
for (IGroup ent : entityFactory.groups()) {
if (ent.getParentContainer() == this) {
for (IGroup ent : entityFactory.groups())
if (ent.getParentContainer() == this)
result.add(ent);
}
}
}
return Collections.unmodifiableCollection(result);
}

View File

@ -59,7 +59,7 @@ public enum LeafType {
DOMAIN, REQUIREMENT,
PORT, PORTIN, PORTOUT,
PORTIN, PORTOUT,
STILL_UNKNOWN;

View File

@ -193,11 +193,17 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public EntityPort getEntityPort1(Bibliotekon bibliotekon) {
return new EntityPort(bibliotekon.getNodeUid((ILeaf) cl1), port1);
return getEntityPort((ILeaf) cl1, port1, bibliotekon);
}
public EntityPort getEntityPort2(Bibliotekon bibliotekon) {
return new EntityPort(bibliotekon.getNodeUid((ILeaf) cl2), port2);
return getEntityPort((ILeaf) cl2, port2, bibliotekon);
}
private EntityPort getEntityPort(ILeaf leaf, String port, Bibliotekon bibliotekon) {
if (leaf.getEntityPosition().usePortP())
return EntityPort.forPort(bibliotekon.getNodeUid(leaf));
return EntityPort.create(bibliotekon.getNodeUid(leaf), port);
}
@Override

View File

@ -329,9 +329,8 @@ final public class EntityImpl implements ILeaf, IGroup {
}
public EntityPosition getEntityPosition() {
checkNotGroup();
if (leafType == LeafType.PORT)
return EntityPosition.PORT;
// if (leafType == LeafType.PORT)
// return EntityPosition.PORT;
if (leafType == LeafType.PORTIN)
return EntityPosition.PORTIN;

View File

@ -209,7 +209,7 @@ public class CommandCreateElementFull extends SingleLineCommand2<DescriptionDiag
type = LeafType.PORTOUT;
usymbol = null;
} else if (symbol.equalsIgnoreCase("port")) {
type = LeafType.PORT;
type = LeafType.PORTIN;
usymbol = null;
} else if (symbol.equalsIgnoreCase("usecase")) {
type = LeafType.USECASE;

View File

@ -90,10 +90,9 @@ import net.sourceforge.plantuml.ugraphic.color.HColors;
public class Cluster implements Moveable {
/* private */ static final String RANK_SAME = "same";
// /* private */ static final String RANK_SAME = "same";
/* private */ static final String RANK_SOURCE = "source";
/* private */ static final String RANK_SINK = "sink";
/* private */ static final String ID_EE = "ee";
public final static String CENTER_ID = "za";
private final Cluster parentCluster;

View File

@ -58,6 +58,7 @@ public class ClusterDotString {
private final Cluster cluster;
private final ISkinParam skinParam;
private static final String ID_EE = "ee";
public ClusterDotString(Cluster cluster, ISkinParam skinParam) {
this.cluster = cluster;
@ -113,9 +114,9 @@ public class ClusterDotString {
if (entityPositionsExceptNormal.size() > 0) {
printClusterEntryExit(sb, stringBounder);
if (hasPort())
subgraphClusterNoLabel(sb, Cluster.ID_EE);
subgraphClusterNoLabel(sb, ID_EE);
else
subgraphClusterWithLabel(sb, Cluster.ID_EE, label);
subgraphClusterWithLabel(sb, ID_EE, label);
} else {
sb.append("label=" + label + ";");
@ -225,31 +226,29 @@ public class ClusterDotString {
}
private void printClusterEntryExit(StringBuilder sb, StringBounder stringBounder) {
printRanks(Cluster.RANK_SOURCE, withPositionProtected(stringBounder, EntityPosition.getInputs()), sb,
stringBounder);
printRanks(Cluster.RANK_SAME, withPositionProtected(stringBounder, EntityPosition.getSame()), sb,
stringBounder);
printRanks(Cluster.RANK_SINK, withPositionProtected(stringBounder, EntityPosition.getOutputs()), sb,
stringBounder);
printRanks(Cluster.RANK_SOURCE, withPosition(EntityPosition.getInputs()), sb, stringBounder);
// printRanks(Cluster.RANK_SAME, withPosition(EntityPosition.getSame()), sb,
// stringBounder);
printRanks(Cluster.RANK_SINK, withPosition(EntityPosition.getOutputs()), sb, stringBounder);
}
private void printRanks(String rank, List<? extends IShapePseudo> entries, StringBuilder sb,
private void printRanks(String rank, List<? extends SvekNode> entries, StringBuilder sb,
StringBounder stringBounder) {
if (entries.size() > 0) {
sb.append("{rank=" + rank + ";");
for (IShapePseudo sh1 : entries)
for (SvekNode sh1 : entries)
sb.append(sh1.getUid() + ";");
sb.append("}");
SvekUtils.println(sb);
for (IShapePseudo sh2 : entries)
for (SvekNode sh2 : entries)
sh2.appendShape(sb, stringBounder);
SvekUtils.println(sb);
if (hasPort()) {
boolean arrow = false;
String node = null;
for (IShapePseudo sh : entries) {
for (SvekNode sh : entries) {
if (arrow)
sb.append("->");
@ -268,28 +267,6 @@ public class ClusterDotString {
}
}
private List<? extends IShapePseudo> withPositionProtected(StringBounder stringBounder,
Set<EntityPosition> targets) {
final List<SvekNode> result = withPosition(targets);
final double maxWith = getMaxWidthFromLabelForEntryExit(result, stringBounder);
final double naturalSpace = 70;
if (maxWith > naturalSpace)
return addProtection(result, maxWith - naturalSpace);
return result;
}
private List<IShapePseudo> addProtection(List<? extends IShapePseudo> entries, double width) {
final List<IShapePseudo> result = new ArrayList<>();
result.add(entries.get(0));
for (int i = 1; i < entries.size(); i++) {
// Pseudo space for the label
result.add(new ShapePseudoImpl("psd" + cluster.diagram.getUniqueSequence(), width, 5));
result.add(entries.get(i));
}
return result;
}
private List<SvekNode> withPosition(Set<EntityPosition> positions) {
final List<SvekNode> result = new ArrayList<>();
for (final Iterator<SvekNode> it = cluster.getNodes().iterator(); it.hasNext();) {
@ -301,21 +278,6 @@ public class ClusterDotString {
return result;
}
private double getMaxWidthFromLabelForEntryExit(List<? extends IShapePseudo> entries, StringBounder stringBounder) {
double result = -Double.MAX_VALUE;
for (IShapePseudo node : entries) {
final double w = getMaxWidthFromLabelForEntryExit(node, stringBounder);
if (w > result)
result = w;
}
return result;
}
private double getMaxWidthFromLabelForEntryExit(IShapePseudo node, StringBounder stringBounder) {
return node.getMaxWidthFromLabelForEntryExit(stringBounder);
}
private boolean protection0(UmlDiagramType type) {
if (skinParam.useSwimlanes(type))
return false;

View File

@ -94,7 +94,8 @@ public class DotStringFactory implements Moveable {
this.colorSequence = new ColorSequence();
this.stringBounder = stringBounder;
this.root = new Cluster(dotData.getEntityFactory().getDiagram(), colorSequence, skinParam, dotData.getRootGroup());
this.root = new Cluster(dotData.getEntityFactory().getDiagram(), colorSequence, skinParam,
dotData.getRootGroup());
this.current = root;
}
@ -401,8 +402,7 @@ public class DotStringFactory implements Moveable {
// corner1.manage(minX, minY);
node.moveSvek(minX, minY);
node.setPolygon(minX, minY, points);
} else if (node.getType() == ShapeType.CIRCLE || node.getType() == ShapeType.CIRCLE_IN_RECT
|| node.getType() == ShapeType.OVAL) {
} else if (node.getType() == ShapeType.CIRCLE || node.getType() == ShapeType.OVAL) {
final double cx = SvekUtils.getValue(svg, idx, "cx");
final double cy = SvekUtils.getValue(svg, idx, "cy") + fullHeight;
final double rx = SvekUtils.getValue(svg, idx, "rx");

View File

@ -170,8 +170,8 @@ public final class GeneralImageBuilder {
if (leaf.getLeafType() == LeafType.ACTIVITY)
return new EntityImageActivity(leaf, skinParam, bibliotekon);
if ((leaf.getLeafType() == LeafType.PORT) || (leaf.getLeafType() == LeafType.PORTIN)
|| (leaf.getLeafType() == LeafType.PORTOUT)) {
if (/*(leaf.getLeafType() == LeafType.PORT) || */leaf.getLeafType() == LeafType.PORTIN
|| leaf.getLeafType() == LeafType.PORTOUT) {
final Cluster parent = bibliotekon.getCluster(leaf.getParentContainer());
return new EntityImagePort(leaf, skinParam, parent, bibliotekon, umlDiagramType.getStyleName());
}

View File

@ -1,48 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2023, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.svek;
import net.sourceforge.plantuml.graphic.StringBounder;
public interface IShapePseudo {
String getUid();
void appendShape(StringBuilder sb, StringBounder stringBounder);
double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder);
}

View File

@ -1,67 +0,0 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2023, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.svek;
import net.sourceforge.plantuml.graphic.StringBounder;
public class ShapePseudoImpl implements IShapePseudo {
private final String uid;
private final double width;
private final double height;
public ShapePseudoImpl(String uid, double width, double height) {
this.uid = uid;
this.width = width;
this.height = height;
}
public String getUid() {
return uid;
}
public void appendShape(StringBuilder sb, StringBounder stringBounder) {
sb.append(uid + " [shape=rect,label=\"\"");
sb.append(",width=" + SvekUtils.pixelToInches(width));
sb.append(",height=" + SvekUtils.pixelToInches(height));
sb.append("];");
}
public double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder) {
throw new UnsupportedOperationException();
}
}

View File

@ -43,7 +43,6 @@ public enum ShapeType {
RECTANGLE_HTML_FOR_PORTS, //
ROUND_RECTANGLE, //
CIRCLE, //
CIRCLE_IN_RECT, //
OVAL, //
DIAMOND, //
OCTAGON, //

View File

@ -48,14 +48,15 @@ import net.sourceforge.plantuml.cucadiagram.ILeaf;
import net.sourceforge.plantuml.cucadiagram.entity.EntityImpl;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.posimo.Positionable;
import net.sourceforge.plantuml.svek.image.AbstractEntityImageBorder;
import net.sourceforge.plantuml.svek.image.EntityImageDescription;
import net.sourceforge.plantuml.svek.image.EntityImageLollipopInterface;
import net.sourceforge.plantuml.svek.image.EntityImagePort;
import net.sourceforge.plantuml.svek.image.EntityImageStateBorder;
import net.sourceforge.plantuml.ugraphic.Shadowable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UPolygon;
public class SvekNode implements Positionable, IShapePseudo, Hideable {
public class SvekNode implements Positionable, Hideable {
private final ShapeType type;
private Dimension2D dimImage;
@ -164,7 +165,46 @@ public class SvekNode implements Positionable, IShapePseudo, Hideable {
SvekUtils.println(sb);
}
private void appendLabelHtmlSpecialForPort(StringBuilder sb, StringBounder stringBounder2) {
private double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder) {
if (image instanceof EntityImagePort) {
final EntityImagePort im = (EntityImagePort) image;
return im.getMaxWidthFromLabelForEntryExit(stringBounder);
}
if (image instanceof EntityImageStateBorder) {
final EntityImageStateBorder im = (EntityImageStateBorder) image;
return im.getMaxWidthFromLabelForEntryExit(stringBounder);
}
throw new UnsupportedOperationException();
}
private void appendLabelHtmlSpecialForPort(StringBuilder sb, StringBounder stringBounder) {
final int width1 = (int) getWidth();
final int width2 = (int) getMaxWidthFromLabelForEntryExit(stringBounder);
if (width2 > 40)
appendLabelHtmlSpecialForPortHtml(sb, stringBounder, width2 - 40);
else
appendLabelHtmlSpecialForPortBasic(sb, stringBounder);
}
private void appendLabelHtmlSpecialForPortHtml(StringBuilder sb, StringBounder stringBounder, int fullWidth) {
if (fullWidth < 10)
fullWidth = 10;
sb.append(uid);
sb.append(" [");
sb.append("shape=plaintext");
sb.append(",");
sb.append("label=<");
sb.append("<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
sb.append("<TR><TD WIDTH=\"" + fullWidth + "\" HEIGHT=\"1\" COLSPAN=\"3\"></TD></TR>");
sb.append("<TR><TD></TD><TD FIXEDSIZE=\"TRUE\" PORT=\"P\" BORDER=\"1\" COLOR=\""
+ StringUtils.sharp000000(color) + "\" WIDTH=\"" + (int) getWidth() + "\" HEIGHT=\"" + (int) getHeight()
+ "\"></TD><TD></TD></TR>");
sb.append("<TR><TD WIDTH=\"" + fullWidth + "\" HEIGHT=\"1\" COLSPAN=\"3\"></TD></TR>");
sb.append("</TABLE>");
sb.append(">];");
}
private void appendLabelHtmlSpecialForPortBasic(StringBuilder sb, StringBounder stringBounder) {
sb.append(uid);
sb.append(" [");
sb.append("shape=rect");
@ -294,8 +334,6 @@ public class SvekNode implements Positionable, IShapePseudo, Hideable {
sb.append("shape=diamond");
else if (type == ShapeType.CIRCLE)
sb.append("shape=circle");
else if (type == ShapeType.CIRCLE_IN_RECT)
sb.append("shape=circle");
else if (type == ShapeType.OVAL)
sb.append("shape=ellipse");
else if (type == ShapeType.ROUND_RECTANGLE)
@ -349,16 +387,6 @@ public class SvekNode implements Positionable, IShapePseudo, Hideable {
this.minY += deltaY;
}
public double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder) {
if (image instanceof AbstractEntityImageBorder) {
final AbstractEntityImageBorder im = (AbstractEntityImageBorder) image;
return im.getMaxWidthFromLabelForEntryExit(stringBounder);
} else {
final Dimension2D dim = image.calculateDimension(stringBounder);
return dim.getWidth();
}
}
public boolean isHidden() {
return image.isHidden();
}

View File

@ -82,11 +82,6 @@ public abstract class AbstractEntityImageBorder extends AbstractEntityImage {
return entityPosition.getDimension(rankdir);
}
public double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder) {
final Dimension2D dimDesc = desc.calculateDimension(stringBounder);
return dimDesc.getWidth();
}
public ShapeType getShapeType() {
return entityPosition.getShapeType();
}

View File

@ -135,7 +135,7 @@ public class EntityImageLollipopInterface extends AbstractEntityImage {
}
public ShapeType getShapeType() {
return ShapeType.CIRCLE_IN_RECT;
return ShapeType.CIRCLE;
}
private double angle;

View File

@ -42,6 +42,7 @@ import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.awt.geom.Dimension2D;
import net.sourceforge.plantuml.cucadiagram.EntityPosition;
import net.sourceforge.plantuml.cucadiagram.ILeaf;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.SName;
@ -106,5 +107,11 @@ public class EntityImageStateBorder extends AbstractEntityImageBorder {
private UStroke getUStroke() {
return new UStroke(1.5);
}
public double getMaxWidthFromLabelForEntryExit(StringBounder stringBounder) {
final Dimension2D dimDesc = desc.calculateDimension(stringBounder);
return dimDesc.getWidth();
}
}

View File

@ -81,7 +81,7 @@ public class Version {
}
public static int beta() {
final int beta = 4;
final int beta = 5;
return beta;
}

View File

@ -52,10 +52,15 @@ import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import net.sourceforge.plantuml.Guillemet;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.cucadiagram.EntityUtils;
import net.sourceforge.plantuml.cucadiagram.IEntity;
import net.sourceforge.plantuml.cucadiagram.IGroup;
import net.sourceforge.plantuml.cucadiagram.ILeaf;
import net.sourceforge.plantuml.cucadiagram.LeafType;
import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
import net.sourceforge.plantuml.statediagram.StateDiagram;
import net.sourceforge.plantuml.xml.XmlFactories;
@ -76,34 +81,54 @@ public class ScxmlStateDiagramStandard {
scxml.setAttribute("xmlns", "http://www.w3.org/2005/07/scxml");
scxml.setAttribute("version", "1.0");
final String initial = getInitial();
if (initial != null) {
if (initial != null)
scxml.setAttribute("initial", initial);
}
document.appendChild(scxml);
for (final IEntity ent : diagram.getLeafsvalues()) {
scxml.appendChild(createState(ent));
}
for (final IEntity ent : diagram.getLeafsvalues())
if (EntityUtils.groupRoot(ent.getParentContainer()))
scxml.appendChild(createState(ent));
for (IGroup ent : diagram.getGroups(false))
if (EntityUtils.groupRoot(ent.getParentContainer()))
exportGroup(scxml, ent);
}
private Element exportGroup(Element dest, IGroup ent) {
final Element gr = createGroup(ent);
dest.appendChild(gr);
for (ILeaf leaf : ent.getLeafsDirect())
gr.appendChild(createState(leaf));
for (IGroup child : ent.getChildren())
exportGroup(gr, child);
return gr;
}
private String getInitial() {
for (final IEntity ent : diagram.getLeafsvalues()) {
if (ent.getLeafType() == LeafType.CIRCLE_START) {
for (final IEntity ent : diagram.getLeafsvalues())
if (ent.getLeafType() == LeafType.CIRCLE_START)
return getId(ent);
}
}
return null;
}
private Element createGroup(IEntity entity) {
return createState(entity);
}
private Element createState(IEntity entity) {
final Element state = document.createElement("state");
state.setAttribute("id", getId(entity));
for (final Link link : diagram.getLinks()) {
if (link.getEntity1() == entity) {
addLink(state, link);
}
final Stereotype stereotype = entity.getStereotype();
if (stereotype != null) {
state.setAttribute("stereotype", stereotype.getLabels(Guillemet.NONE).get(0));
}
for (final Link link : diagram.getLinks())
if (link.getEntity1() == entity)
addLink(state, link);
return state;
}

View File

@ -33,20 +33,22 @@ Expected result MUST be put between triple brackets
{{{
<?xml version="1.0" encoding="UTF-8"?><scxml xmlns="http://www.w3.org/2005/07/scxml" initial="startcounter" version="1.0">
<state id="count_start"/>
<state id="count_done"/>
<state id="count_val[3:0]"/>
<state id="startcounter">
<transition target="count_idle"/>
</state>
<state id="count_idle">
<transition event="count_start" target="count_ongoing"/>
</state>
<state id="count_ongoing">
<transition event="count_val != MAX_VAL" target="count_finish"/>
</state>
<state id="count_finish">
<transition target="count_idle"/>
<state id="counter">
<state id="count_start"/>
<state id="count_done"/>
<state id="count_val[3:0]"/>
<state id="startcounter">
<transition target="count_idle"/>
</state>
<state id="count_idle">
<transition event="count_start" target="count_ongoing"/>
</state>
<state id="count_ongoing">
<transition event="count_val != MAX_VAL" target="count_finish"/>
</state>
<state id="count_finish">
<transition target="count_idle"/>
</state>
</state>
</scxml>
}}}

View File

@ -0,0 +1,118 @@
package nonreg.scxml;
import java.io.IOException;
import org.junit.jupiter.api.Test;
/*
https://github.com/plantuml/plantuml/issues/1101
Test diagram MUST be put between triple quotes
"""
@startuml
state module {
state Somp {
state entry1 <<inputPin>>
state entry2 <<inputPin>>
state sin
sin -> sin2
}
state flop{
state sig_in <<inputPin>>
state sig_ff <<outputPin>>
state flop_0: sig_ff := 0
state flop_1: sig_ff := 1
[*] -> flop_0
flop_0 -> flop_1 : sig_in
}
state counter{
state count_start <<inputPin>>
state count_done <<outputPin>>
state "count_val[3:0]" <<outputPin>>
[*] -> count_idle
count_idle --> count_ongoing: count_start
state count_idle: count_val := 0
state count_ongoing: count_val := count_val +1
count_ongoing -> count_finish: count_val != MAX_VAL
state count_finish: count_done:=1
count_finish -> count_idle
}
state ex <<inputPin>>
state exitAx <<inputPin>>
exitAx --> entry1
sig_ff -> entry2 : "!"
}
@enduml
"""
Expected result MUST be put between triple brackets
{{{
<?xml version="1.0" encoding="UTF-8"?><scxml xmlns="http://www.w3.org/2005/07/scxml" initial="startflop" version="1.0">
<state id="module">
<state id="ex" stereotype="inputPin"/>
<state id="exitAx" stereotype="inputPin">
<transition target="entry1"/>
</state>
<state id="Somp">
<state id="entry1" stereotype="inputPin"/>
<state id="entry2" stereotype="inputPin"/>
<state id="sin">
<transition target="sin2"/>
</state>
<state id="sin2"/>
</state>
<state id="flop">
<state id="sig_in" stereotype="inputPin"/>
<state id="sig_ff" stereotype="outputPin">
<transition event="&quot;!&quot;" target="entry2"/>
</state>
<state id="flop_0">
<transition event="sig_in" target="flop_1"/>
</state>
<state id="flop_1"/>
<state id="startflop">
<transition target="flop_0"/>
</state>
</state>
<state id="counter">
<state id="count_start" stereotype="inputPin"/>
<state id="count_done" stereotype="outputPin"/>
<state id="count_val[3:0]" stereotype="outputPin"/>
<state id="startcounter">
<transition target="count_idle"/>
</state>
<state id="count_idle">
<transition event="count_start" target="count_ongoing"/>
</state>
<state id="count_ongoing">
<transition event="count_val != MAX_VAL" target="count_finish"/>
</state>
<state id="count_finish">
<transition target="count_idle"/>
</state>
</state>
</state>
</scxml>
}}}
*/
public class SCXML0003_Test extends ScXmlTest {
@Test
void testSimple() throws IOException {
checkXmlAndDescription("(18 entities)");
}
}

View File

@ -0,0 +1,55 @@
package nonreg.scxml;
import java.io.IOException;
import org.junit.jupiter.api.Test;
/*
https://github.com/plantuml/plantuml/issues/1101
Test diagram MUST be put between triple quotes
"""
@startuml
state module {
state flop
state Somp {
state entry1 <<inputPin>>
state entry2 <<inputPin>>
state sin
sin -> sin2
}
}
@enduml
"""
Expected result MUST be put between triple brackets
{{{
<?xml version="1.0" encoding="UTF-8"?><scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0">
<state id="module">
<state id="flop"/>
<state id="Somp">
<state id="entry1" stereotype="inputPin"/>
<state id="entry2" stereotype="inputPin"/>
<state id="sin">
<transition target="sin2"/>
</state>
<state id="sin2"/>
</state>
</state>
</scxml>
}}}
*/
public class SCXML0004_Test extends ScXmlTest {
@Test
void testSimple() throws IOException {
checkXmlAndDescription("(5 entities)");
}
}