1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-22 13:05:09 +00:00

EBNF improvements

This commit is contained in:
Arnaud Roques 2022-09-27 18:12:38 +02:00
parent ee3037db80
commit ecf66ff391
18 changed files with 930 additions and 185 deletions

View File

@ -39,21 +39,61 @@ import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UPath;
enum CornerType {
NW, NE, SE, SW;
}
public class CornerCurved implements UDrawable {
private final double delta;
private final CornerType type;
public CornerCurved(double delta) {
private CornerCurved(CornerType type, double delta) {
this.delta = delta;
this.type = type;
if (delta <= 0)
throw new IllegalArgumentException();
}
public static UDrawable createSW(double delta) {
return new CornerCurved(CornerType.SW, delta);
}
public static UDrawable createSE(double delta) {
return new CornerCurved(CornerType.SE, delta);
}
public static UDrawable createNE(double delta) {
return new CornerCurved(CornerType.NE, delta);
}
public static UDrawable createNW(double delta) {
return new CornerCurved(CornerType.NW, delta);
}
@Override
public void drawU(UGraphic ug) {
final UPath path = new UPath();
path.moveTo(0, -Math.abs(delta));
final double a = delta / 4;
path.cubicTo(0, -Math.abs(a), a, 0, delta, 0);
switch (type) {
case SW:
path.moveTo(0, -delta);
path.cubicTo(0, -a, a, 0, delta, 0);
break;
case SE:
path.moveTo(0, -delta);
path.cubicTo(0, -a, -a, 0, -delta, 0);
break;
case NE:
path.moveTo(-delta, 0);
path.cubicTo(-a, 0, 0, a, 0, delta);
break;
case NW:
path.moveTo(0, delta);
path.cubicTo(0, a, a, 0, delta, 0);
break;
}
ug.draw(path);
}

View File

@ -42,4 +42,6 @@ public interface ETile extends TextBlock {
public double linePos(StringBounder stringBounder);
public void push(ETile tile);
}

View File

@ -38,115 +38,89 @@ package net.sourceforge.plantuml.ebnf;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleBuilder;
import net.sourceforge.plantuml.style.StyleSignatureBasic;
import net.sourceforge.plantuml.svek.TextBlockBackcolored;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
import net.sourceforge.plantuml.ugraphic.color.HColors;
public class Alternation extends AbstractTextBlock implements TextBlockBackcolored, ETile {
public class ETileAlternation extends AbstractTextBlock implements ETile {
private final List<String> values = new ArrayList<>();
private final StyleBuilder styleBuilder;
private final HColorSet colorSet;
private final List<ETile> tiles = new ArrayList<>();
private final double marginx = 12;
public Alternation(ISkinParam skinParam) {
this.styleBuilder = skinParam.getCurrentStyleBuilder();
this.colorSet = skinParam.getIHtmlColorSet();
}
public void alternation(Token token) {
values.add(0, token.getData());
@Override
public void push(ETile tile) {
tiles.add(0, tile);
}
@Override
public double linePos(StringBounder stringBounder) {
final Style style = getStyleSignature().getMergedStyle(styleBuilder);
final FontConfiguration fc = style.getFontConfiguration(colorSet);
final ETile tile = new ETileBox(values.get(0), fc);
return tile.linePos(stringBounder);
return tiles.get(0).linePos(stringBounder);
}
@Override
public void drawU(UGraphic ug) {
final StringBounder stringBounder = ug.getStringBounder();
ug = ug.apply(HColors.BLACK);
final Style style = getStyleSignature().getMergedStyle(styleBuilder);
final FontConfiguration fc = style.getFontConfiguration(colorSet);
double y = 0;
double lastLinePos = 0;
final double b = 30 - 16;
final double a = b - 8;
final double c = b + 8;
final double a = 0;
final double b = a + marginx;
final double c = b + marginx;
final XDimension2D fullDim = calculateDimension(stringBounder);
final double q = fullDim.getWidth() - 14;
final double p = q - 8;
final double r = q + 8;
final double r = fullDim.getWidth();
final double q = r - marginx;
final double p = q - marginx;
for (int i = 0; i < values.size(); i++) {
final String value = values.get(i);
final ETile tile = new ETileBox(value, fc);
for (int i = 0; i < tiles.size(); i++) {
final ETile tile = tiles.get(i);
final XDimension2D dim = tile.calculateDimension(stringBounder);
lastLinePos = y + tile.linePos(stringBounder);
tile.drawU(ug.apply(new UTranslate(30, y)));
tile.drawU(ug.apply(new UTranslate(c, y)));
if (i == 0) {
drawHline(ug, lastLinePos, 0, 30);
drawHline(ug, lastLinePos, 30 + dim.getWidth(), fullDim.getWidth());
} else if (i > 0 && i < values.size() - 1) {
drawHline(ug, lastLinePos, c, 30);
new CornerCurved(8).drawU(ug.apply(new UTranslate(b, lastLinePos)));
drawHline(ug, lastLinePos, 30 + dim.getWidth(), p);
new CornerCurved(-8).drawU(ug.apply(new UTranslate(q, lastLinePos)));
} else if (i == values.size() - 1) {
drawHline(ug, lastLinePos, c, 30);
drawHline(ug, lastLinePos, 30 + dim.getWidth(), p);
ETileConcatenation.drawHline(ug, lastLinePos, a, c);
ETileConcatenation.drawHline(ug, lastLinePos, c + dim.getWidth(), r);
} else if (i > 0 && i < tiles.size() - 1) {
CornerCurved.createSW(marginx).drawU(ug.apply(new UTranslate(b, lastLinePos)));
ETileConcatenation.drawHline(ug, lastLinePos, c + dim.getWidth(), p);
CornerCurved.createSE(marginx).drawU(ug.apply(new UTranslate(q, lastLinePos)));
} else if (i == tiles.size() - 1) {
ETileConcatenation.drawHline(ug, lastLinePos, c + dim.getWidth(), p);
}
y += dim.getHeight() + 10;
}
final double linePos = linePos(stringBounder);
final HLineCurved hlineIn = new HLineCurved(lastLinePos - linePos, 8);
final VLineCurved hlineIn = new VLineCurved(lastLinePos - linePos, marginx, CornerCurved.createNE(marginx),
CornerCurved.createSW(marginx));
hlineIn.drawU(ug.apply(new UTranslate(b, linePos)));
final HLineCurved hlineOut = new HLineCurved(lastLinePos - linePos, -8);
final VLineCurved hlineOut = new VLineCurved(lastLinePos - linePos, marginx, CornerCurved.createNW(marginx),
CornerCurved.createSE(marginx));
hlineOut.drawU(ug.apply(new UTranslate(q, linePos)));
}
private void drawHline(UGraphic ug, double y, double x1, double x2) {
ug.apply(new UTranslate(x1, y)).draw(ULine.hline(x2 - x1));
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
final Style style = getStyleSignature().getMergedStyle(styleBuilder);
final FontConfiguration fc = style.getFontConfiguration(colorSet);
double width = 0;
double height = 0;
for (String value : values) {
final ETile tile = new ETileBox(value, fc);
for (ETile tile : tiles) {
final XDimension2D dim = tile.calculateDimension(stringBounder);
height += dim.getHeight() + 10;
height += dim.getHeight();
height += 10;
width = Math.max(width, dim.getWidth());
}
width += 60;
width += 2 * 2 * marginx;
return new XDimension2D(width, height);
}
@ -154,9 +128,4 @@ public class Alternation extends AbstractTextBlock implements TextBlockBackcolor
return StyleSignatureBasic.of(SName.root, SName.element, SName.activityDiagram, SName.activity);
}
@Override
public HColor getBackcolor() {
return null;
}
}

View File

@ -39,23 +39,32 @@ import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UText;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
public class ETileBox extends AbstractTextBlock implements ETile {
private final String value;
private final FontConfiguration fc;
private final Style style;
private final UText utext;
private final HColorSet colorSet;
private final Symbol symbol;
public ETileBox(String value, FontConfiguration fc) {
public ETileBox(String value, Symbol symbol, FontConfiguration fc, Style style, HColorSet colorSet) {
this.symbol = symbol;
this.value = value;
this.fc = fc;
this.utext = new UText(value, fc);
this.style = style;
this.colorSet = colorSet;
}
@Override
@ -71,8 +80,17 @@ public class ETileBox extends AbstractTextBlock implements ETile {
public void drawU(UGraphic ug) {
final XDimension2D dim = calculateDimension(ug.getStringBounder());
final XDimension2D dimText = getTextDim(ug.getStringBounder());
final HColor lineColor = style.value(PName.LineColor).asColor(colorSet);
final HColor backgroundColor = style.value(PName.BackGroundColor).asColor(colorSet);
if (symbol == Symbol.TERMINAL_STRING1 || symbol == Symbol.TERMINAL_STRING2) {
final URectangle rect = new URectangle(dim);
ug.apply(lineColor).apply(new UStroke(0.5)).draw(rect);
} else {
final URectangle rect = new URectangle(dim).rounded(10);
ug.apply(HColors.BLACK).apply(new UStroke(1.5)).draw(rect);
ug.apply(lineColor).apply(backgroundColor.bg()).apply(new UStroke(1.5)).draw(rect);
}
ug.apply(new UTranslate(5, 5 + dimText.getHeight() - utext.getDescent(ug.getStringBounder()))).draw(utext);
}
@ -82,4 +100,9 @@ public class ETileBox extends AbstractTextBlock implements ETile {
return height / 2;
}
@Override
public void push(ETile tile) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,114 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
public class ETileConcatenation extends AbstractTextBlock implements ETile {
private final double marginx = 16;
private final List<ETile> tiles = new ArrayList<>();
@Override
public void push(ETile tile) {
tiles.add(0, tile);
}
@Override
public double linePos(StringBounder stringBounder) {
double result = 0;
for (ETile tile : tiles)
result = Math.max(result, tile.linePos(stringBounder));
return result;
}
@Override
public void drawU(UGraphic ug) {
final StringBounder stringBounder = ug.getStringBounder();
ug = ug.apply(HColors.BLACK);
final double fullLinePos = linePos(stringBounder);
double x = 0;
drawHline(ug, fullLinePos, 0, x);
for (int i = 0; i < tiles.size(); i++) {
final ETile tile = tiles.get(i);
final double linePos = tile.linePos(stringBounder);
tile.drawU(ug.apply(new UTranslate(x, fullLinePos - linePos)));
x += tile.calculateDimension(stringBounder).getWidth();
if (i != tiles.size() - 1) {
drawHline(ug, fullLinePos, x, x + marginx);
x += marginx;
}
}
}
public static void drawHline(UGraphic ug, double y, double x1, double x2) {
ug.apply(new UTranslate(x1, y)).draw(ULine.hline(x2 - x1));
}
public static void drawVline(UGraphic ug, double x, double y1, double y2) {
ug.apply(new UTranslate(x, y1)).draw(ULine.vline(y2 - y1));
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
double width = 0;
double height = 0;
for (int i = 0; i < tiles.size(); i++) {
final ETile tile = tiles.get(i);
final XDimension2D dim = tile.calculateDimension(stringBounder);
height = Math.max(height, dim.getHeight());
width += dim.getWidth();
if (i != tiles.size() - 1)
width += marginx;
}
return new XDimension2D(width, height);
}
}

View File

@ -0,0 +1,92 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
public class ETileOptional extends AbstractTextBlock implements ETile {
private final double posLineTop = 21;
private final double deltax = 15;
private final double deltay = 24;
private final ETile orig;
public ETileOptional(ETile orig) {
this.orig = orig;
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
return XDimension2D.delta(orig.calculateDimension(stringBounder), 2 * deltax, deltay);
}
@Override
public void drawU(UGraphic ug) {
final XDimension2D fullDim = calculateDimension(ug.getStringBounder());
ug = ug.apply(HColors.BLACK);
final double linePos = linePos(ug.getStringBounder());
CornerCurved.createSE(8).drawU(ug.apply(new UTranslate(8, linePos)));
ETileConcatenation.drawVline(ug, 8, linePos - posLineTop + 8, linePos - 8);
CornerCurved.createNW(8).drawU(ug.apply(new UTranslate(8, linePos - posLineTop)));
ETileConcatenation.drawHline(ug, linePos - posLineTop, deltax, fullDim.getWidth() - deltax);
CornerCurved.createSW(8).drawU(ug.apply(new UTranslate(fullDim.getWidth() - 8, linePos)));
ETileConcatenation.drawVline(ug, fullDim.getWidth() - 8, linePos - posLineTop + 8, linePos - 8);
CornerCurved.createNE(8).drawU(ug.apply(new UTranslate(fullDim.getWidth() - 8, linePos - posLineTop)));
ETileConcatenation.drawHline(ug, linePos, 0, deltax);
ETileConcatenation.drawHline(ug, linePos, fullDim.getWidth() - deltax, fullDim.getWidth());
orig.drawU(ug.apply(new UTranslate(deltax, deltay)));
}
@Override
public double linePos(StringBounder stringBounder) {
return deltay + orig.linePos(stringBounder);
}
@Override
public void push(ETile tile) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,97 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
public class ETileRepetition extends AbstractTextBlock implements ETile {
private final double deltax = 20;
private final double deltay = 10;
private final ETile orig;
public ETileRepetition(ETile orig) {
this.orig = orig;
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
return XDimension2D.delta(orig.calculateDimension(stringBounder), 2 * deltax, deltay);
}
@Override
public void drawU(UGraphic ug) {
final XDimension2D fullDim = calculateDimension(ug.getStringBounder());
ug = ug.apply(HColors.BLACK);
final double linePos = linePos(ug.getStringBounder());
final double posA = 7;
final double posB = fullDim.getWidth() - 7;
final double corner = 12;
CornerCurved.createNW(corner).drawU(ug.apply(new UTranslate(posA, linePos)));
ETileConcatenation.drawVline(ug, posA, linePos + corner, fullDim.getHeight() - 1 - corner);
CornerCurved.createSW(corner).drawU(ug.apply(new UTranslate(posA, fullDim.getHeight() - 1)));
CornerCurved.createNE(corner).drawU(ug.apply(new UTranslate(posB, linePos)));
ETileConcatenation.drawVline(ug, posB, linePos + corner, fullDim.getHeight() - 1 - corner);
CornerCurved.createSE(corner).drawU(ug.apply(new UTranslate(posB, fullDim.getHeight() - 1)));
ETileConcatenation.drawHline(ug, fullDim.getHeight() - 1, posA + corner, posB - corner);
ETileConcatenation.drawHline(ug, linePos, 0, deltax);
ETileConcatenation.drawHline(ug, linePos, fullDim.getWidth() - deltax, fullDim.getWidth());
orig.drawU(ug.apply(new UTranslate(deltax, 0)));
}
@Override
public double linePos(StringBounder stringBounder) {
return orig.linePos(stringBounder);
}
@Override
public void push(ETile tile) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,85 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UEllipse;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
public class ETileWithCircles extends AbstractTextBlock implements ETile {
private static final double SIZE = 8;
private final double deltax = 15;
private final ETile orig;
public ETileWithCircles(ETile orig) {
this.orig = orig;
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
return XDimension2D.delta(orig.calculateDimension(stringBounder), 2 * deltax, 0);
}
@Override
public void drawU(UGraphic ug) {
final double linePos = linePos(ug.getStringBounder());
final XDimension2D fullDim = calculateDimension(ug.getStringBounder());
orig.drawU(ug.apply(UTranslate.dx(deltax)));
ug = ug.apply(HColors.BLACK).apply(HColors.BLACK.bg());
final UEllipse circle = new UEllipse(SIZE, SIZE);
ug.apply(new UTranslate(0, linePos - SIZE / 2)).draw(circle);
ug.apply(new UTranslate(fullDim.getWidth() - SIZE / 2, linePos - SIZE / 2)).draw(circle);
ETileConcatenation.drawHline(ug, linePos, SIZE / 2, deltax);
ETileConcatenation.drawHline(ug, linePos, fullDim.getWidth() - deltax, fullDim.getWidth() - SIZE / 2);
}
@Override
public double linePos(StringBounder stringBounder) {
return orig.linePos(stringBounder);
}
@Override
public void push(ETile tile) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,122 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import java.util.ArrayDeque;
import java.util.Deque;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignatureBasic;
import net.sourceforge.plantuml.ugraphic.color.HColorSet;
public class EbnfEngine {
private final Deque<ETile> stack = new ArrayDeque<>();
private final FontConfiguration fontConfiguration;
private final Style style;
private final HColorSet colorSet;
public EbnfEngine(ISkinParam skinParam) {
this.style = getStyleSignature().getMergedStyle(skinParam.getCurrentStyleBuilder());
this.fontConfiguration = style.getFontConfiguration(skinParam.getIHtmlColorSet());
this.colorSet = skinParam.getIHtmlColorSet();
}
public void push(Token element) {
stack.addFirst(new ETileBox(element.getData(), element.getSymbol(), fontConfiguration, style, colorSet));
}
public void optional() {
final ETile arg1 = stack.removeFirst();
stack.addFirst(new ETileOptional(arg1));
}
public void repetition() {
final ETile arg1 = stack.removeFirst();
stack.addFirst(new ETileRepetition(arg1));
}
public void alternation() {
final ETile arg1 = stack.removeFirst();
final ETile arg2 = stack.removeFirst();
if (arg1 instanceof ETileAlternation) {
arg1.push(arg2);
stack.addFirst(arg1);
} else if (arg2 instanceof ETileAlternation) {
arg2.push(arg1);
stack.addFirst(arg2);
} else {
final ETile concat = new ETileAlternation();
concat.push(arg1);
concat.push(arg2);
stack.addFirst(concat);
}
}
public void concatenation() {
final ETile arg1 = stack.removeFirst();
final ETile arg2 = stack.removeFirst();
if (arg1 instanceof ETileConcatenation) {
arg1.push(arg2);
stack.addFirst(arg1);
} else if (arg2 instanceof ETileConcatenation) {
arg2.push(arg1);
stack.addFirst(arg2);
} else {
final ETile concat = new ETileConcatenation();
concat.push(arg1);
concat.push(arg2);
stack.addFirst(concat);
}
}
public TextBlock getTextBlock() {
if (stack.size() != 1)
throw new IllegalStateException();
return new ETileWithCircles(stack.peekFirst());
}
private StyleSignatureBasic getStyleSignature() {
return StyleSignatureBasic.of(SName.root, SName.element, SName.activityDiagram, SName.activity);
}
}

View File

@ -0,0 +1,54 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class EbnfExpressions {
public static List<EbnfSingleExpression> build(List<String> data) {
final List<EbnfSingleExpression> all = new ArrayList<>();
final CharIterator it = new CharIteratorImpl(data);
while (it.peek() != 0)
all.add(new EbnfSingleExpression(it));
return Collections.unmodifiableList(all);
}
}

View File

@ -35,114 +35,105 @@
*/
package net.sourceforge.plantuml.ebnf;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignatureBasic;
interface CharIterator {
char peek();
void next();
}
class CharIteratorImpl implements CharIterator {
final private List<String> data;
private int line = 0;
private int pos = 0;
public CharIteratorImpl(List<String> data) {
this.data = data;
}
public char peek() {
if (line == -1)
return 0;
return data.get(line).charAt(pos);
}
public void next() {
if (line == -1)
throw new IllegalStateException();
pos++;
if (pos >= data.get(line).length()) {
line++;
pos = 0;
}
if (line >= data.size())
line = -1;
}
}
public class EbnfExpression {
public class EbnfSingleExpression {
final List<Token> tokens = new ArrayList<>();
public EbnfExpression(String... data) {
this(Arrays.asList(data));
}
public EbnfExpression(List<String> data) {
final CharIterator it = new CharIteratorImpl(data);
analyze(it);
}
public UDrawable getUDrawable(ISkinParam skinParam) {
final Iterator<Token> iterator = tokens.iterator();
final Token name = iterator.next();
final Token definition = iterator.next();
final ShuntingYard shuntingYard = new ShuntingYard(iterator);
return build(shuntingYard.getOuputQueue(), skinParam);
}
private Alternation build(Iterator<Token> it, ISkinParam skinParam) {
final Deque<Token> stack = new ArrayDeque<>();
final Alternation ebnf = new Alternation(skinParam);
while (it.hasNext()) {
final Token element = it.next();
if (element.getSymbol() == Symbol.TERMINAL_STRING1 || element.getSymbol() == Symbol.LITTERAL) {
stack.addFirst(element);
} else if (element.getSymbol() == Symbol.ALTERNATION) {
ebnf.alternation(stack.removeFirst());
} else {
throw new UnsupportedOperationException(element.toString());
}
}
ebnf.alternation(stack.removeFirst());
return ebnf;
}
private void analyze(CharIterator it) {
EbnfSingleExpression(CharIterator it) {
while (true) {
final char ch = it.peek();
if (Character.isWhitespace(ch)) {
} else if (isLetterOrDigit(ch)) {
final String litteral = readLitteral(it);
tokens.add(new Token(Symbol.LITTERAL, litteral));
} else if (ch == ',') {
tokens.add(new Token(Symbol.CONCATENATION, null));
} else if (ch == '|') {
tokens.add(new Token(Symbol.ALTERNATION, null));
} else if (ch == '=') {
tokens.add(new Token(Symbol.DEFINITION, null));
} else if (ch == '(') {
tokens.add(new Token(Symbol.GROUPING_OPEN, null));
} else if (ch == ')') {
tokens.add(new Token(Symbol.GROUPING_CLOSE, null));
} else if (ch == '[') {
tokens.add(new Token(Symbol.OPTIONAL_OPEN, null));
} else if (ch == ']') {
tokens.add(new Token(Symbol.OPTIONAL_CLOSE, null));
} else if (ch == '{') {
tokens.add(new Token(Symbol.REPETITION_OPEN, null));
} else if (ch == '}') {
tokens.add(new Token(Symbol.REPETITION_CLOSE, null));
} else if (ch == ';' || ch == 0) {
it.next();
break;
} else if (ch == '\"') {
final String litteral = readString(it);
tokens.add(new Token(Symbol.TERMINAL_STRING1, litteral));
} else if (ch == '\'') {
final String litteral = readString(it);
tokens.add(new Token(Symbol.TERMINAL_STRING2, litteral));
} else
throw new UnsupportedOperationException("" + ch);
it.next();
continue;
}
}
private StyleSignatureBasic getStyleSignature() {
return StyleSignatureBasic.of(SName.root, SName.element, SName.activityDiagram, SName.activity);
}
public TextBlock getUDrawable(ISkinParam skinParam) {
final Iterator<Token> iterator = tokens.iterator();
final Token name = iterator.next();
final Token definition = iterator.next();
final List<Token> full = new ShuntingYard(iterator).getOuputQueue();
final TextBlock main = getMainDrawing(skinParam, full.iterator());
final Style style = getStyleSignature().getMergedStyle(skinParam.getCurrentStyleBuilder());
final FontConfiguration fc = style.getFontConfiguration(skinParam.getIHtmlColorSet());
final TitleBox titleBox = new TitleBox(name.getData() + ":", fc);
return TextBlockUtils.mergeTB(titleBox, TextBlockUtils.withMargin(main, 0, 0, 10, 15),
HorizontalAlignment.LEFT);
}
private TextBlock getMainDrawing(ISkinParam skinParam, Iterator<Token> it) {
final EbnfEngine engine = new EbnfEngine(skinParam);
while (it.hasNext()) {
final Token element = it.next();
if (element.getSymbol() == Symbol.TERMINAL_STRING1 || element.getSymbol() == Symbol.TERMINAL_STRING2
|| element.getSymbol() == Symbol.LITTERAL)
engine.push(element);
else if (element.getSymbol() == Symbol.ALTERNATION)
engine.alternation();
else if (element.getSymbol() == Symbol.CONCATENATION)
engine.concatenation();
else if (element.getSymbol() == Symbol.OPTIONAL_CLOSE)
engine.optional();
else if (element.getSymbol() == Symbol.REPETITION_CLOSE)
engine.repetition();
else
throw new UnsupportedOperationException(element.toString());
}
return engine.getTextBlock();
}
private String readString(CharIterator it) {
@ -174,3 +165,40 @@ public class EbnfExpression {
}
}
interface CharIterator {
char peek();
void next();
}
class CharIteratorImpl implements CharIterator {
final private List<String> data;
private int line = 0;
private int pos = 0;
public CharIteratorImpl(List<String> data) {
this.data = data;
}
public char peek() {
if (line == -1)
return 0;
return data.get(line).charAt(pos);
}
public void next() {
if (line == -1)
throw new IllegalStateException();
pos++;
if (pos >= data.get(line).length()) {
line++;
pos = 0;
}
while (line < data.size() && data.get(line).length() == 0)
line++;
if (line >= data.size())
line = -1;
}
}

View File

@ -46,7 +46,10 @@ import net.sourceforge.plantuml.UmlDiagramType;
import net.sourceforge.plantuml.core.DiagramDescription;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.core.UmlSource;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.svek.TextBlockBackcolored;
public class PSystemEbnf extends TitledDiagram {
@ -70,8 +73,11 @@ public class PSystemEbnf extends TitledDiagram {
return createImageBuilder(fileFormatOption).drawable(getTextBlock()).write(os);
}
private UDrawable getTextBlock() {
final EbnfExpression exp = new EbnfExpression(lines);
return exp.getUDrawable(getSkinParam());
private TextBlockBackcolored getTextBlock() {
final List<EbnfSingleExpression> all = EbnfExpressions.build(lines);
TextBlock result = all.get(0).getUDrawable(getSkinParam());
for (int i = 1; i < all.size(); i++)
result = TextBlockUtils.mergeTB(result, all.get(i).getUDrawable(getSkinParam()), HorizontalAlignment.LEFT);
return TextBlockUtils.addBackcolor(result, null);
}
}

View File

@ -37,6 +37,7 @@ package net.sourceforge.plantuml.ebnf;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
@ -49,9 +50,35 @@ public class ShuntingYard {
public ShuntingYard(Iterator<Token> it) {
while (it.hasNext()) {
final Token token = it.next();
if (token.getSymbol() == Symbol.LITTERAL || token.getSymbol() == Symbol.TERMINAL_STRING1) {
if (token.getSymbol() == Symbol.LITTERAL || token.getSymbol() == Symbol.TERMINAL_STRING1
|| token.getSymbol() == Symbol.TERMINAL_STRING2) {
ouputQueue.add(token);
} else if (token.getSymbol() == Symbol.ALTERNATION) {
} else if (token.getSymbol().isOperator()) {
while (thereIsAnOperatorAtTheTopOfTheOperatorStackWithGreaterPrecedence(token))
ouputQueue.add(operatorStack.removeFirst());
operatorStack.addFirst(token);
} else if (token.getSymbol() == Symbol.GROUPING_OPEN) {
operatorStack.addFirst(token);
} else if (token.getSymbol() == Symbol.GROUPING_CLOSE) {
while (operatorStack.peekFirst().getSymbol() != Symbol.GROUPING_OPEN)
ouputQueue.add(operatorStack.removeFirst());
if (operatorStack.peekFirst().getSymbol() == Symbol.GROUPING_OPEN)
operatorStack.removeFirst();
} else if (token.getSymbol() == Symbol.OPTIONAL_OPEN) {
operatorStack.addFirst(token);
} else if (token.getSymbol() == Symbol.OPTIONAL_CLOSE) {
while (operatorStack.peekFirst().getSymbol() != Symbol.OPTIONAL_OPEN)
ouputQueue.add(operatorStack.removeFirst());
if (operatorStack.peekFirst().getSymbol() == Symbol.OPTIONAL_OPEN)
operatorStack.removeFirst();
operatorStack.addFirst(token);
} else if (token.getSymbol() == Symbol.REPETITION_OPEN) {
operatorStack.addFirst(token);
} else if (token.getSymbol() == Symbol.REPETITION_CLOSE) {
while (operatorStack.peekFirst().getSymbol() != Symbol.REPETITION_OPEN)
ouputQueue.add(operatorStack.removeFirst());
if (operatorStack.peekFirst().getSymbol() == Symbol.REPETITION_OPEN)
operatorStack.removeFirst();
operatorStack.addFirst(token);
} else {
throw new UnsupportedOperationException(token.toString());
@ -64,8 +91,16 @@ public class ShuntingYard {
}
}
public final Iterator<Token> getOuputQueue() {
return ouputQueue.iterator();
private boolean thereIsAnOperatorAtTheTopOfTheOperatorStackWithGreaterPrecedence(Token token) {
final Token top = operatorStack.peekFirst();
if (top != null && top.getSymbol().isOperator()
&& top.getSymbol().getPriority() > token.getSymbol().getPriority())
return true;
return false;
}
public final List<Token> getOuputQueue() {
return Collections.unmodifiableList(ouputQueue);
}
}

View File

@ -44,13 +44,30 @@ public enum Symbol {
CONCATENATION, // ,
TERMINATION, // ;
ALTERNATION, // |
OPTIONAL, // [ ]
REPETITION, // { }
GROUPING, // ( )
OPTIONAL_OPEN, // [
OPTIONAL_CLOSE, // ]
REPETITION_OPEN, // {
REPETITION_CLOSE, // }
GROUPING_OPEN, // (
GROUPING_CLOSE, // )
TERMINAL_STRING1, // " "
TERMINAL_STRING2, // ' '
COMMENT, // (* *)
SPECIAL_SEQUENCE, // ? ?
EXCEPTION; // -
public int getPriority() {
switch (this) {
case CONCATENATION:
return 2;
case ALTERNATION:
return 1;
}
throw new UnsupportedOperationException();
}
boolean isOperator() {
return this == CONCATENATION || this == ALTERNATION;
}
}

View File

@ -0,0 +1,71 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2020, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.ebnf;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.FontStyle;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UText;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class TitleBox extends AbstractTextBlock {
private final String value;
private final FontConfiguration fc;
private final UText utext;
public TitleBox(String value, FontConfiguration fc) {
this.value = value;
this.fc = fc.add(FontStyle.BOLD);
this.utext = new UText(value, this.fc);
}
@Override
public XDimension2D calculateDimension(StringBounder stringBounder) {
return stringBounder.calculateDimension(fc.getFont(), value);
}
@Override
public void drawU(UGraphic ug) {
final XDimension2D dimText = calculateDimension(ug.getStringBounder());
ug.apply(new UTranslate(0, dimText.getHeight() - utext.getDescent(ug.getStringBounder()))).draw(utext);
}
}

View File

@ -37,38 +37,27 @@ package net.sourceforge.plantuml.ebnf;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UPath;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class HLineCurved implements UDrawable {
public class VLineCurved implements UDrawable {
private final double height;
private final double delta;
private final UDrawable top;
private final UDrawable bottom;
public HLineCurved(double height, double delta) {
public VLineCurved(double height, double delta, UDrawable top, UDrawable bottom) {
this.height = height;
this.delta = delta;
this.bottom = bottom;
this.top = top;
}
@Override
public void drawU(UGraphic ug) {
if (delta == 0) {
ug.draw(ULine.vline(height));
return;
}
final UPath path = new UPath();
path.moveTo(-delta, 0);
final double a = delta / 4;
path.cubicTo(-a, 0, 0, Math.abs(a), 0, Math.abs(delta));
// path.lineTo(0, delta);
path.lineTo(0, height - Math.abs(delta));
path.cubicTo(0, height - a, a, height, delta, height);
// path.lineTo(delta, height);
ug.draw(path);
bottom.drawU(ug.apply(UTranslate.dy(height)));
ETileConcatenation.drawVline(ug, 0, delta, height - delta);
top.drawU(ug);
}
}

View File

@ -450,7 +450,8 @@ public class ImageBuilder {
if (this.backcolor instanceof HColorSimple)
pngBackColor = this.backcolor.toColor(fileFormatOption.getColorMapper());
if (OptionFlags.getInstance().isReplaceWhiteBackgroundByTransparent() && Color.WHITE.equals(pngBackColor))
if (OptionFlags.getInstance().isReplaceWhiteBackgroundByTransparent()
&& (Color.WHITE.equals(pngBackColor) || Color.BLACK.equals(pngBackColor)))
pngBackColor = new Color(0, 0, 0, 0);
final EmptyImageBuilder builder = new EmptyImageBuilder(watermark, (int) (dim.getWidth() * scaleFactor),

View File

@ -45,7 +45,7 @@ public class Version {
private static final int MAJOR_SEPARATOR = 1000000;
public static int version() {
return 1202208;
return 1202209;
}
public static int versionPatched() {
@ -94,7 +94,7 @@ public class Version {
}
public static long compileTime() {
return 1664096433281L;
return 1664295006047L;
}
public static String compileTimeString() {