diff --git a/src/net/sourceforge/plantuml/FileFormat.java b/src/net/sourceforge/plantuml/FileFormat.java index 0e42638fc..501fce883 100644 --- a/src/net/sourceforge/plantuml/FileFormat.java +++ b/src/net/sourceforge/plantuml/FileFormat.java @@ -62,28 +62,30 @@ import net.sourceforge.plantuml.ugraphic.debug.StringBounderDebug; * */ public enum FileFormat { - PNG("image/png"), - SVG("image/svg+xml"), - EPS("application/postscript"), - EPS_TEXT("application/postscript"), - ATXT("text/plain"), - UTXT("text/plain;charset=UTF-8"), - XMI_STANDARD("application/vnd.xmi+xml"), - XMI_STAR("application/vnd.xmi+xml"), - XMI_ARGO("application/vnd.xmi+xml"), - SCXML("application/scxml+xml"), - PDF("application/pdf"), - MJPEG("video/x-msvideo"), - ANIMATED_GIF("image/gif"), - HTML("text/html"), - HTML5("text/html"), - VDX("application/vnd.visio.xml"), - LATEX("application/x-latex"), - LATEX_NO_PREAMBLE("application/x-latex"), - BASE64("text/plain; charset=x-user-defined"), - BRAILLE_PNG("image/png"), - PREPROC("text/plain"), - DEBUG("text/plain"); + + PNG("image/png"), // + SVG("image/svg+xml"), // + EPS("application/postscript"), // + EPS_TEXT("application/postscript"), // + ATXT("text/plain"), // + UTXT("text/plain;charset=UTF-8"), // + XMI_STANDARD("application/vnd.xmi+xml"), // + XMI_STAR("application/vnd.xmi+xml"), // + XMI_ARGO("application/vnd.xmi+xml"), // + SCXML("application/scxml+xml"), // + GRAPHML("application/graphml+xml"), // + PDF("application/pdf"), // + MJPEG("video/x-msvideo"), // + ANIMATED_GIF("image/gif"), // + HTML("text/html"), // + HTML5("text/html"), // + VDX("application/vnd.visio.xml"), // + LATEX("application/x-latex"), // + LATEX_NO_PREAMBLE("application/x-latex"), // + BASE64("text/plain; charset=x-user-defined"), // + BRAILLE_PNG("image/png"), // + PREPROC("text/plain"), // + DEBUG("text/plain"); // private final String mimeType; @@ -101,24 +103,24 @@ public enum FileFormat { * @return a string starting by a point. */ public String getFileSuffix() { - if (name().startsWith("XMI")) { + if (name().startsWith("XMI")) return ".xmi"; - } - if (this == MJPEG) { + + if (this == MJPEG) return ".avi"; - } - if (this == LATEX_NO_PREAMBLE) { + + if (this == LATEX_NO_PREAMBLE) return ".latex"; - } - if (this == ANIMATED_GIF) { + + if (this == ANIMATED_GIF) return ".gif"; - } - if (this == BRAILLE_PNG) { + + if (this == BRAILLE_PNG) return ".braille.png"; - } - if (this == EPS_TEXT) { + + if (this == EPS_TEXT) return EPS.getFileSuffix(); - } + return "." + StringUtils.goLowerCase(name()); } @@ -134,18 +136,18 @@ public enum FileFormat { } public StringBounder getDefaultStringBounder(TikzFontDistortion tikzFontDistortion, SvgCharSizeHack charSizeHack) { - if (this == LATEX || this == LATEX_NO_PREAMBLE) { + if (this == LATEX || this == LATEX_NO_PREAMBLE) return getTikzStringBounder(tikzFontDistortion); - } - if (this == BRAILLE_PNG) { + + if (this == BRAILLE_PNG) return getBrailleStringBounder(); - } - if (this == SVG) { + + if (this == SVG) return getSvgStringBounder(charSizeHack); - } - if (this == DEBUG) { + + if (this == DEBUG) return new StringBounderDebug(); - } + return getNormalStringBounder(); } @@ -233,43 +235,43 @@ public enum FileFormat { * @return true for EPS. */ public boolean isEps() { - if (this == EPS) { + if (this == EPS) return true; - } - if (this == EPS_TEXT) { + + if (this == EPS_TEXT) return true; - } + return false; } public String changeName(String fileName, int cpt) { - if (cpt == 0) { + if (cpt == 0) return changeName(fileName, getFileSuffix()); - } + return changeName(fileName, OptionFlags.getInstance().getFileSeparator() + String.format("%03d", cpt) + getFileSuffix()); } private SFile computeFilename(SFile pngFile, int i) { - if (i == 0) { + if (i == 0) return pngFile; - } + final SFile dir = pngFile.getParentFile(); return dir.file(computeFilenameInternal(pngFile.getName(), i)); } private String changeName(String fileName, String replacement) { String result = fileName.replaceAll("\\.\\w+$", replacement); - if (result.equals(fileName)) { + if (result.equals(fileName)) result = fileName + replacement; - } + return result; } private String computeFilenameInternal(String name, int i) { - if (i == 0) { + if (i == 0) return name; - } + return name.replaceAll("\\" + getFileSuffix() + "$", OptionFlags.getInstance().getFileSeparator() + String.format("%03d", i) + getFileSuffix()); } @@ -288,9 +290,9 @@ public enum FileFormat { } if (this == SVG) { final String svg = FileUtils.readSvg(existingFile); - if (svg == null) { + if (svg == null) return false; - } + final String currentSignature = SvgGraphics.getMD5Hex(currentMetadata); final int idx = svg.lastIndexOf(SvgGraphics.MD5_HEADER); if (idx != -1) { diff --git a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagram.java b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagram.java index 86402f477..c267c9e12 100644 --- a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagram.java +++ b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagram.java @@ -55,7 +55,6 @@ import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.NamespaceStrategy; import net.sourceforge.plantuml.graphic.USymbol; -import net.sourceforge.plantuml.utils.UniqueSequence; public class ActivityDiagram extends CucaDiagram { @@ -73,7 +72,7 @@ public class ActivityDiagram extends CucaDiagram { } private String getAutoBranch() { - return "#" + UniqueSequence.getValue(); + return "#" + this.getUniqueSequence(); } public IEntity getOrCreate(Ident idNewLong, Code code, Display display, LeafType type) { @@ -173,7 +172,7 @@ public class ActivityDiagram extends CucaDiagram { public IEntity createInnerActivity() { // Log.println("createInnerActivity A"); - final String idShort = "##" + UniqueSequence.getValue(); + final String idShort = "##" + this.getUniqueSequence(); final Ident idNewLong = buildLeafIdent(idShort); final Code code = this.V1972() ? idNewLong : buildCode(idShort); gotoGroup(idNewLong, code, Display.getWithNewlines(code), GroupType.INNER_ACTIVITY, getCurrentGroup(), @@ -193,7 +192,7 @@ public class ActivityDiagram extends CucaDiagram { endGroup(); // Log.println("endgroup"); } - final String idShort = "##" + UniqueSequence.getValue(); + final String idShort = "##" + this.getUniqueSequence(); // Log.println("concurrentActivity A name=" + name+" "+getCurrentGroup()); final Code code = buildCode(idShort); if (getCurrentGroup().getGroupType() != GroupType.INNER_ACTIVITY) { diff --git a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java index 353199b0a..2647ae6ff 100644 --- a/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java +++ b/src/net/sourceforge/plantuml/activitydiagram/ActivityDiagramFactory.java @@ -51,8 +51,8 @@ import net.sourceforge.plantuml.classdiagram.command.CommandHideShow2; import net.sourceforge.plantuml.command.Command; import net.sourceforge.plantuml.command.CommandFootboxIgnored; import net.sourceforge.plantuml.command.CommandRankDir; -import net.sourceforge.plantuml.command.PSystemCommandFactory; import net.sourceforge.plantuml.command.CommonCommands; +import net.sourceforge.plantuml.command.PSystemCommandFactory; import net.sourceforge.plantuml.command.note.CommandFactoryNoteActivity; import net.sourceforge.plantuml.command.note.CommandFactoryNoteOnLink; import net.sourceforge.plantuml.core.UmlSource; diff --git a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClass.java b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClass.java index a4c1a8b18..f80d844c0 100644 --- a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClass.java +++ b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClass.java @@ -126,7 +126,8 @@ public class CommandCreateClass extends SingleLineCommand2 { @Override protected CommandExecutionResult executeArg(ClassDiagram diagram, LineLocation location, RegexResult arg) throws NoSuchColorException { - final LeafType type = LeafType.getLeafType(StringUtils.goUpperCase(arg.get("TYPE", 0))); + final String typeString = StringUtils.goUpperCase(arg.get("TYPE", 0)); + final LeafType type = LeafType.getLeafType(typeString); final String idShort = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg.getLazzy("CODE", 0), "\"([:"); final String display = arg.getLazzy("DISPLAY", 0); @@ -191,6 +192,9 @@ public class CommandCreateClass extends SingleLineCommand2 { CommandCreateClassMultilines.manageExtends("IMPLEMENTS", diagram, arg, entity); CommandCreateClassMultilines.addTags(entity, arg.get("TAGS", 0)); + if (typeString.contains("STATIC")) + entity.setStatic(true); + return CommandExecutionResult.ok(); } diff --git a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java index 117faae7b..9f9341a91 100644 --- a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java +++ b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateClassMultilines.java @@ -226,7 +226,8 @@ public class CommandCreateClassMultilines extends CommandMultilines2 { @@ -124,7 +123,7 @@ final public class CommandLinkLollipop extends SingleLineCommand2 { @@ -111,7 +110,7 @@ public class CommandPackage extends SingleLineCommand2 { boolean override1972 = false; if (arg.get("AS", 0) == null) { if (name.length() == 0) { - idShort = "##" + UniqueSequence.getValue(); + idShort = "##" + diagram.getUniqueSequence(); display = null; } else { idShort = name; diff --git a/src/net/sourceforge/plantuml/command/CommandPackageEmpty.java b/src/net/sourceforge/plantuml/command/CommandPackageEmpty.java index f858833d2..3ba9c5d64 100644 --- a/src/net/sourceforge/plantuml/command/CommandPackageEmpty.java +++ b/src/net/sourceforge/plantuml/command/CommandPackageEmpty.java @@ -52,7 +52,6 @@ import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.NamespaceStrategy; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException; -import net.sourceforge.plantuml.utils.UniqueSequence; public class CommandPackageEmpty extends SingleLineCommand2 { @@ -88,7 +87,7 @@ public class CommandPackageEmpty extends SingleLineCommand2 { @@ -121,7 +120,7 @@ public final class CommandFactoryNoteActivity implements SingleMultiFactoryComma // final String s = StringUtils.getMergedLines(strings); - final String codeString = UniqueSequence.getString("GMN"); + final String codeString = diagram.getUniqueSequence("GMN"); final Ident ident = diagram.buildLeafIdent(codeString); final Code code = diagram.V1972() ? ident : diagram.buildCode(codeString); final IEntity note = diagram.createLeaf(ident, code, strings, LeafType.NOTE, null); @@ -139,7 +138,7 @@ public final class CommandFactoryNoteActivity implements SingleMultiFactoryComma @Override protected CommandExecutionResult executeArg(final ActivityDiagram diagram, LineLocation location, RegexResult arg) throws NoSuchColorException { - final String tmp = UniqueSequence.getString("GN"); + final String tmp = diagram.getUniqueSequence("GN"); final Ident ident = diagram.buildLeafIdent(tmp); final Code code = diagram.V1972() ? ident : diagram.buildCode(tmp); final IEntity note = diagram.createNote(ident, code, Display.getWithNewlines(arg.get("NOTE", 0))); diff --git a/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java index 9d743383c..0be05ac3f 100644 --- a/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryNoteOnEntity.java @@ -56,7 +56,6 @@ import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexOr; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.cucadiagram.Code; -import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; @@ -70,7 +69,6 @@ import net.sourceforge.plantuml.graphic.color.ColorParser; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.graphic.color.Colors; import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException; -import net.sourceforge.plantuml.utils.UniqueSequence; public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryCommand { @@ -229,7 +227,7 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma } } - final String tmp = UniqueSequence.getString("GMN"); + final String tmp = diagram.getUniqueSequence("GMN"); final Ident idNewLong = diagram.buildLeafIdent(tmp); final IEntity note; if (diagram.V1972()) diff --git a/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java b/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java index 0872a9c6d..6e692726c 100644 --- a/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java +++ b/src/net/sourceforge/plantuml/command/note/CommandFactoryTipOnEntity.java @@ -51,7 +51,6 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.cucadiagram.Code; -import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Ident; import net.sourceforge.plantuml.cucadiagram.LeafType; diff --git a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java index 60232f322..6abc9997d 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java +++ b/src/net/sourceforge/plantuml/cucadiagram/CucaDiagram.java @@ -44,6 +44,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import net.sourceforge.plantuml.BackSlash; import net.sourceforge.plantuml.FileFormat; @@ -62,6 +63,7 @@ import net.sourceforge.plantuml.cucadiagram.dot.CucaDiagramTxtMaker; import net.sourceforge.plantuml.cucadiagram.entity.EntityFactory; import net.sourceforge.plantuml.elk.CucaDiagramFileMakerElk; import net.sourceforge.plantuml.graphic.USymbol; +import net.sourceforge.plantuml.graphml.CucaDiagramGraphmlMaker; import net.sourceforge.plantuml.sdot.CucaDiagramFileMakerSmetana; import net.sourceforge.plantuml.security.SecurityUtils; import net.sourceforge.plantuml.skin.VisibilityModifier; @@ -559,6 +561,11 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return result.toArray(new String[result.size()]); } + private void createFilesGraphml(OutputStream suggestedFile) throws IOException { + final CucaDiagramGraphmlMaker maker = new CucaDiagramGraphmlMaker(this); + maker.createFiles(suggestedFile); + } + private void createFilesXmi(OutputStream suggestedFile, FileFormat fileFormat) throws IOException { final CucaDiagramXmiMaker maker = new CucaDiagramXmiMaker(this, fileFormat); maker.createFiles(suggestedFile); @@ -583,6 +590,11 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return ImageDataSimple.ok(); } + if (fileFormat == FileFormat.GRAPHML) { + createFilesGraphml(os); + return ImageDataSimple.ok(); + } + if (fileFormat.name().startsWith("XMI")) { createFilesXmi(os, fileFormat); return ImageDataSimple.ok(); @@ -789,6 +801,17 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return true; } + final public boolean isStandaloneForArgo(IEntity ent) { + for (final Link link : getLinks()) { + if (link.isHidden() || link.isInvis()) + continue; + if (link.getEntity1() == ent || link.getEntity2() == ent) + return false; + } + + return true; + } + final public Link getLastLink() { final List links = getLinks(); for (int i = links.size() - 1; i >= 0; i--) { @@ -874,4 +897,14 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy, return ClockwiseTopRightBottomLeft.topRightBottomLeft(0, 5, 5, 0); } + private final AtomicInteger cpt = new AtomicInteger(1); + + public int getUniqueSequence() { + return cpt.addAndGet(1); + } + + public String getUniqueSequence(String prefix) { + return prefix + getUniqueSequence(); + } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/EntityPosition.java b/src/net/sourceforge/plantuml/cucadiagram/EntityPosition.java index 8efd9c3a3..4e93a0f55 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/EntityPosition.java +++ b/src/net/sourceforge/plantuml/cucadiagram/EntityPosition.java @@ -95,9 +95,9 @@ public enum EntityPosition { public Dimension2D getDimension(Rankdir rankdir) { if (this == EXPANSION_INPUT || this == EXPANSION_OUTPUT) { - if (rankdir == Rankdir.TOP_TO_BOTTOM) { + if (rankdir == Rankdir.TOP_TO_BOTTOM) return new Dimension2DDouble(EntityPosition.RADIUS * 2 * 4, EntityPosition.RADIUS * 2); - } + return new Dimension2DDouble(EntityPosition.RADIUS * 2, EntityPosition.RADIUS * 2 * 4); } return new Dimension2DDouble(EntityPosition.RADIUS * 2, EntityPosition.RADIUS * 2); @@ -117,37 +117,37 @@ public enum EntityPosition { } public ShapeType getShapeType() { - if (this == NORMAL) { + if (this == NORMAL) throw new IllegalStateException(); - } - if (this == ENTRY_POINT || this == EXIT_POINT) { + + if (this == ENTRY_POINT || this == EXIT_POINT) return ShapeType.CIRCLE; - } + return ShapeType.RECTANGLE; } public static EntityPosition fromStereotype(String label) { - if ("<>".equalsIgnoreCase(label)) { + if ("<>".equalsIgnoreCase(label)) return PORT; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return ENTRY_POINT; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return EXIT_POINT; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return INPUT_PIN; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return OUTPUT_PIN; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return EXPANSION_INPUT; - } - if ("<>".equalsIgnoreCase(label)) { + + if ("<>".equalsIgnoreCase(label)) return EXPANSION_OUTPUT; - } + return EntityPosition.NORMAL; } diff --git a/src/net/sourceforge/plantuml/cucadiagram/ILeaf.java b/src/net/sourceforge/plantuml/cucadiagram/ILeaf.java index 6e5895955..900c083a3 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/ILeaf.java +++ b/src/net/sourceforge/plantuml/cucadiagram/ILeaf.java @@ -81,4 +81,8 @@ public interface ILeaf extends IEntity { public VisibilityModifier getVisibilityModifier(); + public void setStatic(boolean isStatic); + + public boolean isStatic(); + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/Link.java b/src/net/sourceforge/plantuml/cucadiagram/Link.java index 01b2dd697..bf851ffca 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Link.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Link.java @@ -46,6 +46,7 @@ import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.awt.geom.Dimension2D; import net.sourceforge.plantuml.command.Position; +import net.sourceforge.plantuml.cucadiagram.entity.EntityImpl; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; @@ -57,7 +58,6 @@ import net.sourceforge.plantuml.style.StyleBuilder; import net.sourceforge.plantuml.svek.Bibliotekon; import net.sourceforge.plantuml.ugraphic.UComment; import net.sourceforge.plantuml.ugraphic.UFont; -import net.sourceforge.plantuml.utils.UniqueSequence; public class Link extends WithLinkType implements Hideable, Removeable { @@ -73,7 +73,7 @@ public class Link extends WithLinkType implements Hideable, Removeable { private final LinkArg linkArg; - final private String uid = "LNK" + UniqueSequence.getValue(); + final private String uid; private Display note; private Position notePosition; @@ -120,7 +120,9 @@ public class Link extends WithLinkType implements Hideable, Removeable { this.styleBuilder = styleBuilder; this.cl1 = Objects.requireNonNull(cl1); this.cl2 = Objects.requireNonNull(cl2); + this.type = type; + this.uid = "LNK" + ((EntityImpl) cl1).getDiagram().getUniqueSequence(); this.linkArg = linkArg; } diff --git a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java index ddb13921a..1ab1af417 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java +++ b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityFactory.java @@ -512,4 +512,8 @@ public final class EntityFactory { return Objects.requireNonNull(parentContainer); } + public CucaDiagram getDiagram() { + return namespaceSeparator; + } + } diff --git a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java index 42280e562..7f1e614d2 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java +++ b/src/net/sourceforge/plantuml/cucadiagram/entity/EntityImpl.java @@ -57,6 +57,7 @@ import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.cucadiagram.Bodier; import net.sourceforge.plantuml.cucadiagram.Code; +import net.sourceforge.plantuml.cucadiagram.CucaDiagram; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.DisplayPositioned; import net.sourceforge.plantuml.cucadiagram.EntityPosition; @@ -85,7 +86,6 @@ import net.sourceforge.plantuml.svek.PackageStyle; import net.sourceforge.plantuml.svek.SingleStrategy; import net.sourceforge.plantuml.ugraphic.UFont; import net.sourceforge.plantuml.ugraphic.color.HColor; -import net.sourceforge.plantuml.utils.UniqueSequence; final public class EntityImpl implements ILeaf, IGroup { @@ -98,7 +98,7 @@ final public class EntityImpl implements ILeaf, IGroup { private Url url; private final Bodier bodier; - private final String uid = StringUtils.getUid("cl", UniqueSequence.getValue()); + private final String uid; private Display display = Display.empty(); private DisplayPositioned legend = null; @@ -150,6 +150,7 @@ final public class EntityImpl implements ILeaf, IGroup { private EntityImpl(Ident ident, EntityFactory entityFactory, Code code, Bodier bodier, IGroup parentContainer, String namespaceSeparator, int rawLayout) { this.ident = Objects.requireNonNull(ident); + this.uid = StringUtils.getUid("cl", entityFactory.getDiagram().getUniqueSequence()); if (entityFactory.namespaceSeparator.V1972()) code = ident; @@ -810,4 +811,20 @@ final public class EntityImpl implements ILeaf, IGroup { return Collections.unmodifiableList(result); } + public CucaDiagram getDiagram() { + return entityFactory.getDiagram(); + } + + private boolean isStatic; + + @Override + public void setStatic(boolean isStatic) { + this.isStatic = isStatic; + } + + @Override + public boolean isStatic() { + return isStatic; + } + } diff --git a/src/net/sourceforge/plantuml/descdiagram/command/CommandPackageWithUSymbol.java b/src/net/sourceforge/plantuml/descdiagram/command/CommandPackageWithUSymbol.java index f5fb05822..28e235f3b 100644 --- a/src/net/sourceforge/plantuml/descdiagram/command/CommandPackageWithUSymbol.java +++ b/src/net/sourceforge/plantuml/descdiagram/command/CommandPackageWithUSymbol.java @@ -64,7 +64,6 @@ import net.sourceforge.plantuml.graphic.color.ColorParser; import net.sourceforge.plantuml.graphic.color.ColorType; import net.sourceforge.plantuml.graphic.color.Colors; import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException; -import net.sourceforge.plantuml.utils.UniqueSequence; public class CommandPackageWithUSymbol extends SingleLineCommand2 { @@ -141,7 +140,7 @@ public class CommandPackageWithUSymbol extends SingleLineCommand2 same1 = getExistingAssociatedPoints(entity1A, entity1B); final List same2 = getExistingAssociatedPoints(entity2A, entity2B); if (same1.size() == 0 && same2.size() == 0) { - final String tmp1 = UniqueSequence.getString("apoint"); - final String tmp2 = UniqueSequence.getString("apoint"); + final String tmp1 = this.getUniqueSequence("apoint"); + final String tmp2 = this.getUniqueSequence("apoint"); final Ident ident1 = buildLeafIdent(tmp1); final Ident ident2 = buildLeafIdent(tmp2); final Code code1 = this.V1972() ? ident1 : buildCode(tmp1); @@ -252,7 +251,7 @@ public abstract class AbstractClassOrObjectDiagram extends AbstractEntityDiagram this.entity1 = entity1; this.entity2 = entity2; this.associed = associed; - final String idShort = UniqueSequence.getString("apoint"); + final String idShort = AbstractClassOrObjectDiagram.this.getUniqueSequence("apoint"); final Ident ident = buildLeafIdent(idShort); final Code code = AbstractClassOrObjectDiagram.this.V1972() ? ident : buildCode(idShort); point = getOrCreateLeaf(ident, code, LeafType.POINT_FOR_ASSOCIATION, null); diff --git a/src/net/sourceforge/plantuml/statediagram/StateDiagram.java b/src/net/sourceforge/plantuml/statediagram/StateDiagram.java index 2a8fb8239..a432f88be 100644 --- a/src/net/sourceforge/plantuml/statediagram/StateDiagram.java +++ b/src/net/sourceforge/plantuml/statediagram/StateDiagram.java @@ -54,7 +54,6 @@ import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.NamespaceStrategy; import net.sourceforge.plantuml.graphic.USymbol; -import net.sourceforge.plantuml.utils.UniqueSequence; public class StateDiagram extends AbstractEntityDiagram { @@ -228,7 +227,7 @@ public class StateDiagram extends AbstractEntityDiagram { super.endGroup(); } getCurrentGroup().setConcurrentSeparator(direction); - final String tmp1 = UniqueSequence.getString(CONCURRENT_PREFIX); + final String tmp1 = this.getUniqueSequence(CONCURRENT_PREFIX); final Ident ident1 = buildLeafIdent(tmp1); final Code code1 = this.V1972() ? ident1 : buildCode(tmp1); gotoGroup(ident1, code1, Display.create(""), GroupType.CONCURRENT_STATE, getCurrentGroup(), @@ -237,7 +236,7 @@ public class StateDiagram extends AbstractEntityDiagram { if (EntityUtils.groupRoot(cur) == false && cur.getGroupType() == GroupType.STATE) { cur.moveEntitiesTo(conc1); super.endGroup(); - final String tmp2 = UniqueSequence.getString(CONCURRENT_PREFIX); + final String tmp2 = this.getUniqueSequence(CONCURRENT_PREFIX); final Ident ident2 = buildLeafIdent(tmp2); final Code code2 = this.V1972() ? ident2 : buildCode(tmp2); gotoGroup(ident2, code2, Display.create(""), GroupType.CONCURRENT_STATE, getCurrentGroup(), diff --git a/src/net/sourceforge/plantuml/svek/Cluster.java b/src/net/sourceforge/plantuml/svek/Cluster.java index 099b8c2c8..76f8a6256 100644 --- a/src/net/sourceforge/plantuml/svek/Cluster.java +++ b/src/net/sourceforge/plantuml/svek/Cluster.java @@ -52,18 +52,17 @@ import java.util.Set; import net.sourceforge.plantuml.AlignmentParam; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.ISkinParam; -import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.UmlDiagramType; import net.sourceforge.plantuml.Url; import net.sourceforge.plantuml.api.ThemeStyle; import net.sourceforge.plantuml.awt.geom.Dimension2D; +import net.sourceforge.plantuml.cucadiagram.CucaDiagram; import net.sourceforge.plantuml.cucadiagram.EntityPosition; import net.sourceforge.plantuml.cucadiagram.EntityUtils; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.IGroup; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion; -import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.USymbol; @@ -88,14 +87,13 @@ import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; import net.sourceforge.plantuml.ugraphic.color.HColorSet; import net.sourceforge.plantuml.ugraphic.color.HColors; -import net.sourceforge.plantuml.utils.UniqueSequence; public class Cluster implements Moveable { - 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"; + /* 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; @@ -105,6 +103,7 @@ public class Cluster implements Moveable { private final int color; private final int colorTitle; private final ISkinParam skinParam; + protected final CucaDiagram diagram; private int titleAndAttributeWidth; private int titleAndAttributeHeight; @@ -138,16 +137,18 @@ public class Cluster implements Moveable { return Collections.unmodifiableSet(result); } - public Cluster(ColorSequence colorSequence, ISkinParam skinParam, IGroup root) { - this(null, colorSequence, skinParam, root); + public Cluster(CucaDiagram diagram, ColorSequence colorSequence, ISkinParam skinParam, IGroup root) { + this(diagram, null, colorSequence, skinParam, root); } - private Cluster(Cluster parentCluster, ColorSequence colorSequence, ISkinParam skinParam, IGroup group) { + private Cluster(CucaDiagram diagram, Cluster parentCluster, ColorSequence colorSequence, ISkinParam skinParam, + IGroup group) { if (group == null) throw new IllegalStateException(); this.parentCluster = parentCluster; this.group = group; + this.diagram = diagram; this.color = colorSequence.getValue(); this.colorTitle = colorSequence.getValue(); @@ -244,7 +245,7 @@ public class Cluster implements Moveable { public Cluster createChild(int titleAndAttributeWidth, int titleAndAttributeHeight, TextBlock title, TextBlock stereo, ColorSequence colorSequence, ISkinParam skinParam, IGroup g) { - final Cluster child = new Cluster(this, colorSequence, skinParam, g); + final Cluster child = new Cluster(diagram, this, colorSequence, skinParam, g); child.titleAndAttributeWidth = titleAndAttributeWidth; child.titleAndAttributeHeight = titleAndAttributeHeight; child.ztitle = title; @@ -257,6 +258,10 @@ public class Cluster implements Moveable { return Collections.singleton(group); } + final IGroup getGroup() { + return group; + } + public final int getTitleAndAttributeWidth() { return titleAndAttributeWidth; } @@ -375,7 +380,7 @@ public class Cluster implements Moveable { return style.getStroke(); } - public void manageEntryExitPoint(StringBounder stringBounder) { + void manageEntryExitPoint(StringBounder stringBounder) { final Collection insides = new ArrayList<>(); final List points = new ArrayList<>(); for (SvekNode sh : nodes) @@ -499,106 +504,12 @@ public class Cluster implements Moveable { this.maxY = maxY; } - private boolean isThereALinkFromOrToGroup(Collection lines) { - for (SvekLine line : lines) - if (line.isLinkFromOrTo(group)) - return true; - - return false; - } - public void printCluster1(StringBuilder sb, Collection lines, StringBounder stringBounder) { for (SvekNode node : getNodesOrderedTop(lines)) node.appendShape(sb, stringBounder); } - private List addProtection(List entries, double width) { - final List 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" + UniqueSequence.getValue(), width, 5)); - result.add(entries.get(i)); - } - return result; - } - - private double getMaxWidthFromLabelForEntryExit(List 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 void printRanks(String rank, List entries, StringBuilder sb, - StringBounder stringBounder) { - if (entries.size() > 0) { - sb.append("{rank=" + rank + ";"); - for (IShapePseudo sh1 : entries) - sb.append(sh1.getUid() + ";"); - - sb.append("}"); - SvekUtils.println(sb); - for (IShapePseudo sh2 : entries) - sh2.appendShape(sb, stringBounder); - - SvekUtils.println(sb); - if (hasPort()) { - boolean arrow = false; - String node = null; - for (IShapePseudo sh : entries) { - if (arrow) - sb.append("->"); - - arrow = true; - node = sh.getUid(); - sb.append(node); - } - sb.append(';'); - SvekUtils.println(sb); - sb.append(node + "->" + empty() + ";"); - SvekUtils.println(sb); - } - } - } - - private List withPositionProtected(StringBounder stringBounder, - Set targets) { - final List 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 withPosition(Set positions) { - final List result = new ArrayList<>(); - for (final Iterator it = nodes.iterator(); it.hasNext();) { - final SvekNode sh = it.next(); - if (positions.contains(sh.getEntityPosition())) - result.add(sh); - - } - return result; - } - - private void printClusterEntryExit(StringBuilder sb, StringBounder stringBounder) { - printRanks(RANK_SOURCE, withPositionProtected(stringBounder, EntityPosition.getInputs()), sb, stringBounder); - printRanks(RANK_SAME, withPositionProtected(stringBounder, EntityPosition.getSame()), sb, stringBounder); - printRanks(RANK_SINK, withPositionProtected(stringBounder, EntityPosition.getOutputs()), sb, stringBounder); - } - public SvekNode printCluster2(StringBuilder sb, Collection lines, StringBounder stringBounder, DotMode dotMode, GraphvizVersion graphvizVersion, UmlDiagramType type) { @@ -618,6 +529,11 @@ public class Cluster implements Moveable { return added; } + private void printInternal(StringBuilder sb, Collection lines, StringBounder stringBounder, + DotMode dotMode, GraphvizVersion graphvizVersion, UmlDiagramType type) { + new ClusterDotString(this, skinParam).printInternal(sb, lines, stringBounder, dotMode, graphvizVersion, type); + } + private void appendRankSame(StringBuilder sb, Collection lines) { for (String same : getRankSame(lines)) { sb.append(same); @@ -643,7 +559,7 @@ public class Cluster implements Moveable { return rankSame; } - public void fillRankMin(Set rankMin) { + void fillRankMin(Set rankMin) { for (SvekNode sh : getNodes()) if (sh.isTop()) rankMin.add(sh.getUid()); @@ -665,204 +581,33 @@ public class Cluster implements Moveable { return "cluster" + color; } - public static String getSpecialPointId(IEntity group) { + static String getSpecialPointId(IEntity group) { return CENTER_ID + group.getUid(); } - private boolean protection0(UmlDiagramType type) { - if (skinParam.useSwimlanes(type)) - return false; - - return true; - } - - private boolean protection1(UmlDiagramType type) { - if (group.getUSymbol() == USymbols.NODE) - return true; - - if (skinParam.useSwimlanes(type)) - return false; - - return true; - } - - public String getMinPoint(UmlDiagramType type) { + String getMinPoint(UmlDiagramType type) { if (skinParam.useSwimlanes(type)) return "minPoint" + color; return null; } - public String getMaxPoint(UmlDiagramType type) { + String getMaxPoint(UmlDiagramType type) { if (skinParam.useSwimlanes(type)) return "maxPoint" + color; return null; } - private String getSourceInPoint(UmlDiagramType type) { - if (skinParam.useSwimlanes(type)) - return "sourceIn" + color; - - return null; - } - - private String getSinkInPoint(UmlDiagramType type) { - if (skinParam.useSwimlanes(type)) - return "sinkIn" + color; - - return null; - } - - private void printInternal(StringBuilder sb, Collection lines, StringBounder stringBounder, - DotMode dotMode, GraphvizVersion graphvizVersion, UmlDiagramType type) { - final boolean thereALinkFromOrToGroup2 = isThereALinkFromOrToGroup(lines); - boolean thereALinkFromOrToGroup1 = thereALinkFromOrToGroup2; - final boolean useProtectionWhenThereALinkFromOrToGroup = graphvizVersion - .useProtectionWhenThereALinkFromOrToGroup(); - if (useProtectionWhenThereALinkFromOrToGroup == false) - thereALinkFromOrToGroup1 = false; - - // final boolean thereALinkFromOrToGroup1 = false; - if (thereALinkFromOrToGroup1) - subgraphClusterNoLabel(sb, "a"); - - final Set entityPositionsExceptNormal = entityPositionsExceptNormal(); - if (entityPositionsExceptNormal.size() > 0) - for (SvekLine line : lines) - if (line.isLinkFromOrTo(group)) - line.setProjectionCluster(this); - - boolean protection0 = protection0(type); - boolean protection1 = protection1(type); - if (entityPositionsExceptNormal.size() > 0 || useProtectionWhenThereALinkFromOrToGroup == false) { - protection0 = false; - protection1 = false; - } - // if (graphvizVersion.modeSafe()) { - // protection0 = false; - // protection1 = false; - // } - if (protection0) - subgraphClusterNoLabel(sb, "p0"); - - sb.append("subgraph " + getClusterId() + " {"); - sb.append("style=solid;"); - sb.append("color=\"" + StringUtils.sharp000000(color) + "\";"); - - final String label; - if (isLabel()) { - final StringBuilder sblabel = new StringBuilder("<"); - SvekLine.appendTable(sblabel, getTitleAndAttributeWidth(), getTitleAndAttributeHeight() - 5, colorTitle); - sblabel.append(">"); - label = sblabel.toString(); - final HorizontalAlignment align = skinParam.getHorizontalAlignment(AlignmentParam.packageTitleAlignment, - null, false, null); - sb.append("labeljust=\"" + align.getGraphVizValue() + "\";"); - } else { - label = "\"\""; - } - - if (entityPositionsExceptNormal.size() > 0) { - printClusterEntryExit(sb, stringBounder); - if (hasPort()) - subgraphClusterNoLabel(sb, ID_EE); - else - subgraphClusterWithLabel(sb, ID_EE, label); - - } else { - sb.append("label=" + label + ";"); - SvekUtils.println(sb); - } - - if (thereALinkFromOrToGroup2) - sb.append(getSpecialPointId(group) + " [shape=point,width=.01,label=\"\"];"); - - if (thereALinkFromOrToGroup1) - subgraphClusterNoLabel(sb, "i"); - - if (protection1) - subgraphClusterNoLabel(sb, "p1"); - - if (skinParam.useSwimlanes(type)) { - sb.append("{rank = source; "); - sb.append(getSourceInPoint(type)); - sb.append(" [shape=point,width=.01,label=\"\"];"); - sb.append(getMinPoint(type) + "->" + getSourceInPoint(type) + " [weight=999];"); - sb.append("}"); - SvekUtils.println(sb); - sb.append("{rank = sink; "); - sb.append(getSinkInPoint(type)); - sb.append(" [shape=point,width=.01,label=\"\"];"); - sb.append("}"); - sb.append(getSinkInPoint(type) + "->" + getMaxPoint(type) + " [weight=999];"); - SvekUtils.println(sb); - } - SvekUtils.println(sb); - printCluster1(sb, lines, stringBounder); - - final SvekNode added = printCluster2(sb, lines, stringBounder, dotMode, graphvizVersion, type); - if (entityPositionsExceptNormal.size() > 0) - if (hasPort()) { - sb.append(empty() + " [shape=rect,width=.01,height=.01,label="); - sb.append(label); - sb.append("];"); - } else if (added == null) { - sb.append(empty() + " [shape=point,width=.01,label=\"\"];"); - } - SvekUtils.println(sb); - - sb.append("}"); - if (protection1) - sb.append("}"); - - if (thereALinkFromOrToGroup1) { - sb.append("}"); - sb.append("}"); - } - if (entityPositionsExceptNormal.size() > 0) - sb.append("}"); - - if (protection0) - sb.append("}"); - - SvekUtils.println(sb); - } - - private boolean hasPort() { - for (EntityPosition pos : entityPositionsExceptNormal()) - if (pos.isPort()) - return true; - - return false; - } - - private String empty() { - // return "empty" + color; - // We use the same node with one for thereALinkFromOrToGroup2 as an empty - // because we cannot put a new node in the nested inside of the cluster - // if thereALinkFromOrToGroup2 is enabled. - return getSpecialPointId(group); - } - public boolean isLabel() { return getTitleAndAttributeHeight() > 0 && getTitleAndAttributeWidth() > 0; } - private void subgraphClusterNoLabel(StringBuilder sb, String id) { - subgraphClusterWithLabel(sb, id, "\"\""); - } - - private void subgraphClusterWithLabel(StringBuilder sb, String id, String label) { - sb.append("subgraph " + getClusterId() + id + " {"); - sb.append("label=" + label + ";"); - } - - public int getColor() { + int getColor() { return color; } - public int getTitleColor() { + int getTitleColor() { return colorTitle; } @@ -891,7 +636,7 @@ public class Cluster implements Moveable { // return parentCluster.getBackColor(umlDiagramType, style); } - public boolean isClusterOf(IEntity ent) { + boolean isClusterOf(IEntity ent) { if (ent.isGroup() == false) return false; @@ -911,7 +656,7 @@ public class Cluster implements Moveable { return backColor; } - public double checkFolderPosition(Point2D pt, StringBounder stringBounder) { + double checkFolderPosition(Point2D pt, StringBounder stringBounder) { if (getClusterPosition().isPointJustUpper(pt)) { if (ztitle == null) return 0; diff --git a/src/net/sourceforge/plantuml/svek/ClusterDotString.java b/src/net/sourceforge/plantuml/svek/ClusterDotString.java new file mode 100644 index 000000000..8680d0aff --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/ClusterDotString.java @@ -0,0 +1,344 @@ +/* ======================================================================== + * 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 + * Contribution : Hisashi Miyashita + * + * + */ +package net.sourceforge.plantuml.svek; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import net.sourceforge.plantuml.AlignmentParam; +import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.StringUtils; +import net.sourceforge.plantuml.UmlDiagramType; +import net.sourceforge.plantuml.cucadiagram.EntityPosition; +import net.sourceforge.plantuml.cucadiagram.dot.GraphvizVersion; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.USymbols; + +public class ClusterDotString { + + private final Cluster cluster; + private final ISkinParam skinParam; + + public ClusterDotString(Cluster cluster, ISkinParam skinParam) { + this.cluster = cluster; + this.skinParam = skinParam; + } + + void printInternal(StringBuilder sb, Collection lines, StringBounder stringBounder, DotMode dotMode, + GraphvizVersion graphvizVersion, UmlDiagramType type) { + final boolean thereALinkFromOrToGroup2 = isThereALinkFromOrToGroup(lines); + boolean thereALinkFromOrToGroup1 = thereALinkFromOrToGroup2; + final boolean useProtectionWhenThereALinkFromOrToGroup = graphvizVersion + .useProtectionWhenThereALinkFromOrToGroup(); + if (useProtectionWhenThereALinkFromOrToGroup == false) + thereALinkFromOrToGroup1 = false; + + if (thereALinkFromOrToGroup1) + subgraphClusterNoLabel(sb, "a"); + + final Set entityPositionsExceptNormal = entityPositionsExceptNormal(); + if (entityPositionsExceptNormal.size() > 0) + for (SvekLine line : lines) + if (line.isLinkFromOrTo(cluster.getGroup())) + line.setProjectionCluster(cluster); + + boolean protection0 = protection0(type); + boolean protection1 = protection1(type); + if (entityPositionsExceptNormal.size() > 0 || useProtectionWhenThereALinkFromOrToGroup == false) { + protection0 = false; + protection1 = false; + } + + if (protection0) + subgraphClusterNoLabel(sb, "p0"); + + sb.append("subgraph " + cluster.getClusterId() + " {"); + sb.append("style=solid;"); + sb.append("color=\"" + StringUtils.sharp000000(cluster.getColor()) + "\";"); + + final String label; + if (cluster.isLabel()) { + final StringBuilder sblabel = new StringBuilder("<"); + SvekLine.appendTable(sblabel, cluster.getTitleAndAttributeWidth(), cluster.getTitleAndAttributeHeight() - 5, + cluster.getTitleColor()); + sblabel.append(">"); + label = sblabel.toString(); + final HorizontalAlignment align = skinParam.getHorizontalAlignment(AlignmentParam.packageTitleAlignment, + null, false, null); + sb.append("labeljust=\"" + align.getGraphVizValue() + "\";"); + } else { + label = "\"\""; + } + + if (entityPositionsExceptNormal.size() > 0) { + printClusterEntryExit(sb, stringBounder); + if (hasPort()) + subgraphClusterNoLabel(sb, Cluster.ID_EE); + else + subgraphClusterWithLabel(sb, Cluster.ID_EE, label); + + } else { + sb.append("label=" + label + ";"); + SvekUtils.println(sb); + } + + if (thereALinkFromOrToGroup2) + sb.append(Cluster.getSpecialPointId(cluster.getGroup()) + " [shape=point,width=.01,label=\"\"];"); + + if (thereALinkFromOrToGroup1) + subgraphClusterNoLabel(sb, "i"); + + if (protection1) + subgraphClusterNoLabel(sb, "p1"); + + if (skinParam.useSwimlanes(type)) { + sb.append("{rank = source; "); + sb.append(getSourceInPoint(type)); + sb.append(" [shape=point,width=.01,label=\"\"];"); + sb.append(cluster.getMinPoint(type) + "->" + getSourceInPoint(type) + " [weight=999];"); + sb.append("}"); + SvekUtils.println(sb); + sb.append("{rank = sink; "); + sb.append(getSinkInPoint(type)); + sb.append(" [shape=point,width=.01,label=\"\"];"); + sb.append("}"); + sb.append(getSinkInPoint(type) + "->" + cluster.getMaxPoint(type) + " [weight=999];"); + SvekUtils.println(sb); + } + SvekUtils.println(sb); + cluster.printCluster1(sb, lines, stringBounder); + + final SvekNode added = cluster.printCluster2(sb, lines, stringBounder, dotMode, graphvizVersion, type); + if (entityPositionsExceptNormal.size() > 0) + if (hasPort()) { + sb.append(empty() + " [shape=rect,width=.01,height=.01,label="); + sb.append(label); + sb.append("];"); + } else if (added == null) { + sb.append(empty() + " [shape=point,width=.01,label=\"\"];"); + } + SvekUtils.println(sb); + + sb.append("}"); + if (protection1) + sb.append("}"); + + if (thereALinkFromOrToGroup1) { + sb.append("}"); + sb.append("}"); + } + if (entityPositionsExceptNormal.size() > 0) + sb.append("}"); + + if (protection0) + sb.append("}"); + + SvekUtils.println(sb); + } + + private String getSourceInPoint(UmlDiagramType type) { + if (skinParam.useSwimlanes(type)) + return "sourceIn" + cluster.getColor(); + + return null; + } + + private String getSinkInPoint(UmlDiagramType type) { + if (skinParam.useSwimlanes(type)) + return "sinkIn" + cluster.getColor(); + + return null; + } + + private String empty() { + // return "empty" + color; + // We use the same node with one for thereALinkFromOrToGroup2 as an empty + // because we cannot put a new node in the nested inside of the cluster + // if thereALinkFromOrToGroup2 is enabled. + return Cluster.getSpecialPointId(cluster.getGroup()); + } + + private boolean hasPort() { + for (EntityPosition pos : entityPositionsExceptNormal()) + if (pos.isPort()) + return true; + + return false; + } + + private Set entityPositionsExceptNormal() { + final Set result = EnumSet.noneOf(EntityPosition.class); + for (SvekNode sh : cluster.getNodes()) + if (sh.getEntityPosition() != EntityPosition.NORMAL) + result.add(sh.getEntityPosition()); + + return Collections.unmodifiableSet(result); + } + + private void subgraphClusterNoLabel(StringBuilder sb, String id) { + subgraphClusterWithLabel(sb, id, "\"\""); + } + + private void subgraphClusterWithLabel(StringBuilder sb, String id, String label) { + sb.append("subgraph " + cluster.getClusterId() + id + " {"); + sb.append("label=" + label + ";"); + } + + 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); + } + + private void printRanks(String rank, List entries, StringBuilder sb, + StringBounder stringBounder) { + if (entries.size() > 0) { + sb.append("{rank=" + rank + ";"); + for (IShapePseudo sh1 : entries) + sb.append(sh1.getUid() + ";"); + + sb.append("}"); + SvekUtils.println(sb); + for (IShapePseudo sh2 : entries) + sh2.appendShape(sb, stringBounder); + + SvekUtils.println(sb); + if (hasPort()) { + boolean arrow = false; + String node = null; + for (IShapePseudo sh : entries) { + if (arrow) + sb.append("->"); + + arrow = true; + node = sh.getUid(); + sb.append(node); + } + if (arrow) + sb.append(" [arrowhead=none]"); + + sb.append(';'); + SvekUtils.println(sb); + sb.append(node + "->" + empty() + ";"); + SvekUtils.println(sb); + } + } + } + + private List withPositionProtected(StringBounder stringBounder, + Set targets) { + final List 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 addProtection(List entries, double width) { + final List 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 withPosition(Set positions) { + final List result = new ArrayList<>(); + for (final Iterator it = cluster.getNodes().iterator(); it.hasNext();) { + final SvekNode sh = it.next(); + if (positions.contains(sh.getEntityPosition())) + result.add(sh); + + } + return result; + } + + private double getMaxWidthFromLabelForEntryExit(List 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; + + return true; + } + + private boolean protection1(UmlDiagramType type) { + if (cluster.getGroup().getUSymbol() == USymbols.NODE) + return true; + + if (skinParam.useSwimlanes(type)) + return false; + + return true; + } + + private boolean isThereALinkFromOrToGroup(Collection lines) { + for (SvekLine line : lines) + if (line.isLinkFromOrTo(cluster.getGroup())) + return true; + + return false; + } + +} diff --git a/src/net/sourceforge/plantuml/svek/DotStringFactory.java b/src/net/sourceforge/plantuml/svek/DotStringFactory.java index bf2d7cd5a..9b4ae8190 100644 --- a/src/net/sourceforge/plantuml/svek/DotStringFactory.java +++ b/src/net/sourceforge/plantuml/svek/DotStringFactory.java @@ -94,7 +94,7 @@ public class DotStringFactory implements Moveable { this.colorSequence = new ColorSequence(); this.stringBounder = stringBounder; - this.root = new Cluster(colorSequence, skinParam, dotData.getRootGroup()); + this.root = new Cluster(dotData.getEntityFactory().getDiagram(), colorSequence, skinParam, dotData.getRootGroup()); this.current = root; } @@ -105,7 +105,7 @@ public class DotStringFactory implements Moveable { this.colorSequence = new ColorSequence(); this.stringBounder = stringBounder; - this.root = new Cluster(colorSequence, skinParam, diagram.getEntityFactory().getRootGroup()); + this.root = new Cluster(diagram, colorSequence, skinParam, diagram.getEntityFactory().getRootGroup()); this.current = root; } @@ -173,13 +173,13 @@ public class DotStringFactory implements Moveable { SvekUtils.println(sb); for (String s : dotStrings) { - if (s.startsWith("ranksep")) { + if (s.startsWith("ranksep")) sb.append("ranksep=" + ranksepInches + ";"); - } else if (s.startsWith("nodesep")) { + else if (s.startsWith("nodesep")) sb.append("nodesep=" + nodesepInches + ";"); - } else { + else sb.append(s); - } + SvekUtils.println(sb); } // sb.append("newrank=true;"); @@ -309,9 +309,9 @@ public class DotStringFactory implements Moveable { try { final ProcessState state = graphviz.createFile3(baos); baos.close(); - if (state.differs(ProcessState.TERMINATED_OK())) { + if (state.differs(ProcessState.TERMINATED_OK())) throw new IllegalStateException("Timeout4 " + state, state.getCause()); - } + } catch (GraphvizJsRuntimeException e) { System.err.println("GraphvizJsRuntimeException"); graphvizVersion = GraphvizJs.getGraphvizVersion(true); @@ -367,7 +367,7 @@ public class DotStringFactory implements Moveable { int idx = svg.indexOf("" + node.getUid() + ""); if (node.getType() == ShapeType.RECTANGLE || node.getType() == ShapeType.RECTANGLE_HTML_FOR_PORTS || node.getType() == ShapeType.RECTANGLE_WITH_CIRCLE_INSIDE || node.getType() == ShapeType.FOLDER - || node.getType() == ShapeType.DIAMOND) { + || node.getType() == ShapeType.DIAMOND || node.getType() == ShapeType.RECTANGLE_PORT) { final List points = svgResult.substring(idx).extractList(SvgResult.POINTS_EQUALS); final double minY = SvekUtils.getMinY(points); final double overscanX = node.getOverscanX(stringBounder); diff --git a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java index a34f5fb3e..0bc2e2d17 100644 --- a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java +++ b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java @@ -99,6 +99,8 @@ import net.sourceforge.plantuml.graphic.USymbolHexagon; import net.sourceforge.plantuml.graphic.USymbolInterface; import net.sourceforge.plantuml.graphic.USymbols; import net.sourceforge.plantuml.log.Logme; +import net.sourceforge.plantuml.security.SecurityProfile; +import net.sourceforge.plantuml.security.SecurityUtils; import net.sourceforge.plantuml.style.PName; import net.sourceforge.plantuml.style.SName; import net.sourceforge.plantuml.style.Style; @@ -444,7 +446,10 @@ public final class GeneralImageBuilder { if (dotStringFactory.illegalDotExe()) return error(dotStringFactory.getDotExe()); - if (basefile == null && isSvekTrace()) + if (basefile == null && isSvekTrace() + && (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE + || SecurityUtils.getSecurityProfile() == SecurityProfile.LEGACY + || SecurityUtils.getSecurityProfile() == SecurityProfile.SANDBOX)) basefile = new BaseFile(null); final String svg; diff --git a/src/net/sourceforge/plantuml/svek/ShapeType.java b/src/net/sourceforge/plantuml/svek/ShapeType.java index 5fdb0b4b1..253a4bab9 100644 --- a/src/net/sourceforge/plantuml/svek/ShapeType.java +++ b/src/net/sourceforge/plantuml/svek/ShapeType.java @@ -37,7 +37,18 @@ package net.sourceforge.plantuml.svek; public enum ShapeType { - RECTANGLE, RECTANGLE_WITH_CIRCLE_INSIDE, RECTANGLE_HTML_FOR_PORTS, ROUND_RECTANGLE, CIRCLE, CIRCLE_IN_RECT, OVAL, - DIAMOND, OCTAGON, FOLDER, HEXAGON + RECTANGLE, // + RECTANGLE_PORT, // + RECTANGLE_WITH_CIRCLE_INSIDE, // + RECTANGLE_HTML_FOR_PORTS, // + ROUND_RECTANGLE, // + CIRCLE, // + CIRCLE_IN_RECT, // + OVAL, // + DIAMOND, // + OCTAGON, // + FOLDER, // + HEXAGON, // + PORT // } diff --git a/src/net/sourceforge/plantuml/svek/SvekLine.java b/src/net/sourceforge/plantuml/svek/SvekLine.java index 27fa06880..1503fbfde 100644 --- a/src/net/sourceforge/plantuml/svek/SvekLine.java +++ b/src/net/sourceforge/plantuml/svek/SvekLine.java @@ -102,7 +102,6 @@ import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UGroupType; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UPolygon; -import net.sourceforge.plantuml.ugraphic.URectangle; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; import net.sourceforge.plantuml.ugraphic.color.HColor; diff --git a/src/net/sourceforge/plantuml/svek/SvekNode.java b/src/net/sourceforge/plantuml/svek/SvekNode.java index c49827f5e..c4e5ff8c4 100644 --- a/src/net/sourceforge/plantuml/svek/SvekNode.java +++ b/src/net/sourceforge/plantuml/svek/SvekNode.java @@ -137,6 +137,10 @@ public class SvekNode implements Positionable, IShapePseudo, Hideable { appendLabelHtmlSpecialForLink(sb, stringBounder); return; } + if (type == ShapeType.RECTANGLE_PORT) { + appendLabelHtmlSpecialForPort(sb, stringBounder); + return; + } if (type == ShapeType.RECTANGLE_WITH_CIRCLE_INSIDE) { appendHtml(sb); return; @@ -160,6 +164,21 @@ public class SvekNode implements Positionable, IShapePseudo, Hideable { SvekUtils.println(sb); } + private void appendLabelHtmlSpecialForPort(StringBuilder sb, StringBounder stringBounder2) { + sb.append(uid); + sb.append(" ["); + sb.append("shape=rect"); + sb.append(","); + sb.append("label=\"\""); + sb.append(","); + sb.append("width=" + SvekUtils.pixelToInches(getWidth())); + sb.append(","); + sb.append("height=" + SvekUtils.pixelToInches(getHeight())); + sb.append(","); + sb.append("color=\"" + StringUtils.sharp000000(color) + "\""); + sb.append("];"); + } + private Margins shield() { if (shield == null) { this.shield = image.getShield(stringBounder); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java b/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java index 3a6a276d5..b5c7d61a6 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImagePort.java @@ -132,6 +132,6 @@ public class EntityImagePort extends AbstractEntityImageBorder { } public ShapeType getShapeType() { - return ShapeType.RECTANGLE; + return ShapeType.RECTANGLE_PORT; } } diff --git a/src/net/sourceforge/plantuml/utils/UniqueSequence.java b/src/net/sourceforge/plantuml/utils/UniqueSequence.java deleted file mode 100644 index 91be0f82f..000000000 --- a/src/net/sourceforge/plantuml/utils/UniqueSequence.java +++ /dev/null @@ -1,52 +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.utils; - -import java.util.concurrent.atomic.AtomicInteger; - -public class UniqueSequence { - - private static final AtomicInteger cpt = new AtomicInteger(1); - - public static int getValue() { - return cpt.addAndGet(1); - } - - public static String getString(String prefix) { - return prefix + getValue(); - } - -} diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index 21ed7c2e5..5e9e10969 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -81,7 +81,7 @@ public class Version { } public static int beta() { - final int beta = 2; + final int beta = 3; return beta; } diff --git a/src/net/sourceforge/plantuml/xmi/CucaDiagramXmiMaker.java b/src/net/sourceforge/plantuml/xmi/CucaDiagramXmiMaker.java index a698f9a12..af2cf6e04 100644 --- a/src/net/sourceforge/plantuml/xmi/CucaDiagramXmiMaker.java +++ b/src/net/sourceforge/plantuml/xmi/CucaDiagramXmiMaker.java @@ -66,20 +66,20 @@ public final class CucaDiagramXmiMaker { public void createFiles(OutputStream fos) throws IOException { try { - final IXmiClassDiagram xmi; - if (diagram instanceof StateDiagram) { + final XmlDiagramTransformer xmi; + if (diagram instanceof StateDiagram) xmi = new XmiStateDiagram((StateDiagram) diagram); - } else if (diagram instanceof DescriptionDiagram) { + else if (diagram instanceof DescriptionDiagram) xmi = new XmiDescriptionDiagram((DescriptionDiagram) diagram); - } else if (fileFormat == FileFormat.XMI_STANDARD) { + else if (fileFormat == FileFormat.XMI_STANDARD) xmi = new XmiClassDiagramStandard((ClassDiagram) diagram); - } else if (fileFormat == FileFormat.XMI_ARGO) { + else if (fileFormat == FileFormat.XMI_ARGO) xmi = new XmiClassDiagramArgo((ClassDiagram) diagram); - } else if (fileFormat == FileFormat.XMI_STAR) { + else if (fileFormat == FileFormat.XMI_STAR) xmi = new XmiClassDiagramStar((ClassDiagram) diagram); - } else { + else throw new UnsupportedOperationException(); - } + xmi.transformerXml(fos); } catch (ParserConfigurationException e) { Log.error(e.toString()); diff --git a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramAbstract.java b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramAbstract.java index 964e7a649..d2792f0cd 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramAbstract.java +++ b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramAbstract.java @@ -57,14 +57,14 @@ import org.w3c.dom.Element; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.IEntity; +import net.sourceforge.plantuml.cucadiagram.ILeaf; import net.sourceforge.plantuml.cucadiagram.LeafType; import net.sourceforge.plantuml.cucadiagram.Member; import net.sourceforge.plantuml.cucadiagram.Stereotype; import net.sourceforge.plantuml.skin.VisibilityModifier; -import net.sourceforge.plantuml.utils.UniqueSequence; import net.sourceforge.plantuml.xml.XmlFactories; -abstract class XmiClassDiagramAbstract implements IXmiClassDiagram { +abstract class XmiClassDiagramAbstract implements XmlDiagramTransformer { // https://www.ibm.com/developerworks/library/x-wxxm24/ // http://pierre.ree7.fr/blog/?p=5 @@ -99,9 +99,6 @@ abstract class XmiClassDiagramAbstract implements IXmiClassDiagram { final Element content = document.createElement("XMI.content"); xmi.appendChild(content); - // final Element model = document.createElement("UML:Model"); model.setAttribute("xmi.id", CucaDiagramXmiMaker.getModel(classDiagram)); model.setAttribute("name", "PlantUML"); @@ -131,32 +128,24 @@ abstract class XmiClassDiagramAbstract implements IXmiClassDiagram { final Transformer transformer = XmlFactories.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - // transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); transformer.setOutputProperty(OutputKeys.ENCODING, UTF_8.name()); // tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(source, resultat); } final protected Element createEntityNode(IEntity entity) { - // final Element cla = document.createElement("UML:Class"); - if (entity.getLeafType() == LeafType.NOTE) { + if (entity.getLeafType() == LeafType.NOTE) return null; - } cla.setAttribute("xmi.id", entity.getUid()); cla.setAttribute("name", entity.getDisplay().get(0).toString()); final String parentCode = entity.getIdent().parent().forXmi(); - // final LongCode parentCode = entity.getParentContainer().getLongCode(); - if (parentCode.length() == 0) { + + if (parentCode.length() == 0) cla.setAttribute("namespace", CucaDiagramXmiMaker.getModel(classDiagram)); - } else { + else cla.setAttribute("namespace", parentCode); - } final Stereotype stereotype = entity.getStereotype(); if (stereotype != null) { @@ -170,45 +159,47 @@ abstract class XmiClassDiagramAbstract implements IXmiClassDiagram { } final LeafType type = entity.getLeafType(); - if (type == LeafType.ABSTRACT_CLASS) { + if (type == LeafType.ABSTRACT_CLASS) cla.setAttribute("isAbstract", "true"); - } else if (type == LeafType.INTERFACE) { + else if (type == LeafType.INTERFACE) cla.setAttribute("isInterface", "true"); - } + + if (((ILeaf) entity).isStatic()) + cla.setAttribute("isStatic", "true"); + + if (((ILeaf) entity).getVisibilityModifier() == VisibilityModifier.PRIVATE_FIELD + || ((ILeaf) entity).getVisibilityModifier() == VisibilityModifier.PRIVATE_METHOD) + cla.setAttribute("visibility", ((ILeaf) entity).getVisibilityModifier().getXmiVisibility()); final Element feature = document.createElement("UML:Classifier.feature"); cla.appendChild(feature); for (CharSequence cs : entity.getBodier().getFieldsToDisplay()) { final Member m = (Member) cs; - // + final Element attribute = document.createElement("UML:Attribute"); - attribute.setAttribute("xmi.id", "att" + UniqueSequence.getValue()); + attribute.setAttribute("xmi.id", "att" + classDiagram.getUniqueSequence()); attribute.setAttribute("name", m.getDisplay(false)); final VisibilityModifier visibility = m.getVisibilityModifier(); - if (visibility != null) { + if (visibility != null) attribute.setAttribute("visibility", visibility.getXmiVisibility()); - } + if (m.isStatic()) + attribute.setAttribute("isStatic", "true"); + feature.appendChild(attribute); } for (CharSequence cs : entity.getBodier().getMethodsToDisplay()) { final Member m = (Member) cs; - // final Element operation = document.createElement("UML:Operation"); - operation.setAttribute("xmi.id", "att" + UniqueSequence.getValue()); + operation.setAttribute("xmi.id", "att" + classDiagram.getUniqueSequence()); operation.setAttribute("name", m.getDisplay(false)); final VisibilityModifier visibility = m.getVisibilityModifier(); - if (visibility != null) { + if (visibility != null) operation.setAttribute("visibility", visibility.getXmiVisibility()); - } + if (m.isStatic()) + operation.setAttribute("isStatic", "true"); + feature.appendChild(operation); } return cla; diff --git a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramArgo.java b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramArgo.java index 2d72e30dc..1ba419516 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramArgo.java +++ b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramArgo.java @@ -42,104 +42,84 @@ import org.w3c.dom.Element; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Link; -import net.sourceforge.plantuml.utils.UniqueSequence; -public class XmiClassDiagramArgo extends XmiClassDiagramAbstract implements IXmiClassDiagram { +public class XmiClassDiagramArgo extends XmiClassDiagramAbstract implements XmlDiagramTransformer { public XmiClassDiagramArgo(ClassDiagram classDiagram) throws ParserConfigurationException { super(classDiagram); for (final IEntity ent : classDiagram.getLeafsvalues()) { - if (classDiagram.isStandalone(ent) == false) { + if (classDiagram.isStandaloneForArgo(ent) == false) continue; - } + final Element cla = createEntityNode(ent); - if (cla == null) { + if (cla == null) continue; - } + ownedElement.appendChild(cla); done.add(ent); } - // if (fileFormat != FileFormat.XMI_STANDARD) { - for (final Link link : classDiagram.getLinks()) { + for (final Link link : classDiagram.getLinks()) addLink(link); - } - // } } private void addLink(Link link) { - final String assId = "ass" + UniqueSequence.getValue(); - // if ((link.getType().getDecor1() == LinkDecor.EXTENDS || link.getType().getDecor2() == LinkDecor.EXTENDS) - // && fileFormat == FileFormat.XMI_STAR) { - // addExtension(link, assId); - // return; - // } + if (link.isHidden() || link.isInvis()) + return; + + final String assId = "ass" + classDiagram.getUniqueSequence(); + final Element association = document.createElement("UML:Association"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(classDiagram)); - if (link.getLabel() != null) { + if (link.getLabel() != null) association.setAttribute("name", forXMI(link.getLabel())); - } final Element connection = document.createElement("UML:Association.connection"); final Element end1 = document.createElement("UML:AssociationEnd"); - end1.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end1.setAttribute("xmi.id", "end" + classDiagram.getUniqueSequence()); end1.setAttribute("association", assId); end1.setAttribute("type", link.getEntity1().getUid()); - if (link.getQualifier1() != null) { + if (link.getQualifier1() != null) end1.setAttribute("name", forXMI(link.getQualifier1())); - } + final Element endparticipant1 = document.createElement("UML:AssociationEnd.participant"); - // if (fileFormat == FileFormat.XMI_ARGO) { + if (done.contains(link.getEntity1())) { endparticipant1.appendChild(createEntityNodeRef(link.getEntity1())); } else { final Element element = createEntityNode(link.getEntity1()); - if (element == null) { + if (element == null) return; - } + endparticipant1.appendChild(element); done.add(link.getEntity1()); } - // } else if (fileFormat == FileFormat.XMI_STAR) { - // if (link.getType().getDecor2() == LinkDecor.COMPOSITION) { - // end1.setAttribute("aggregation", "composite"); - // } - // if (link.getType().getDecor2() == LinkDecor.AGREGATION) { - // end1.setAttribute("aggregation", "aggregate"); - // } - // } + end1.appendChild(endparticipant1); connection.appendChild(end1); final Element end2 = document.createElement("UML:AssociationEnd"); - end2.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end2.setAttribute("xmi.id", "end" + classDiagram.getUniqueSequence()); end2.setAttribute("association", assId); end2.setAttribute("type", link.getEntity2().getUid()); - if (link.getQualifier2() != null) { + if (link.getQualifier2() != null) end2.setAttribute("name", forXMI(link.getQualifier2())); - } + final Element endparticipant2 = document.createElement("UML:AssociationEnd.participant"); - // if (fileFormat == FileFormat.XMI_ARGO) { + if (done.contains(link.getEntity2())) { endparticipant2.appendChild(createEntityNodeRef(link.getEntity2())); } else { final Element element = createEntityNode(link.getEntity2()); - if (element == null) { + if (element == null) return; - } + endparticipant2.appendChild(element); done.add(link.getEntity2()); } - // } else if (fileFormat == FileFormat.XMI_STAR) { - // if (link.getType().getDecor1() == LinkDecor.COMPOSITION) { - // end2.setAttribute("aggregation", "composite"); - // } - // if (link.getType().getDecor1() == LinkDecor.AGREGATION) { - // end2.setAttribute("aggregation", "aggregate"); - // } - // } + end2.appendChild(endparticipant2); connection.appendChild(end2); diff --git a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStandard.java b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStandard.java index 73db9632a..52b4a26a3 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStandard.java +++ b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStandard.java @@ -42,7 +42,7 @@ import org.w3c.dom.Element; import net.sourceforge.plantuml.classdiagram.ClassDiagram; import net.sourceforge.plantuml.cucadiagram.IEntity; -public class XmiClassDiagramStandard extends XmiClassDiagramAbstract implements IXmiClassDiagram { +public class XmiClassDiagramStandard extends XmiClassDiagramAbstract implements XmlDiagramTransformer { public XmiClassDiagramStandard(ClassDiagram classDiagram) throws ParserConfigurationException { super(classDiagram); diff --git a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStar.java b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStar.java index 835d3469e..603289d47 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStar.java +++ b/src/net/sourceforge/plantuml/xmi/XmiClassDiagramStar.java @@ -44,43 +44,31 @@ import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.cucadiagram.IEntity; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.LinkDecor; -import net.sourceforge.plantuml.utils.UniqueSequence; -public class XmiClassDiagramStar extends XmiClassDiagramAbstract implements IXmiClassDiagram { +public class XmiClassDiagramStar extends XmiClassDiagramAbstract implements XmlDiagramTransformer { public XmiClassDiagramStar(ClassDiagram classDiagram) throws ParserConfigurationException { super(classDiagram); for (final IEntity ent : classDiagram.getLeafsvalues()) { - // if (fileFormat == FileFormat.XMI_ARGO && isStandalone(ent) == false) { - // continue; - // } final Element cla = createEntityNode(ent); - if (cla == null) { + if (cla == null) continue; - } + ownedElement.appendChild(cla); done.add(ent); } - // if (fileFormat != FileFormat.XMI_STANDARD) { - for (final Link link : classDiagram.getLinks()) { + for (final Link link : classDiagram.getLinks()) addLink(link); - } - // } + } - // private boolean isStandalone(IEntity ent) { - // for (final Link link : classDiagram.getLinks()) { - // if (link.getEntity1() == ent || link.getEntity2() == ent) { - // return false; - // } - // } - // return true; - // } - private void addLink(Link link) { - final String assId = "ass" + UniqueSequence.getValue(); + if (link.isHidden() || link.isInvis()) + return; + + final String assId = "ass" + classDiagram.getUniqueSequence(); if (link.getType().getDecor1() == LinkDecor.EXTENDS || link.getType().getDecor2() == LinkDecor.EXTENDS) { addExtension(link, assId); return; @@ -88,60 +76,43 @@ public class XmiClassDiagramStar extends XmiClassDiagramAbstract implements IXmi final Element association = document.createElement("UML:Association"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(classDiagram)); - if (Display.isNull(link.getLabel()) == false) { + if (Display.isNull(link.getLabel()) == false) association.setAttribute("name", forXMI(link.getLabel())); - } final Element connection = document.createElement("UML:Association.connection"); final Element end1 = document.createElement("UML:AssociationEnd"); - end1.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end1.setAttribute("xmi.id", "end" + classDiagram.getUniqueSequence()); end1.setAttribute("association", assId); end1.setAttribute("type", link.getEntity1().getUid()); - if (link.getQualifier1() != null) { + if (link.getQualifier1() != null) end1.setAttribute("name", forXMI(link.getQualifier1())); - } + final Element endparticipant1 = document.createElement("UML:AssociationEnd.participant"); - // if (fileFormat == FileFormat.XMI_ARGO) { - // if (done.contains(link.getEntity1())) { - // endparticipant1.appendChild(createEntityNodeRef(link.getEntity1())); - // } else { - // endparticipant1.appendChild(createEntityNode(link.getEntity1())); - // done.add(link.getEntity1()); - // } - // } else if (fileFormat == FileFormat.XMI_STAR) { - if (link.getType().getDecor2() == LinkDecor.COMPOSITION) { + + if (link.getType().getDecor2() == LinkDecor.COMPOSITION) end1.setAttribute("aggregation", "composite"); - } - if (link.getType().getDecor2() == LinkDecor.AGREGATION) { + + if (link.getType().getDecor2() == LinkDecor.AGREGATION) end1.setAttribute("aggregation", "aggregate"); - } - // } + end1.appendChild(endparticipant1); connection.appendChild(end1); final Element end2 = document.createElement("UML:AssociationEnd"); - end2.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end2.setAttribute("xmi.id", "end" + classDiagram.getUniqueSequence()); end2.setAttribute("association", assId); end2.setAttribute("type", link.getEntity2().getUid()); - if (link.getQualifier2() != null) { + if (link.getQualifier2() != null) end2.setAttribute("name", forXMI(link.getQualifier2())); - } + final Element endparticipant2 = document.createElement("UML:AssociationEnd.participant"); - // if (fileFormat == FileFormat.XMI_ARGO) { - // if (done.contains(link.getEntity2())) { - // endparticipant2.appendChild(createEntityNodeRef(link.getEntity2())); - // } else { - // endparticipant2.appendChild(createEntityNode(link.getEntity2())); - // done.add(link.getEntity2()); - // } - // } else if (fileFormat == FileFormat.XMI_STAR) { - if (link.getType().getDecor1() == LinkDecor.COMPOSITION) { + + if (link.getType().getDecor1() == LinkDecor.COMPOSITION) end2.setAttribute("aggregation", "composite"); - } - if (link.getType().getDecor1() == LinkDecor.AGREGATION) { + + if (link.getType().getDecor1() == LinkDecor.AGREGATION) end2.setAttribute("aggregation", "aggregate"); - } - // } + end2.appendChild(endparticipant2); connection.appendChild(end2); @@ -155,9 +126,9 @@ public class XmiClassDiagramStar extends XmiClassDiagramAbstract implements IXmi final Element association = document.createElement("UML:Generalization"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(classDiagram)); - if (link.getLabel() != null) { + if (link.getLabel() != null) association.setAttribute("name", forXMI(link.getLabel())); - } + if (link.getType().getDecor1() == LinkDecor.EXTENDS) { association.setAttribute("child", link.getEntity1().getUid()); association.setAttribute("parent", link.getEntity2().getUid()); diff --git a/src/net/sourceforge/plantuml/xmi/XmiDescriptionDiagram.java b/src/net/sourceforge/plantuml/xmi/XmiDescriptionDiagram.java index 79e01439f..d5f7d16a3 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiDescriptionDiagram.java +++ b/src/net/sourceforge/plantuml/xmi/XmiDescriptionDiagram.java @@ -59,11 +59,10 @@ import net.sourceforge.plantuml.cucadiagram.IGroup; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.LinkDecor; import net.sourceforge.plantuml.descdiagram.DescriptionDiagram; -import net.sourceforge.plantuml.utils.UniqueSequence; import net.sourceforge.plantuml.version.Version; import net.sourceforge.plantuml.xml.XmlFactories; -public class XmiDescriptionDiagram implements IXmiClassDiagram { +public class XmiDescriptionDiagram implements XmlDiagramTransformer { private final DescriptionDiagram diagram; private final Document document; @@ -98,43 +97,37 @@ public class XmiDescriptionDiagram implements IXmiClassDiagram { // isLeaf="false" isAbstract="false"> final Element model = document.createElement("UML:Model"); model.setAttribute("xmi.id", CucaDiagramXmiMaker.getModel(diagram)); - model.setAttribute("name", "PlantUML "+Version.versionString()); + model.setAttribute("name", "PlantUML " + Version.versionString()); content.appendChild(model); // this.ownedElement = document.createElement("UML:Namespace.ownedElement"); model.appendChild(ownedElement); - for (final IGroup gr : diagram.getGroups(false)) { - if (gr.getParentContainer() instanceof GroupRoot) { - addState(gr, ownedElement); - } - } + for (final IGroup gr : diagram.getGroups(false)) + if (gr.getParentContainer() instanceof GroupRoot) + addElement(gr, ownedElement); - for (final IEntity ent : diagram.getLeafsvalues()) { - if (ent.getParentContainer() instanceof GroupRoot) { - addState(ent, ownedElement); - } - } + for (final IEntity ent : diagram.getLeafsvalues()) + if (ent.getParentContainer() instanceof GroupRoot) + addElement(ent, ownedElement); - for (final Link link : diagram.getLinks()) { + for (final Link link : diagram.getLinks()) addLink(link); - } + } - private void addState(final IEntity tobeAdded, Element container) { - final Element elementState = createEntityNode(tobeAdded); - container.appendChild(elementState); - for (final IEntity ent : diagram.getGroups(false)) { - if (ent.getParentContainer() == tobeAdded) { - addState(ent, elementState); - } - } - for (final IEntity ent : diagram.getLeafsvalues()) { - if (ent.getParentContainer() == tobeAdded) { - addState(ent, elementState); - } - } + private void addElement(final IEntity tobeAdded, Element container) { + final Element element = createEntityNode(tobeAdded); + container.appendChild(element); + for (final IEntity ent : diagram.getGroups(false)) + if (ent.getParentContainer() == tobeAdded) + addElement(ent, element); + + for (final IEntity ent : diagram.getLeafsvalues()) + if (ent.getParentContainer() == tobeAdded) + addElement(ent, element); + } public static String forXMI(String s) { @@ -146,50 +139,47 @@ public class XmiDescriptionDiagram implements IXmiClassDiagram { } private void addLink(Link link) { - final String assId = "ass" + UniqueSequence.getValue(); + final String assId = "ass" + diagram.getUniqueSequence(); final Element association = document.createElement("UML:Association"); association.setAttribute("xmi.id", assId); association.setAttribute("namespace", CucaDiagramXmiMaker.getModel(diagram)); - if (Display.isNull(link.getLabel()) == false) { + if (Display.isNull(link.getLabel()) == false) association.setAttribute("name", forXMI(link.getLabel())); - } final Element connection = document.createElement("UML:Association.connection"); final Element end1 = document.createElement("UML:AssociationEnd"); - end1.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end1.setAttribute("xmi.id", "end" + diagram.getUniqueSequence()); end1.setAttribute("association", assId); end1.setAttribute("type", link.getEntity1().getUid()); - if (link.getQualifier1() != null) { + if (link.getQualifier1() != null) end1.setAttribute("name", forXMI(link.getQualifier1())); - } + final Element endparticipant1 = document.createElement("UML:AssociationEnd.participant"); - if (link.getType().getDecor2() == LinkDecor.COMPOSITION) { + if (link.getType().getDecor2() == LinkDecor.COMPOSITION) end1.setAttribute("aggregation", "composite"); - } - if (link.getType().getDecor2() == LinkDecor.AGREGATION) { + + if (link.getType().getDecor2() == LinkDecor.AGREGATION) end1.setAttribute("aggregation", "aggregate"); - } - // } + end1.appendChild(endparticipant1); connection.appendChild(end1); final Element end2 = document.createElement("UML:AssociationEnd"); - end2.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end2.setAttribute("xmi.id", "end" + diagram.getUniqueSequence()); end2.setAttribute("association", assId); end2.setAttribute("type", link.getEntity2().getUid()); - if (link.getQualifier2() != null) { + if (link.getQualifier2() != null) end2.setAttribute("name", forXMI(link.getQualifier2())); - } + final Element endparticipant2 = document.createElement("UML:AssociationEnd.participant"); - if (link.getType().getDecor1() == LinkDecor.COMPOSITION) { + if (link.getType().getDecor1() == LinkDecor.COMPOSITION) end2.setAttribute("aggregation", "composite"); - } - if (link.getType().getDecor1() == LinkDecor.AGREGATION) { + + if (link.getType().getDecor1() == LinkDecor.AGREGATION) end2.setAttribute("aggregation", "aggregate"); - } - // } + end2.appendChild(endparticipant2); connection.appendChild(end2); @@ -232,7 +222,6 @@ public class XmiDescriptionDiagram implements IXmiClassDiagram { final Transformer transformer = XmlFactories.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - // transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); transformer.setOutputProperty(OutputKeys.ENCODING, UTF_8.name()); // tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(source, resultat); diff --git a/src/net/sourceforge/plantuml/xmi/XmiStateDiagram.java b/src/net/sourceforge/plantuml/xmi/XmiStateDiagram.java index 8aa054053..dd7671831 100644 --- a/src/net/sourceforge/plantuml/xmi/XmiStateDiagram.java +++ b/src/net/sourceforge/plantuml/xmi/XmiStateDiagram.java @@ -59,11 +59,10 @@ import net.sourceforge.plantuml.cucadiagram.IGroup; import net.sourceforge.plantuml.cucadiagram.Link; import net.sourceforge.plantuml.cucadiagram.LinkDecor; import net.sourceforge.plantuml.statediagram.StateDiagram; -import net.sourceforge.plantuml.utils.UniqueSequence; import net.sourceforge.plantuml.version.Version; import net.sourceforge.plantuml.xml.XmlFactories; -public class XmiStateDiagram implements IXmiClassDiagram { +public class XmiStateDiagram implements XmlDiagramTransformer { private final StateDiagram diagram; private final Document document; @@ -146,7 +145,7 @@ public class XmiStateDiagram implements IXmiClassDiagram { } private void addLink(Link link) { - final String assId = "ass" + UniqueSequence.getValue(); + final String assId = "ass" + diagram.getUniqueSequence(); final Element association = document.createElement("UML:Association"); association.setAttribute("xmi.id", assId); @@ -157,7 +156,7 @@ public class XmiStateDiagram implements IXmiClassDiagram { final Element connection = document.createElement("UML:Association.connection"); final Element end1 = document.createElement("UML:AssociationEnd"); - end1.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end1.setAttribute("xmi.id", "end" + diagram.getUniqueSequence()); end1.setAttribute("association", assId); end1.setAttribute("type", link.getEntity1().getUid()); if (link.getQualifier1() != null) { @@ -176,7 +175,7 @@ public class XmiStateDiagram implements IXmiClassDiagram { connection.appendChild(end1); final Element end2 = document.createElement("UML:AssociationEnd"); - end2.setAttribute("xmi.id", "end" + UniqueSequence.getValue()); + end2.setAttribute("xmi.id", "end" + diagram.getUniqueSequence()); end2.setAttribute("association", assId); end2.setAttribute("type", link.getEntity2().getUid()); if (link.getQualifier2() != null) { diff --git a/src/net/sourceforge/plantuml/xmi/IXmiClassDiagram.java b/src/net/sourceforge/plantuml/xmi/XmlDiagramTransformer.java similarity index 97% rename from src/net/sourceforge/plantuml/xmi/IXmiClassDiagram.java rename to src/net/sourceforge/plantuml/xmi/XmlDiagramTransformer.java index faab8ed62..0429dbcda 100644 --- a/src/net/sourceforge/plantuml/xmi/IXmiClassDiagram.java +++ b/src/net/sourceforge/plantuml/xmi/XmlDiagramTransformer.java @@ -40,7 +40,7 @@ import java.io.OutputStream; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; -public interface IXmiClassDiagram { +public interface XmlDiagramTransformer { void transformerXml(OutputStream os) throws TransformerException, ParserConfigurationException; diff --git a/test/nonreg/graphml/GraphmlTest.java b/test/nonreg/graphml/GraphmlTest.java new file mode 100644 index 000000000..b411ceafe --- /dev/null +++ b/test/nonreg/graphml/GraphmlTest.java @@ -0,0 +1,106 @@ +package nonreg.graphml; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicInteger; + +import net.sourceforge.plantuml.FileFormat; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.SourceStringReader; +import net.sourceforge.plantuml.core.DiagramDescription; + +public class GraphmlTest { + + private static final String TRIPLE_QUOTE = "\"\"\""; + + protected String getXmlAndCheckXmlAndDescription(final String expectedDescription) + throws IOException, UnsupportedEncodingException { + final String actualResult = runPlantUML(expectedDescription); + final String xmlExpected = readStringFromSourceFile(getDiagramFile(), "{{{", "}}}"); + + // This is really a hack. Since XML generation does not guarantee the order of + // attributes, we make an easy to do check by sorting characters. + // Of course, this is really incomplete: a faulty String may match the expected + // result if, for example, an attribute is moved from a node to another. + // However, we consider that it is a good start. + if (sortString(actualResult).equals(sortString(xmlExpected)) == false) { + assertEquals(xmlExpected, actualResult, "Generated GraphML is not ok"); + } + + return actualResult; + } + + private String sortString(String s) { + final Map map = new TreeMap<>(); + for (int i = 0; i < s.length(); i++) { + final char ch = s.charAt(i); + // We ignore non writable characters + if (ch <= ' ') + continue; + + AtomicInteger count = map.get(ch); + if (count == null) + map.put(ch, new AtomicInteger(1)); + else + count.addAndGet(1); + } + return map.toString(); + } + + private String getLocalFolder() { + return "test/" + getPackageName().replace(".", "/"); + } + + private String getPackageName() { + return getClass().getPackage().getName(); + } + + private Path getDiagramFile() { + return Paths.get(getLocalFolder(), getClass().getSimpleName() + ".java"); + } + + private String runPlantUML(String expectedDescription) throws IOException, UnsupportedEncodingException { + final String diagramText = readStringFromSourceFile(getDiagramFile(), TRIPLE_QUOTE, TRIPLE_QUOTE); + final SourceStringReader ssr = new SourceStringReader(diagramText, UTF_8); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final DiagramDescription diagramDescription = ssr.outputImage(baos, 0, + new FileFormatOption(FileFormat.GRAPHML)); + assertEquals(expectedDescription, diagramDescription.getDescription(), "Bad description"); + + return new String(baos.toByteArray(), UTF_8); + } + + private String readStringFromSourceFile(Path path, String startMarker, String endMarker) throws IOException { + assertTrue(Files.exists(path), "Cannot find " + path); + assertTrue(Files.isReadable(path), "Cannot read " + path); + final List allLines = Files.readAllLines(path, UTF_8); + final int first = allLines.indexOf(startMarker); + final int last = allLines.lastIndexOf(endMarker); + assertTrue(first != -1); + assertTrue(last != -1); + assertTrue(last > first); + return packString(allLines.subList(first + 1, last)); + } + + private String packString(Collection list) { + final StringBuilder sb = new StringBuilder(); + for (String s : list) { + sb.append(s); + sb.append("\n"); + } + return sb.toString(); + } + +} diff --git a/test/nonreg/graphml/component/GML0000_Test.java b/test/nonreg/graphml/component/GML0000_Test.java new file mode 100644 index 000000000..1defb06cb --- /dev/null +++ b/test/nonreg/graphml/component/GML0000_Test.java @@ -0,0 +1,44 @@ +package nonreg.graphml.component; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.graphml.GraphmlTest; + +/* + +Test diagram MUST be put between triple quotes + +""" +@startuml +component comp1 +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{ + + + + + +}}} + + */ +public class GML0000_Test extends GraphmlTest { + + @Test + void testSimple() throws IOException { + final String xml = getXmlAndCheckXmlAndDescription("(1 entities)"); + + // Those tests are ULGY: please improve them! + assertTrue(xml.contains("")); + assertTrue(xml.contains("")); + } + +} diff --git a/test/nonreg/graphml/component/GML0001_Test.java b/test/nonreg/graphml/component/GML0001_Test.java new file mode 100644 index 000000000..d139f9d8c --- /dev/null +++ b/test/nonreg/graphml/component/GML0001_Test.java @@ -0,0 +1,47 @@ +package nonreg.graphml.component; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.graphml.GraphmlTest; + +/* + +Test diagram MUST be put between triple quotes + +""" +@startuml +component comp1 +component comp2 +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{ + + + + + + +}}} + + */ +public class GML0001_Test extends GraphmlTest { + + @Test + void testSimple() throws IOException { + final String xml = getXmlAndCheckXmlAndDescription("(2 entities)"); + + // Those tests are ULGY: please improve them! + assertTrue(xml.contains("")); + assertTrue(xml.contains("")); + assertTrue(xml.contains("")); + } + +} diff --git a/test/nonreg/xmi/XmiTest.java b/test/nonreg/xmi/XmiTest.java new file mode 100644 index 000000000..8af2e0f10 --- /dev/null +++ b/test/nonreg/xmi/XmiTest.java @@ -0,0 +1,112 @@ +package nonreg.xmi; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicInteger; + +import net.sourceforge.plantuml.FileFormat; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.SourceStringReader; +import net.sourceforge.plantuml.core.DiagramDescription; + +public class XmiTest { + + private static final String TRIPLE_QUOTE = "\"\"\""; + + protected void checkXmlAndDescription(final String expectedDescription) + throws IOException, UnsupportedEncodingException { + final String star = runPlantUML(expectedDescription, FileFormat.XMI_STAR); + final String startExpected = readStringFromSourceFile(getDiagramFile(), "{{{star", "}}}star"); + + // This is really a hack. Since XML generation does not guarantee the order of + // attributes, we make an easy to do check by sorting characters. + // Of course, this is really incomplete: a faulty String may match the expected + // result if, for example, an attribute is moved from a node to another. + // However, we consider that it is a good start. + if (sortString(star).equals(sortString(startExpected)) == false) { + assertEquals(startExpected, star, "XmiStar: Generated GraphML is not ok"); + } + + final String argo = runPlantUML(expectedDescription, FileFormat.XMI_ARGO); + final String argoExpected = readStringFromSourceFile(getDiagramFile(), "{{{argo", "}}}argo"); + + if (sortString(argo).equals(sortString(argoExpected)) == false) { + assertEquals(argoExpected, argo, "XmiArgo: Generated GraphML is not ok"); + } + + } + + private String sortString(String s) { + final Map map = new TreeMap<>(); + for (int i = 0; i < s.length(); i++) { + final char ch = s.charAt(i); + // We ignore non writable characters + if (ch <= ' ') + continue; + + AtomicInteger count = map.get(ch); + if (count == null) + map.put(ch, new AtomicInteger(1)); + else + count.addAndGet(1); + } + return map.toString(); + } + + private String getLocalFolder() { + return "test/" + getPackageName().replace(".", "/"); + } + + private String getPackageName() { + return getClass().getPackage().getName(); + } + + private Path getDiagramFile() { + return Paths.get(getLocalFolder(), getClass().getSimpleName() + ".java"); + } + + private String runPlantUML(String expectedDescription, FileFormat format) + throws IOException, UnsupportedEncodingException { + final String diagramText = readStringFromSourceFile(getDiagramFile(), TRIPLE_QUOTE, TRIPLE_QUOTE); + final SourceStringReader ssr = new SourceStringReader(diagramText, UTF_8); + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final DiagramDescription diagramDescription = ssr.outputImage(baos, 0, new FileFormatOption(format)); + assertEquals(expectedDescription, diagramDescription.getDescription(), "Bad description"); + + return new String(baos.toByteArray(), UTF_8); + } + + private String readStringFromSourceFile(Path path, String startMarker, String endMarker) throws IOException { + assertTrue(Files.exists(path), "Cannot find " + path); + assertTrue(Files.isReadable(path), "Cannot read " + path); + final List allLines = Files.readAllLines(path, UTF_8); + final int first = allLines.indexOf(startMarker); + final int last = allLines.lastIndexOf(endMarker); + assertTrue(first != -1); + assertTrue(last != -1); + assertTrue(last > first); + return packString(allLines.subList(first + 1, last)); + } + + private String packString(Collection list) { + final StringBuilder sb = new StringBuilder(); + for (String s : list) { + sb.append(s); + sb.append("\n"); + } + return sb.toString(); + } + +} diff --git a/test/nonreg/xmi/clazz/XMI0000_Test.java b/test/nonreg/xmi/clazz/XMI0000_Test.java new file mode 100644 index 000000000..ae186bcfe --- /dev/null +++ b/test/nonreg/xmi/clazz/XMI0000_Test.java @@ -0,0 +1,74 @@ +package nonreg.xmi.clazz; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.xmi.XmiTest; + +/* + + +https://forum.plantuml.net/12644/class-access-modifiers-not-in-xmi-export + +Test diagram MUST be put between triple quotes + +""" +@startuml +-class foo{ + # field1 : type +} +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{star + + + + + + + + + + + + + + + + + +}}}star + +{{{argo + + + + + + + + + + + + + + + + + +}}}argo + + */ +public class XMI0000_Test extends XmiTest { + + @Test + void testSimple() throws IOException { + checkXmlAndDescription("(1 entities)"); + } + +} diff --git a/test/nonreg/xmi/clazz/XMI0002_Test.java b/test/nonreg/xmi/clazz/XMI0002_Test.java new file mode 100644 index 000000000..98d43ebd3 --- /dev/null +++ b/test/nonreg/xmi/clazz/XMI0002_Test.java @@ -0,0 +1,101 @@ +package nonreg.xmi.clazz; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.xmi.XmiTest; + +/* + + +https://forum.plantuml.net/12972/only-the-first-line-any-component-description-exported-file + + +Test diagram MUST be put between triple quotes + +""" +@startuml +class A { +} + +class B{ +} + +A -->B +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{star + + + + + + + + + + + + + + + + + + + + + + + + + + + +}}}star + +{{{argo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}}}argo + + */ +public class XMI0002_Test extends XmiTest { + + @Test + void testSimple() throws IOException { + checkXmlAndDescription("(2 entities)"); + } + +} diff --git a/test/nonreg/xmi/clazz/XMI0003_Test.java b/test/nonreg/xmi/clazz/XMI0003_Test.java new file mode 100644 index 000000000..f1a372139 --- /dev/null +++ b/test/nonreg/xmi/clazz/XMI0003_Test.java @@ -0,0 +1,91 @@ +package nonreg.xmi.clazz; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.xmi.XmiTest; + +/* + + + + +Test diagram MUST be put between triple quotes + +""" +@startuml +class A { + {method}{abstract}{static} + method +} + +abstract class B{ +} + +static class C{ +} + +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{star + + + + + + + + + + + + + + + + + + + + + + +}}}star + +{{{argo + + + + + + + + + + + + + + + + + + + + + + +}}}argo + + */ +public class XMI0003_Test extends XmiTest { + + @Test + void testSimple() throws IOException { + checkXmlAndDescription("(3 entities)"); + } + +} diff --git a/test/nonreg/xmi/component/XMI0001_Test.java b/test/nonreg/xmi/component/XMI0001_Test.java new file mode 100644 index 000000000..3c9362385 --- /dev/null +++ b/test/nonreg/xmi/component/XMI0001_Test.java @@ -0,0 +1,124 @@ +package nonreg.xmi.component; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.xmi.XmiTest; + +/* + + +https://forum.plantuml.net/12972/only-the-first-line-any-component-description-exported-file + + +Test diagram MUST be put between triple quotes + +""" +@startuml +component test +note top of test: first line1\nsecond line2 +note bottom of test + first line3 + second line4 +end note +@enduml +""" + +Expected result MUST be put between triple brackets + +{{{star + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}}}star + +{{{argo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +}}}argo + + */ +public class XMI0001_Test extends XmiTest { + + @Test + void testSimple() throws IOException { + checkXmlAndDescription("(3 entities)"); + } + +}