This commit is contained in:
Arnaud Roques 2022-12-04 19:59:49 +01:00
parent 0d7f2eea2c
commit 3cf5e15bb4
24 changed files with 447 additions and 129 deletions

View File

@ -65,13 +65,8 @@ public class PSystemUtils {
FileFormatOption fileFormatOption, boolean checkMetadata) throws IOException {
final SFile existingFile = suggestedFile.getFile(0);
if (checkMetadata && fileFormatOption.getFileFormat().doesSupportMetadata() && existingFile.exists()
&& system.getNbImages() == 1) {
// final String version = Version.versionString();
// System.out.println(system.getMetadata());
// System.out.println(data);
// System.out.println(version);
// System.out.println(data.contains(version));
if (checkMetadata && fileFormatOption.getFileFormat().doesSupportMetadata() && existingFile.exists()) {
// && system.getNbImages() == 1) {
final boolean sameMetadata = fileFormatOption.getFileFormat().equalsMetadata(system.getMetadata(),
existingFile);
if (sameMetadata) {
@ -80,15 +75,14 @@ public class PSystemUtils {
}
}
if (system instanceof NewpagedDiagram) {
if (system instanceof NewpagedDiagram)
return exportDiagramsNewpaged((NewpagedDiagram) system, suggestedFile, fileFormatOption);
}
if (system instanceof SequenceDiagram) {
if (system instanceof SequenceDiagram)
return exportDiagramsSequence((SequenceDiagram) system, suggestedFile, fileFormatOption);
}
if (system instanceof CucaDiagram && fileFormatOption.getFileFormat() == FileFormat.HTML) {
if (system instanceof CucaDiagram && fileFormatOption.getFileFormat() == FileFormat.HTML)
return createFilesHtml((CucaDiagram) system, suggestedFile);
}
return exportDiagramsDefault(system, suggestedFile, fileFormatOption);
}
@ -100,9 +94,9 @@ public class PSystemUtils {
for (int i = 0; i < nbImages; i++) {
final SFile f = suggestedFile.getFile(i);
if (canFileBeWritten(f) == false) {
if (canFileBeWritten(f) == false)
return result;
}
final OutputStream fos = f.createBufferedOutputStream();
ImageData cmap = null;
try {
@ -141,9 +135,9 @@ public class PSystemUtils {
for (int i = 0; i < nbImages; i++) {
final SFile f = suggestedFile.getFile(i);
if (PSystemUtils.canFileBeWritten(suggestedFile.getFile(i)) == false) {
if (PSystemUtils.canFileBeWritten(suggestedFile.getFile(i)) == false)
return result;
}
final OutputStream fos = f.createBufferedOutputStream();
ImageData cmap = null;
try {
@ -151,9 +145,9 @@ public class PSystemUtils {
} finally {
fos.close();
}
if (cmap != null && cmap.containsCMapData()) {
if (cmap != null && cmap.containsCMapData())
system.exportCmap(suggestedFile, i, cmap);
}
Log.info("File size : " + f.length());
result.add(new FileImageData(f, cmap));
}
@ -179,9 +173,9 @@ public class PSystemUtils {
: diagram.getSkinParam().getSplitParam()).getFiles();
final List<FileImageData> result = new ArrayList<>();
for (SFile f : files) {
for (SFile f : files)
result.add(new FileImageData(f, imageData));
}
return result;
}
@ -190,13 +184,11 @@ public class PSystemUtils {
final SFile outputFile = suggestedFile.getFile(0);
if (outputFile.isDirectory()) {
if (outputFile.isDirectory())
throw new IllegalArgumentException("File is a directory " + suggestedFile);
}
if (!canFileBeWritten(outputFile)) {
if (!canFileBeWritten(outputFile))
return emptyList();
}
final ImageData imageData;
@ -204,17 +196,14 @@ public class PSystemUtils {
imageData = system.exportDiagram(os, 0, fileFormatOption);
}
if (imageData == null) {
if (imageData == null)
return emptyList();
}
if (imageData.containsCMapData() && system instanceof UmlDiagram) {
if (imageData.containsCMapData() && system instanceof UmlDiagram)
((UmlDiagram) system).exportCmap(suggestedFile, 0, imageData);
}
if (system instanceof TitledDiagram && fileFormatOption.getFileFormat() == FileFormat.PNG) {
if (system instanceof TitledDiagram && fileFormatOption.getFileFormat() == FileFormat.PNG)
return splitPng((TitledDiagram) system, suggestedFile, imageData, fileFormatOption);
}
return singletonList(new FileImageData(outputFile, imageData));
}

View File

@ -65,23 +65,22 @@ public class ComponentTextNote extends AbstractComponentText {
final int height = (int) dimensionToUse.getHeight();
charArea.fillRect(' ', 2, 1, width - 3, height - 2);
if (type == ComponentType.NOTE) {
if (fileFormat == FileFormat.UTXT) {
if (fileFormat == FileFormat.UTXT)
charArea.drawNoteSimpleUnicode(2, 0, width - 2, height);
} else {
else
charArea.drawNoteSimple(2, 0, width - 2, height);
}
} else if (type == ComponentType.NOTE_BOX) {
if (fileFormat == FileFormat.UTXT) {
} else if (type == ComponentType.NOTE_BOX || type == ComponentType.NOTE_HEXAGONAL) {
if (fileFormat == FileFormat.UTXT)
charArea.drawBoxSimpleUnicode(2, 0, width - 2, height);
} else {
else
charArea.drawBoxSimple(2, 0, width - 2, height);
}
}
if (fileFormat == FileFormat.UTXT) {
if (fileFormat == FileFormat.UTXT)
charArea.drawStringsLRUnicode(stringsToDisplay.asList(), 3, 1);
} else {
else
charArea.drawStringsLRSimple(stringsToDisplay.asList(), 3, 1);
}
}
public double getPreferredHeight(StringBounder stringBounder) {

View File

@ -75,7 +75,7 @@ public class TextSkin extends Rose {
@Override
public Component createComponentNote(Style[] styles, ComponentType type, ISkinParam param, Display stringsToDisplay,
Colors colors, NotePosition notePosition) {
if (type == ComponentType.NOTE || type == ComponentType.NOTE_BOX)
if (type == ComponentType.NOTE || type == ComponentType.NOTE_BOX || type == ComponentType.NOTE_HEXAGONAL)
return new ComponentTextNote(type, stringsToDisplay, fileFormat);
throw new UnsupportedOperationException(type.toString());

View File

@ -1,8 +1,12 @@
package net.sourceforge.plantuml.awt.geom;
import net.sourceforge.plantuml.awt.XShape;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class XLine2D implements XShape {
public class XLine2D implements XShape, UDrawable {
final public double x1;
final public double y1;
@ -18,7 +22,10 @@ public class XLine2D implements XShape {
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
public XLine2D(XPoint2D p1, XPoint2D p2) {
this(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public XPoint2D getMiddle() {
@ -27,10 +34,6 @@ public class XLine2D implements XShape {
return new XPoint2D(mx, my);
}
public XLine2D(XPoint2D p1, XPoint2D p2) {
this(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public final double getX1() {
return x1;
}
@ -129,4 +132,31 @@ public class XLine2D implements XShape {
}
return lenSq;
}
public XPoint2D intersect(XLine2D line2) {
final double s1x = this.x2 - this.x1;
final double s1y = this.y2 - this.y1;
final double s2x = line2.x2 - line2.x1;
final double s2y = line2.y2 - line2.y1;
final double s = (-s1y * (this.x1 - line2.x1) + s1x * (this.y1 - line2.y1)) / (-s2x * s1y + s1x * s2y);
final double t = (s2x * (this.y1 - line2.y1) - s2y * (this.x1 - line2.x1)) / (-s2x * s1y + s1x * s2y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
return new XPoint2D(this.x1 + (t * s1x), this.y1 + (t * s1y));
return null;
}
public void drawU(UGraphic ug) {
ug = ug.apply(new UTranslate(x1, y1));
final ULine line = new ULine(x2 - x1, y2 - y1);
ug.draw(line);
}
public double getAngle() {
return Math.atan2(y2 - y1, x2 - x1);
}
}

View File

@ -76,4 +76,30 @@ public class XRectangle2D implements XShape {
return xp >= getMinX() && xp < getMaxX() && yp >= getMinY() && yp < getMaxY();
}
public XPoint2D intersect(XLine2D line) {
final XPoint2D a = new XPoint2D(x, y);
final XPoint2D b = new XPoint2D(x + width, y);
final XPoint2D c = new XPoint2D(x + width, y + height);
final XPoint2D d = new XPoint2D(x, y + height);
final XLine2D line1 = new XLine2D(a, b);
final XLine2D line2 = new XLine2D(b, c);
final XLine2D line3 = new XLine2D(c, d);
final XLine2D line4 = new XLine2D(d, a);
XPoint2D result = line.intersect(line1);
if (result != null)
return result;
result = line.intersect(line2);
if (result != null)
return result;
result = line.intersect(line3);
if (result != null)
return result;
result = line.intersect(line4);
if (result != null)
return result;
return null;
}
}

View File

@ -154,10 +154,12 @@ public class ETileBox extends ETile {
final URectangle rect = new URectangle(dimBox);
ug.apply(new UTranslate(posxBox, posy)).apply(lineColor).apply(new UStroke(0.5)).draw(rect);
} else if (symbol == Symbol.SPECIAL_SEQUENCE) {
final URectangle rect1 = new URectangle(dimBox.delta(2)).rounded(12);
final URectangle rect2 = new URectangle(dimBox.delta(-2)).rounded(8);
ug.apply(new UTranslate(posxBox - 1, posy - 1)).apply(lineColor).apply(new UStroke(1.0, 1.0, 1.0)).draw(rect1);
ug.apply(new UTranslate(posxBox + 1, posy + 1)).apply(lineColor).apply(new UStroke(0.5)).draw(rect2);
final URectangle rect = new URectangle(dimBox);
ug.apply(new UTranslate(posxBox, posy)).apply(lineColor).apply(new UStroke(5, 5, 1)).draw(rect);
// final URectangle rect1 = new URectangle(dimBox.delta(2)).rounded(12);
// final URectangle rect2 = new URectangle(dimBox.delta(-2)).rounded(8);
// ug.apply(new UTranslate(posxBox - 1, posy - 1)).apply(lineColor).apply(new UStroke(5.0, 5.0, 1.0)).draw(rect1);
// ug.apply(new UTranslate(posxBox + 1, posy + 1)).apply(lineColor).apply(new UStroke(0.5)).draw(rect2);
} else {
final URectangle rect = new URectangle(dimBox).rounded(10);
ug.apply(new UTranslate(posxBox, posy)).apply(lineColor).apply(backgroundColor.bg()).apply(new UStroke(1.5))

View File

@ -48,7 +48,7 @@ import net.sourceforge.plantuml.security.SImageIO;
public class IconLoader {
private static final int NUMBER_OF_ICONS = 30;
private static final int NUMBER_OF_ICONS = 31;
private final static Map<String, BufferedImage> all = new ConcurrentHashMap<String, BufferedImage>();
static private final List<String> tmp = new ArrayList<>();
@ -61,9 +61,9 @@ public class IconLoader {
private static String getSomeQuote() {
synchronized (tmp) {
if (tmp.size() == 0) {
for (int i = 0; i < NUMBER_OF_ICONS; i++) {
for (int i = 0; i < NUMBER_OF_ICONS; i++)
tmp.add("sprite" + String.format("%03d", i) + ".png");
}
Collections.shuffle(tmp);
}
final int size = tmp.size();
@ -77,9 +77,9 @@ public class IconLoader {
BufferedImage result = all.get(name);
if (result == null) {
result = getIconSlow(name);
if (result != null) {
if (result != null)
all.put(name, result);
}
}
return result;
}
@ -87,9 +87,9 @@ public class IconLoader {
private static BufferedImage getIconSlow(String name) {
try {
final InputStream is = IconLoader.class.getResourceAsStream(name);
if (is == null) {
if (is == null)
return null;
}
final BufferedImage image = SImageIO.read(is);
is.close();
return image;
@ -100,19 +100,18 @@ public class IconLoader {
}
private static BufferedImage addTransparent(BufferedImage ico) {
if (ico == null) {
if (ico == null)
return null;
}
final BufferedImage transparentIcon = new BufferedImage(ico.getWidth(), ico.getHeight(),
BufferedImage.TYPE_INT_ARGB_PRE);
for (int i = 0; i < ico.getWidth(); i++) {
for (int i = 0; i < ico.getWidth(); i++)
for (int j = 0; j < ico.getHeight(); j++) {
final int col = ico.getRGB(i, j);
if (col != ico.getRGB(0, 0)) {
if (col != ico.getRGB(0, 0))
transparentIcon.setRGB(i, j, col);
}
}
}
return transparentIcon;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -57,7 +57,8 @@ public class CommandLinkAnchor extends SingleLineCommand2<SequenceDiagram> {
new RegexLeaf("LINK", "\\<-\\>"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("ANCHOR2", "\\{([%pLN_]+)\\}"), //
RegexLeaf.spaceZeroOrMore(), new RegexLeaf("MESSAGE", "(?::[%s]*(.*))?"), RegexLeaf.end());
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("MESSAGE", "(?::[%s]*(.*))?"), RegexLeaf.end());
}
@Override

View File

@ -43,28 +43,28 @@ public abstract class Extremity implements UDrawable {
protected double manageround(double angle) {
final double deg = angle * 180.0 / Math.PI;
if (isCloseTo(0, deg)) {
if (isCloseTo(0, deg))
return 0;
}
if (isCloseTo(90, deg)) {
if (isCloseTo(90, deg))
return 90.0 * Math.PI / 180.0;
}
if (isCloseTo(180, deg)) {
if (isCloseTo(180, deg))
return 180.0 * Math.PI / 180.0;
}
if (isCloseTo(270, deg)) {
if (isCloseTo(270, deg))
return 270.0 * Math.PI / 180.0;
}
if (isCloseTo(360, deg)) {
if (isCloseTo(360, deg))
return 0;
}
return angle;
}
private boolean isCloseTo(double value, double variable) {
if (Math.abs(value - variable) < 0.05) {
if (Math.abs(value - variable) < 0.05)
return true;
}
return false;
}

View File

@ -36,7 +36,6 @@
package net.sourceforge.plantuml.svek.extremity;
import net.sourceforge.plantuml.awt.geom.XPoint2D;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UPolygon;

View File

@ -196,4 +196,8 @@ public abstract class AbstractCommonUGraphic implements UGraphic {
return false;
}
public final UTranslate getTranslate() {
return translate;
}
}

View File

@ -50,9 +50,9 @@ public class UFont {
private static final Set<String> names = new HashSet<>();
static {
for (String name : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()) {
for (String name : GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames())
names.add(name.toLowerCase());
}
}
public String toStringDebug() {
@ -71,9 +71,9 @@ public class UFont {
if (fontFamily.contains(",")) {
for (String name : fontFamily.split(",")) {
name = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(name).trim();
if (doesFamilyExists(name)) {
if (doesFamilyExists(name))
return new Font(fontFamily, fontStyle, fontSize);
}
}
}
return new Font(fontFamily, fontStyle, fontSize);
@ -154,21 +154,22 @@ public class UFont {
public String getFamily(UFontContext context) {
if (context == UFontContext.EPS) {
if (family == null) {
if (family == null)
return "Times-Roman";
}
return font.getPSName();
}
if (context == UFontContext.SVG) {
if (family.equalsIgnoreCase("sansserif")) {
if (family.equalsIgnoreCase("sansserif"))
return "sans-serif";
}
return family;
}
return family;
}
// Kludge for testing because font names on some machines (only macOS?) do not end with <DOT><STYLE>
// Kludge for testing because font names on some machines (only macOS?) do not
// end with <DOT><STYLE>
// See https://github.com/plantuml/plantuml/issues/720
private String getPortableFontName() {
final String name = font.getFontName();
@ -194,9 +195,9 @@ public class UFont {
@Override
public boolean equals(Object obj) {
if (obj instanceof UFont == false) {
if (obj instanceof UFont == false)
return false;
}
return this.font.equals(((UFont) obj).font);
}

View File

@ -132,6 +132,15 @@ public class DriverTextG2d implements UDriver<UText, Graphics2D> {
visible.ensureVisible(x + width, y + 1.5);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// https://stackoverflow.com/questions/31536952/how-to-fix-text-quality-in-java-graphics
// https://stackoverflow.com/questions/72818320/improve-java2d-drawing-quality-on-hi-resolution-monitors
/*
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
*/
g2d.setFont(font.getUnderlayingFont());
g2d.setColor(fontConfiguration.getColor().toColor(mapper));
g2d.drawString(text, (float) x, (float) y);

View File

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

View File

@ -50,18 +50,34 @@ import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException;
public class CommandWBSItem extends SingleLineCommand2<WBSDiagram> {
public CommandWBSItem() {
super(false, getRegexConcat());
public CommandWBSItem(int mode) {
super(false, getRegexConcat(mode));
}
static IRegex getRegexConcat() {
return RegexConcat.build(CommandWBSItem.class.getName(), RegexLeaf.start(), //
static IRegex getRegexConcat(int mode) {
if (mode == 0)
return RegexConcat.build(CommandWBSItem.class.getName() + mode, RegexLeaf.start(), //
new RegexLeaf("TYPE", "([ \t]*[*+-]+)"), //
new RegexOptional(new RegexLeaf("BACKCOLOR", "\\[(#\\w+)\\]")), //
new RegexOptional(new RegexLeaf("CODE", "\\(([%pLN_]+)\\)")), //
new RegexLeaf("SHAPE", "(_)?"), //
new RegexLeaf("DIRECTION", "([<>])?"), //
RegexLeaf.spaceOneOrMore(), //
new RegexLeaf("LABEL", "([^%s].*)"), //
RegexLeaf.end());
return RegexConcat.build(CommandWBSItem.class.getName() + mode, RegexLeaf.start(), //
new RegexLeaf("TYPE", "([ \t]*[*+-]+)"), //
new RegexOptional(new RegexLeaf("BACKCOLOR", "\\[(#\\w+)\\]")), //
new RegexLeaf("SHAPE", "(_)?"), //
new RegexLeaf("DIRECTION", "([<>])?"), //
RegexLeaf.spaceOneOrMore(), //
new RegexLeaf("LABEL", "([^%s].*)"), RegexLeaf.end());
new RegexLeaf("LABEL", "[%g](.*)[%g]"), //
RegexLeaf.spaceOneOrMore(), //
new RegexLeaf("as"), //
RegexLeaf.spaceOneOrMore(), //
new RegexLeaf("CODE", "([%pLN_]+)"), //
RegexLeaf.end());
}
@Override
@ -69,6 +85,7 @@ public class CommandWBSItem extends SingleLineCommand2<WBSDiagram> {
throws NoSuchColorException {
final String type = arg.get("TYPE", 0);
final String label = arg.get("LABEL", 0);
final String code = arg.get("CODE", 0);
final String stringColor = arg.get("BACKCOLOR", 0);
HColor backColor = null;
if (stringColor != null)
@ -81,7 +98,7 @@ public class CommandWBSItem extends SingleLineCommand2<WBSDiagram> {
else if (">".equals(direction))
dir = Direction.RIGHT;
return diagram.addIdea(backColor, diagram.getSmartLevel(type), label, dir,
return diagram.addIdea(code, backColor, diagram.getSmartLevel(type), label, dir,
IdeaShape.fromDesc(arg.get("SHAPE", 0)));
}

View File

@ -94,20 +94,18 @@ public class CommandWBSItemMultiline extends CommandMultilines2<WBSDiagram> {
lines = lines.removeStartingAndEnding(line0.get("DATA", 0), 1);
final String stereotype = lineLast.get(1);
if (stereotype != null) {
if (stereotype != null)
lines = lines.overrideLastLine(lineLast.get(0));
}
final String type = line0.get("TYPE", 0);
final String stringColor = line0.get("BACKCOLOR", 0);
HColor backColor = null;
if (stringColor != null) {
if (stringColor != null)
backColor = diagram.getSkinParam().getIHtmlColorSet().getColor(stringColor);
}
Direction dir = Direction.RIGHT;
return diagram.addIdea(backColor, diagram.getSmartLevel(type), lines.toDisplay(), stereotype, dir,
return diagram.addIdea(null, backColor, diagram.getSmartLevel(type), lines.toDisplay(), stereotype, dir,
IdeaShape.fromDesc(line0.get("SHAPE", 0)));
}

View File

@ -0,0 +1,71 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2023, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.wbs;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.command.SingleLineCommand2;
import net.sourceforge.plantuml.command.regex.IRegex;
import net.sourceforge.plantuml.command.regex.RegexConcat;
import net.sourceforge.plantuml.command.regex.RegexLeaf;
import net.sourceforge.plantuml.command.regex.RegexResult;
public class CommandWBSLink extends SingleLineCommand2<WBSDiagram> {
public CommandWBSLink() {
super(getRegexConcat());
}
static IRegex getRegexConcat() {
return RegexConcat.build(CommandWBSLink.class.getName(), RegexLeaf.start(), //
new RegexLeaf("CODE1", "([%pLN_]+)"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("LINK", "-+\\>"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("CODE2", "([%pLN_]+)"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("MESSAGE", "(?::[%s]*(.*))?"), RegexLeaf.end());
}
@Override
protected CommandExecutionResult executeArg(WBSDiagram diagram, LineLocation location, RegexResult arg) {
final String code1 = arg.get("CODE1", 0);
final String code2 = arg.get("CODE2", 0);
// final String message = arg.get("MESSAGE", 0);
return diagram.link(code1, code2);
}
}

View File

@ -46,6 +46,7 @@ import net.sourceforge.plantuml.awt.geom.XPoint2D;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
@ -58,9 +59,11 @@ class ITFComposed extends WBSTextBlock implements ITF {
final private double delta1x = 10;
final private double marginBottom;// = 15;
private final WElement idea;
private ITFComposed(ISkinParam skinParam, WElement idea, List<ITF> left, List<ITF> right) {
super(skinParam, idea.getStyleBuilder(), idea.getLevel());
this.idea = idea;
this.left = left;
this.right = right;
this.main = buildMain(idea);
@ -69,17 +72,17 @@ class ITFComposed extends WBSTextBlock implements ITF {
}
public static ITF build2(ISkinParam skinParam, WElement idea) {
if (idea.isLeaf()) {
return new ITFLeaf(idea.getStyle(), idea.withBackColor(skinParam), idea.getLabel(), idea.getShape());
}
if (idea.isLeaf())
return new ITFLeaf(idea, idea.withBackColor(skinParam));
final List<ITF> left = new ArrayList<>();
final List<ITF> right = new ArrayList<>();
for (WElement child : idea.getChildren(Direction.LEFT)) {
for (WElement child : idea.getChildren(Direction.LEFT))
left.add(build2(skinParam, child));
}
for (WElement child : idea.getChildren(Direction.RIGHT)) {
for (WElement child : idea.getChildren(Direction.RIGHT))
right.add(build2(skinParam, child));
}
return new ITFComposed(skinParam, idea, left, right);
}
@ -128,7 +131,14 @@ class ITFComposed extends WBSTextBlock implements ITF {
public void drawU(final UGraphic ug) {
final StringBounder stringBounder = ug.getStringBounder();
final XDimension2D mainDim = main.calculateDimension(stringBounder);
if (ug instanceof AbstractCommonUGraphic) {
final UTranslate translate = ((AbstractCommonUGraphic) ug).getTranslate();
idea.setGeometry(translate, mainDim);
}
final double wx = getw1(stringBounder) - mainDim.getWidth() / 2;
main.drawU(ug.apply(UTranslate.dx(wx)));
final double x = getw1(stringBounder);
@ -159,18 +169,18 @@ class ITFComposed extends WBSTextBlock implements ITF {
final private double getCollWidth(StringBounder stringBounder, Collection<? extends TextBlock> all) {
double result = 0;
for (TextBlock child : all) {
for (TextBlock child : all)
result = Math.max(result, child.calculateDimension(stringBounder).getWidth());
}
return result;
}
final private double getCollHeight(StringBounder stringBounder, Collection<? extends TextBlock> all,
double deltay) {
double result = 0;
for (TextBlock child : all) {
for (TextBlock child : all)
result += deltay + child.calculateDimension(stringBounder).getHeight();
}
return result;
}

View File

@ -47,18 +47,24 @@ import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.mindmap.IdeaShape;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
class ITFLeaf extends AbstractTextBlock implements ITF {
private final TextBlock box;
private final WElement idea;
public ITFLeaf(Style style, ISkinParam skinParam, Display label, IdeaShape shape) {
public ITFLeaf(WElement idea, ISkinParam skinParam) {
final IdeaShape shape = idea.getShape();
final Style style = idea.getStyle();
final Display label = idea.getLabel();
this.idea = idea;
if (shape == IdeaShape.BOX) {
this.box = FtileBoxOld.createWbs(style, skinParam, label);
} else {
final TextBlock text = label.create0(
style.getFontConfiguration(skinParam.getIHtmlColorSet()),
final TextBlock text = label.create0(style.getFontConfiguration(skinParam.getIHtmlColorSet()),
style.getHorizontalAlignment(), skinParam, style.wrapWidth(), CreoleMode.FULL, null, null);
this.box = TextBlockUtils.withMargin(text, 0, 3, 1, 1);
}
@ -69,6 +75,10 @@ class ITFLeaf extends AbstractTextBlock implements ITF {
}
public void drawU(UGraphic ug) {
if (ug instanceof AbstractCommonUGraphic) {
final UTranslate translate = ((AbstractCommonUGraphic) ug).getTranslate();
idea.setGeometry(translate, calculateDimension(ug.getStringBounder()));
}
box.drawU(ug);
}

View File

@ -37,6 +37,10 @@ package net.sourceforge.plantuml.wbs;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.FileFormatOption;
@ -54,16 +58,23 @@ import net.sourceforge.plantuml.core.UmlSource;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.InnerStrategy;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.mindmap.IdeaShape;
import net.sourceforge.plantuml.style.NoStyleAvailableException;
import net.sourceforge.plantuml.svek.TextBlockBackcolored;
import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic;
import net.sourceforge.plantuml.ugraphic.MinMax;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
public class WBSDiagram extends UmlDiagram {
private WElement root;
private WElement last;
private String first;
private final Map<String, WElement> codes = new LinkedHashMap<>();
private final List<WBSLink> links = new ArrayList<>();
public DiagramDescription getDescription() {
return new DiagramDescription("Work Breakdown Structure");
}
@ -106,18 +117,30 @@ public class WBSDiagram extends UmlDiagram {
}
private void drawMe(UGraphic ug) {
getDrawingElement().drawU(ug);
UTranslate translate = null;
if (ug instanceof AbstractCommonUGraphic)
translate = ((AbstractCommonUGraphic) ug).getTranslate();
final Fork fork = getDrawingElement();
fork.drawU(ug);
if (translate == null)
return;
ug = ug.apply(translate.reverse());
for (WBSLink link : links)
link.drawU(ug);
}
private TextBlock getDrawingElement() {
private Fork getDrawingElement() {
return new Fork(getSkinParam(), root);
}
public final static Pattern2 patternStereotype = MyPattern
.cmpile("^\\s*(.*?)(?:\\s*\\<\\<\\s*(.*)\\s*\\>\\>)\\s*$");
public CommandExecutionResult addIdea(HColor backColor, int level, String label, Direction direction,
public CommandExecutionResult addIdea(String code, HColor backColor, int level, String label, Direction direction,
IdeaShape shape) {
final Matcher2 m = patternStereotype.matcher(label);
String stereotype = null;
@ -126,10 +149,10 @@ public class WBSDiagram extends UmlDiagram {
stereotype = m.group(2);
}
final Display display = Display.getWithNewlines(label);
return addIdea(backColor, level, display, stereotype, direction, shape);
return addIdea(code, backColor, level, display, stereotype, direction, shape);
}
public CommandExecutionResult addIdea(HColor backColor, int level, Display display, String stereotype,
public CommandExecutionResult addIdea(String code, HColor backColor, int level, Display display, String stereotype,
Direction direction, IdeaShape shape) {
try {
if (level == 0) {
@ -139,17 +162,13 @@ public class WBSDiagram extends UmlDiagram {
initRoot(backColor, display, stereotype, shape);
return CommandExecutionResult.ok();
}
return add(backColor, level, display, stereotype, direction, shape);
return add(code, backColor, level, display, stereotype, direction, shape);
} catch (NoStyleAvailableException e) {
// Logme.error(e);
return CommandExecutionResult.error("General failure: no style available.");
}
}
private WElement root;
private WElement last;
private String first;
private void initRoot(HColor backColor, Display display, String stereotype, IdeaShape shape) {
root = new WElement(backColor, display, stereotype, getSkinParam().getCurrentStyleBuilder(), shape);
last = root;
@ -185,13 +204,15 @@ public class WBSDiagram extends UmlDiagram {
throw new UnsupportedOperationException("type=<" + type + ">[" + first + "]");
}
private CommandExecutionResult add(HColor backColor, int level, Display display, String stereotype,
private CommandExecutionResult add(String code, HColor backColor, int level, Display display, String stereotype,
Direction direction, IdeaShape shape) {
try {
if (level == last.getLevel() + 1) {
final WElement newIdea = last.createElement(backColor, level, display, stereotype, direction, shape,
getSkinParam().getCurrentStyleBuilder());
last = newIdea;
if (code != null)
codes.put(code, newIdea);
return CommandExecutionResult.ok();
}
if (level <= last.getLevel()) {
@ -199,6 +220,8 @@ public class WBSDiagram extends UmlDiagram {
final WElement newIdea = getParentOfLast(diff).createElement(backColor, level, display, stereotype,
direction, shape, getSkinParam().getCurrentStyleBuilder());
last = newIdea;
if (code != null)
codes.put(code, newIdea);
return CommandExecutionResult.ok();
}
return CommandExecutionResult.error("Bad tree structure");
@ -208,4 +231,17 @@ public class WBSDiagram extends UmlDiagram {
}
}
public CommandExecutionResult link(String code1, String code2) {
final WElement element1 = codes.get(code1);
if (element1 == null)
return CommandExecutionResult.error("No such node " + code1);
final WElement element2 = codes.get(code2);
if (element2 == null)
return CommandExecutionResult.error("No such node " + code2);
links.add(new WBSLink(element1, element2));
return CommandExecutionResult.ok();
}
}

View File

@ -56,8 +56,10 @@ public class WBSDiagramFactory extends PSystemCommandFactory {
final List<Command> cmds = new ArrayList<>();
CommonCommands.addCommonCommands1(cmds);
cmds.add(new CommandWBSItem());
cmds.add(new CommandWBSItem(1));
cmds.add(new CommandWBSItem(0));
cmds.add(new CommandWBSItemMultiline());
cmds.add(new CommandWBSLink());
return cmds;
}

View File

@ -0,0 +1,97 @@
/* ========================================================================
* PlantUML : a free UML diagram generator
* ========================================================================
*
* (C) Copyright 2009-2023, Arnaud Roques
*
* Project Info: http://plantuml.com
*
* If you like this project or if you find it useful, you can support us at:
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PlantUML distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
*
* Original Author: Arnaud Roques
*
*
*/
package net.sourceforge.plantuml.wbs;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.awt.geom.XLine2D;
import net.sourceforge.plantuml.awt.geom.XPoint2D;
import net.sourceforge.plantuml.awt.geom.XRectangle2D;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.svek.extremity.ExtremityArrow;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColors;
class WBSLink implements UDrawable {
private final WElement element1;
private final WElement element2;
public WBSLink(WElement element1, WElement element2) {
this.element1 = element1;
this.element2 = element2;
}
public final WElement getElement1() {
return element1;
}
public final WElement getElement2() {
return element2;
}
public void drawU(UGraphic ug) {
final WElement element1 = getElement1();
final WElement element2 = getElement2();
final UTranslate position1 = element1.getPosition();
final UTranslate position2 = element2.getPosition();
final XDimension2D dim1 = element1.getDimension();
final XDimension2D dim2 = element2.getDimension();
if (position1 != null && position2 != null) {
final XRectangle2D rect1 = new XRectangle2D(position1.getDx(), position1.getDy(), dim1.getWidth(),
dim1.getHeight());
final XRectangle2D rect2 = new XRectangle2D(position2.getDx(), position2.getDy(), dim2.getWidth(),
dim2.getHeight());
XLine2D line = new XLine2D(rect1.getCenterX(), rect1.getCenterY(), rect2.getCenterX(), rect2.getCenterY());
final XPoint2D c1 = rect1.intersect(line);
final XPoint2D c2 = rect2.intersect(line);
line = new XLine2D(c1, c2);
ug = ug.apply(HColors.RED);
line.drawU(ug);
final double angle = line.getAngle();
final ExtremityArrow arrow = new ExtremityArrow(c2, angle);
arrow.drawU(ug);
}
}
}

View File

@ -43,6 +43,7 @@ import java.util.List;
import net.sourceforge.plantuml.Direction;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.SkinParamColors;
import net.sourceforge.plantuml.awt.geom.XDimension2D;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.graphic.color.Colors;
@ -52,6 +53,7 @@ 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.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
final public class WElement {
@ -65,6 +67,8 @@ final public class WElement {
private final List<WElement> childrenLeft = new ArrayList<>();
private final List<WElement> childrenRight = new ArrayList<>();
private final IdeaShape shape;
private UTranslate position;
private XDimension2D dimension;
private StyleSignatureBasic getDefaultStyleDefinitionNode(int level) {
final String depth = SName.depth(level);
@ -85,7 +89,8 @@ final public class WElement {
return StyleSignatureBasic.of(SName.root, SName.element, SName.wbsDiagram, SName.node, SName.boxless)
.addS(stereotype).add(depth);
return StyleSignatureBasic.of(SName.root, SName.element, SName.wbsDiagram, SName.node).addS(stereotype).add(depth);
return StyleSignatureBasic.of(SName.root, SName.element, SName.wbsDiagram, SName.node).addS(stereotype)
.add(depth);
}
public ISkinParam withBackColor(ISkinParam skinParam) {
@ -172,4 +177,17 @@ final public class WElement {
return styleBuilder;
}
public final void setGeometry(UTranslate position, XDimension2D dimension) {
this.position = position;
this.dimension = dimension;
}
public final UTranslate getPosition() {
return position;
}
public final XDimension2D getDimension() {
return dimension;
}
}