1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-21 20:45:10 +00:00

Adding contribution from Hisashi Miyashita for SysML v2 support

This commit is contained in:
Arnaud Roques 2020-05-07 16:12:08 +02:00
parent f2529b8b88
commit e9fb57cbbe
215 changed files with 4976 additions and 1898 deletions

View File

@ -97,7 +97,7 @@ public class AnnotatedWorker {
final double y1 = 10;
final double y2 = 10;
final SymbolContext symbolContext = new SymbolContext(getSkinParam().getBackgroundColor(false), HColorUtils.BLACK)
final SymbolContext symbolContext = new SymbolContext(getBackgroundColor(), HColorUtils.BLACK)
.withShadow(getSkinParam().shadowing(null) ? 3 : 0);
final MinMax originalMinMax = TextBlockUtils.getMinMax(original, stringBounder, false);
final TextBlock title = mainFrame.create(new FontConfiguration(getSkinParam(), FontParam.CAPTION, null),
@ -137,6 +137,10 @@ public class AnnotatedWorker {
};
}
private HColor getBackgroundColor() {
return getSkinParam().getBackgroundColor(false);
}
private TextBlock addLegend(TextBlock original) {
final DisplayPositionned legend = annotated.getLegend();
if (legend.isNull()) {
@ -166,8 +170,8 @@ public class AnnotatedWorker {
return TextBlockUtils.empty(0, 0);
}
if (SkinParam.USE_STYLES()) {
final Style style = StyleSignature.of(SName.root, SName.caption).getMergedStyle(
skinParam.getCurrentStyleBuilder());
final Style style = StyleSignature.of(SName.root, SName.caption)
.getMergedStyle(skinParam.getCurrentStyleBuilder());
return style.createTextBlockBordered(caption.getDisplay(), skinParam.getIHtmlColorSet(), skinParam);
}
return caption.getDisplay().create(new FontConfiguration(getSkinParam(), FontParam.CAPTION, null),
@ -182,8 +186,8 @@ public class AnnotatedWorker {
final TextBlock block;
if (SkinParam.USE_STYLES()) {
final Style style = StyleSignature.of(SName.root, SName.title).getMergedStyle(
skinParam.getCurrentStyleBuilder());
final Style style = StyleSignature.of(SName.root, SName.title)
.getMergedStyle(skinParam.getCurrentStyleBuilder());
block = style.createTextBlockBordered(title.getDisplay(), skinParam.getIHtmlColorSet(), skinParam);
} else {
final ISkinParam skinParam = getSkinParam();

View File

@ -38,6 +38,7 @@ package net.sourceforge.plantuml;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
@ -58,7 +59,8 @@ import net.sourceforge.plantuml.ugraphic.UFont;
*
*/
public enum FileFormat {
PNG, SVG, EPS, EPS_TEXT, ATXT, UTXT, XMI_STANDARD, XMI_STAR, XMI_ARGO, SCXML, PDF, MJPEG, ANIMATED_GIF, HTML, HTML5, VDX, LATEX, LATEX_NO_PREAMBLE, BASE64, BRAILLE_PNG, PREPROC;
PNG, SVG, EPS, EPS_TEXT, ATXT, UTXT, XMI_STANDARD, XMI_STAR, XMI_ARGO, SCXML, PDF, MJPEG, ANIMATED_GIF, HTML, HTML5,
VDX, LATEX, LATEX_NO_PREAMBLE, BASE64, BRAILLE_PNG, PREPROC;
/**
* Returns the file format to be used for that format.
@ -89,6 +91,10 @@ public enum FileFormat {
final static private BufferedImage imDummy = new BufferedImage(800, 100, BufferedImage.TYPE_INT_RGB);
final static private Graphics2D gg = imDummy.createGraphics();
static {
// KEY_FRACTIONALMETRICS
gg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
public StringBounder getDefaultStringBounder(TikzFontDistortion tikzFontDistortion) {
if (this == LATEX || this == LATEX_NO_PREAMBLE) {
@ -178,8 +184,8 @@ public enum FileFormat {
if (cpt == 0) {
return changeName(fileName, getFileSuffix());
}
return changeName(fileName, OptionFlags.getInstance().getFileSeparator() + String.format("%03d", cpt)
+ getFileSuffix());
return changeName(fileName,
OptionFlags.getInstance().getFileSeparator() + String.format("%03d", cpt) + getFileSuffix());
}
private File computeFilename(File pngFile, int i) {
@ -233,4 +239,5 @@ public enum FileFormat {
}
return false;
}
}

View File

@ -57,6 +57,7 @@ import javax.swing.UIManager;
import net.sourceforge.plantuml.activitydiagram.ActivityDiagramFactory;
import net.sourceforge.plantuml.classdiagram.ClassDiagramFactory;
import net.sourceforge.plantuml.code.NoPlantumlCompressionException;
import net.sourceforge.plantuml.code.Transcoder;
import net.sourceforge.plantuml.code.TranscoderUtil;
import net.sourceforge.plantuml.command.UmlDiagramFactory;
@ -78,7 +79,7 @@ public class Run {
private static Cypher cypher;
public static void main(String[] argsArray) throws IOException, InterruptedException {
public static void main(String[] argsArray) throws NoPlantumlCompressionException, IOException, InterruptedException {
System.setProperty("log4j.debug", "false");
final long start = System.currentTimeMillis();
if (argsArray.length > 0 && argsArray[0].equalsIgnoreCase("-headless")) {
@ -358,7 +359,7 @@ public class Run {
new Pipe(option, System.out, System.in, charset).managePipe(error);
}
private static void manageAllFiles(Option option, ErrorStatus error) throws IOException, InterruptedException {
private static void manageAllFiles(Option option, ErrorStatus error) throws NoPlantumlCompressionException, InterruptedException {
File lockFile = null;
try {
@ -377,7 +378,7 @@ public class Run {
}
private static void processArgs(Option option, ErrorStatus error) throws IOException, InterruptedException {
private static void processArgs(Option option, ErrorStatus error) throws NoPlantumlCompressionException, InterruptedException {
if (option.isDecodeurl() == false && option.getNbThreads() > 1 && option.isCheckOnly() == false
&& OptionFlags.getInstance().isExtractFromMetadata() == false) {
multithread(option, error);

View File

@ -156,6 +156,14 @@ public class SkinParam implements ISkinParam {
return result;
}
static public void setBetaStyle(boolean betastyle) {
USE_STYLE2.set(betastyle);
}
public static int zeroMargin(int defaultValue) {
return defaultValue;
}
private static final String stereoPatternString = "\\<\\<(.*?)\\>\\>";
private static final Pattern2 stereoPattern = MyPattern.cmpile(stereoPatternString);
@ -176,7 +184,8 @@ public class SkinParam implements ISkinParam {
for (String key2 : cleanForKey(key)) {
params.put(key2, StringUtils.trin(value));
if (key2.startsWith("usebetastyle")) {
USE_STYLE2.set("true".equalsIgnoreCase(value));
final boolean betastyle = "true".equalsIgnoreCase(value);
setBetaStyle(betastyle);
}
if (USE_STYLES()) {
final FromSkinparamToStyle convertor = new FromSkinparamToStyle(key2, value, getCurrentStyleBuilder());

View File

@ -59,11 +59,11 @@ public class SourceStringReader {
final private List<BlockUml> blocks;
public SourceStringReader(String source) {
this(Defines.createEmpty(), source, Collections.<String> emptyList());
this(Defines.createEmpty(), source, Collections.<String>emptyList());
}
public SourceStringReader(String source, String charset) {
this(Defines.createEmpty(), source, "UTF-8", Collections.<String> emptyList());
this(Defines.createEmpty(), source, "UTF-8", Collections.<String>emptyList());
}
public SourceStringReader(Defines defines, String source, List<String> config) {
@ -71,11 +71,11 @@ public class SourceStringReader {
}
public SourceStringReader(Defines defines, String source) {
this(defines, source, "UTF-8", Collections.<String> emptyList());
this(defines, source, "UTF-8", Collections.<String>emptyList());
}
public SourceStringReader(String source, File newCurrentDir) {
this(Defines.createEmpty(), source, "UTF-8", Collections.<String> emptyList(), newCurrentDir);
this(Defines.createEmpty(), source, "UTF-8", Collections.<String>emptyList(), newCurrentDir);
}
public SourceStringReader(Defines defines, String source, String charset, List<String> config) {
@ -157,7 +157,8 @@ public class SourceStringReader {
// final CMapData cmap = new CMapData();
final ImageData imageData = system.exportDiagram(os, numImage, fileFormatOption);
// if (imageData.containsCMapData()) {
// return system.getDescription().getDescription() + BackSlash.BS_N + imageData.getCMapData("plantuml");
// return system.getDescription().getDescription() + BackSlash.BS_N +
// imageData.getCMapData("plantuml");
// }
return system.getDescription();
}
@ -176,9 +177,11 @@ public class SourceStringReader {
final Diagram system = b.getDiagram();
final int nbInSystem = system.getNbImages();
if (numImage < nbInSystem) {
// final ImageData imageData = system.exportDiagram(os, numImage, fileFormatOption);
// final ImageData imageData = system.exportDiagram(os, numImage,
// fileFormatOption);
// if (imageData.containsCMapData()) {
// return system.getDescription().withCMapData(imageData.getCMapData("plantuml"));
// return
// system.getDescription().withCMapData(imageData.getCMapData("plantuml"));
// }
return system.getDescription();
}
@ -223,8 +226,8 @@ public class SourceStringReader {
private void noStartumlFound(OutputStream os, FileFormatOption fileFormatOption, long seed) throws IOException {
final TextBlockBackcolored error = GraphicStrings.createForError(Arrays.asList("No @startuml/@enduml found"),
fileFormatOption.isUseRedForError());
final ImageBuilder imageBuilder = new ImageBuilder(new ColorMapperIdentity(), 1.0, error.getBackcolor(), null,
null, 0, 0, null, false);
final ImageBuilder imageBuilder = ImageBuilder.buildA(new ColorMapperIdentity(), false, null, null, null,
1.0, error.getBackcolor());
imageBuilder.setUDrawable(error);
imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed, os);
}

View File

@ -99,6 +99,10 @@ final public class StringLocated {
return trimmed;
}
// public StringLocated getTrimmedRight() {
// return new StringLocated(StringUtils.trinEnding(this.getString()), location, preprocessorError);
// }
public StringLocated removeInnerComment() {
final String string = s.toString();
final String trim = string.replace('\t', ' ').trim();

View File

@ -456,18 +456,33 @@ public class StringUtils {
if (arg.length() == 0) {
return arg;
}
return trinEndingInternal(arg, getPositionStartNonSpace(arg));
}
private static int getPositionStartNonSpace(String arg) {
int i = 0;
while (i < arg.length() && isSpaceOrTabOrNull(arg.charAt(i))) {
i++;
}
int j = arg.length() - 1;
while (j >= i && isSpaceOrTabOrNull(arg.charAt(j))) {
j--;
}
if (i == 0 && j == arg.length() - 1) {
return i;
}
private static String trinEnding(String arg) {
if (arg.length() == 0) {
return arg;
}
return arg.substring(i, j + 1);
return trinEndingInternal(arg, 0);
}
private static String trinEndingInternal(String arg, int from) {
int j = arg.length() - 1;
while (j >= from && isSpaceOrTabOrNull(arg.charAt(j))) {
j--;
}
if (from == 0 && j == arg.length() - 1) {
return arg;
}
return arg.substring(from, j + 1);
}
private static boolean isSpaceOrTabOrNull(char c) {

View File

@ -207,6 +207,9 @@ public abstract class UmlDiagram extends TitledDiagram implements Diagram, Annot
} catch (Exception e) {
e.printStackTrace();
exportDiagramError(os, e, fileFormatOption, seed, null);
} catch (Error e) {
e.printStackTrace();
exportDiagramError(os, e, fileFormatOption, seed, null);
}
return ImageDataSimple.error();
}
@ -227,8 +230,8 @@ public abstract class UmlDiagram extends TitledDiagram implements Diagram, Annot
strings.addAll(CommandExecutionResult.getStackTrace(exception));
final ImageBuilder imageBuilder = new ImageBuilder(new ColorMapperIdentity(), 1.0, HColorUtils.WHITE, metadata,
null, 0, 0, null, false);
final ImageBuilder imageBuilder = ImageBuilder.buildA(new ColorMapperIdentity(), false,
null, metadata, null, 1.0, HColorUtils.WHITE);
final FlashCodeUtils utils = FlashCodeFactory.getFlashCodeUtils();
final BufferedImage im = utils.exportFlashcode(flash, Color.BLACK, Color.WHITE);

View File

@ -35,6 +35,40 @@
*/
package net.sourceforge.plantuml;
import net.sourceforge.plantuml.style.SName;
public enum UmlDiagramType {
SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, WIRE, HELP
SEQUENCE, STATE, CLASS, OBJECT, ACTIVITY, DESCRIPTION, COMPOSITE, FLOW, TIMING, BPM, NWDIAG, MINDMAP, WBS, WIRE,
HELP;
public SName getStyleName() {
if (this == SEQUENCE) {
return SName.sequenceDiagram;
}
if (this == STATE) {
return SName.stateDiagram;
}
if (this == CLASS) {
return SName.classDiagram;
}
if (this == OBJECT) {
return SName.objectDiagram;
}
if (this == ACTIVITY) {
return SName.activityDiagram;
}
if (this == DESCRIPTION) {
return SName.componentDiagram;
}
if (this == COMPOSITE) {
return SName.componentDiagram;
}
if (this == MINDMAP) {
return SName.mindmapDiagram;
}
if (this == WBS) {
return SName.wbsDiagram;
}
return SName.activityDiagram;
}
}

View File

@ -115,8 +115,8 @@ public class CommandLinkLongActivity extends CommandMultilines2<ActivityDiagram>
@Override
protected CommandExecutionResult executeNow(final ActivityDiagram diagram, BlocLines lines) {
lines = lines.trim(false);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
lines = lines.trim();
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
final IEntity entity1 = CommandLinkActivity.getEntity(diagram, line0, true);
if (entity1 == null) {
@ -157,7 +157,7 @@ public class CommandLinkLongActivity extends CommandMultilines2<ActivityDiagram>
}
}
final List<String> lineLast = StringUtils.getSplit(MyPattern.cmpile(getPatternEnd()), lines.getLast499()
final List<String> lineLast = StringUtils.getSplit(MyPattern.cmpile(getPatternEnd()), lines.getLast()
.getString());
if (StringUtils.isNotEmpty(lineLast.get(0))) {
if (sb.length() > 0 && sb.toString().endsWith(BackSlash.BS_BS_N) == false) {

View File

@ -45,13 +45,12 @@ import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.ISkinSimple;
import net.sourceforge.plantuml.Scale;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.UmlDiagram;
import net.sourceforge.plantuml.UmlDiagramType;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.activitydiagram3.ftile.BoxStyle;
import net.sourceforge.plantuml.activitydiagram3.ftile.ISwimlanesA;
import net.sourceforge.plantuml.activitydiagram3.ftile.SwimlanesAAA;
import net.sourceforge.plantuml.activitydiagram3.ftile.SwimlanesC;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlanes;
import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.core.DiagramDescription;
import net.sourceforge.plantuml.core.ImageData;
@ -63,6 +62,7 @@ import net.sourceforge.plantuml.graphic.USymbol;
import net.sourceforge.plantuml.graphic.color.Colors;
import net.sourceforge.plantuml.sequencediagram.NotePosition;
import net.sourceforge.plantuml.sequencediagram.NoteType;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
@ -76,36 +76,7 @@ public class ActivityDiagram3 extends UmlDiagram {
private SwimlaneStrategy swimlaneStrategy;
private final ISwimlanesA swinlanes = new SwimlanesAAA(getSkinParam(), getPragma());
// private final ISwimlanesA swinlanes = new SwimlanesC(getSkinParam(),
// getPragma());
private ImageData exportDiagramInternalAAA(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException {
// BUG42
// COMPRESSION
swinlanes.computeSize(fileFormatOption.getDefaultStringBounder());
TextBlock result = swinlanes;
result = CompressionXorYBuilder.build(CompressionMode.ON_X, result, fileFormatOption.getDefaultStringBounder());
result = CompressionXorYBuilder.build(CompressionMode.ON_Y, result, fileFormatOption.getDefaultStringBounder());
result = new TextBlockRecentred(result);
final ISkinParam skinParam = getSkinParam();
result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result);
final Dimension2D dim = result.getMinMax(fileFormatOption.getDefaultStringBounder()).getDimension();
final double margin = 10;
final double dpiFactor = getDpiFactor(fileFormatOption, Dimension2DDouble.delta(dim, 2 * margin, 0));
final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), dpiFactor,
fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), margin, margin,
getAnimation());
imageBuilder.setUDrawable(result);
return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os);
}
private final Swimlanes swinlanes = new Swimlanes(getSkinParam(), getPragma());
public ActivityDiagram3(ISkinSimple skinParam) {
super(skinParam);
@ -233,9 +204,6 @@ public class ActivityDiagram3 extends UmlDiagram {
@Override
protected ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException {
if (swinlanes instanceof SwimlanesC == false || swinlanes instanceof SwimlanesAAA) {
return exportDiagramInternalAAA(os, index, fileFormatOption);
}
// BUG42
// COMPRESSION
swinlanes.computeSize(fileFormatOption.getDefaultStringBounder());
@ -249,12 +217,18 @@ public class ActivityDiagram3 extends UmlDiagram {
result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result);
final Dimension2D dim = result.getMinMax(fileFormatOption.getDefaultStringBounder()).getDimension();
final double margin = 10;
final double dpiFactor = getDpiFactor(fileFormatOption, Dimension2DDouble.delta(dim, 2 * margin, 0));
final ClockwiseTopRightBottomLeft margins;
if (SkinParam.USE_STYLES()) {
margins = ClockwiseTopRightBottomLeft.marginForDocument(skinParam.getCurrentStyleBuilder());
} else {
margins = ClockwiseTopRightBottomLeft.margin1margin2(10, 10);
}
final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), dpiFactor,
fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), margin, margin,
getAnimation());
final double dpiFactor = getDpiFactor(fileFormatOption,
Dimension2DDouble.delta(dim, margins.getLeft() + margins.getRight(), 0));
final ImageBuilder imageBuilder = ImageBuilder.buildD(getSkinParam(), margins, getAnimation(),
fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), dpiFactor);
imageBuilder.setUDrawable(result);
return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os);

View File

@ -35,6 +35,8 @@
*/
package net.sourceforge.plantuml.activitydiagram3.command;
import java.util.regex.Matcher;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.Url;
@ -56,7 +58,26 @@ import net.sourceforge.plantuml.graphic.color.Colors;
public class CommandActivity3 extends SingleLineCommand2<ActivityDiagram3> {
public static final String ENDING_GROUP = "(;|\\\\\\\\|(?<![/|<>}\\]])(?:[/<}\\]])|(?<!\\</?\\w{1,5})(?<!\\<img[^>]{1,999})(?<!\\<[&$]\\w{1,999})(?<!\\>)(?:\\>)|(?<!\\|.{1,999})(?:\\|))";
public static final String endingGroup() {
return "(" //
+ ";" //
+ "|" //
+ Matcher.quoteReplacement("\\\\") // that is simply \ character
+ "|" //
+ "(?<![/|<>}\\]])[/<}]" // About /<}
+ "|" //
+ "(?<![/|}\\]])\\]" // About ]
+ "|" //
+ "(?<!\\</?\\w{1,5})(?<!\\<img[^>]{1,999})(?<!\\<[&$]\\w{1,999})(?<!\\>)\\>" // About >
+ "|" //
+ "(?<!\\|.{1,999})\\|" // About |
+ ")";
}
public static void main(String[] args) {
System.err.println(Matcher.quoteReplacement("\\\\"));
System.err.println(Matcher.quoteReplacement("\\\\").equals("\\\\\\\\"));
}
public CommandActivity3() {
super(getRegexConcat());
@ -71,7 +92,7 @@ public class CommandActivity3 extends SingleLineCommand2<ActivityDiagram3> {
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf(":"), //
new RegexLeaf("LABEL", "(.*)"), //
new RegexLeaf("STYLE", ENDING_GROUP), //
new RegexLeaf("STYLE", endingGroup()), //
RegexLeaf.end());
}

View File

@ -57,7 +57,7 @@ public class CommandActivityLong3 extends CommandMultilines2<ActivityDiagram3> {
@Override
public String getPatternEnd() {
return "^(.*)" + CommandActivity3.ENDING_GROUP + "$";
return "^(.*)" + CommandActivity3.endingGroup() + "$";
}
private static ColorParser color() {
@ -75,11 +75,11 @@ public class CommandActivityLong3 extends CommandMultilines2<ActivityDiagram3> {
@Override
protected CommandExecutionResult executeNow(ActivityDiagram3 diagram, BlocLines lines) {
lines = lines.removeEmptyColumns();
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
final Colors colors = color().getColor(line0, diagram.getSkinParam().getIHtmlColorSet());
// final HtmlColor color = diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(line0.get("COLOR", 0));
final BoxStyle style = BoxStyle.fromChar(lines.getLastChar());
lines = lines.removeStartingAndEnding2(line0.get("DATA", 0));
lines = lines.removeStartingAndEnding(line0.get("DATA", 0), 1);
diagram.addActivity(lines.toDisplay(), style, null, colors);
return CommandExecutionResult.ok();
}

View File

@ -74,7 +74,7 @@ public class CommandArrowLong3 extends CommandMultilines2<ActivityDiagram3> {
@Override
protected CommandExecutionResult executeNow(ActivityDiagram3 diagram, BlocLines lines) {
lines = lines.removeEmptyColumns();
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
// final HtmlColor color = diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(line0.get("COLOR", 0));
// diagram.setColorNextArrow(Rainbow.fromColor(color));
final String colorString = line0.get("COLOR", 0);
@ -83,7 +83,7 @@ public class CommandArrowLong3 extends CommandMultilines2<ActivityDiagram3> {
.colorArrowSeparationSpace());
diagram.setColorNextArrow(rainbow);
}
lines = lines.removeStartingAndEnding2(line0.get("LABEL", 0));
lines = lines.removeStartingAndEnding(line0.get("LABEL", 0), 1);
diagram.setLabelNextArrow(lines.toDisplay());
return CommandExecutionResult.ok();
}

View File

@ -58,7 +58,7 @@ public class CommandBackward3 extends SingleLineCommand2<ActivityDiagram3> {
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf(":"), //
new RegexLeaf("LABEL", "(.*)"), //
new RegexLeaf("STYLE", CommandActivity3.ENDING_GROUP), //
new RegexLeaf("STYLE", CommandActivity3.endingGroup()), //
RegexLeaf.end());
}

View File

@ -69,7 +69,7 @@ public class CommandNoteLong3 extends CommandMultilines2<ActivityDiagram3> {
@Override
protected CommandExecutionResult executeNow(final ActivityDiagram3 diagram, BlocLines lines) {
// final List<? extends CharSequence> in = StringUtils.removeEmptyColumns2(lines.subList(1, lines.size() - 1));
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
final NotePosition position = NotePosition.defaultLeft(line0.get("POSITION", 0));

View File

@ -66,7 +66,7 @@ public class CommandRepeat3 extends SingleLineCommand2<ActivityDiagram3> {
new RegexLeaf("repeat"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexOptional(new RegexLeaf("LABEL", ":(.*?)")), //
new RegexOptional(new RegexLeaf("STYLE", CommandActivity3.ENDING_GROUP)), //
new RegexOptional(new RegexLeaf("STYLE", CommandActivity3.endingGroup())), //
// new RegexLeaf(";?"), //
RegexLeaf.end());
}

View File

@ -80,9 +80,9 @@ public class CommandRepeatWhile3Multilines extends CommandMultilines3<ActivityDi
@Override
protected CommandExecutionResult executeNow(ActivityDiagram3 diagram, BlocLines lines) {
lines = lines.trim(false);
final RegexResult line0 = getStartingPattern().matcher(StringUtils.trin(lines.getFirst499().getString()));
final RegexResult lineLast = getPatternEnd2().matcher(lines.getLast499().getString());
lines = lines.trim();
final RegexResult line0 = getStartingPattern().matcher(StringUtils.trin(lines.getFirst().getString()));
final RegexResult lineLast = getPatternEnd2().matcher(lines.getLast().getString());
// System.err.println("line0=" + line0);
// System.err.println("linesLast=" + lineLast);

View File

@ -42,8 +42,8 @@ import java.util.List;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.MinMax;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UBackground;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UParam;

View File

@ -125,8 +125,8 @@ public class FtileAssemblySimple extends AbstractTextBlock implements Ftile {
public FtileGeometry calculateDimension(StringBounder stringBounder) {
if (calculateDimension == null) {
calculateDimension = tile1.calculateDimension(stringBounder).appendBottom(
tile2.calculateDimension(stringBounder));
calculateDimension = tile1.calculateDimension(stringBounder)
.appendBottom(tile2.calculateDimension(stringBounder));
}
return calculateDimension;
}

View File

@ -114,6 +114,10 @@ public class FtileGeometry extends Dimension2D {
return new FtileGeometry(width, height + northHeight, left, inY, outY);
}
// public FtileGeometry incInnerHeight(double northHeight) {
// return new FtileGeometry(width, height + northHeight, left, inY, outY + northHeight);
// }
public FtileGeometry(Dimension2D dim, double left, double inY, double outY) {
this(dim.getWidth(), dim.getHeight(), left, inY, outY);
}

View File

@ -43,12 +43,12 @@ import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class FtileHeightFixed extends AbstractFtile {
public class FtileHeightFixedCentered extends AbstractFtile {
private final Ftile tile;
private final double fixedHeight;
public FtileHeightFixed(Ftile tile, double fixedHeight) {
public FtileHeightFixedCentered(Ftile tile, double fixedHeight) {
super(tile.skinParam());
this.tile = tile;
this.fixedHeight = fixedHeight;

View File

@ -0,0 +1,94 @@
/* ========================================================================
* 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.activitydiagram3.ftile;
import java.util.Set;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class FtileHeightFixedMarged extends AbstractFtile {
private final Ftile tile;
private final double ymargin1;
private final double ymargin2;
public FtileHeightFixedMarged(double ymargin1, Ftile tile, double ymargin2) {
super(tile.skinParam());
this.tile = tile;
this.ymargin1 = ymargin1;
this.ymargin2 = ymargin2;
}
@Override
public LinkRendering getInLinkRendering() {
return tile.getInLinkRendering();
}
@Override
public LinkRendering getOutLinkRendering() {
return tile.getOutLinkRendering();
}
public Set<Swimlane> getSwimlanes() {
return tile.getSwimlanes();
}
public Swimlane getSwimlaneIn() {
return tile.getSwimlaneIn();
}
public Swimlane getSwimlaneOut() {
return tile.getSwimlaneOut();
}
@Override
protected FtileGeometry calculateDimensionFtile(StringBounder stringBounder) {
final FtileGeometry dim = tile.calculateDimension(stringBounder);
return dim.translate(getTranslate(stringBounder)).fixedHeight(ymargin1 + dim.getHeight() + ymargin2);
}
private UTranslate getTranslate(StringBounder stringBounder) {
return UTranslate.dy(ymargin1);
}
public void drawU(UGraphic ug) {
ug.apply(getTranslate(ug.getStringBounder())).draw(tile);
}
}

View File

@ -43,12 +43,12 @@ import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
public class FtileMinWidth extends FtileDecorate {
public class FtileMinWidthCentered extends FtileDecorate {
private final double minWidth;
private FtileGeometry calculateDimensionInternal;
public FtileMinWidth(Ftile tile, double minWidth) {
public FtileMinWidthCentered(Ftile tile, double minWidth) {
super(tile);
this.minWidth = minWidth;
}

View File

@ -87,7 +87,7 @@ import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
import net.sourceforge.plantuml.ugraphic.comp.SlotFinder;
import net.sourceforge.plantuml.utils.MathUtils;
public class SwimlanesAAA extends AbstractTextBlock implements ISwimlanesA, TextBlock, Styleable {
public class Swimlanes extends AbstractTextBlock implements TextBlock, Styleable {
private final ISkinParam skinParam;;
private final Pragma pragma;
@ -121,7 +121,7 @@ public class SwimlanesAAA extends AbstractTextBlock implements ISwimlanesA, Text
return StyleSignature.of(SName.root, SName.element, SName.classDiagram, SName.swimlane);
}
public SwimlanesAAA(ISkinParam skinParam, Pragma pragma) {
public Swimlanes(ISkinParam skinParam, Pragma pragma) {
this.skinParam = skinParam;
this.pragma = pragma;
}

View File

@ -1,333 +0,0 @@
/* ========================================================================
* 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.activitydiagram3.ftile;
import java.awt.geom.Dimension2D;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.Pragma;
import net.sourceforge.plantuml.activitydiagram3.Instruction;
import net.sourceforge.plantuml.activitydiagram3.InstructionList;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAddNote;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAddUrl;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorAssembly;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorCreateGroup;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorCreateParallel;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorIf;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorRepeat;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorSwitch;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.FtileFactoryDelegatorWhile;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.UGraphicInterceptorOneSwimlane;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.VCompactFactory;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.AbstractTextBlock;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.TextBlockUtils;
import net.sourceforge.plantuml.graphic.UGraphicDelegator;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.style.SName;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.style.StyleSignature;
import net.sourceforge.plantuml.style.Styleable;
import net.sourceforge.plantuml.svek.UGraphicForSnake;
import net.sourceforge.plantuml.ugraphic.LimitFinder;
import net.sourceforge.plantuml.ugraphic.MinMax;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UShape;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
import net.sourceforge.plantuml.ugraphic.comp.SlotFinder;
import net.sourceforge.plantuml.ugraphic.comp.SlotSet;
import net.sourceforge.plantuml.utils.MathUtils;
public class SwimlanesA extends AbstractTextBlock implements ISwimlanesA, TextBlock, Styleable {
protected final ISkinParam skinParam;;
private final Pragma pragma;
protected final List<Swimlane> swimlanes = new ArrayList<Swimlane>();
private Swimlane currentSwimlane = null;
private final Instruction root = new InstructionList();
private Instruction currentInstruction = root;
private LinkRendering nextLinkRenderer = LinkRendering.none();
private Style style;
public StyleSignature getDefaultStyleDefinition() {
return StyleSignature.of(SName.root, SName.element, SName.classDiagram, SName.swimlane);
}
public SwimlanesA(ISkinParam skinParam, Pragma pragma) {
this.skinParam = skinParam;
this.pragma = pragma;
}
protected Style getStyle() {
if (style == null) {
this.style = getDefaultStyleDefinition().getMergedStyle(skinParam.getCurrentStyleBuilder());
}
return style;
}
private FtileFactory getFtileFactory(StringBounder stringBounder) {
FtileFactory factory = new VCompactFactory(skinParam, stringBounder);
factory = new FtileFactoryDelegatorAddUrl(factory);
factory = new FtileFactoryDelegatorAssembly(factory);
factory = new FtileFactoryDelegatorIf(factory, pragma);
factory = new FtileFactoryDelegatorSwitch(factory);
factory = new FtileFactoryDelegatorWhile(factory);
factory = new FtileFactoryDelegatorRepeat(factory);
factory = new FtileFactoryDelegatorCreateParallel(factory);
// factory = new FtileFactoryDelegatorCreateParallelAddingMargin(new
// FtileFactoryDelegatorCreateParallel1(factory));
factory = new FtileFactoryDelegatorAddNote(factory);
factory = new FtileFactoryDelegatorCreateGroup(factory);
return factory;
}
public void swimlane(String name, HColor color, Display label) {
currentSwimlane = getOrCreate(name);
if (color != null) {
currentSwimlane.setSpecificColorTOBEREMOVED(ColorType.BACK, color);
}
if (Display.isNull(label) == false) {
currentSwimlane.setDisplay(label);
}
}
private Swimlane getOrCreate(String name) {
for (Swimlane s : swimlanes) {
if (s.getName().equals(name)) {
return s;
}
}
final Swimlane result = new Swimlane(name);
swimlanes.add(result);
return result;
}
class Cross extends UGraphicDelegator {
private Cross(UGraphic ug) {
super(ug);
}
@Override
public void draw(UShape shape) {
if (shape instanceof Ftile) {
final Ftile tile = (Ftile) shape;
tile.drawU(this);
} else if (shape instanceof Connection) {
final Connection connection = (Connection) shape;
final Ftile tile1 = connection.getFtile1();
final Ftile tile2 = connection.getFtile2();
if (tile1 == null || tile2 == null) {
return;
}
if (tile1.getSwimlaneOut() != tile2.getSwimlaneIn()) {
final ConnectionCross connectionCross = new ConnectionCross(connection);
connectionCross.drawU(getUg());
}
}
}
public UGraphic apply(UChange change) {
return new Cross(getUg().apply(change));
}
}
protected double separationMargin() {
return 10;
}
// private TextBlock full;
public final void computeSize(StringBounder stringBounder) {
final SlotFinder ug = new SlotFinder(CompressionMode.ON_Y, stringBounder);
if (swimlanes.size() > 1) {
TextBlock full = root.createFtile(getFtileFactory(stringBounder));
computeSizeInternal(ug, full);
}
}
public final void drawU(UGraphic ug) {
TextBlock full = root.createFtile(getFtileFactory(ug.getStringBounder()));
ug = new UGraphicForSnake(ug);
if (swimlanes.size() > 1) {
drawWhenSwimlanes(ug, full);
} else {
// BUG42
full = new TextBlockInterceptorUDrawable(full);
full.drawU(ug);
ug.flushUg();
}
}
static private void printDebug(UGraphic ug, SlotSet slot, HColor col, TextBlock full) {
slot.drawDebugX(ug.apply(col).apply(col.bg()), full.calculateDimension(ug.getStringBounder()).getHeight());
}
protected void drawWhenSwimlanes(final UGraphic ug, TextBlock full) {
final StringBounder stringBounder = ug.getStringBounder();
final Dimension2D dimensionFull = full.calculateDimension(stringBounder);
double x2 = 0;
for (Swimlane swimlane : swimlanes) {
final HColor back = swimlane.getColors(skinParam).getColor(ColorType.BACK);
if (back != null) {
UGraphic background = ug.apply(back.bg()).apply(back);
background = background.apply(UTranslate.dx(x2));
drawBackColor(background, swimlane, dimensionFull);
}
full.drawU(new UGraphicInterceptorOneSwimlane(ug, swimlane, swimlanes).apply(swimlane.getTranslate())
.apply(getTitleHeightTranslate(stringBounder)));
x2 += swimlane.getActualWidth();
}
final Cross cross = new Cross(ug.apply(getTitleHeightTranslate(stringBounder)));
full.drawU(cross);
cross.flushUg();
}
protected void drawBackColor(UGraphic ug, Swimlane swimlane, Dimension2D dimensionFull) {
final StringBounder stringBounder = ug.getStringBounder();
final double height = dimensionFull.getHeight() + getTitleHeightTranslate(stringBounder).getDy();
final URectangle rectangle = new URectangle(swimlane.getActualWidth(), height).ignoreForCompressionOnX()
.ignoreForCompressionOnY();
ug.draw(rectangle);
}
protected UTranslate getTitleHeightTranslate(final StringBounder stringBounder) {
return new UTranslate();
}
private void computeDrawingWidths(UGraphic ug, TextBlock full) {
final StringBounder stringBounder = ug.getStringBounder();
for (Swimlane swimlane : swimlanes) {
final LimitFinder limitFinder = new LimitFinder(stringBounder, false);
final UGraphicInterceptorOneSwimlane interceptor = new UGraphicInterceptorOneSwimlane(
new UGraphicForSnake(limitFinder), swimlane, swimlanes);
full.drawU(interceptor);
interceptor.flushUg();
final MinMax minMax = limitFinder.getMinMax();
swimlane.setMinMax(minMax);
}
}
private void computeSizeInternal(UGraphic ug, TextBlock full) {
computeDrawingWidths(ug, full);
double x1 = 0;
double swimlaneWidth = skinParam.swimlaneWidth();
if (swimlaneWidth == ISkinParam.SWIMLANE_WIDTH_SAME) {
for (Swimlane swimlane : swimlanes) {
swimlaneWidth = Math.max(swimlaneWidth, rawDrawingWidth(swimlane));
}
}
for (Swimlane swimlane : swimlanes) {
final double swimlaneActualWidth = swimlaneActualWidth(ug.getStringBounder(), swimlaneWidth, swimlane);
final UTranslate translate = UTranslate.dx(x1 - swimlane.getMinMax().getMinX() + separationMargin()
+ (swimlaneActualWidth - rawDrawingWidth(swimlane)) / 2.0);
swimlane.setTranslate(translate);
swimlane.setWidth(swimlaneActualWidth);
x1 += swimlaneActualWidth;
}
}
protected double swimlaneActualWidth(StringBounder stringBounder, double swimlaneWidth, Swimlane swimlane) {
return MathUtils.max(swimlaneWidth, rawDrawingWidth(swimlane));
}
private double rawDrawingWidth(Swimlane swimlane) {
return swimlane.getMinMax().getWidth() + 2 * separationMargin();
}
public Dimension2D calculateDimension(StringBounder stringBounder) {
return getMinMax(stringBounder).getDimension();
}
public Instruction getCurrent() {
return currentInstruction;
}
public void setCurrent(Instruction current) {
this.currentInstruction = current;
}
public LinkRendering nextLinkRenderer() {
return nextLinkRenderer;
}
public void setNextLinkRenderer(LinkRendering link) {
if (link == null) {
throw new IllegalArgumentException();
}
this.nextLinkRenderer = link;
}
public Swimlane getCurrentSwimlane() {
return currentSwimlane;
}
private MinMax cachedMinMax;
@Override
public MinMax getMinMax(StringBounder stringBounder) {
if (cachedMinMax == null) {
cachedMinMax = TextBlockUtils.getMinMax(this, stringBounder, false);
}
return cachedMinMax;
}
}

View File

@ -1,144 +0,0 @@
/* ========================================================================
* 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.activitydiagram3.ftile;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineBreakStrategy;
import net.sourceforge.plantuml.Pragma;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.graphic.FontConfiguration;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.URectangle;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.utils.MathUtils;
public class SwimlanesB extends SwimlanesA {
public SwimlanesB(ISkinParam skinParam, Pragma pragma) {
super(skinParam, pragma);
}
@Override
protected void drawWhenSwimlanes(UGraphic ug, TextBlock full) {
super.drawWhenSwimlanes(ug, full);
double x2 = 0;
final StringBounder stringBounder = ug.getStringBounder();
HColor color = skinParam.getHtmlColor(ColorParam.swimlaneTitleBackground, null, false);
if (SkinParam.USE_STYLES()) {
color = getStyle().value(PName.BackGroundColor).asColor(skinParam.getIHtmlColorSet());
}
if (color != null) {
final double titleHeight = getTitlesHeight(stringBounder);
final URectangle back = new URectangle(getTitlesWidth(stringBounder), titleHeight).ignoreForCompressionOnX().ignoreForCompressionOnY();
ug.apply(color.bg()).apply(color).draw(back);
}
for (Swimlane swimlane : swimlanes) {
final TextBlock swTitle = getTitle(swimlane);
final double titleWidth = swTitle.calculateDimension(stringBounder).getWidth();
final double posTitle = x2 + (swimlane.getActualWidth() - titleWidth) / 2;
swTitle.drawU(ug.apply(UTranslate.dx(posTitle)));
x2 += swimlane.getActualWidth();
}
}
private double getTitlesWidth(StringBounder stringBounder) {
double x2 = 0;
for (Swimlane swimlane : swimlanes) {
x2 += swimlane.getActualWidth();
}
return x2;
}
private TextBlock getTitle(Swimlane swimlane) {
final HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT;
FontConfiguration fontConfiguration = new FontConfiguration(skinParam, FontParam.SWIMLANE_TITLE, null);
if (SkinParam.USE_STYLES()) {
fontConfiguration = getStyle().getFontConfiguration(skinParam.getIHtmlColorSet());
}
LineBreakStrategy wrap = getWrap();
if (wrap.isAuto()) {
wrap = new LineBreakStrategy("" + ((int) swimlane.getActualWidth()));
}
return swimlane.getDisplay().create9(fontConfiguration, horizontalAlignment, skinParam, wrap);
}
private LineBreakStrategy getWrap() {
LineBreakStrategy wrap = skinParam.swimlaneWrapTitleWidth();
if (wrap == LineBreakStrategy.NONE) {
wrap = skinParam.wrapWidth();
}
return wrap;
}
@Override
protected double swimlaneActualWidth(StringBounder stringBounder, double swimlaneWidth, Swimlane swimlane) {
final double m1 = super.swimlaneActualWidth(stringBounder, swimlaneWidth, swimlane);
if (getWrap().isAuto()) {
return m1;
}
final double titleWidth = getTitle(swimlane).calculateDimension(stringBounder).getWidth();
return MathUtils.max(m1, titleWidth + 2 * separationMargin());
}
@Override
protected UTranslate getTitleHeightTranslate(final StringBounder stringBounder) {
double titlesHeight = getTitlesHeight(stringBounder);
return UTranslate.dy(titlesHeight > 0 ? titlesHeight + 5 : 0);
}
private double getTitlesHeight(StringBounder stringBounder) {
double titlesHeight = 0;
for (Swimlane swimlane : swimlanes) {
final TextBlock swTitle = getTitle(swimlane);
titlesHeight = Math.max(titlesHeight, swTitle.calculateDimension(stringBounder).getHeight());
}
return titlesHeight;
}
}

View File

@ -1,93 +0,0 @@
/* ========================================================================
* 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.activitydiagram3.ftile;
import java.awt.geom.Dimension2D;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.LineParam;
import net.sourceforge.plantuml.Pragma;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.skin.rose.Rose;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.ULine;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
public class SwimlanesC extends SwimlanesB {
public SwimlanesC(ISkinParam skinParam, Pragma pragma) {
super(skinParam, pragma);
}
@Override
protected void drawWhenSwimlanes(UGraphic ug, TextBlock full) {
super.drawWhenSwimlanes(ug, full);
double x2 = 0;
final StringBounder stringBounder = ug.getStringBounder();
final Dimension2D dimensionFull = full.calculateDimension(stringBounder);
final UTranslate titleHeightTranslate = getTitleHeightTranslate(stringBounder);
for (Swimlane swimlane : swimlanes) {
drawSeparation(ug.apply(UTranslate.dx(x2)), dimensionFull.getHeight() + titleHeightTranslate.getDy());
x2 += swimlane.getActualWidth();
}
drawSeparation(ug.apply(UTranslate.dx(x2)), dimensionFull.getHeight() + titleHeightTranslate.getDy());
}
private void drawSeparation(UGraphic ug, double height) {
HColor color = skinParam.getHtmlColor(ColorParam.swimlaneBorder, null, false);
if (color == null) {
color = ColorParam.swimlaneBorder.getDefaultValue();
}
UStroke thickness = Rose.getStroke(skinParam, LineParam.swimlaneBorder, 2);
if (SkinParam.USE_STYLES()) {
color = getStyle().value(PName.LineColor).asColor(skinParam.getIHtmlColorSet());
thickness = getStyle().getStroke();
}
ug.apply(thickness).apply(color).draw(ULine.vline(height));
}
}

View File

@ -53,7 +53,6 @@ import net.sourceforge.plantuml.ugraphic.UPolygon;
import net.sourceforge.plantuml.ugraphic.UStroke;
import net.sourceforge.plantuml.ugraphic.UTranslate;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import net.sourceforge.plantuml.ugraphic.color.HColorUtils;
import net.sourceforge.plantuml.ugraphic.comp.CompressionMode;
public class Worm implements Iterable<Point2D.Double> {
@ -101,10 +100,14 @@ public class Worm implements Iterable<Point2D.Double> {
}
final HColor arrowHeadColor = colorAndStyle.getArrowHeadColor();
if (arrowHeadColor != null && arrowHeadColor.equals(HColorUtils.transparent()) == false) {
ug = ug.apply(arrowHeadColor);
ug = ug.apply(arrowHeadColor.bg());
if (arrowHeadColor == null) {
throw new IllegalStateException();
}
// if (arrowHeadColor == null || arrowHeadColor.equals(HColorUtils.transparent())) {
// return;
// }
ug = ug.apply(arrowHeadColor);
ug = ug.apply(arrowHeadColor.bg());
if (startDecoration != null) {
ug = ug.apply(new UStroke(1.5));
@ -212,6 +215,12 @@ public class Worm implements Iterable<Point2D.Double> {
}
public void addPoint(double x, double y) {
if (Double.isNaN(x)) {
throw new IllegalArgumentException();
}
if (Double.isNaN(y)) {
throw new IllegalArgumentException();
}
if (points.size() > 0) {
final Point2D last = getLast();
if (last.getX() == x && last.getY() == y) {

View File

@ -38,8 +38,8 @@ package net.sourceforge.plantuml.activitydiagram3.ftile;
import net.sourceforge.plantuml.Url;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.ugraphic.MinMax;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UBackground;
import net.sourceforge.plantuml.ugraphic.UChange;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UParam;
import net.sourceforge.plantuml.ugraphic.UParamNull;

View File

@ -35,7 +35,7 @@
*/
package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact;
import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.FontParam;
@ -43,7 +43,8 @@ import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileHeightFixedCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
import net.sourceforge.plantuml.creole.CreoleMode;
import net.sourceforge.plantuml.cucadiagram.Display;
@ -64,10 +65,7 @@ public abstract class AbstractParallelFtilesBuilder {
private final ISkinParam skinParam;
private final StringBounder stringBounder;
private final List<Ftile> list;
private final Ftile middle;
private final FtileGeometry middleDimension;
protected final List<Ftile> list99 = new ArrayList<Ftile>();
public StyleSignature getDefaultStyleDefinition() {
return StyleSignature.of(SName.root, SName.element, SName.activityDiagram, SName.activity);
@ -77,23 +75,47 @@ public abstract class AbstractParallelFtilesBuilder {
return StyleSignature.of(SName.root, SName.element, SName.activityDiagram, SName.arrow);
}
public AbstractParallelFtilesBuilder(ISkinParam skinParam, StringBounder stringBounder, final List<Ftile> list,
Ftile middle) {
public AbstractParallelFtilesBuilder(ISkinParam skinParam, StringBounder stringBounder, List<Ftile> all) {
this.skinParam = skinParam;
this.stringBounder = stringBounder;
this.list = list;
this.middle = middle;
this.middleDimension = middle.calculateDimension(getStringBounder());
this.list99.addAll(getFoo2(all));
}
public final Ftile build() {
final Ftile step1 = doStep1();
return doStep2(step1);
protected List<Ftile> getFoo2(List<Ftile> all) {
final double maxHeight = computeMaxHeight(all);
final List<Ftile> result = new ArrayList<Ftile>();
for (Ftile ftile : all) {
final Ftile newFtile = computeNewFtile(ftile, maxHeight);
result.add(newFtile);
}
return result;
}
protected abstract Ftile doStep1();
private Ftile computeNewFtile(Ftile ftile, double maxHeight) {
final double spaceArroundBlackBar = 20;
final double xMargin = 14;
Ftile tmp;
tmp = FtileUtils.addHorizontalMargin(ftile, xMargin);
tmp = new FtileHeightFixedCentered(tmp, maxHeight + 2 * spaceArroundBlackBar);
return tmp;
}
protected abstract Ftile doStep2(Ftile step1);
final protected double computeMaxHeight(List<Ftile> all) {
double height = 0;
for (Ftile tmp : all) {
height = Math.max(height, tmp.calculateDimension(getStringBounder()).getHeight());
}
return height;
}
public final Ftile build(Ftile inner) {
final Ftile step1 = doStep1(inner);
return doStep2(inner, step1);
}
protected abstract Ftile doStep1(Ftile inner);
protected abstract Ftile doStep2(Ftile inner, Ftile step1);
protected StringBounder getStringBounder() {
return stringBounder;
@ -128,20 +150,12 @@ public abstract class AbstractParallelFtilesBuilder {
return getTextBlock(display);
}
protected final List<Ftile> getList() {
return Collections.unmodifiableList(list);
}
protected final Ftile getMiddle() {
return middle;
}
protected final double getHeightOfMiddle() {
return middleDimension.getHeight();
protected final double getHeightOfMiddle(Ftile middle) {
return middle.calculateDimension(getStringBounder()).getHeight();
}
protected Swimlane swimlaneOutForStep2() {
return list.get(list.size() - 1).getSwimlaneOut();
return list99.get(list99.size() - 1).getSwimlaneOut();
}
}

View File

@ -35,56 +35,35 @@
*/
package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact;
import java.awt.geom.Dimension2D;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.activitydiagram3.ForkStyle;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactoryDelegator;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileHeightFixed;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
public class FtileFactoryDelegatorCreateParallel extends FtileFactoryDelegator {
private final double spaceArroundBlackBar = 20;
private final double xMargin = 14;
public final class FtileFactoryDelegatorCreateParallel extends FtileFactoryDelegator {
public FtileFactoryDelegatorCreateParallel(FtileFactory factory) {
super(factory);
}
private Ftile allOverlapped(Swimlane swimlane, List<Ftile> all, ForkStyle style, String label) {
return new FtileForkInnerOverlapped(all);
}
@Override
public Ftile createParallel(List<Ftile> all, ForkStyle style, String label, Swimlane in, Swimlane out) {
final Dimension2D dimSuper = super.createParallel(all, style, label, in, out).calculateDimension(
getStringBounder());
final double height1 = dimSuper.getHeight() + 2 * spaceArroundBlackBar;
final List<Ftile> list = new ArrayList<Ftile>();
for (Ftile tmp : all) {
list.add(new FtileHeightFixed(FtileUtils.addHorizontalMargin(tmp, xMargin), height1));
}
final Ftile inner = super.createParallel(list, style, label, in, out);
AbstractParallelFtilesBuilder builder;
if (style == ForkStyle.SPLIT) {
builder = new ParallelBuilderSplit(skinParam(), getStringBounder(), list, inner);
builder = new ParallelBuilderSplit(skinParam(), getStringBounder(), all);
} else if (style == ForkStyle.MERGE) {
builder = new ParallelBuilderMerge(skinParam(), getStringBounder(), list, inner);
builder = new ParallelBuilderMerge(skinParam(), getStringBounder(), all);
} else if (style == ForkStyle.FORK) {
builder = new ParallelBuilderFork(skinParam(), getStringBounder(), list, inner, label, in, out);
builder = new ParallelBuilderFork(skinParam(), getStringBounder(), label, in, out, all);
} else {
throw new IllegalStateException();
}
return builder.build();
final Ftile inner = super.createParallel(builder.list99, style, label, in, out);
return builder.build(inner);
}
}

View File

@ -1,73 +0,0 @@
/* ========================================================================
* 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.activitydiagram3.ftile.vcompact;
import java.awt.geom.Dimension2D;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.plantuml.activitydiagram3.ForkStyle;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactoryDelegator;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileHeightFixed;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
public class FtileFactoryDelegatorCreateParallelAddingMargin extends FtileFactoryDelegator {
private final double spaceArroundBlackBar = 20;
private final double xMargin = 14;
public FtileFactoryDelegatorCreateParallelAddingMargin(FtileFactory factory) {
super(factory);
}
@Override
public Ftile createParallel(List<Ftile> all, ForkStyle style, String label, Swimlane in, Swimlane out) {
final Dimension2D dimSuper = super.createParallel(all, style, label, in, out).calculateDimension(
getStringBounder());
final double height1 = dimSuper.getHeight() + 2 * spaceArroundBlackBar;
final List<Ftile> list = new ArrayList<Ftile>();
for (Ftile tmp : all) {
list.add(new FtileHeightFixed(FtileUtils.addHorizontalMargin(tmp, xMargin), height1));
}
return super.createParallel(list, style, label, in, out);
}
}

View File

@ -45,7 +45,7 @@ import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactoryDelegator;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidthCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond.FtileSwitchNude;
import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond.FtileSwitchWithDiamonds;
@ -77,7 +77,7 @@ public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator {
private Ftile createNude(Swimlane swimlane, List<Branch> branches) {
final List<Ftile> ftiles = new ArrayList<Ftile>();
for (Branch branch : branches) {
ftiles.add(new FtileMinWidth(branch.getFtile(), 30));
ftiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
return new FtileSwitchNude(ftiles, swimlane);
}
@ -85,7 +85,7 @@ public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator {
private Ftile createWithDiamonds(Swimlane swimlane, List<Branch> branches, Display labelTest) {
final List<Ftile> ftiles = new ArrayList<Ftile>();
for (Branch branch : branches) {
ftiles.add(new FtileMinWidth(branch.getFtile(), 30));
ftiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
final Ftile diamond1 = getDiamond1(swimlane, branches.get(0), labelTest);
final Ftile diamond2 = getDiamond2(swimlane, branches.get(0));
@ -98,7 +98,7 @@ public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator {
final Ftile diamond1 = getDiamond1(swimlane, branches.get(0), labelTest);
final Ftile diamond2 = getDiamond2(swimlane, branches.get(0));
for (Branch branch : branches) {
ftiles.add(new FtileMinWidth(branch.getFtile(), 30));
ftiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
final Rainbow arrowColor = Rainbow.build(skinParam());
if (ftiles.size() == 1) {

View File

@ -37,7 +37,6 @@ package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.nio.channels.IllegalSelectorException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -46,7 +45,6 @@ import java.util.List;
import java.util.Set;
import net.sourceforge.plantuml.Dimension2DDouble;
import net.sourceforge.plantuml.ISkinParam;
import net.sourceforge.plantuml.activitydiagram3.Branch;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.activitydiagram3.ftile.AbstractConnection;
@ -58,7 +56,7 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileAssemblySimple;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidthCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.MergeStrategy;
import net.sourceforge.plantuml.activitydiagram3.ftile.Snake;
@ -152,10 +150,10 @@ class FtileIfLongHorizontal extends AbstractFtile {
final List<Ftile> tiles = new ArrayList<Ftile>();
for (Branch branch : thens) {
tiles.add(new FtileMinWidth(branch.getFtile(), 30));
tiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
final Ftile tile2 = new FtileMinWidth(branch2.getFtile(), 30);
final Ftile tile2 = new FtileMinWidthCentered(branch2.getFtile(), 30);
List<Ftile> diamonds = new ArrayList<Ftile>();
List<Double> inlabelSizes = new ArrayList<Double>();
@ -237,13 +235,6 @@ class FtileIfLongHorizontal extends AbstractFtile {
return FtileUtils.addConnection(result, conns);
}
static private TextBlock getSpecial(Branch branch, FontConfiguration fcTest, ISkinParam skinParam) {
if (branch.getSpecial() == null) {
return null;
}
return branch.getSpecial().getDisplay().create(fcTest, HorizontalAlignment.LEFT, skinParam);
}
class ConnectionHorizontal extends AbstractConnection {
private final Rainbow color;
@ -487,7 +478,7 @@ class FtileIfLongHorizontal extends AbstractFtile {
final double minX = minmax[0];
final double maxX = minmax[1];
if (minX == Double.NaN || maxX == Double.NaN) {
if (Double.isNaN(minX) || Double.isNaN(maxX)) {
return;
}
@ -498,9 +489,21 @@ class FtileIfLongHorizontal extends AbstractFtile {
ug.draw(s);
}
private Double getLeftOut(final StringBounder stringBounder) {
final FtileGeometry dim = calculateDimension(stringBounder);
if (dim.hasPointOut()) {
return dim.getLeft();
}
return null;
}
private double[] getMinmax(StringBounder stringBounder, double width, List<Ftile> allTiles, Swimlane intoSw,
List<Swimlane> allSwimlanes) {
final int current = allSwimlanes.indexOf(intoSw);
final Double leftOut = getLeftOut(stringBounder);
if (leftOut == null)
return new double[] { Double.NaN, Double.NaN };
if (current == -1) {
throw new IllegalStateException();
}
@ -510,6 +513,8 @@ class FtileIfLongHorizontal extends AbstractFtile {
return new double[] { Double.NaN, Double.NaN };
double minX = current != first ? 0 : width;
double maxX = current != last ? width : 0;
minX = Math.min(minX, leftOut);
maxX = Math.max(maxX, leftOut);
for (Ftile tmp : allTiles) {
if (tmp.calculateDimension(stringBounder).hasPointOut() == false) {
continue;
@ -526,8 +531,13 @@ class FtileIfLongHorizontal extends AbstractFtile {
}
private double[] getMinmaxSimple(StringBounder stringBounder, double width, List<Ftile> allTiles) {
final Double leftOut = getLeftOut(stringBounder);
if (leftOut == null)
return new double[] { Double.NaN, Double.NaN };
double minX = width / 2;
double maxX = width / 2;
minX = Math.min(minX, leftOut);
maxX = Math.max(maxX, leftOut);
for (Ftile tmp : allTiles) {
if (tmp.calculateDimension(stringBounder).hasPointOut() == false) {
continue;

View File

@ -53,7 +53,7 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.Connection;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidthCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileOverpassing;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Snake;
@ -133,10 +133,10 @@ class FtileIfLongVertical extends AbstractFtile {
final List<Ftile> tiles = new ArrayList<Ftile>();
for (Branch branch : thens) {
tiles.add(new FtileMinWidth(branch.getFtile(), 30));
tiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
final Ftile tile2 = new FtileMinWidth(branch2.getFtile(), 30);
final Ftile tile2 = new FtileMinWidthCentered(branch2.getFtile(), 30);
List<Ftile> diamonds = new ArrayList<Ftile>();
for (Branch branch : thens) {

View File

@ -50,7 +50,7 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.AbstractFtile;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidthCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileDiamondInside2;
import net.sourceforge.plantuml.cucadiagram.Display;
@ -104,7 +104,7 @@ class FtileSwitch extends AbstractFtile {
final List<Ftile> tiles = new ArrayList<Ftile>();
for (Branch branch : thens) {
tiles.add(new FtileMinWidth(branch.getFtile(), 30));
tiles.add(new FtileMinWidthCentered(branch.getFtile(), 30));
}
List<Double> inlabelSizes = new ArrayList<Double>();

View File

@ -50,6 +50,8 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.ConnectionTranslatable;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileAssemblySimple;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileHeightFixedCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileHeightFixedMarged;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.Snake;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
@ -57,6 +59,7 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileBlackBlock;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.Rainbow;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.Style;
import net.sourceforge.plantuml.ugraphic.UGraphic;
import net.sourceforge.plantuml.ugraphic.UTranslate;
@ -67,28 +70,70 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
private final Swimlane in;
private final Swimlane out;
public ParallelBuilderFork(ISkinParam skinParam, StringBounder stringBounder, final List<Ftile> list, Ftile inner,
String label, Swimlane in, Swimlane out) {
super(skinParam, stringBounder, list, inner);
public ParallelBuilderFork(ISkinParam skinParam, StringBounder stringBounder, String label, Swimlane in,
Swimlane out, List<Ftile> all) {
super(skinParam, stringBounder, all);
this.label = label;
this.in = in;
this.out = out;
}
protected List<Ftile> getFoo2(List<Ftile> all) {
final double maxHeight = computeMaxHeight(all);
final double ymargin1 = getSuppSpace1(all, getStringBounder());
final double ymargin2 = getSuppSpace2(all, getStringBounder());
final List<Ftile> result = new ArrayList<Ftile>();
for (Ftile ftile : all) {
final Ftile newFtile = computeNewFtile(ftile, maxHeight, ymargin1, ymargin2);
result.add(newFtile);
}
return result;
}
private Ftile computeNewFtile(Ftile ftile, double maxHeight, double ymargin1, double ymargin2) {
final double spaceArroundBlackBar = 20;
final double xMargin = 14;
Ftile tmp;
tmp = FtileUtils.addHorizontalMargin(ftile, xMargin, xMargin + getSuppForIncomingArrow(ftile));
tmp = new FtileHeightFixedCentered(tmp, maxHeight + 2 * spaceArroundBlackBar);
tmp = new FtileHeightFixedMarged(ymargin1, tmp, ymargin2);
return tmp;
}
private double getSuppForIncomingArrow(Ftile ftile) {
final double x1 = getXSuppForDisplay(ftile, ftile.getInLinkRendering().getDisplay());
final double x2 = getXSuppForDisplay(ftile, ftile.getOutLinkRendering().getDisplay());
return Math.max(x1, x2);
}
private double getXSuppForDisplay(Ftile ftile, Display label) {
final TextBlock text = getTextBlock(label);
if (text == null) {
return 0;
}
final double textWidth = text.calculateDimension(getStringBounder()).getWidth();
final FtileGeometry ftileDim = ftile.calculateDimension(getStringBounder());
final double pos2 = ftileDim.getLeft() + textWidth;
if (pos2 > ftileDim.getWidth()) {
return pos2 - ftileDim.getWidth();
}
return 0;
}
@Override
protected Swimlane swimlaneOutForStep2() {
return out;
}
@Override
protected Ftile doStep1() {
Ftile result = getMiddle();
protected Ftile doStep1(Ftile middle) {
Ftile result = middle;
final List<Connection> conns = new ArrayList<Connection>();
final Swimlane swimlaneBlack = in;
final Ftile black = new FtileBlackBlock(skinParam(), getRose()
.getHtmlColor(skinParam(), ColorParam.activityBar), swimlaneBlack);
final Ftile black = new FtileBlackBlock(skinParam(),
getRose().getHtmlColor(skinParam(), ColorParam.activityBar), swimlaneBlack);
double x = 0;
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final Dimension2D dim = tmp.calculateDimension(getStringBounder());
final Rainbow def;
if (SkinParam.USE_STYLES()) {
@ -109,8 +154,39 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
return new FtileAssemblySimple(black, result);
}
private double getSuppSpace1(List<Ftile> all, StringBounder stringBounder) {
double result = 0;
for (Ftile child : all) {
final TextBlock text = getTextBlock(child.getInLinkRendering().getDisplay());
if (text == null) {
continue;
}
final Dimension2D dim = text.calculateDimension(stringBounder);
result = Math.max(result, dim.getHeight());
}
return result;
}
private double getSuppSpace2(List<Ftile> all, StringBounder stringBounder) {
double result = 0;
for (Ftile child : all) {
final TextBlock text = getTextBlock(child.getOutLinkRendering().getDisplay());
if (text == null) {
continue;
}
final Dimension2D dim = text.calculateDimension(stringBounder);
result = Math.max(result, dim.getHeight());
}
return result;
}
private double getJustBeforeBar2(Ftile middle, StringBounder stringBounder) {
return barHeight + getHeightOfMiddle(middle);
}
@Override
protected Ftile doStep2(Ftile result) {
protected Ftile doStep2(Ftile middle, Ftile result) {
final Swimlane swimlaneBlack = out;
final Ftile out = new FtileBlackBlock(skinParam(), getRose().getHtmlColor(skinParam(), ColorParam.activityBar),
swimlaneBlack);
@ -122,8 +198,7 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
result = new FtileAssemblySimple(result, out);
final List<Connection> conns = new ArrayList<Connection>();
double x = 0;
for (Ftile tmp : getList()) {
final UTranslate translate0 = UTranslate.dy(barHeight);
for (Ftile tmp : list99) {
final Dimension2D dim = tmp.calculateDimension(getStringBounder());
final Rainbow def;
if (SkinParam.USE_STYLES()) {
@ -133,7 +208,7 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
def = Rainbow.build(skinParam());
}
final Rainbow rainbow = tmp.getOutLinkRendering().getRainbow(def);
conns.add(new ConnectionOut(translate0, tmp, out, x, rainbow, getHeightOfMiddle()));
conns.add(new ConnectionOut(tmp, out, x, rainbow, getJustBeforeBar2(middle, getStringBounder())));
x += dim.getWidth();
}
result = FtileUtils.addConnection(result, conns);
@ -148,28 +223,30 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
public ConnectionIn(Ftile ftile1, Ftile ftile2, double x, Rainbow arrowColor) {
super(ftile1, ftile2);
label = ftile2.getInLinkRendering().getDisplay();
this.label = ftile2.getInLinkRendering().getDisplay();
this.x = x;
this.arrowColor = arrowColor;
}
public void drawU(UGraphic ug) {
ug = ug.apply(UTranslate.dx(x));
final FtileGeometry geo = getFtile2().calculateDimension(getStringBounder());
final FtileGeometry geo2 = getFtile2().calculateDimension(getStringBounder());
final Snake snake = new Snake(arrowHorizontalAlignment(), arrowColor, Arrows.asToDown());
if (Display.isNull(label) == false) {
snake.setLabel(getTextBlock(label));
}
snake.addPoint(geo.getLeft(), 0);
snake.addPoint(geo.getLeft(), geo.getInY());
final Point2D p1 = new Point2D.Double(geo2.getLeft(), 0);
final Point2D p2 = new Point2D.Double(geo2.getLeft(), geo2.getInY());
snake.addPoint(p1);
snake.addPoint(p2);
ug.draw(snake);
}
public void drawTranslate(UGraphic ug, UTranslate translate1, UTranslate translate2) {
ug = ug.apply(UTranslate.dx(x));
final FtileGeometry geo = getFtile2().calculateDimension(getStringBounder());
final Point2D p1 = new Point2D.Double(geo.getLeft(), 0);
final Point2D p2 = new Point2D.Double(geo.getLeft(), geo.getInY());
final FtileGeometry geo2 = getFtile2().calculateDimension(getStringBounder());
final Point2D p1 = new Point2D.Double(geo2.getLeft(), 0);
final Point2D p2 = new Point2D.Double(geo2.getLeft(), geo2.getInY());
final Snake snake = new Snake(arrowHorizontalAlignment(), arrowColor, Arrows.asToDown());
if (Display.isNull(label) == false) {
@ -191,32 +268,29 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
private final double x;
private final Rainbow arrowColor;
private final double height;
private final Display label;
private final UTranslate translate0;
private final double justBeforeBar2;
public ConnectionOut(UTranslate translate0, Ftile ftile1, Ftile ftile2, double x, Rainbow arrowColor,
double height) {
public ConnectionOut(Ftile ftile1, Ftile ftile2, double x, Rainbow arrowColor, double justBeforeBar2) {
super(ftile1, ftile2);
this.translate0 = translate0;
this.justBeforeBar2 = justBeforeBar2;
this.label = ftile1.getOutLinkRendering().getDisplay();
this.x = x;
this.arrowColor = arrowColor;
this.height = height;
}
public void drawU(UGraphic ug) {
ug = ug.apply(UTranslate.dx(x));
final FtileGeometry geo = getFtile1().calculateDimension(getStringBounder());
if (geo.hasPointOut() == false) {
final FtileGeometry geo1 = getFtile1().calculateDimension(getStringBounder());
if (geo1.hasPointOut() == false) {
return;
}
final Snake snake = new Snake(arrowHorizontalAlignment(), arrowColor, Arrows.asToDown());
if (Display.isNull(label) == false) {
snake.setLabel(getTextBlock(label));
}
final Point2D p1 = translate0.getTranslated(new Point2D.Double(geo.getLeft(), geo.getOutY()));
final Point2D p2 = translate0.getTranslated(new Point2D.Double(geo.getLeft(), height));
final Point2D p1 = new Point2D.Double(geo1.getLeft(), barHeight + geo1.getOutY());
final Point2D p2 = new Point2D.Double(geo1.getLeft(), justBeforeBar2);
snake.addPoint(p1);
snake.addPoint(p2);
ug.draw(snake);
@ -228,8 +302,8 @@ public class ParallelBuilderFork extends AbstractParallelFtilesBuilder {
if (geo.hasPointOut() == false) {
return;
}
final Point2D p1 = translate0.getTranslated(new Point2D.Double(geo.getLeft(), geo.getOutY()));
final Point2D p2 = translate0.getTranslated(new Point2D.Double(geo.getLeft(), height));
final Point2D p1 = new Point2D.Double(geo.getLeft(), barHeight + geo.getOutY());
final Point2D p2 = new Point2D.Double(geo.getLeft(), justBeforeBar2);
final Snake snake = new Snake(arrowHorizontalAlignment(), arrowColor, Arrows.asToDown());
if (Display.isNull(label) == false) {

View File

@ -65,19 +65,19 @@ import net.sourceforge.plantuml.ugraphic.color.HColor;
public class ParallelBuilderMerge extends AbstractParallelFtilesBuilder {
public ParallelBuilderMerge(ISkinParam skinParam, StringBounder stringBounder, final List<Ftile> list, Ftile inner) {
super(skinParam, stringBounder, list, inner);
public ParallelBuilderMerge(ISkinParam skinParam, StringBounder stringBounder, List<Ftile> all) {
super(skinParam, stringBounder, all);
}
@Override
protected Ftile doStep1() {
Ftile result = getMiddle();
protected Ftile doStep1(Ftile inner) {
Ftile result = inner;
final List<Connection> conns = new ArrayList<Connection>();
final HColor colorBar = getRose().getHtmlColor(skinParam(), ColorParam.activityBar);
final Ftile black = new FtileBlackBlock(skinParam(), colorBar, getList().get(0).getSwimlaneIn());
final Ftile black = new FtileBlackBlock(skinParam(), colorBar, list99.get(0).getSwimlaneIn());
double x = 0;
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final Dimension2D dim = tmp.calculateDimension(getStringBounder());
final Rainbow def;
if (SkinParam.USE_STYLES()) {
@ -99,7 +99,7 @@ public class ParallelBuilderMerge extends AbstractParallelFtilesBuilder {
}
@Override
protected Ftile doStep2(Ftile result) {
protected Ftile doStep2(Ftile inner, Ftile result) {
final HColor borderColor = getRose().getHtmlColor(skinParam(), ColorParam.activityDiamondBorder);
final HColor backColor = getRose().getHtmlColor(skinParam(), ColorParam.activityDiamondBackground);
final Ftile out = new FtileDiamond(skinParam(), backColor, borderColor, swimlaneOutForStep2());
@ -108,7 +108,7 @@ public class ParallelBuilderMerge extends AbstractParallelFtilesBuilder {
final UTranslate diamondTranslate = result.getTranslateFor(out, getStringBounder());
int i = 0;
double x = 0;
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final Dimension2D dim = tmp.calculateDimension(getStringBounder());
final UTranslate translate0 = new UTranslate(x, barHeight);
final Rainbow def;

View File

@ -65,8 +65,8 @@ import net.sourceforge.plantuml.ugraphic.color.HColor;
public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
public ParallelBuilderSplit(ISkinParam skinParam, StringBounder stringBounder, final List<Ftile> list, Ftile inner) {
super(skinParam, stringBounder, list, inner);
public ParallelBuilderSplit(ISkinParam skinParam, StringBounder stringBounder, List<Ftile> all) {
super(skinParam, stringBounder, all);
}
@Override
@ -75,8 +75,8 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
}
@Override
protected Ftile doStep1() {
Ftile result = getMiddle();
protected Ftile doStep1(Ftile inner) {
Ftile result = inner;
final List<Connection> conns = new ArrayList<Connection>();
final Rainbow thinColor;
if (SkinParam.USE_STYLES()) {
@ -85,11 +85,11 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
} else {
thinColor = result.getInLinkRendering().getRainbow(Rainbow.build(skinParam()));
}
final Ftile thin = new FtileThinSplit(skinParam(), getThin1Color(thinColor), getList().get(0).getSwimlaneIn());
final Ftile thin = new FtileThinSplit(skinParam(), getThin1Color(thinColor), list99.get(0).getSwimlaneIn());
double x = 0;
double first = 0;
double last = 0;
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final FtileGeometry dim = tmp.calculateDimension(getStringBounder());
if (first == 0) {
first = x + dim.getLeft();
@ -123,7 +123,7 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
}
private HColor getThin1Color(final Rainbow thinColor) {
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final Rainbow rainbow;
final LinkRendering inLinkRendering = tmp.getInLinkRendering();
if (SkinParam.USE_STYLES()) {
@ -140,7 +140,7 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
}
private boolean hasOut() {
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final boolean hasOutTmp = tmp.calculateDimension(getStringBounder()).hasPointOut();
if (hasOutTmp) {
return true;
@ -150,7 +150,7 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
}
@Override
protected Ftile doStep2(Ftile result) {
protected Ftile doStep2(Ftile inner, Ftile result) {
final FtileGeometry geom = result.calculateDimension(getStringBounder());
if (hasOut() == false) {
@ -172,7 +172,7 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
double x = 0;
double first = 0;
double last = 0;
for (Ftile tmp : getList()) {
for (Ftile tmp : list99) {
final UTranslate translate0 = UTranslate.dy(1.5);
final FtileGeometry dim = tmp.calculateDimension(getStringBounder());
if (dim.hasPointOut()) {
@ -191,7 +191,7 @@ public class ParallelBuilderSplit extends AbstractParallelFtilesBuilder {
rainbow = outLinkRendering.getRainbow(Rainbow.build(skinParam()));
}
conns.add(new ConnectionOut(translate0, tmp, out, x, rainbow, getHeightOfMiddle()));
conns.add(new ConnectionOut(translate0, tmp, out, x, rainbow, getHeightOfMiddle(inner)));
x += dim.getWidth();
}
if (last < geom.getLeft()) {

View File

@ -46,7 +46,7 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.Diamond;
import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileEmpty;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidthCentered;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils;
import net.sourceforge.plantuml.activitydiagram3.ftile.FtileWithUrl;
import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane;
@ -132,8 +132,8 @@ public class ConditionalBuilder {
this.stringBounder = stringBounder;
this.url = url;
this.tile1 = new FtileMinWidth(branch1.getFtile(), 30);
this.tile2 = new FtileMinWidth(branch2.getFtile(), 30);
this.tile1 = new FtileMinWidthCentered(branch1.getFtile(), 30);
this.tile2 = new FtileMinWidthCentered(branch2.getFtile(), 30);
}
@ -166,8 +166,8 @@ public class ConditionalBuilder {
}
private Ftile createDown(Branch branch1, Branch branch2) {
final Ftile tile1 = new FtileMinWidth(branch1.getFtile(), 30);
final Ftile tile2 = new FtileMinWidth(branch2.getFtile(), 30);
final Ftile tile1 = new FtileMinWidthCentered(branch1.getFtile(), 30);
final Ftile tile2 = new FtileMinWidthCentered(branch2.getFtile(), 30);
final TextBlock tb1 = getLabelPositive(branch1);
final TextBlock tb2 = getLabelPositive(branch2);
final Ftile diamond1 = getDiamond1(false, tb1, tb2);

View File

@ -81,11 +81,10 @@ import net.sourceforge.plantuml.ugraphic.color.HColorNone;
public class FtileBox extends AbstractFtile {
private double padding() {
return padding;
}
private double padding = 10;
private double padding1 = 10;
private double padding2 = 10;
private double paddingTop = 10;
private double paddingBottom = 10;
private final TextBlock tb;
private double roundCorner = 25;
private final double shadowing;
@ -130,12 +129,12 @@ public class FtileBox extends AbstractFtile {
class MyStencil implements Stencil {
public double getStartingX(StringBounder stringBounder, double y) {
return -padding();
return -padding1;
}
public double getEndingX(StringBounder stringBounder, double y) {
final Dimension2D dim = calculateDimension(stringBounder);
return dim.getWidth() - padding();
return dim.getWidth() - padding2;
}
}
@ -199,7 +198,10 @@ public class FtileBox extends AbstractFtile {
this.backColor = style.value(PName.BackGroundColor).asColor(getIHtmlColorSet());
fc = style.getFontConfiguration(getIHtmlColorSet());
horizontalAlignment = style.getHorizontalAlignment();
this.padding = style.getPadding().asDouble();
this.padding1 = style.getPadding().getLeft();
this.padding2 = style.getPadding().getRight();
this.paddingTop = style.getPadding().getTop();
this.paddingBottom = style.getPadding().getBottom();
this.roundCorner = style.value(PName.RoundCorner).asDouble();
this.shadowing = style.value(PName.Shadowing).asDouble();
wrapWidth = style.wrapWidth();
@ -251,20 +253,20 @@ public class FtileBox extends AbstractFtile {
rect.drawU(ug);
if (horizontalAlignment == HorizontalAlignment.LEFT) {
tb.drawU(ug.apply(new UTranslate(padding(), padding())));
tb.drawU(ug.apply(new UTranslate(padding1, paddingTop)));
} else if (horizontalAlignment == HorizontalAlignment.RIGHT) {
final Dimension2D dimTb = tb.calculateDimension(ug.getStringBounder());
tb.drawU(ug.apply(new UTranslate(dimTotal.getWidth() - dimTb.getWidth() - padding(), padding())));
tb.drawU(ug.apply(new UTranslate(dimTotal.getWidth() - dimTb.getWidth() - padding2, paddingBottom)));
} else if (horizontalAlignment == HorizontalAlignment.CENTER) {
final Dimension2D dimTb = tb.calculateDimension(ug.getStringBounder());
tb.drawU(ug.apply(new UTranslate((dimTotal.getWidth() - dimTb.getWidth()) / 2, padding())));
tb.drawU(ug.apply(new UTranslate((dimTotal.getWidth() - dimTb.getWidth()) / 2, paddingBottom)));
}
}
@Override
protected FtileGeometry calculateDimensionFtile(StringBounder stringBounder) {
Dimension2D dim = tb.calculateDimension(stringBounder);
dim = Dimension2DDouble.delta(dim, 2 * padding(), 2 * padding());
dim = Dimension2DDouble.delta(dim, padding1 + padding2, paddingBottom + paddingTop);
dim = Dimension2DDouble.atLeast(dim, minimumWidth, 0);
return new FtileGeometry(dim, dim.getWidth() / 2, 0, dim.getHeight());
}

View File

@ -49,6 +49,7 @@ import net.sourceforge.plantuml.command.CommandExecutionResult;
import net.sourceforge.plantuml.core.DiagramDescription;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.graphic.UDrawable;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
public class BpmDiagram extends UmlDiagram {
@ -82,10 +83,17 @@ public class BpmDiagram extends UmlDiagram {
protected ImageData exportDiagramInternal(OutputStream os, int index, FileFormatOption fileFormatOption)
throws IOException {
final double dpiFactor = 1;
final double margin = 10;
final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), dpiFactor,
fileFormatOption.isWithMetadata() ? getMetadata() : null, getWarningOrError(), margin, margin,
getAnimation());
final int margin1;
final int margin2;
if (SkinParam.USE_STYLES()) {
margin1 = SkinParam.zeroMargin(10);
margin2 = SkinParam.zeroMargin(10);
} else {
margin1 = 10;
margin2 = 10;
}
final ImageBuilder imageBuilder = ImageBuilder.buildD(getSkinParam(), ClockwiseTopRightBottomLeft.margin1margin2((double) margin1, (double) margin2), getAnimation(), fileFormatOption.isWithMetadata() ? getMetadata() : null,
getWarningOrError(), dpiFactor);
imageBuilder.setUDrawable(getUDrawable());
return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os);

View File

@ -128,8 +128,8 @@ public class UGraphicBraille extends AbstractUGraphic<BrailleGrid> implements Cl
}
public void writeImageTOBEMOVED(OutputStream os, String metadata, int dpi) throws IOException {
final ImageBuilder imageBuilder = new ImageBuilder(new ColorMapperIdentity(), 1.0, HColorUtils.WHITE,
metadata, null, 0, 0, null, false);
final ImageBuilder imageBuilder = ImageBuilder.buildA(new ColorMapperIdentity(),
false, null, metadata, null, 1.0, HColorUtils.WHITE);
imageBuilder.setUDrawable(new BrailleDrawer(getGraphicObject()));
imageBuilder.writeImageTOBEMOVED(new FileFormatOption(FileFormat.PNG), 42, os);

View File

@ -40,6 +40,7 @@ import java.io.OutputStream;
import net.sourceforge.plantuml.FileFormatOption;
import net.sourceforge.plantuml.ISkinSimple;
import net.sourceforge.plantuml.SkinParam;
import net.sourceforge.plantuml.UmlDiagramType;
import net.sourceforge.plantuml.core.ImageData;
import net.sourceforge.plantuml.creole.CreoleMode;
@ -55,6 +56,7 @@ import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.graphic.USymbol;
import net.sourceforge.plantuml.objectdiagram.AbstractClassOrObjectDiagram;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.svek.image.EntityImageClass;
import net.sourceforge.plantuml.ugraphic.ImageBuilder;
@ -129,7 +131,8 @@ public class ClassDiagram extends AbstractClassOrObjectDiagram {
return createEntityWithNamespace1972(idNewLong, code, display, type, symbol);
}
private ILeaf createEntityWithNamespace1972(Ident id, Code fullyCode, Display display, LeafType type, USymbol symbol) {
private ILeaf createEntityWithNamespace1972(Ident id, Code fullyCode, Display display, LeafType type,
USymbol symbol) {
if (this.V1972())
throw new UnsupportedOperationException();
checkNotNull(id);
@ -200,7 +203,17 @@ public class ClassDiagram extends AbstractClassOrObjectDiagram {
final RowLayout rawLayout = getRawLayout(i);
fullLayout.addRowLayout(rawLayout);
}
final ImageBuilder imageBuilder = new ImageBuilder(getSkinParam(), 1, null, null, 0, 10, null);
final int margin1;
final int margin2;
if (SkinParam.USE_STYLES()) {
margin1 = SkinParam.zeroMargin(0);
margin2 = SkinParam.zeroMargin(10);
} else {
margin1 = 0;
margin2 = 10;
}
final ImageBuilder imageBuilder = ImageBuilder.buildD(getSkinParam(), ClockwiseTopRightBottomLeft.margin1margin2((double) margin1, (double) margin2), null, null,
null, (double) 1);
imageBuilder.setUDrawable(fullLayout);
return imageBuilder.writeImageTOBEMOVED(fileFormatOption, seed(), os);
}

View File

@ -144,7 +144,7 @@ public class CommandCreateClassMultilines extends CommandMultilines2<ClassDiagra
@Override
protected CommandExecutionResult executeNow(ClassDiagram diagram, BlocLines lines) {
lines = lines.trimSmart(1);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
final IEntity entity = executeArg0(diagram, line0);
if (entity == null) {
return CommandExecutionResult.error("No such entity");

View File

@ -30,6 +30,7 @@
*
*
* Original Author: Arnaud Roques
* Contribution : Hisashi Miyashita
*
*
*/
@ -178,6 +179,9 @@ public class CommandCreateElementFull2 extends SingleLineCommand2<ClassDiagram>
if (symbol == null) {
type = LeafType.DESCRIPTION;
usymbol = diagram.getSkinParam().getActorStyle().getUSymbol();
} else if (symbol.equalsIgnoreCase("port")) {
type = LeafType.PORT;
usymbol = null;
} else if (symbol.equalsIgnoreCase("usecase")) {
type = LeafType.USECASE;
usymbol = null;

View File

@ -30,6 +30,7 @@
*
*
* Original Author: Arnaud Roques
* Contribution : Hisashi Miyashita
*
*
*/
@ -90,14 +91,16 @@ final public class CommandLinkClass extends SingleLineCommand2<AbstractClassOrOb
new RegexConcat(
//
new RegexLeaf("ARROW_HEAD1", "([%s]+[ox]|[)#\\[<*+^}]|[<\\[]\\||\\}o|\\}\\||\\|o|\\|\\|)?"), //
new RegexLeaf("ARROW_HEAD1",
"([%s]+[ox]|[)#\\[<*+^}]|\\<\\|[\\:\\|]|[<\\[]\\||\\}o|\\}\\||\\|o|\\|\\|)?"), //
new RegexLeaf("ARROW_BODY1", "([-=.]+)"), //
new RegexLeaf("ARROW_STYLE1", "(?:\\[(" + CommandLinkElement.LINE_STYLE + ")\\])?"), //
new RegexLeaf("ARROW_DIRECTION", "(left|right|up|down|le?|ri?|up?|do?)?"), //
new RegexOptional(new RegexLeaf("INSIDE", "(0|\\(0\\)|\\(0|0\\))(?=[-=.~])")), //
new RegexLeaf("ARROW_STYLE2", "(?:\\[(" + CommandLinkElement.LINE_STYLE + ")\\])?"), //
new RegexLeaf("ARROW_BODY2", "([-=.]*)"), //
new RegexLeaf("ARROW_HEAD2", "([ox][%s]+|[(#\\]>*+^\\{]|\\|[>\\]]|o\\{|\\|\\{|o\\||\\|\\|)?")), //
new RegexLeaf("ARROW_HEAD2",
"([ox][%s]+|:\\>\\>?|[(#\\]>*+^\\{]|[\\|\\:]\\|\\>|\\|[>\\]]|o\\{|\\|\\{|o\\||\\|\\|)?")), //
RegexLeaf.spaceZeroOrMore(), new RegexOptional(new RegexLeaf("SECOND_LABEL", "[%g]([^%g]+)[%g]")), //
RegexLeaf.spaceZeroOrMore(), //
new RegexOr( //
@ -567,6 +570,12 @@ final public class CommandLinkClass extends SingleLineCommand2<AbstractClassOrOb
if ("<|".equals(s)) {
return LinkDecor.EXTENDS;
}
if ("<|:".equals(s)) {
return LinkDecor.DEFINEDBY;
}
if ("<||".equals(s)) {
return LinkDecor.REDEFINES;
}
if ("}".equals(s)) {
return LinkDecor.CROWFOOT;
}
@ -617,6 +626,12 @@ final public class CommandLinkClass extends SingleLineCommand2<AbstractClassOrOb
if ("|>".equals(s)) {
return LinkDecor.EXTENDS;
}
if (":|>".equals(s)) {
return LinkDecor.DEFINEDBY;
}
if ("||>".equals(s)) {
return LinkDecor.REDEFINES;
}
if (">".equals(s)) {
return LinkDecor.ARROW;
}

View File

@ -88,7 +88,7 @@ public class ArobaseStringCompressor implements StringCompressor {
return "";
}
public String decompress(String s) throws IOException {
public String decompress(String s) {
String result = clean(s);
if (result.startsWith("@start")) {
return result;

View File

@ -35,17 +35,15 @@
*/
package net.sourceforge.plantuml.code;
import java.io.IOException;
import net.sourceforge.plantuml.StringUtils;
public class ArobaseStringCompressor2 implements StringCompressor {
public String compress(String data) throws IOException {
public String compress(String data) {
return clean2(data);
}
public String decompress(String s) throws IOException {
public String decompress(String s) {
return clean2(s);
}

View File

@ -33,30 +33,39 @@
*
*
*/
package net.sourceforge.plantuml.activitydiagram3.ftile;
package net.sourceforge.plantuml.code;
import net.sourceforge.plantuml.activitydiagram3.Instruction;
import net.sourceforge.plantuml.activitydiagram3.LinkRendering;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.graphic.TextBlock;
import net.sourceforge.plantuml.style.Styleable;
import net.sourceforge.plantuml.ugraphic.color.HColor;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public interface ISwimlanesA extends TextBlock, Styleable {
public class ByteArray {
public void computeSize(StringBounder stringBounder);
private final byte data[];
private final int length;
public void swimlane(String name, HColor color, Display label);
private ByteArray(byte data[], int length) {
this.data = data;
this.length = length;
}
public void setCurrent(Instruction ins);
public static ByteArray from(byte[] input) {
return new ByteArray(input, input.length);
}
public Instruction getCurrent();
public String toUFT8String() throws UnsupportedEncodingException {
return new String(data, 0, length, "UTF-8");
}
public LinkRendering nextLinkRenderer();
public String toUPF9String() throws IOException {
return Upf9.decodeString(data, length);
}
public Swimlane getCurrentSwimlane();
public int getByteAt(int i) {
return data[i];
}
public void setNextLinkRenderer(LinkRendering link);
public int length() {
return length;
}
}
}

View File

@ -35,8 +35,6 @@
*/
package net.sourceforge.plantuml.code;
import java.io.IOException;
public interface Compression {
/**
@ -47,11 +45,11 @@ public interface Compression {
byte[] compress(final byte[] in);
/**
* Grows the given <code>in</code> array with length <code>len</code>
* compressed with the <code>shrink</code> method.
* Grows the given <code>in</code> array with length <code>len</code> compressed
* with the <code>shrink</code> method.
*
* @return a newly created array with the expanded data.
*/
byte[] decompress(byte[] in) throws IOException;
ByteArray decompress(byte[] in) throws NoPlantumlCompressionException;
}

View File

@ -48,13 +48,18 @@ public class CompressionBrotli implements Compression {
throw new UnsupportedOperationException();
}
public byte[] decompress(byte[] in) throws IOException {
final BrotliInputStream brotli = new BrotliInputStream(new ByteArrayInputStream(in));
final ByteArrayOutputStream result = new ByteArrayOutputStream();
FileUtils.copyToStream(brotli, result);
brotli.close();
result.close();
return result.toByteArray();
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
try {
final BrotliInputStream brotli = new BrotliInputStream(new ByteArrayInputStream(in));
final ByteArrayOutputStream result = new ByteArrayOutputStream();
FileUtils.copyToStream(brotli, result);
brotli.close();
result.close();
return ByteArray.from(result.toByteArray());
} catch (IOException e) {
e.printStackTrace();
throw new NoPlantumlCompressionException(e);
}
}
}

View File

@ -59,19 +59,24 @@ public class CompressionHuffman implements Compression {
}
}
public byte[] decompress(byte[] in) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayInputStream bais = new ByteArrayInputStream(in);
final InflaterInputStream gz = new InflaterInputStream(bais);
int read;
while ((read = gz.read()) != -1) {
baos.write(read);
final ByteArrayInputStream bais = new ByteArrayInputStream(in);
final InflaterInputStream gz = new InflaterInputStream(bais);
int read;
while ((read = gz.read()) != -1) {
baos.write(read);
}
gz.close();
bais.close();
baos.close();
return ByteArray.from(baos.toByteArray());
} catch (IOException e) {
System.err.println("Not Huffman");
throw new NoPlantumlCompressionException(e);
}
gz.close();
bais.close();
baos.close();
return baos.toByteArray();
}
}

View File

@ -41,8 +41,8 @@ public class CompressionNone implements Compression {
return in;
}
public byte[] decompress(byte[] in) {
return in;
public ByteArray decompress(byte[] in) {
return ByteArray.from(in);
}
}

View File

@ -53,14 +53,14 @@ public class CompressionZlib implements Compression {
return null;
}
int len = in.length * 2;
if (len < 100) {
len = 100;
if (len < 1000) {
len = 1000;
}
byte[] result = null;
while (result == null) {
result = tryCompress(in, len);
len *= 2;
}
// while (result == null) {
result = tryCompress(in, len);
// len *= 2;
// }
return result;
}
@ -79,20 +79,33 @@ public class CompressionZlib implements Compression {
return result;
}
public byte[] decompress(byte[] in) throws IOException {
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
try {
final byte in2[] = new byte[in.length + 256];
System.arraycopy(in, 0, in2, 0, in.length);
// for (int i = 0; i < in.length; i++) {
// in2[i] = in[i];
// }
final byte in2[] = new byte[in.length + 256];
for (int i = 0; i < in.length; i++) {
in2[i] = in[i];
}
int len = in.length * 5;
byte[] result = null;
while (result == null) {
int len = 100000;
byte[] result = null;
result = tryDecompress(in2, len);
len *= 2;
if (result == null) {
throw new NoPlantumlCompressionException("Too big?");
}
// int len = in.length * 5;
// byte[] result = null;
// while (result == null) {
// result = tryDecompress(in2, len);
// len *= 2;
// }
return ByteArray.from(result);
} catch (IOException e) {
e.printStackTrace();
throw new NoPlantumlCompressionException(e);
}
return result;
}
private byte[] tryDecompress(byte[] in, final int len) throws IOException {
@ -120,9 +133,10 @@ public class CompressionZlib implements Compression {
private byte[] copyArray(final byte[] data, final int len) {
final byte[] result = new byte[len];
for (int i = 0; i < result.length; i++) {
result[i] = data[i];
}
System.arraycopy(data, 0, result, 0, len);
// for (int i = 0; i < result.length; i++) {
// result[i] = data[i];
// }
return result;
}

View File

@ -0,0 +1,88 @@
/* ========================================================================
* 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.code;
import java.io.ByteArrayInputStream;
import java.util.zip.Deflater;
import net.sourceforge.plantuml.code.deflate.ByteBitInputStream;
import net.sourceforge.plantuml.code.deflate.Decompressor;
public class CompressionZlibPure implements Compression {
private static boolean USE_ZOPFLI = false;
private static final int COMPRESSION_LEVEL = 9;
public byte[] compress(byte[] in) {
if (USE_ZOPFLI) {
return new CompressionZopfliZlib().compress(in);
}
if (in.length == 0) {
return null;
}
int len = in.length * 2;
if (len < 1000) {
len = 1000;
}
// Compress the bytes
final Deflater compresser = new Deflater(COMPRESSION_LEVEL, true);
compresser.setInput(in);
compresser.finish();
final byte[] output = new byte[len];
final int compressedDataLength = compresser.deflate(output);
if (compresser.finished() == false) {
return null;
}
return copyArray(output, compressedDataLength);
}
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
final ByteBitInputStream in2 = new ByteBitInputStream(new ByteArrayInputStream(in));
try {
return ByteArray.from(Decompressor.decompress(in2));
} catch (Exception e) {
throw new NoPlantumlCompressionException(e);
}
}
private byte[] copyArray(final byte[] data, final int len) {
final byte[] result = new byte[len];
System.arraycopy(data, 0, result, 0, len);
return result;
}
}

View File

@ -35,8 +35,6 @@
*/
package net.sourceforge.plantuml.code;
import java.io.IOException;
import net.sourceforge.plantuml.zopfli.Options;
import net.sourceforge.plantuml.zopfli.Options.BlockSplitting;
import net.sourceforge.plantuml.zopfli.Options.OutputFormat;
@ -58,7 +56,7 @@ public class CompressionZopfliZlib implements Compression {
return compressor.compress(options, in).getResult();
}
public byte[] decompress(byte[] in) throws IOException {
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
return new CompressionZlib().decompress(in);
}

View File

@ -0,0 +1,183 @@
/* ========================================================================
* 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.code;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class Keywords {
private final List<String> keywords = new ArrayList<String>();
public static void main(String[] args) {
System.err.println("keywords=" + new Keywords().keywords.size());
final Set<String> sorted = new TreeSet<String>(new Keywords().keywords);
for (String s : sorted) {
System.err.println(s);
}
}
public String compress(String s) {
for (int i = 0; i < keywords.size(); i++) {
final char c = (char) ('\uE000' + i);
s = s.replace(keywords.get(i), "" + c);
}
return s;
}
public Keywords() {
add("actor");
add("participant");
add("usecase");
add("class");
add("interface");
add("abstract");
add("enum");
add("component");
add("state");
add("object");
add("artifact");
add("folder");
add("rectangle");
add("node");
add("frame");
add("cloud");
add("database");
add("storage");
add("agent");
add("stack");
add("boundary");
add("control");
add("entity");
add("card");
add("file");
add("package");
add("queue");
add("archimate");
add("diamond");
add("detach");
add("@start");
add("@end");
add("also");
add("autonumber");
add("caption");
add("title");
add("newpage");
add("loop");
add("break");
add("critical");
add("note");
add("legend");
add("group");
add("left");
add("right");
add("link");
add("over");
add("activate");
add("deactivate");
add("destroy");
add("create");
add("footbox");
add("hide");
add("show");
add("skinparam");
add("skin");
add("bottom");
add("namespace");
add("page");
add("down");
add("else");
add("endif");
add("partition");
add("footer");
add("header");
add("center");
add("rotate");
add("return");
add("repeat");
add("start");
add("stop");
add("while");
add("endwhile");
add("fork");
add("again");
add("kill");
add("order");
add("mainframe");
add("across");
add("stereotype");
add("split");
add("style");
add("!exit");
add("!include");
add("!pragma");
add("!undef");
add("!ifdef");
add("!endif");
add("!ifndef");
add("!else");
add("!function");
add("!procedure");
add("!endfunction");
add("!endprocedure");
add("!unquoted");
add("!return");
add("!startsub");
add("!endsub");
add("!assert");
add("!local");
}
private void add(String string) {
if (keywords.contains(string)) {
throw new IllegalArgumentException(string);
}
if (string.length() <= 3) {
throw new IllegalArgumentException(string);
}
keywords.add(string);
if (keywords.size() > 127) {
throw new IllegalArgumentException();
}
}
}

View File

@ -0,0 +1,50 @@
/* ========================================================================
* 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.code;
import java.io.IOException;
public class NoPlantumlCompressionException extends IOException {
public NoPlantumlCompressionException(Exception cause) {
super(cause);
}
public NoPlantumlCompressionException(String description) {
super(description);
}
}

View File

@ -41,6 +41,6 @@ public interface StringCompressor {
String compress(String s) throws IOException;
String decompress(String compressed) throws IOException;
String decompress(String compressed) throws NoPlantumlCompressionException;
}

View File

@ -43,7 +43,7 @@ public class StringCompressorNone implements StringCompressor {
return s;
}
public String decompress(String stringAnnoted) throws IOException {
public String decompress(String stringAnnoted) {
return stringAnnoted;
}
}

View File

@ -41,5 +41,5 @@ public interface Transcoder {
public String encode(String text) throws IOException;
public String decode(String code) throws IOException;
public String decode(String code) throws NoPlantumlCompressionException;
}

View File

@ -39,43 +39,54 @@ import java.io.IOException;
public class TranscoderImpl implements Transcoder {
static enum Format {
UTF8, UPF9;
}
private final Compression compression;
private final URLEncoder urlEncoder;
private final StringCompressor stringCompressor;
private final Format format;
// private TranscoderImpl() {
// this(new AsciiEncoder(), new StringCompressorNone(), new CompressionHuffman());
// }
//
// private TranscoderImpl(Compression compression) {
// this(new AsciiEncoder(), new StringCompressorNone(), compression);
// }
//
// private TranscoderImpl(URLEncoder urlEncoder, Compression compression) {
// this(urlEncoder, new ArobaseStringCompressor(), compression);
// }
public TranscoderImpl(URLEncoder urlEncoder, StringCompressor stringCompressor, Compression compression) {
private TranscoderImpl(URLEncoder urlEncoder, StringCompressor stringCompressor, Compression compression,
Format format) {
this.compression = compression;
this.urlEncoder = urlEncoder;
this.stringCompressor = stringCompressor;
this.format = format;
}
public static Transcoder utf8(URLEncoder urlEncoder, StringCompressor stringCompressor, Compression compression) {
return new TranscoderImpl(urlEncoder, stringCompressor, compression, Format.UTF8);
}
public static Transcoder upf9(URLEncoder urlEncoder, StringCompressor stringCompressor, Compression compression) {
return new TranscoderImpl(urlEncoder, stringCompressor, compression, Format.UPF9);
}
public String encode(String text) throws IOException {
final String stringAnnoted = stringCompressor.compress(text);
final byte[] data;
if (format == Format.UTF8)
data = stringAnnoted.getBytes("UTF-8");
else
data = Upf9.getBytes(stringAnnoted);
final byte[] data = stringAnnoted.getBytes("UTF-8");
final byte[] compressedData = compression.compress(data);
return urlEncoder.encode(compressedData);
}
public String decode(String code) throws IOException {
final byte compressedData[] = urlEncoder.decode(code);
final byte data[] = compression.decompress(compressedData);
return stringCompressor.decompress(new String(data, "UTF-8"));
public String decode(String code) throws NoPlantumlCompressionException {
try {
final byte compressedData[] = urlEncoder.decode(code);
final ByteArray data = compression.decompress(compressedData);
final String string = format == Format.UTF8 ? data.toUFT8String() : data.toUPF9String();
return stringCompressor.decompress(string);
} catch (Exception e) {
System.err.println("Cannot decode string");
throw new NoPlantumlCompressionException(e);
}
}
}

View File

@ -40,59 +40,22 @@ import java.io.IOException;
public class TranscoderSmart implements Transcoder {
// Legacy encoder
private final Transcoder oldOne = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor(),
private final Transcoder oldOne = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionHuffman());
private final Transcoder zlib = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor(),
private final Transcoder zlib = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionZlib());
private final Transcoder brotli = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionBrotli());
private final Transcoder zlibBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionZlib());
private final Transcoder brotliBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionBrotli());
private final Transcoder base64only = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionNone());
private final Transcoder hexOnly = new TranscoderImpl(new AsciiEncoderHex(), new ArobaseStringCompressor(),
new CompressionNone());
public String decode(String code) throws IOException {
public String decode(String code) throws NoPlantumlCompressionException {
// Work in progress
// See https://github.com/plantuml/plantuml/issues/117
// Two char headers
if (code.startsWith("0A")) {
return zlibBase64.decode(code.substring(2));
if (code.startsWith("~0")) {
return zlib.decode(code.substring(2));
}
if (code.startsWith("0B")) {
return brotliBase64.decode(code.substring(2));
}
if (code.startsWith("0C")) {
return base64only.decode(code.substring(2));
}
if (code.startsWith("0D")) {
return hexOnly.decode(code.substring(2));
}
// Text prefix
// Just a wild try: use them only for testing
if (code.startsWith("-deflate-")) {
return zlibBase64.decode(code.substring("-deflate-".length()));
}
if (code.startsWith("-brotli-")) {
return brotliBase64.decode(code.substring("-brotli-".length()));
}
if (code.startsWith("-base64-")) {
return base64only.decode(code.substring("-base64-".length()));
}
if (code.startsWith("-hex-")) {
return hexOnly.decode(code.substring("-hex-".length()));
if (code.startsWith("~1")) {
return oldOne.decode(code.substring(2));
}
// Legacy decoding : you should not use it any more.
if (code.startsWith("0")) {
return brotli.decode(code.substring(1));
}
try {
return zlib.decode(code);
} catch (Exception ex) {

View File

@ -40,24 +40,23 @@ import java.io.IOException;
public class TranscoderSmart2 implements Transcoder {
// Legacy encoder
private final Transcoder oldOne = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(),
private final Transcoder oldOne = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor2(),
new CompressionHuffman());
private final Transcoder zlib = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(),
private final Transcoder zlib = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor2(),
new CompressionZlib());
private final Transcoder brotli = new TranscoderImpl(new AsciiEncoder(), new ArobaseStringCompressor2(),
private final Transcoder brotli = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor2(),
new CompressionBrotli());
private final Transcoder zlibBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(),
private final Transcoder zlibBase64 = TranscoderImpl.utf8(new AsciiEncoderBase64(), new ArobaseStringCompressor2(),
new CompressionZlib());
private final Transcoder brotliBase64 = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(),
new CompressionBrotli());
private final Transcoder base64only = new TranscoderImpl(new AsciiEncoderBase64(), new ArobaseStringCompressor2(),
private final Transcoder brotliBase64 = TranscoderImpl.utf8(new AsciiEncoderBase64(),
new ArobaseStringCompressor2(), new CompressionBrotli());
private final Transcoder base64only = TranscoderImpl.utf8(new AsciiEncoderBase64(), new ArobaseStringCompressor2(),
new CompressionNone());
private final Transcoder hexOnly = new TranscoderImpl(new AsciiEncoderHex(), new ArobaseStringCompressor2(),
private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor2(),
new CompressionNone());
public String decode(String code) throws IOException {
public String decode(String code) throws NoPlantumlCompressionException {
// Work in progress
// See https://github.com/plantuml/plantuml/issues/117

View File

@ -0,0 +1,108 @@
/* ========================================================================
* 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.code;
import java.io.IOException;
public class TranscoderSmartAttic implements Transcoder {
// Legacy encoder
private final Transcoder oldOne = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionHuffman());
private final Transcoder zlib = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionZlib());
private final Transcoder brotli = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionBrotli());
private final Transcoder zlibBase64 = TranscoderImpl.utf8(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionZlib());
private final Transcoder brotliBase64 = TranscoderImpl.utf8(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionBrotli());
private final Transcoder base64only = TranscoderImpl.utf8(new AsciiEncoderBase64(), new ArobaseStringCompressor(),
new CompressionNone());
private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor(),
new CompressionNone());
public String decode(String code) throws NoPlantumlCompressionException {
// Work in progress
// See https://github.com/plantuml/plantuml/issues/117
// Two char headers
if (code.startsWith("0A")) {
return zlibBase64.decode(code.substring(2));
}
if (code.startsWith("0B")) {
return brotliBase64.decode(code.substring(2));
}
if (code.startsWith("0C")) {
return base64only.decode(code.substring(2));
}
if (code.startsWith("0D")) {
return hexOnly.decode(code.substring(2));
}
// Text prefix
// Just a wild try: use them only for testing
if (code.startsWith("-deflate-")) {
return zlibBase64.decode(code.substring("-deflate-".length()));
}
if (code.startsWith("-brotli-")) {
return brotliBase64.decode(code.substring("-brotli-".length()));
}
if (code.startsWith("-base64-")) {
return base64only.decode(code.substring("-base64-".length()));
}
if (code.startsWith("-hex-")) {
return hexOnly.decode(code.substring("-hex-".length()));
}
// Legacy decoding : you should not use it any more.
if (code.startsWith("0")) {
return brotli.decode(code.substring(1));
}
try {
return zlib.decode(code);
} catch (Exception ex) {
return oldOne.decode(code);
}
// return zlib.decode(code);
}
public String encode(String text) throws IOException {
// Right now, we still use the legacy encoding.
// This will be changed in the incoming months
return zlib.encode(text);
}
}

View File

@ -0,0 +1,181 @@
/* ========================================================================
* 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.code;
import java.io.IOException;
public class TranscoderSmartProtected implements Transcoder {
// Legacy encoder
private final Transcoder oldOne = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionHuffman());
private final Transcoder zlib = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionZlib());
private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor(),
new CompressionNone());
public String decode(String code) throws NoPlantumlCompressionException {
// Work in progress
// See https://github.com/plantuml/plantuml/issues/117
if (code.startsWith("~0")) {
return decodeZlib(code.substring(2));
}
if (code.startsWith("~1")) {
return decodeHuffman(code.substring(2));
}
if (code.startsWith("~h")) {
return hexOnly.decode(code.substring(2));
}
return decodeZlib(code);
}
private String decodeZlib(String code) {
try {
return zlib.decode(code);
} catch (Exception ex) {
try {
oldOne.decode(code);
return textProtectedDeflate2(code);
} catch (Exception ex2) {
return textProtectedDeflate(code);
}
}
}
private String decodeHuffman(String code) {
try {
return oldOne.decode(code);
} catch (Exception ex) {
return textProtectedHuffman(code);
}
}
private String textProtectedHuffman(String code) {
final StringBuilder result = new StringBuilder();
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like HUFFMAN data.");
appendLine(result, "");
appendLine(result, "See https://plantuml.com/pte");
appendLine(result, "");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private String textProtectedDeflate2(String code) {
final StringBuilder result = new StringBuilder();
final String codeshort = code.length() > 30 ? code.substring(0, 30) + "..." : code;
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like DEFLATE data.");
appendLine(result, "It looks like your plugin is using HUFFMAN encoding.");
appendLine(result, "");
appendLine(result,
"This means you have now to add an header ~1 to your data. For example, you have to change:");
appendLine(result, "http://www.plantuml.com/plantuml/png/" + codeshort);
appendLine(result, "to");
appendLine(result, "http://www.plantuml.com/plantuml/png/~1" + codeshort);
appendLine(result, "");
appendLine(result, "It will work this way");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private String textProtectedDeflate(String code) {
final StringBuilder result = new StringBuilder();
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like DEFLATE data.");
appendLine(result, "");
appendLine(result, "See https://plantuml.com/pte");
appendLine(result, "");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private void appendURL(StringBuilder result, String url) {
while (url.length() > 80) {
appendLine(result, url.substring(0, 80));
url = url.substring(80);
}
if (url.length() > 0) {
appendLine(result, url);
}
}
private void appendLine(StringBuilder sb, String s) {
sb.append(s);
sb.append("\n");
}
public String encode(String text) throws IOException {
// Right now, we still use the legacy encoding.
// This will be changed in the incoming months
return zlib.encode(text);
}
}

View File

@ -0,0 +1,181 @@
/* ========================================================================
* 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.code;
import java.io.IOException;
public class TranscoderSmartProtectedPure implements Transcoder {
// Legacy encoder
private final Transcoder oldOne = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionHuffman());
private final Transcoder zlib = TranscoderImpl.utf8(new AsciiEncoder(), new ArobaseStringCompressor(),
new CompressionZlibPure());
private final Transcoder hexOnly = TranscoderImpl.utf8(new AsciiEncoderHex(), new ArobaseStringCompressor(),
new CompressionNone());
public String decode(String code) throws NoPlantumlCompressionException {
// Work in progress
// See https://github.com/plantuml/plantuml/issues/117
if (code.startsWith("~0")) {
return decodeZlib(code.substring(2));
}
if (code.startsWith("~1")) {
return decodeHuffman(code.substring(2));
}
if (code.startsWith("~h")) {
return hexOnly.decode(code.substring(2));
}
return decodeZlib(code);
}
private String decodeZlib(String code) {
try {
return zlib.decode(code);
} catch (Exception ex) {
try {
oldOne.decode(code);
return textProtectedDeflate2(code);
} catch (Exception ex2) {
return textProtectedDeflate(code);
}
}
}
private String decodeHuffman(String code) {
try {
return oldOne.decode(code);
} catch (Exception ex) {
return textProtectedHuffman(code);
}
}
private String textProtectedHuffman(String code) {
final StringBuilder result = new StringBuilder();
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like HUFFMAN data.");
appendLine(result, "");
appendLine(result, "See https://plantuml.com/pte");
appendLine(result, "");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private String textProtectedDeflate2(String code) {
final StringBuilder result = new StringBuilder();
final String codeshort = code.length() > 30 ? code.substring(0, 30) + "..." : code;
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like DEFLATE data.");
appendLine(result, "It looks like your plugin is using HUFFMAN encoding.");
appendLine(result, "");
appendLine(result,
"This means you have now to add an header ~1 to your data. For example, you have to change:");
appendLine(result, "http://www.plantuml.com/plantuml/png/" + codeshort);
appendLine(result, "to");
appendLine(result, "http://www.plantuml.com/plantuml/png/~1" + codeshort);
appendLine(result, "");
appendLine(result, "It will work this way");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private String textProtectedDeflate(String code) {
final StringBuilder result = new StringBuilder();
appendLine(result, "@startuml");
appendLine(result, "legend");
appendLine(result, "The plugin you are using seems to generated a bad URL.");
appendLine(result, "This URL does not look like DEFLATE data.");
appendLine(result, "");
appendLine(result, "See https://plantuml.com/pte");
appendLine(result, "");
appendLine(result, "You may contact the PlantUML team at plantuml@gmail.com");
appendLine(result,
"But you should also probably contact the plugin authors you are currently using and send them this image");
appendLine(result, "");
appendLine(result, "For the record, here is your data:");
appendLine(result, "");
appendURL(result, code);
appendLine(result, "endlegend");
appendLine(result, "@enduml");
return result.toString();
}
private void appendURL(StringBuilder result, String url) {
while (url.length() > 80) {
appendLine(result, url.substring(0, 80));
url = url.substring(80);
}
if (url.length() > 0) {
appendLine(result, url);
}
}
private void appendLine(StringBuilder sb, String s) {
sb.append(s);
sb.append("\n");
}
public String encode(String text) throws IOException {
// Right now, we still use the legacy encoding.
// This will be changed in the incoming months
return zlib.encode(text);
}
}

View File

@ -41,8 +41,12 @@ public class TranscoderUtil {
return new TranscoderSmart();
}
public static Transcoder getDefaultTranscoder2() {
return new TranscoderSmart2();
public static Transcoder getDefaultTranscoderProtected() {
return new TranscoderSmartProtected();
}
public static Transcoder getDefaultTranscoderProtectedPure() {
return new TranscoderSmartProtectedPure();
}
}

View File

@ -0,0 +1,156 @@
/* ========================================================================
* 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.code;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class Upf9 {
private Upf9() {
}
public static byte[] encodeChar(char c) {
final byte[] result = encodeCharInternal(c);
assert checkBack(c, result);
return result;
}
private static boolean checkBack(char c, byte[] result) {
try {
if (c == decodeChar(new ByteArrayInputStream(result)))
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private static byte[] encodeCharInternal(char c) {
if (c == '\n' || c == '\r' || c == '\t') {
return new byte[] { (byte) c };
}
if (c >= '\u0020' && c <= '\u007E') {
return new byte[] { (byte) c };
}
if (c >= '\u0080' && c <= '\u00FF') {
return new byte[] { 0x0B, (byte) c };
}
if (c >= '\u0100' && c <= '\u08FF') {
return new byte[] { highByte(c), lowByte(c) };
}
if (c >= '\u0900' && c <= '\u10FF') {
return new byte[] { (byte) (5 + highByte(c)), lowByte(c) };
}
if (c >= '\u1900' && c <= '\u1FFF') {
return new byte[] { (byte) (-3 + highByte(c)), lowByte(c) };
}
if (c >= '\u2000' && c <= '\u9FFF') {
return new byte[] { (byte) (96 + highByte(c)), lowByte(c) };
}
if (c >= '\uE000' && c <= '\uE07F') {
return new byte[] { 0x0B, lowByte(c) };
}
return new byte[] { 0x0C, highByte(c), lowByte(c) };
}
static int decodeChar(InputStream is) throws IOException {
final int read0 = is.read();
if (read0 == -1) {
return -1;
}
if (read0 == 0x0B) {
final int read1 = is.read();
if (read1 >= 0x80)
return (char) read1;
return (char) ((0xE0 << 8) + read1);
}
if (read0 == 0x0C) {
final int read1 = is.read();
final int read2 = is.read();
return (char) ((read1 << 8) + read2);
}
if (read0 >= 0x01 && read0 <= 0x08) {
final int read1 = is.read();
return (char) ((read0 << 8) + read1);
}
if (read0 >= 0x0E && read0 <= 0x15) {
final int read1 = is.read();
return (char) (((read0 - 5) << 8) + read1);
}
if (read0 >= 0x16 && read0 <= 0x1C) {
final int read1 = is.read();
return (char) (((read0 + 3) << 8) + read1);
}
if (read0 >= 0x80 && read0 <= 0xFF) {
final int read1 = is.read();
return (char) (((read0 - 96) << 8) + read1);
}
return (char) read0;
}
private static byte lowByte(char c) {
return (byte) (c & 0x00FF);
}
private static byte highByte(char c) {
return (byte) ((c & 0xFF00) >> 8);
}
public static byte[] getBytes(String s) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int i = 0; i < s.length(); i++) {
baos.write(encodeChar(s.charAt(i)));
}
baos.close();
return baos.toByteArray();
}
public static String decodeString(byte[] data, int length) throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(data, 0, length);
final StringBuilder result = new StringBuilder();
int read;
while ((read = decodeChar(bais)) != -1) {
result.append((char) read);
}
bais.close();
return result.toString();
}
}

View File

@ -0,0 +1,62 @@
package net.sourceforge.plantuml.code.deflate;
/*
* Simple DEFLATE decompressor
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/simple-deflate-decompressor
* https://github.com/nayuki/Simple-DEFLATE-decompressor
*/
import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
/**
* A stream of bits that can be read. Bits are packed in little endian within a byte.
* For example, the byte 0x87 reads as the sequence of bits [1,1,1,0,0,0,0,1].
*/
public interface BitInputStream extends Closeable {
/**
* Returns the current bit position, which ascends from 0 to 7 as bits are read.
* @return the current bit position, which is between 0 and 7
*/
public int getBitPosition();
/**
* Discards the remainder of the current byte (if any) and reads the next
* whole byte from the stream. Returns -1 if the end of stream is reached.
* @return the next byte from the stream, or -1 if the end of stream is reached
*/
public int readByte() throws IOException;
/**
* Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
* the end of stream is reached. The end of stream always occurs on a byte boundary.
* @return the next bit of 0 or 1, or -1 for the end of stream
* @throws IOException if an I/O exception occurred
*/
public int read() throws IOException;
/**
* Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException}
* if the end of stream is reached. The end of stream always occurs on a byte boundary.
* @return the next bit of 0 or 1
* @throws IOException if an I/O exception occurred
* @throws EOFException if the end of stream is reached
*/
public int readNoEof() throws IOException;
/**
* Closes this stream and the underlying input stream.
* @throws IOException if an I/O exception occurred
*/
public void close() throws IOException;
}

View File

@ -0,0 +1,98 @@
package net.sourceforge.plantuml.code.deflate;
/*
* Simple DEFLATE decompressor
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/simple-deflate-decompressor
* https://github.com/nayuki/Simple-DEFLATE-decompressor
*/
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
/**
* A stream of bits that can be read. Because they come from an underlying byte stream,
* the total number of bits is always a multiple of 8. The bits are read in little endian.
* Mutable and not thread-safe.
*/
public final class ByteBitInputStream implements BitInputStream {
/*---- Fields ----*/
// The underlying byte stream to read from (not null).
private InputStream input;
// Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
private int currentByte;
// Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
private int numBitsRemaining;
/*---- Constructor ----*/
/**
* Constructs a bit input stream based on the specified byte input stream.
* @param in the byte input stream (not {@code null})
* @throws NullPointerException if the input stream is {@code null}
*/
public ByteBitInputStream(InputStream in) {
input = Objects.requireNonNull(in);
currentByte = 0;
numBitsRemaining = 0;
}
/*---- Methods ----*/
public int getBitPosition() {
if (numBitsRemaining < 0 || numBitsRemaining > 7)
throw new IllegalStateException();
return (8 - numBitsRemaining) % 8;
}
public int readByte() throws IOException {
currentByte = 0;
numBitsRemaining = 0;
return input.read();
}
public int read() throws IOException {
if (currentByte == -1)
return -1;
if (numBitsRemaining == 0) {
currentByte = input.read();
if (currentByte == -1)
return -1;
numBitsRemaining = 8;
}
if (numBitsRemaining <= 0)
throw new IllegalStateException();
numBitsRemaining--;
return (currentByte >>> (7 - numBitsRemaining)) & 1;
}
public int readNoEof() throws IOException {
int result = read();
if (result == -1)
throw new EOFException();
return result;
}
public void close() throws IOException {
input.close();
currentByte = -1;
numBitsRemaining = 0;
}
}

View File

@ -0,0 +1,92 @@
package net.sourceforge.plantuml.code.deflate;
/*
* Simple DEFLATE decompressor
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/simple-deflate-decompressor
* https://github.com/nayuki/Simple-DEFLATE-decompressor
*/
import java.io.IOException;
import java.util.Objects;
/**
* Stores a finite recent history of a byte stream. Useful as an implicit
* dictionary for Lempel-Ziv schemes. Mutable and not thread-safe.
*/
final class ByteHistory {
/*---- Fields ----*/
// Circular buffer of byte data.
private byte[] data;
// Index of next byte to write to, always in the range [0, data.length).
private int index;
/*---- Constructor ----*/
/**
* Constructs a byte history of the specified size, initialized to zeros.
* @param size the size, which must be positive
* @throws IllegalArgumentException if size is zero or negative
*/
public ByteHistory(int size) {
if (size < 1)
throw new IllegalArgumentException("Size must be positive");
data = new byte[size];
index = 0;
}
/*---- Methods ----*/
/**
* Appends the specified byte to this history.
* This overwrites the byte value at {@code size} positions ago.
* @param b the byte value to append
*/
public void append(int b) {
if (index < 0 || index >= data.length)
throw new IllegalStateException();
data[index] = (byte)b;
index = (index + 1) % data.length;
}
/**
* Copies {@code len} bytes starting at {@code dist} bytes ago to
* the specified output stream and also back into this buffer itself.
* <p>Note that if the length exceeds the distance, then some of the output
* data will be a copy of data that was copied earlier in the process.</p>
* @param dist the distance to go back, in the range [1, size]
* @param len the length to copy, which must be at least 0
* @param out the output stream to write to (not {@code null})
* @throws NullPointerException if the output stream is {@code null}
* @throws IllegalArgumentException if the length is negative,
* distance is not positive, or distance is greater than the buffer size
* @throws IOException if an I/O exception occurs
*/
public void copy(int dist, int len, OutputStreamProtected out) throws IOException {
Objects.requireNonNull(out);
if (len < 0 || dist < 1 || dist > data.length)
throw new IllegalArgumentException();
int readIndex = (index - dist + data.length) % data.length;
if (readIndex < 0 || readIndex >= data.length)
throw new IllegalStateException();
for (int i = 0; i < len; i++) {
byte b = data[readIndex];
readIndex = (readIndex + 1) % data.length;
out.write(b);
append(b);
}
}
}

View File

@ -0,0 +1,174 @@
package net.sourceforge.plantuml.code.deflate;
/*
* Simple DEFLATE decompressor
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/simple-deflate-decompressor
* https://github.com/nayuki/Simple-DEFLATE-decompressor
*/
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
/**
* A canonical Huffman code, where the code values for each symbol is derived
* from a given sequence of code lengths. This data structure is immutable.
* This could be transformed into an explicit Huffman code tree.
* <p>Example:</p>
* <pre> Code lengths (canonical code):
* Symbol A: 1
* Symbol B: 0 (no code)
* Symbol C: 3
* Symbol D: 2
* Symbol E: 3
*
* Generated Huffman codes:
* Symbol A: 0
* Symbol B: (Absent)
* Symbol C: 110
* Symbol D: 10
* Symbol E: 111
*
* Huffman code tree:
* .
* / \
* A .
* / \
* D .
* / \
* C E</pre>
*/
final class CanonicalCode {
/*
* These arrays store the Huffman codes and values necessary for decoding.
* symbolCodeBits contains Huffman codes, each padded with a 1 bit at the
* beginning to disambiguate codes of different lengths (e.g. otherwise we
* can't distinguish 0b01 from 0b0001). Each symbolCodeBits[i] decodes to its
* corresponding symbolValues[i]. Values in symbolCodeBits are strictly increasing.
*
* For the example of codeLengths=[1,0,3,2,3], we would have:
* i | symbolCodeBits[i] | symbolValues[i]
* --+-------------------+----------------
* 0 | 0b1_0 | 0
* 1 | 0b1_10 | 3
* 2 | 0b1_110 | 2
* 3 | 0b1_111 | 4
*/
private int[] symbolCodeBits;
private int[] symbolValues;
/**
* Constructs a canonical Huffman code from the specified array of symbol code lengths.
* Each code length must be non-negative. Code length 0 means no code for the symbol.
* The collection of code lengths must represent a proper full Huffman code tree.
* <p>Examples of code lengths that result in correct full Huffman code trees:</p>
* <ul>
* <li>[1, 1] (result: A=0, B=1)</li>
* <li>[2, 2, 1, 0, 0, 0] (result: A=10, B=11, C=0)</li>
* <li>[3, 3, 3, 3, 3, 3, 3, 3] (result: A=000, B=001, C=010, ..., H=111)</li>
* </ul>
* <p>Examples of code lengths that result in under-full Huffman code trees:</p>
* <ul>
* <li>[0, 2, 0] (result: B=00, unused=01, unused=1)</li>
* <li>[0, 1, 0, 2] (result: B=0, D=10, unused=11)</li>
* </ul>
* <p>Examples of code lengths that result in over-full Huffman code trees:</p>
* <ul>
* <li>[1, 1, 1] (result: A=0, B=1, C=overflow)</li>
* <li>[1, 1, 2, 2, 3, 3, 3, 3] (result: A=0, B=1, C=overflow, ...)</li>
* </ul>
* @param canonicalCodeLengths array of symbol code lengths (not {@code null})
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if any element is negative, any value exceeds MAX_CODE_LENGTH,
* or the collection of code lengths would yield an under-full or over-full Huffman code tree
*/
public CanonicalCode(int[] codeLengths) {
// Check argument values
Objects.requireNonNull(codeLengths);
for (int x : codeLengths) {
if (x < 0)
throw new IllegalArgumentException("Negative code length");
if (x > MAX_CODE_LENGTH)
throw new IllegalArgumentException("Maximum code length exceeded");
}
// Allocate code values to symbols. Symbols are processed in the order
// of shortest code length first, breaking ties by lowest symbol value.
symbolCodeBits = new int[codeLengths.length];
symbolValues = new int[codeLengths.length];
int numSymbolsAllocated = 0;
int nextCode = 0;
for (int codeLength = 1; codeLength <= MAX_CODE_LENGTH; codeLength++) {
nextCode <<= 1;
int startBit = 1 << codeLength;
for (int symbol = 0; symbol < codeLengths.length; symbol++) {
if (codeLengths[symbol] != codeLength)
continue;
if (nextCode >= startBit)
throw new IllegalArgumentException("This canonical code produces an over-full Huffman code tree");
symbolCodeBits[numSymbolsAllocated] = startBit | nextCode;
symbolValues [numSymbolsAllocated] = symbol;
numSymbolsAllocated++;
nextCode++;
}
}
if (nextCode != 1 << MAX_CODE_LENGTH)
throw new IllegalArgumentException("This canonical code produces an under-full Huffman code tree");
// Trim unused trailing elements
symbolCodeBits = Arrays.copyOf(symbolCodeBits, numSymbolsAllocated);
symbolValues = Arrays.copyOf(symbolValues , numSymbolsAllocated);
}
/**
* Decodes the next symbol from the specified bit input stream based on this
* canonical code. The returned symbol value is in the range [0, codeLengths.length).
* @param in the bit input stream to read from
* @return the next decoded symbol
* @throws IOException if an I/O exception occurred
*/
public int decodeNextSymbol(BitInputStream in) throws IOException {
Objects.requireNonNull(in);
int codeBits = 1; // The start bit
while (true) {
// Accumulate one bit at a time on the right side until a match is
// found in the symbolCodeBits array. Because the Huffman code tree is
// full, this loop must terminate after at most MAX_CODE_LENGTH iterations.
codeBits = codeBits << 1 | in.readNoEof();
int index = Arrays.binarySearch(symbolCodeBits, codeBits);
if (index >= 0)
return symbolValues[index];
}
}
/**
* Returns a string representation of this canonical code,
* useful for debugging only, and the format is subject to change.
* @return a string representation of this canonical code
*/
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < symbolCodeBits.length; i++) {
sb.append(String.format("Code %s: Symbol %d%n",
Integer.toBinaryString(symbolCodeBits[i]).substring(1),
symbolValues[i]));
}
return sb.toString();
}
// The maximum Huffman code length allowed in the DEFLATE standard.
private static final int MAX_CODE_LENGTH = 15;
}

View File

@ -0,0 +1,300 @@
package net.sourceforge.plantuml.code.deflate;
import java.io.EOFException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.zip.DataFormatException;
/**
* Decompresses raw DEFLATE data (without zlib or gzip container) into bytes.
*/
public final class Decompressor {
/*---- Public functions ----*/
/**
* Reads from the specified input stream, decompress the data, and returns a new byte array.
* @param in the bit input stream to read from (not {@code null})
* @throws NullPointerException if the input stream is {@code null}
* @throws DataFormatException if the DEFLATE data is malformed
*/
public static byte[] decompress(BitInputStream in) throws IOException, DataFormatException {
OutputStreamProtected out = new OutputStreamProtected();
decompress(in, out);
return out.toByteArray();
}
/**
* Reads from the specified input stream, decompress the data, and writes to the specified output stream.
* @param in the bit input stream to read from (not {@code null})
* @param out the byte output stream to write to (not {@code null})
* @throws NullPointerException if the input or output stream is {@code null}
* @throws DataFormatException if the DEFLATE data is malformed
*/
public static void decompress(BitInputStream in, OutputStreamProtected out) throws IOException, DataFormatException {
new Decompressor(in, out);
}
/*---- Private implementation ----*/
private BitInputStream input;
private OutputStreamProtected output;
private ByteHistory dictionary;
// Constructor, which immediately performs decompression
private Decompressor(BitInputStream in, OutputStreamProtected out) throws IOException, DataFormatException {
// Initialize fields
input = Objects.requireNonNull(in);
output = Objects.requireNonNull(out);
dictionary = new ByteHistory(32 * 1024);
// Process the stream of blocks
boolean isFinal;
do {
// Read the block header
isFinal = in.readNoEof() == 1; // bfinal
int type = readInt(2); // btype
// Decompress rest of block based on the type
if (type == 0)
decompressUncompressedBlock();
else if (type == 1)
decompressHuffmanBlock(FIXED_LITERAL_LENGTH_CODE, FIXED_DISTANCE_CODE);
else if (type == 2) {
CanonicalCode[] litLenAndDist = decodeHuffmanCodes();
decompressHuffmanBlock(litLenAndDist[0], litLenAndDist[1]);
} else if (type == 3)
throw new DataFormatException("Reserved block type");
else
throw new IllegalStateException("Impossible value");
} while (!isFinal);
}
/*-- The constant code trees for static Huffman codes (btype = 1) --*/
private static final CanonicalCode FIXED_LITERAL_LENGTH_CODE;
private static final CanonicalCode FIXED_DISTANCE_CODE;
static { // Make temporary tables of canonical code lengths
int[] llcodelens = new int[288];
Arrays.fill(llcodelens, 0, 144, 8);
Arrays.fill(llcodelens, 144, 256, 9);
Arrays.fill(llcodelens, 256, 280, 7);
Arrays.fill(llcodelens, 280, 288, 8);
FIXED_LITERAL_LENGTH_CODE = new CanonicalCode(llcodelens);
int[] distcodelens = new int[32];
Arrays.fill(distcodelens, 5);
FIXED_DISTANCE_CODE = new CanonicalCode(distcodelens);
}
/*-- Method for reading and decoding dynamic Huffman codes (btype = 2) --*/
// Reads from the bit input stream, decodes the Huffman code
// specifications into code trees, and returns the trees.
private CanonicalCode[] decodeHuffmanCodes() throws IOException, DataFormatException {
int numLitLenCodes = readInt(5) + 257; // hlit + 257
int numDistCodes = readInt(5) + 1; // hdist + 1
// Read the code length code lengths
int numCodeLenCodes = readInt(4) + 4; // hclen + 4
int[] codeLenCodeLen = new int[19]; // This array is filled in a strange order
codeLenCodeLen[16] = readInt(3);
codeLenCodeLen[17] = readInt(3);
codeLenCodeLen[18] = readInt(3);
codeLenCodeLen[ 0] = readInt(3);
for (int i = 0; i < numCodeLenCodes - 4; i++) {
int j = (i % 2 == 0) ? (8 + i / 2) : (7 - i / 2);
codeLenCodeLen[j] = readInt(3);
}
// Create the code length code
CanonicalCode codeLenCode;
try {
codeLenCode = new CanonicalCode(codeLenCodeLen);
} catch (IllegalArgumentException e) {
throw new DataFormatException(e.getMessage());
}
// Read the main code lengths and handle runs
int[] codeLens = new int[numLitLenCodes + numDistCodes];
for (int codeLensIndex = 0; codeLensIndex < codeLens.length; ) {
int sym = codeLenCode.decodeNextSymbol(input);
if (0 <= sym && sym <= 15) {
codeLens[codeLensIndex] = sym;
codeLensIndex++;
} else {
int runLen;
int runVal = 0;
if (sym == 16) {
if (codeLensIndex == 0)
throw new DataFormatException("No code length value to copy");
runLen = readInt(2) + 3;
runVal = codeLens[codeLensIndex - 1];
} else if (sym == 17)
runLen = readInt(3) + 3;
else if (sym == 18)
runLen = readInt(7) + 11;
else
throw new IllegalStateException("Symbol out of range");
int end = codeLensIndex + runLen;
if (end > codeLens.length)
throw new DataFormatException("Run exceeds number of codes");
Arrays.fill(codeLens, codeLensIndex, end, runVal);
codeLensIndex = end;
}
}
// Create literal-length code tree
int[] litLenCodeLen = Arrays.copyOf(codeLens, numLitLenCodes);
CanonicalCode litLenCode;
try {
litLenCode = new CanonicalCode(litLenCodeLen);
} catch (IllegalArgumentException e) {
throw new DataFormatException(e.getMessage());
}
// Create distance code tree with some extra processing
int[] distCodeLen = Arrays.copyOfRange(codeLens, numLitLenCodes, codeLens.length);
CanonicalCode distCode;
if (distCodeLen.length == 1 && distCodeLen[0] == 0)
distCode = null; // Empty distance code; the block shall be all literal symbols
else {
// Get statistics for upcoming logic
int oneCount = 0;
int otherPositiveCount = 0;
for (int x : distCodeLen) {
if (x == 1)
oneCount++;
else if (x > 1)
otherPositiveCount++;
}
// Handle the case where only one distance code is defined
if (oneCount == 1 && otherPositiveCount == 0) {
// Add a dummy invalid code to make the Huffman tree complete
distCodeLen = Arrays.copyOf(distCodeLen, 32);
distCodeLen[31] = 1;
}
try {
distCode = new CanonicalCode(distCodeLen);
} catch (IllegalArgumentException e) {
throw new DataFormatException(e.getMessage());
}
}
return new CanonicalCode[]{litLenCode, distCode};
}
/*-- Block decompression methods --*/
// Handles and copies an uncompressed block from the bit input stream.
private void decompressUncompressedBlock() throws IOException, DataFormatException {
// Discard bits to align to byte boundary
while (input.getBitPosition() != 0)
input.readNoEof();
// Read length
int len = readInt(16);
int nlen = readInt(16);
if ((len ^ 0xFFFF) != nlen)
throw new DataFormatException("Invalid length in uncompressed block");
// Copy bytes
for (int i = 0; i < len; i++) {
int b = input.readByte();
if (b == -1)
throw new EOFException();
output.write(b);
dictionary.append(b);
}
}
// Decompresses a Huffman-coded block from the bit input stream based on the given Huffman codes.
private void decompressHuffmanBlock(CanonicalCode litLenCode, CanonicalCode distCode)
throws IOException, DataFormatException {
Objects.requireNonNull(litLenCode);
// distCode is allowed to be null
while (true) {
int sym = litLenCode.decodeNextSymbol(input);
if (sym == 256) // End of block
break;
if (sym < 256) { // Literal byte
output.write(sym);
dictionary.append(sym);
} else { // Length and distance for copying
int run = decodeRunLength(sym);
if (run < 3 || run > 258)
throw new IllegalStateException("Invalid run length");
if (distCode == null)
throw new DataFormatException("Length symbol encountered with empty distance code");
int distSym = distCode.decodeNextSymbol(input);
int dist = decodeDistance(distSym);
if (dist < 1 || dist > 32768)
throw new IllegalStateException("Invalid distance");
dictionary.copy(dist, run, output);
}
}
}
/*-- Symbol decoding methods --*/
// Returns the run length based on the given symbol and possibly reading more bits.
private int decodeRunLength(int sym) throws IOException, DataFormatException {
if (sym < 257 || sym > 287) // Cannot occur in the bit stream; indicates the decompressor is buggy
throw new IllegalStateException("Invalid run length symbol: " + sym);
else if (sym <= 264)
return sym - 254;
else if (sym <= 284) {
int numExtraBits = (sym - 261) / 4;
return (((sym - 265) % 4 + 4) << numExtraBits) + 3 + readInt(numExtraBits);
} else if (sym == 285)
return 258;
else // sym is 286 or 287
throw new DataFormatException("Reserved length symbol: " + sym);
}
// Returns the distance based on the given symbol and possibly reading more bits.
private int decodeDistance(int sym) throws IOException, DataFormatException {
if (sym < 0 || sym > 31) // Cannot occur in the bit stream; indicates the decompressor is buggy
throw new IllegalStateException("Invalid distance symbol: " + sym);
if (sym <= 3)
return sym + 1;
else if (sym <= 29) {
int numExtraBits = sym / 2 - 1;
return ((sym % 2 + 2) << numExtraBits) + 1 + readInt(numExtraBits);
} else // sym is 30 or 31
throw new DataFormatException("Reserved distance symbol: " + sym);
}
/*-- Utility method --*/
// Reads the given number of bits from the bit input stream as a single integer, packed in little endian.
private int readInt(int numBits) throws IOException {
if (numBits < 0 || numBits > 31)
throw new IllegalArgumentException();
int result = 0;
for (int i = 0; i < numBits; i++)
result |= input.readNoEof() << i;
return result;
}
}

View File

@ -0,0 +1,38 @@
package net.sourceforge.plantuml.code.deflate;
import java.io.ByteArrayOutputStream;
/*
* Simple DEFLATE decompressor
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/simple-deflate-decompressor
* https://github.com/nayuki/Simple-DEFLATE-decompressor
*/
import java.io.Closeable;
import java.io.IOException;
public class OutputStreamProtected implements Closeable {
private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
private int counter = 0;
public void close() throws IOException {
baos.close();
}
public byte[] toByteArray() {
return baos.toByteArray();
}
public void write(int b) throws IOException {
this.counter++;
baos.write(b);
if (counter > 128000) {
throw new IOException("Too big");
}
}
}

View File

@ -57,7 +57,13 @@ public class BlocLines implements Iterable<StringLocated> {
@Override
public String toString() {
return lines.toString();
final StringBuilder sb = new StringBuilder();
for (StringLocated line : lines) {
sb.append("<<<");
sb.append(line);
sb.append(">>>");
}
return sb.toString();
}
public static BlocLines load(File f, LineLocation location) throws IOException {
@ -88,7 +94,7 @@ public class BlocLines implements Iterable<StringLocated> {
return Display.createFoo(lines);
}
public static BlocLines single2(StringLocated single) {
public static BlocLines single(StringLocated single) {
final List<StringLocated> result = new ArrayList<StringLocated>();
result.add(single);
return new BlocLines(result);
@ -120,7 +126,7 @@ public class BlocLines implements Iterable<StringLocated> {
this(new ArrayList<StringLocated>());
}
public BlocLines add2(StringLocated s) {
public BlocLines add(StringLocated s) {
final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
copy.add(s);
return new BlocLines(copy);
@ -132,10 +138,6 @@ public class BlocLines implements Iterable<StringLocated> {
return new BlocLines(copy);
}
// public List<CharSequence2> getLines() {
// return lines2;
// }
public List<String> getLinesAsStringForSprite() {
final List<String> result = new ArrayList<String>();
for (StringLocated s : lines) {
@ -148,43 +150,55 @@ public class BlocLines implements Iterable<StringLocated> {
return lines.size();
}
public StringLocated get499(int i) {
public StringLocated getAt(int i) {
return lines.get(i);
}
public StringLocated getFirst499() {
public StringLocated getFirst() {
if (lines.size() == 0) {
return null;
}
return lines.get(0);
}
public StringLocated getLast499() {
public StringLocated getLast() {
return lines.get(lines.size() - 1);
}
public BlocLines cleanList2(MultilinesStrategy strategy) {
public BlocLines cleanList(MultilinesStrategy strategy) {
final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
strategy.cleanList(copy);
return new BlocLines(copy);
}
public BlocLines trim(boolean removeEmptyLines) {
public BlocLines trim() {
final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
for (int i = 0; i < copy.size(); i++) {
final StringLocated s = copy.get(i);
copy.set(i, new StringLocated(s.getTrimmed().getString(), s.getLocation()));
copy.set(i, s.getTrimmed());
}
if (removeEmptyLines) {
for (final Iterator<StringLocated> it = copy.iterator(); it.hasNext();) {
if (it.next().getString().length() == 0) {
it.remove();
}
return new BlocLines(copy);
}
public BlocLines removeEmptyLines() {
final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
for (final Iterator<StringLocated> it = copy.iterator(); it.hasNext();) {
if (it.next().getString().length() == 0) {
it.remove();
}
}
return new BlocLines(copy);
}
// public BlocLines trimRight() {
// final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
// for (int i = 0; i < copy.size(); i++) {
// final StringLocated s = copy.get(i);
// copy.set(i, s.getTrimmedRight());
// }
// return new BlocLines(copy);
// }
public BlocLines removeEmptyColumns() {
if (firstColumnRemovable(lines) == false) {
return this;
@ -221,7 +235,7 @@ public class BlocLines implements Iterable<StringLocated> {
return s.getString().charAt(s.getString().length() - 1);
}
public BlocLines removeStartingAndEnding2(String data) {
public BlocLines removeStartingAndEnding(String data, int removeAtEnd) {
if (lines.size() == 0) {
return this;
}
@ -229,7 +243,18 @@ public class BlocLines implements Iterable<StringLocated> {
copy.set(0, new StringLocated(data, null));
final int n = copy.size() - 1;
final StringLocated s = copy.get(n);
copy.set(n, s.substring(0, s.getString().length() - 1));
copy.set(n, s.substring(0, s.getString().length() - removeAtEnd));
return new BlocLines(copy);
}
public BlocLines overrideLastLine(String last) {
if (lines.size() == 0) {
return this;
}
final List<StringLocated> copy = new ArrayList<StringLocated>(lines);
final int n = copy.size() - 1;
final StringLocated currentLast = copy.get(n);
copy.set(n, new StringLocated(last, currentLast.getLocation()));
return new BlocLines(copy);
}
@ -299,10 +324,10 @@ public class BlocLines implements Iterable<StringLocated> {
if (size() < 2) {
return this;
}
final String first = getFirst499().getTrimmed().getString();
final String second = get499(1).getTrimmed().getString();
final String first = getFirst().getTrimmed().getString();
final String second = getAt(1).getTrimmed().getString();
if (first.endsWith("{") == false && second.equals("{")) {
final StringLocated vline = getFirst499().append(" {");
final StringLocated vline = getFirst().append(" {");
final List<StringLocated> result = new ArrayList<StringLocated>();
result.add(vline);
result.addAll(this.lines.subList(2, this.lines.size()));

View File

@ -66,7 +66,7 @@ public class CommandDecoratorMultine<D extends Diagram> implements Command<D> {
return CommandControl.NOT_OK;
}
lines = lines.toSingleLineWithHiddenNewLine();
if (cmd.isForbidden(lines.getFirst499().getString())) {
if (cmd.isForbidden(lines.getFirst().getString())) {
return CommandControl.NOT_OK;
}
final CommandControl tmp = cmd.isValid(lines);

View File

@ -82,7 +82,8 @@ public final class CommandFactorySprite implements SingleMultiFactoryCommand<Wit
return new SingleLineCommand2<WithSprite>(getRegexConcatSingleLine()) {
@Override
protected CommandExecutionResult executeArg(final WithSprite system, LineLocation location, RegexResult arg) {
protected CommandExecutionResult executeArg(final WithSprite system, LineLocation location,
RegexResult arg) {
return executeInternal(system, arg, Arrays.asList((String) arg.get("DATA", 0)));
}
@ -98,8 +99,8 @@ public final class CommandFactorySprite implements SingleMultiFactoryCommand<Wit
}
protected CommandExecutionResult executeNow(final WithSprite system, BlocLines lines) {
lines = lines.trim(true);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
lines = lines.trim().removeEmptyLines();
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
@ -113,33 +114,32 @@ public final class CommandFactorySprite implements SingleMultiFactoryCommand<Wit
}
private CommandExecutionResult executeInternal(WithSprite system, RegexResult line0, final List<String> strings) {
try {
final Sprite sprite;
if (line0.get("DIM", 0) == null) {
sprite = SpriteGrayLevel.GRAY_16.buildSprite(-1, -1, strings);
} else {
final int width = Integer.parseInt(line0.get("DIM", 0));
final int height = Integer.parseInt(line0.get("DIM", 1));
if (line0.get("DIM", 4) == null) {
final int nbLevel = Integer.parseInt(line0.get("DIM", 2));
if (nbLevel != 4 && nbLevel != 8 && nbLevel != 16) {
return CommandExecutionResult.error("Only 4, 8 or 16 graylevel are allowed.");
}
final SpriteGrayLevel level = SpriteGrayLevel.get(nbLevel);
if (line0.get("DIM", 3) == null) {
sprite = level.buildSprite(width, height, strings);
} else {
sprite = level.buildSpriteZ(width, height, concat(strings));
}
} else {
sprite = SpriteColorBuilder4096.buildSprite(strings);
final Sprite sprite;
if (line0.get("DIM", 0) == null) {
sprite = SpriteGrayLevel.GRAY_16.buildSprite(-1, -1, strings);
} else {
final int width = Integer.parseInt(line0.get("DIM", 0));
final int height = Integer.parseInt(line0.get("DIM", 1));
if (line0.get("DIM", 4) == null) {
final int nbLevel = Integer.parseInt(line0.get("DIM", 2));
if (nbLevel != 4 && nbLevel != 8 && nbLevel != 16) {
return CommandExecutionResult.error("Only 4, 8 or 16 graylevel are allowed.");
}
final SpriteGrayLevel level = SpriteGrayLevel.get(nbLevel);
if (line0.get("DIM", 3) == null) {
sprite = level.buildSprite(width, height, strings);
} else {
sprite = level.buildSpriteZ(width, height, concat(strings));
if (sprite == null) {
return CommandExecutionResult.error("Cannot decode sprite.");
}
}
} else {
sprite = SpriteColorBuilder4096.buildSprite(strings);
}
system.addSprite(line0.get("NAME", 0), sprite);
return CommandExecutionResult.ok();
} catch (IOException e) {
return CommandExecutionResult.error("Cannot decode sprite.");
}
system.addSprite(line0.get("NAME", 0), sprite);
return CommandExecutionResult.ok();
}
private String concat(final List<String> strings) {

View File

@ -61,7 +61,7 @@ public abstract class CommandMultilines<S extends Diagram> implements Command<S>
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
Matcher2 m1 = starting.matcher(lines.getFirst499().getTrimmed().getString());
Matcher2 m1 = starting.matcher(lines.getFirst().getTrimmed().getString());
if (m1.matches() == false) {
return CommandControl.NOT_OK;
}
@ -69,7 +69,7 @@ public abstract class CommandMultilines<S extends Diagram> implements Command<S>
return CommandControl.OK_PARTIAL;
}
m1 = MyPattern.cmpile(getPatternEnd()).matcher(lines.getLast499().getTrimmed().getString());
m1 = MyPattern.cmpile(getPatternEnd()).matcher(lines.getLast().getTrimmed().getString());
if (m1.matches() == false) {
return CommandControl.OK_PARTIAL;
}

View File

@ -66,13 +66,13 @@ public abstract class CommandMultilines2<S extends Diagram> implements Command<S
}
final public CommandControl isValid(BlocLines lines) {
lines = lines.cleanList2(strategy);
lines = lines.cleanList(strategy);
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
if (syntaxWithFinalBracket()) {
if (lines.size() == 1 && lines.getFirst499().getTrimmed().getString().endsWith("{") == false) {
final String vline = ((StringLocated) lines.get499(0)).getString() + " {";
if (lines.size() == 1 && lines.getFirst().getTrimmed().getString().endsWith("{") == false) {
final String vline = ((StringLocated) lines.getAt(0)).getString() + " {";
if (isValid(BlocLines.singleString(vline)) == CommandControl.OK_PARTIAL) {
return CommandControl.OK_PARTIAL;
}
@ -80,7 +80,7 @@ public abstract class CommandMultilines2<S extends Diagram> implements Command<S
}
lines = lines.eventuallyMoveBracket();
}
final StringLocated first = lines.getFirst499();
final StringLocated first = lines.getFirst();
if (first == null) {
return CommandControl.NOT_OK;
}
@ -92,7 +92,7 @@ public abstract class CommandMultilines2<S extends Diagram> implements Command<S
return CommandControl.OK_PARTIAL;
}
final Matcher2 m1 = MyPattern.cmpile(getPatternEnd()).matcher(lines.getLast499().getTrimmed().getString());
final Matcher2 m1 = MyPattern.cmpile(getPatternEnd()).matcher(lines.getLast().getTrimmed().getString());
if (m1.matches() == false) {
return CommandControl.OK_PARTIAL;
}
@ -102,7 +102,7 @@ public abstract class CommandMultilines2<S extends Diagram> implements Command<S
}
public final CommandExecutionResult execute(S system, BlocLines lines) {
lines = lines.cleanList2(strategy);
lines = lines.cleanList(strategy);
if (syntaxWithFinalBracket()) {
lines = lines.eventuallyMoveBracket();
}

View File

@ -61,11 +61,11 @@ public abstract class CommandMultilines3<S extends Diagram> implements Command<S
}
final public CommandControl isValid(BlocLines lines) {
lines = lines.cleanList2(strategy);
lines = lines.cleanList(strategy);
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
final StringLocated first = lines.getFirst499();
final StringLocated first = lines.getFirst();
if (first == null) {
return CommandControl.NOT_OK;
}
@ -77,7 +77,7 @@ public abstract class CommandMultilines3<S extends Diagram> implements Command<S
return CommandControl.OK_PARTIAL;
}
final StringLocated potentialLast = lines.getLast499().getTrimmed();
final StringLocated potentialLast = lines.getLast().getTrimmed();
final boolean m1 = getPatternEnd2().match(potentialLast);
if (m1 == false) {
return CommandControl.OK_PARTIAL;
@ -88,7 +88,7 @@ public abstract class CommandMultilines3<S extends Diagram> implements Command<S
}
public final CommandExecutionResult execute(S system, BlocLines lines) {
lines = lines.cleanList2(strategy);
lines = lines.cleanList(strategy);
return executeNow(system, lines);
}

View File

@ -71,7 +71,7 @@ public abstract class CommandMultilinesBracket<S extends Diagram> implements Com
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
final Matcher2 m1 = starting.matcher(lines.getFirst499().getTrimmed().getString());
final Matcher2 m1 = starting.matcher(lines.getFirst().getTrimmed().getString());
if (m1.matches() == false) {
return CommandControl.NOT_OK;
}

View File

@ -0,0 +1,66 @@
/* ========================================================================
* 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.command;
import net.sourceforge.plantuml.TitledDiagram;
import net.sourceforge.plantuml.cucadiagram.Display;
import net.sourceforge.plantuml.cucadiagram.DisplayPositionned;
import net.sourceforge.plantuml.graphic.HorizontalAlignment;
import net.sourceforge.plantuml.graphic.VerticalAlignment;
public class CommandMultilinesCaption extends CommandMultilines<TitledDiagram> {
public CommandMultilinesCaption() {
super("(?i)^caption$");
}
@Override
public String getPatternEnd() {
return "(?i)^end[%s]?caption$";
}
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
final Display strings = lines.toDisplay();
if (strings.size() > 0) {
diagram.setCaption(DisplayPositionned.single(strings.replaceBackslashT(), HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM));
return CommandExecutionResult.ok();
}
return CommandExecutionResult.error("No caption defined");
}
}

View File

@ -55,8 +55,8 @@ public class CommandMultilinesFooter extends CommandMultilines<TitledDiagram> {
}
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
lines = lines.trim(false);
final Matcher2 m = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
lines = lines.trim();
final Matcher2 m = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
if (m.find() == false) {
throw new IllegalStateException();
}

View File

@ -55,8 +55,8 @@ public class CommandMultilinesHeader extends CommandMultilines<TitledDiagram> {
}
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
lines = lines.trim(false);
final Matcher2 m = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
lines = lines.trim();
final Matcher2 m = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
if (m.find() == false) {
throw new IllegalStateException();
}

View File

@ -75,7 +75,7 @@ public class CommandMultilinesLegend extends CommandMultilines2<TitledDiagram> {
@Override
protected CommandExecutionResult executeNow(TitledDiagram diagram, BlocLines lines) {
lines = lines.trimSmart(1);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
final String align = line0.get("ALIGN", 0);
final String valign = line0.get("VALIGN", 0);
lines = lines.subExtract(1, 1);

View File

@ -63,7 +63,7 @@ public class CommandSkinParamMultilines extends CommandMultilinesBracket<UmlDiag
public CommandExecutionResult execute(UmlDiagram diagram, BlocLines lines) {
final SkinLoader skinLoader = new SkinLoader(diagram);
final Matcher2 mStart = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final Matcher2 mStart = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
if (mStart.find() == false) {
throw new IllegalStateException();
}

View File

@ -91,9 +91,9 @@ public abstract class SingleLineCommand2<S extends Diagram> implements Command<S
if (isCommandForbidden()) {
return CommandControl.NOT_OK;
}
final StringLocated line2 = myTrim2(lines.getFirst499());
final StringLocated line2 = myTrim2(lines.getFirst());
if (syntaxWithFinalBracket() && line2.getString().endsWith("{") == false) {
final String vline = lines.get499(0).getString() + " {";
final String vline = lines.getAt(0).getString() + " {";
if (isValid(BlocLines.singleString(vline)) == CommandControl.OK) {
return CommandControl.OK_PARTIAL;
}
@ -109,10 +109,10 @@ public abstract class SingleLineCommand2<S extends Diagram> implements Command<S
private CommandControl isValidBracket(BlocLines lines) {
assert lines.size() == 2;
assert syntaxWithFinalBracket();
if (myTrim(lines.get499(1)).equals("{") == false) {
if (myTrim(lines.getAt(1)).equals("{") == false) {
return CommandControl.NOT_OK;
}
final String vline = lines.get499(0).getString() + " {";
final String vline = lines.getAt(0).getString() + " {";
return isValid(BlocLines.singleString(vline));
}
@ -125,13 +125,13 @@ public abstract class SingleLineCommand2<S extends Diagram> implements Command<S
public final CommandExecutionResult execute(S system, BlocLines lines) {
if (syntaxWithFinalBracket() && lines.size() == 2) {
assert myTrim(lines.get499(1)).equals("{");
lines = BlocLines.singleString(lines.getFirst499().getString() + " {");
assert myTrim(lines.getAt(1)).equals("{");
lines = BlocLines.singleString(lines.getFirst().getString() + " {");
}
if (lines.size() != 1) {
throw new IllegalArgumentException();
}
final StringLocated first = lines.getFirst499();
final StringLocated first = lines.getFirst();
final String line = myTrim(first);
if (isForbidden(line)) {
return CommandExecutionResult.error("Syntax error: " + line);

View File

@ -79,7 +79,7 @@ public class SkinLoader {
}
lines = lines.subExtract(1, 1);
lines = lines.trim(true);
lines = lines.trim().removeEmptyLines();
for (StringLocated s : lines) {
assert s.getString().length() > 0;

View File

@ -128,7 +128,7 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory {
final CommandExecutionResult result = sys.executeCommand(step.command, step.blocLines);
if (result.isOk() == false) {
final ErrorUml err = new ErrorUml(ErrorUmlType.EXECUTION_ERROR, result.getError(),
((StringLocated) step.blocLines.getFirst499()).getLocation());
((StringLocated) step.blocLines.getFirst()).getLocation());
sys = PSystemErrorUtils.buildV2(source, err, result.getDebugLines(), it.getTrace());
}
if (result.getNewDiagram() != null) {
@ -150,7 +150,7 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory {
}
private Step getCandidate(final IteratorCounter2 it) {
final BlocLines single = BlocLines.single2(it.peek());
final BlocLines single = BlocLines.single(it.peek());
if (cmds == null) {
cmds = createCommands();
}
@ -196,11 +196,11 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory {
private BlocLines addOneSingleLineManageEmbedded2(IteratorCounter2 it, BlocLines lines) {
final StringLocated linetoBeAdded = it.next();
lines = lines.add2(linetoBeAdded);
lines = lines.add(linetoBeAdded);
if (linetoBeAdded.getTrimmed().getString().equals("{{")) {
while (it.hasNext()) {
final StringLocated s = it.next();
lines = lines.add2(s);
lines = lines.add(s);
if (s.getTrimmed().getString().equals("}}")) {
return lines;
}
@ -258,6 +258,7 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory {
cmds.add(new CommandTitle());
cmds.add(new CommandMainframe());
cmds.add(new CommandCaption());
cmds.add(new CommandMultilinesCaption());
cmds.add(new CommandMultilinesTitle());
cmds.add(new CommandMultilinesLegend());

View File

@ -117,7 +117,7 @@ public final class CommandFactoryNote implements SingleMultiFactoryCommand<Abstr
protected CommandExecutionResult executeNow(final AbstractEntityDiagram system, BlocLines lines) {
// StringUtils.trim(lines, false);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
return executeInternal(system, line0, lines);

View File

@ -100,7 +100,7 @@ public final class CommandFactoryNoteActivity implements SingleMultiFactoryComma
public final CommandExecutionResult executeNow(final ActivityDiagram diagram, BlocLines lines) {
// StringUtils.trim(lines, true);
final RegexResult arg = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult arg = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();

View File

@ -35,6 +35,8 @@
*/
package net.sourceforge.plantuml.command.note;
import net.sourceforge.plantuml.ColorParam;
import net.sourceforge.plantuml.FontParam;
import net.sourceforge.plantuml.LineLocation;
import net.sourceforge.plantuml.StringUtils;
import net.sourceforge.plantuml.Url;
@ -63,6 +65,7 @@ import net.sourceforge.plantuml.cucadiagram.Link;
import net.sourceforge.plantuml.cucadiagram.LinkDecor;
import net.sourceforge.plantuml.cucadiagram.LinkType;
import net.sourceforge.plantuml.cucadiagram.Stereotag;
import net.sourceforge.plantuml.cucadiagram.Stereotype;
import net.sourceforge.plantuml.graphic.color.ColorParser;
import net.sourceforge.plantuml.graphic.color.ColorType;
import net.sourceforge.plantuml.graphic.color.Colors;
@ -89,6 +92,8 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
RegexLeaf.spaceOneOrMore(), partialPattern), //
new RegexLeaf("")), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("TAGS", Stereotag.pattern() + "?"), //
RegexLeaf.spaceZeroOrMore(), //
color().getRegex(), //
@ -99,7 +104,7 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("NOTE", "(.*)"), //
RegexLeaf.end() //
);
);
}
private static ColorParser color() {
@ -120,6 +125,8 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
partialPattern), //
new RegexLeaf("")), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("TAGS", Stereotag.pattern() + "?"), //
RegexLeaf.spaceZeroOrMore(), //
color().getRegex(), //
@ -128,7 +135,7 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("\\{"), //
RegexLeaf.end() //
);
);
}
return RegexConcat.build(CommandFactoryNoteOnEntity.class.getName() + key + "multi" + withBracket,
RegexLeaf.start(), //
@ -142,13 +149,15 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
partialPattern), //
new RegexLeaf("")), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("TAGS", Stereotag.pattern() + "?"), //
RegexLeaf.spaceZeroOrMore(), //
color().getRegex(), //
RegexLeaf.spaceZeroOrMore(), //
new RegexLeaf("URL", "(" + UrlBuilder.getRegexp() + ")?"), //
RegexLeaf.end() //
);
);
}
public Command<AbstractEntityDiagram> createSingleLine() {
@ -177,7 +186,7 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
protected CommandExecutionResult executeNow(final AbstractEntityDiagram system, BlocLines lines) {
// StringUtils.trim(lines, false);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
@ -226,15 +235,24 @@ public final class CommandFactoryNoteOnEntity implements SingleMultiFactoryComma
else
note = diagram.createLeaf(idNewLong, diagram.buildCode(tmp), strings.toDisplay(), LeafType.NOTE, null);
final Colors colors = color().getColor(line0, diagram.getSkinParam().getIHtmlColorSet());
Colors colors = color().getColor(line0, diagram.getSkinParam().getIHtmlColorSet());
final String stereotypeString = line0.get("STEREO", 0);
if (stereotypeString != null) {
final Stereotype stereotype = new Stereotype(stereotypeString);
colors = colors.applyStereotypeForNote(stereotype, diagram.getSkinParam(), FontParam.NOTE,
ColorParam.noteBackground, ColorParam.noteBorder);
note.setStereotype(stereotype);
}
note.setColors(colors);
if (url != null) {
note.addUrl(url);
}
CommandCreateClassMultilines.addTags(note, line0.get("TAGS", 0));
final Position position = Position.valueOf(StringUtils.goUpperCase(pos)).withRankdir(
diagram.getSkinParam().getRankdir());
final Position position = Position.valueOf(StringUtils.goUpperCase(pos))
.withRankdir(diagram.getSkinParam().getRankdir());
final Link link;
final LinkType type = new LinkType(LinkDecor.NONE, LinkDecor.NONE).goDashed();

View File

@ -102,7 +102,7 @@ public final class CommandFactoryNoteOnLink implements SingleMultiFactoryCommand
}
protected CommandExecutionResult executeNow(final CucaDiagram system, BlocLines lines) {
final String line0 = lines.getFirst499().getTrimmed().getString();
final String line0 = lines.getFirst().getTrimmed().getString();
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
if (lines.size() > 0) {

View File

@ -123,7 +123,7 @@ public final class CommandFactoryTipOnEntity implements SingleMultiFactoryComman
protected CommandExecutionResult executeNow(final AbstractEntityDiagram system, BlocLines lines) {
// StringUtils.trim(lines, false);
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();

View File

@ -127,7 +127,7 @@ public final class FactorySequenceNoteAcrossCommand implements SingleMultiFactor
}
protected CommandExecutionResult executeNow(final SequenceDiagram system, BlocLines lines) {
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
return executeInternal(system, line0, lines);

View File

@ -120,7 +120,7 @@ public final class FactorySequenceNoteCommand implements SingleMultiFactoryComma
}
protected CommandExecutionResult executeNow(final SequenceDiagram system, BlocLines lines) {
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
return executeInternal(system, line0, lines);

View File

@ -123,7 +123,7 @@ public final class FactorySequenceNoteOnArrowCommand implements SingleMultiFacto
}
protected CommandExecutionResult executeNow(final SequenceDiagram diagram, BlocLines lines) {
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst499().getTrimmed().getString());
final RegexResult line0 = getStartingPattern().matcher(lines.getFirst().getTrimmed().getString());
lines = lines.subExtract(1, 1);
lines = lines.removeEmptyColumns();
return executeInternal(diagram, line0, lines);

Some files were not shown because too many files have changed in this diff Show More