mirror of
https://github.com/octoleo/plantuml.git
synced 2024-11-24 13:57:33 +00:00
Adding contribution from Hisashi Miyashita for SysML v2 support
This commit is contained in:
parent
f2529b8b88
commit
e9fb57cbbe
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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--;
|
||||
return i;
|
||||
}
|
||||
if (i == 0 && j == arg.length() - 1) {
|
||||
|
||||
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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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) {
|
||||
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) {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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>();
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -48,13 +48,18 @@ public class CompressionBrotli implements Compression {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public byte[] decompress(byte[] in) throws IOException {
|
||||
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 result.toByteArray();
|
||||
return ByteArray.from(result.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new NoPlantumlCompressionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ public class CompressionHuffman implements Compression {
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] decompress(byte[] in) throws IOException {
|
||||
public ByteArray decompress(byte[] in) throws NoPlantumlCompressionException {
|
||||
try {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(in);
|
||||
@ -71,7 +72,11 @@ public class CompressionHuffman implements Compression {
|
||||
gz.close();
|
||||
bais.close();
|
||||
baos.close();
|
||||
return baos.toByteArray();
|
||||
return ByteArray.from(baos.toByteArray());
|
||||
} catch (IOException e) {
|
||||
System.err.println("Not Huffman");
|
||||
throw new NoPlantumlCompressionException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
// while (result == null) {
|
||||
result = tryCompress(in, len);
|
||||
len *= 2;
|
||||
}
|
||||
// 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];
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
in2[i] = in[i];
|
||||
System.arraycopy(in, 0, in2, 0, in.length);
|
||||
// for (int i = 0; i < in.length; i++) {
|
||||
// in2[i] = in[i];
|
||||
// }
|
||||
|
||||
int len = 100000;
|
||||
byte[] result = null;
|
||||
result = tryDecompress(in2, len);
|
||||
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);
|
||||
}
|
||||
|
||||
int len = in.length * 5;
|
||||
byte[] result = null;
|
||||
while (result == null) {
|
||||
result = tryDecompress(in2, len);
|
||||
len *= 2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
88
src/net/sourceforge/plantuml/code/CompressionZlibPure.java
Normal file
88
src/net/sourceforge/plantuml/code/CompressionZlibPure.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
183
src/net/sourceforge/plantuml/code/Keywords.java
Normal file
183
src/net/sourceforge/plantuml/code/Keywords.java
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
public String decode(String code) throws NoPlantumlCompressionException {
|
||||
try {
|
||||
final byte compressedData[] = urlEncoder.decode(code);
|
||||
final byte data[] = compression.decompress(compressedData);
|
||||
|
||||
return stringCompressor.decompress(new String(data, "UTF-8"));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
108
src/net/sourceforge/plantuml/code/TranscoderSmartAttic.java
Normal file
108
src/net/sourceforge/plantuml/code/TranscoderSmartAttic.java
Normal 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);
|
||||
}
|
||||
}
|
181
src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java
Normal file
181
src/net/sourceforge/plantuml/code/TranscoderSmartProtected.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
156
src/net/sourceforge/plantuml/code/Upf9.java
Normal file
156
src/net/sourceforge/plantuml/code/Upf9.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
92
src/net/sourceforge/plantuml/code/deflate/ByteHistory.java
Normal file
92
src/net/sourceforge/plantuml/code/deflate/ByteHistory.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
174
src/net/sourceforge/plantuml/code/deflate/CanonicalCode.java
Normal file
174
src/net/sourceforge/plantuml/code/deflate/CanonicalCode.java
Normal 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;
|
||||
|
||||
}
|
300
src/net/sourceforge/plantuml/code/deflate/Decompressor.java
Normal file
300
src/net/sourceforge/plantuml/code/deflate/Decompressor.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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) {
|
||||
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()));
|
||||
|
@ -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);
|
||||
|
@ -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,7 +114,6 @@ 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);
|
||||
@ -130,6 +130,9 @@ public final class CommandFactorySprite implements SingleMultiFactoryCommand<Wit
|
||||
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);
|
||||
@ -137,9 +140,6 @@ public final class CommandFactorySprite implements SingleMultiFactoryCommand<Wit
|
||||
}
|
||||
system.addSprite(line0.get("NAME", 0), sprite);
|
||||
return CommandExecutionResult.ok();
|
||||
} catch (IOException e) {
|
||||
return CommandExecutionResult.error("Cannot decode sprite.");
|
||||
}
|
||||
}
|
||||
|
||||
private String concat(final List<String> strings) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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(), //
|
||||
@ -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(), //
|
||||
@ -142,6 +149,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(), //
|
||||
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user