Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Chen Notation for ER-diagrams #1718

Merged
merged 25 commits into from Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4e3d8c9
Parse Chen EER diagrams
Benjamin-Davies Aug 26, 2023
07b25de
Add entities, attributes and relations to graph
Benjamin-Davies Aug 26, 2023
d4110d5
Add associations between entities
Benjamin-Davies Aug 26, 2023
c91b5e2
Fix diagram layout not working
Benjamin-Davies Aug 27, 2023
e26ccf7
Tweak Chen EER syntax to be more consistent with existing diagram types
Benjamin-Davies Nov 15, 2023
4d01e6f
Merge entity and relationship commands
Benjamin-Davies Nov 15, 2023
153b96a
Fix stereotype handling
Benjamin-Davies Nov 15, 2023
fb9fd7e
Merge remote-tracking branch 'upstream/master' into cheneer
Benjamin-Davies Nov 15, 2023
6361f82
Add new leaf types
Benjamin-Davies Nov 15, 2023
c6bd537
Draw relationships as diamonds
Benjamin-Davies Nov 15, 2023
de74e7f
Change leaf style based on stereotype
Benjamin-Davies Nov 16, 2023
3734465
Style associations
Benjamin-Davies Nov 16, 2023
9e8a313
Add subset associations
Benjamin-Davies Nov 16, 2023
96785da
Add multiple subclasses command
Benjamin-Davies Nov 16, 2023
9ad8482
Introduce CHEN_CIRCLE entity type
Benjamin-Davies Nov 16, 2023
273f8b4
Add tests
Benjamin-Davies Nov 16, 2023
60de4ba
Merge branch 'master' into cheneer
Benjamin-Davies Mar 16, 2024
8312e8c
Correctly detect cheneer diagrams
Benjamin-Davies Mar 16, 2024
90a88ce
Support long name and alias in Chen-EER
Benjamin-Davies Mar 16, 2024
8325543
Document purpose of shared methods
Benjamin-Davies Mar 20, 2024
cbe84c2
Fix attribute labels
Benjamin-Davies Mar 20, 2024
d39bfbc
Add test for aliases
Benjamin-Davies Mar 20, 2024
234cb3a
Add tests for each new command
Benjamin-Davies Mar 21, 2024
e14c8ef
Re-add chronology diagram
Benjamin-Davies Mar 21, 2024
4b5bcd3
Fix compatibility with Java 8
Benjamin-Davies Mar 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/net/sourceforge/plantuml/PSystemBuilder.java
Expand Up @@ -48,6 +48,7 @@
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;
Expand Down Expand Up @@ -277,6 +278,8 @@ final public Diagram createPSystem(List<StringLocated> source, List<StringLocate
factories.add(new HclDiagramFactory());
factories.add(new PSystemEbnfFactory());
factories.add(new PSystemRegexFactory());

factories.add(new ChenEerDiagramFactory());
}

private boolean isOk(Diagram ps) {
Expand Down
2 changes: 2 additions & 0 deletions src/net/sourceforge/plantuml/abel/LeafType.java
Expand Up @@ -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) {
Expand Down
95 changes: 95 additions & 0 deletions 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<String, String> skinParam) {
super(source, UmlDiagramType.CHEN_EER, skinParam);
}

private final Stack<Entity> ownerStack = new Stack<Entity>();

/**
* 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.
*
* <p>
* 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();
}

}
78 changes: 78 additions & 0 deletions 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<Command> 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<String, String> skinParam) {
return new ChenEerDiagram(source, skinParam);
}

}
108 changes: 108 additions & 0 deletions 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<ChenEerDiagram> {

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<Entity> quark1 = diagram.quarkInContext(true, name1);
final Entity entity1 = quark1.getData();
if (entity1 == null) {
return CommandExecutionResult.error("No such entity: " + name1);
}

final Quark<Entity> 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();
}

}