diff --git a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateElementFull2.java b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateElementFull2.java index 66b213876..77bc0ab61 100644 --- a/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateElementFull2.java +++ b/src/net/sourceforge/plantuml/classdiagram/command/CommandCreateElementFull2.java @@ -185,6 +185,12 @@ public class CommandCreateElementFull2 extends SingleLineCommand2 } else if (symbol.equalsIgnoreCase("port")) { type = LeafType.PORT; usymbol = null; + } else if (symbol.equalsIgnoreCase("portin")) { + type = LeafType.PORTIN; + usymbol = null; + } else if (symbol.equalsIgnoreCase("portout")) { + type = LeafType.PORTOUT; + usymbol = null; } else if (symbol.equalsIgnoreCase("usecase")) { type = LeafType.USECASE; usymbol = null; diff --git a/src/net/sourceforge/plantuml/command/BlocLines.java b/src/net/sourceforge/plantuml/command/BlocLines.java index 2feba8220..d2d558b22 100644 --- a/src/net/sourceforge/plantuml/command/BlocLines.java +++ b/src/net/sourceforge/plantuml/command/BlocLines.java @@ -68,9 +68,9 @@ public class BlocLines implements Iterable { public static BlocLines load(SFile f, LineLocation location) throws IOException { final BufferedReader br = f.openBufferedReader(); - if (br == null) { + if (br == null) return null; - } + return loadInternal(br, location); } @@ -87,9 +87,8 @@ public class BlocLines implements Iterable { final List result = new ArrayList<>(); String s; try { - while ((s = br.readLine()) != null) { + while ((s = br.readLine()) != null) result.add(new StringLocated(s, location)); - } } finally { br.close(); } @@ -118,17 +117,17 @@ public class BlocLines implements Iterable { public static BlocLines fromArray(String[] array) { final List result = new ArrayList<>(); - for (String single : array) { + for (String single : array) result.add(new StringLocated(single, null)); - } + return new BlocLines(result); } public static BlocLines getWithNewlines(String s) { final List result = new ArrayList<>(); - for (String cs : BackSlash.getWithNewlines(s)) { + for (String cs : BackSlash.getWithNewlines(s)) result.add(new StringLocated(cs, null)); - } + return new BlocLines(result); } @@ -150,9 +149,9 @@ public class BlocLines implements Iterable { public List getLinesAsStringForSprite() { final List result = new ArrayList<>(); - for (StringLocated s : lines) { + for (StringLocated s : lines) result.add(s.getString()); - } + return result; } @@ -165,9 +164,9 @@ public class BlocLines implements Iterable { } public StringLocated getFirst() { - if (lines.size() == 0) { + if (lines.size() == 0) return null; - } + return lines.get(0); } @@ -192,11 +191,10 @@ public class BlocLines implements Iterable { public BlocLines removeEmptyLines() { final List copy = new ArrayList<>(lines); - for (final Iterator it = copy.iterator(); it.hasNext();) { - if (it.next().getString().length() == 0) { + for (final Iterator it = copy.iterator(); it.hasNext();) + if (it.next().getString().length() == 0) it.remove(); - } - } + return new BlocLines(copy); } @@ -210,16 +208,16 @@ public class BlocLines implements Iterable { // } public BlocLines removeEmptyColumns() { - if (firstColumnRemovable(lines) == false) { + if (firstColumnRemovable(lines) == false) return this; - } + final List copy = new ArrayList<>(lines); do { for (int i = 0; i < copy.size(); i++) { final StringLocated s = copy.get(i); - if (s.getString().length() > 0) { + if (s.getString().length() > 0) copy.set(i, s.substring(1, s.getString().length())); - } + } } while (firstColumnRemovable(copy)); return new BlocLines(copy); @@ -228,14 +226,14 @@ public class BlocLines implements Iterable { private static boolean firstColumnRemovable(List data) { boolean allEmpty = true; for (StringLocated s : data) { - if (s.getString().length() == 0) { + if (s.getString().length() == 0) continue; - } + allEmpty = false; final char c = s.getString().charAt(0); - if (c != ' ' && c != '\t') { + if (c != ' ' && c != '\t') return false; - } + } return allEmpty == false; } @@ -246,9 +244,9 @@ public class BlocLines implements Iterable { } public BlocLines removeStartingAndEnding(String data, int removeAtEnd) { - if (lines.size() == 0) { + if (lines.size() == 0) return this; - } + final List copy = new ArrayList<>(lines); copy.set(0, new StringLocated(data, null)); final int n = copy.size() - 1; @@ -258,9 +256,9 @@ public class BlocLines implements Iterable { } public BlocLines overrideLastLine(String last) { - if (lines.size() == 0) { + if (lines.size() == 0) return this; - } + final List copy = new ArrayList<>(lines); final int n = copy.size() - 1; final StringLocated currentLast = copy.get(n); @@ -278,9 +276,9 @@ public class BlocLines implements Iterable { } public BlocLines trimSmart(int referenceLine) { - if (lines.size() <= referenceLine) { + if (lines.size() <= referenceLine) return this; - } + final List copy = new ArrayList<>(lines); final int nbStartingSpace = nbStartingSpace(copy.get(referenceLine).getString()); for (int i = referenceLine; i < copy.size(); i++) { @@ -292,9 +290,9 @@ public class BlocLines implements Iterable { private static int nbStartingSpace(CharSequence s) { int nb = 0; - while (nb < s.length() && isSpaceOrTab(s.charAt(nb))) { + while (nb < s.length() && isSpaceOrTab(s.charAt(nb))) nb++; - } + return nb; } @@ -331,9 +329,9 @@ public class BlocLines implements Iterable { } public BlocLines eventuallyMoveBracket() { - if (size() < 2) { + if (size() < 2) return this; - } + final String first = getFirst().getTrimmed().getString(); final String second = getAt(1).getTrimmed().getString(); if (first.endsWith("{") == false && second.equals("{")) { @@ -348,7 +346,7 @@ public class BlocLines implements Iterable { public BlocLines eventuallyMoveAllEmptyBracket() { final List result = new ArrayList<>(); - for (StringLocated line : lines) { + for (StringLocated line : lines) if (line.getTrimmed().toString().equals("{")) { if (result.size() > 0) { final int pos = result.size() - 1; @@ -358,7 +356,7 @@ public class BlocLines implements Iterable { } else { result.add(line); } - } + return new BlocLines(result); } diff --git a/src/net/sourceforge/plantuml/command/CommandSpriteFile.java b/src/net/sourceforge/plantuml/command/CommandSpriteFile.java index 24f206e70..e7edf1376 100644 --- a/src/net/sourceforge/plantuml/command/CommandSpriteFile.java +++ b/src/net/sourceforge/plantuml/command/CommandSpriteFile.java @@ -69,7 +69,7 @@ public class CommandSpriteFile extends SingleLineCommand2 { new RegexLeaf("\\$?"), // new RegexLeaf("NAME", "([-%pLN_]+)"), // RegexLeaf.spaceOneOrMore(), // - new RegexLeaf("FILE", "(.*)"), RegexLeaf.end()); + new RegexLeaf("FILE", "([^<>%g#]*)"), RegexLeaf.end()); } @Override @@ -80,37 +80,37 @@ public class CommandSpriteFile extends SingleLineCommand2 { if (src.startsWith("jar:")) { final String inner = src.substring(4) + ".png"; final InputStream is = SpriteImage.getInternalSprite(inner); - if (is == null) { + if (is == null) return CommandExecutionResult.error("No such internal sprite: " + inner); - } + sprite = new SpriteImage(SImageIO.read(is)); } else if (src.contains("~")) { final int idx = src.lastIndexOf("~"); final SFile f = FileSystem.getInstance().getFile(src.substring(0, idx)); - if (f.exists() == false) { + if (f.exists() == false) return CommandExecutionResult.error("Cannot read: " + src); - } + final String name = src.substring(idx + 1); sprite = getImageFromZip(f, name); - if (sprite == null) { + if (sprite == null) return CommandExecutionResult.error("Cannot read: " + src); - } + } else { final SFile f = FileSystem.getInstance().getFile(src); - if (f.exists() == false) { + if (f.exists() == false) return CommandExecutionResult.error("Cannot read: " + src); - } + if (isSvg(f.getName())) { final String tmp = FileUtils.readSvg(f); - if (tmp == null) { + if (tmp == null) return CommandExecutionResult.error("Cannot read: " + src); - } + sprite = new SpriteSvg(tmp); } else { final BufferedImage tmp = f.readRasterImageFromFile(); - if (tmp == null) { + if (tmp == null) return CommandExecutionResult.error("Cannot read: " + src); - } + sprite = new SpriteImage(tmp); } } diff --git a/src/net/sourceforge/plantuml/command/CommandSpriteSvg.java b/src/net/sourceforge/plantuml/command/CommandSpriteSvg.java new file mode 100644 index 000000000..81a217b76 --- /dev/null +++ b/src/net/sourceforge/plantuml/command/CommandSpriteSvg.java @@ -0,0 +1,70 @@ +/* ======================================================================== + * 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.command; + +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.TitledDiagram; +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; +import net.sourceforge.plantuml.emoji.SvgNanoParser; + +public class CommandSpriteSvg extends SingleLineCommand2 { + + public CommandSpriteSvg() { + super(getRegexConcat()); + } + + private static IRegex getRegexConcat() { + return RegexConcat.build(CommandSpriteSvg.class.getName(), RegexLeaf.start(), // + new RegexLeaf("sprite"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("\\$?"), // + new RegexLeaf("NAME", "([-%pLN_]+)"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("SVG", "(\\)"), RegexLeaf.end()); + } + + @Override + protected CommandExecutionResult executeArg(TitledDiagram system, LineLocation location, RegexResult arg) { + final String svg = arg.get("SVG", 0); + final SvgNanoParser nanoParser = new SvgNanoParser(svg, true); + system.addSprite(arg.get("NAME", 0), nanoParser); + + return CommandExecutionResult.ok(); + } +} diff --git a/src/net/sourceforge/plantuml/command/CommandSpriteSvgMultiline.java b/src/net/sourceforge/plantuml/command/CommandSpriteSvgMultiline.java new file mode 100644 index 000000000..a5a46ccf2 --- /dev/null +++ b/src/net/sourceforge/plantuml/command/CommandSpriteSvgMultiline.java @@ -0,0 +1,85 @@ +/* ======================================================================== + * 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.command; + +import net.sourceforge.plantuml.StringLocated; +import net.sourceforge.plantuml.TitledDiagram; +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; +import net.sourceforge.plantuml.emoji.SvgNanoParser; +import net.sourceforge.plantuml.ugraphic.color.NoSuchColorException; + +public class CommandSpriteSvgMultiline extends CommandMultilines2 { + + public CommandSpriteSvgMultiline() { + super(getRegexConcat(), MultilinesStrategy.KEEP_STARTING_QUOTE); + } + + private static IRegex getRegexConcat() { + return RegexConcat.build(CommandSpriteSvgMultiline.class.getName(), RegexLeaf.start(), // + new RegexLeaf("sprite"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("\\$?"), // + new RegexLeaf("NAME", "([-%pLN_]+)"), // + RegexLeaf.spaceOneOrMore(), // + new RegexLeaf("SVGSTART", "(\\)$"; + } + + @Override + protected CommandExecutionResult executeNow(TitledDiagram system, BlocLines lines) throws NoSuchColorException { + + final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString()); + final String svgStart = line0.get("SVGSTART", 0); + lines = lines.subExtract(1, 0); + + final StringBuilder svg = new StringBuilder(svgStart); + for (StringLocated sl : lines) + svg.append(sl.getString()); + + final SvgNanoParser nanoParser = new SvgNanoParser(svg.toString(), true); + system.addSprite(line0.get("NAME", 0), nanoParser); + + return CommandExecutionResult.ok(); + } +} diff --git a/src/net/sourceforge/plantuml/command/CommonCommands.java b/src/net/sourceforge/plantuml/command/CommonCommands.java index 4477a1aa2..da1e6f1bf 100644 --- a/src/net/sourceforge/plantuml/command/CommonCommands.java +++ b/src/net/sourceforge/plantuml/command/CommonCommands.java @@ -77,7 +77,9 @@ public final class CommonCommands { final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite(); cmds.add(factorySpriteCommand.createMultiLine(false)); cmds.add(factorySpriteCommand.createSingleLine()); + cmds.add(new CommandSpriteSvg()); cmds.add(new CommandSpriteFile()); + cmds.add(new CommandSpriteSvgMultiline()); cmds.add(new CommandStyleMultilinesCSS()); cmds.add(new CommandStyleImport()); diff --git a/src/net/sourceforge/plantuml/command/MultilinesStrategy.java b/src/net/sourceforge/plantuml/command/MultilinesStrategy.java index a988732ec..6b407745b 100644 --- a/src/net/sourceforge/plantuml/command/MultilinesStrategy.java +++ b/src/net/sourceforge/plantuml/command/MultilinesStrategy.java @@ -44,17 +44,17 @@ public enum MultilinesStrategy { REMOVE_STARTING_QUOTE, KEEP_STARTING_QUOTE; public void cleanList(List lines) { - if (this == REMOVE_STARTING_QUOTE) { + if (this == REMOVE_STARTING_QUOTE) filterQuote(lines); - } + } private void filterQuote(List lines) { for (final Iterator it = lines.iterator(); it.hasNext();) { final StringLocated s = it.next(); - if (hasStartingQuote(s)) { + if (hasStartingQuote(s)) it.remove(); - } + } } diff --git a/src/net/sourceforge/plantuml/dedication/Dedications.java b/src/net/sourceforge/plantuml/dedication/Dedications.java index 5c2495218..b05c9f069 100644 --- a/src/net/sourceforge/plantuml/dedication/Dedications.java +++ b/src/net/sourceforge/plantuml/dedication/Dedications.java @@ -61,6 +61,8 @@ public class Dedications { "1182423723677118831606503500858825217076578422970565964857326298418401529955036896808663335300684244453386039908536275400945824932191521017102701344437753036730900076162922741167523337650578479960119614237031234925702200473053235777"))); all.add(secret(3, "514816d583044efbd336882227deb822194ff63e3bdc3cf707a01f17770d5a6a", new BigInteger( "538955952645999836068094511687012232127213955837942782605199622268460518023083462090291844640318324475656060087513198129259364840841077651829017347845508167869708224054456044836844382437974410757740941102771969965334031780041648873"))); + all.add(secret(1, "ae8a7cf3997ccd6418866fc59e596502e1bd1c0265bba2fc380ad7f51c76518f", new BigInteger( + "987988542836850639056829173787067531749177506648884857100630852970876999799588072360773169026225182488073794585127241896588994816566037813451743416913613428321215803586563629080034406083114565732322220091545330060636171674602040157"))); } catch (Throwable t) { t.printStackTrace(); } diff --git a/src/net/sourceforge/plantuml/dedication/ae8a7cf3997ccd6418866fc59e596502e1bd1c0265bba2fc380ad7f51c76518f.png b/src/net/sourceforge/plantuml/dedication/ae8a7cf3997ccd6418866fc59e596502e1bd1c0265bba2fc380ad7f51c76518f.png new file mode 100644 index 000000000..4314323c1 Binary files /dev/null and b/src/net/sourceforge/plantuml/dedication/ae8a7cf3997ccd6418866fc59e596502e1bd1c0265bba2fc380ad7f51c76518f.png differ diff --git a/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java b/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java index 45c4d769d..95f89acaf 100644 --- a/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java +++ b/src/net/sourceforge/plantuml/descdiagram/DescriptionDiagramFactory.java @@ -63,6 +63,8 @@ import net.sourceforge.plantuml.descdiagram.command.CommandCreateElementMultilin import net.sourceforge.plantuml.descdiagram.command.CommandLinkElement; import net.sourceforge.plantuml.descdiagram.command.CommandNewpage; import net.sourceforge.plantuml.descdiagram.command.CommandPackageWithUSymbol; +import net.sourceforge.plantuml.objectdiagram.command.CommandCreateJson; +import net.sourceforge.plantuml.objectdiagram.command.CommandCreateMap; public class DescriptionDiagramFactory extends PSystemCommandFactory { @@ -116,6 +118,8 @@ public class DescriptionDiagramFactory extends PSystemCommandFactory { cmds.add(factoryNoteOnEntityCommand.createMultiLine(false)); cmds.add(factoryNoteCommand.createMultiLine(false)); + cmds.add(new CommandCreateMap()); + cmds.add(new CommandCreateJson()); // cmds.add(new CommandHideShowSpecificClass()); cmds.add(new CommandArchimate()); diff --git a/src/net/sourceforge/plantuml/emoji/Emoji.java b/src/net/sourceforge/plantuml/emoji/Emoji.java index 4b771d893..e5da1f837 100644 --- a/src/net/sourceforge/plantuml/emoji/Emoji.java +++ b/src/net/sourceforge/plantuml/emoji/Emoji.java @@ -1,6 +1,5 @@ package net.sourceforge.plantuml.emoji; -import java.awt.Color; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -11,26 +10,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import net.sourceforge.plantuml.emoji.data.Dummy; -import net.sourceforge.plantuml.openiconic.SvgPath; -import net.sourceforge.plantuml.ugraphic.UEllipse; import net.sourceforge.plantuml.ugraphic.UGraphic; -import net.sourceforge.plantuml.ugraphic.UStroke; -import net.sourceforge.plantuml.ugraphic.UTranslate; -import net.sourceforge.plantuml.ugraphic.color.ColorChangerMonochrome; import net.sourceforge.plantuml.ugraphic.color.HColor; -import net.sourceforge.plantuml.ugraphic.color.HColorNone; -import net.sourceforge.plantuml.ugraphic.color.HColorSet; -import net.sourceforge.plantuml.ugraphic.color.HColorSimple; // Emojji from https://twemoji.twitter.com/ // Shorcut from https://api.github.com/emojis public class Emoji { - private final static Map ALL = new HashMap<>(); static { @@ -49,9 +37,8 @@ public class Emoji { return Collections.unmodifiableMap(new TreeMap<>(ALL)); } - private final List data = new ArrayList<>(); - private int minGray = 999; - private int maxGray = -1; + private SvgNanoParser nano; + private final String unicode; private final String shortcut; @@ -83,34 +70,17 @@ public class Emoji { return ALL.get(name.toLowerCase()); } - private String extractData(String name, String s) { - final Pattern p = Pattern.compile(name + "=\"([^\"]+)\""); - final Matcher m = p.matcher(s); - if (m.find()) - return m.group(1); - - return null; - } - private synchronized void loadIfNeed() throws IOException { - if (data.size() > 0) + if (nano != null) return; + final List data = new ArrayList(); try (BufferedReader br = new BufferedReader( new InputStreamReader(Dummy.class.getResourceAsStream(unicode + ".svg")))) { final String singleLine = br.readLine(); - - final Pattern p = Pattern.compile("\\<[^<>]+\\>"); - final Matcher m = p.matcher(singleLine); - while (m.find()) { - final String s = m.group(0); - if (s.contains("") || s.contains("") - || s.contains("")) { - ugs = stack.remove(0); - } else if (s.contains("")) { - stack.add(0, ugs); - } else if (s.contains(" data = new ArrayList<>(); + private int minGray = 999; + private int maxGray = -1; + private final String svgStart; + private final boolean keepColors; + + private String extractData(String name, String s) { + final Pattern p = Pattern.compile(name + "=\"([^\"]+)\""); + final Matcher m = p.matcher(s); + if (m.find()) + return m.group(1); + + return null; + } + + public SvgNanoParser(String svg, boolean keepColors) { + this(Collections.singletonList(svg), keepColors); + } + + public SvgNanoParser(List svg, boolean keepColors) { + this.svgStart = svg.get(0); + this.keepColors = keepColors; + + for (String singleLine : svg) { + final Pattern p = Pattern.compile("\\<[^<>]+\\>"); + final Matcher m = p.matcher(singleLine); + while (m.find()) { + final String s = m.group(0); + if (s.contains("") || s.contains("") + || s.contains("")) { + ugs = stack.remove(0); + } else if (s.contains("")) { + stack.add(0, ugs); + } else if (s.contains(" { +public class CommandCreateMap extends CommandMultilines2 { public CommandCreateMap() { super(getRegexConcat(), MultilinesStrategy.REMOVE_STARTING_QUOTE); @@ -100,7 +100,7 @@ public class CommandCreateMap extends CommandMultilines2