diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 40bde6ee6..66b642108 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -48,6 +48,7 @@ import net.sourceforge.plantuml.activitydiagram3.ActivityDiagramFactory3; import net.sourceforge.plantuml.api.PSystemFactory; import net.sourceforge.plantuml.board.BoardDiagramFactory; import net.sourceforge.plantuml.bpm.BpmDiagramFactory; +import net.sourceforge.plantuml.cheneer.ChenEerDiagramFactory; import net.sourceforge.plantuml.chronology.ChronologyDiagramFactory; import net.sourceforge.plantuml.classdiagram.ClassDiagramFactory; import net.sourceforge.plantuml.core.Diagram; @@ -277,6 +278,8 @@ public class PSystemBuilder { factories.add(new HclDiagramFactory()); factories.add(new PSystemEbnfFactory()); factories.add(new PSystemRegexFactory()); + + factories.add(new ChenEerDiagramFactory()); } private boolean isOk(Diagram ps) { diff --git a/src/net/sourceforge/plantuml/abel/LeafType.java b/src/net/sourceforge/plantuml/abel/LeafType.java index ce9b751e1..34c7a2de4 100644 --- a/src/net/sourceforge/plantuml/abel/LeafType.java +++ b/src/net/sourceforge/plantuml/abel/LeafType.java @@ -62,6 +62,8 @@ public enum LeafType { PORTIN, PORTOUT, + CHEN_ENTITY, CHEN_RELATIONSHIP, CHEN_ATTRIBUTE, CHEN_CIRCLE, + STILL_UNKNOWN; public static LeafType getLeafType(String type) { diff --git a/src/net/sourceforge/plantuml/cheneer/ChenEerDiagram.java b/src/net/sourceforge/plantuml/cheneer/ChenEerDiagram.java new file mode 100644 index 000000000..0decacbef --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/ChenEerDiagram.java @@ -0,0 +1,95 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer; + +import java.util.Map; +import java.util.Stack; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.classdiagram.AbstractEntityDiagram; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.skin.UmlDiagramType; + +public class ChenEerDiagram extends AbstractEntityDiagram { + + public ChenEerDiagram(UmlSource source, Map skinParam) { + super(source, UmlDiagramType.CHEN_EER, skinParam); + } + + private final Stack ownerStack = new Stack(); + + /** + * Pushes the owner of the following attributes. + * + * @see #peekOwner() + * @param group the entity that owns the following attributes + */ + public void pushOwner(Entity group) { + ownerStack.push(group); + } + + /** + * Pops an attribute owner from the stack. See also {@link #peekOwner()}. + * + * @see #peekOwner() + * @return true if an owner was popped, false if the stack was empty + */ + public boolean popOwner() { + if (ownerStack.isEmpty()) { + return false; + } + ownerStack.pop(); + return true; + } + + /** + * Returns the owner of the current attribute. + * + *

+ * This is used to link attributes based on their lexical position (how they + * appear in sources) without nesting the entities (like how packages are + * done). It is for this reason that we can't use CucaDiagram.getCurrentGroup, + * as that method nests the entities. + * + * @return the owner of the current attribute, or null if there is no owner + */ + public Entity peekOwner() { + if (ownerStack.isEmpty()) { + return null; + } + return ownerStack.peek(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/ChenEerDiagramFactory.java b/src/net/sourceforge/plantuml/cheneer/ChenEerDiagramFactory.java new file mode 100644 index 000000000..5712b5f99 --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/ChenEerDiagramFactory.java @@ -0,0 +1,78 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer; + +import java.util.List; +import java.util.Map; + +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.cheneer.command.CommandAssociate; +import net.sourceforge.plantuml.cheneer.command.CommandCreateAttribute; +import net.sourceforge.plantuml.cheneer.command.CommandCreateEntity; +import net.sourceforge.plantuml.cheneer.command.CommandEndGroup; +import net.sourceforge.plantuml.cheneer.command.CommandMultiSubclass; +import net.sourceforge.plantuml.cheneer.command.CommandSimpleSubclass; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommonCommands; +import net.sourceforge.plantuml.command.PSystemCommandFactory; +import net.sourceforge.plantuml.core.DiagramType; +import net.sourceforge.plantuml.core.UmlSource; + +public class ChenEerDiagramFactory extends PSystemCommandFactory { + + public ChenEerDiagramFactory() { + super(DiagramType.CHEN_EER); + } + + @Override + protected void initCommandsList(List cmds) { + CommonCommands.addTitleCommands(cmds); + CommonCommands.addCommonCommands2(cmds); + + cmds.add(new CommandCreateEntity()); + cmds.add(new CommandCreateAttribute()); + cmds.add(new CommandAssociate()); + cmds.add(new CommandEndGroup()); + cmds.add(new CommandSimpleSubclass()); + cmds.add(new CommandMultiSubclass()); + } + + @Override + public AbstractPSystem createEmptyDiagram(UmlSource source, Map skinParam) { + return new ChenEerDiagram(source, skinParam); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandAssociate.java b/src/net/sourceforge/plantuml/cheneer/command/CommandAssociate.java new file mode 100644 index 000000000..0f799f01f --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandAssociate.java @@ -0,0 +1,108 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.abel.LinkArg; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.decoration.LinkDecor; +import net.sourceforge.plantuml.decoration.LinkType; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.plasma.Quark; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexOptional; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandAssociate extends SingleLineCommand2 { + + public CommandAssociate() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateEntity.class.getName(), RegexLeaf.start(), // + new RegexLeaf("NAME1", "([\\w-]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("PARTICIPATION", "([-=])"), // + new RegexOptional( // + new RegexLeaf("CARDINALITY", "(\\w+|\\(\\w+,[%s]*\\w+\\))")), // + new RegexLeaf("PARTICIPATION2", "([-=])"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("NAME2", "([\\w-]+)"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + final String name1 = diagram.cleanId(arg.get("NAME1", 0)); + final String name2 = diagram.cleanId(arg.get("NAME2", 0)); + final boolean isDouble = arg.get("PARTICIPATION", 0).equals("="); + final String cardinality = arg.get("CARDINALITY", 0); + + final Quark quark1 = diagram.quarkInContext(true, name1); + final Entity entity1 = quark1.getData(); + if (entity1 == null) { + return CommandExecutionResult.error("No such entity: " + name1); + } + + final Quark quark2 = diagram.quarkInContext(true, name2); + final Entity entity2 = quark2.getData(); + if (entity2 == null) { + return CommandExecutionResult.error("No such entity: " + name2); + } + + LinkType linkType = new LinkType(LinkDecor.NONE, LinkDecor.NONE); + if (isDouble) { + linkType = linkType.goBold(); + } + final Link link = new Link(diagram.getEntityFactory(), diagram.getCurrentStyleBuilder(), entity1, entity2, + linkType, + LinkArg.build(Display.getWithNewlines(cardinality), 3)); + link.setPortMembers(diagram.getPortId(entity1.getName()), diagram.getPortId(entity2.getName())); + diagram.addLink(link); + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandCreateAttribute.java b/src/net/sourceforge/plantuml/cheneer/command/CommandCreateAttribute.java new file mode 100644 index 000000000..be8b8a78f --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandCreateAttribute.java @@ -0,0 +1,126 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.LeafType; +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.abel.LinkArg; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.decoration.LinkDecor; +import net.sourceforge.plantuml.decoration.LinkType; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.plasma.Quark; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexOptional; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.stereo.Stereotype; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandCreateAttribute extends SingleLineCommand2 { + + public CommandCreateAttribute() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateEntity.class.getName(), RegexLeaf.start(), // + RegexLeaf.spaceZeroOrMore(), + new RegexOptional( // Copied from CommandCreatePackageBlock + new RegexConcat( // + new RegexLeaf("DISPLAY", "[%g]([^%g]+)[%g]"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("as"), // + RegexLeaf.spaceOneOrMore() // + )), // + new RegexLeaf("CODE", "([%pLN%s_.:]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO", "(<<.*>>)?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("COMPOSITE", "(\\{)?"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + final Entity owner = diagram.peekOwner(); + if (owner == null) { + return CommandExecutionResult.error("Attribute must be inside an entity, relationship or another attribute"); + } + + final LeafType type = LeafType.CHEN_ATTRIBUTE; + final String idShort = diagram.cleanId(arg.get("CODE", 0).trim()); + final String id = owner.getName() + "/" + idShort; + final Quark quark = diagram.quarkInContext(true, id); + String displayText = arg.get("DISPLAY", 0); + if (displayText == null) + displayText = idShort; + + final String stereo = arg.get("STEREO", 0); + final boolean composite = arg.get("COMPOSITE", 0) != null; + + Entity entity = quark.getData(); + if (entity == null) { + final Display display = Display.getWithNewlines(displayText); + entity = diagram.reallyCreateLeaf(quark, display, type, null); + } else { + return CommandExecutionResult.error("Attribute already exists"); + } + + if (stereo != null) { + entity.setStereotype(Stereotype.build(stereo)); + entity.setStereostyle(stereo); + } + + final LinkType linkType = new LinkType(LinkDecor.NONE, LinkDecor.NONE); + final Link link = new Link(diagram.getEntityFactory(), diagram.getCurrentStyleBuilder(), entity, owner, linkType, + LinkArg.build(Display.NULL, 2)); + diagram.addLink(link); + + if (composite) { + diagram.pushOwner(entity); + } + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandCreateEntity.java b/src/net/sourceforge/plantuml/cheneer/command/CommandCreateEntity.java new file mode 100644 index 000000000..904e2c625 --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandCreateEntity.java @@ -0,0 +1,123 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.LeafType; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.plasma.Quark; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexOptional; +import net.sourceforge.plantuml.regex.RegexOr; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.stereo.Stereotype; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandCreateEntity extends SingleLineCommand2 { + + public CommandCreateEntity() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateEntity.class.getName(), RegexLeaf.start(), // + new RegexLeaf("TYPE", "(entity|relationship)"), // + RegexLeaf.spaceOneOrMore(), // + new RegexOptional( // Copied from CommandCreatePackageBlock + new RegexConcat( // + new RegexLeaf("DISPLAY", "[%g]([^%g]+)[%g]"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("as"), // + RegexLeaf.spaceOneOrMore() // + )), // + new RegexLeaf("CODE", "([%pLN_.]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("STEREO", "(<<.+>>)?"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("\\{"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + LeafType type; + switch (arg.get("TYPE", 0)) { + case "entity": + type = LeafType.CHEN_ENTITY; + break; + case "relationship": + type = LeafType.CHEN_RELATIONSHIP; + break; + default: + throw new IllegalStateException(); + } + + final String idShort = arg.get("CODE", 0); + final Quark quark = diagram.quarkInContext(true, diagram.cleanId(idShort)); + String displayText = arg.get("DISPLAY", 0); + if (displayText == null) + displayText = quark.getName(); + + final String stereo = arg.get("STEREO", 0); + + Entity entity = quark.getData(); + + if (entity == null) { + Display display = Display.getWithNewlines(displayText); + entity = diagram.reallyCreateLeaf(quark, display, type, null); + } else { + if (entity.muteToType(type, null) == false) + return CommandExecutionResult.error("Bad name"); + } + + if (stereo != null) { + entity.setStereotype(Stereotype.build(stereo)); + entity.setStereostyle(stereo); + } + + diagram.pushOwner(entity); + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandEndGroup.java b/src/net/sourceforge/plantuml/cheneer/command/CommandEndGroup.java new file mode 100644 index 000000000..d3c4dcfc4 --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandEndGroup.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandEndGroup extends SingleLineCommand2 { + + public CommandEndGroup() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandEndGroup.class.getName(), RegexLeaf.start(), // + new RegexLeaf("\\}"), // + RegexLeaf.end()); // + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) { + if (!diagram.popOwner()) { + return CommandExecutionResult.error("Unbalanced brackets"); + } + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclass.java b/src/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclass.java new file mode 100644 index 000000000..5a8a2519b --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclass.java @@ -0,0 +1,138 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.LeafType; +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.abel.LinkArg; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.decoration.LinkDecor; +import net.sourceforge.plantuml.decoration.LinkType; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.plasma.Quark; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandMultiSubclass extends SingleLineCommand2 { + + public CommandMultiSubclass() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateEntity.class.getName(), RegexLeaf.start(), // + new RegexLeaf("SUPERCLASS", "([\\w-]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("PARTICIPATION", "([-=])"), // + new RegexLeaf("(>)"), // + new RegexLeaf("PARTICIPATION2", "([-=])"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("SYMBOL", "([doU])"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("\\{"), // + new RegexLeaf("SUBCLASSES", "(.+)"), // + new RegexLeaf("\\}"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + final String superclass = diagram.cleanId(arg.get("SUPERCLASS", 0)); + final String subclasses = arg.get("SUBCLASSES", 0); + final List subclassIds = Arrays.stream(subclasses.split(",")) + .map(String::trim) + .map(diagram::cleanId) + .collect(Collectors.toList()); + final boolean isDouble = arg.get("PARTICIPATION", 0).equals("="); + final String symbol = arg.get("SYMBOL", 0); + + final Quark centerQuark = diagram.quarkInContext(false, superclass + "/" + symbol + subclasses + "/center"); + final Entity centerEntity = diagram.reallyCreateLeaf(centerQuark, Display.create(symbol), LeafType.CHEN_CIRCLE, null); + + final Quark superclassQuark = diagram.quarkInContext(true, superclass); + final Entity superclassEntity = superclassQuark.getData(); + if (superclassEntity == null) { + return CommandExecutionResult.error("No such entity: " + superclass); + } + + LinkType linkType = new LinkType(LinkDecor.NONE, LinkDecor.NONE); + if (isDouble) { + linkType = linkType.goBold(); + } + if (symbol.equals("U")) { + linkType = linkType.withMiddleSuperset(); + } + final Link link = new Link(diagram.getEntityFactory(), diagram.getCurrentStyleBuilder(), superclassEntity, + centerEntity, + linkType, + LinkArg.build(Display.NULL, 2)); + link.setPortMembers(diagram.getPortId(superclassEntity.getName()), diagram.getPortId(centerEntity.getName())); + diagram.addLink(link); + + for (String subclass : subclassIds) { + final Quark subclassQuark = diagram.quarkInContext(true, subclass); + final Entity subclassEntity = subclassQuark.getData(); + if (subclassEntity == null) { + return CommandExecutionResult.error("No such entity: " + subclass); + } + + LinkType subclassLinkType = new LinkType(LinkDecor.NONE, LinkDecor.NONE); + if (!symbol.equals("U")) { + subclassLinkType = subclassLinkType.withMiddleSuperset(); + } + final Link subclassLink = new Link(diagram.getEntityFactory(), diagram.getCurrentStyleBuilder(), centerEntity, + subclassEntity, + subclassLinkType, + LinkArg.build(Display.NULL, 3)); + diagram.addLink(subclassLink); + } + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclass.java b/src/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclass.java new file mode 100644 index 000000000..323ecd862 --- /dev/null +++ b/src/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclass.java @@ -0,0 +1,111 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://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.cheneer.command; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.abel.LinkArg; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.command.SingleLineCommand2; +import net.sourceforge.plantuml.decoration.LinkDecor; +import net.sourceforge.plantuml.decoration.LinkType; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.klimt.creole.Display; +import net.sourceforge.plantuml.plasma.Quark; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexConcat; +import net.sourceforge.plantuml.regex.RegexLeaf; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.LineLocation; + +public class CommandSimpleSubclass extends SingleLineCommand2 { + + public CommandSimpleSubclass() { + super(getRegexConcat()); + } + + protected static IRegex getRegexConcat() { + return RegexConcat.build(CommandCreateEntity.class.getName(), RegexLeaf.start(), // + new RegexLeaf("NAME1", "([\\w-]+)"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("PARTICIPATION", "([-=])"), // + new RegexLeaf("DIRECTION", "([<>])"), // + new RegexLeaf("PARTICIPATION2", "([-=])"), // + RegexLeaf.spaceZeroOrMore(), // + new RegexLeaf("NAME2", "([\\w-]+)"), // + RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(ChenEerDiagram diagram, LineLocation location, RegexResult arg) + throws NoSuchColorException { + String name1 = diagram.cleanId(arg.get("NAME1", 0)); + String name2 = diagram.cleanId(arg.get("NAME2", 0)); + final boolean isDouble = arg.get("PARTICIPATION", 0).equals("="); + final boolean isSuperset = arg.get("DIRECTION", 0).equals(">"); + + final Quark quark1 = diagram.quarkInContext(true, name1); + final Entity entity1 = quark1.getData(); + if (entity1 == null) { + return CommandExecutionResult.error("No such entity: " + name1); + } + + final Quark quark2 = diagram.quarkInContext(true, name2); + final Entity entity2 = quark2.getData(); + if (entity2 == null) { + return CommandExecutionResult.error("No such entity: " + name2); + } + + LinkType linkType = new LinkType(LinkDecor.NONE, LinkDecor.NONE); + if (isDouble) { + linkType = linkType.goBold(); + } + if (isSuperset) { + linkType = linkType.withMiddleSuperset(); + } else { + linkType = linkType.withMiddleSubset(); + } + final Link link = new Link(diagram.getEntityFactory(), diagram.getCurrentStyleBuilder(), entity1, entity2, + linkType, + LinkArg.build(Display.NULL, 3)); + link.setPortMembers(diagram.getPortId(entity1.getName()), diagram.getPortId(entity2.getName())); + diagram.addLink(link); + + return CommandExecutionResult.ok(); + } + +} diff --git a/src/net/sourceforge/plantuml/core/DiagramType.java b/src/net/sourceforge/plantuml/core/DiagramType.java index 1f1e7f9ae..0105cbd83 100644 --- a/src/net/sourceforge/plantuml/core/DiagramType.java +++ b/src/net/sourceforge/plantuml/core/DiagramType.java @@ -5,12 +5,12 @@ * (C) Copyright 2009-2024, Arnaud Roques * * Project Info: https://plantuml.com - * + * * If you like this project or if you find it useful, you can support us at: - * + * * https://plantuml.com/patreon (only 1$ per month!) * https://plantuml.com/paypal - * + * * This file is part of PlantUML. * * PlantUML is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import net.sourceforge.plantuml.utils.StartUtils; public enum DiagramType { // ::remove folder when __HAXE__ UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, MATH, LATEX, DEFINITION, GANTT, CHRONOLOGY, NW, MINDMAP, - WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, UNKNOWN; + WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, CHEN_EER, UNKNOWN; static public DiagramType getTypeFromArobaseStart(String s) { s = s.toLowerCase(); @@ -130,6 +130,9 @@ public enum DiagramType { if (StartUtils.startsWithSymbolAnd("startchronology", s)) return CHRONOLOGY; + if (StartUtils.startsWithSymbolAnd("startchen", s)) + return CHEN_EER; + return UNKNOWN; } } diff --git a/src/net/sourceforge/plantuml/decoration/LinkMiddleDecor.java b/src/net/sourceforge/plantuml/decoration/LinkMiddleDecor.java index e2afe1f26..262d05f22 100644 --- a/src/net/sourceforge/plantuml/decoration/LinkMiddleDecor.java +++ b/src/net/sourceforge/plantuml/decoration/LinkMiddleDecor.java @@ -40,10 +40,11 @@ import net.sourceforge.plantuml.svek.extremity.MiddleCircleCircledMode; import net.sourceforge.plantuml.svek.extremity.MiddleFactory; import net.sourceforge.plantuml.svek.extremity.MiddleFactoryCircle; import net.sourceforge.plantuml.svek.extremity.MiddleFactoryCircleCircled; +import net.sourceforge.plantuml.svek.extremity.MiddleFactorySubset; public enum LinkMiddleDecor { - NONE, CIRCLE, CIRCLE_CIRCLED, CIRCLE_CIRCLED1, CIRCLE_CIRCLED2; + NONE, CIRCLE, CIRCLE_CIRCLED, CIRCLE_CIRCLED1, CIRCLE_CIRCLED2, SUBSET, SUPERSET; public MiddleFactory getMiddleFactory(HColor backColor, HColor diagramBackColor) { if (this == CIRCLE) @@ -57,6 +58,12 @@ public enum LinkMiddleDecor { if (this == CIRCLE_CIRCLED2) return new MiddleFactoryCircleCircled(MiddleCircleCircledMode.MODE2, backColor, diagramBackColor); + + if (this == SUBSET) + return new MiddleFactorySubset(false); + + if (this == SUPERSET) + return new MiddleFactorySubset(true); throw new UnsupportedOperationException(); } diff --git a/src/net/sourceforge/plantuml/decoration/LinkType.java b/src/net/sourceforge/plantuml/decoration/LinkType.java index 6a6710684..482004431 100644 --- a/src/net/sourceforge/plantuml/decoration/LinkType.java +++ b/src/net/sourceforge/plantuml/decoration/LinkType.java @@ -148,6 +148,14 @@ public class LinkType { return new LinkType(decor1, decor2, LinkMiddleDecor.CIRCLE_CIRCLED2, linkStyle); } + public LinkType withMiddleSubset() { + return new LinkType(decor1, decor2, LinkMiddleDecor.SUBSET, linkStyle); + } + + public LinkType withMiddleSuperset() { + return new LinkType(decor1, decor2, LinkMiddleDecor.SUPERSET, linkStyle); + } + public LinkType getInvisible() { return new LinkType(decor1, decor2, middleDecor, LinkStyle.INVISIBLE()); } diff --git a/src/net/sourceforge/plantuml/skin/UmlDiagramType.java b/src/net/sourceforge/plantuml/skin/UmlDiagramType.java index 00bdbd29f..b29b560aa 100644 --- a/src/net/sourceforge/plantuml/skin/UmlDiagramType.java +++ b/src/net/sourceforge/plantuml/skin/UmlDiagramType.java @@ -39,7 +39,7 @@ import net.sourceforge.plantuml.style.SName; public enum UmlDiagramType { SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, WIRE, - HELP, GANTT, SALT, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, CHRONOLOGY; + HELP, GANTT, SALT, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, CHRONOLOGY, CHEN_EER; public SName getStyleName() { if (this == SEQUENCE) diff --git a/src/net/sourceforge/plantuml/style/SName.java b/src/net/sourceforge/plantuml/style/SName.java index 7f1f9689f..a0bad78fd 100644 --- a/src/net/sourceforge/plantuml/style/SName.java +++ b/src/net/sourceforge/plantuml/style/SName.java @@ -64,6 +64,10 @@ public enum SName { component, // composite, // robust, // + chenAttribute, // + chenEerDiagram, // + chenEntity, // + chenRelationship, // concise, // clock, // componentDiagram, // diff --git a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java index dc08ee433..2505b5220 100644 --- a/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java +++ b/src/net/sourceforge/plantuml/svek/GeneralImageBuilder.java @@ -99,6 +99,10 @@ import net.sourceforge.plantuml.svek.image.EntityImageArcCircle; import net.sourceforge.plantuml.svek.image.EntityImageAssociation; import net.sourceforge.plantuml.svek.image.EntityImageAssociationPoint; import net.sourceforge.plantuml.svek.image.EntityImageBranch; +import net.sourceforge.plantuml.svek.image.EntityImageChenAttribute; +import net.sourceforge.plantuml.svek.image.EntityImageChenCircle; +import net.sourceforge.plantuml.svek.image.EntityImageChenEntity; +import net.sourceforge.plantuml.svek.image.EntityImageChenRelationship; import net.sourceforge.plantuml.svek.image.EntityImageCircleEnd; import net.sourceforge.plantuml.svek.image.EntityImageCircleStart; import net.sourceforge.plantuml.svek.image.EntityImageClass; @@ -254,6 +258,18 @@ public final class GeneralImageBuilder { if (leaf.getLeafType() == LeafType.TIPS) return new EntityImageTips(leaf, skinParam, bibliotekon, umlDiagramType); + if (leaf.getLeafType() == LeafType.CHEN_ENTITY) + return new EntityImageChenEntity(leaf, skinParam); + + if (leaf.getLeafType() == LeafType.CHEN_RELATIONSHIP) + return new EntityImageChenRelationship(leaf, skinParam); + + if (leaf.getLeafType() == LeafType.CHEN_ATTRIBUTE) + return new EntityImageChenAttribute(leaf, skinParam); + + if (leaf.getLeafType() == LeafType.CHEN_CIRCLE) + return new EntityImageChenCircle(leaf, skinParam); + // TODO Clean if (leaf.getLeafType() == LeafType.DOMAIN && leaf.getStereotype() != null && leaf.getStereotype().isMachineOrSpecification()) diff --git a/src/net/sourceforge/plantuml/svek/extremity/MiddleFactorySubset.java b/src/net/sourceforge/plantuml/svek/extremity/MiddleFactorySubset.java new file mode 100644 index 000000000..37a2b067c --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/extremity/MiddleFactorySubset.java @@ -0,0 +1,52 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.extremity; + +import net.sourceforge.plantuml.klimt.shape.UDrawable; + +public class MiddleFactorySubset implements MiddleFactory { + + private final boolean reverse; + + public MiddleFactorySubset(boolean reverse) { + this.reverse = reverse; + } + + public UDrawable createUDrawable(double angle) { + return new MiddleSubset(angle, reverse); + } + +} diff --git a/src/net/sourceforge/plantuml/svek/extremity/MiddleSubset.java b/src/net/sourceforge/plantuml/svek/extremity/MiddleSubset.java new file mode 100644 index 000000000..00acf5e0c --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/extremity/MiddleSubset.java @@ -0,0 +1,82 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.extremity; + +import net.sourceforge.plantuml.klimt.UStroke; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.geom.XPoint2D; +import net.sourceforge.plantuml.klimt.shape.UEllipse; +import net.sourceforge.plantuml.klimt.shape.ULine; + +class MiddleSubset extends Extremity { + + private final double radius = 6; + private final double length = 10; + + private final double angle; + private final boolean reverse; + + public MiddleSubset(double angle, boolean reverse) { + this.angle = angle; + this.reverse = reverse; + } + + @Override + public XPoint2D somePoint() { + return null; + } + + public void drawU(UGraphic ug) { + ug = ug.apply(UStroke.withThickness(1.5)); + + final double rotate = reverse ? -45 : 135; + + ug.apply(new UTranslate(-radius, -radius)).draw(new UEllipse(2 * radius, 2 * radius, angle + rotate, 180)); + + final double sin = Math.sin(Math.toRadians(angle + rotate)); + final double cos = Math.cos(Math.toRadians(angle + rotate)); + + ug.apply(new UTranslate(radius * cos, radius * -sin)).draw(new ULine(length * sin, length * cos)); + ug.apply(new UTranslate(radius * -cos, radius * sin)).draw(new ULine(length * sin, length * cos)); + } + + @Override + public double getDecorationLength() { + return radius; + } + +} diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageChenAttribute.java b/src/net/sourceforge/plantuml/svek/image/EntityImageChenAttribute.java new file mode 100644 index 000000000..b69ba154b --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageChenAttribute.java @@ -0,0 +1,177 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.image; + +import java.util.Collections; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.klimt.UGroupType; +import net.sourceforge.plantuml.klimt.UShape; +import net.sourceforge.plantuml.klimt.UStroke; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.ColorType; +import net.sourceforge.plantuml.klimt.color.Colors; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.creole.CreoleMode; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.geom.XDimension2D; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.TextBlockInEllipse; +import net.sourceforge.plantuml.klimt.shape.UEllipse; +import net.sourceforge.plantuml.style.ISkinParam; +import net.sourceforge.plantuml.style.PName; +import net.sourceforge.plantuml.style.SName; +import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignatureBasic; +import net.sourceforge.plantuml.svek.AbstractEntityImage; +import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.url.Url; + +public class EntityImageChenAttribute extends AbstractEntityImage { + + final static private int MARGIN = 6; + + final private boolean isKey; + final private boolean isMulti; + final private boolean isDerived; + + final private TextBlock title; + final private Url url; + + public EntityImageChenAttribute(Entity entity, ISkinParam skinParam) { + super(entity, skinParam); + + isKey = hasStereotype("<>"); + isMulti = hasStereotype("<>"); + isDerived = hasStereotype("<>"); + + FontConfiguration titleFontConfiguration = getStyleTitle(entity, skinParam) + .getFontConfiguration(getSkinParam().getIHtmlColorSet(), entity.getColors()); + if (isKey) { + titleFontConfiguration = titleFontConfiguration.underline(); + } + + title = entity.getDisplay().create8(titleFontConfiguration, HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, + getStyle().wrapWidth()); + + url = entity.getUrl99(); + } + + private boolean hasStereotype(String stereotype) { + return getEntity().getStereotype() != null && getEntity().getStereotype().toString().contains(stereotype); + } + + private Style getStyle() { + return getStyle(getEntity(), getSkinParam()); + } + + private static Style getStyle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenAttribute) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + private static Style getStyleTitle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenAttribute, SName.title) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + @Override + public ShapeType getShapeType() { + return ShapeType.OVAL; + } + + @Override + public XDimension2D calculateDimension(StringBounder stringBounder) { + final TextBlockInEllipse ellipse = new TextBlockInEllipse(title, stringBounder); + + return ellipse.calculateDimension(stringBounder); + } + + @Override + public void drawU(UGraphic ug) { + ug.startGroup(Collections.singletonMap(UGroupType.ID, getEntity().getQuark().toStringPoint())); + if (url != null) + ug.startUrl(url); + + final XDimension2D dimTotal = calculateDimension(ug.getStringBounder()); + final XDimension2D dimTitle = title.calculateDimension(ug.getStringBounder()); + + UStroke stroke = getStyle().getStroke(getEntity().getColors()); + if (isDerived) { + stroke = new UStroke(10, 10, stroke.getThickness()); + } + + ug = applyColor(ug); + ug = ug.apply(stroke); + ug.draw(getShape(dimTotal)); + if (isMulti) { + ug.apply(new UTranslate(3, 3)).draw(getShape(dimTotal.delta(-6))); + } + + final double xTitle = (dimTotal.getWidth() - dimTitle.getWidth()) / 2; + final double yTitle = MARGIN; + title.drawU(ug.apply(new UTranslate(xTitle, yTitle))); + + if (url != null) + ug.closeUrl(); + + ug.closeGroup(); + } + + final protected UGraphic applyColor(UGraphic ug) { + Colors colors = getEntity().getColors(); + + HColor border = colors.getColor(ColorType.LINE); + if (border == null) + border = getStyle().value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(border); + + HColor backcolor = colors.getColor(ColorType.BACK); + if (backcolor == null) + backcolor = getStyle().value(PName.BackGroundColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(backcolor.bg()); + + return ug; + } + + private UShape getShape(XDimension2D dimTotal) { + return UEllipse.build(dimTotal.getWidth(), dimTotal.getHeight()); + } + +} diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageChenCircle.java b/src/net/sourceforge/plantuml/svek/image/EntityImageChenCircle.java new file mode 100644 index 000000000..0badab72e --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageChenCircle.java @@ -0,0 +1,175 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.image; + +import java.util.Collections; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.klimt.UGroupType; +import net.sourceforge.plantuml.klimt.UShape; +import net.sourceforge.plantuml.klimt.UStroke; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.ColorType; +import net.sourceforge.plantuml.klimt.color.Colors; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.creole.CreoleMode; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.geom.XDimension2D; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.TextBlockInEllipse; +import net.sourceforge.plantuml.klimt.shape.UEllipse; +import net.sourceforge.plantuml.style.ISkinParam; +import net.sourceforge.plantuml.style.PName; +import net.sourceforge.plantuml.style.SName; +import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignatureBasic; +import net.sourceforge.plantuml.svek.AbstractEntityImage; +import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.url.Url; + +public class EntityImageChenCircle extends AbstractEntityImage { + + final static private int MARGIN = 6; + + final private boolean isKey; + final private boolean isMulti; + final private boolean isDerived; + + final private TextBlock title; + final private Url url; + + public EntityImageChenCircle(Entity entity, ISkinParam skinParam) { + super(entity, skinParam); + + isKey = hasStereotype("<>"); + isMulti = hasStereotype("<>"); + isDerived = hasStereotype("<>"); + + FontConfiguration titleFontConfiguration = getStyleTitle(entity, skinParam) + .getFontConfiguration(getSkinParam().getIHtmlColorSet(), entity.getColors()); + if (isKey) { + titleFontConfiguration = titleFontConfiguration.underline(); + } + + title = entity.getDisplay().create8(titleFontConfiguration, HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, + getStyle().wrapWidth()); + + url = entity.getUrl99(); + } + + private boolean hasStereotype(String stereotype) { + return getEntity().getStereotype() != null && getEntity().getStereotype().toString().contains(stereotype); + } + + private Style getStyle() { + return getStyle(getEntity(), getSkinParam()); + } + + private static Style getStyle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.circle) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + private static Style getStyleTitle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.circle, SName.title) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + @Override + public ShapeType getShapeType() { + return ShapeType.OVAL; + } + + @Override + public XDimension2D calculateDimension(StringBounder stringBounder) { + return new XDimension2D(25, 25); + } + + @Override + public void drawU(UGraphic ug) { + ug.startGroup(Collections.singletonMap(UGroupType.ID, getEntity().getQuark().toStringPoint())); + if (url != null) + ug.startUrl(url); + + final XDimension2D dimTotal = calculateDimension(ug.getStringBounder()); + final XDimension2D dimTitle = title.calculateDimension(ug.getStringBounder()); + + UStroke stroke = getStyle().getStroke(getEntity().getColors()); + if (isDerived) { + stroke = new UStroke(10, 10, stroke.getThickness()); + } + + ug = applyColor(ug); + ug = ug.apply(stroke); + ug.draw(getShape(dimTotal)); + if (isMulti) { + ug.apply(new UTranslate(3, 3)).draw(getShape(dimTotal.delta(-6))); + } + + final double xTitle = (dimTotal.getWidth() - dimTitle.getWidth()) / 2; + final double yTitle = (dimTotal.getHeight() - dimTitle.getHeight()) / 2; + title.drawU(ug.apply(new UTranslate(xTitle, yTitle))); + + if (url != null) + ug.closeUrl(); + + ug.closeGroup(); + } + + final protected UGraphic applyColor(UGraphic ug) { + Colors colors = getEntity().getColors(); + + HColor border = colors.getColor(ColorType.LINE); + if (border == null) + border = getStyle().value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(border); + + HColor backcolor = colors.getColor(ColorType.BACK); + if (backcolor == null) + backcolor = getStyle().value(PName.BackGroundColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(backcolor.bg()); + + return ug; + } + + private UShape getShape(XDimension2D dimTotal) { + return UEllipse.build(dimTotal.getWidth(), dimTotal.getHeight()); + } + +} diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageChenEntity.java b/src/net/sourceforge/plantuml/svek/image/EntityImageChenEntity.java new file mode 100644 index 000000000..a86b97676 --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageChenEntity.java @@ -0,0 +1,162 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.image; + +import java.util.Collections; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.klimt.UGroupType; +import net.sourceforge.plantuml.klimt.UStroke; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.ColorType; +import net.sourceforge.plantuml.klimt.color.Colors; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.creole.CreoleMode; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.geom.XDimension2D; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.URectangle; +import net.sourceforge.plantuml.style.ISkinParam; +import net.sourceforge.plantuml.style.PName; +import net.sourceforge.plantuml.style.SName; +import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignatureBasic; +import net.sourceforge.plantuml.svek.AbstractEntityImage; +import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.url.Url; + +public class EntityImageChenEntity extends AbstractEntityImage { + + final private boolean isWeak; + + final private TextBlock title; + final private Url url; + + public EntityImageChenEntity(Entity entity, ISkinParam skinParam) { + super(entity, skinParam); + + isWeak = hasStereotype("<>"); + + final FontConfiguration titleFontConfiguration = getStyleStateTitle(entity, skinParam) + .getFontConfiguration(getSkinParam().getIHtmlColorSet(), entity.getColors()); + + title = entity.getDisplay().create8(titleFontConfiguration, HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, + getStyleState().wrapWidth()); + + url = entity.getUrl99(); + } + + private boolean hasStereotype(String stereotype) { + return getEntity().getStereotype() != null && getEntity().getStereotype().toString().contains(stereotype); + } + + private Style getStyleState() { + return getStyleState(getEntity(), getSkinParam()); + } + + private static Style getStyleState(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenEntity) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + private static Style getStyleStateTitle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenEntity, SName.title) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + @Override + public ShapeType getShapeType() { + return ShapeType.RECTANGLE; + } + + @Override + public XDimension2D calculateDimension(StringBounder stringBounder) { + final XDimension2D dim = title.calculateDimension(stringBounder); + + return dim.delta(MARGIN * 2 + 2 * MARGIN_LINE); + } + + @Override + public void drawU(UGraphic ug) { + ug.startGroup(Collections.singletonMap(UGroupType.ID, getEntity().getQuark().toStringPoint())); + if (url != null) + ug.startUrl(url); + + final XDimension2D dimTotal = calculateDimension(ug.getStringBounder()); + final XDimension2D dimTitle = title.calculateDimension(ug.getStringBounder()); + + final UStroke stroke = getStyleState().getStroke(getEntity().getColors()); + ug = applyColor(ug); + ug = ug.apply(stroke); + ug.draw(getShape(dimTotal)); + if (isWeak) { + ug.apply(new UTranslate(3, 3)).draw(getShape(dimTotal.delta(-6))); + } + + final double xTitle = (dimTotal.getWidth() - dimTitle.getWidth()) / 2; + final double yTitle = MARGIN + MARGIN_LINE; + title.drawU(ug.apply(new UTranslate(xTitle, yTitle))); + + if (url != null) + ug.closeUrl(); + + ug.closeGroup(); + } + + final protected UGraphic applyColor(UGraphic ug) { + Colors colors = getEntity().getColors(); + + HColor border = colors.getColor(ColorType.LINE); + if (border == null) + border = getStyleState().value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(border); + + HColor backcolor = colors.getColor(ColorType.BACK); + if (backcolor == null) + backcolor = getStyleState().value(PName.BackGroundColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(backcolor.bg()); + + return ug; + } + + private URectangle getShape(XDimension2D dimTotal) { + return URectangle.build(dimTotal); + } + +} diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageChenRelationship.java b/src/net/sourceforge/plantuml/svek/image/EntityImageChenRelationship.java new file mode 100644 index 000000000..8bf58c962 --- /dev/null +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageChenRelationship.java @@ -0,0 +1,178 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2024, Arnaud Roques + * + * Project Info: https://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * https://plantuml.com/patreon (only 1$ per month!) + * https://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + * + */ +package net.sourceforge.plantuml.svek.image; + +import java.util.Arrays; +import java.util.Collections; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.klimt.UGroupType; +import net.sourceforge.plantuml.klimt.UShape; +import net.sourceforge.plantuml.klimt.UStroke; +import net.sourceforge.plantuml.klimt.UTranslate; +import net.sourceforge.plantuml.klimt.color.ColorType; +import net.sourceforge.plantuml.klimt.color.Colors; +import net.sourceforge.plantuml.klimt.color.HColor; +import net.sourceforge.plantuml.klimt.creole.CreoleMode; +import net.sourceforge.plantuml.klimt.drawing.UGraphic; +import net.sourceforge.plantuml.klimt.font.FontConfiguration; +import net.sourceforge.plantuml.klimt.font.StringBounder; +import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment; +import net.sourceforge.plantuml.klimt.geom.XDimension2D; +import net.sourceforge.plantuml.klimt.geom.XPoint2D; +import net.sourceforge.plantuml.klimt.shape.TextBlock; +import net.sourceforge.plantuml.klimt.shape.UPolygon; +import net.sourceforge.plantuml.style.ISkinParam; +import net.sourceforge.plantuml.style.PName; +import net.sourceforge.plantuml.style.SName; +import net.sourceforge.plantuml.style.Style; +import net.sourceforge.plantuml.style.StyleSignatureBasic; +import net.sourceforge.plantuml.svek.AbstractEntityImage; +import net.sourceforge.plantuml.svek.ShapeType; +import net.sourceforge.plantuml.url.Url; + +public class EntityImageChenRelationship extends AbstractEntityImage { + + final private boolean isIdentifying; + + final private TextBlock title; + final private Url url; + + public EntityImageChenRelationship(Entity entity, ISkinParam skinParam) { + super(entity, skinParam); + + isIdentifying = hasStereotype("<>"); + + final FontConfiguration titleFontConfiguration = getStyleTitle(entity, skinParam) + .getFontConfiguration(getSkinParam().getIHtmlColorSet(), entity.getColors()); + + title = entity.getDisplay().create8(titleFontConfiguration, HorizontalAlignment.CENTER, skinParam, CreoleMode.FULL, + getStyle().wrapWidth()); + + url = entity.getUrl99(); + } + + private boolean hasStereotype(String stereotype) { + return getEntity().getStereotype() != null && getEntity().getStereotype().toString().contains(stereotype); + } + + private Style getStyle() { + return getStyle(getEntity(), getSkinParam()); + } + + private static Style getStyle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenRelationship) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + private static Style getStyleTitle(Entity group, ISkinParam skinParam) { + return StyleSignatureBasic.of(SName.root, SName.element, SName.chenEerDiagram, SName.chenRelationship, SName.title) + .withTOBECHANGED(group.getStereotype()).getMergedStyle(skinParam.getCurrentStyleBuilder()); + } + + @Override + public ShapeType getShapeType() { + return ShapeType.DIAMOND; + } + + @Override + public XDimension2D calculateDimension(StringBounder stringBounder) { + final XDimension2D dimTitle = title.calculateDimension(stringBounder); + + // Fit a diamond with aspect ratio 2 around the text + // diagonal = dimTitle dot ([1, 2] / sqrt(5)) + 2 * MARGIN + // dimTotal = diagonal * [sqrt(5), sqrt(5) / 2] + + final double diagonal = (dimTitle.getWidth() + 2 * dimTitle.getHeight()) / Math.sqrt(5) + 2 * MARGIN; + return new XDimension2D(diagonal * Math.sqrt(5), diagonal * Math.sqrt(5) / 2); + } + + @Override + public void drawU(UGraphic ug) { + ug.startGroup(Collections.singletonMap(UGroupType.ID, getEntity().getQuark().toStringPoint())); + if (url != null) + ug.startUrl(url); + + final XDimension2D dimTotal = calculateDimension(ug.getStringBounder()); + final XDimension2D dimTitle = title.calculateDimension(ug.getStringBounder()); + + final UStroke stroke = getStyle().getStroke(getEntity().getColors()); + ug = applyColor(ug); + ug = ug.apply(stroke); + ug.draw(getShape(dimTotal)); + if (isIdentifying) { + ug.apply(new UTranslate(10, 5)).draw(getShape(dimTotal.delta(-20, -10))); + } + + final double xTitle = (dimTotal.getWidth() - dimTitle.getWidth()) / 2; + final double yTitle = (dimTotal.getHeight() - dimTitle.getHeight()) / 2; + title.drawU(ug.apply(new UTranslate(xTitle, yTitle))); + + if (url != null) + ug.closeUrl(); + + ug.closeGroup(); + } + + final protected UGraphic applyColor(UGraphic ug) { + Colors colors = getEntity().getColors(); + + HColor border = colors.getColor(ColorType.LINE); + if (border == null) + border = getStyle().value(PName.LineColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(border); + + HColor backcolor = colors.getColor(ColorType.BACK); + if (backcolor == null) + backcolor = getStyle().value(PName.BackGroundColor).asColor(getSkinParam().getIHtmlColorSet()); + ug = ug.apply(backcolor.bg()); + + return ug; + } + + private UShape getShape(XDimension2D dimTotal) { + final double width = dimTotal.getWidth(); + final double height = dimTotal.getHeight(); + + final XPoint2D p1 = new XPoint2D(0, height / 2); + final XPoint2D p2 = new XPoint2D(width / 2, 0); + final XPoint2D p3 = new XPoint2D(width, height / 2); + final XPoint2D p4 = new XPoint2D(width / 2, height); + + return new UPolygon(Arrays.asList(p1, p2, p3, p4)); + } + +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandAssociateTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandAssociateTest.java new file mode 100644 index 000000000..1012443b6 --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandAssociateTest.java @@ -0,0 +1,126 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +public class CommandAssociateTest { + + private final Command command = new CommandAssociate(); + + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parse() { + IRegex regex = CommandAssociate.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 -- E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("CARDINALITY", 0)).isNull(); + } + + @Test + void test_parseWithCompulsoryParticipation() { + IRegex regex = CommandAssociate.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 == E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("="); + assertThat(matcher.get("CARDINALITY", 0)).isNull(); + } + + @Test + void test_parseWithCardinality() { + IRegex regex = CommandAssociate.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 -N- E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("CARDINALITY", 0)).isEqualTo("N"); + } + + @Test + void test_parseCardinalityRange() { + IRegex regex = CommandAssociate.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 -(1, n)- E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("CARDINALITY", 0)).isEqualTo("(1, n)"); + } + + @Test + void test_execute() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 -- E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(1); + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link.getLabel().toString()).isEqualTo("NULL"); + } + + @Test + void test_executeWithCompulsoryParticipation() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 == E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(1); + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(2); + assertThat(link.getLabel().toString()).isEqualTo("NULL"); + } + + @Test + void test_executeWithCardinality() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 -N- E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(1); + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link.getLabel().toString()).isEqualTo("[N]"); + } +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandCreateAttributeTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandCreateAttributeTest.java new file mode 100644 index 000000000..d2735db5d --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandCreateAttributeTest.java @@ -0,0 +1,173 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +public class CommandCreateAttributeTest { + + private final Command command = new CommandCreateAttribute(); + + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parse() { + IRegex regex = CommandCreateAttribute.getRegexConcat(); + RegexResult matcher = regex.matcher("attr"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("attr"); + assertThat(matcher.get("STEREO", 0)).isNull(); + assertThat(matcher.get("COMPOSITE", 0)).isNull(); + } + + @Test + void test_parseWithType() { + IRegex regex = CommandCreateAttribute.getRegexConcat(); + RegexResult matcher = regex.matcher("attr : String"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("attr : String"); + assertThat(matcher.get("STEREO", 0)).isNull(); + assertThat(matcher.get("COMPOSITE", 0)).isNull(); + } + + @Test + void test_parseComposite() { + IRegex regex = CommandCreateAttribute.getRegexConcat(); + RegexResult matcher = regex.matcher("attr{"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("attr"); + assertThat(matcher.get("STEREO", 0)).isNull(); + assertThat(matcher.get("COMPOSITE", 0)).isNotNull(); + } + + @Test + void test_parseWithDisplay() { + IRegex regex = CommandCreateAttribute.getRegexConcat(); + RegexResult matcher = regex.matcher("\"My Attribute\" as attr"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("DISPLAY", 0)).isEqualTo("My Attribute"); + assertThat(matcher.get("CODE", 0)).isEqualTo("attr"); + assertThat(matcher.get("STEREO", 0)).isNull(); + assertThat(matcher.get("COMPOSITE", 0)).isNull(); + } + + @Test + void test_parseWithStereo() { + IRegex regex = CommandCreateAttribute.getRegexConcat(); + RegexResult matcher = regex.matcher("attr<>"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("attr"); + assertThat(matcher.get("STEREO", 0)).isEqualTo("<>"); + assertThat(matcher.get("COMPOSITE", 0)).isNull(); + } + + @Test + void test_execute() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E {")); + + BlocLines lines = BlocLines.singleString("\"Attribute\" as attr<>"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Entity entity = diagram.quarkInContext(true, "E").getData(); + assertThat(entity).isNotNull(); + + Entity attribute = diagram.quarkInContext(true, "E/attr").getData(); + assertThat(attribute).isNotNull(); + assertThat(attribute.getDisplay().toString()).isEqualTo("[Attribute]"); + assertThat(attribute.getStereotype().toString()).isEqualTo("<>"); + + assertThat(diagram.getLinks().size()).isEqualTo(1); + Link link = diagram.getLinks().get(0); + assertThat(link).isNotNull(); + assertThat(link.getEntity1()).isSameAs(attribute); + assertThat(link.getEntity2()).isSameAs(entity); + } + + @Test + void test_executeNested() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E {")); + + CommandExecutionResult result1 = command.execute(diagram, BlocLines.singleString("attr1{")); + CommandExecutionResult result2 = command.execute(diagram, BlocLines.singleString("attr2")); + + assertThat(result1).matches(CommandExecutionResult::isOk); + assertThat(result2).matches(CommandExecutionResult::isOk); + + Entity entity = diagram.quarkInContext(true, "E").getData(); + assertThat(entity).isNotNull(); + + Entity attribute1 = diagram.quarkInContext(true, "E/attr1").getData(); + assertThat(attribute1).isNotNull(); + assertThat(attribute1.getDisplay().toString()).isEqualTo("[attr1]"); + + Entity attribute2 = diagram.quarkInContext(true, "E/attr1/attr2").getData(); + assertThat(attribute2).isNotNull(); + assertThat(attribute2.getDisplay().toString()).isEqualTo("[attr2]"); + + assertThat(diagram.getLinks().size()).isEqualTo(2); + Link link1 = diagram.getLinks().get(0); + assertThat(link1).isNotNull(); + assertThat(link1.getEntity1()).isSameAs(attribute1); + assertThat(link1.getEntity2()).isSameAs(entity); + Link link2 = diagram.getLinks().get(1); + assertThat(link2).isNotNull(); + assertThat(link2.getEntity1()).isSameAs(attribute2); + assertThat(link2.getEntity2()).isSameAs(attribute1); + } + + @Test + void test_executeNonNested() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E {")); + + CommandExecutionResult result1 = command.execute(diagram, BlocLines.singleString("attr1")); + CommandExecutionResult result2 = command.execute(diagram, BlocLines.singleString("attr2")); + + assertThat(result1).matches(CommandExecutionResult::isOk); + assertThat(result2).matches(CommandExecutionResult::isOk); + + Entity entity = diagram.quarkInContext(true, "E").getData(); + assertThat(entity).isNotNull(); + + Entity attribute1 = diagram.quarkInContext(true, "E/attr1").getData(); + assertThat(attribute1).isNotNull(); + assertThat(attribute1.getDisplay().toString()).isEqualTo("[attr1]"); + + Entity attribute2 = diagram.quarkInContext(true, "E/attr2").getData(); + assertThat(attribute2).isNotNull(); + assertThat(attribute2.getDisplay().toString()).isEqualTo("[attr2]"); + + assertThat(diagram.getLinks().size()).isEqualTo(2); + Link link1 = diagram.getLinks().get(0); + assertThat(link1).isNotNull(); + assertThat(link1.getEntity1()).isSameAs(attribute1); + assertThat(link1.getEntity2()).isSameAs(entity); + Link link2 = diagram.getLinks().get(1); + assertThat(link2).isNotNull(); + assertThat(link2.getEntity1()).isSameAs(attribute2); + assertThat(link2.getEntity2()).isSameAs(entity); + } +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandCreateEntityTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandCreateEntityTest.java new file mode 100644 index 000000000..f9730f537 --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandCreateEntityTest.java @@ -0,0 +1,123 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.plantuml.abel.Entity; +import net.sourceforge.plantuml.abel.LeafType; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +public class CommandCreateEntityTest { + + private final Command command = new CommandCreateEntity(); + + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parseEntity() { + IRegex regex = CommandCreateEntity.getRegexConcat(); + RegexResult matcher = regex.matcher("entity Bus_123 {"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("TYPE", 0)).isEqualTo("entity"); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("Bus_123"); + assertThat(matcher.get("STEREO", 0)).isNull(); + } + + @Test + void test_parseRelationship() { + IRegex regex = CommandCreateEntity.getRegexConcat(); + RegexResult matcher = regex.matcher("relationship Drives {"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("TYPE", 0)).isEqualTo("relationship"); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("Drives"); + assertThat(matcher.get("STEREO", 0)).isNull(); + } + + @Test + void test_parseInvalid() { + IRegex regex = CommandCreateEntity.getRegexConcat(); + RegexResult matcher = regex.matcher("class MyClass {"); + + assertThat(matcher).isNull(); + } + + @Test + void test_parseEntityWithStereo() { + IRegex regex = CommandCreateEntity.getRegexConcat(); + RegexResult matcher = regex.matcher("entity Bus_123 <> {"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("TYPE", 0)).isEqualTo("entity"); + assertThat(matcher.get("DISPLAY", 0)).isNull(); + assertThat(matcher.get("CODE", 0)).isEqualTo("Bus_123"); + assertThat(matcher.get("STEREO", 0)).isEqualTo("<>"); + } + + @Test + void test_parseEntityWithDisplayName() { + IRegex regex = CommandCreateEntity.getRegexConcat(); + RegexResult matcher = regex.matcher("entity \"Red Bus :)\" as Bus_123 <> {"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("TYPE", 0)).isEqualTo("entity"); + assertThat(matcher.get("DISPLAY", 0)).isEqualTo("Red Bus :)"); + assertThat(matcher.get("CODE", 0)).isEqualTo("Bus_123"); + assertThat(matcher.get("STEREO", 0)).isEqualTo("<>"); + } + + @Test + void test_executeWithEntity() throws NoSuchColorException { + BlocLines lines = BlocLines.singleString("entity \"display\" as code <> {"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Entity entity = diagram.quarkInContext(true, "code").getData(); + assertThat(entity).isNotNull(); + assertThat(entity.getLeafType()).isEqualTo(LeafType.CHEN_ENTITY); + assertThat(entity.getDisplay().toString()).isEqualTo("[display]"); + assertThat(entity.getStereotype().toString()).isEqualTo("<>"); + + assertThat(diagram.peekOwner()).isSameAs(entity); + } + + @Test + void test_executeWithRelationship() throws NoSuchColorException { + BlocLines lines = BlocLines.singleString("relationship \"display\" as code <> {"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Entity entity = diagram.quarkInContext(true, "code").getData(); + assertThat(entity).isNotNull(); + assertThat(entity.getLeafType()).isEqualTo(LeafType.CHEN_RELATIONSHIP); + assertThat(entity.getDisplay().toString()).isEqualTo("[display]"); + assertThat(entity.getStereotype().toString()).isEqualTo("<>"); + + assertThat(diagram.peekOwner()).isSameAs(entity); + } + + @Test + void test_executeWithEntityWhenAlreadyExists() throws NoSuchColorException { + BlocLines lines = BlocLines.singleString("entity \"display\" as code <> {"); + command.execute(diagram, lines); + + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + } +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandEndGroupTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandEndGroupTest.java new file mode 100644 index 000000000..99f4a5591 --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandEndGroupTest.java @@ -0,0 +1,49 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +@ExtendWith(MockitoExtension.class) +public class CommandEndGroupTest { + + private final Command command = new CommandEndGroup(); + + @Spy + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parse() { + IRegex regex = CommandEndGroup.getRegexConcat(); + RegexResult matcher = regex.matcher("}"); + + assertThat(matcher).isNotNull(); + } + + @Test + void test_execute() throws NoSuchColorException { + diagram.pushOwner(null); + + BlocLines lines = BlocLines.singleString("}"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Mockito.verify(diagram).popOwner(); + } +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclassTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclassTest.java new file mode 100644 index 000000000..d1fc338ed --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandMultiSubclassTest.java @@ -0,0 +1,213 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.decoration.LinkMiddleDecor; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +public class CommandMultiSubclassTest { + + private final Command command = new CommandMultiSubclass(); + + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parse() { + IRegex regex = CommandMultiSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 ->- d { E2, E3, E4 }"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("SUPERCLASS", 0)).isEqualTo("E1"); + assertThat(matcher.get("SUBCLASSES", 0)).isEqualTo(" E2, E3, E4 "); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("SYMBOL", 0)).isEqualTo("d"); + } + + @Test + void test_parseWithCompulsoryParticipation() { + IRegex regex = CommandMultiSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 =>= d { E2, E3, E4 }"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("SUPERCLASS", 0)).isEqualTo("E1"); + assertThat(matcher.get("SUBCLASSES", 0)).isEqualTo(" E2, E3, E4 "); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("="); + assertThat(matcher.get("SYMBOL", 0)).isEqualTo("d"); + } + + @Test + void test_parseOverlapping() { + IRegex regex = CommandMultiSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 ->- o { E2, E3, E4 }"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("SUPERCLASS", 0)).isEqualTo("E1"); + assertThat(matcher.get("SUBCLASSES", 0)).isEqualTo(" E2, E3, E4 "); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("SYMBOL", 0)).isEqualTo("o"); + } + + @Test + void test_parseCategory() { + IRegex regex = CommandMultiSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 ->- U { E2, E3, E4 }"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("SUPERCLASS", 0)).isEqualTo("E1"); + assertThat(matcher.get("SUBCLASSES", 0)).isEqualTo(" E2, E3, E4 "); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("SYMBOL", 0)).isEqualTo("U"); + } + + @Test + void test_executeOverlappingSubclasses() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E3 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E4 {")); + + BlocLines lines = BlocLines.singleString("E1 ->- o { E2, E3, E4 }"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(4); + Link link1 = diagram.getLinks().get(0); + assertThat(link1.getEntity1().getName()).isEqualTo("E1"); + assertThat(link1.getEntity2().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link1.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link1.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link2 = diagram.getLinks().get(1); + assertThat(link2.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link2.getEntity2().getName()).isEqualTo("E2"); + assertThat(link2.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link2.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link3 = diagram.getLinks().get(2); + assertThat(link3.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link3.getEntity2().getName()).isEqualTo("E3"); + assertThat(link3.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link3.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link4 = diagram.getLinks().get(3); + assertThat(link4.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link4.getEntity2().getName()).isEqualTo("E4"); + assertThat(link4.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link4.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + } + + @Test + void test_executeOverlappingSubclassesWithCompulsaryParticipation() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E3 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E4 {")); + + BlocLines lines = BlocLines.singleString("E1 =>= o { E2, E3, E4 }"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(4); + Link link1 = diagram.getLinks().get(0); + assertThat(link1.getEntity1().getName()).isEqualTo("E1"); + assertThat(link1.getEntity2().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link1.getType().getStyle().getStroke3().getThickness()).isEqualTo(2); + assertThat(link1.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link2 = diagram.getLinks().get(1); + assertThat(link2.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link2.getEntity2().getName()).isEqualTo("E2"); + assertThat(link2.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link2.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link3 = diagram.getLinks().get(2); + assertThat(link3.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link3.getEntity2().getName()).isEqualTo("E3"); + assertThat(link3.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link3.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link4 = diagram.getLinks().get(3); + assertThat(link4.getEntity1().getName()).isEqualTo("E1/o E2, E3, E4 /center"); + assertThat(link4.getEntity2().getName()).isEqualTo("E4"); + assertThat(link4.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link4.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + } + + @Test + void test_executeCategories() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E3 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E4 {")); + + BlocLines lines = BlocLines.singleString("E1 ->- U { E2, E3, E4 }"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(4); + Link link1 = diagram.getLinks().get(0); + assertThat(link1.getEntity1().getName()).isEqualTo("E1"); + assertThat(link1.getEntity2().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link1.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link1.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link2 = diagram.getLinks().get(1); + assertThat(link2.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link2.getEntity2().getName()).isEqualTo("E2"); + assertThat(link2.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link2.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link3 = diagram.getLinks().get(2); + assertThat(link3.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link3.getEntity2().getName()).isEqualTo("E3"); + assertThat(link3.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link3.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link4 = diagram.getLinks().get(3); + assertThat(link4.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link4.getEntity2().getName()).isEqualTo("E4"); + assertThat(link4.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link4.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + } + + @Test + void test_executeCategoriesWithCompulsaryParticipation() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E3 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E4 {")); + + BlocLines lines = BlocLines.singleString("E1 =>= U { E2, E3, E4 }"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + assertThat(diagram.getLinks().size()).isEqualTo(4); + Link link1 = diagram.getLinks().get(0); + assertThat(link1.getEntity1().getName()).isEqualTo("E1"); + assertThat(link1.getEntity2().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link1.getType().getStyle().getStroke3().getThickness()).isEqualTo(2); + assertThat(link1.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + Link link2 = diagram.getLinks().get(1); + assertThat(link2.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link2.getEntity2().getName()).isEqualTo("E2"); + assertThat(link2.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link2.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link3 = diagram.getLinks().get(2); + assertThat(link3.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link3.getEntity2().getName()).isEqualTo("E3"); + assertThat(link3.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link3.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + Link link4 = diagram.getLinks().get(3); + assertThat(link4.getEntity1().getName()).isEqualTo("E1/U E2, E3, E4 /center"); + assertThat(link4.getEntity2().getName()).isEqualTo("E4"); + assertThat(link4.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link4.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.NONE); + } +} diff --git a/test/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclassTest.java b/test/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclassTest.java new file mode 100644 index 000000000..22a33b2c5 --- /dev/null +++ b/test/net/sourceforge/plantuml/cheneer/command/CommandSimpleSubclassTest.java @@ -0,0 +1,112 @@ +package net.sourceforge.plantuml.cheneer.command; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; + +import org.junit.jupiter.api.Test; + +import net.sourceforge.plantuml.abel.Link; +import net.sourceforge.plantuml.cheneer.ChenEerDiagram; +import net.sourceforge.plantuml.command.Command; +import net.sourceforge.plantuml.command.CommandExecutionResult; +import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.decoration.LinkMiddleDecor; +import net.sourceforge.plantuml.klimt.color.NoSuchColorException; +import net.sourceforge.plantuml.regex.IRegex; +import net.sourceforge.plantuml.regex.RegexResult; +import net.sourceforge.plantuml.utils.BlocLines; + +public class CommandSimpleSubclassTest { + + private final Command command = new CommandSimpleSubclass(); + + private final ChenEerDiagram diagram = new ChenEerDiagram(UmlSource.create(new ArrayList<>(), false), null); + + @Test + void test_parseSubset() { + IRegex regex = CommandSimpleSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 -<- E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("DIRECTION", 0)).isEqualTo("<"); + } + + @Test + void test_parseSubsetWithCompulsoryParticipation() { + IRegex regex = CommandSimpleSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 =<= E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("="); + assertThat(matcher.get("DIRECTION", 0)).isEqualTo("<"); + } + + @Test + void test_parseSuperset() { + IRegex regex = CommandSimpleSubclass.getRegexConcat(); + RegexResult matcher = regex.matcher("E1 ->- E2"); + + assertThat(matcher).isNotNull(); + assertThat(matcher.get("NAME1", 0)).isEqualTo("E1"); + assertThat(matcher.get("NAME2", 0)).isEqualTo("E2"); + assertThat(matcher.get("PARTICIPATION", 0)).isEqualTo("-"); + assertThat(matcher.get("DIRECTION", 0)).isEqualTo(">"); + } + + @Test + void test_executeSubset() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 -<- E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUBSET); + } + + @Test + void test_executeSubsetWithCompulsoryParticipation() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 =<= E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(2); + assertThat(link.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUBSET); + } + + @Test + void test_executeSuperset() throws NoSuchColorException { + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E1 {")); + new CommandCreateEntity().execute(diagram, BlocLines.singleString("entity E2 {")); + + BlocLines lines = BlocLines.singleString("E1 ->- E2"); + CommandExecutionResult result = command.execute(diagram, lines); + + assertThat(result).matches(CommandExecutionResult::isOk); + + Link link = diagram.getLinks().get(0); + assertThat(link.getEntity1().getName()).isEqualTo("E1"); + assertThat(link.getEntity2().getName()).isEqualTo("E2"); + assertThat(link.getType().getStyle().getStroke3().getThickness()).isEqualTo(1); + assertThat(link.getType().getMiddleDecor()).isEqualTo(LinkMiddleDecor.SUPERSET); + } +} diff --git a/test/nonreg/simple/ChenMovieAlias_Test.java b/test/nonreg/simple/ChenMovieAlias_Test.java new file mode 100644 index 000000000..38aeac532 --- /dev/null +++ b/test/nonreg/simple/ChenMovieAlias_Test.java @@ -0,0 +1,94 @@ +package nonreg.simple; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.BasicTest; + +/* + +Test diagram MUST be put between triple quotes + +""" +@startchen movies + +entity "Director" as DIRECTOR { + "No." as Number <> + Name { + Fname + Lname + } + Born : DATE + Died + Age +} + +entity "Customer" as CUSTOMER { + Number <> + Bonus <> + Name <> +} + +entity "Movie" as MOVIE { + Code +} + +relationship "was-rented-to" as RENTED_TO { + Date +} + +RENTED_TO -1- CUSTOMER +RENTED_TO -N- MOVIE +RENTED_TO -(N,M)- DIRECTOR + +entity "Parent" as PARENT { +} + +entity "Member" as MEMBER { +} + +CUSTOMER ->- PARENT +MEMBER -<- CUSTOMER + +entity "Kid" as CHILD <> { + Name <> +} + +relationship "is-parent-of" as PARENT_OF <> { +} + +PARENT_OF -1- PARENT +PARENT_OF =N= CHILD + +entity "Little Kid" as TODDLER { + FavoriteToy +} + +entity "Primary-Aged Kid" as PRIMARY_AGE { + FavoriteColor +} + +entity "Teenager" as TEEN { + Hobby +} + +CHILD =>= d { TODDLER, PRIMARY_AGE, TEEN } + +entity "Human" as PERSON { +} + +PERSON ->- U { CUSTOMER, DIRECTOR } + +@endchen +""" + + */ +public class ChenMovieAlias_Test extends BasicTest { + + @Test + void testSimple() throws IOException { + checkImage("(30 entities)"); + } + +} diff --git a/test/nonreg/simple/ChenMovieAlias_TestResult.java b/test/nonreg/simple/ChenMovieAlias_TestResult.java new file mode 100644 index 000000000..70a5dd854 --- /dev/null +++ b/test/nonreg/simple/ChenMovieAlias_TestResult.java @@ -0,0 +1,1077 @@ +package nonreg.simple; + +public class ChenMovieAlias_TestResult { +} +/* +""" +DPI: 96 +dimension: [ 1600.7960 ; 777.0000 ] +scaleFactor: 1.0000 +seed: 8173768504811424439 +svgLinkTarget: _top +hoverPathColorRGB: null +preserveAspectRatio: none + +RECTANGLE: + pt1: [ 225.0000 ; 345.5000 ] + pt2: [ 371.0712 ; 379.5000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Director + position: [ 235.0000 ; 366.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 200.5000 ; 232.5000 ] + pt2: [ 261.9272 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: No. + position: [ 211.6171 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 82.0000 ; 232.5000 ] + pt2: [ 182.4750 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 98.8355 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 24.5000 ; 122.5000 ] + pt2: [ 117.5753 ; 148.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Fname + position: [ 40.2519 ; 139.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 136.0000 ; 121.5000 ] + pt2: [ 250.0711 ; 149.1142 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Lname + position: [ 151.8671 ; 138.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 376.0000 ; 225.0000 ] + pt2: [ 555.7951 ; 265.7590 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Born : DATE + position: [ 386.3602 ; 241.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 574.0000 ; 232.5000 ] + pt2: [ 647.9416 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Died + position: [ 586.9498 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 6.0000 ; 232.5000 ] + pt2: [ 64.3515 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Age + position: [ 16.6667 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1102.0000 ; 345.5000 ] + pt2: [ 1229.6315 ; 379.5000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Customer + position: [ 1112.0000 ; 366.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 908.5000 ; 231.0000 ] + pt2: [ 1027.7119 ; 259.6424 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Number + position: [ 923.6174 ; 247.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1045.5000 ; 231.5000 ] + pt2: [ 1160.1275 ; 259.2255 ] + start: 0.0 + extend: 0.0 + stroke: 10.0-10.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Bonus + position: [ 1061.2808 ; 248.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1179.0000 ; 232.5000 ] + pt2: [ 1279.4750 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +ELLIPSE: + pt1: [ 1182.0000 ; 235.5000 ] + pt2: [ 1276.4750 ; 255.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 1195.8355 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 696.5000 ; 345.5000 ] + pt2: [ 783.3873 ; 379.5000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Movie + position: [ 706.5000 ; 366.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 752.5000 ; 232.5000 ] + pt2: [ 841.6043 ; 258.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Code + position: [ 767.6703 ; 249.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +POLYGON: + points: + - [ 578.5000 ; 135.6745 ] + - [ 683.8491 ; 83.0000 ] + - [ 789.1982 ; 135.6745 ] + - [ 683.8491 ; 188.3491 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: was-rented-to + position: [ 603.6803 ; 139.5634 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 642.0000 ; 16.0000 ] + pt2: [ 725.5211 ; 41.7990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Date + position: [ 656.3527 ; 32.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1237.5000 ; 522.0000 ] + pt2: [ 1346.8250 ; 556.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Parent + position: [ 1247.5000 ; 542.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1298.0000 ; 118.5000 ] + pt2: [ 1392.0549 ; 152.5000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Member + position: [ 1308.0000 ; 139.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1391.0000 ; 522.0000 ] + pt2: [ 1448.6410 ; 556.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +RECTANGLE: + pt1: [ 1394.0000 ; 525.0000 ] + pt2: [ 1445.6410 ; 553.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Kid + position: [ 1401.0000 ; 542.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1397.0000 ; 459.0000 ] + pt2: [ 1497.4750 ; 484.7990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 1413.8355 ; 475.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +POLYGON: + points: + - [ 1248.0000 ; 362.5454 ] + - [ 1367.0907 ; 303.0000 ] + - [ 1486.1815 ; 362.5454 ] + - [ 1367.0907 ; 422.0907 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +POLYGON: + points: + - [ 1258.0000 ; 362.5454 ] + - [ 1367.0907 ; 308.0000 ] + - [ 1476.1815 ; 362.5454 ] + - [ 1367.0907 ; 417.0907 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: is-parent-of + position: [ 1273.1803 ; 366.4343 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 961.0000 ; 738.0000 ] + pt2: [ 1150.8871 ; 772.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Little Kid + position: [ 971.0000 ; 758.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 926.5000 ; 655.0000 ] + pt2: [ 1133.2015 ; 701.1403 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: FavoriteToy + position: [ 935.8014 ; 671.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1221.5000 ; 738.0000 ] + pt2: [ 1420.7716 ; 772.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Primary-Aged Kid + position: [ 1231.5000 ; 758.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1190.0000 ; 655.5000 ] + pt2: [ 1392.3804 ; 700.7761 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: FavoriteColor + position: [ 1199.4497 ; 672.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1464.5000 ; 738.0000 ] + pt2: [ 1595.7960 ; 772.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Teenager + position: [ 1474.5000 ; 758.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1448.5000 ; 665.0000 ] + pt2: [ 1555.1381 ; 691.1276 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Hobby + position: [ 1465.6665 ; 681.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1407.5000 ; 593.0000 ] + pt2: [ 1432.5000 ; 618.0000 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: d + position: [ 1413.3082 ; 609.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1003.0000 ; 12.0000 ] + pt2: [ 1082.9460 ; 46.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Human + position: [ 1013.0000 ; 32.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1030.5000 ; 123.0000 ] + pt2: [ 1055.5000 ; 148.0000 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: U + position: [ 1036.3048 ; 139.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 232.1702 ; 252.8070 ] + - type: SEG_CUBICTO + pt1: [ 244.3231 ; 273.6665 ] + pt2: [ 268.9649 ; 315.9622 ] + pt3: [ 282.5249 ; 339.2368 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 143.4512 ; 252.5897 ] + - type: SEG_CUBICTO + pt1: [ 173.5015 ; 273.4077 ] + pt2: [ 235.0250 ; 316.0294 ] + pt3: [ 268.7005 ; 339.3588 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 71.9975 ; 142.8890 ] + - type: SEG_CUBICTO + pt1: [ 83.7642 ; 163.7218 ] + pt2: [ 107.3724 ; 205.5201 ] + pt3: [ 119.0841 ; 226.2555 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 179.5202 ; 143.7429 ] + - type: SEG_CUBICTO + pt1: [ 167.5581 ; 164.9216 ] + pt2: [ 144.3016 ; 206.0972 ] + pt3: [ 132.7905 ; 226.4775 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 431.5011 ; 260.0082 ] + - type: SEG_CUBICTO + pt1: [ 398.8293 ; 282.3728 ] + pt2: [ 345.8814 ; 318.6169 ] + pt3: [ 315.4799 ; 339.4275 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 577.3751 ; 252.5142 ] + - type: SEG_CUBICTO + pt1: [ 571.3454 ; 255.0514 ] + pt2: [ 564.9792 ; 257.6656 ] + pt3: [ 559.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 482.8743 ; 289.7213 ] + pt2: [ 393.2083 ; 321.0528 ] + pt3: [ 339.5708 ; 339.4093 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 51.7745 ; 252.5268 ] + - type: SEG_CUBICTO + pt1: [ 56.7584 ; 255.0632 ] + pt2: [ 62.0302 ; 257.6739 ] + pt3: [ 67.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 130.8004 ; 289.8615 ] + pt2: [ 206.4657 ; 321.1514 ] + pt3: [ 251.7823 ; 339.4613 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 985.4907 ; 254.1436 ] + - type: SEG_CUBICTO + pt1: [ 1022.2659 ; 275.5029 ] + pt2: [ 1093.2657 ; 316.7402 ] + pt3: [ 1132.4153 ; 339.4786 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1104.2269 ; 253.6920 ] + - type: SEG_CUBICTO + pt1: [ 1115.7976 ; 274.8131 ] + pt2: [ 1138.4553 ; 316.1723 ] + pt3: [ 1151.0385 ; 339.1416 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1216.2579 ; 252.8070 ] + - type: SEG_CUBICTO + pt1: [ 1204.8305 ; 273.6665 ] + pt2: [ 1181.6598 ; 315.9622 ] + pt3: [ 1168.9094 ; 339.2368 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 784.9000 ; 252.8070 ] + - type: SEG_CUBICTO + pt1: [ 774.5609 ; 273.6665 ] + pt2: [ 753.5970 ; 315.9622 ] + pt3: [ 742.0609 ; 339.2368 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 678.0000 ; 36.3979 ] + - type: SEG_CUBICTO + pt1: [ 678.0000 ; 46.5620 ] + pt2: [ 678.0000 ; 61.6797 ] + pt3: [ 678.0000 ; 76.7427 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 783.9201 ; 179.4304 ] + - type: SEG_CUBICTO + pt1: [ 805.0022 ; 191.1245 ] + pt2: [ 826.3650 ; 204.4783 ] + pt3: [ 845.0000 ; 219.0000 ] + - type: SEG_CUBICTO + pt1: [ 864.3608 ; 234.0873 ] + pt2: [ 861.5196 ; 246.4714 ] + pt3: [ 882.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 948.2135 ; 303.7382 ] + pt2: [ 1036.5592 ; 329.5771 ] + pt3: [ 1095.7197 ; 343.1239 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 888.0000 ; 239.0000 ] + pt2: [ 900.3969 ; 252.0000 ] + +TEXT: + text: 1 + position: [ 889.0000 ; 248.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 690.8475 ; 182.1195 ] + - type: SEG_CUBICTO + pt1: [ 703.4411 ; 232.7188 ] + pt2: [ 721.8869 ; 306.8313 ] + pt3: [ 729.9624 ; 339.2776 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 716.0000 ; 239.0000 ] + pt2: [ 728.5088 ; 252.0000 ] + +TEXT: + text: N + position: [ 717.0000 ; 248.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 572.4552 ; 141.3090 ] + - type: SEG_CUBICTO + pt1: [ 473.4806 ; 153.8082 ] + pt2: [ 335.6648 ; 178.0968 ] + pt3: [ 301.0000 ; 219.0000 ] + - type: SEG_CUBICTO + pt1: [ 271.9795 ; 253.2431 ] + pt2: [ 280.9041 ; 311.3247 ] + pt3: [ 287.5633 ; 339.3813 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 307.0000 ; 239.0000 ] + pt2: [ 367.5178 ; 252.0000 ] + +TEXT: + text: (N,M) + position: [ 308.0000 ; 248.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1171.6279 ; 373.6038 ] + - type: SEG_CUBICTO + pt1: [ 1195.6314 ; 406.8467 ] + pt2: [ 1250.4207 ; 482.7255 ] + pt3: [ 1274.4002 ; 515.9352 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1336.5920 ; 146.6696 ] + - type: SEG_CUBICTO + pt1: [ 1332.2375 ; 172.2425 ] + pt2: [ 1321.3527 ; 222.9198 ] + pt3: [ 1299.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 1281.6387 ; 288.8001 ] + pt2: [ 1262.1722 ; 280.2715 ] + pt3: [ 1233.0000 ; 297.0000 ] + - type: SEG_CUBICTO + pt1: [ 1212.1484 ; 308.9571 ] + pt2: [ 1191.0078 ; 326.6412 ] + pt3: [ 1176.8815 ; 339.4340 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1435.9215 ; 479.2260 ] + - type: SEG_CUBICTO + pt1: [ 1431.6443 ; 489.5231 ] + pt2: [ 1425.4891 ; 504.3410 ] + pt3: [ 1420.7893 ; 515.6555 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1335.8174 ; 416.0914 ] + - type: SEG_CUBICTO + pt1: [ 1320.7529 ; 451.1416 ] + pt2: [ 1302.7049 ; 493.1332 ] + pt3: [ 1293.0006 ; 515.7121 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 1325.0000 ; 465.5000 ] + pt2: [ 1337.3969 ; 478.5000 ] + +TEXT: + text: 1 + position: [ 1326.0000 ; 475.0556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1358.1384 ; 416.0133 ] + - type: SEG_CUBICTO + pt1: [ 1358.9834 ; 436.5538 ] + pt2: [ 1362.0875 ; 459.3842 ] + pt3: [ 1370.0000 ; 479.0000 ] + - type: SEG_CUBICTO + pt1: [ 1375.6368 ; 492.9743 ] + pt2: [ 1386.3839 ; 506.0318 ] + pt3: [ 1395.8452 ; 515.6898 ] + stroke: 0.0-0.0-2.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 1376.0000 ; 465.5000 ] + pt2: [ 1388.5088 ; 478.5000 ] + +TEXT: + text: N + position: [ 1377.0000 ; 475.0556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1031.6602 ; 695.0968 ] + - type: SEG_CUBICTO + pt1: [ 1035.7346 ; 706.8497 ] + pt2: [ 1040.6559 ; 721.0459 ] + pt3: [ 1044.3744 ; 731.7723 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1293.6772 ; 694.6931 ] + - type: SEG_CUBICTO + pt1: [ 1298.3842 ; 706.4605 ] + pt2: [ 1304.1079 ; 720.7696 ] + pt3: [ 1308.4396 ; 731.5989 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1500.4987 ; 685.0500 ] + - type: SEG_CUBICTO + pt1: [ 1505.2291 ; 697.7208 ] + pt2: [ 1512.6997 ; 717.7313 ] + pt3: [ 1517.9454 ; 731.7824 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1414.0000 ; 550.2761 ] + - type: SEG_CUBICTO + pt1: [ 1414.0000 ; 561.6212 ] + pt2: [ 1414.0000 ; 576.4948 ] + pt3: [ 1414.0000 ; 586.7072 ] + stroke: 0.0-0.0-2.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1401.2771 ; 600.2072 ] + - type: SEG_CUBICTO + pt1: [ 1363.7609 ; 599.9125 ] + pt2: [ 1251.4289 ; 603.1572 ] + pt3: [ 1175.0000 ; 649.0000 ] + - type: SEG_CUBICTO + pt1: [ 1152.2590 ; 662.6403 ] + pt2: [ 1157.0453 ; 677.6393 ] + pt3: [ 1137.0000 ; 695.0000 ] + - type: SEG_CUBICTO + pt1: [ 1120.2885 ; 709.4734 ] + pt2: [ 1099.1544 ; 722.4488 ] + pt3: [ 1081.9010 ; 731.9383 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1414.4114 ; 612.0393 ] + - type: SEG_CUBICTO + pt1: [ 1414.5294 ; 630.9891 ] + pt2: [ 1412.3704 ; 669.1714 ] + pt3: [ 1395.0000 ; 695.0000 ] + - type: SEG_CUBICTO + pt1: [ 1384.3079 ; 710.8984 ] + pt2: [ 1367.0782 ; 723.2084 ] + pt3: [ 1351.3421 ; 731.9456 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1426.8860 ; 600.2582 ] + - type: SEG_CUBICTO + pt1: [ 1456.2165 ; 600.4959 ] + pt2: [ 1527.8255 ; 605.7005 ] + pt3: [ 1559.0000 ; 649.0000 ] + - type: SEG_CUBICTO + pt1: [ 1577.5338 ; 674.7423 ] + pt2: [ 1554.7041 ; 711.2267 ] + pt3: [ 1538.1772 ; 731.9584 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1037.0000 ; 40.3281 ] + - type: SEG_CUBICTO + pt1: [ 1037.0000 ; 61.5674 ] + pt2: [ 1037.0000 ; 98.1555 ] + pt3: [ 1037.0000 ; 116.8167 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1049.5409 ; 130.4592 ] + - type: SEG_CUBICTO + pt1: [ 1091.2973 ; 131.0869 ] + pt2: [ 1226.1328 ; 139.4190 ] + pt3: [ 1282.0000 ; 219.0000 ] + - type: SEG_CUBICTO + pt1: [ 1292.4699 ; 233.9141 ] + pt2: [ 1290.1227 ; 243.6883 ] + pt3: [ 1282.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 1269.8357 ; 284.4279 ] + pt2: [ 1254.5386 ; 280.2435 ] + pt3: [ 1233.0000 ; 297.0000 ] + - type: SEG_CUBICTO + pt1: [ 1214.7975 ; 311.1611 ] + pt2: [ 1194.3279 ; 327.6114 ] + pt3: [ 1179.7068 ; 339.4543 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1024.2296 ; 131.6209 ] + - type: SEG_CUBICTO + pt1: [ 980.6910 ; 135.9617 ] + pt2: [ 835.3843 ; 154.7622 ] + pt3: [ 738.0000 ; 219.0000 ] + - type: SEG_CUBICTO + pt1: [ 718.2392 ; 232.0348 ] + pt2: [ 724.1429 ; 247.5637 ] + pt3: [ 704.0000 ; 260.0000 ] + - type: SEG_CUBICTO + pt1: [ 598.1032 ; 325.3810 ] + pt2: [ 451.8207 ; 346.0494 ] + pt3: [ 365.0560 ; 352.5521 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +""" +*/ \ No newline at end of file diff --git a/test/nonreg/simple/ChenMovieExtended_Test.java b/test/nonreg/simple/ChenMovieExtended_Test.java new file mode 100644 index 000000000..d26d61e0d --- /dev/null +++ b/test/nonreg/simple/ChenMovieExtended_Test.java @@ -0,0 +1,94 @@ +package nonreg.simple; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.BasicTest; + +/* + +Test diagram MUST be put between triple quotes + +""" +@startchen movies + +entity DIRECTOR { + Number <> + Name { + Fname + Lname + } + Born : DATE + Died + Age +} + +entity CUSTOMER { + Number <> + Bonus <> + Name <> +} + +entity MOVIE { + Code +} + +relationship RENTED_TO { + Date +} + +RENTED_TO -1- CUSTOMER +RENTED_TO -N- MOVIE +RENTED_TO -(N,M)- DIRECTOR + +entity PARENT { +} + +entity MEMBER { +} + +CUSTOMER ->- PARENT +MEMBER -<- CUSTOMER + +entity CHILD <> { + Name <> +} + +relationship PARENT_OF <> { +} + +PARENT_OF -1- PARENT +PARENT_OF =N= CHILD + +entity TODDLER { + FavoriteToy +} + +entity PRIMARY_AGE { + FavoriteColor +} + +entity TEEN { + Hobby +} + +CHILD =>= d { TODDLER, PRIMARY_AGE, TEEN } + +entity PERSON { +} + +PERSON ->- U { CUSTOMER, DIRECTOR } + +@endchen +""" + + */ +public class ChenMovieExtended_Test extends BasicTest { + + @Test + void testSimple() throws IOException { + checkImage("(30 entities)"); + } + +} diff --git a/test/nonreg/simple/ChenMovieExtended_TestResult.java b/test/nonreg/simple/ChenMovieExtended_TestResult.java new file mode 100644 index 000000000..6219b35af --- /dev/null +++ b/test/nonreg/simple/ChenMovieExtended_TestResult.java @@ -0,0 +1,1073 @@ +package nonreg.simple; + +public class ChenMovieExtended_TestResult { +} +/* +""" +DPI: 96 +dimension: [ 1611.3106 ; 720.0000 ] +scaleFactor: 1.0000 +seed: -7760046765121812191 +svgLinkTarget: _top +hoverPathColorRGB: null +preserveAspectRatio: none + +RECTANGLE: + pt1: [ 298.5000 ; 310.0000 ] + pt2: [ 413.4536 ; 344.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: DIRECTOR + position: [ 308.5000 ; 330.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 200.5000 ; 217.0000 ] + pt2: [ 319.7119 ; 245.6424 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Number + position: [ 215.6174 ; 233.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 82.0000 ; 218.5000 ] + pt2: [ 182.4750 ; 244.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 98.8355 ; 235.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 24.5000 ; 115.5000 ] + pt2: [ 117.5753 ; 141.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Fname + position: [ 40.2519 ; 132.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 136.0000 ; 114.5000 ] + pt2: [ 250.0711 ; 142.1142 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Lname + position: [ 151.8671 ; 131.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 434.0000 ; 211.0000 ] + pt2: [ 613.7951 ; 251.7590 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Born : DATE + position: [ 444.3602 ; 227.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 632.0000 ; 218.5000 ] + pt2: [ 705.9416 ; 244.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Died + position: [ 644.9498 ; 235.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 6.0000 ; 218.5000 ] + pt2: [ 64.3515 ; 244.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Age + position: [ 16.6667 ; 235.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1158.0000 ; 310.0000 ] + pt2: [ 1290.4781 ; 344.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: CUSTOMER + position: [ 1168.0000 ; 330.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 966.5000 ; 217.0000 ] + pt2: [ 1085.7119 ; 245.6424 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Number + position: [ 981.6174 ; 233.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1103.5000 ; 217.5000 ] + pt2: [ 1218.1275 ; 245.2255 ] + start: 0.0 + extend: 0.0 + stroke: 10.0-10.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Bonus + position: [ 1119.2808 ; 234.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1237.0000 ; 218.5000 ] + pt2: [ 1337.4750 ; 244.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +ELLIPSE: + pt1: [ 1240.0000 ; 221.5000 ] + pt2: [ 1334.4750 ; 241.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 1253.8355 ; 235.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 759.0000 ; 310.0000 ] + pt2: [ 837.2949 ; 344.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: MOVIE + position: [ 769.0000 ; 330.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 810.5000 ; 218.5000 ] + pt2: [ 899.6043 ; 244.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Code + position: [ 825.6703 ; 235.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +POLYGON: + points: + - [ 651.5000 ; 128.3553 ] + - [ 742.2105 ; 83.0000 ] + - [ 832.9210 ; 128.3553 ] + - [ 742.2105 ; 173.7105 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: RENTED_TO + position: [ 676.6803 ; 132.2441 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 700.0000 ; 16.0000 ] + pt2: [ 783.5211 ; 41.7990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Date + position: [ 714.3527 ; 32.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1229.5000 ; 465.0000 ] + pt2: [ 1354.0571 ; 499.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: PARENT + position: [ 1239.5000 ; 485.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1346.0000 ; 111.5000 ] + pt2: [ 1460.3033 ; 145.5000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: MEMBER + position: [ 1356.0000 ; 132.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1395.0000 ; 465.0000 ] + pt2: [ 1488.9311 ; 499.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +RECTANGLE: + pt1: [ 1398.0000 ; 468.0000 ] + pt2: [ 1485.9311 ; 496.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: CHILD + position: [ 1405.0000 ; 485.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1414.0000 ; 402.0000 ] + pt2: [ 1514.4750 ; 427.7990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 1430.8355 ; 418.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +POLYGON: + points: + - [ 1308.0000 ; 327.0569 ] + - [ 1384.1139 ; 289.0000 ] + - [ 1460.2278 ; 327.0569 ] + - [ 1384.1139 ; 365.1139 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +POLYGON: + points: + - [ 1318.0000 ; 327.0569 ] + - [ 1384.1139 ; 294.0000 ] + - [ 1450.2278 ; 327.0569 ] + - [ 1384.1139 ; 360.1139 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: PARENT_OF + position: [ 1333.1803 ; 330.9458 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1054.5000 ; 681.0000 ] + pt2: [ 1181.8526 ; 715.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: TODDLER + position: [ 1064.5000 ; 701.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 948.5000 ; 598.0000 ] + pt2: [ 1155.2015 ; 644.1403 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: FavoriteToy + position: [ 957.8014 ; 614.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1267.5000 ; 681.0000 ] + pt2: [ 1456.6987 ; 715.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: PRIMARY_AGE + position: [ 1277.5000 ; 701.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1212.0000 ; 598.5000 ] + pt2: [ 1414.3804 ; 643.7761 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: FavoriteColor + position: [ 1221.4497 ; 615.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1523.0000 ; 681.0000 ] + pt2: [ 1589.1122 ; 715.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: TEEN + position: [ 1533.0000 ; 701.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1470.5000 ; 608.0000 ] + pt2: [ 1577.1381 ; 634.1276 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Hobby + position: [ 1487.6665 ; 624.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1429.5000 ; 536.0000 ] + pt2: [ 1454.5000 ; 561.0000 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: d + position: [ 1435.3082 ; 552.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 867.0000 ; 12.0000 ] + pt2: [ 957.4807 ; 46.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: PERSON + position: [ 877.0000 ; 32.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 899.5000 ; 116.0000 ] + pt2: [ 924.5000 ; 141.0000 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: U + position: [ 905.3048 ; 132.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 268.1651 ; 240.2962 ] + - type: SEG_CUBICTO + pt1: [ 285.5853 ; 257.2628 ] + pt2: [ 315.1026 ; 286.0114 ] + pt3: [ 333.5209 ; 303.9500 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 154.8255 ; 238.5321 ] + - type: SEG_CUBICTO + pt1: [ 194.7642 ; 255.2029 ] + pt2: [ 267.0296 ; 285.3673 ] + pt3: [ 311.5348 ; 303.9442 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 72.4798 ; 135.8846 ] + - type: SEG_CUBICTO + pt1: [ 84.2510 ; 155.3746 ] + pt2: [ 106.9591 ; 192.9732 ] + pt3: [ 118.6496 ; 212.3296 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 179.0253 ; 136.7040 ] + - type: SEG_CUBICTO + pt1: [ 167.1409 ; 156.3814 ] + pt2: [ 144.9474 ; 193.1281 ] + pt3: [ 133.4036 ; 212.2416 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 482.7817 ; 246.1007 ] + - type: SEG_CUBICTO + pt1: [ 451.8961 ; 263.2900 ] + pt2: [ 407.5456 ; 287.9731 ] + pt3: [ 378.7542 ; 303.9969 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 635.9871 ; 238.6440 ] + - type: SEG_CUBICTO + pt1: [ 629.8072 ; 241.2278 ] + pt2: [ 623.2244 ; 243.8286 ] + pt3: [ 617.0000 ; 246.0000 ] + - type: SEG_CUBICTO + pt1: [ 546.0356 ; 270.7566 ] + pt2: [ 462.2325 ; 292.8599 ] + pt3: [ 407.6991 ; 306.3262 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 50.7303 ; 238.6785 ] + - type: SEG_CUBICTO + pt1: [ 55.9588 ; 241.3192 ] + pt2: [ 61.5971 ; 243.9358 ] + pt3: [ 67.0000 ; 246.0000 ] + - type: SEG_CUBICTO + pt1: [ 142.9032 ; 274.9989 ] + pt2: [ 234.4743 ; 296.6554 ] + pt3: [ 292.4787 ; 308.8199 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1048.7909 ; 240.0957 ] + - type: SEG_CUBICTO + pt1: [ 1084.6142 ; 257.0123 ] + pt2: [ 1145.7067 ; 285.8615 ] + pt3: [ 1183.8552 ; 303.8761 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1163.7599 ; 239.5008 ] + - type: SEG_CUBICTO + pt1: [ 1175.1200 ; 256.3607 ] + pt2: [ 1194.9292 ; 285.7601 ] + pt3: [ 1207.2057 ; 303.9799 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1272.7639 ; 238.7235 ] + - type: SEG_CUBICTO + pt1: [ 1261.5571 ; 255.3557 ] + pt2: [ 1241.4744 ; 285.1610 ] + pt3: [ 1228.9918 ; 303.6868 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 841.5482 ; 238.7235 ] + - type: SEG_CUBICTO + pt1: [ 831.4088 ; 255.3557 ] + pt2: [ 813.2388 ; 285.1610 ] + pt3: [ 801.9449 ; 303.6868 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 736.0000 ; 36.3484 ] + - type: SEG_CUBICTO + pt1: [ 736.0000 ; 46.5968 ] + pt2: [ 736.0000 ; 61.8318 ] + pt3: [ 736.0000 ; 76.5937 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 826.7636 ; 160.0422 ] + - type: SEG_CUBICTO + pt1: [ 852.5824 ; 172.4484 ] + pt2: [ 879.9325 ; 187.6334 ] + pt3: [ 903.0000 ; 205.0000 ] + - type: SEG_CUBICTO + pt1: [ 922.6093 ; 219.7630 ] + pt2: [ 919.0540 ; 233.2041 ] + pt3: [ 940.0000 ; 246.0000 ] + - type: SEG_CUBICTO + pt1: [ 1005.5294 ; 286.0319 ] + pt2: [ 1092.6223 ; 304.6706 ] + pt3: [ 1151.7405 ; 313.1735 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 946.0000 ; 225.0000 ] + pt2: [ 958.3969 ; 238.0000 ] + +TEXT: + text: 1 + position: [ 947.0000 ; 234.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 748.7073 ; 168.0889 ] + - type: SEG_CUBICTO + pt1: [ 761.0345 ; 211.3442 ] + pt2: [ 779.0663 ; 274.6167 ] + pt3: [ 787.4284 ; 303.9587 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 776.0000 ; 225.0000 ] + pt2: [ 788.5088 ; 238.0000 ] + +TEXT: + text: N + position: [ 777.0000 ; 234.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 645.2131 ; 130.8428 ] + - type: SEG_CUBICTO + pt1: [ 545.9048 ; 140.9068 ] + pt2: [ 395.8949 ; 162.7634 ] + pt3: [ 359.0000 ; 205.0000 ] + - type: SEG_CUBICTO + pt1: [ 335.0217 ; 232.4498 ] + pt2: [ 340.5887 ; 278.9941 ] + pt3: [ 345.8106 ; 303.6089 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 365.0000 ; 225.0000 ] + pt2: [ 425.5178 ; 238.0000 ] + +TEXT: + text: (N,M) + position: [ 366.0000 ; 234.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1225.1487 ; 338.0845 ] + - type: SEG_CUBICTO + pt1: [ 1238.1745 ; 367.3927 ] + pt2: [ 1265.6366 ; 429.1824 ] + pt3: [ 1278.7424 ; 458.6705 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1399.4767 ; 139.5548 ] + - type: SEG_CUBICTO + pt1: [ 1402.9872 ; 168.6950 ] + pt2: [ 1405.7433 ; 230.4632 ] + pt3: [ 1373.0000 ; 265.0000 ] + - type: SEG_CUBICTO + pt1: [ 1347.9258 ; 291.4477 ] + pt2: [ 1327.3605 ; 270.8529 ] + pt3: [ 1293.0000 ; 283.0000 ] + - type: SEG_CUBICTO + pt1: [ 1277.1209 ; 288.6136 ] + pt2: [ 1260.2330 ; 296.7368 ] + pt3: [ 1246.5110 ; 303.9427 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1453.8620 ; 422.2260 ] + - type: SEG_CUBICTO + pt1: [ 1450.3768 ; 432.5231 ] + pt2: [ 1445.3615 ; 447.3410 ] + pt3: [ 1441.5320 ; 458.6555 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1355.7294 ; 359.0370 ] + - type: SEG_CUBICTO + pt1: [ 1336.5849 ; 390.8751 ] + pt2: [ 1309.8892 ; 435.2712 ] + pt3: [ 1295.7259 ; 458.8254 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 1338.0000 ; 408.5000 ] + pt2: [ 1350.3969 ; 421.5000 ] + +TEXT: + text: 1 + position: [ 1339.0000 ; 418.0556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1375.7164 ; 359.0616 ] + - type: SEG_CUBICTO + pt1: [ 1375.8794 ; 378.5549 ] + pt2: [ 1378.2970 ; 402.4053 ] + pt3: [ 1387.0000 ; 422.0000 ] + - type: SEG_CUBICTO + pt1: [ 1393.3583 ; 436.3156 ] + pt2: [ 1405.1898 ; 449.2873 ] + pt3: [ 1415.6337 ; 458.8144 ] + stroke: 0.0-0.0-2.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 1393.0000 ; 408.5000 ] + pt2: [ 1405.5088 ; 421.5000 ] + +TEXT: + text: N + position: [ 1394.0000 ; 418.0556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1065.4452 ; 638.0968 ] + - type: SEG_CUBICTO + pt1: [ 1075.7878 ; 649.8497 ] + pt2: [ 1088.2804 ; 664.0459 ] + pt3: [ 1097.7196 ; 674.7723 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1321.1728 ; 637.6931 ] + - type: SEG_CUBICTO + pt1: [ 1328.8608 ; 649.4605 ] + pt2: [ 1338.2095 ; 663.7696 ] + pt3: [ 1345.2846 ; 674.5989 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1523.1414 ; 628.0500 ] + - type: SEG_CUBICTO + pt1: [ 1528.5475 ; 640.7208 ] + pt2: [ 1537.0854 ; 660.7313 ] + pt3: [ 1543.0805 ; 674.7824 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1436.0000 ; 493.2761 ] + - type: SEG_CUBICTO + pt1: [ 1436.0000 ; 504.6212 ] + pt2: [ 1436.0000 ; 519.4948 ] + pt3: [ 1436.0000 ; 529.7072 ] + stroke: 0.0-0.0-2.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1423.2771 ; 543.2072 ] + - type: SEG_CUBICTO + pt1: [ 1385.7609 ; 542.9125 ] + pt2: [ 1273.4289 ; 546.1572 ] + pt3: [ 1197.0000 ; 592.0000 ] + - type: SEG_CUBICTO + pt1: [ 1174.2590 ; 605.6403 ] + pt2: [ 1176.2443 ; 617.8544 ] + pt3: [ 1159.0000 ; 638.0000 ] + - type: SEG_CUBICTO + pt1: [ 1148.2836 ; 650.5194 ] + pt2: [ 1135.9085 ; 664.4539 ] + pt3: [ 1126.5474 ; 674.8919 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1436.0189 ; 555.0998 ] + - type: SEG_CUBICTO + pt1: [ 1435.5583 ; 573.8059 ] + pt2: [ 1432.5689 ; 611.2406 ] + pt3: [ 1417.0000 ; 638.0000 ] + - type: SEG_CUBICTO + pt1: [ 1408.3927 ; 652.7940 ] + pt2: [ 1394.1355 ; 665.5244 ] + pt3: [ 1381.5681 ; 674.7981 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1448.8860 ; 543.2582 ] + - type: SEG_CUBICTO + pt1: [ 1478.2165 ; 543.4959 ] + pt2: [ 1549.8255 ; 548.7005 ] + pt3: [ 1581.0000 ; 592.0000 ] + - type: SEG_CUBICTO + pt1: [ 1599.3106 ; 617.4323 ] + pt2: [ 1578.4090 ; 654.0281 ] + pt3: [ 1563.1402 ; 674.8629 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 906.0000 ; 40.1001 ] + - type: SEG_CUBICTO + pt1: [ 906.0000 ; 59.7879 ] + pt2: [ 906.0000 ; 92.6243 ] + pt3: [ 906.0000 ; 109.9627 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 918.8689 ; 123.8100 ] + - type: SEG_CUBICTO + pt1: [ 984.8556 ; 125.6932 ] + pt2: [ 1284.3167 ; 137.8868 ] + pt3: [ 1340.0000 ; 205.0000 ] + - type: SEG_CUBICTO + pt1: [ 1351.6354 ; 219.0238 ] + pt2: [ 1348.9399 ; 230.1215 ] + pt3: [ 1340.0000 ; 246.0000 ] + - type: SEG_CUBICTO + pt1: [ 1330.2773 ; 263.2689 ] + pt2: [ 1285.0517 ; 287.8579 ] + pt3: [ 1252.4998 ; 303.8713 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 893.3683 ; 131.4109 ] + - type: SEG_CUBICTO + pt1: [ 872.0927 ; 145.0407 ] + pt2: [ 828.2752 ; 174.4430 ] + pt3: [ 796.0000 ; 205.0000 ] + - type: SEG_CUBICTO + pt1: [ 778.8096 ; 221.2753 ] + pt2: [ 782.4478 ; 234.0717 ] + pt3: [ 762.0000 ; 246.0000 ] + - type: SEG_CUBICTO + pt1: [ 702.6802 ; 280.6044 ] + pt2: [ 506.3854 ; 304.4476 ] + pt3: [ 407.7005 ; 314.5578 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +""" +*/ \ No newline at end of file diff --git a/test/nonreg/simple/ChenMovie_Test.java b/test/nonreg/simple/ChenMovie_Test.java new file mode 100644 index 000000000..98e3dace5 --- /dev/null +++ b/test/nonreg/simple/ChenMovie_Test.java @@ -0,0 +1,56 @@ +package nonreg.simple; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import nonreg.BasicTest; + +/* + +Test diagram MUST be put between triple quotes + +""" +@startchen movies + +entity DIRECTOR { + Number <> + Name { + Fname + Lname + } + Born : DATE + Died + Age +} + +entity CUSTOMER { + Number <> + Bonus <> + Name <> +} + +entity MOVIE { + Code +} + +relationship RENTED_TO { + Date +} + +RENTED_TO -1- CUSTOMER +RENTED_TO -N- MOVIE +RENTED_TO -(N,M)- DIRECTOR + +@endchen +""" + + */ +public class ChenMovie_Test extends BasicTest { + + @Test + void testSimple() throws IOException { + checkImage("(16 entities)"); + } + +} diff --git a/test/nonreg/simple/ChenMovie_TestResult.java b/test/nonreg/simple/ChenMovie_TestResult.java new file mode 100644 index 000000000..73d81f756 --- /dev/null +++ b/test/nonreg/simple/ChenMovie_TestResult.java @@ -0,0 +1,555 @@ +package nonreg.simple; + +public class ChenMovie_TestResult { +} +/* +""" +DPI: 96 +dimension: [ 1357.2949 ; 320.0000 ] +scaleFactor: 1.0000 +seed: 1893551533522493087 +svgLinkTarget: _top +hoverPathColorRGB: null +preserveAspectRatio: none + +RECTANGLE: + pt1: [ 411.5000 ; 281.0000 ] + pt2: [ 526.4536 ; 315.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: DIRECTOR + position: [ 421.5000 ; 301.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 654.5000 ; 209.0000 ] + pt2: [ 773.7119 ; 237.6424 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Number + position: [ 669.6174 ; 225.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 74.0000 ; 210.5000 ] + pt2: [ 174.4750 ; 236.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 90.8355 ; 227.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 138.5000 ; 107.5000 ] + pt2: [ 231.5753 ; 133.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Fname + position: [ 154.2519 ; 124.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 6.0000 ; 106.5000 ] + pt2: [ 120.0711 ; 134.1142 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Lname + position: [ 21.8671 ; 123.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 192.0000 ; 203.0000 ] + pt2: [ 371.7951 ; 243.7590 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Born : DATE + position: [ 202.3602 ; 219.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 390.0000 ; 210.5000 ] + pt2: [ 463.9416 ; 236.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Died + position: [ 402.9498 ; 227.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 482.0000 ; 210.5000 ] + pt2: [ 540.3515 ; 236.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Age + position: [ 492.6667 ; 227.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 917.0000 ; 281.0000 ] + pt2: [ 1049.4781 ; 315.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: CUSTOMER + position: [ 927.0000 ; 301.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1091.5000 ; 209.0000 ] + pt2: [ 1210.7119 ; 237.6424 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Number + position: [ 1106.6174 ; 225.8889 ] + orientation: 0 + font: SansSerif.plain/14 [UNDERLINE] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 791.5000 ; 209.5000 ] + pt2: [ 906.1275 ; 237.2255 ] + start: 0.0 + extend: 0.0 + stroke: 10.0-10.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Bonus + position: [ 807.2808 ; 226.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 973.0000 ; 210.5000 ] + pt2: [ 1073.4750 ; 236.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +ELLIPSE: + pt1: [ 976.0000 ; 213.5000 ] + pt2: [ 1070.4750 ; 233.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Name + position: [ 989.8355 ; 227.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +RECTANGLE: + pt1: [ 1274.0000 ; 281.0000 ] + pt2: [ 1352.2949 ; 315.0000 ] + xCorner: 0 + yCorner: 0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: MOVIE + position: [ 1284.0000 ; 301.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 1228.5000 ; 210.5000 ] + pt2: [ 1317.6043 ; 236.2990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Code + position: [ 1243.6703 ; 227.3889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +POLYGON: + points: + - [ 852.5000 ; 120.3553 ] + - [ 943.2105 ; 75.0000 ] + - [ 1033.9210 ; 120.3553 ] + - [ 943.2105 ; 165.7105 ] + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: RENTED_TO + position: [ 877.6803 ; 124.2441 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +ELLIPSE: + pt1: [ 901.0000 ; 12.0000 ] + pt2: [ 984.5211 ; 37.7990 ] + start: 0.0 + extend: 0.0 + stroke: 0.0-0.0-0.5 + shadow: 0 + color: ff181818 + backcolor: fff1f1f1 + +TEXT: + text: Date + position: [ 915.3527 ; 28.8889 ] + orientation: 0 + font: SansSerif.plain/14 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 665.3328 ; 232.0606 ] + - type: SEG_CUBICTO + pt1: [ 641.4594 ; 239.5693 ] + pt2: [ 611.1286 ; 248.9786 ] + pt3: [ 584.0000 ; 257.0000 ] + - type: SEG_CUBICTO + pt1: [ 563.3889 ; 263.0943 ] + pt2: [ 540.7253 ; 269.5323 ] + pt3: [ 520.6400 ; 275.1474 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 151.7733 ; 230.5368 ] + - type: SEG_CUBICTO + pt1: [ 159.9663 ; 233.2134 ] + pt2: [ 168.7450 ; 235.8814 ] + pt3: [ 177.0000 ; 238.0000 ] + - type: SEG_CUBICTO + pt1: [ 255.1385 ; 258.0537 ] + pt2: [ 347.1264 ; 273.7179 ] + pt3: [ 405.2514 ; 282.6619 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 171.5202 ; 127.8846 ] + - type: SEG_CUBICTO + pt1: [ 159.7490 ; 147.3746 ] + pt2: [ 137.0409 ; 184.9732 ] + pt3: [ 125.3504 ; 204.3296 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 64.9747 ; 128.7040 ] + - type: SEG_CUBICTO + pt1: [ 76.8591 ; 148.3814 ] + pt2: [ 99.0526 ; 185.1281 ] + pt3: [ 110.5964 ; 204.2416 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 326.6049 ; 238.1195 ] + - type: SEG_CUBICTO + pt1: [ 356.3505 ; 249.6519 ] + pt2: [ 393.4909 ; 264.0513 ] + pt3: [ 421.5014 ; 274.9110 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 428.1247 ; 230.7986 ] + - type: SEG_CUBICTO + pt1: [ 435.1459 ; 242.9185 ] + pt2: [ 445.9126 ; 261.5039 ] + pt3: [ 453.6250 ; 274.8170 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 497.8753 ; 230.7986 ] + - type: SEG_CUBICTO + pt1: [ 490.8541 ; 242.9185 ] + pt2: [ 480.0874 ; 261.5039 ] + pt3: [ 472.3750 ; 274.8170 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1113.4005 ; 232.1367 ] + - type: SEG_CUBICTO + pt1: [ 1085.2657 ; 244.2782 ] + pt2: [ 1044.0729 ; 262.0549 ] + pt3: [ 1014.3238 ; 274.8930 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 867.2664 ; 231.6292 ] + - type: SEG_CUBICTO + pt1: [ 889.7416 ; 243.7893 ] + pt2: [ 923.2277 ; 261.9068 ] + pt3: [ 947.2935 ; 274.9275 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1010.2145 ; 230.7986 ] + - type: SEG_CUBICTO + pt1: [ 1003.5277 ; 242.9185 ] + pt2: [ 993.2737 ; 261.5039 ] + pt3: [ 985.9285 ; 274.8170 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1273.7855 ; 230.7986 ] + - type: SEG_CUBICTO + pt1: [ 1280.4723 ; 242.9185 ] + pt2: [ 1290.7263 ; 261.5039 ] + pt3: [ 1298.0715 ; 274.8170 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 937.0000 ; 32.2235 ] + - type: SEG_CUBICTO + pt1: [ 937.0000 ; 41.6286 ] + pt2: [ 937.0000 ; 55.2460 ] + pt3: [ 937.0000 ; 68.6542 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 935.4608 ; 160.0549 ] + - type: SEG_CUBICTO + pt1: [ 935.8346 ; 183.6946 ] + pt2: [ 938.2163 ; 212.9522 ] + pt3: [ 946.0000 ; 238.0000 ] + - type: SEG_CUBICTO + pt1: [ 950.1123 ; 251.2335 ] + pt2: [ 958.0422 ; 264.6940 ] + pt3: [ 964.8519 ; 274.7384 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 952.0000 ; 217.0000 ] + pt2: [ 964.3969 ; 230.0000 ] + +TEXT: + text: 1 + position: [ 953.0000 ; 226.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 1027.7972 ; 121.8769 ] + - type: SEG_CUBICTO + pt1: [ 1129.4735 ; 131.1293 ] + pt2: [ 1284.8054 ; 152.3173 ] + pt3: [ 1321.0000 ; 197.0000 ] + - type: SEG_CUBICTO + pt1: [ 1338.9667 ; 219.1802 ] + pt2: [ 1326.2568 ; 254.3104 ] + pt3: [ 1316.1265 ; 274.7586 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 1336.0000 ; 217.0000 ] + pt2: [ 1348.5088 ; 230.0000 ] + +TEXT: + text: N + position: [ 1337.0000 ; 226.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +PATH: + - type: SEG_MOVETO + pt1: [ 846.3294 ; 120.6490 ] + - type: SEG_CUBICTO + pt1: [ 770.3065 ; 128.4455 ] + pt2: [ 661.2914 ; 148.0025 ] + pt3: [ 579.0000 ; 197.0000 ] + - type: SEG_CUBICTO + pt1: [ 558.1640 ; 209.4060 ] + pt2: [ 561.2682 ; 222.0525 ] + pt3: [ 543.0000 ; 238.0000 ] + - type: SEG_CUBICTO + pt1: [ 527.0605 ; 251.9147 ] + pt2: [ 507.2472 ; 265.0672 ] + pt3: [ 491.3266 ; 274.7892 ] + stroke: 0.0-0.0-1.0 + shadow: 0 + color: ff181818 + backcolor: NULL_COLOR + +EMPTY: + pt1: [ 585.0000 ; 217.0000 ] + pt2: [ 645.5178 ; 230.0000 ] + +TEXT: + text: (N,M) + position: [ 586.0000 ; 226.5556 ] + orientation: 0 + font: SansSerif.plain/11 [] + color: ff000000 + extendedColor: NULL_COLOR + +""" +*/ \ No newline at end of file