From 99041c5ccbba423664ee36039b26ce7cccd37643 Mon Sep 17 00:00:00 2001 From: Arnaud Roques Date: Fri, 24 May 2019 21:59:31 +0200 Subject: [PATCH] version 1.2019.6 --- pom.xml | 2 +- .../sourceforge/plantuml/AnnotatedWorker.java | 2 +- src/net/sourceforge/plantuml/BlockUml.java | 18 +- .../sourceforge/plantuml/BlockUmlBuilder.java | 8 +- src/net/sourceforge/plantuml/ColorParam.java | 2 + src/net/sourceforge/plantuml/CornerParam.java | 2 +- src/net/sourceforge/plantuml/ErrorUml.java | 19 +- src/net/sourceforge/plantuml/FontParam.java | 2 + .../plantuml/GeneratedImageImpl.java | 3 +- src/net/sourceforge/plantuml/ISkinParam.java | 2 + src/net/sourceforge/plantuml/LineParam.java | 1 + .../sourceforge/plantuml/PSystemBuilder.java | 10 +- src/net/sourceforge/plantuml/Pipe.java | 1 + src/net/sourceforge/plantuml/SkinParam.java | 9 + .../plantuml/SkinParamDelegator.java | 5 + .../plantuml/SourceFileReaderAbstract.java | 1 + src/net/sourceforge/plantuml/StdrptPipe0.java | 3 +- src/net/sourceforge/plantuml/StdrptV1.java | 3 +- .../activitydiagram3/ActivityDiagram3.java | 4 +- .../activitydiagram3/InstructionList.java | 9 - .../activitydiagram3/InstructionSplit.java | 19 +- .../activitydiagram3/command/CommandCase.java | 2 - .../activitydiagram3/ftile/FtileGeometry.java | 49 +- .../activitydiagram3/ftile/Snake.java | 12 +- .../plantuml/activitydiagram3/ftile/Worm.java | 6 + .../vcompact/FtileFactoryDelegatorSwitch.java | 38 +- .../ftile/vcompact/FtileGroup.java | 2 +- .../ftile/vcompact/FtileIfLongHorizontal.java | 11 +- .../ftile/vcompact/FtileWhile.java | 5 +- .../ftile/vcompact/cond/FtileIfWithLinks.java | 23 +- .../ftile/vcompact/cond/FtileSwitchNude.java | 7 +- .../cond/FtileSwitchWithDiamonds.java | 30 +- .../cond/FtileSwitchWithManyLinks.java | 280 ++++++++++ .../vcompact/cond/FtileSwitchWithOneLink.java | 150 ++++++ .../plantuml/command/BlocLines.java | 1 - .../command/PSystemAbstractFactory.java | 18 +- .../plantuml/command/PSystemBasicFactory.java | 7 +- .../command/PSystemSingleLineFactory.java | 16 +- .../plantuml/command/SingleLineCommand2.java | 2 +- .../plantuml/command/UmlDiagramFactory.java | 18 +- ...FactorySequenceNoteOverSeveralCommand.java | 32 +- .../plantuml/creole/CreoleMode.java | 2 +- .../plantuml/cucadiagram/Display.java | 12 +- .../plantuml/cucadiagram/Stereotype.java | 3 + .../cucadiagram/dot/GraphvizUtils.java | 22 +- .../plantuml/dedication/Dedications.java | 1 + .../plantuml/dedication/boundaries.png | Bin 0 -> 51300 bytes .../descdiagram/command/CommandArchimate.java | 7 +- .../plantuml/donors/PSystemDonors.java | 35 +- .../plantuml/{ => error}/PSystemError.java | 427 ++++++--------- .../error/PSystemErrorPreprocessor.java | 59 +++ .../plantuml/error/PSystemErrorUtils.java | 106 ++++ .../PSystemErrorV2.java} | 19 +- .../sourceforge/plantuml/fun/IconLoader.java | 4 +- .../sourceforge/plantuml/fun/sprite021.png | Bin 2040 -> 2038 bytes .../sourceforge/plantuml/fun/sprite027.png | Bin 0 -> 400 bytes .../sourceforge/plantuml/fun/sprite028.png | Bin 0 -> 1787 bytes .../plantuml/graphic/FontConfiguration.java | 4 + .../plantuml/graphic/GraphicStrings.java | 82 +-- .../plantuml/graphic/HtmlColorUtils.java | 2 + .../plantuml/graphic/QuoteUtils.java | 11 +- .../plantuml/graphic/SingleLine.java | 20 +- .../plantuml/graphic/SkinParameter.java | 4 + .../plantuml/graphic/TextBlockRaw.java | 95 ++++ .../plantuml/graphic/TextBlockSimple.java | 8 +- .../plantuml/graphic/TextBlockUtils.java | 5 + .../sourceforge/plantuml/graphic/USymbol.java | 23 +- .../plantuml/graphic/USymbolArtifact.java | 4 +- .../plantuml/graphic/USymbolCard.java | 4 +- .../plantuml/graphic/USymbolCloud.java | 4 +- .../plantuml/graphic/USymbolCollections.java | 22 +- .../plantuml/graphic/USymbolComponent1.java | 4 +- .../plantuml/graphic/USymbolComponent2.java | 4 +- .../plantuml/graphic/USymbolDatabase.java | 4 +- .../plantuml/graphic/USymbolFile.java | 4 +- .../plantuml/graphic/USymbolFolder.java | 4 +- .../plantuml/graphic/USymbolFrame.java | 4 +- .../plantuml/graphic/USymbolNode.java | 28 +- .../plantuml/graphic/USymbolQueue.java | 4 +- .../plantuml/graphic/USymbolRect.java | 22 +- .../graphic/USymbolSimpleAbstract.java | 4 +- .../plantuml/graphic/USymbolStack.java | 4 +- .../plantuml/graphic/USymbolStorage.java | 4 +- .../plantuml/graphic/USymbolTogether.java | 4 +- .../plantuml/jungle/GTileNode.java | 2 +- .../plantuml/mindmap/MindMapDiagram.java | 5 +- .../plantuml/nwdiag/DiagElement.java | 2 +- .../plantuml/preproc/EvalBoolean.java | 2 +- .../plantuml/preproc/FileWithSuffix.java | 4 + .../sourceforge/plantuml/preproc/Sub2.java | 93 ++++ .../sourceforge/plantuml/preproc/Truth.java | 2 +- .../plantuml/preproc/UncommentReadLine.java | 6 - .../plantuml/preproc2/Preprocessor.java | 6 +- .../preproc2/PreprocessorInclude.java | 22 +- .../preproc2/PreprocessorIncludeStrategy.java | 2 +- .../preproc2/PreprocessorModeSet.java | 2 + .../plantuml/preproc2/ReadLineAddConfig.java | 2 +- .../preproc2/ReadLineQuoteComment.java | 10 + .../plantuml/preproc2/SubPreprocessor.java | 2 +- .../sequencediagram/command/CommandArrow.java | 19 +- .../teoz/CommunicationTile.java | 16 +- .../teoz/SequenceDiagramFileMakerTeoz.java | 20 +- .../skin/rose/ComponentRoseDatabase.java | 2 +- .../skin/rose/ComponentRoseQueue.java | 2 +- .../plantuml/stats/StatsUtilsIncrement.java | 4 +- .../plantuml/suggest/SuggestEngine.java | 161 ------ .../plantuml/suggest/SuggestEngineResult.java | 92 ---- .../sourceforge/plantuml/svek/Cluster.java | 8 +- .../plantuml/svek/ClusterDecoration.java | 4 +- src/net/sourceforge/plantuml/svek/Line.java | 25 +- .../plantuml/svek/extremity/Extremity.java | 16 +- .../svek/extremity/ExtremityDiamond.java | 11 + .../extremity/ExtremityOther.java} | 38 +- .../svek/image/EntityImageDescription.java | 6 +- .../svek/image/EntityImageEmptyPackage.java | 5 +- .../svek/image/EntityImageState2.java | 2 +- .../plantuml/syntax/SyntaxChecker.java | 13 +- .../plantuml/syntax/SyntaxResult.java | 20 +- .../plantuml/tim/ConditionalContext.java | 23 +- .../plantuml/tim/ConditionalContexts.java | 11 +- src/net/sourceforge/plantuml/tim/Eater.java | 29 +- .../plantuml/tim/EaterAffectation.java | 11 +- .../plantuml/tim/EaterAffectationDefine.java | 12 +- .../sourceforge/plantuml/tim/EaterAssert.java | 1 + .../plantuml/tim/EaterDeclareFunction.java | 33 +- .../plantuml/tim/EaterDumpMemory.java | 54 ++ .../EaterElseIf.java} | 46 +- .../plantuml/tim/EaterException.java | 14 +- .../plantuml/tim/EaterFunctionCall.java | 25 +- src/net/sourceforge/plantuml/tim/EaterIf.java | 1 + .../sourceforge/plantuml/tim/EaterIfdef.java | 21 +- .../sourceforge/plantuml/tim/EaterIfndef.java | 3 +- .../sourceforge/plantuml/tim/EaterImport.java | 1 + .../plantuml/tim/EaterInclude.java | 21 +- .../EaterIncludesub.java} | 40 +- .../plantuml/tim/EaterLegacyDefine.java | 3 +- .../plantuml/tim/EaterLegacyDefineLong.java | 3 +- .../sourceforge/plantuml/tim/EaterLog.java | 54 ++ .../sourceforge/plantuml/tim/EaterReturn.java | 1 + .../plantuml/tim/EaterStartsub.java | 60 +++ .../sourceforge/plantuml/tim/EaterUndef.java | 54 ++ .../sourceforge/plantuml/tim/TContext.java | 490 ++++++++++++------ .../sourceforge/plantuml/tim/TFunction.java | 4 +- .../plantuml/tim/TFunctionImpl.java | 50 +- .../sourceforge/plantuml/tim/TLineType.java | 62 ++- src/net/sourceforge/plantuml/tim/TMemory.java | 11 +- .../plantuml/tim/TMemoryGlobal.java | 35 +- .../plantuml/tim/TMemoryLocal.java | 101 +++- .../Variator.java => tim/TVariableScope.java} | 15 +- .../sourceforge/plantuml/tim/TimLoader.java | 47 +- src/net/sourceforge/plantuml/tim/Trie.java | 41 +- .../plantuml/tim/expression/TValue.java | 14 + .../tim/expression/TokenOperator.java | 10 + .../stdlib/AlwaysFalse.java} | 49 +- .../stdlib/AlwaysTrue.java} | 44 +- .../plantuml/tim/stdlib/CallUserFunction.java | 67 +++ .../plantuml/tim/stdlib/DateFunction.java | 16 +- .../plantuml/tim/stdlib/Dirpath.java | 15 +- .../plantuml/tim/stdlib/FileExists.java | 15 +- .../plantuml/tim/stdlib/Filename.java | 15 +- .../plantuml/tim/stdlib/FunctionExists.java | 60 +++ .../plantuml/tim/stdlib/GetVariableValue.java | 65 +++ .../plantuml/tim/stdlib/Getenv.java | 15 +- .../stdlib/IntVal.java} | 63 +-- .../tim/stdlib/InvokeVoidFunction.java | 88 ++++ .../plantuml/tim/stdlib/LogicalNot.java | 59 +++ .../plantuml/tim/stdlib/SetVariableValue.java | 67 +++ .../stdlib/SimpleReturnFunction.java} | 60 +-- .../plantuml/tim/stdlib/Strlen.java | 15 +- .../plantuml/tim/stdlib/Strpos.java | 15 +- .../plantuml/tim/stdlib/Substr.java | 15 +- .../plantuml/tim/stdlib/VariableExists.java | 60 +++ .../plantuml/ugraphic/ImageBuilder.java | 16 +- .../plantuml/version/IteratorCounter2.java | 3 + .../version/IteratorCounter2Impl.java | 22 +- .../sourceforge/plantuml/version/Version.java | 4 +- .../sourceforge/plantuml/wbs/WBSDiagram.java | 3 +- stdlib/awslib-abx.repx | Bin 0 -> 19066 bytes stdlib/awslib-dex.repx | Bin 0 -> 122023 bytes stdlib/home.repx | 1 + 180 files changed, 3251 insertions(+), 1541 deletions(-) create mode 100644 src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithManyLinks.java create mode 100644 src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithOneLink.java create mode 100644 src/net/sourceforge/plantuml/dedication/boundaries.png rename src/net/sourceforge/plantuml/{ => error}/PSystemError.java (62%) create mode 100644 src/net/sourceforge/plantuml/error/PSystemErrorPreprocessor.java create mode 100644 src/net/sourceforge/plantuml/error/PSystemErrorUtils.java rename src/net/sourceforge/plantuml/{suggest/SuggestEngineStatus.java => error/PSystemErrorV2.java} (74%) create mode 100644 src/net/sourceforge/plantuml/fun/sprite027.png create mode 100644 src/net/sourceforge/plantuml/fun/sprite028.png create mode 100644 src/net/sourceforge/plantuml/graphic/TextBlockRaw.java create mode 100644 src/net/sourceforge/plantuml/preproc/Sub2.java delete mode 100644 src/net/sourceforge/plantuml/suggest/SuggestEngine.java delete mode 100644 src/net/sourceforge/plantuml/suggest/SuggestEngineResult.java rename src/net/sourceforge/plantuml/{suggest/VariatorRemoveOneChar.java => svek/extremity/ExtremityOther.java} (73%) create mode 100644 src/net/sourceforge/plantuml/tim/EaterDumpMemory.java rename src/net/sourceforge/plantuml/{suggest/VariatorAddOneChar.java => tim/EaterElseIf.java} (70%) rename src/net/sourceforge/plantuml/{suggest/VariatorSwapChar.java => tim/EaterIncludesub.java} (71%) create mode 100644 src/net/sourceforge/plantuml/tim/EaterLog.java create mode 100644 src/net/sourceforge/plantuml/tim/EaterStartsub.java create mode 100644 src/net/sourceforge/plantuml/tim/EaterUndef.java rename src/net/sourceforge/plantuml/{suggest/Variator.java => tim/TVariableScope.java} (91%) rename src/net/sourceforge/plantuml/{suggest/VariatorAddTwoChar.java => tim/stdlib/AlwaysFalse.java} (64%) rename src/net/sourceforge/plantuml/{suggest/VariatorIteratorAdaptor.java => tim/stdlib/AlwaysTrue.java} (65%) create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/CallUserFunction.java create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/FunctionExists.java create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/GetVariableValue.java rename src/net/sourceforge/plantuml/{suggest/VariatorSwapLetter.java => tim/stdlib/IntVal.java} (59%) create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/InvokeVoidFunction.java create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/LogicalNot.java create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/SetVariableValue.java rename src/net/sourceforge/plantuml/{suggest/VariatorAddOneCharBetweenWords.java => tim/stdlib/SimpleReturnFunction.java} (59%) create mode 100644 src/net/sourceforge/plantuml/tim/stdlib/VariableExists.java create mode 100644 stdlib/awslib-abx.repx create mode 100644 stdlib/awslib-dex.repx diff --git a/pom.xml b/pom.xml index 32e6716b3..85aeca85b 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ net.sourceforge.plantuml plantuml - 1.2019.6-SNAPSHOT + 1.2019.7-SNAPSHOT jar PlantUML diff --git a/src/net/sourceforge/plantuml/AnnotatedWorker.java b/src/net/sourceforge/plantuml/AnnotatedWorker.java index d0ae850d8..1afec513c 100644 --- a/src/net/sourceforge/plantuml/AnnotatedWorker.java +++ b/src/net/sourceforge/plantuml/AnnotatedWorker.java @@ -99,7 +99,7 @@ public class AnnotatedWorker { final double width = x1 + Math.max(dimOriginal.getWidth(), dimTitle.getWidth()) + x2; final double height = dimTitle.getHeight() + y1 + dimOriginal.getHeight() + y2; final TextBlock result = USymbol.FRAME.asBig(title, HorizontalAlignment.LEFT, TextBlockUtils.empty(0, 0), - width, height, symbolContext); + width, height, symbolContext, skinParam.getStereotypeAlignment()); return new TextBlockBackcolored() { diff --git a/src/net/sourceforge/plantuml/BlockUml.java b/src/net/sourceforge/plantuml/BlockUml.java index 1a827c5ea..73102e17b 100644 --- a/src/net/sourceforge/plantuml/BlockUml.java +++ b/src/net/sourceforge/plantuml/BlockUml.java @@ -47,6 +47,7 @@ import net.sourceforge.plantuml.code.Transcoder; import net.sourceforge.plantuml.code.TranscoderUtil; import net.sourceforge.plantuml.command.regex.Matcher2; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemErrorPreprocessor; import net.sourceforge.plantuml.preproc.Defines; import net.sourceforge.plantuml.preproc2.PreprocessorMode; import net.sourceforge.plantuml.preproc2.PreprocessorModeSet; @@ -57,6 +58,7 @@ import net.sourceforge.plantuml.version.Version; public class BlockUml { private final List data; + private List debug; private Diagram system; private final Defines localDefines; private final ISkinSimple skinParam; @@ -96,6 +98,9 @@ public class BlockUml { return result; } + private PreprocessorMode pmode = PreprocessorMode.V1_LEGACY; + private boolean preprocessorError; + public BlockUml(List strings, Defines defines, ISkinSimple skinParam, PreprocessorModeSet mode) { this.localDefines = defines; this.skinParam = skinParam; @@ -104,7 +109,12 @@ public class BlockUml { throw new IllegalArgumentException(); } if (mode != null && mode.getPreprocessorMode() == PreprocessorMode.V2_NEW_TIM) { - this.data = new TimLoader(mode.getImportedFiles(), defines).load(strings); + this.pmode = mode.getPreprocessorMode(); + final TimLoader timLoader = new TimLoader(mode.getImportedFiles(), defines, mode.getCharset()); + timLoader.load(strings); + this.data = timLoader.getResult(); + this.debug = timLoader.getDebug(); + this.preprocessorError = timLoader.isPreprocessorError(); } else { this.data = new ArrayList(strings); } @@ -139,7 +149,11 @@ public class BlockUml { public Diagram getDiagram() { if (system == null) { - system = new PSystemBuilder().createPSystem(skinParam, data); + if (preprocessorError) { + system = new PSystemErrorPreprocessor(data, debug); + } else { + system = new PSystemBuilder().createPSystem(skinParam, data); + } } return system; } diff --git a/src/net/sourceforge/plantuml/BlockUmlBuilder.java b/src/net/sourceforge/plantuml/BlockUmlBuilder.java index 1cf84c1cb..6048abe71 100644 --- a/src/net/sourceforge/plantuml/BlockUmlBuilder.java +++ b/src/net/sourceforge/plantuml/BlockUmlBuilder.java @@ -57,18 +57,20 @@ import net.sourceforge.plantuml.utils.StartUtils; public final class BlockUmlBuilder implements DefinitionsContainer { - private PreprocessorMode mode = PreprocessorMode.V1_LEGACY; + private PreprocessorMode mode = PreprocessorMode.V2_NEW_TIM; private final List blocks = new ArrayList(); private Set usedFiles = new HashSet(); private final UncommentReadLine reader2; private final Defines defines; private final ImportedFiles importedFiles; + private final String charset; public BlockUmlBuilder(List config, String charset, Defines defines, Reader reader, File newCurrentDir, String desc) throws IOException { ReadLineNumbered includer = null; this.defines = defines; + this.charset = charset; try { this.reader2 = new UncommentReadLine(new PreprocessorChangeModeReader(ReadLineReader.create(reader, desc), this)); @@ -159,4 +161,8 @@ public final class BlockUmlBuilder implements DefinitionsContainer { return importedFiles; } + public final String getCharset() { + return charset; + } + } diff --git a/src/net/sourceforge/plantuml/ColorParam.java b/src/net/sourceforge/plantuml/ColorParam.java index 66c80d66c..ff0f2d8ce 100644 --- a/src/net/sourceforge/plantuml/ColorParam.java +++ b/src/net/sourceforge/plantuml/ColorParam.java @@ -140,6 +140,8 @@ public enum ColorParam { nodeBorder(HtmlColorUtils.BLACK, ColorType.LINE), rectangleBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK), rectangleBorder(HtmlColorUtils.BLACK, ColorType.LINE), + archimateBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK), + archimateBorder(HtmlColorUtils.BLACK, ColorType.LINE), cardBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK), cardBorder(HtmlColorUtils.BLACK, ColorType.LINE), agentBackground(HtmlColorUtils.MY_YELLOW, true, ColorType.BACK), diff --git a/src/net/sourceforge/plantuml/CornerParam.java b/src/net/sourceforge/plantuml/CornerParam.java index 84cfd23a4..971c6b8b6 100644 --- a/src/net/sourceforge/plantuml/CornerParam.java +++ b/src/net/sourceforge/plantuml/CornerParam.java @@ -36,7 +36,7 @@ package net.sourceforge.plantuml; public enum CornerParam { - DEFAULT, diagramBorder, titleBorder, rectangle, component, card, agent; + DEFAULT, diagramBorder, titleBorder, rectangle, archimate, component, card, agent; public String getRoundKey() { if (this == DEFAULT) { diff --git a/src/net/sourceforge/plantuml/ErrorUml.java b/src/net/sourceforge/plantuml/ErrorUml.java index 7944ca0a6..82267a388 100644 --- a/src/net/sourceforge/plantuml/ErrorUml.java +++ b/src/net/sourceforge/plantuml/ErrorUml.java @@ -35,14 +35,11 @@ */ package net.sourceforge.plantuml; -import net.sourceforge.plantuml.suggest.SuggestEngineResult; -import net.sourceforge.plantuml.suggest.SuggestEngineStatus; public class ErrorUml { private final String error; private final ErrorUmlType type; - private SuggestEngineResult suggest; private final LineLocation lineLocation; public ErrorUml(ErrorUmlType type, String error, LineLocation lineLocation) { @@ -62,12 +59,12 @@ public class ErrorUml { @Override public int hashCode() { - return error.hashCode() + type.hashCode() + getPosition() + (suggest == null ? 0 : suggest.hashCode()); + return error.hashCode() + type.hashCode() + getPosition(); } @Override public String toString() { - return type.toString() + " " + getPosition() + " " + error + " " + suggest; + return type.toString() + " " + getPosition() + " " + error; } public final String getError() { @@ -86,16 +83,4 @@ public class ErrorUml { return lineLocation; } - public final SuggestEngineResult getSuggest() { - return suggest; - } - - public final boolean hasSuggest() { - return suggest != null && suggest.getStatus() == SuggestEngineStatus.ONE_SUGGESTION; - } - - public void setSuggest(SuggestEngineResult suggest) { - this.suggest = suggest; - } - } diff --git a/src/net/sourceforge/plantuml/FontParam.java b/src/net/sourceforge/plantuml/FontParam.java index 99821476a..13d2333e6 100644 --- a/src/net/sourceforge/plantuml/FontParam.java +++ b/src/net/sourceforge/plantuml/FontParam.java @@ -77,6 +77,7 @@ public enum FontParam { ENTITY(14, Font.PLAIN), // AGENT(14, Font.PLAIN), // RECTANGLE(14, Font.PLAIN), // + ARCHIMATE(14, Font.PLAIN), // CARD(14, Font.PLAIN), // NODE(14, Font.PLAIN), // DATABASE(14, Font.PLAIN), // @@ -110,6 +111,7 @@ public enum FontParam { ENTITY_STEREOTYPE(14, Font.ITALIC), // AGENT_STEREOTYPE(14, Font.ITALIC), // RECTANGLE_STEREOTYPE(14, Font.ITALIC), // + ARCHIMATE_STEREOTYPE(14, Font.ITALIC), // CARD_STEREOTYPE(14, Font.ITALIC), // NODE_STEREOTYPE(14, Font.ITALIC), // FOLDER_STEREOTYPE(14, Font.ITALIC), // diff --git a/src/net/sourceforge/plantuml/GeneratedImageImpl.java b/src/net/sourceforge/plantuml/GeneratedImageImpl.java index a3ab2592c..39e5ba2c2 100644 --- a/src/net/sourceforge/plantuml/GeneratedImageImpl.java +++ b/src/net/sourceforge/plantuml/GeneratedImageImpl.java @@ -38,6 +38,7 @@ package net.sourceforge.plantuml; import java.io.File; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemError; public class GeneratedImageImpl implements GeneratedImage { @@ -68,7 +69,7 @@ public class GeneratedImageImpl implements GeneratedImage { public int lineErrorRaw() { final Diagram system = blockUml.getDiagram(); if (system instanceof PSystemError) { - return ((PSystemError) system).getHigherErrorPosition2().getPosition(); + return ((PSystemError) system).getLineLocation().getPosition(); } return -1; } diff --git a/src/net/sourceforge/plantuml/ISkinParam.java b/src/net/sourceforge/plantuml/ISkinParam.java index d09186bd2..14e5422b1 100644 --- a/src/net/sourceforge/plantuml/ISkinParam.java +++ b/src/net/sourceforge/plantuml/ISkinParam.java @@ -73,6 +73,8 @@ public interface ISkinParam extends ISkinSimple { public HorizontalAlignment getDefaultTextAlignment(HorizontalAlignment defaultValue); + public HorizontalAlignment getStereotypeAlignment(); + public int getCircledCharacterRadius(); public char getCircledCharacter(Stereotype stereotype); diff --git a/src/net/sourceforge/plantuml/LineParam.java b/src/net/sourceforge/plantuml/LineParam.java index e28c93548..bebacc0e3 100644 --- a/src/net/sourceforge/plantuml/LineParam.java +++ b/src/net/sourceforge/plantuml/LineParam.java @@ -55,6 +55,7 @@ public enum LineParam { titleBorder, diagramBorder, rectangleBorder, + archimateBorder, componentBorder, cardBorder, agentBorder, diff --git a/src/net/sourceforge/plantuml/PSystemBuilder.java b/src/net/sourceforge/plantuml/PSystemBuilder.java index 3c2a2aa84..03de86db0 100644 --- a/src/net/sourceforge/plantuml/PSystemBuilder.java +++ b/src/net/sourceforge/plantuml/PSystemBuilder.java @@ -63,6 +63,8 @@ import net.sourceforge.plantuml.eggs.PSystemColorsFactory; import net.sourceforge.plantuml.eggs.PSystemEggFactory; import net.sourceforge.plantuml.eggs.PSystemRIPFactory; import net.sourceforge.plantuml.eggs.PSystemWelcomeFactory; +import net.sourceforge.plantuml.error.PSystemError; +import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.flowdiagram.FlowDiagramFactory; import net.sourceforge.plantuml.font.PSystemListFontsFactory; import net.sourceforge.plantuml.help.HelpFactory; @@ -100,15 +102,15 @@ public class PSystemBuilder { final DiagramType type = DiagramType.getTypeFromArobaseStart(strings2.get(0).getString()); final UmlSource umlSource = new UmlSource(strings2, type == DiagramType.UML); - // int cpt = 0; for (StringLocated s : strings2) { if (s.getPreprocessorError() != null) { + // Dead code : should not append Log.error("Preprocessor Error: " + s.getPreprocessorError()); final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, s.getPreprocessorError(), /* cpt */ s.getLocation()); - return new PSystemError(umlSource, err, Collections. emptyList()); + // return PSystemErrorUtils.buildV1(umlSource, err, Collections. emptyList()); + return PSystemErrorUtils.buildV2(umlSource, err, Collections. emptyList(), strings2); } - // cpt++; } final DiagramType diagramType = umlSource.getDiagramType(); @@ -126,7 +128,7 @@ public class PSystemBuilder { errors.add((PSystemError) sys); } - final PSystemError err = PSystemError.merge(errors); + final PSystemError err = PSystemErrorUtils.merge(errors); result = err; return err; } finally { diff --git a/src/net/sourceforge/plantuml/Pipe.java b/src/net/sourceforge/plantuml/Pipe.java index bc8dfcee6..fbfda6801 100644 --- a/src/net/sourceforge/plantuml/Pipe.java +++ b/src/net/sourceforge/plantuml/Pipe.java @@ -44,6 +44,7 @@ import java.util.List; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.DiagramDescription; +import net.sourceforge.plantuml.error.PSystemError; import net.sourceforge.plantuml.preproc.Defines; public class Pipe { diff --git a/src/net/sourceforge/plantuml/SkinParam.java b/src/net/sourceforge/plantuml/SkinParam.java index d0fe5fe8a..c55465dea 100644 --- a/src/net/sourceforge/plantuml/SkinParam.java +++ b/src/net/sourceforge/plantuml/SkinParam.java @@ -550,6 +550,15 @@ public class SkinParam implements ISkinParam { return result; } + public HorizontalAlignment getStereotypeAlignment() { + final String value = getValue("stereotypealignment"); + final HorizontalAlignment result = HorizontalAlignment.fromString(value); + if (result == null) { + return HorizontalAlignment.CENTER; + } + return result; + } + private String getArg(String value, int i) { if (value == null) { return null; diff --git a/src/net/sourceforge/plantuml/SkinParamDelegator.java b/src/net/sourceforge/plantuml/SkinParamDelegator.java index 9375473a1..c09d5adfe 100644 --- a/src/net/sourceforge/plantuml/SkinParamDelegator.java +++ b/src/net/sourceforge/plantuml/SkinParamDelegator.java @@ -317,5 +317,10 @@ public class SkinParamDelegator implements ISkinParam { public Map values() { return skinParam.values(); } + + public HorizontalAlignment getStereotypeAlignment() { + return skinParam.getStereotypeAlignment(); + } + } diff --git a/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java b/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java index 31ab739b4..337f03d4e 100644 --- a/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java +++ b/src/net/sourceforge/plantuml/SourceFileReaderAbstract.java @@ -52,6 +52,7 @@ import java.util.List; import java.util.Set; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemError; import net.sourceforge.plantuml.preproc.FileWithSuffix; public abstract class SourceFileReaderAbstract { diff --git a/src/net/sourceforge/plantuml/StdrptPipe0.java b/src/net/sourceforge/plantuml/StdrptPipe0.java index 835dad54a..7254bb1b2 100644 --- a/src/net/sourceforge/plantuml/StdrptPipe0.java +++ b/src/net/sourceforge/plantuml/StdrptPipe0.java @@ -38,6 +38,7 @@ package net.sourceforge.plantuml; import java.io.PrintStream; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemError; public class StdrptPipe0 implements Stdrpt { @@ -45,7 +46,7 @@ public class StdrptPipe0 implements Stdrpt { if (sys instanceof PSystemError) { final PSystemError err = (PSystemError) sys; output.println("ERROR"); - output.println(err.getHigherErrorPosition2().getPosition()); + output.println(err.getLineLocation().getPosition()); for (ErrorUml er : err.getErrorsUml()) { output.println(er.getError()); } diff --git a/src/net/sourceforge/plantuml/StdrptV1.java b/src/net/sourceforge/plantuml/StdrptV1.java index b6edfbe4f..83f0015d0 100644 --- a/src/net/sourceforge/plantuml/StdrptV1.java +++ b/src/net/sourceforge/plantuml/StdrptV1.java @@ -40,6 +40,7 @@ import java.io.PrintStream; import net.sourceforge.plantuml.command.PSystemAbstractFactory; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.eggs.PSystemWelcome; +import net.sourceforge.plantuml.error.PSystemError; public class StdrptV1 implements Stdrpt { @@ -58,7 +59,7 @@ public class StdrptV1 implements Stdrpt { output.println("status=NO_DATA"); } else { output.println("status=ERROR"); - output.println("lineNumber=" + err.getHigherErrorPosition2().getPosition()); + output.println("lineNumber=" + err.getLineLocation().getPosition()); for (ErrorUml er : err.getErrorsUml()) { output.println("label=" + er.getError()); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java index b37d04e53..fd37e2388 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ActivityDiagram3.java @@ -262,7 +262,7 @@ public class ActivityDiagram3 extends UmlDiagram { } public void split() { - final InstructionSplit instructionSplit = new InstructionSplit(current(), nextLinkRenderer()); + final InstructionSplit instructionSplit = new InstructionSplit(current(), nextLinkRenderer(), swinlanes.getCurrentSwimlane()); setNextLinkRendererInternal(LinkRendering.none()); current().add(instructionSplit); setCurrent(instructionSplit); @@ -279,7 +279,7 @@ public class ActivityDiagram3 extends UmlDiagram { public CommandExecutionResult endSplit() { if (current() instanceof InstructionSplit) { - ((InstructionSplit) current()).endSplit(nextLinkRenderer()); + ((InstructionSplit) current()).endSplit(nextLinkRenderer(), swinlanes.getCurrentSwimlane()); setNextLinkRendererInternal(LinkRendering.none()); setCurrent(((InstructionSplit) current()).getParent()); return CommandExecutionResult.ok(); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/InstructionList.java b/src/net/sourceforge/plantuml/activitydiagram3/InstructionList.java index e911a1c89..7448c350d 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/InstructionList.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/InstructionList.java @@ -155,15 +155,6 @@ public class InstructionList extends WithNote implements Instruction, Instructio public Swimlane getSwimlaneIn() { return defaultSwimlane; - // final Set swimlanes = getSwimlanes(); - // if (swimlanes.size() == 0) { - // return null; - // } - // if (swimlanes.size() == 1) { - // return swimlanes.iterator().next(); - // } - // System.err.println("foo1="+getClass()); - // return all.get(0).getSwimlaneIn(); } public Swimlane getSwimlaneOut() { diff --git a/src/net/sourceforge/plantuml/activitydiagram3/InstructionSplit.java b/src/net/sourceforge/plantuml/activitydiagram3/InstructionSplit.java index c311885d3..c6abe32ea 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/InstructionSplit.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/InstructionSplit.java @@ -52,16 +52,20 @@ public class InstructionSplit implements Instruction { private final List splits = new ArrayList(); private final Instruction parent; private final LinkRendering inlinkRendering; + private final Swimlane swimlaneIn; + private Swimlane swimlaneOut; - public InstructionSplit(Instruction parent, LinkRendering inlinkRendering) { + public InstructionSplit(Instruction parent, LinkRendering inlinkRendering, Swimlane swimlane) { this.parent = parent; - this.splits.add(new InstructionList()); + this.swimlaneIn = swimlane; + + this.splits.add(new InstructionList(swimlane)); this.inlinkRendering = inlinkRendering; if (inlinkRendering == null) { throw new IllegalArgumentException(); } } - + public boolean containsBreak() { for (InstructionList split : splits) { if (split.containsBreak()) { @@ -71,7 +75,6 @@ public class InstructionSplit implements Instruction { return false; } - private InstructionList getLast() { return splits.get(splits.size() - 1); } @@ -96,14 +99,15 @@ public class InstructionSplit implements Instruction { if (inlinkRendering != null) { getLast().setOutRendering(inlinkRendering); } - final InstructionList list = new InstructionList(); + final InstructionList list = new InstructionList(swimlaneIn); this.splits.add(list); } - public void endSplit(LinkRendering inlinkRendering) { + public void endSplit(LinkRendering inlinkRendering, Swimlane endSwimlane) { if (inlinkRendering != null) { getLast().setOutRendering(inlinkRendering); } + this.swimlaneOut = endSwimlane; } @@ -128,7 +132,8 @@ public class InstructionSplit implements Instruction { } public Swimlane getSwimlaneOut() { - return getLast().getSwimlaneOut(); + return swimlaneOut; + // return getLast().getSwimlaneOut(); } } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/command/CommandCase.java b/src/net/sourceforge/plantuml/activitydiagram3/command/CommandCase.java index 1b4911b57..0c79e6479 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/command/CommandCase.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/command/CommandCase.java @@ -43,8 +43,6 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.cucadiagram.Display; -import net.sourceforge.plantuml.graphic.HtmlColor; -import net.sourceforge.plantuml.graphic.color.ColorParser; public class CommandCase extends SingleLineCommand2 { diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileGeometry.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileGeometry.java index 5ebc2655b..6c7bdf894 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileGeometry.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/FtileGeometry.java @@ -48,6 +48,44 @@ public class FtileGeometry extends Dimension2D { private final double inY; private final double outY; + public Point2D getPointA() { + return new Point2D.Double(left, inY); + } + + public Point2D getPointIn() { + return new Point2D.Double(left, inY); + } + + public Point2D getPointB() { + if (outY == Double.MIN_NORMAL) { + throw new UnsupportedOperationException(); + } + return new Point2D.Double(width, (inY + outY) / 2); + } + + public Point2D getPointC() { + if (outY == Double.MIN_NORMAL) { + throw new UnsupportedOperationException(); + } + return new Point2D.Double(left, outY); + } + + public Point2D getPointD() { + if (outY == Double.MIN_NORMAL) { + throw new UnsupportedOperationException(); + } + return new Point2D.Double(0, (inY + outY) / 2); + } + + public Point2D getPointOut() { + if (outY == Double.MIN_NORMAL) { + throw new UnsupportedOperationException(); + } + return new Point2D.Double(left, outY); + } + + + public FtileGeometry(Dimension2D dim, double left, double inY) { this(dim.getWidth(), dim.getHeight(), left, inY); } @@ -86,17 +124,6 @@ public class FtileGeometry extends Dimension2D { return outY != Double.MIN_NORMAL; } - public Point2D getPointIn() { - return new Point2D.Double(left, inY); - } - - public Point2D getPointOut() { - if (outY == Double.MIN_NORMAL) { - throw new UnsupportedOperationException(); - } - return new Point2D.Double(left, outY); - } - public FtileGeometry withoutPointOut() { return new FtileGeometry(width, height, left, inY); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java index 564b3049e..bf20b18be 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Snake.java @@ -66,12 +66,11 @@ public class Snake implements UShape { private MergeStrategy mergeable = MergeStrategy.FULL; private Direction emphasizeDirection; private final HorizontalAlignment horizontalAlignment; - + public final void setIgnoreForCompression(boolean ignoreForCompression) { this.worm.setIgnoreForCompression(ignoreForCompression); } - public Snake transformX(CompressionTransform compressionTransform) { final Snake result = new Snake(startDecoration, horizontalAlignment, color, endDecoration); result.textBlock = this.textBlock; @@ -206,14 +205,19 @@ public class Snake implements UShape { final Dimension2D dim = textBlock.calculateDimension(stringBounder); double x = Math.max(pt1.getX(), pt2.getX()) + 4; final boolean zigzag = worm.getDirectionsCode().startsWith("DLD") || worm.getDirectionsCode().startsWith("DRD"); + double y = (pt1.getY() + pt2.getY()) / 2 - dim.getHeight() / 2; if (horizontalAlignment == HorizontalAlignment.CENTER && zigzag) { final Point2D pt3 = worm.get(2); x = (pt2.getX() + pt3.getX()) / 2 - dim.getWidth() / 2; } else if (horizontalAlignment == HorizontalAlignment.RIGHT && zigzag) { - // final Point2D pt3 = worm.get(2); x = Math.max(pt1.getX(), pt2.getX()) - dim.getWidth() - 4; + } else if (worm.getDirectionsCode().equals("RD")) { + x = Math.max(pt1.getX(), pt2.getX()); + y = (pt1.getY() + worm.get(2).getY()) / 2 - dim.getHeight() / 2; + } else if (worm.getDirectionsCode().equals("LD")) { + x = Math.min(pt1.getX(), pt2.getX()); + y = (pt1.getY() + worm.get(2).getY()) / 2 - dim.getHeight() / 2; } - final double y = (pt1.getY() + pt2.getY()) / 2 - dim.getHeight() / 2; return new Point2D.Double(x, y); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java index 31aef25ef..911fd434b 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/Worm.java @@ -206,6 +206,12 @@ public class Worm implements Iterable { } public void addPoint(double x, double y) { + if (points.size() > 0) { + final Point2D last = getLast(); + if (last.getX() == x && last.getY() == y) { + return; + } + } this.points.add(new Point2D.Double(x, y)); } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorSwitch.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorSwitch.java index 8e027b31a..dee9622be 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorSwitch.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileFactoryDelegatorSwitch.java @@ -40,10 +40,8 @@ import java.util.List; import net.sourceforge.plantuml.ColorParam; import net.sourceforge.plantuml.FontParam; -import net.sourceforge.plantuml.LineBreakStrategy; import net.sourceforge.plantuml.activitydiagram3.Branch; import net.sourceforge.plantuml.activitydiagram3.LinkRendering; -import net.sourceforge.plantuml.activitydiagram3.ftile.Diamond; import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile; import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactory; import net.sourceforge.plantuml.activitydiagram3.ftile.FtileFactoryDelegator; @@ -51,20 +49,17 @@ import net.sourceforge.plantuml.activitydiagram3.ftile.FtileMinWidth; 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; -import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileDiamond; +import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond.FtileSwitchWithOneLink; +import net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond.FtileSwitchWithManyLinks; import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileDiamondInside; -import net.sourceforge.plantuml.creole.CreoleMode; -import net.sourceforge.plantuml.creole.CreoleParser; -import net.sourceforge.plantuml.creole.Sheet; -import net.sourceforge.plantuml.creole.SheetBlock1; -import net.sourceforge.plantuml.creole.SheetBlock2; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.graphic.FontConfiguration; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.HtmlColor; +import net.sourceforge.plantuml.graphic.HtmlColorAndStyle; +import net.sourceforge.plantuml.graphic.Rainbow; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; -import net.sourceforge.plantuml.svek.ConditionStyle; public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator { @@ -93,7 +88,8 @@ public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator { // fcArrow, topInlinkRendering, afterEndwhile, fcTest); // return createNude(swimlane, branches); - return createWithDiamonds(swimlane, branches, labelTest); + // return createWithDiamonds(swimlane, branches, labelTest); + return createWithLinks(swimlane, branches, labelTest); } private Ftile createNude(Swimlane swimlane, List branches) { @@ -111,7 +107,27 @@ public class FtileFactoryDelegatorSwitch extends FtileFactoryDelegator { } final Ftile diamond1 = getDiamond1(swimlane, branches.get(0), labelTest); final Ftile diamond2 = getDiamond2(swimlane, branches.get(0)); - return new FtileSwitchWithDiamonds(ftiles, swimlane, diamond1, diamond2, getStringBounder()); + + return new FtileSwitchWithDiamonds(ftiles, branches, swimlane, diamond1, diamond2, getStringBounder()); + } + + private Ftile createWithLinks(Swimlane swimlane, List branches, Display labelTest) { + final List ftiles = new ArrayList(); + for (Branch branch : branches) { + ftiles.add(new FtileMinWidth(branch.getFtile(), 30)); + } + final Ftile diamond1 = getDiamond1(swimlane, branches.get(0), labelTest); + final Ftile diamond2 = getDiamond2(swimlane, branches.get(0)); + final Rainbow arrowColor = HtmlColorAndStyle.build(skinParam()); + if (ftiles.size() == 1) { + final FtileSwitchWithOneLink result = new FtileSwitchWithOneLink(ftiles, branches, swimlane, diamond1, + diamond2, getStringBounder(), arrowColor); + return result.addLinks(); + } + final FtileSwitchWithManyLinks result = new FtileSwitchWithManyLinks(ftiles, branches, swimlane, diamond1, + diamond2, getStringBounder(), arrowColor); + return result.addLinks(); + } private Ftile getDiamond1(Swimlane swimlane, Branch branch0, Display test) { diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java index 5c1b0a7fa..1a1dce4bf 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileGroup.java @@ -209,7 +209,7 @@ public class FtileGroup extends AbstractFtile { .withShadow(skinParam().shadowing(null)).withStroke(stroke).withCorner(roundCorner, 0); type.asBig(name, inner.skinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false), - TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext).drawU(ug); + TextBlockUtils.empty(0, 0), dimTotal.getWidth(), dimTotal.getHeight(), symbolContext, skinParam().getStereotypeAlignment()).drawU(ug); final Dimension2D dimHeaderNote = headerNote.calculateDimension(stringBounder); headerNote.drawU(ug.apply(new UTranslate(dimTotal.getWidth() - dimHeaderNote.getWidth() - 10, diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileIfLongHorizontal.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileIfLongHorizontal.java index b18d3de14..fd68b59c3 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileIfLongHorizontal.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileIfLongHorizontal.java @@ -593,13 +593,22 @@ class FtileIfLongHorizontal extends AbstractFtile { for (Ftile couple : couples) { result = Dimension2DDouble.mergeLR(result, couple.calculateDimension(stringBounder)); } - final FtileGeometry dimTile2 = tile2.calculateDimension(stringBounder); + Dimension2D dimTile2 = tile2.calculateDimension(stringBounder); + dimTile2 = Dimension2DDouble.delta(dimTile2, 0, getDiamondsHeight(stringBounder) / 2); result = Dimension2DDouble.mergeLR(result, dimTile2); result = Dimension2DDouble.delta(result, xSeparation * couples.size(), 100); return new FtileGeometry(result, result.getWidth() / 2, 0); } + private double getDiamondsHeight(StringBounder stringBounder) { + double height = 0; + for (Ftile diamond : diamonds) { + height = Math.max(height, diamond.calculateDimension(stringBounder).getHeight()); + } + return height; + } + @Override protected FtileGeometry calculateDimensionFtile(StringBounder stringBounder) { final Dimension2D dimTotal = calculateDimensionInternal(stringBounder); diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java index af93efe5f..1cf69898a 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/FtileWhile.java @@ -70,6 +70,7 @@ import net.sourceforge.plantuml.graphic.HtmlColor; import net.sourceforge.plantuml.graphic.Rainbow; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.svek.ConditionStyle; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; @@ -118,8 +119,8 @@ class FtileWhile extends AbstractFtile { ConditionStyle conditionStyle, FontConfiguration fcTest, Instruction specialOut) { final TextBlock yesTb = yes.create(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam()); - final TextBlock testTb = test.create(fcTest, - whileBlock.skinParam().getDefaultTextAlignment(HorizontalAlignment.LEFT), ftileFactory.skinParam()); + final TextBlock testTb = test.isWhite() ? TextBlockUtils.empty(0, 0) : test.create(fcTest, whileBlock + .skinParam().getDefaultTextAlignment(HorizontalAlignment.LEFT), ftileFactory.skinParam()); final TextBlock out = out2.create(fontArrow, HorizontalAlignment.LEFT, ftileFactory.skinParam()); final Ftile diamond1; diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileIfWithLinks.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileIfWithLinks.java index f628c17b0..c6b55621a 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileIfWithLinks.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileIfWithLinks.java @@ -119,18 +119,15 @@ public class FtileIfWithLinks extends FtileIfWithDiamonds { private Point2D getP1(StringBounder stringBounder) { final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); - final double diamondWidth = dimDiamond1.getWidth(); - final double x; + final Point2D pt; if (getFtile2() == tile1) { - x = 0; + pt = dimDiamond1.getPointD(); } else if (getFtile2() == tile2) { - x = diamondWidth; + pt = dimDiamond1.getPointB(); } else { throw new IllegalStateException(); } - final double half = (dimDiamond1.getOutY() - dimDiamond1.getInY()) / 2; - return getTranslateDiamond1(stringBounder) - .getTranslated(new Point2D.Double(x, dimDiamond1.getInY() + half)); + return getTranslateDiamond1(stringBounder).getTranslated(pt); } private Point2D getP2(final StringBounder stringBounder) { @@ -214,18 +211,16 @@ public class FtileIfWithLinks extends FtileIfWithDiamonds { } private Point2D getP2(StringBounder stringBounder) { - final Dimension2D dimDiamond2 = diamond2.calculateDimension(stringBounder); - final double diamondWidth = dimDiamond2.getWidth(); - final double x; + final FtileGeometry dimDiamond2 = diamond2.calculateDimension(stringBounder); + final Point2D pt; if (getFtile1() == tile1) { - x = 0; + pt = dimDiamond2.getPointD(); } else if (getFtile1() == tile2) { - x = diamondWidth; + pt = dimDiamond2.getPointB(); } else { throw new IllegalStateException(); } - return getTranslateDiamond2(stringBounder) - .getTranslated(new Point2D.Double(x, dimDiamond2.getHeight() / 2)); + return getTranslateDiamond2(stringBounder).getTranslated(pt); } private UTranslate translate(StringBounder stringBounder) { diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchNude.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchNude.java index 70b0a4d9c..094191b59 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchNude.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchNude.java @@ -36,7 +36,6 @@ package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond; import java.awt.geom.Dimension2D; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -91,12 +90,12 @@ public class FtileSwitchNude extends FtileDimensionMemoize { @Override public UTranslate getTranslateFor(Ftile child, StringBounder stringBounder) { if (tiles.contains(child)) { - return getTranslate1(child, stringBounder); + return getTranslateNude(child, stringBounder); } throw new UnsupportedOperationException(); } - private UTranslate getTranslate1(Ftile tile, StringBounder stringBounder) { + protected UTranslate getTranslateNude(Ftile tile, StringBounder stringBounder) { double x1 = 0; for (Ftile candidate : tiles) { final FtileGeometry dim1 = candidate.calculateDimension(stringBounder); @@ -111,7 +110,7 @@ public class FtileSwitchNude extends FtileDimensionMemoize { public void drawU(UGraphic ug) { final StringBounder stringBounder = ug.getStringBounder(); for (Ftile tile : tiles) { - ug.apply(getTranslate1(tile, stringBounder)).draw(tile); + ug.apply(getTranslateNude(tile, stringBounder)).draw(tile); } } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithDiamonds.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithDiamonds.java index 1e54321cb..a6ea5a6cc 100644 --- a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithDiamonds.java +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithDiamonds.java @@ -35,18 +35,21 @@ */ package net.sourceforge.plantuml.activitydiagram3.ftile.vcompact.cond; -import java.awt.geom.Dimension2D; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.activitydiagram3.Branch; import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile; import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry; import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane; +import net.sourceforge.plantuml.creole.CreoleMode; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; -import net.sourceforge.plantuml.ugraphic.UChange; +import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UTranslate; @@ -54,10 +57,12 @@ public class FtileSwitchWithDiamonds extends FtileSwitchNude { protected final Ftile diamond1; protected final Ftile diamond2; + protected final List branches; - public FtileSwitchWithDiamonds(List tiles, Swimlane in, Ftile diamond1, Ftile diamond2, - StringBounder stringBounder) { + public FtileSwitchWithDiamonds(List tiles, List branches, Swimlane in, Ftile diamond1, + Ftile diamond2, StringBounder stringBounder) { super(tiles, in); + this.branches = branches; this.diamond1 = diamond1; this.diamond2 = diamond2; } @@ -96,11 +101,11 @@ public class FtileSwitchWithDiamonds extends FtileSwitchNude { final StringBounder stringBounder = ug.getStringBounder(); ug.apply(getTranslateDiamond1(stringBounder)).draw(diamond1); - super.drawU(ug.apply(getUTranslateMain(stringBounder))); + super.drawU(ug.apply(getTranslateMain(stringBounder))); ug.apply(getTranslateDiamond2(stringBounder)).draw(diamond2); } - private UChange getUTranslateMain(StringBounder stringBounder) { + protected UTranslate getTranslateMain(StringBounder stringBounder) { final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); return new UTranslate(0, dimDiamond1.getHeight() + getYdelta1a(stringBounder)); } @@ -121,4 +126,15 @@ public class FtileSwitchWithDiamonds extends FtileSwitchNude { return new UTranslate(x2, y2); } + protected UTranslate getTranslateOf(Ftile tile, StringBounder stringBounder) { + return getTranslateNude(tile, stringBounder).compose(getTranslateMain(stringBounder)); + } + + protected TextBlock getLabelPositive(Branch branch) { + final FontConfiguration fcArrow = new FontConfiguration(skinParam(), FontParam.ARROW, null); + return branch.getLabelPositive().create(fcArrow, HorizontalAlignment.LEFT, skinParam(), CreoleMode.SIMPLE_LINE); + } + + + } diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithManyLinks.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithManyLinks.java new file mode 100644 index 000000000..cb43d0b09 --- /dev/null +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithManyLinks.java @@ -0,0 +1,280 @@ +/* ======================================================================== + * 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.cond; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.activitydiagram3.Branch; +import net.sourceforge.plantuml.activitydiagram3.ftile.AbstractConnection; +import net.sourceforge.plantuml.activitydiagram3.ftile.Arrows; +import net.sourceforge.plantuml.activitydiagram3.ftile.Connection; +import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile; +import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry; +import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils; +import net.sourceforge.plantuml.activitydiagram3.ftile.Snake; +import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane; +import net.sourceforge.plantuml.graphic.Rainbow; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPolygon; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class FtileSwitchWithManyLinks extends FtileSwitchWithDiamonds { + + private final Rainbow arrowColor; + private final double margin = 10; + + public FtileSwitchWithManyLinks(List tiles, List branches, Swimlane in, Ftile diamond1, + Ftile diamond2, StringBounder stringBounder, Rainbow arrowColor) { + super(tiles, branches, in, diamond1, diamond2, stringBounder); + this.arrowColor = arrowColor; + } + + class ConnectionHorizontalThenVertical extends AbstractConnection { + + private final Branch branch; + + public ConnectionHorizontalThenVertical(Ftile tile, Branch branch) { + super(diamond1, tile); + this.branch = branch; + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final Point2D p1 = getP1(stringBounder); + final Point2D p2 = getP2(stringBounder); + final double x1 = p1.getX(); + final double y1 = p1.getY(); + final double x2 = p2.getX(); + final double y2 = p2.getY(); + + final Snake snake = new Snake(null, arrowHorizontalAlignment(), arrowColor, Arrows.asToDown()); + snake.setLabel(getLabelPositive(branch)); + snake.addPoint(x1, y1); + snake.addPoint(x2, y1); + snake.addPoint(x2, y2); + + ug.draw(snake); + } + + private Point2D getP1(StringBounder stringBounder) { + final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); + final Point2D pt; + if (getFtile2() == tiles.get(0)) { + pt = dimDiamond1.getPointD(); + } else if (getFtile2() == tiles.get(tiles.size() - 1)) { + pt = dimDiamond1.getPointB(); + } else { + throw new IllegalStateException(); + } + return getTranslateDiamond1(stringBounder).getTranslated(pt); + } + + private Point2D getP2(final StringBounder stringBounder) { + return getTranslateOf(getFtile2(), stringBounder).getTranslated( + getFtile2().calculateDimension(stringBounder).getPointIn()); + } + + } + + class ConnectionVerticalThenHorizontal extends AbstractConnection { + + public ConnectionVerticalThenHorizontal(Ftile tile) { + super(tile, diamond2); + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final FtileGeometry geo = getFtile1().calculateDimension(stringBounder); + if (geo.hasPointOut() == false) { + return; + } + final Point2D p1 = getP1(stringBounder); + final Point2D p2 = getP2(stringBounder); + + final double x1 = p1.getX(); + final double y1 = p1.getY(); + final double x2 = p2.getX(); + final double y2 = p2.getY(); + + final UPolygon arrow = x2 > x1 ? Arrows.asToRight() : Arrows.asToLeft(); + final Snake snake = new Snake(arrowHorizontalAlignment(), arrowColor, arrow); + snake.addPoint(x1, y1); + snake.addPoint(x1, y2); + snake.addPoint(x2, y2); + + ug.draw(snake); + } + + private Point2D getP1(StringBounder stringBounder) { + return getTranslateOf(getFtile1(), stringBounder).getTranslated( + getFtile1().calculateDimension(stringBounder).getPointOut()); + } + + private Point2D getP2(StringBounder stringBounder) { + final FtileGeometry dimDiamond2 = diamond2.calculateDimension(stringBounder); + final Point2D pt; + if (getFtile1() == tiles.get(0)) { + pt = dimDiamond2.getPointD(); + } else if (getFtile1() == tiles.get(tiles.size() - 1)) { + pt = dimDiamond2.getPointB(); + } else { + throw new IllegalStateException(); + } + return getTranslateDiamond2(stringBounder).getTranslated(pt); + + } + + } + + protected UTranslate getTranslateOf(Ftile tile, StringBounder stringBounder) { + return getTranslateNude(tile, stringBounder).compose(getTranslateMain(stringBounder)); + + } + + class ConnectionVerticalTop extends AbstractConnection { + + private final Branch branch; + + public ConnectionVerticalTop(Ftile tile, Branch branch) { + super(diamond1, tile); + this.branch = branch; + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); + final UTranslate translateDiamond1 = getTranslateDiamond1(stringBounder); + final Point2D p1b = translateDiamond1.getTranslated(dimDiamond1.getPointB()); + final Point2D p1c = translateDiamond1.getTranslated(dimDiamond1.getPointC()); + final Point2D p1d = translateDiamond1.getTranslated(dimDiamond1.getPointD()); + + final Point2D p2 = getP2(stringBounder); + final double x2 = p2.getX(); + final double y2 = p2.getY(); + + final Snake snake = new Snake(null, arrowHorizontalAlignment(), arrowColor, Arrows.asToDown()); + snake.setLabel(getLabelPositive(branch)); + if (x2 < p1d.getX() - margin || x2 > p1b.getX() + margin) { + snake.addPoint(x2, p1d.getY()); + snake.addPoint(x2, y2); + } else { + final double x1 = p1c.getX(); + final double y1 = p1c.getY(); + + final double ym = (y1 * 2 + y2) / 3; + snake.addPoint(x1, y1); + snake.addPoint(x1, ym); + snake.addPoint(x2, ym); + snake.addPoint(x2, y2); + } + ug.draw(snake); + } + + private Point2D getP2(final StringBounder stringBounder) { + return getTranslateOf(getFtile2(), stringBounder).getTranslated( + getFtile2().calculateDimension(stringBounder).getPointIn()); + } + + } + + class ConnectionVerticalBottom extends AbstractConnection { + + public ConnectionVerticalBottom(Ftile tile) { + super(tile, diamond2); + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final Point2D p1 = getP1(stringBounder); + final FtileGeometry dimDiamond2 = diamond2.calculateDimension(stringBounder); + final UTranslate translateDiamond2 = getTranslateDiamond2(stringBounder); + final Point2D p2a = translateDiamond2.getTranslated(dimDiamond2.getPointA()); + final Point2D p2b = translateDiamond2.getTranslated(dimDiamond2.getPointB()); + final Point2D p2d = translateDiamond2.getTranslated(dimDiamond2.getPointD()); + + final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); + final UTranslate translateDiamond1 = getTranslateDiamond1(stringBounder); + final Point2D p1b = translateDiamond1.getTranslated(dimDiamond1.getPointB()); + final Point2D p1c = translateDiamond1.getTranslated(dimDiamond1.getPointC()); + final Point2D p1d = translateDiamond1.getTranslated(dimDiamond1.getPointD()); + + final double x1 = p1.getX(); + final double y1 = p1.getY(); + final double x2 = p2a.getX(); + final double y2 = p2a.getY(); + + final double ym = (y1 + y2) / 2; + + final Snake snake = new Snake(null, arrowHorizontalAlignment(), arrowColor, Arrows.asToDown()); + + if (x1 < p1d.getX() - margin || x1 > p1b.getX() + margin) { + snake.addPoint(x1, y1); + snake.addPoint(x1, p2d.getY()); + } else { + snake.addPoint(x1, y1); + snake.addPoint(x1, ym); + snake.addPoint(x2, ym); + snake.addPoint(x2, y2); + } + + ug.draw(snake); + } + + private Point2D getP1(StringBounder stringBounder) { + return getTranslateOf(getFtile1(), stringBounder).getTranslated( + getFtile1().calculateDimension(stringBounder).getPointOut()); + } + + } + + public Ftile addLinks() { + final List conns = new ArrayList(); + conns.add(new ConnectionHorizontalThenVertical(tiles.get(0), branches.get(0))); + conns.add(new ConnectionHorizontalThenVertical(tiles.get(tiles.size() - 1), branches.get(tiles.size() - 1))); + conns.add(new ConnectionVerticalThenHorizontal(tiles.get(0))); + conns.add(new ConnectionVerticalThenHorizontal(tiles.get(tiles.size() - 1))); + for (int i = 1; i < tiles.size() - 1; i++) { + conns.add(new ConnectionVerticalTop(tiles.get(i), branches.get(i))); + conns.add(new ConnectionVerticalBottom(tiles.get(i))); + } + + return FtileUtils.addConnection(this, conns); + } + +} diff --git a/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithOneLink.java b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithOneLink.java new file mode 100644 index 000000000..eaec448b3 --- /dev/null +++ b/src/net/sourceforge/plantuml/activitydiagram3/ftile/vcompact/cond/FtileSwitchWithOneLink.java @@ -0,0 +1,150 @@ +/* ======================================================================== + * 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.cond; + +import java.awt.geom.Point2D; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.FontParam; +import net.sourceforge.plantuml.activitydiagram3.Branch; +import net.sourceforge.plantuml.activitydiagram3.ftile.AbstractConnection; +import net.sourceforge.plantuml.activitydiagram3.ftile.Arrows; +import net.sourceforge.plantuml.activitydiagram3.ftile.Connection; +import net.sourceforge.plantuml.activitydiagram3.ftile.Ftile; +import net.sourceforge.plantuml.activitydiagram3.ftile.FtileGeometry; +import net.sourceforge.plantuml.activitydiagram3.ftile.FtileUtils; +import net.sourceforge.plantuml.activitydiagram3.ftile.Snake; +import net.sourceforge.plantuml.activitydiagram3.ftile.Swimlane; +import net.sourceforge.plantuml.creole.CreoleMode; +import net.sourceforge.plantuml.graphic.FontConfiguration; +import net.sourceforge.plantuml.graphic.HorizontalAlignment; +import net.sourceforge.plantuml.graphic.Rainbow; +import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.ugraphic.UGraphic; + +public class FtileSwitchWithOneLink extends FtileSwitchWithDiamonds { + + private final Rainbow arrowColor; + + public FtileSwitchWithOneLink(List tiles, List branches, Swimlane in, Ftile diamond1, + Ftile diamond2, StringBounder stringBounder, Rainbow arrowColor) { + super(tiles, branches, in, diamond1, diamond2, stringBounder); + this.arrowColor = arrowColor; + } + + class ConnectionVerticalTop extends AbstractConnection { + + private final Branch branch; + + public ConnectionVerticalTop(Ftile tile, Branch branch) { + super(diamond1, tile); + this.branch = branch; + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final Point2D p1 = getP1(stringBounder); + final Point2D p2 = getP2(stringBounder); + final double x1 = p1.getX(); + final double y1 = p1.getY(); + final double x2 = p2.getX(); + final double y2 = p2.getY(); + + final Snake snake = new Snake(null, arrowHorizontalAlignment(), arrowColor, Arrows.asToDown()); + snake.setLabel(getLabelPositive(branch)); + // snake.addPoint(x1, y1); + snake.addPoint(x2, y1); + snake.addPoint(x2, y2); + + ug.draw(snake); + } + + private Point2D getP1(StringBounder stringBounder) { + final FtileGeometry dimDiamond1 = diamond1.calculateDimension(stringBounder); + return getTranslateDiamond1(stringBounder).getTranslated(dimDiamond1.getPointC()); + } + + private Point2D getP2(final StringBounder stringBounder) { + return getTranslateOf(getFtile2(), stringBounder).getTranslated( + getFtile2().calculateDimension(stringBounder).getPointIn()); + } + } + + class ConnectionVerticalBottom extends AbstractConnection { + + public ConnectionVerticalBottom(Ftile tile) { + super(tile, diamond2); + } + + public void drawU(UGraphic ug) { + final StringBounder stringBounder = ug.getStringBounder(); + final Point2D p1 = getP1(stringBounder); + final Point2D p2 = getP2(stringBounder); + final double x1 = p1.getX(); + final double y1 = p1.getY(); + final double x2 = p2.getX(); + final double y2 = p2.getY(); + + final Snake snake = new Snake(null, arrowHorizontalAlignment(), arrowColor, Arrows.asToDown()); + // snake.addPoint(x1, y1); + snake.addPoint(x2, y1); + snake.addPoint(x2, y2); + + ug.draw(snake); + } + + private Point2D getP1(StringBounder stringBounder) { + return getTranslateOf(getFtile1(), stringBounder).getTranslated( + getFtile1().calculateDimension(stringBounder).getPointOut()); + } + + private Point2D getP2(StringBounder stringBounder) { + final FtileGeometry dimDiamond2 = diamond2.calculateDimension(stringBounder); + return getTranslateDiamond2(stringBounder).getTranslated(dimDiamond2.getPointA()); + } + } + + public Ftile addLinks() { + final List conns = new ArrayList(); + conns.add(new ConnectionVerticalTop(tiles.get(0), branches.get(0))); + conns.add(new ConnectionVerticalBottom(tiles.get(0))); + + return FtileUtils.addConnection(this, conns); + } + +} diff --git a/src/net/sourceforge/plantuml/command/BlocLines.java b/src/net/sourceforge/plantuml/command/BlocLines.java index 413f6a3c1..24114d8a6 100644 --- a/src/net/sourceforge/plantuml/command/BlocLines.java +++ b/src/net/sourceforge/plantuml/command/BlocLines.java @@ -48,7 +48,6 @@ import java.util.List; import net.sourceforge.plantuml.BackSlash; import net.sourceforge.plantuml.LineLocation; -import net.sourceforge.plantuml.LineLocationImpl; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.cucadiagram.Display; diff --git a/src/net/sourceforge/plantuml/command/PSystemAbstractFactory.java b/src/net/sourceforge/plantuml/command/PSystemAbstractFactory.java index 668edc11d..9c9c8e4fe 100644 --- a/src/net/sourceforge/plantuml/command/PSystemAbstractFactory.java +++ b/src/net/sourceforge/plantuml/command/PSystemAbstractFactory.java @@ -35,14 +35,17 @@ */ package net.sourceforge.plantuml.command; -import net.sourceforge.plantuml.AbstractPSystem; +import java.util.List; + import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.ErrorUmlType; import net.sourceforge.plantuml.LineLocation; -import net.sourceforge.plantuml.PSystemError; +import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.api.PSystemFactory; import net.sourceforge.plantuml.core.DiagramType; import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.error.PSystemError; +import net.sourceforge.plantuml.error.PSystemErrorUtils; public abstract class PSystemAbstractFactory implements PSystemFactory { @@ -53,17 +56,20 @@ public abstract class PSystemAbstractFactory implements PSystemFactory { this.type = type; } - final protected AbstractPSystem buildEmptyError(UmlSource source, LineLocation lineLocation) { + final protected PSystemError buildEmptyError(UmlSource source, LineLocation lineLocation, + List trace) { final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, EMPTY_DESCRIPTION, /* 1, */lineLocation); - final PSystemError result = new PSystemError(source, err, null); + // final AbstractPSystemError result = PSystemErrorUtils.buildV1(source, err, null); + final PSystemError result = PSystemErrorUtils.buildV2(source, err, null, trace); result.setSource(source); return result; } - final protected PSystemError buildExecutionError(UmlSource source, String stringError, LineLocation lineLocation) { + final protected PSystemError buildExecutionError(UmlSource source, String stringError, + LineLocation lineLocation, List trace) { final ErrorUml err = new ErrorUml(ErrorUmlType.EXECUTION_ERROR, stringError, /* 1, */ lineLocation); - final PSystemError result = new PSystemError(source, err, null); + final PSystemError result = PSystemErrorUtils.buildV2(source, err, null, trace); result.setSource(source); return result; } diff --git a/src/net/sourceforge/plantuml/command/PSystemBasicFactory.java b/src/net/sourceforge/plantuml/command/PSystemBasicFactory.java index f3a4ef7cd..acd62283d 100644 --- a/src/net/sourceforge/plantuml/command/PSystemBasicFactory.java +++ b/src/net/sourceforge/plantuml/command/PSystemBasicFactory.java @@ -38,11 +38,11 @@ package net.sourceforge.plantuml.command; import net.sourceforge.plantuml.AbstractPSystem; import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.ErrorUmlType; -import net.sourceforge.plantuml.PSystemError; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.DiagramType; import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.utils.StartUtils; import net.sourceforge.plantuml.version.IteratorCounter2; @@ -80,7 +80,7 @@ public abstract class PSystemBasicFactory

extends PSy first = false; if (StartUtils.isArobaseEndDiagram(s.getString())) { if (source.getTotalLineCount() == 2 && source.isStartDef() == false) { - return buildEmptyError(source, s.getLocation()); + return buildEmptyError(source, s.getLocation(), it.getTrace()); } if (system != null) { system.setSource(source); @@ -90,7 +90,8 @@ public abstract class PSystemBasicFactory

extends PSy system = executeLine(system, s.getString()); if (system == null) { final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, "Syntax Error?", s.getLocation()); - return new PSystemError(source, err, null); + // return PSystemErrorUtils.buildV1(source, err, null); + return PSystemErrorUtils.buildV2(source, err, null, it.getTrace()); } } if (system != null) { diff --git a/src/net/sourceforge/plantuml/command/PSystemSingleLineFactory.java b/src/net/sourceforge/plantuml/command/PSystemSingleLineFactory.java index 4c964f121..596e2db81 100644 --- a/src/net/sourceforge/plantuml/command/PSystemSingleLineFactory.java +++ b/src/net/sourceforge/plantuml/command/PSystemSingleLineFactory.java @@ -38,11 +38,12 @@ package net.sourceforge.plantuml.command; import net.sourceforge.plantuml.AbstractPSystem; import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.ErrorUmlType; -import net.sourceforge.plantuml.PSystemError; +import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.DiagramType; import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.utils.StartUtils; import net.sourceforge.plantuml.version.IteratorCounter2; @@ -61,7 +62,8 @@ public abstract class PSystemSingleLineFactory extends PSystemAbstractFactory { } final IteratorCounter2 it = source.iterator2(); if (source.isEmpty()) { - return buildEmptyError(source, it.peek().getLocation()); + final LineLocation location = it.next().getLocation(); + return buildEmptyError(source, location, it.getTrace()); } final StringLocated startLine = it.next(); @@ -70,17 +72,17 @@ public abstract class PSystemSingleLineFactory extends PSystemAbstractFactory { } if (it.hasNext() == false) { - return buildEmptyError(source, startLine.getLocation()); + return buildEmptyError(source, startLine.getLocation(), it.getTrace()); } final StringLocated s = it.next(); if (StartUtils.isArobaseEndDiagram(s.getString())) { - return buildEmptyError(source, s.getLocation()); + return buildEmptyError(source, s.getLocation(), it.getTrace()); } final AbstractPSystem sys = executeLine(s.getString()); if (sys == null) { - final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, "Syntax Error?", - /* it.currentNum() - 1, */s.getLocation()); - return new PSystemError(source, err, null); + final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, "Syntax Error?", s.getLocation()); + // return PSystemErrorUtils.buildV1(source, err, null); + return PSystemErrorUtils.buildV2(source, err, null, it.getTrace()); } sys.setSource(source); return sys; diff --git a/src/net/sourceforge/plantuml/command/SingleLineCommand2.java b/src/net/sourceforge/plantuml/command/SingleLineCommand2.java index 8959e003d..5e03c0805 100644 --- a/src/net/sourceforge/plantuml/command/SingleLineCommand2.java +++ b/src/net/sourceforge/plantuml/command/SingleLineCommand2.java @@ -36,11 +36,11 @@ package net.sourceforge.plantuml.command; import net.sourceforge.plantuml.LineLocation; -import net.sourceforge.plantuml.PSystemError; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemError; public abstract class SingleLineCommand2 implements Command { diff --git a/src/net/sourceforge/plantuml/command/UmlDiagramFactory.java b/src/net/sourceforge/plantuml/command/UmlDiagramFactory.java index 8edabaa00..37319acfa 100644 --- a/src/net/sourceforge/plantuml/command/UmlDiagramFactory.java +++ b/src/net/sourceforge/plantuml/command/UmlDiagramFactory.java @@ -43,7 +43,7 @@ import java.util.List; import net.sourceforge.plantuml.AbstractPSystem; import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.ErrorUmlType; -import net.sourceforge.plantuml.PSystemError; +import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.classdiagram.command.CommandHideShowByGender; @@ -51,6 +51,8 @@ import net.sourceforge.plantuml.classdiagram.command.CommandHideShowByVisibility import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.core.DiagramType; import net.sourceforge.plantuml.core.UmlSource; +import net.sourceforge.plantuml.error.PSystemError; +import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.sequencediagram.command.CommandSkin; import net.sourceforge.plantuml.utils.StartUtils; import net.sourceforge.plantuml.version.IteratorCounter2; @@ -76,7 +78,8 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory { } if (source.isEmpty()) { - return buildEmptyError(source, startLine.getLocation()); + it.next(); + return buildEmptyError(source, startLine.getLocation(), it.getTrace()); } AbstractPSystem sys = createEmptyDiagram(); @@ -87,10 +90,12 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory { } final String err = sys.checkFinalError(); if (err != null) { - return buildExecutionError(source, err, it.peek().getLocation()); + final LineLocation location = it.next().getLocation(); + return buildExecutionError(source, err, location, it.getTrace()); } if (source.getTotalLineCount() == 2) { - return buildEmptyError(source, it.peek().getLocation()); + final LineLocation location = it.next().getLocation(); + return buildEmptyError(source, location, it.getTrace()); } sys.makeDiagramReady(); if (sys.isOk() == false) { @@ -113,14 +118,15 @@ public abstract class UmlDiagramFactory extends PSystemAbstractFactory { final Step step = getCandidate(it); if (step == null) { final ErrorUml err = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, "Syntax Error?", it.peek().getLocation()); - return new PSystemError(source, err, null); + it.next(); + return PSystemErrorUtils.buildV2(source, err, null, it.getTrace()); } 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()); - sys = new PSystemError(source, err, result.getDebugLines()); + sys = PSystemErrorUtils.buildV2(source, err, result.getDebugLines(), it.getTrace()); } if (result.getNewDiagram() != null) { sys = result.getNewDiagram(); diff --git a/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java b/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java index 97cc403d1..f658dcae0 100644 --- a/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java +++ b/src/net/sourceforge/plantuml/command/note/sequence/FactorySequenceNoteOverSeveralCommand.java @@ -35,6 +35,8 @@ */ package net.sourceforge.plantuml.command.note.sequence; +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; @@ -51,6 +53,7 @@ import net.sourceforge.plantuml.command.regex.RegexConcat; import net.sourceforge.plantuml.command.regex.RegexLeaf; import net.sourceforge.plantuml.command.regex.RegexResult; import net.sourceforge.plantuml.cucadiagram.Display; +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; @@ -65,7 +68,11 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF return new RegexConcat( // new RegexLeaf("^"), // new RegexLeaf("VMERGE", "(/)?[%s]*"), // - new RegexLeaf("STYLE", "(note|hnote|rnote)[%s]+over[%s]+"), // + new RegexLeaf("STYLE", "(note|hnote|rnote)"), // + new RegexLeaf("[%s]*"), // + new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + new RegexLeaf("[%s]*"), // + new RegexLeaf("over[%s]+"), // new RegexLeaf("P1", "([\\p{L}0-9_.@]+|[%g][^%g]+[%g])[%s]*\\,[%s]*"), // new RegexLeaf("P2", "([\\p{L}0-9_.@]+|[%g][^%g]+[%g])[%s]*"), // color().getRegex(), // @@ -78,7 +85,11 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF return new RegexConcat( // new RegexLeaf("^"), // new RegexLeaf("VMERGE", "(/)?[%s]*"), // - new RegexLeaf("STYLE", "(note|hnote|rnote)[%s]+over[%s]+"), // + new RegexLeaf("STYLE", "(note|hnote|rnote)"), // + new RegexLeaf("[%s]*"), // + new RegexLeaf("STEREO", "(\\<{2}.*\\>{2})?"), // + new RegexLeaf("[%s]*"), // + new RegexLeaf("over[%s]+"), // new RegexLeaf("P1", "([\\p{L}0-9_.@]+|[%g][^%g]+[%g])[%s]*\\,[%s]*"), // new RegexLeaf("P2", "([\\p{L}0-9_.@]+|[%g][^%g]+[%g])[%s]*"), // color().getRegex(), // @@ -87,17 +98,17 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF new RegexLeaf("NOTE", "(.*)"), // new RegexLeaf("$")); } - + private static ColorParser color() { return ColorParser.simpleColor(ColorType.BACK); } - public Command createSingleLine() { return new SingleLineCommand2(getRegexConcatSingleLine()) { @Override - protected CommandExecutionResult executeArg(final SequenceDiagram system, LineLocation location, RegexResult arg) { + protected CommandExecutionResult executeArg(final SequenceDiagram system, LineLocation location, + RegexResult arg) { final BlocLines strings = BlocLines.getWithNewlines(arg.get("NOTE", 0)); return executeInternal(system, arg, strings); @@ -135,9 +146,16 @@ public final class FactorySequenceNoteOverSeveralCommand implements SingleMultiF final boolean tryMerge = line0.get("VMERGE", 0) != null; final Display display = diagram.manageVariable(lines.toDisplay()); final Note note = new Note(p1, p2, display); - 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.setColors(colors); - // note.setSpecificColorTOBEREMOVED(ColorType.BACK, diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(line0.get("COLOR", 0))); + // note.setSpecificColorTOBEREMOVED(ColorType.BACK, + // diagram.getSkinParam().getIHtmlColorSet().getColorIfValid(line0.get("COLOR", 0))); note.setStyle(NoteStyle.getNoteStyle(line0.get("STYLE", 0))); if (line0.get("URL", 0) != null) { final UrlBuilder urlBuilder = new UrlBuilder(diagram.getSkinParam().getValue("topurl"), ModeUrl.STRICT); diff --git a/src/net/sourceforge/plantuml/creole/CreoleMode.java b/src/net/sourceforge/plantuml/creole/CreoleMode.java index 7fb8a28e9..8100efde8 100644 --- a/src/net/sourceforge/plantuml/creole/CreoleMode.java +++ b/src/net/sourceforge/plantuml/creole/CreoleMode.java @@ -36,6 +36,6 @@ package net.sourceforge.plantuml.creole; public enum CreoleMode { - FULL, SIMPLE_LINE; + FULL, SIMPLE_LINE, NO_CREOLE; } diff --git a/src/net/sourceforge/plantuml/cucadiagram/Display.java b/src/net/sourceforge/plantuml/cucadiagram/Display.java index d0c8327f1..9e91940c5 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Display.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Display.java @@ -452,8 +452,8 @@ public class Display implements Iterable { } public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, - ISkinSimple spriteContainer, CreoleMode modeSimpleLine) { - return create(fontConfiguration, horizontalAlignment, spriteContainer, LineBreakStrategy.NONE, modeSimpleLine, + ISkinSimple spriteContainer, CreoleMode creoleMode) { + return create(fontConfiguration, horizontalAlignment, spriteContainer, LineBreakStrategy.NONE, creoleMode, null, null); } @@ -470,7 +470,7 @@ public class Display implements Iterable { } public TextBlock create(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, - ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode modeSimpleLine, + ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode creoleMode, UFont fontForStereotype, HtmlColor htmlColorForStereotype) { if (maxMessageSize == null) { throw new IllegalArgumentException(); @@ -492,12 +492,12 @@ public class Display implements Iterable { } } - return getCreole(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, modeSimpleLine); + return getCreole(fontConfiguration, horizontalAlignment, spriteContainer, maxMessageSize, creoleMode); } private TextBlock getCreole(FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, - ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode modeSimpleLine) { - final Sheet sheet = new CreoleParser(fontConfiguration, horizontalAlignment, spriteContainer, modeSimpleLine) + ISkinSimple spriteContainer, LineBreakStrategy maxMessageSize, CreoleMode creoleMode) { + final Sheet sheet = new CreoleParser(fontConfiguration, horizontalAlignment, spriteContainer, creoleMode) .createSheet(this); final SheetBlock1 sheetBlock1 = new SheetBlock1(sheet, maxMessageSize, spriteContainer == null ? 0 : spriteContainer.getPadding()); diff --git a/src/net/sourceforge/plantuml/cucadiagram/Stereotype.java b/src/net/sourceforge/plantuml/cucadiagram/Stereotype.java index f09d2f339..0141831ee 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/Stereotype.java +++ b/src/net/sourceforge/plantuml/cucadiagram/Stereotype.java @@ -245,6 +245,9 @@ public class Stereotype implements CharSequence { if (isWithOOSymbol()) { return null; } + if (spriteName != null && spriteName.startsWith("archimate/")) { + return guillemet.manageGuillemet("<<" + spriteName.substring("archimate/".length()) + ">>"); + } return guillemet.manageGuillemet(label); } diff --git a/src/net/sourceforge/plantuml/cucadiagram/dot/GraphvizUtils.java b/src/net/sourceforge/plantuml/cucadiagram/dot/GraphvizUtils.java index 9b495a057..fe9993620 100644 --- a/src/net/sourceforge/plantuml/cucadiagram/dot/GraphvizUtils.java +++ b/src/net/sourceforge/plantuml/cucadiagram/dot/GraphvizUtils.java @@ -132,33 +132,31 @@ public class GraphvizUtils { if (local != null) { return local; } - final String env = System.getProperty("PLANTUML_LIMIT_SIZE"); + final String env = getenv("PLANTUML_LIMIT_SIZE"); if (StringUtils.isNotEmpty(env) && env.matches("\\d+")) { return Integer.parseInt(env); } - final String getenv = System.getenv("PLANTUML_LIMIT_SIZE"); - if (StringUtils.isNotEmpty(getenv) && getenv.matches("\\d+")) { - return Integer.parseInt(getenv); - } return 4096; } public static String getenvDefaultConfigFilename() { - final String env = System.getProperty("PLANTUML_DEFAULT_CONFIG_FILENAME"); - if (StringUtils.isNotEmpty(env)) { - return env; - } - return System.getenv("PLANTUML_DEFAULT_CONFIG_FILENAME"); + return getenv("PLANTUML_DEFAULT_CONFIG_FILENAME"); } public static String getenvLogData() { - final String env = System.getProperty("PLANTUML_LOGDATA"); + return getenv("PLANTUML_LOGDATA"); + } + + public static String getenv(String name) { + final String env = System.getProperty(name); if (StringUtils.isNotEmpty(env)) { return env; } - return System.getenv("PLANTUML_LOGDATA"); + return System.getenv(name); } + + private static String dotVersion = null; public static String dotVersion() throws IOException, InterruptedException { diff --git a/src/net/sourceforge/plantuml/dedication/Dedications.java b/src/net/sourceforge/plantuml/dedication/Dedications.java index 3a7c3fd29..edb3139f6 100644 --- a/src/net/sourceforge/plantuml/dedication/Dedications.java +++ b/src/net/sourceforge/plantuml/dedication/Dedications.java @@ -51,6 +51,7 @@ public class Dedications { addNormal("Write your own dedication!", "dedication"); addNormal("linux_china", "linux_china"); addNormal("ARKBAN", "arkban"); + addNormal("Boundaries allow discipline to create true strength", "boundaries"); addCrypted("0", "pOhci6rKgPXw32AeYXhOpSY0suoauHq5VUSwFqHLHsLYgSO6WaJ7BW5vtHBAoU6ePbcW7d8Flx99MWjPSKQTDm00"); addCrypted("1", "LTxN3hdnhSJ515qcA7IQ841axt4GXfUd3n2wgNirYCdLnyX2360Gv1OEOnJ1-gwFzRW5B3HAqLBkR6Ge0WW_Z000"); } diff --git a/src/net/sourceforge/plantuml/dedication/boundaries.png b/src/net/sourceforge/plantuml/dedication/boundaries.png new file mode 100644 index 0000000000000000000000000000000000000000..b989556e6ac921c6ea34df2a7ef4d3225fdd3854 GIT binary patch literal 51300 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 { final Code code = Code.of(StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(codeRaw)); final String icon = arg.getLazzy("STEREOTYPE", 0); - final IEntity entity = diagram.getOrCreateLeaf(code, LeafType.DESCRIPTION, USymbol.RECTANGLE); - + final IEntity entity = diagram.getOrCreateLeaf(code, LeafType.DESCRIPTION, USymbol.ARCHIMATE); + final String displayRaw = arg.getLazzy("DISPLAY", 0); String display = displayRaw; @@ -112,7 +112,7 @@ public class CommandArchimate extends SingleLineCommand2 { display = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(display); entity.setDisplay(Display.getWithNewlines(display)); - entity.setUSymbol(USymbol.RECTANGLE); + entity.setUSymbol(USymbol.ARCHIMATE); if (icon != null) { entity.setStereotype(new Stereotype("<<$archimate/" + icon + ">>", diagram.getSkinParam() .getCircledCharacterRadius(), diagram.getSkinParam().getFont(null, false, @@ -124,5 +124,4 @@ public class CommandArchimate extends SingleLineCommand2 { return CommandExecutionResult.ok(); } - } diff --git a/src/net/sourceforge/plantuml/donors/PSystemDonors.java b/src/net/sourceforge/plantuml/donors/PSystemDonors.java index dc5121d98..81187d210 100644 --- a/src/net/sourceforge/plantuml/donors/PSystemDonors.java +++ b/src/net/sourceforge/plantuml/donors/PSystemDonors.java @@ -70,23 +70,24 @@ public class PSystemDonors extends AbstractPSystem { private static final int COLS = 6; private static final int FREE_LINES = 6; - - public static final String DONORS = "6nC90AmEEBmtNeGqQuvtvvyfOnYjY14ipnEA4uiuxGR47-3Ujh6l87u5mINjNXY1P6bpXlCCebWGDPxr" - + "KuTjRlPNQ4jzbOnnKnDcmWH88JoNxPv-tYvLP9GWfehjjqnexsy_BjGXhHM2At1JEVztQO1veO0qJgTu" - + "29S3r7yAbjuekTPi_jATxOLcRJPqN81ADTfOiwDOi-L3HEbheJ6HsMkCWcoRQyUUKV8enbSYnLeRMs2L" - + "anOKQcCunITQ3_zH2sZIcbr3UhQ0OXaf6itRlZRs7PoVmQ0HmgnqnA3iKEBGNM2iKD-e8KnAi20tYcbi" - + "9END4pL2EA32B_oZ92bd3raPPTY0CDi31Qn-JH28PrD12MTxNWCAzs2BXWPBTMvPwIxt3yDJeImQhWKT" - + "PWvoWLG0UHDq8P-hprpIk8rDCSEBxiPuzKr2tcJd-UFDWxxfj34mVkuUcYdBSg3QUaZXbEiOlpewvAU6" - + "ZEpzfexOPWdX-MqkJFlI0fqVG2-rXednD-UNXMI8Z2breQVEwPDzYa1vPIaiUXLJNWlzeilLRI2UHmyM" - + "s5HVvrfPmGvTcTWDVK8hdCCwN-1K3VNFGwwwZa_1DM6tUzkKCsbpgVX_wvPc9ka1EcYYZT3L4YDFtxIg" - + "5vCXWfT17uRS0d83gY-JH-Lb-P3usXzGU4iYWIfjpcY_KPanNt9OH7ZXlJDLF01cDubyGLWyI0_YEe7U" - + "XYgRwB2xVa-Jac7JniovKIgMkmvZL3wcavMBxjLSu2iDmx9i3ktMVi1Hm0FOQLvr5dUj0fosz9vOB8qd" - + "6KZNCAS6qdvKsVUq9TsNEaPcMM_nhYxnRcu7VnwwV63V5YqmhNGTiY0qRngHKxSuprE3wczFo0PjJRFE" - + "3ivL8KAWc1cN0VUx9YigEO8m6Svmw7a2mgPrNh7A3UvUcCwrpixKjKHOprnz3DIG7tKsO5IwJgG07-Uz" - + "W6V0eyJ-SDuhenxgsn1sBQ1431DifCBOHWYhXCqPP4Jlbvvvd-1zNjfZeTx6DpkVSIX-RA8xnWs0LcSq" - + "4xgl6v29qCXNgPSy9ax0pxZzXdemws3ZR_IqOXp4bf8Oe0he9_mI7DJEMpIDzHPzRcljRTdvywyvCicf" - + "sDUnMX0z1q7-goYearYEAkz6Vb_ulC9Y8ICWri4ELruQlH1WM13Iibogjdj6uKmfbfkfdJ9AVQZmVv9B" - + "4CJbZIWlDc6LqQS4gxMtUbAvRLz-n-4j1u__4rMUYUJIbSL8bWjXYlCqtiT89QnR8Go-3fy0"; + + public static final String DONORS = "6qq90AmER5DS9tl8vfhbtlpPbKCCAM84o_E4uZ2mYAUx0V47kBTjx2k8Nq5mIRiNHY1PcfrHNOSGbmZ6" + + "UZUdwEgVdbcBbJybk-gCEFN2l32zqB1XCybzPh80tdwg32d1lpLJ_WZwmrDMI5HRTZHHjDaZL_zlEeNa" + + "eI8CGxCL7YMZ4Mf_89AnPgUQmzsFQjsrwk8kA7HReSPqYZY6gyBS4Xz5LlOApDboYPUh5efRQHnxGSMj" + + "cF0IAQwsiGGkEQY9IaqEPxWXzVKVzGRQRAwmKikzeBYs8KcjV__OEGvmVWw3IXY7MB21COSAX_a4FKMz" + + "4OEnYqGJfPuCOnCndpmnm8GNcjZ0FyeYfaTfPaz76yRXaL30vTTm0d5KLLHeTl0ne7YKMdIicAwBuqwp" + + "-lhGUqeQYuQRm8A31Mc2L01v4tJ2dn5hV5MvjztGm2lEpZhRPY6lyl3oyUP6tzwuir2-xnwUwUEweTgY" + + "bBcDxwszvoqWTolrMl5FEMAPQ-9skNegqFBh1V8Fe9VcHCNwcPU7XUOGzpRiYxZF-PsF8G9ZnMcmsBiO" + + "wZNfoIv_iuaipo0Bl8IVYutCn1Q-Sl4mw9TQyJoYyuMGPMNvkEXeMNjCj2PkrhrzikU8kPh_VpTzX9ca" + + "4tGoHMtgceXIPkrUjIU35C7JG6-6t0Ho1whJzIfE7nVvptf0z5P51gAqEUFzGd51RMWpn1nOwqA96y3y" + + "Af5E6AUJj4HQ0-XjkBA8j6NQy-xAsRvYpBrCSc6xQpHMn0TooBEQtJq56saObx9PEgBzW3s1Hx6pN7Ms" + + "m5e5EExflUlDLF-9WNgL9oKXhKUKnp7ygsR34gMoQ9kyMShVC_t6duUkBzZJeaDCAxqEMGog5ur8fNyP" + + "_Mv5wUyWPMDUya7Um5TqJ0DXolWKSBjvCgMABHYxThh3mXOWtERYYbK1SFT2TIujAxUmAMRTS_KnK2b-" + + "Z4zWgCmBpmhiEEy5EWCzIgoFvhtIvscvDmLR2oXJBGGBQQAShHGKvMkHZ5ZhqdFG1dZxou8BzDQUet6a" + + "G_5h8ReZRG2qPb6DqEUw0Pa8bN95l-PZOGJyxQ-ltODH1n__EePFnK6yf2G6f0BQqOtpe7wwferWlKMV" + + "Vz-sgu_Wpx_cqH2dQhltjmRHwo38Vu62S3fNp-0mAlDdu0FZT2KzeDJ1IgsyD7eQO4GGqhAUI_kSaHuP" + + "K-NsrI9th0yL_sqhnWdAUCFAYqM2eiMIitoxMYPL8FRrEnQd73B-JrHv9f9BLqv68XGxEyIPZVVHXk7c" + + "c-36JCSL0crVVxURrQaokv2Srt0WCW00"; @Override final protected ImageData exportDiagramNow(OutputStream os, int num, FileFormatOption fileFormat, long seed) diff --git a/src/net/sourceforge/plantuml/PSystemError.java b/src/net/sourceforge/plantuml/error/PSystemError.java similarity index 62% rename from src/net/sourceforge/plantuml/PSystemError.java rename to src/net/sourceforge/plantuml/error/PSystemError.java index 9d338f7a9..93e6349f3 100644 --- a/src/net/sourceforge/plantuml/PSystemError.java +++ b/src/net/sourceforge/plantuml/error/PSystemError.java @@ -32,7 +32,7 @@ * Original Author: Arnaud Roques * */ -package net.sourceforge.plantuml; +package net.sourceforge.plantuml.error; import java.awt.Color; import java.awt.geom.Dimension2D; @@ -42,18 +42,26 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; +import net.sourceforge.plantuml.AbstractPSystem; +import net.sourceforge.plantuml.BackSlash; +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ErrorUml; +import net.sourceforge.plantuml.FileFormat; +import net.sourceforge.plantuml.FileFormatOption; +import net.sourceforge.plantuml.FileImageData; +import net.sourceforge.plantuml.LineLocation; +import net.sourceforge.plantuml.SpriteContainerEmpty; +import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.api.ImageDataAbstract; import net.sourceforge.plantuml.api.ImageDataSimple; import net.sourceforge.plantuml.asciiart.UmlCharArea; import net.sourceforge.plantuml.core.DiagramDescription; import net.sourceforge.plantuml.core.ImageData; -import net.sourceforge.plantuml.core.UmlSource; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.eggs.PSystemWelcome; import net.sourceforge.plantuml.flashcode.FlashCodeFactory; @@ -69,6 +77,7 @@ import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.InnerStrategy; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; +import net.sourceforge.plantuml.graphic.TextBlockRaw; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.graphic.VerticalAlignment; import net.sourceforge.plantuml.svek.TextBlockBackcolored; @@ -83,53 +92,109 @@ import net.sourceforge.plantuml.ugraphic.txt.UGraphicTxt; import net.sourceforge.plantuml.version.LicenseInfo; import net.sourceforge.plantuml.version.PSystemVersion; -public class PSystemError extends AbstractPSystem { +public abstract class PSystemError extends AbstractPSystem { - private final LineLocation higherErrorPosition; - private final List printedErrors; - private final List debugLines = new ArrayList(); + protected List trace; + protected ErrorUml singleError; - public PSystemError(UmlSource source, ErrorUml singleError, List debugLines) { - this(source, Collections.singletonList(singleError), debugLines); + final protected StringLocated getLastLine() { + return trace.get(trace.size() - 1); } - private PSystemError(UmlSource source, List all, List debugLines) { - this.setSource(source); + final public LineLocation getLineLocation() { + return getLastLine().getLocation(); + } - final LineLocation execution = getHigherErrorPosition2(ErrorUmlType.EXECUTION_ERROR, all); - final LineLocation syntax = getHigherErrorPosition2(ErrorUmlType.SYNTAX_ERROR, all); + final public Collection getErrorsUml() { + return Collections.singleton(singleError); + } - if (execution == null && syntax == null) { - throw new IllegalStateException(); + final public String getWarningOrError() { + final StringBuilder sb = new StringBuilder(); + sb.append(getDescription()); + sb.append(BackSlash.CHAR_NEWLINE); + for (CharSequence t : getTitle().getDisplay()) { + sb.append(t); + sb.append(BackSlash.CHAR_NEWLINE); } + sb.append(BackSlash.CHAR_NEWLINE); + return sb.toString(); + } - if (execution != null && (syntax == null || execution.compareTo(syntax) >= 0)) { - higherErrorPosition = execution; - printedErrors = getErrorsAt2(execution, ErrorUmlType.EXECUTION_ERROR, all); + private TextBlockBackcolored getGraphicalFormatted() { + final FontConfiguration fc0 = GraphicStrings.sansSerif14(HtmlColorUtils.BLACK).bold(); + final FontConfiguration fc1 = GraphicStrings.sansSerif14(HtmlColorUtils.MY_GREEN).bold(); + final FontConfiguration fc2 = GraphicStrings.sansSerif14(HtmlColorUtils.RED).bold(); + + final List fullBody = getTextFullBody(); + final TextBlock result0 = TextBlockUtils.addBackcolor( + TextBlockUtils.withMargin(new TextBlockRaw(getTextFromStack(), fc0), 1, 1, 1, 4), + HtmlColorUtils.MY_GREEN); + final TextBlock result1 = new TextBlockRaw(allButLast(fullBody), fc1); + final TextBlock result2 = new TextBlockRaw(onlyLast(fullBody), fc1.wave(HtmlColorUtils.RED)); + final TextBlock result3 = new TextBlockRaw(getTextError(), fc2); + TextBlock result = result0; + result = TextBlockUtils.mergeTB(result, result1, HorizontalAlignment.LEFT); + result = TextBlockUtils.mergeTB(result, result2, HorizontalAlignment.LEFT); + result = TextBlockUtils.mergeTB(result, result3, HorizontalAlignment.LEFT); + result = TextBlockUtils.withMargin(result, 5, 5); + return TextBlockUtils.addBackcolor(result, HtmlColorUtils.BLACK); + } + + private List getPureAsciiFormatted() { + final List result = getTextFromStack(); + result.addAll(getTextFullBody()); + result.add("^^^^^"); + result.addAll(getTextError()); + return result; + } + + private List getTextFromStack() { + LineLocation lineLocation = getLineLocation(); + final List result = new ArrayList(); + if (lineLocation != null) { + append(result, lineLocation); + while (lineLocation.getParent() != null) { + lineLocation = lineLocation.getParent(); + append(result, lineLocation); + } + } + return result; + } + + private List getTextFullBody() { + final List result = new ArrayList(); + result.add(" "); + final int traceSize = trace.size(); + if (traceSize > 40) { + for (StringLocated s : trace.subList(0, 5)) { + addToResult(result, s); + } + result.add("..."); + final int skipped = traceSize - 5 - 20; + result.add("... ( skipping " + skipped + " lines )"); + result.add("..."); + for (StringLocated s : trace.subList(traceSize - 20, traceSize)) { + addToResult(result, s); + } } else { - // assert syntax.compareTo(execution) > 0; - higherErrorPosition = syntax; - printedErrors = getErrorsAt2(syntax, ErrorUmlType.SYNTAX_ERROR, all); + for (StringLocated s : trace) { + addToResult(result, s); + } } - - if (debugLines != null) { - this.debugLines.addAll(debugLines); - } - + return result; } - private String getSuggestColor(boolean useRed) { - if (useRed) { - return "black"; + private void addToResult(final List result, StringLocated s) { + String tmp = s.getString(); + if (tmp.length() > 120) { + tmp = tmp.substring(0, 120) + " ..."; } - return "white"; + result.add(tmp); } - private String getRed(boolean useRed) { - if (useRed) { - return "#CD0A0A"; - } - return "red"; + private List getTextError() { + return Arrays.asList(" " + singleError.getError()); } @Override @@ -138,13 +203,13 @@ public class PSystemError extends AbstractPSystem { if (fileFormat.getFileFormat() == FileFormat.ATXT || fileFormat.getFileFormat() == FileFormat.UTXT) { final UGraphicTxt ugt = new UGraphicTxt(); final UmlCharArea area = ugt.getCharArea(); - area.drawStringsLR(getTextStrings(), 0, 0); + area.drawStringsLR(getPureAsciiFormatted(), 0, 0); area.print(new PrintStream(os)); return new ImageDataSimple(1, 1); } - final boolean useRed = fileFormat.isUseRedForError(); - final TextBlockBackcolored result = GraphicStrings.createForError(getHtmlStrings(useRed), useRed); + // final boolean useRed = fileFormat.isUseRedForError(); + final TextBlockBackcolored result = getGraphicalFormatted(); TextBlock udrawable; final ImageBuilder imageBuilder = new ImageBuilder(new ColorMapperIdentity(), 1.0, result.getBackcolor(), @@ -156,11 +221,11 @@ public class PSystemError extends AbstractPSystem { } final int min = (int) (System.currentTimeMillis() / 60000L) % 60; // udrawable = addMessageAdopt(udrawable); - if (min == 1 && LicenseInfo.retrieveNamedOrDistributorQuickIsValid() == false) { + if (min == 1 || min == 8) { udrawable = addMessagePatreon(udrawable); - } else if (min == 15 && LicenseInfo.retrieveNamedOrDistributorQuickIsValid() == false) { + } else if (min == 15) { udrawable = addMessageLiberapay(udrawable); - } else if (min == 30 && LicenseInfo.retrieveNamedOrDistributorQuickIsValid() == false) { + } else if (min == 30) { udrawable = addMessageDedication(udrawable); } else if (getSource().containsIgnoreCase("arecibo")) { udrawable = addMessageArecibo(udrawable); @@ -171,6 +236,31 @@ public class PSystemError extends AbstractPSystem { return imageData; } + private void append(List result, LineLocation lineLocation) { + if (lineLocation.getDescription() != null) { + result.add("[From " + lineLocation.getDescription() + " (line " + (lineLocation.getPosition() + 1) + ") ]"); + } + } + + // private String getRed(boolean useRed) { + // if (useRed) { + // return "#CD0A0A"; + // } + // return "red"; + // } + // + final public DiagramDescription getDescription() { + return new DiagramDescription("(Error)"); + } + + private List allButLast(List full) { + return full.subList(0, full.size() - 1); + } + + private List onlyLast(List full) { + return full.subList(full.size() - 1, full.size()); + } + private TextBlockBackcolored getWelcome() throws IOException { return new PSystemWelcome(GraphicPosition.BACKGROUND_CORNER_TOP_RIGHT).getGraphicStrings(); } @@ -181,6 +271,9 @@ public class PSystemError extends AbstractPSystem { } private TextBlock addMessageLiberapay(final TextBlock source) throws IOException { + if (LicenseInfo.retrieveNamedOrDistributorQuickIsValid()) { + return source; + } final TextBlock message = getMessageLiberapay(); TextBlock result = TextBlockUtils.mergeTB(message, source, HorizontalAlignment.LEFT); result = TextBlockUtils.mergeTB(result, message, HorizontalAlignment.LEFT); @@ -188,6 +281,9 @@ public class PSystemError extends AbstractPSystem { } private TextBlock addMessagePatreon(final TextBlock source) throws IOException { + if (LicenseInfo.retrieveNamedOrDistributorQuickIsValid()) { + return source; + } final TextBlock message = getMessagePatreon(); TextBlock result = TextBlockUtils.mergeTB(message, source, HorizontalAlignment.LEFT); result = TextBlockUtils.mergeTB(result, message, HorizontalAlignment.LEFT); @@ -195,12 +291,18 @@ public class PSystemError extends AbstractPSystem { } private TextBlock addMessageDedication(final TextBlock source) throws IOException { + if (LicenseInfo.retrieveNamedOrDistributorQuickIsValid()) { + return source; + } final TextBlock message = getMessageDedication(); TextBlock result = TextBlockUtils.mergeTB(message, source, HorizontalAlignment.LEFT); return result; } private TextBlock addMessageAdopt(final TextBlock source) throws IOException { + if (LicenseInfo.retrieveNamedOrDistributorQuickIsValid()) { + return source; + } final TextBlock message = getMessageAdopt(); TextBlock result = TextBlockUtils.mergeTB(message, source, HorizontalAlignment.LEFT); return result; @@ -341,6 +443,10 @@ public class PSystemError extends AbstractPSystem { } + public int size() { + return trace.size(); + } + private BufferedImage smaller(BufferedImage im) { if (im == null) { return null; @@ -349,241 +455,4 @@ public class PSystemError extends AbstractPSystem { return im.getSubimage(nb, nb, im.getWidth() - 2 * nb, im.getHeight() - 2 * nb); } - private List getTextStrings() { - final List result = new ArrayList(getStack()); - if (result.size() > 0) { - result.add(" "); - } - - for (String s : getPartialCode()) { - result.add(s); - } - final String errorLine = getSource().getLine(higherErrorPosition); - final String err = StringUtils.hideComparatorCharacters(errorLine); - if (StringUtils.isNotEmpty(err)) { - result.add(err); - } - final StringBuilder underscore = new StringBuilder(); - for (int i = 0; i < errorLine.length(); i++) { - underscore.append("^"); - } - result.add(underscore.toString()); - final Collection textErrors = new LinkedHashSet(); - for (ErrorUml er : printedErrors) { - textErrors.add(er.getError()); - } - for (String er : textErrors) { - result.add(" " + er); - } - boolean first = true; - for (String s : getSuggest()) { - if (first) { - result.add(" " + s); - } else { - result.add(s); - } - first = false; - } - result.addAll(this.debugLines); - - return result; - } - - private List getStack() { - LineLocation lineLocation = getLineLocation(); - final List result = new ArrayList(); - if (lineLocation != null) { - append(result, lineLocation); - while (lineLocation.getParent() != null) { - lineLocation = lineLocation.getParent(); - append(result, lineLocation); - } - } - return result; - } - - public LineLocation getLineLocation() { - for (ErrorUml err : printedErrors) { - if (err.getLineLocation() != null) { - return err.getLineLocation(); - } - } - return null; - } - - private void append(List result, LineLocation lineLocation) { - if (lineLocation.getDescription() != null) { - result.add("[From " + lineLocation.getDescription() + " (line " + (lineLocation.getPosition() + 1) + ") ]"); - } - } - - private List getPartialCode() { - List result = new ArrayList(); - for (Iterator it = getSource().iterator2(); it.hasNext();) { - final StringLocated s = it.next(); - final String tmp = s.getString(); - result.add(tmp); - final LineLocation location = s.getLocation(); - if (location.getDescription().equals(higherErrorPosition.getDescription()) - && location.compareTo(higherErrorPosition) >= 0) { - break; - } - } - final int limit = 5; - if (result.size() > limit) { - final int skip = result.size() - limit + 1; - final String skipMessage; - if (skip == 1) { - skipMessage = "... (skipping 1 line) ..."; - } else { - skipMessage = "... (skipping " + skip + " lines) ..."; - } - result = new ArrayList(result.subList(skip, result.size())); - result.add(0, skipMessage); - } - return result; - - } - - private List getHtmlStrings(boolean useRed) { - final List htmlStrings = new ArrayList(getStack()); - if (htmlStrings.size() > 0) { - htmlStrings.add("----"); - } - - final List partialCode = getPartialCode(); - for (String s : partialCode) { - htmlStrings.add(StringUtils.hideComparatorCharacters(s)); - } - if (partialCode.size() > 0) { - final int idx = htmlStrings.size() - 1; - final String last = htmlStrings.get(idx); - htmlStrings.set(idx, "" + last + ""); - } - - final Collection textErrors = new LinkedHashSet(); - for (ErrorUml er : printedErrors) { - textErrors.add(er.getError()); - } - for (String er : textErrors) { - htmlStrings.add(" " + er + ""); - } - boolean first = true; - for (String s : getSuggest()) { - if (first) { - htmlStrings.add(" " + s + ""); - } else { - htmlStrings.add("" + StringUtils.hideComparatorCharacters(s) - + ""); - } - first = false; - } - htmlStrings.addAll(this.debugLines); - - return htmlStrings; - } - - private List getSuggest() { - boolean suggested = false; - for (ErrorUml er : printedErrors) { - if (er.hasSuggest()) { - suggested = true; - } - } - if (suggested == false) { - return Collections.emptyList(); - } - final List result = new ArrayList(); - result.add("Did you mean:"); - for (ErrorUml er : printedErrors) { - if (er.hasSuggest()) { - result.add(er.getSuggest().getSuggestedLine()); - } - } - return Collections.unmodifiableList(result); - - } - - private Collection getErrors(ErrorUmlType type, List all) { - final Collection result = new LinkedHashSet(); - for (ErrorUml error : all) { - if (error.getType() == type) { - result.add(error); - } - } - return result; - } - - private LineLocation getHigherErrorPosition2(ErrorUmlType type, List all) { - LineLocation max = null; - for (ErrorUml error : getErrors(type, all)) { - if (max == null || error.getLineLocation().compareTo(max) > 0) { - max = error.getLineLocation(); - } - } - return max; - } - - private List getErrorsAt2(LineLocation position, ErrorUmlType type, List all) { - final List result = new ArrayList(); - for (ErrorUml error : getErrors(type, all)) { - if (error.getLineLocation().compareTo(position) == 0 && StringUtils.isNotEmpty(error.getError())) { - result.add(error); - } - } - return result; - } - - public DiagramDescription getDescription() { - return new DiagramDescription("(Error)"); - } - - public final LineLocation getHigherErrorPosition2() { - return higherErrorPosition; - } - - public final Collection getErrorsUml() { - return Collections.unmodifiableCollection(printedErrors); - } - - @Override - public String getWarningOrError() { - final StringBuilder sb = new StringBuilder(); - sb.append(getDescription()); - sb.append(BackSlash.CHAR_NEWLINE); - for (CharSequence t : getTitle().getDisplay()) { - sb.append(t); - sb.append(BackSlash.CHAR_NEWLINE); - } - sb.append(BackSlash.CHAR_NEWLINE); - for (String s : getSuggest()) { - sb.append(s); - sb.append(BackSlash.CHAR_NEWLINE); - } - return sb.toString(); - } - - public static PSystemError merge(Collection ps) { - UmlSource source = null; - final List errors = new ArrayList(); - final List debugs = new ArrayList(); - for (PSystemError system : ps) { - if (system == null) { - continue; - } - if (system.getSource() != null && source == null) { - source = system.getSource(); - } - errors.addAll(system.getErrorsUml()); - debugs.addAll(system.debugLines); - if (system.debugLines.size() > 0) { - debugs.add("-"); - } - } - if (source == null) { - throw new IllegalStateException(); - } - return new PSystemError(source, errors, debugs); - } - } diff --git a/src/net/sourceforge/plantuml/error/PSystemErrorPreprocessor.java b/src/net/sourceforge/plantuml/error/PSystemErrorPreprocessor.java new file mode 100644 index 000000000..bd2696ab1 --- /dev/null +++ b/src/net/sourceforge/plantuml/error/PSystemErrorPreprocessor.java @@ -0,0 +1,59 @@ +/* ======================================================================== + * 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.error; + +import java.util.List; + +import net.sourceforge.plantuml.ErrorUml; +import net.sourceforge.plantuml.ErrorUmlType; +import net.sourceforge.plantuml.StringLocated; +import net.sourceforge.plantuml.core.DiagramType; +import net.sourceforge.plantuml.core.UmlSource; + +public class PSystemErrorPreprocessor extends PSystemError { + + public PSystemErrorPreprocessor(List input, List trace) { + final DiagramType type = DiagramType.getTypeFromArobaseStart(input.get(0).getString()); + this.setSource(new UmlSource(input, type == DiagramType.UML)); + this.trace = trace; + this.singleError = new ErrorUml(ErrorUmlType.SYNTAX_ERROR, getLastLine().getPreprocessorError(), getLastLine() + .getLocation()); + + } + + + + +} diff --git a/src/net/sourceforge/plantuml/error/PSystemErrorUtils.java b/src/net/sourceforge/plantuml/error/PSystemErrorUtils.java new file mode 100644 index 000000000..d68f56f8e --- /dev/null +++ b/src/net/sourceforge/plantuml/error/PSystemErrorUtils.java @@ -0,0 +1,106 @@ +/* ======================================================================== + * 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.error; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import net.sourceforge.plantuml.ErrorUml; +import net.sourceforge.plantuml.StringLocated; +import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.core.UmlSource; + +public class PSystemErrorUtils { + + // public static AbstractPSystemError buildV1(UmlSource source, ErrorUml singleError, List debugLines) { + // return new PSystemErrorV1(source, singleError, debugLines); + // } + + public static PSystemError buildV2(UmlSource source, ErrorUml singleError, List debugLines, + List list) { + // return new PSystemErrorV1(source, singleError, debugLines); + return new PSystemErrorV2(source, list, singleError); + } + + public static PSystemError merge(Collection ps) { + UmlSource source = null; + final List errors = new ArrayList(); + // final List debugs = new ArrayList(); + final List errorsV2 = new ArrayList(); + for (PSystemError system : ps) { + if (system == null) { + continue; + } + if (system.getSource() != null && source == null) { + source = system.getSource(); + } + errors.addAll(system.getErrorsUml()); + // if (system instanceof PSystemErrorV1) { + // debugs.addAll(((PSystemErrorV1) system).debugLines); + // if (((PSystemErrorV1) system).debugLines.size() > 0) { + // debugs.add("-"); + // } + // } + if (system instanceof PSystemErrorV2) { + errorsV2.add((PSystemErrorV2) system); + } + } + if (source == null) { + throw new IllegalStateException(); + } + if (errorsV2.size() > 0) { + return mergeV2(errorsV2); + } + throw new IllegalStateException(); + // return new PSystemErrorV1(source, errors, debugs); + } + + private static PSystemErrorV2 mergeV2(List errorsV2) { + PSystemErrorV2 result = null; + for (PSystemErrorV2 err : errorsV2) { + if (result == null || result.size() < err.size()) { + result = err; + } + } + return result; + } + + public static boolean isDiagramError(Class type) { + return PSystemError.class.isAssignableFrom(type); + // return type == PSystemErrorV1.class; + } + +} diff --git a/src/net/sourceforge/plantuml/suggest/SuggestEngineStatus.java b/src/net/sourceforge/plantuml/error/PSystemErrorV2.java similarity index 74% rename from src/net/sourceforge/plantuml/suggest/SuggestEngineStatus.java rename to src/net/sourceforge/plantuml/error/PSystemErrorV2.java index afef8ac83..6c3108d68 100644 --- a/src/net/sourceforge/plantuml/suggest/SuggestEngineStatus.java +++ b/src/net/sourceforge/plantuml/error/PSystemErrorV2.java @@ -31,11 +31,22 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.error; -public enum SuggestEngineStatus { - SYNTAX_OK, CANNOT_CORRECT, ONE_SUGGESTION +import java.util.List; + +import net.sourceforge.plantuml.ErrorUml; +import net.sourceforge.plantuml.StringLocated; +import net.sourceforge.plantuml.core.UmlSource; + +public class PSystemErrorV2 extends PSystemError { + + public PSystemErrorV2(UmlSource source, List trace, ErrorUml singleError) { + this.setSource(source); + this.trace = trace; + this.singleError = singleError; + + } } diff --git a/src/net/sourceforge/plantuml/fun/IconLoader.java b/src/net/sourceforge/plantuml/fun/IconLoader.java index 7e7b35d17..4e3b7b04a 100644 --- a/src/net/sourceforge/plantuml/fun/IconLoader.java +++ b/src/net/sourceforge/plantuml/fun/IconLoader.java @@ -44,12 +44,12 @@ import javax.imageio.ImageIO; public class IconLoader { - private static final int NUMBER_OF_ICONS = 27; + private static final int NUMBER_OF_ICONS = 29; private final static Map all = new ConcurrentHashMap(); public static BufferedImage getRandom() { - // return addTransparent(getIcon("sprite026.png")); + // return addTransparent(getIcon("sprite028.png")); return addTransparent(getIcon(getSomeQuote())); } diff --git a/src/net/sourceforge/plantuml/fun/sprite021.png b/src/net/sourceforge/plantuml/fun/sprite021.png index efc0b8665ae356e82b6194c3931542ea96e8b607..ef4522ed43bd076484d0ac4dde8220f302679ef9 100644 GIT binary patch delta 2010 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 d+`oSIf0!;A*}!a002ovPDHLkV1nLQWTXH9 literal 0 HcmV?d00001 diff --git a/src/net/sourceforge/plantuml/graphic/FontConfiguration.java b/src/net/sourceforge/plantuml/graphic/FontConfiguration.java index 14603f570..a44c03963 100644 --- a/src/net/sourceforge/plantuml/graphic/FontConfiguration.java +++ b/src/net/sourceforge/plantuml/graphic/FontConfiguration.java @@ -222,6 +222,10 @@ public class FontConfiguration { return add(FontStyle.UNDERLINE); } + public FontConfiguration wave(HtmlColor color) { + return add(FontStyle.WAVE).changeExtendedColor(color); + } + public FontConfiguration hyperlink() { if (useUnderlineForHyperlink) { return add(FontStyle.UNDERLINE).withHyperlink(); diff --git a/src/net/sourceforge/plantuml/graphic/GraphicStrings.java b/src/net/sourceforge/plantuml/graphic/GraphicStrings.java index 1c63aac82..cd748b67a 100644 --- a/src/net/sourceforge/plantuml/graphic/GraphicStrings.java +++ b/src/net/sourceforge/plantuml/graphic/GraphicStrings.java @@ -41,6 +41,7 @@ import java.util.List; import net.sourceforge.plantuml.Dimension2DDouble; import net.sourceforge.plantuml.SpriteContainerEmpty; +import net.sourceforge.plantuml.creole.CreoleMode; import net.sourceforge.plantuml.cucadiagram.Display; import net.sourceforge.plantuml.svek.IEntityImage; import net.sourceforge.plantuml.svek.Margins; @@ -58,13 +59,9 @@ public class GraphicStrings extends AbstractTextBlock implements IEntityImage { private final HtmlColor background; - private final UFont font; + private final static HtmlColor hyperlinkColor = HtmlColorUtils.BLUE; - private final HtmlColor maincolor; - - private final HtmlColor hyperlinkColor = HtmlColorUtils.BLUE; - - private final boolean useUnderlineForHyperlink = true; + private final static boolean useUnderlineForHyperlink = true; private final List strings; @@ -72,63 +69,87 @@ public class GraphicStrings extends AbstractTextBlock implements IEntityImage { private final GraphicPosition position; + private final FontConfiguration fontConfiguration; + public static IEntityImage createForError(List strings, boolean useRed) { + return new GraphicStrings(strings, sansSerif14(getForeColor(useRed)).bold(), getBackColor(useRed), null, null, + CreoleMode.NO_CREOLE); + } + + private static HtmlColor getForeColor(boolean useRed) { if (useRed) { - return new GraphicStrings(strings, UFont.sansSerif(14).bold(), HtmlColorUtils.BLACK, - HtmlColorUtils.RED_LIGHT, null, null); + return HtmlColorUtils.BLACK; } - return new GraphicStrings(strings, UFont.sansSerif(14).bold(), HtmlColorSet.getInstance().getColorIfValid( - "#33FF02"), HtmlColorUtils.BLACK, null, null); + return HtmlColorUtils.MY_GREEN; + } + + private static HtmlColor getBackColor(boolean useRed) { + if (useRed) { + return HtmlColorUtils.RED_LIGHT; + } + return HtmlColorUtils.BLACK; } public static TextBlockBackcolored createGreenOnBlackMonospaced(List strings) { - return new GraphicStrings(strings, monospaced14(), HtmlColorUtils.GREEN, HtmlColorUtils.BLACK, null, null); + return new GraphicStrings(strings, monospaced14(HtmlColorUtils.GREEN), HtmlColorUtils.BLACK, null, null, + CreoleMode.SIMPLE_LINE); } public static TextBlockBackcolored createBlackOnWhite(List strings) { - return new GraphicStrings(strings, sansSerif12(), HtmlColorUtils.BLACK, HtmlColorUtils.WHITE, null, null); + return new GraphicStrings(strings, sansSerif12(HtmlColorUtils.BLACK), HtmlColorUtils.WHITE, null, null, + CreoleMode.FULL); } public static TextBlockBackcolored createBlackOnWhiteMonospaced(List strings) { - return new GraphicStrings(strings, monospaced14(), HtmlColorUtils.BLACK, HtmlColorUtils.WHITE, null, null); + return new GraphicStrings(strings, monospaced14(HtmlColorUtils.BLACK), HtmlColorUtils.WHITE, null, null, + CreoleMode.FULL); } public static TextBlockBackcolored createBlackOnWhite(List strings, BufferedImage image, GraphicPosition position) { - return new GraphicStrings(strings, sansSerif12(), HtmlColorUtils.BLACK, HtmlColorUtils.WHITE, image, position); + return new GraphicStrings(strings, sansSerif12(HtmlColorUtils.BLACK), HtmlColorUtils.WHITE, image, position, + CreoleMode.FULL); } - private static UFont sansSerif12() { - return UFont.sansSerif(12); + private static FontConfiguration sansSerif12(HtmlColor color) { + return new FontConfiguration(UFont.sansSerif(12), color, hyperlinkColor, useUnderlineForHyperlink); } - private static UFont monospaced14() { - return UFont.monospaced(14); + public static FontConfiguration sansSerif14(HtmlColor color) { + return new FontConfiguration(UFont.sansSerif(14), color, hyperlinkColor, useUnderlineForHyperlink); } - private GraphicStrings(List strings, UFont font, HtmlColor maincolor, HtmlColor background, - BufferedImage image, GraphicPosition position) { + private static FontConfiguration monospaced14(HtmlColor color) { + return new FontConfiguration(UFont.monospaced(14), color, hyperlinkColor, useUnderlineForHyperlink); + } + + private final CreoleMode mode; + + private GraphicStrings(List strings, FontConfiguration fontConfiguration, HtmlColor background, + BufferedImage image, GraphicPosition position, CreoleMode mode) { this.strings = strings; - this.font = font; - this.maincolor = maincolor; this.background = background; this.image = image; this.position = position; + this.mode = mode; + this.fontConfiguration = fontConfiguration; + } private TextBlock getTextBlock() { - TextBlock result = null; - result = Display.create(strings).create( - new FontConfiguration(font, maincolor, hyperlinkColor, useUnderlineForHyperlink), - HorizontalAlignment.LEFT, new SpriteContainerEmpty()); - // result = DateEventUtils.addEvent(result, green); - return result; + final Display display = Display.create(strings); + if (mode == CreoleMode.NO_CREOLE) { + return new TextBlockRaw(strings, fontConfiguration); + + } else { + return display.create(fontConfiguration, HorizontalAlignment.LEFT, new SpriteContainerEmpty(), mode); + } } public void drawU(UGraphic ug) { ug = ug.apply(new UTranslate(margin, margin)); final Dimension2D size = calculateDimensionInternal(ug.getStringBounder()); - getTextBlock().drawU(ug.apply(new UChangeColor(maincolor))); + getTextBlock().drawU(ug.apply(new UChangeColor(fontConfiguration.getColor()))); if (image != null) { if (position == GraphicPosition.BOTTOM) { @@ -176,10 +197,9 @@ public class GraphicStrings extends AbstractTextBlock implements IEntityImage { public boolean isHidden() { return false; } - + public double getOverscanX(StringBounder stringBounder) { return 0; } - } diff --git a/src/net/sourceforge/plantuml/graphic/HtmlColorUtils.java b/src/net/sourceforge/plantuml/graphic/HtmlColorUtils.java index 43ace0083..02c568845 100644 --- a/src/net/sourceforge/plantuml/graphic/HtmlColorUtils.java +++ b/src/net/sourceforge/plantuml/graphic/HtmlColorUtils.java @@ -48,6 +48,7 @@ public class HtmlColorUtils { public static final HtmlColor LIGHT_GRAY; public static final HtmlColor MY_YELLOW; public static final HtmlColor MY_RED; + public static final HtmlColor MY_GREEN; public static final HtmlColor COL_C82930; public static final HtmlColor COL_F24D5C; @@ -86,6 +87,7 @@ public class HtmlColorUtils { LIGHT_GRAY = set.getColorIfValid("#C0C0C0"); MY_YELLOW = set.getColorIfValid("#FEFECE"); MY_RED = set.getColorIfValid("#A80036"); + MY_GREEN = set.getColorIfValid("#33FF02"); COL_C82930 = set.getColorIfValid("#C82930"); COL_F24D5C = set.getColorIfValid("#F24D5C"); diff --git a/src/net/sourceforge/plantuml/graphic/QuoteUtils.java b/src/net/sourceforge/plantuml/graphic/QuoteUtils.java index ec8fec644..8aa6c9960 100644 --- a/src/net/sourceforge/plantuml/graphic/QuoteUtils.java +++ b/src/net/sourceforge/plantuml/graphic/QuoteUtils.java @@ -304,7 +304,16 @@ public class QuoteUtils { "Dhnaq ibhf rgrf rzorgrf, rzoebhvyyrm gbhg", "Gurer nva'g ab phevat jung'f jebat jvgu gung guvat", "Vs lbh cevpx hf, qb jr abg oyrrq?", "V qvq lbhe wbo bapr - V jnf tbbq ng vg.", "Vyf cbheenvrag snver har fryrpgvba nh fgnaqneq...", "Gung'f ab jnl gb gerng n sevraq.", - "Ubjrire ornhgvshy gur fgengrtl, lbh fubhyq bppnfvbanyyl ybbx ng gur erfhygf"); + "Ubjrire ornhgvshy gur fgengrtl, lbh fubhyq bppnfvbanyyl ybbx ng gur erfhygf", + "Qba'g svk vg vs vg'f abg oebxra", + "Fhqqrayl V'z gnxvat fhttrfgvbaf sebz fbzr fgebat-nez zna jvgu na VD bs zvahf 50.", + "Fur ehvaf rirelguvat fur'f va. Fur ehvaf guvatf fur'f abg rira va.", + "Byvir, V guvax lbh fubhyq xabj guvf: lbh'er n ubeevoyr npgerff.", + "Lbh'er yngr! Qb lbh unir ab pbaprcg bs gvzr ?", + "P'zba zna, yrg'f qb fbzrguvat gung ernyyl pbbxf.", + "Nh sbaq, znvagranag, yrf qvcybzngrf ceraqenvrag cyhgbg yr cnf fhe yrf ubzzrf q'npgvba.", + "Whfg zragnyyl gubhtu... ner lbh bxnl ?", "Jr xabj fur'f bxnl orpnhfr fur'f oybaq", + "Gh oyhssrf Znegbav"); private QuoteUtils() { } diff --git a/src/net/sourceforge/plantuml/graphic/SingleLine.java b/src/net/sourceforge/plantuml/graphic/SingleLine.java index 60a2ea3cd..3c8400a0b 100644 --- a/src/net/sourceforge/plantuml/graphic/SingleLine.java +++ b/src/net/sourceforge/plantuml/graphic/SingleLine.java @@ -51,7 +51,24 @@ class SingleLine extends AbstractTextBlock implements Line { private final List blocs = new ArrayList(); private final HorizontalAlignment horizontalAlignment; - public SingleLine(String text, FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, + public static SingleLine withSomeHtmlTag(String text, FontConfiguration fontConfiguration, + HorizontalAlignment horizontalAlignment, SpriteContainer spriteContainer) { + return new SingleLine(text, fontConfiguration, horizontalAlignment, spriteContainer); + } + + public static SingleLine rawText(String text, FontConfiguration fontConfiguration) { + return new SingleLine(text, fontConfiguration); + } + + private SingleLine(String text, FontConfiguration fontConfiguration) { + if (text.length() == 0) { + text = " "; + } + this.horizontalAlignment = HorizontalAlignment.LEFT; + this.blocs.add(new TileText(text, fontConfiguration, null)); + } + + private SingleLine(String text, FontConfiguration fontConfiguration, HorizontalAlignment horizontalAlignment, SpriteContainer spriteContainer) { if (text.length() == 0) { text = " "; @@ -139,4 +156,5 @@ class SingleLine extends AbstractTextBlock implements Line { public HorizontalAlignment getHorizontalAlignment() { return horizontalAlignment; } + } diff --git a/src/net/sourceforge/plantuml/graphic/SkinParameter.java b/src/net/sourceforge/plantuml/graphic/SkinParameter.java index d27491d01..7667d43d7 100644 --- a/src/net/sourceforge/plantuml/graphic/SkinParameter.java +++ b/src/net/sourceforge/plantuml/graphic/SkinParameter.java @@ -97,6 +97,10 @@ public class SkinParameter { ColorParam.rectangleBorder, FontParam.RECTANGLE, FontParam.RECTANGLE_STEREOTYPE, LineParam.rectangleBorder, CornerParam.rectangle); + public static final SkinParameter ARCHIMATE = new SkinParameter("ARCHIMATE", ColorParam.archimateBackground, + ColorParam.archimateBorder, FontParam.ARCHIMATE, FontParam.ARCHIMATE_STEREOTYPE, LineParam.archimateBorder, + CornerParam.archimate); + public static final SkinParameter COLLECTIONS = new SkinParameter("COLLECTIONS", ColorParam.collectionsBackground, ColorParam.collectionsBorder, FontParam.RECTANGLE, FontParam.RECTANGLE_STEREOTYPE); diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockRaw.java b/src/net/sourceforge/plantuml/graphic/TextBlockRaw.java new file mode 100644 index 000000000..af94867cf --- /dev/null +++ b/src/net/sourceforge/plantuml/graphic/TextBlockRaw.java @@ -0,0 +1,95 @@ +/* ======================================================================== + * 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.graphic; + +import java.awt.geom.Dimension2D; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.plantuml.Dimension2DDouble; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UTranslate; + +public class TextBlockRaw extends AbstractTextBlock implements TextBlock { + + private List lines2; + + private final List strings; + private final FontConfiguration fontConfiguration; + + public TextBlockRaw(List strings, FontConfiguration fontConfiguration) { + this.strings = strings; + this.fontConfiguration = fontConfiguration; + } + + private List getLines(StringBounder stringBounder) { + if (lines2 == null) { + if (stringBounder == null) { + throw new IllegalStateException(); + } + this.lines2 = new ArrayList(); + for (String s : strings) { + lines2.add(SingleLine.rawText(s, fontConfiguration)); + } + } + return lines2; + } + + public Dimension2D calculateDimension(StringBounder stringBounder) { + return getTextDimension(stringBounder); + } + + protected final Dimension2D getTextDimension(StringBounder stringBounder) { + double width = 0; + double height = 0; + for (Line line : getLines(stringBounder)) { + final Dimension2D size2D = line.calculateDimension(stringBounder); + height += size2D.getHeight(); + width = Math.max(width, size2D.getWidth()); + } + return new Dimension2DDouble(width, height); + } + + public void drawU(UGraphic ug) { + double y = 0; + + for (Line line : getLines(ug.getStringBounder())) { + line.drawU(ug.apply(new UTranslate(0, y))); + y += line.calculateDimension(ug.getStringBounder()).getHeight(); + } + } + +} diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockSimple.java b/src/net/sourceforge/plantuml/graphic/TextBlockSimple.java index 16e2d4c1e..abf993350 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockSimple.java +++ b/src/net/sourceforge/plantuml/graphic/TextBlockSimple.java @@ -145,15 +145,15 @@ public class TextBlockSimple extends AbstractTextBlock implements TextBlock { if (s.length() == 0 || MyPattern.mtches(s, "^[%s]*$ ")) { return; } - lines2.add(new SingleLine(s, fontConfiguration, horizontalAlignment, spriteContainer)); + lines2.add(SingleLine.withSomeHtmlTag(s, fontConfiguration, horizontalAlignment, spriteContainer)); } private void addSingleLine(String s) { - lines2.add(new SingleLine(s, fontConfiguration, horizontalAlignment, spriteContainer)); + lines2.add(SingleLine.withSomeHtmlTag(s, fontConfiguration, horizontalAlignment, spriteContainer)); } private double getTextWidth(StringBounder stringBounder, String s) { - final Line line = new SingleLine(s, fontConfiguration, horizontalAlignment, spriteContainer); + final Line line = SingleLine.withSomeHtmlTag(s, fontConfiguration, horizontalAlignment, spriteContainer); return line.calculateDimension(stringBounder).getWidth(); } @@ -162,7 +162,7 @@ public class TextBlockSimple extends AbstractTextBlock implements TextBlock { assert s.getLabel(Guillemet.DOUBLE_COMPARATOR) != null; final List result = new ArrayList(); for (String st : s.getLabels(spriteContainer.guillemet())) { - result.add(new SingleLine(st, fontConfiguration, horizontalAlignment, spriteContainer)); + result.add(SingleLine.withSomeHtmlTag(st, fontConfiguration, horizontalAlignment, spriteContainer)); } return Collections.unmodifiableList(result); } diff --git a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java index 2c3156914..b05ae4bd5 100644 --- a/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java +++ b/src/net/sourceforge/plantuml/graphic/TextBlockUtils.java @@ -124,6 +124,11 @@ public class TextBlockUtils { return new TextBlockVertical2(b1, b2, horizontalAlignment); } + // public static TextBlockBackcolored mergeColoredTB(TextBlockBackcolored b1, TextBlockBackcolored b2, + // HorizontalAlignment horizontalAlignment) { + // return addBackcolor(mergeTB(b1, b2, horizontalAlignment), b1.getBackcolor()); + // } + public static MinMax getMinMax(TextBlock tb, StringBounder stringBounder) { final LimitFinder limitFinder = new LimitFinder(stringBounder, false); tb.drawU(limitFinder); diff --git a/src/net/sourceforge/plantuml/graphic/USymbol.java b/src/net/sourceforge/plantuml/graphic/USymbol.java index 60daad2a3..a82290830 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbol.java +++ b/src/net/sourceforge/plantuml/graphic/USymbol.java @@ -58,14 +58,16 @@ public abstract class USymbol { public final static USymbol ARTIFACT = record("ARTIFACT", SkinParameter.ARTIFACT, new USymbolArtifact()); public final static USymbol PACKAGE = record("PACKAGE", SkinParameter.PACKAGE, new USymbolFolder( SkinParameter.PACKAGE, true)); - public final static USymbol FOLDER = record("FOLDER", SkinParameter.FOLDER, new USymbolFolder(SkinParameter.FOLDER, false)); + public final static USymbol FOLDER = record("FOLDER", SkinParameter.FOLDER, new USymbolFolder(SkinParameter.FOLDER, + false)); public final static USymbol FILE = record("FILE", SkinParameter.FILE, new USymbolFile()); public final static USymbol RECTANGLE = record("RECTANGLE", SkinParameter.RECTANGLE, new USymbolRect( - SkinParameter.RECTANGLE, HorizontalAlignment.CENTER)); + SkinParameter.RECTANGLE)); + public final static USymbol ARCHIMATE = record("ARCHIMATE", SkinParameter.ARCHIMATE, new USymbolRect( + SkinParameter.ARCHIMATE)); public final static USymbol COLLECTIONS = record("COLLECTIONS", SkinParameter.COLLECTIONS, new USymbolCollections( - SkinParameter.RECTANGLE, HorizontalAlignment.CENTER)); - public final static USymbol AGENT = record("AGENT", SkinParameter.AGENT, new USymbolRect(SkinParameter.AGENT, - HorizontalAlignment.CENTER)); + SkinParameter.RECTANGLE)); + public final static USymbol AGENT = record("AGENT", SkinParameter.AGENT, new USymbolRect(SkinParameter.AGENT)); public final static USymbol ACTOR = record("ACTOR", SkinParameter.ACTOR, new USymbolActor()); public final static USymbol USECASE = null; public final static USymbol COMPONENT1 = record("COMPONENT1", SkinParameter.COMPONENT1, new USymbolComponent1()); @@ -81,9 +83,9 @@ public abstract class USymbol { abstract public SkinParameter getSkinParameter(); - public USymbol withStereoAlignment(HorizontalAlignment alignment) { - return this; - } + // public USymbol withStereoAlignment(HorizontalAlignment alignment) { + // return this; + // } public FontParam getFontParam() { return getSkinParameter().getFontParam(); @@ -124,10 +126,11 @@ public abstract class USymbol { return symbol; } - public abstract TextBlock asSmall(TextBlock name, TextBlock label, TextBlock stereotype, SymbolContext symbolContext); + public abstract TextBlock asSmall(TextBlock name, TextBlock label, TextBlock stereotype, + SymbolContext symbolContext, HorizontalAlignment stereoAlignment); public abstract TextBlock asBig(TextBlock label, HorizontalAlignment labelAlignment, TextBlock stereotype, - double width, double height, SymbolContext symbolContext); + double width, double height, SymbolContext symbolContext, HorizontalAlignment stereoAlignment); static class Margin { private final double x1; diff --git a/src/net/sourceforge/plantuml/graphic/USymbolArtifact.java b/src/net/sourceforge/plantuml/graphic/USymbolArtifact.java index 5e40fd132..740a23256 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolArtifact.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolArtifact.java @@ -95,7 +95,7 @@ class USymbolArtifact extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -119,7 +119,7 @@ class USymbolArtifact extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolCard.java b/src/net/sourceforge/plantuml/graphic/USymbolCard.java index d701b1237..660baa97d 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolCard.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolCard.java @@ -73,7 +73,7 @@ class USymbolCard extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -96,7 +96,7 @@ class USymbolCard extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolCloud.java b/src/net/sourceforge/plantuml/graphic/USymbolCloud.java index 670e49794..62396fcf5 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolCloud.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolCloud.java @@ -216,7 +216,7 @@ class USymbolCloud extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -239,7 +239,7 @@ class USymbolCloud extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolCollections.java b/src/net/sourceforge/plantuml/graphic/USymbolCollections.java index 04ca4a540..107b12cb9 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolCollections.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolCollections.java @@ -47,17 +47,17 @@ import net.sourceforge.plantuml.ugraphic.UTranslate; class USymbolCollections extends USymbol { private final SkinParameter skinParameter; - private final HorizontalAlignment stereotypeAlignement; + // private final HorizontalAlignment stereotypeAlignement; - public USymbolCollections(SkinParameter skinParameter, HorizontalAlignment stereotypeAlignement) { + public USymbolCollections(SkinParameter skinParameter) { this.skinParameter = skinParameter; - this.stereotypeAlignement = stereotypeAlignement; + // this.stereotypeAlignement = stereotypeAlignement; } - @Override - public USymbol withStereoAlignment(HorizontalAlignment alignment) { - return new USymbolCollections(skinParameter, alignment); - } +// @Override +// public USymbol withStereoAlignment(HorizontalAlignment alignment) { +// return new USymbolCollections(skinParameter, alignment); +// } @Override public SkinParameter getSkinParameter() { @@ -85,7 +85,7 @@ class USymbolCollections extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -95,7 +95,7 @@ class USymbolCollections extends USymbol { drawCollections(ug, dim.getWidth(), dim.getHeight(), symbolContext.isShadowing(), symbolContext.getRoundCorner()); final Margin margin = getMargin(); - final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereotypeAlignement); + final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereoAlignment); tb.drawU(ug.apply(new UTranslate(margin.getX1() - getDeltaCollection() / 2, margin.getY1() - getDeltaCollection() / 2))); } @@ -110,7 +110,7 @@ class USymbolCollections extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { final Dimension2D dim = calculateDimension(ug.getStringBounder()); @@ -120,7 +120,7 @@ class USymbolCollections extends USymbol { final Dimension2D dimStereo = stereotype.calculateDimension(ug.getStringBounder()); final double posStereoX; final double posStereoY; - if (stereotypeAlignement == HorizontalAlignment.RIGHT) { + if (stereoAlignment == HorizontalAlignment.RIGHT) { posStereoX = width - dimStereo.getWidth() - getMargin().getX1() / 2; posStereoY = getMargin().getY1() / 2; } else { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolComponent1.java b/src/net/sourceforge/plantuml/graphic/USymbolComponent1.java index 3860988a4..ff769dd5b 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolComponent1.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolComponent1.java @@ -75,7 +75,7 @@ class USymbolComponent1 extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -100,7 +100,7 @@ class USymbolComponent1 extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { throw new UnsupportedOperationException(); } diff --git a/src/net/sourceforge/plantuml/graphic/USymbolComponent2.java b/src/net/sourceforge/plantuml/graphic/USymbolComponent2.java index d4fdf1db6..f38dced23 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolComponent2.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolComponent2.java @@ -78,7 +78,7 @@ class USymbolComponent2 extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -104,7 +104,7 @@ class USymbolComponent2 extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolDatabase.java b/src/net/sourceforge/plantuml/graphic/USymbolDatabase.java index 812bcc744..1a8b8a601 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolDatabase.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolDatabase.java @@ -114,7 +114,7 @@ class USymbolDatabase extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -137,7 +137,7 @@ class USymbolDatabase extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolFile.java b/src/net/sourceforge/plantuml/graphic/USymbolFile.java index e7980359d..42db16d0b 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolFile.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolFile.java @@ -105,7 +105,7 @@ class USymbolFile extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -129,7 +129,7 @@ class USymbolFile extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolFolder.java b/src/net/sourceforge/plantuml/graphic/USymbolFolder.java index b20be9f03..ca55ebe8d 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolFolder.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolFolder.java @@ -134,7 +134,7 @@ public class USymbolFolder extends USymbol { @Override public TextBlock asSmall(final TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { if (name == null) { throw new IllegalArgumentException(); } @@ -167,7 +167,7 @@ public class USymbolFolder extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolFrame.java b/src/net/sourceforge/plantuml/graphic/USymbolFrame.java index 71142b8d7..adb26d7e2 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolFrame.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolFrame.java @@ -98,7 +98,7 @@ class USymbolFrame extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -122,7 +122,7 @@ class USymbolFrame extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolNode.java b/src/net/sourceforge/plantuml/graphic/USymbolNode.java index b03d606dd..ac04800e0 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolNode.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolNode.java @@ -48,11 +48,22 @@ import net.sourceforge.plantuml.ugraphic.UTranslate; class USymbolNode extends USymbol { + // private final HorizontalAlignment stereotypeAlignement; + @Override public SkinParameter getSkinParameter() { return SkinParameter.NODE; } +// public USymbolNode(HorizontalAlignment stereotypeAlignement) { +// this.stereotypeAlignement = stereotypeAlignement; +// } +// +// @Override +// public USymbol withStereoAlignment(HorizontalAlignment alignment) { +// return new USymbolNode(alignment); +// } + private void drawNode(UGraphic ug, double width, double height, boolean shadowing) { final UPolygon shape = new UPolygon(); shape.addPoint(0, 10); @@ -111,7 +122,7 @@ class USymbolNode extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -119,7 +130,7 @@ class USymbolNode extends USymbol { ug = symbolContext.apply(ug); drawNode(ug, dim.getWidth(), dim.getHeight(), symbolContext.isShadowing()); final Margin margin = getMargin(); - final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, HorizontalAlignment.CENTER); + final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereoAlignment); final UGraphic ug2 = new MyUGraphicNode(ug, dim.getWidth()); tb.drawU(ug2.apply(new UTranslate(margin.getX1(), margin.getY1()))); } @@ -134,7 +145,7 @@ class USymbolNode extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -144,8 +155,15 @@ class USymbolNode extends USymbol { ug = ug.apply(new UTranslate(-4, 11)); final Dimension2D dimStereo = stereotype.calculateDimension(ug.getStringBounder()); - final double posStereo = (width - dimStereo.getWidth()) / 2; - stereotype.drawU(ug.apply(new UTranslate(posStereo, 2))); + final double posStereoX; + final double posStereoY = 2; + if (stereoAlignment == HorizontalAlignment.RIGHT) { + posStereoX = width - dimStereo.getWidth() - getMargin().getX1(); + } else { + posStereoX = (width - dimStereo.getWidth()) / 2; + + } + stereotype.drawU(ug.apply(new UTranslate(posStereoX, posStereoY))); final Dimension2D dimTitle = title.calculateDimension(ug.getStringBounder()); final double posTitle = (width - dimTitle.getWidth()) / 2; title.drawU(ug.apply(new UTranslate(posTitle, 2 + dimStereo.getHeight()))); diff --git a/src/net/sourceforge/plantuml/graphic/USymbolQueue.java b/src/net/sourceforge/plantuml/graphic/USymbolQueue.java index 799261720..010e330ef 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolQueue.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolQueue.java @@ -129,7 +129,7 @@ class USymbolQueue extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -153,7 +153,7 @@ class USymbolQueue extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolRect.java b/src/net/sourceforge/plantuml/graphic/USymbolRect.java index e5db9846f..3daae2265 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolRect.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolRect.java @@ -49,17 +49,17 @@ import net.sourceforge.plantuml.ugraphic.UTranslate; class USymbolRect extends USymbol { private final SkinParameter skinParameter; - private final HorizontalAlignment stereotypeAlignement; + // private final HorizontalAlignment stereotypeAlignement; - public USymbolRect(SkinParameter skinParameter, HorizontalAlignment stereotypeAlignement) { + public USymbolRect(SkinParameter skinParameter) { this.skinParameter = skinParameter; - this.stereotypeAlignement = stereotypeAlignement; +// this.stereotypeAlignement = stereotypeAlignement; } - @Override - public USymbol withStereoAlignment(HorizontalAlignment alignment) { - return new USymbolRect(skinParameter, alignment); - } +// @Override +// public USymbol withStereoAlignment(HorizontalAlignment alignment) { +// return new USymbolRect(skinParameter, alignment); +// } @Override public SkinParameter getSkinParameter() { @@ -96,7 +96,7 @@ class USymbolRect extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -106,7 +106,7 @@ class USymbolRect extends USymbol { drawRect(ug, dim.getWidth(), dim.getHeight(), symbolContext.isShadowing(), symbolContext.getRoundCorner(), symbolContext.getDiagonalCorner()); final Margin margin = getMargin(); - final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereotypeAlignement); + final TextBlock tb = TextBlockUtils.mergeTB(stereotype, label, stereoAlignment); tb.drawU(ug.apply(new UTranslate(margin.getX1(), margin.getY1()))); } @@ -120,7 +120,7 @@ class USymbolRect extends USymbol { @Override public TextBlock asBig(final TextBlock title, final HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { final Dimension2D dim = calculateDimension(ug.getStringBounder()); @@ -130,7 +130,7 @@ class USymbolRect extends USymbol { final Dimension2D dimStereo = stereotype.calculateDimension(ug.getStringBounder()); final double posStereoX; final double posStereoY; - if (stereotypeAlignement == HorizontalAlignment.RIGHT) { + if (stereoAlignment == HorizontalAlignment.RIGHT) { posStereoX = width - dimStereo.getWidth() - getMargin().getX1() / 2; posStereoY = getMargin().getY1() / 2; } else { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolSimpleAbstract.java b/src/net/sourceforge/plantuml/graphic/USymbolSimpleAbstract.java index 188569320..8e4162529 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolSimpleAbstract.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolSimpleAbstract.java @@ -45,7 +45,7 @@ abstract class USymbolSimpleAbstract extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { if (stereotype == null) { throw new IllegalArgumentException(); } @@ -83,7 +83,7 @@ abstract class USymbolSimpleAbstract extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { throw new UnsupportedOperationException(); } diff --git a/src/net/sourceforge/plantuml/graphic/USymbolStack.java b/src/net/sourceforge/plantuml/graphic/USymbolStack.java index a672e9c91..a3d500069 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolStack.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolStack.java @@ -91,7 +91,7 @@ class USymbolStack extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -115,7 +115,7 @@ class USymbolStack extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { throw new UnsupportedOperationException(); } diff --git a/src/net/sourceforge/plantuml/graphic/USymbolStorage.java b/src/net/sourceforge/plantuml/graphic/USymbolStorage.java index 39bd27101..05817599b 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolStorage.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolStorage.java @@ -65,7 +65,7 @@ class USymbolStorage extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { @@ -88,7 +88,7 @@ class USymbolStorage extends USymbol { @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/graphic/USymbolTogether.java b/src/net/sourceforge/plantuml/graphic/USymbolTogether.java index 37c5c5897..d7232d532 100644 --- a/src/net/sourceforge/plantuml/graphic/USymbolTogether.java +++ b/src/net/sourceforge/plantuml/graphic/USymbolTogether.java @@ -49,13 +49,13 @@ class USymbolTogether extends USymbol { @Override public TextBlock asSmall(TextBlock name, final TextBlock label, final TextBlock stereotype, - final SymbolContext symbolContext) { + final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return TextBlockUtils.empty(10, 10); } @Override public TextBlock asBig(final TextBlock title, HorizontalAlignment labelAlignment, final TextBlock stereotype, - final double width, final double height, final SymbolContext symbolContext) { + final double width, final double height, final SymbolContext symbolContext, final HorizontalAlignment stereoAlignment) { return new AbstractTextBlock() { public void drawU(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/jungle/GTileNode.java b/src/net/sourceforge/plantuml/jungle/GTileNode.java index c8717dea5..ada8adbe1 100644 --- a/src/net/sourceforge/plantuml/jungle/GTileNode.java +++ b/src/net/sourceforge/plantuml/jungle/GTileNode.java @@ -69,7 +69,7 @@ public class GTileNode extends AbstractTextBlock implements GTile { final SheetBlock1 sheetBlock1 = getTextBlock(display); final SymbolContext symbolContext = new SymbolContext(HtmlColorUtils.MY_YELLOW, HtmlColorUtils.BLACK); - tb = USymbol.RECTANGLE.asSmall(null, sheetBlock1, TextBlockUtils.empty(0, 0), symbolContext); + tb = USymbol.RECTANGLE.asSmall(null, sheetBlock1, TextBlockUtils.empty(0, 0), symbolContext, HorizontalAlignment.CENTER); } public static SheetBlock1 getTextBlock(final Display display) { diff --git a/src/net/sourceforge/plantuml/mindmap/MindMapDiagram.java b/src/net/sourceforge/plantuml/mindmap/MindMapDiagram.java index 232207d6c..0de1f5818 100644 --- a/src/net/sourceforge/plantuml/mindmap/MindMapDiagram.java +++ b/src/net/sourceforge/plantuml/mindmap/MindMapDiagram.java @@ -90,9 +90,8 @@ public class MindMapDiagram extends UmlDiagram { final double dpiFactor = scale == null ? getScaleCoef(fileFormatOption) : scale.getScale(100, 100); final ISkinParam skinParam = getSkinParam(); final ImageBuilder imageBuilder = new ImageBuilder(skinParam.getColorMapper(), dpiFactor, - skinParam.getBackgroundColor(), - fileFormatOption.isWithMetadata() ? getMetadata() : null, - "", 10, 10, null, skinParam.handwritten()); + skinParam.getBackgroundColor(), fileFormatOption.isWithMetadata() ? getMetadata() : null, "", 10, 10, + null, skinParam.handwritten()); TextBlock result = getTextBlock(); result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result); diff --git a/src/net/sourceforge/plantuml/nwdiag/DiagElement.java b/src/net/sourceforge/plantuml/nwdiag/DiagElement.java index 7764aee35..afecba7b5 100644 --- a/src/net/sourceforge/plantuml/nwdiag/DiagElement.java +++ b/src/net/sourceforge/plantuml/nwdiag/DiagElement.java @@ -88,7 +88,7 @@ public class DiagElement { ColorParam.activityBorder.getDefaultValue()).withShadow(true); final TextBlock desc = toTextBlock(description); final TextBlock box = shape - .asSmall(TextBlockUtils.empty(0, 0), desc, TextBlockUtils.empty(0, 0), symbolContext); + .asSmall(TextBlockUtils.empty(0, 0), desc, TextBlockUtils.empty(0, 0), symbolContext, HorizontalAlignment.CENTER); return new LinkedElement(ad1, box, ad2, mainNetwork, this); } diff --git a/src/net/sourceforge/plantuml/preproc/EvalBoolean.java b/src/net/sourceforge/plantuml/preproc/EvalBoolean.java index 624dc4ad5..2f07a018e 100644 --- a/src/net/sourceforge/plantuml/preproc/EvalBoolean.java +++ b/src/net/sourceforge/plantuml/preproc/EvalBoolean.java @@ -116,7 +116,7 @@ public class EvalBoolean { } private boolean isIdentifier() { - return ch == '_' || Character.isLetterOrDigit(ch); + return ch == '_' || ch == '$' || Character.isLetterOrDigit(ch); } public boolean eval() { diff --git a/src/net/sourceforge/plantuml/preproc/FileWithSuffix.java b/src/net/sourceforge/plantuml/preproc/FileWithSuffix.java index 2593452df..b0010f7db 100644 --- a/src/net/sourceforge/plantuml/preproc/FileWithSuffix.java +++ b/src/net/sourceforge/plantuml/preproc/FileWithSuffix.java @@ -193,5 +193,9 @@ public class FileWithSuffix { public final String getSuffix() { return suffix; } + + public String toStringDebug() { + return file.getAbsolutePath(); + } } diff --git a/src/net/sourceforge/plantuml/preproc/Sub2.java b/src/net/sourceforge/plantuml/preproc/Sub2.java new file mode 100644 index 000000000..376d834f1 --- /dev/null +++ b/src/net/sourceforge/plantuml/preproc/Sub2.java @@ -0,0 +1,93 @@ +/* ======================================================================== + * 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.preproc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import net.sourceforge.plantuml.StringLocated; +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.EaterStartsub; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TLineType; +import net.sourceforge.plantuml.tim.TMemory; + +public class Sub2 { + + private final String name; + private final List lines = new ArrayList(); + + public Sub2(String name) { + this.name = name; + } + + public void add(StringLocated s) { + this.lines.add(s); + } + + public final List lines() { + return Collections.unmodifiableList(lines); + } + + public static Sub2 fromFile(ReadLine reader, String blocname, TContext context, TMemory memory) throws IOException, + EaterException { + Sub2 result = null; + StringLocated s = null; + while ((s = reader.readLine()) != null) { + final TLineType type = TLineType.getFromLine(s.getStringTrimmed()); + if (type == TLineType.STARTSUB) { + final EaterStartsub eater = new EaterStartsub(s.getStringTrimmed()); + eater.execute(context, memory); + if (eater.getSubname().equals(blocname)) { + result = new Sub2(blocname); + } + continue; + } + if (type == TLineType.ENDSUB && result != null) { + reader.close(); + return result; + } + if (result != null) { + result.add(s); + } + } + reader.close(); + return null; + } + +} \ No newline at end of file diff --git a/src/net/sourceforge/plantuml/preproc/Truth.java b/src/net/sourceforge/plantuml/preproc/Truth.java index 1b487102d..534df45b0 100644 --- a/src/net/sourceforge/plantuml/preproc/Truth.java +++ b/src/net/sourceforge/plantuml/preproc/Truth.java @@ -35,7 +35,7 @@ */ package net.sourceforge.plantuml.preproc; -interface Truth { +public interface Truth { public boolean isTrue(String name); } diff --git a/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java b/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java index 6403e3968..95cf5cfae 100644 --- a/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java +++ b/src/net/sourceforge/plantuml/preproc/UncommentReadLine.java @@ -48,13 +48,11 @@ public class UncommentReadLine extends ReadLineInstrumented implements ReadLine private static final Pattern2 unpause = MyPattern.cmpile(StartUtils.PAUSE_PATTERN); private final ReadLine raw; - // private final Pattern2 start; private String headerToRemove; private boolean paused; public UncommentReadLine(ReadLine source) { this.raw = source; - // this.start = MyPattern.cmpile(StartUtils.START_PATTERN); } @Override @@ -70,10 +68,6 @@ public class UncommentReadLine extends ReadLineInstrumented implements ReadLine return null; } - // final Matcher m = start.matcher(result); - // if (m.find()) { - // headerToRemove = m.group(1); - // } final String tmp = StartUtils.beforeStartUml(result.getString()); if (tmp != null) { headerToRemove = tmp; diff --git a/src/net/sourceforge/plantuml/preproc2/Preprocessor.java b/src/net/sourceforge/plantuml/preproc2/Preprocessor.java index 72a0be226..329408bcd 100644 --- a/src/net/sourceforge/plantuml/preproc2/Preprocessor.java +++ b/src/net/sourceforge/plantuml/preproc2/Preprocessor.java @@ -72,12 +72,12 @@ public class Preprocessor implements ReadLineNumbered { defines.saveState(); } final ReadFilterAnd filtersV2 = new ReadFilterAnd(); - filtersV2.add(new ReadLineQuoteComment()); - filtersV2.add(new SubPreprocessor(charset, definitionsContainer)); + filtersV2.add(new ReadLineQuoteComment(true)); + filtersV2.add(new ReadLineAddConfig(config)); this.sourceV2 = filtersV2.applyFilter(reader); final ReadFilterAnd filters = new ReadFilterAnd(); - filters.add(new ReadLineQuoteComment()); + filters.add(new ReadLineQuoteComment(false)); include = new PreprocessorInclude(config, charset, defines, definitionsContainer, importedFiles, filesUsedGlobal); filters.add(new ReadLineAddConfig(config)); diff --git a/src/net/sourceforge/plantuml/preproc2/PreprocessorInclude.java b/src/net/sourceforge/plantuml/preproc2/PreprocessorInclude.java index bbd39f306..960401c76 100644 --- a/src/net/sourceforge/plantuml/preproc2/PreprocessorInclude.java +++ b/src/net/sourceforge/plantuml/preproc2/PreprocessorInclude.java @@ -69,6 +69,7 @@ import net.sourceforge.plantuml.preproc.ReadLineSimple; import net.sourceforge.plantuml.preproc.ReadLineSingle; import net.sourceforge.plantuml.preproc.StartDiagramExtractReader; import net.sourceforge.plantuml.preproc.Stdlib; +import net.sourceforge.plantuml.tim.EaterException; import net.sourceforge.plantuml.utils.StartUtils; public class PreprocessorInclude implements ReadFilter { @@ -336,7 +337,7 @@ public class PreprocessorInclude implements ReadFilter { } } - public static ReadLine getReaderIncludeUrl(final URL url, StringLocated s, String suf, String charset) { + private static ReadLine getReaderIncludeUrl(final URL url, StringLocated s, String suf, String charset) { try { if (StartDiagramExtractReader.containsStartDiagram(url, s, charset)) { return StartDiagramExtractReader.build(url, s, suf, charset); @@ -355,6 +356,25 @@ public class PreprocessorInclude implements ReadFilter { } + public static ReadLine getReaderIncludeUrl2(final URL url, StringLocated s, String suf, String charset) throws EaterException { + try { + if (StartDiagramExtractReader.containsStartDiagram(url, s, charset)) { + return StartDiagramExtractReader.build(url, s, suf, charset); + } + final InputStream is = url.openStream(); + if (charset == null) { + Log.info("Using default charset"); + return ReadLineReader.create(new InputStreamReader(is), url.toString(), s.getLocation()); + } + Log.info("Using charset " + charset); + return ReadLineReader.create(new InputStreamReader(is, charset), url.toString(), s.getLocation()); + } catch (IOException e) { + e.printStackTrace(); + throw new EaterException("Cannot open URL"); + } + + } + public Set getFilesUsedGlobal() { return filesUsedGlobal; } diff --git a/src/net/sourceforge/plantuml/preproc2/PreprocessorIncludeStrategy.java b/src/net/sourceforge/plantuml/preproc2/PreprocessorIncludeStrategy.java index 0ea8936ac..45898b49a 100644 --- a/src/net/sourceforge/plantuml/preproc2/PreprocessorIncludeStrategy.java +++ b/src/net/sourceforge/plantuml/preproc2/PreprocessorIncludeStrategy.java @@ -37,7 +37,7 @@ package net.sourceforge.plantuml.preproc2; public enum PreprocessorIncludeStrategy { - ONCE, MANY; + ONCE, MANY, DEFAULT; public static PreprocessorIncludeStrategy fromString(String group) { if ("once".equalsIgnoreCase(group)) { diff --git a/src/net/sourceforge/plantuml/preproc2/PreprocessorModeSet.java b/src/net/sourceforge/plantuml/preproc2/PreprocessorModeSet.java index db40f537a..41b07a954 100644 --- a/src/net/sourceforge/plantuml/preproc2/PreprocessorModeSet.java +++ b/src/net/sourceforge/plantuml/preproc2/PreprocessorModeSet.java @@ -44,6 +44,8 @@ public interface PreprocessorModeSet { public void setPreprocessorMode(PreprocessorMode mode); public ImportedFiles getImportedFiles(); + + public String getCharset(); } diff --git a/src/net/sourceforge/plantuml/preproc2/ReadLineAddConfig.java b/src/net/sourceforge/plantuml/preproc2/ReadLineAddConfig.java index 0b31444f4..41c7b670f 100644 --- a/src/net/sourceforge/plantuml/preproc2/ReadLineAddConfig.java +++ b/src/net/sourceforge/plantuml/preproc2/ReadLineAddConfig.java @@ -74,7 +74,7 @@ public class ReadLineAddConfig implements ReadFilter { } result = raw.readLine(); if (result != null && StartUtils.isArobaseStartDiagram(result.getString()) && config.size() > 0) { - inserted = new ReadLineQuoteComment().applyFilter(new ReadLineList(config, result.getLocation())); + inserted = new ReadLineQuoteComment(false).applyFilter(new ReadLineList(config, result.getLocation())); } return result; } diff --git a/src/net/sourceforge/plantuml/preproc2/ReadLineQuoteComment.java b/src/net/sourceforge/plantuml/preproc2/ReadLineQuoteComment.java index 6587c9ded..c4b7ab5f4 100644 --- a/src/net/sourceforge/plantuml/preproc2/ReadLineQuoteComment.java +++ b/src/net/sourceforge/plantuml/preproc2/ReadLineQuoteComment.java @@ -42,7 +42,17 @@ import net.sourceforge.plantuml.preproc.ReadLine; public class ReadLineQuoteComment implements ReadFilter { + private final boolean ignoreMe; + + public ReadLineQuoteComment(boolean ignoreMe) { + this.ignoreMe = ignoreMe; + } + public ReadLine applyFilter(final ReadLine source) { + if (ignoreMe) { + return source; + } + return new ReadLine() { public void close() throws IOException { diff --git a/src/net/sourceforge/plantuml/preproc2/SubPreprocessor.java b/src/net/sourceforge/plantuml/preproc2/SubPreprocessor.java index c1c375819..2e89353cf 100644 --- a/src/net/sourceforge/plantuml/preproc2/SubPreprocessor.java +++ b/src/net/sourceforge/plantuml/preproc2/SubPreprocessor.java @@ -178,7 +178,7 @@ public class SubPreprocessor implements ReadFilter { } private ReadLine getReaderIncludeWithoutComment(StringLocated s, final File f) { - return new ReadLineQuoteComment().applyFilter(getReaderIncludeRaw(s, f)); + return new ReadLineQuoteComment(false).applyFilter(getReaderIncludeRaw(s, f)); } private ReadLine getReaderIncludeRaw(StringLocated s, final File f) { diff --git a/src/net/sourceforge/plantuml/sequencediagram/command/CommandArrow.java b/src/net/sourceforge/plantuml/sequencediagram/command/CommandArrow.java index 868ff130e..ac3ff26d2 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/command/CommandArrow.java +++ b/src/net/sourceforge/plantuml/sequencediagram/command/CommandArrow.java @@ -209,11 +209,20 @@ public class CommandArrow extends SingleLineCommand2 { if (circleAtStart) { config = config.withDecoration1(ArrowDecoration.CIRCLE); } - if (dressing1.contains("x")) { - config = config.withHead2(ArrowHead.CROSSX); - } - if (dressing2.contains("x")) { - config = config.withHead2(ArrowHead.CROSSX); + if (reverseDefine) { + if (dressing1.contains("x")) { + config = config.withHead2(ArrowHead.CROSSX); + } + if (dressing2.contains("x")) { + config = config.withHead1(ArrowHead.CROSSX); + } + } else { + if (dressing1.contains("x")) { + config = config.withHead1(ArrowHead.CROSSX); + } + if (dressing2.contains("x")) { + config = config.withHead2(ArrowHead.CROSSX); + } } if (reverseDefine) { config = config.reverseDefine(); diff --git a/src/net/sourceforge/plantuml/sequencediagram/teoz/CommunicationTile.java b/src/net/sourceforge/plantuml/sequencediagram/teoz/CommunicationTile.java index 775642f08..ad97dbb9a 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/teoz/CommunicationTile.java +++ b/src/net/sourceforge/plantuml/sequencediagram/teoz/CommunicationTile.java @@ -38,6 +38,7 @@ package net.sourceforge.plantuml.sequencediagram.teoz; import java.awt.geom.Dimension2D; import net.sourceforge.plantuml.ISkinParam; +import net.sourceforge.plantuml.LineParam; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.VerticalAlignment; @@ -52,6 +53,7 @@ import net.sourceforge.plantuml.skin.Context2D; import net.sourceforge.plantuml.skin.rose.AbstractComponentRoseArrow; import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; public class CommunicationTile extends AbstractTile implements TileWithUpdateStairs, TileWithCallbackY { @@ -104,6 +106,15 @@ public class CommunicationTile extends AbstractTile implements TileWithUpdateSta private boolean isCreate() { return message.isCreate(); } + + private double getArrowThickness() { + final UStroke result = skinParam.getThickness(LineParam.sequenceArrow, null); + if (result == null) { + return 1; + } + return result.getThickness(); + } + private ArrowComponent getComponent(StringBounder stringBounder) { ArrowConfiguration arrowConfiguration = message.getArrowConfiguration(); @@ -113,9 +124,10 @@ public class CommunicationTile extends AbstractTile implements TileWithUpdateSta if (isReverse(stringBounder)) { arrowConfiguration = arrowConfiguration.reverse(); } + arrowConfiguration = arrowConfiguration.withThickness(getArrowThickness()); - final ArrowComponent comp = skin.createComponentArrow(arrowConfiguration, skinParam, - message.getLabelNumbered()); + final ArrowComponent comp = skin + .createComponentArrow(arrowConfiguration, skinParam, message.getLabelNumbered()); return comp; } diff --git a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java index 434dd3b48..53d7c0cad 100644 --- a/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java +++ b/src/net/sourceforge/plantuml/sequencediagram/teoz/SequenceDiagramFileMakerTeoz.java @@ -142,15 +142,25 @@ public class SequenceDiagramFileMakerTeoz implements FileMaker { final ImageBuilder imageBuilder = new ImageBuilder(diagram.getSkinParam(), oneOf(scale, dpiFactor), metadata, null, 3, 10, diagram.getAnimation()); - imageBuilder.setUDrawable(new UDrawable() { - public void drawU(UGraphic ug) { - drawInternal(ug, index); - } - }); + imageBuilder.setUDrawable(new Foo(index)); return imageBuilder.writeImageTOBEMOVED(fileFormatOption, diagram.seed(), os); } + class Foo implements UDrawable { + + private final int index; + + Foo(int index) { + this.index = index; + } + + public void drawU(UGraphic ug) { + drawInternal(ug, index); + } + + } + private UGraphic goDownAndCenterForEnglobers(UGraphic ug) { ug = goDown(ug, title); ug = goDown(ug, header); diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDatabase.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDatabase.java index c7d4c01dc..b5733660d 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDatabase.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseDatabase.java @@ -69,7 +69,7 @@ public class ComponentRoseDatabase extends AbstractTextualComponent { final SymbolContext symbolContext = new SymbolContext(biColor.getBackColor(), biColor.getForeColor()) .withStroke(new UStroke(1.5)).withShadow(biColor.getDeltaShadow() > 0); this.stickman = USymbol.DATABASE.asSmall(null, TextBlockUtils.empty(16, 17), - TextBlockUtils.empty(0, 0), symbolContext); + TextBlockUtils.empty(0, 0), symbolContext, HorizontalAlignment.CENTER); } @Override diff --git a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseQueue.java b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseQueue.java index 3e3f8c563..426896269 100644 --- a/src/net/sourceforge/plantuml/skin/rose/ComponentRoseQueue.java +++ b/src/net/sourceforge/plantuml/skin/rose/ComponentRoseQueue.java @@ -65,7 +65,7 @@ public class ComponentRoseQueue extends AbstractTextualComponent { false, fontForStereotype, htmlColorForStereotype); this.head = head; this.stickman = USymbol.QUEUE.asSmall(TextBlockUtils.empty(0, 0), getTextBlock(), TextBlockUtils.empty(0, 0), - biColor); + biColor, HorizontalAlignment.CENTER); } @Override diff --git a/src/net/sourceforge/plantuml/stats/StatsUtilsIncrement.java b/src/net/sourceforge/plantuml/stats/StatsUtilsIncrement.java index 801c83ff8..cafbbb211 100644 --- a/src/net/sourceforge/plantuml/stats/StatsUtilsIncrement.java +++ b/src/net/sourceforge/plantuml/stats/StatsUtilsIncrement.java @@ -41,11 +41,11 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.prefs.Preferences; import net.sourceforge.plantuml.FileFormat; -import net.sourceforge.plantuml.PSystemError; import net.sourceforge.plantuml.activitydiagram3.ActivityDiagram3; import net.sourceforge.plantuml.core.Diagram; import net.sourceforge.plantuml.directdot.PSystemDot; import net.sourceforge.plantuml.eggs.PSystemWelcome; +import net.sourceforge.plantuml.error.PSystemErrorUtils; import net.sourceforge.plantuml.math.PSystemMath; import net.sourceforge.plantuml.salt.PSystemSalt; import net.sourceforge.plantuml.stats.api.Stats; @@ -110,7 +110,7 @@ public class StatsUtilsIncrement { } private static String name(Class type) { - if (type == PSystemError.class) { + if (PSystemErrorUtils.isDiagramError(type)) { return "Error"; } if (type == ActivityDiagram3.class) { diff --git a/src/net/sourceforge/plantuml/suggest/SuggestEngine.java b/src/net/sourceforge/plantuml/suggest/SuggestEngine.java deleted file mode 100644 index b06864e75..000000000 --- a/src/net/sourceforge/plantuml/suggest/SuggestEngine.java +++ /dev/null @@ -1,161 +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.suggest; - -import java.util.Iterator; - -import net.sourceforge.plantuml.AbstractPSystem; -import net.sourceforge.plantuml.command.UmlDiagramFactory; -import net.sourceforge.plantuml.core.UmlSource; -import net.sourceforge.plantuml.version.IteratorCounter2; - -final public class SuggestEngine { - - private static final int LIMIT = 120; - - private final UmlDiagramFactory systemFactory; - - private final IteratorCounter2 it99; - - public SuggestEngine(UmlSource source, Object foo) { - throw new UnsupportedOperationException(); - } - - public SuggestEngine(UmlSource source, UmlDiagramFactory systemFactory) { -// this.systemFactory = systemFactory; -// this.it99 = source.iterator2(); -// final CharSequence startLine = it99.next(); -// if (StartUtils.isArobaseStartDiagram(startLine) == false) { - throw new UnsupportedOperationException(); -// } - } - - public SuggestEngineResult tryToSuggest(AbstractPSystem system) { - return executeUmlCommand(system); - } - - private SuggestEngineResult executeUmlCommand(AbstractPSystem system) { - throw new UnsupportedOperationException(); -// while (it99.hasNext()) { -// if (StartUtils.isArobaseEndDiagram(it99.peek())) { -// return SuggestEngineResult.SYNTAX_OK; -// } -// final SuggestEngineResult check = checkAndCorrect(); -// if (check.getStatus() != SuggestEngineStatus.SYNTAX_OK) { -// return check; -// } -// final CommandControl commandControl = systemFactory.isValid2(it99); -// if (commandControl == CommandControl.OK_PARTIAL) { -// systemFactory.goForwardMultiline(it99); -// // if (ok == false) { -// // return SuggestEngineResult.CANNOT_CORRECT; -// // } -// } else if (commandControl == CommandControl.OK) { -// it99.next(); -// // final Command cmd = new ProtectedCommand(systemFactory.createCommand(Arrays.asList(s))); -// // final CommandExecutionResult result = cmd.execute(system, Arrays.asList(s)); -// // if (result.isOk() == false) { -// // return SuggestEngineResult.CANNOT_CORRECT; -// // } -// } else { -// return SuggestEngineResult.CANNOT_CORRECT; -// } -// } -// return SuggestEngineResult.CANNOT_CORRECT; - } - - SuggestEngineResult checkAndCorrect() { - throw new UnsupportedOperationException(); -// final String incorrectLine = it99.peek().toString(); -// if (incorrectLine.length() > LIMIT) { -// return SuggestEngineResult.CANNOT_CORRECT; -// } -// final CommandControl commandControl = systemFactory.isValid2(it99); -// if (commandControl != CommandControl.NOT_OK) { -// return SuggestEngineResult.SYNTAX_OK; -// } -// -// if (StringUtils.trin(incorrectLine).startsWith("{") -// && systemFactory.isValid(BlocLines.single(it99.peekPrevious() + " {")) != CommandControl.NOT_OK) { -// return new SuggestEngineResult(it99.peekPrevious() + " {"); -// } -// -// final Collection> all = new ArrayList>(); -// all.add(new VariatorRemoveOneChar(incorrectLine)); -// all.add(new VariatorSwapLetter(incorrectLine)); -// // all.add(new VariatorAddOneCharBetweenWords(incorrectLine, ':')); -// all.add(new VariatorAddOneCharBetweenWords(incorrectLine, '-')); -// all.add(new VariatorAddOneCharBetweenWords(incorrectLine, ' ')); -// // all.add(new VariatorAddTwoChar(incorrectLine, '\"')); -// -// for (Iterator it2 : all) { -// final SuggestEngineResult result = tryThis(it2); -// if (result != null) { -// return result; -// } -// } -// return SuggestEngineResult.CANNOT_CORRECT; - } - - private SuggestEngineResult tryThis(Iterator it2) { - throw new UnsupportedOperationException(); -// while (it2.hasNext()) { -// final String newS = it2.next(); -// if (StringUtils.trin(newS).length() == 0) { -// continue; -// } -// final CommandControl commandControl = systemFactory.isValid2(replaceFirstLine(newS)); -// if (commandControl == CommandControl.OK) { -// return new SuggestEngineResult(newS); -// } -// } -// return null; - } - - private IteratorCounter2 replaceFirstLine(String s) { - throw new UnsupportedOperationException(); -// final List tmp = new ArrayList(); -// tmp.add(new CharSequence2(s, null)); -// final Iterator it3 = it99.cloneMe(); -// if (it3.hasNext()) { -// it3.next(); -// } -// while (it3.hasNext()) { -// tmp.add(new CharSequence2(it3.next(), null)); -// } -// return new IteratorCounter2Impl(tmp); - } -} diff --git a/src/net/sourceforge/plantuml/suggest/SuggestEngineResult.java b/src/net/sourceforge/plantuml/suggest/SuggestEngineResult.java deleted file mode 100644 index 3eec4a8d2..000000000 --- a/src/net/sourceforge/plantuml/suggest/SuggestEngineResult.java +++ /dev/null @@ -1,92 +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.suggest; - -import net.sourceforge.plantuml.StringUtils; - -public class SuggestEngineResult { - - private final SuggestEngineStatus status; - private final String suggestedLine; - - public static final SuggestEngineResult CANNOT_CORRECT = new SuggestEngineResult(SuggestEngineStatus.CANNOT_CORRECT); - public static final SuggestEngineResult SYNTAX_OK = new SuggestEngineResult(SuggestEngineStatus.SYNTAX_OK); - - private SuggestEngineResult(SuggestEngineStatus status) { - if (status == SuggestEngineStatus.ONE_SUGGESTION) { - throw new IllegalArgumentException(); - } - this.status = status; - this.suggestedLine = null; - } - - @Override - public String toString() { - return status + " " + suggestedLine; - } - - @Override - public int hashCode() { - return status.hashCode() + (suggestedLine == null ? 0 : suggestedLine.hashCode()); - } - - @Override - public boolean equals(Object obj) { - final SuggestEngineResult this2 = (SuggestEngineResult) obj; - return status.equals(this2.status) && sameString(suggestedLine, this2.suggestedLine); - } - - private static boolean sameString(String a, String b) { - return (a == null && b == null) || (a != null && a.equals(b)); - } - - public SuggestEngineResult(String suggestedLine) { - if (StringUtils.trin(suggestedLine).length() == 0) { - throw new IllegalArgumentException(); - } - this.status = SuggestEngineStatus.ONE_SUGGESTION; - this.suggestedLine = suggestedLine; - } - - public final SuggestEngineStatus getStatus() { - return status; - } - - public final String getSuggestedLine() { - return suggestedLine; - } - -} diff --git a/src/net/sourceforge/plantuml/svek/Cluster.java b/src/net/sourceforge/plantuml/svek/Cluster.java index 62fdcc6cc..5ba24a029 100644 --- a/src/net/sourceforge/plantuml/svek/Cluster.java +++ b/src/net/sourceforge/plantuml/svek/Cluster.java @@ -354,8 +354,9 @@ public class Cluster implements Moveable { } } - final boolean shadowing = group.getUSymbol() == null ? skinParam2.shadowing2(group.getStereotype(), USymbol.PACKAGE.getSkinParameter()) - : skinParam2.shadowing2(group.getStereotype(), group.getUSymbol().getSkinParameter()); + final boolean shadowing = group.getUSymbol() == null ? skinParam2.shadowing2(group.getStereotype(), + USymbol.PACKAGE.getSkinParameter()) : skinParam2.shadowing2(group.getStereotype(), group + .getUSymbol().getSkinParameter()); if (ztitle != null || zstereo != null) { final HtmlColor back = getBackColor(getBackColor(umlDiagramType), skinParam2, group.getStereotype()); final double roundCorner = group.getUSymbol() == null ? 0 : group.getUSymbol().getSkinParameter() @@ -365,7 +366,8 @@ public class Cluster implements Moveable { final ClusterDecoration decoration = new ClusterDecoration(style, group.getUSymbol(), ztitle, zstereo, minX, minY, maxX, maxY, stroke2); decoration.drawU(ug, back, borderColor, shadowing, roundCorner, - skinParam2.getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false)); + skinParam2.getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false), + skinParam2.getStereotypeAlignment()); return; } final URectangle rect = new URectangle(maxX - minX, maxY - minY); diff --git a/src/net/sourceforge/plantuml/svek/ClusterDecoration.java b/src/net/sourceforge/plantuml/svek/ClusterDecoration.java index f58e10eb5..e59738066 100644 --- a/src/net/sourceforge/plantuml/svek/ClusterDecoration.java +++ b/src/net/sourceforge/plantuml/svek/ClusterDecoration.java @@ -84,14 +84,14 @@ public class ClusterDecoration { public final static int marginTitleY2 = 3; public void drawU(UGraphic ug, HtmlColor backColor, HtmlColor borderColor, boolean shadowing, double roundCorner, - HorizontalAlignment titleAlignment) { + HorizontalAlignment titleAlignment, HorizontalAlignment stereoAlignment) { final SymbolContext biColor = new SymbolContext(backColor, borderColor); if (symbol == null) { throw new UnsupportedOperationException(); } final SymbolContext symbolContext = biColor.withShadow(shadowing).withStroke(defaultStroke) .withCorner(roundCorner, 0); - symbol.asBig(title, titleAlignment, stereo, maxX - minX, maxY - minY, symbolContext).drawU( + symbol.asBig(title, titleAlignment, stereo, maxX - minX, maxY - minY, symbolContext, stereoAlignment).drawU( ug.apply(new UTranslate(minX, minY))); } diff --git a/src/net/sourceforge/plantuml/svek/Line.java b/src/net/sourceforge/plantuml/svek/Line.java index a6adbec8e..a632ae99c 100644 --- a/src/net/sourceforge/plantuml/svek/Line.java +++ b/src/net/sourceforge/plantuml/svek/Line.java @@ -88,6 +88,7 @@ import net.sourceforge.plantuml.skin.rose.Rose; import net.sourceforge.plantuml.svek.extremity.Extremity; import net.sourceforge.plantuml.svek.extremity.ExtremityFactory; import net.sourceforge.plantuml.svek.extremity.ExtremityFactoryExtends; +import net.sourceforge.plantuml.svek.extremity.ExtremityOther; import net.sourceforge.plantuml.svek.image.EntityImageNoteLink; import net.sourceforge.plantuml.ugraphic.UChangeBackColor; import net.sourceforge.plantuml.ugraphic.UChangeColor; @@ -95,7 +96,6 @@ import net.sourceforge.plantuml.ugraphic.UComment; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.ULine; import net.sourceforge.plantuml.ugraphic.UPolygon; -import net.sourceforge.plantuml.ugraphic.UShape; import net.sourceforge.plantuml.ugraphic.UStroke; import net.sourceforge.plantuml.ugraphic.UTranslate; @@ -524,12 +524,8 @@ public class Line implements Moveable, Hideable { }; } } else if (decor != LinkDecor.NONE) { - final UShape sh = new UPolygon(pointListIterator.next()); - return new UDrawable() { - public void drawU(UGraphic ug) { - ug.draw(sh); - } - }; + final UPolygon sh = new UPolygon(pointListIterator.next()); + return new ExtremityOther(sh); } return null; @@ -710,6 +706,21 @@ public class Line implements Moveable, Hideable { } } + if (extremity1 instanceof Extremity && extremity2 instanceof Extremity) { + // http://forum.plantuml.net/9421/arrow-inversion-with-skinparam-linetype-ortho-missing-arrow + final Point2D p1 = ((Extremity) extremity1).isTooSmallSoGiveThePointCloserToThisOne(todraw + .getStartPoint()); + if (p1 != null) { + todraw.forceStartPoint(p1.getX(), p1.getY()); + } + final Point2D p2 = ((Extremity) extremity2).isTooSmallSoGiveThePointCloserToThisOne(todraw + .getEndPoint()); + if (p2 != null) { + todraw.forceEndPoint(p2.getX(), p2.getY()); + } + + } + final String comment = link.getEntity1().getCode().getFullName() + "-" + link.getEntity2().getCode().getFullName(); todraw.setComment(uniq(ids, comment)); diff --git a/src/net/sourceforge/plantuml/svek/extremity/Extremity.java b/src/net/sourceforge/plantuml/svek/extremity/Extremity.java index 9a88e1f23..23da0fd9e 100644 --- a/src/net/sourceforge/plantuml/svek/extremity/Extremity.java +++ b/src/net/sourceforge/plantuml/svek/extremity/Extremity.java @@ -44,25 +44,25 @@ public abstract class Extremity implements UDrawable { protected double manageround(double angle) { final double deg = angle * 180.0 / Math.PI; - if (isCloseToo(0, deg)) { + if (isCloseTo(0, deg)) { return 0; } - if (isCloseToo(90, deg)) { + if (isCloseTo(90, deg)) { return 90.0 * Math.PI / 180.0; } - if (isCloseToo(180, deg)) { + if (isCloseTo(180, deg)) { return 180.0 * Math.PI / 180.0; } - if (isCloseToo(270, deg)) { + if (isCloseTo(270, deg)) { return 270.0 * Math.PI / 180.0; } - if (isCloseToo(360, deg)) { + if (isCloseTo(360, deg)) { return 0; } return angle; } - private boolean isCloseToo(double value, double variable) { + private boolean isCloseTo(double value, double variable) { if (Math.abs(value - variable) < 0.05) { return true; } @@ -70,5 +70,9 @@ public abstract class Extremity implements UDrawable { } public abstract Point2D somePoint(); + + public Point2D isTooSmallSoGiveThePointCloserToThisOne(Point2D pt) { + return null; + } } diff --git a/src/net/sourceforge/plantuml/svek/extremity/ExtremityDiamond.java b/src/net/sourceforge/plantuml/svek/extremity/ExtremityDiamond.java index 66c75e7ea..031ebe360 100644 --- a/src/net/sourceforge/plantuml/svek/extremity/ExtremityDiamond.java +++ b/src/net/sourceforge/plantuml/svek/extremity/ExtremityDiamond.java @@ -79,4 +79,15 @@ class ExtremityDiamond extends Extremity { ug.draw(polygon); } + @Override + public Point2D isTooSmallSoGiveThePointCloserToThisOne(Point2D pt) { + Point2D result = null; + for (Point2D p : polygon.getPoints()) { + if (result == null || p.distance(pt) < result.distance(pt)) { + result = p; + } + } + return result; + } + } diff --git a/src/net/sourceforge/plantuml/suggest/VariatorRemoveOneChar.java b/src/net/sourceforge/plantuml/svek/extremity/ExtremityOther.java similarity index 73% rename from src/net/sourceforge/plantuml/suggest/VariatorRemoveOneChar.java rename to src/net/sourceforge/plantuml/svek/extremity/ExtremityOther.java index 600ef3ab7..4bd7b8c09 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorRemoveOneChar.java +++ b/src/net/sourceforge/plantuml/svek/extremity/ExtremityOther.java @@ -31,32 +31,30 @@ * * Original Author: Arnaud Roques * - * + * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.svek.extremity; -public class VariatorRemoveOneChar extends VariatorIteratorAdaptor { +import java.awt.geom.Point2D; - private final String data; - private int i; +import net.sourceforge.plantuml.ugraphic.UGraphic; +import net.sourceforge.plantuml.ugraphic.UPolygon; + +public class ExtremityOther extends Extremity { + + final private UPolygon polygon; + + public ExtremityOther(UPolygon polygon) { + this.polygon = polygon; + } + + public void drawU(UGraphic ug) { + ug.draw(polygon); - public VariatorRemoveOneChar(String data) { - this.data = data; } @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i >= data.length()) { - return null; - } - return data.substring(0, i) + data.substring(i + 1); - } - - public void nextStep() { - i++; - } - }; + public Point2D somePoint() { + return polygon.getPoints().get(0); } } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java index b1d852de2..d839dd2dd 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageDescription.java @@ -138,7 +138,7 @@ public class EntityImageDescription extends AbstractEntityImage { stereo = TextBlockUtils.empty(0, 0); if (stereotype != null && stereotype.getSprite(getSkinParam()) != null) { - symbol = symbol.withStereoAlignment(HorizontalAlignment.RIGHT); + // symbol = symbol.withStereoAlignment(HorizontalAlignment.RIGHT); stereo = stereotype.getSprite(getSkinParam()); } else if (stereotype != null && stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) != null && portionShower.showPortion(EntityPortion.STEREOTYPE, entity)) { @@ -152,9 +152,9 @@ public class EntityImageDescription extends AbstractEntityImage { if (hideText) { asSmall = symbol.asSmall(TextBlockUtils.empty(0, 0), TextBlockUtils.empty(0, 0), - TextBlockUtils.empty(0, 0), ctx); + TextBlockUtils.empty(0, 0), ctx, skinParam.getStereotypeAlignment()); } else { - asSmall = symbol.asSmall(name, desc, stereo, ctx); + asSmall = symbol.asSmall(name, desc, stereo, ctx, skinParam.getStereotypeAlignment()); } } diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java index 97255661b..23f857b18 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageEmptyPackage.java @@ -130,8 +130,9 @@ public class EntityImageEmptyPackage extends AbstractEntityImage { stereoBlock, 0, 0, widthTotal, heightTotal, getStroke()); decoration.drawU(ug, back, SkinParamUtils.getColor(getSkinParam(), getStereo(), ColorParam.packageBorder), - getSkinParam().shadowing(getEntity().getStereotype()), roundCorner, - getSkinParam().getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false)); + getSkinParam().shadowing(getEntity().getStereotype()), roundCorner, getSkinParam() + .getHorizontalAlignment(AlignmentParam.packageTitleAlignment, null, false), getSkinParam() + .getStereotypeAlignment()); if (url != null) { ug.closeAction(); diff --git a/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java b/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java index 9358e918f..491390b85 100644 --- a/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java +++ b/src/net/sourceforge/plantuml/svek/image/EntityImageState2.java @@ -95,7 +95,7 @@ public class EntityImageState2 extends AbstractEntityImage { final TextBlock desc = new BodyEnhanced(entity.getDisplay(), symbol.getFontParam(), skinParam, HorizontalAlignment.CENTER, stereotype, symbol.manageHorizontalLine(), false, entity); - asSmall = symbol.asSmall(null, desc, stereo, ctx); + asSmall = symbol.asSmall(null, desc, stereo, ctx, skinParam.getStereotypeAlignment()); } diff --git a/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java b/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java index 972635f0a..9d21c5de7 100644 --- a/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java +++ b/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java @@ -44,10 +44,10 @@ import net.sourceforge.plantuml.ErrorUml; import net.sourceforge.plantuml.LineLocation; import net.sourceforge.plantuml.LineLocationImpl; import net.sourceforge.plantuml.OptionFlags; -import net.sourceforge.plantuml.PSystemError; import net.sourceforge.plantuml.SourceStringReader; import net.sourceforge.plantuml.UmlDiagram; import net.sourceforge.plantuml.core.Diagram; +import net.sourceforge.plantuml.error.PSystemError; import net.sourceforge.plantuml.preproc.Defines; public class SyntaxChecker { @@ -68,17 +68,13 @@ public class SyntaxChecker { if (source.startsWith("@startuml\n") == false) { result.setError(true); result.setLineLocation(new LineLocationImpl("", null).oneLineRead()); - // result.setErrorLinePosition(0); result.addErrorText("No @startuml found"); - // result.setSuggest(Arrays.asList("Did you mean:", "@startuml")); return result; } if (source.endsWith("@enduml\n") == false && source.endsWith("@enduml") == false) { result.setError(true); result.setLineLocation(lastLineNumber2(source)); - // result.setErrorLinePosition(lastLineNumber(source)); result.addErrorText("No @enduml found"); - // result.setSuggest(Arrays.asList("Did you mean:", "@enduml")); return result; } final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source, @@ -88,9 +84,7 @@ public class SyntaxChecker { if (blocks.size() == 0) { result.setError(true); result.setLineLocation(lastLineNumber2(source)); - // result.setErrorLinePosition(lastLineNumber(source)); result.addErrorText("No @enduml found"); - // result.setSuggest(Arrays.asList("Did you mean:", "@enduml")); return result; } final Diagram system = blocks.get(0).getDiagram(); @@ -101,13 +95,11 @@ public class SyntaxChecker { } else if (system instanceof PSystemError) { result.setError(true); final PSystemError sys = (PSystemError) system; - // result.setErrorLinePosition(sys.getHigherErrorPosition()); result.setLineLocation(sys.getLineLocation()); result.setSystemError(sys); for (ErrorUml er : sys.getErrorsUml()) { result.addErrorText(er.getError()); } - // result.setSuggest(sys.getSuggest()); } else { result.setDescription(system.getDescription().getDescription()); } @@ -124,7 +116,6 @@ public class SyntaxChecker { result.setError(true); result.setLineLocation(lastLineNumber2(source)); result.addErrorText("No @enduml found"); - // result.setSuggest(Arrays.asList("Did you mean:", "@enduml")); return result; } @@ -136,13 +127,11 @@ public class SyntaxChecker { } else if (system instanceof PSystemError) { result.setError(true); final PSystemError sys = (PSystemError) system; - // result.setErrorLinePosition(sys.getHigherErrorPosition()); result.setLineLocation(sys.getLineLocation()); for (ErrorUml er : sys.getErrorsUml()) { result.addErrorText(er.getError()); } result.setSystemError(sys); - // result.setSuggest(sys.getSuggest()); } else { result.setDescription(system.getDescription().getDescription()); } diff --git a/src/net/sourceforge/plantuml/syntax/SyntaxResult.java b/src/net/sourceforge/plantuml/syntax/SyntaxResult.java index 473e8aafe..1581094bd 100644 --- a/src/net/sourceforge/plantuml/syntax/SyntaxResult.java +++ b/src/net/sourceforge/plantuml/syntax/SyntaxResult.java @@ -43,17 +43,15 @@ import java.util.TreeSet; import net.sourceforge.plantuml.FileFormatOption; import net.sourceforge.plantuml.LineLocation; -import net.sourceforge.plantuml.PSystemError; import net.sourceforge.plantuml.UmlDiagramType; +import net.sourceforge.plantuml.error.PSystemError; public class SyntaxResult { private UmlDiagramType umlDiagramType; private boolean isError; private String description; - // private int errorLinePosition; private Collection errors = new TreeSet(); - // private List suggest; private boolean hasCmapData; private PSystemError systemError; private LineLocation lineLocation; @@ -70,14 +68,6 @@ public class SyntaxResult { return description; } - // public int getErrorLinePosition() { - // return errorLinePosition; - // } - - // public List getSuggest() { - // return suggest; - // } - public Collection getErrors() { return Collections.unmodifiableCollection(errors); } @@ -94,18 +84,10 @@ public class SyntaxResult { this.description = description; } - // public void setErrorLinePosition(int errorLinePosition) { - // this.errorLinePosition = errorLinePosition; - // } - public void addErrorText(String error) { this.errors.add(error); } - // public void setSuggest(List suggest) { - // this.suggest = suggest; - // } - public final boolean hasCmapData() { return hasCmapData; } diff --git a/src/net/sourceforge/plantuml/tim/ConditionalContext.java b/src/net/sourceforge/plantuml/tim/ConditionalContext.java index f9135bc04..921335a89 100644 --- a/src/net/sourceforge/plantuml/tim/ConditionalContext.java +++ b/src/net/sourceforge/plantuml/tim/ConditionalContext.java @@ -37,9 +37,13 @@ package net.sourceforge.plantuml.tim; public class ConditionalContext { private boolean isTrue; + private boolean hasBeenBurn; private ConditionalContext(boolean isTrue) { this.isTrue = isTrue; + if (this.isTrue) { + hasBeenBurn = true; + } } public static ConditionalContext fromValue(boolean isTrue) { @@ -50,8 +54,25 @@ public class ConditionalContext { return isTrue; } + public void enteringElseIf() { + this.isTrue = false; + } + public void nowInElse() { - this.isTrue = !isTrue; + this.isTrue = !hasBeenBurn; + } + + public void nowInSomeElseIf() { + this.isTrue = true; + this.hasBeenBurn = true; + } + + public final boolean hasBeenBurn() { + return hasBeenBurn; + } + + public final void setHasBeenBurn(boolean hasBeenBurn) { + this.hasBeenBurn = hasBeenBurn; } } diff --git a/src/net/sourceforge/plantuml/tim/ConditionalContexts.java b/src/net/sourceforge/plantuml/tim/ConditionalContexts.java index 7471100a8..db8aee6dd 100644 --- a/src/net/sourceforge/plantuml/tim/ConditionalContexts.java +++ b/src/net/sourceforge/plantuml/tim/ConditionalContexts.java @@ -37,7 +37,7 @@ package net.sourceforge.plantuml.tim; import java.util.Deque; import java.util.LinkedList; -public class ConditionalContexts { +public abstract class ConditionalContexts { private final Deque allIfs = new LinkedList(); @@ -53,4 +53,13 @@ public class ConditionalContexts { return allIfs.pollLast(); } + public boolean areAllIfOk() { + for (ConditionalContext conditionalContext : allIfs) { + if (conditionalContext.conditionIsOkHere() == false) { + return false; + } + } + return true; + } + } diff --git a/src/net/sourceforge/plantuml/tim/Eater.java b/src/net/sourceforge/plantuml/tim/Eater.java index cb3ca8924..f38d742be 100644 --- a/src/net/sourceforge/plantuml/tim/Eater.java +++ b/src/net/sourceforge/plantuml/tim/Eater.java @@ -132,7 +132,7 @@ public abstract class Eater { } } - final protected String eatAntGetVarname() throws EaterException { + final protected String eatAndGetVarname() throws EaterException { final StringBuilder varname = new StringBuilder("" + eatOneChar()); if (TLineType.isLetterOrUnderscoreOrDollar(varname.charAt(0)) == false) { throw new EaterException("a002"); @@ -141,7 +141,7 @@ public abstract class Eater { return varname.toString(); } - final protected String eatAntGetFunctionName() throws EaterException { + final protected String eatAndGetFunctionName() throws EaterException { final StringBuilder varname = new StringBuilder("" + eatOneChar()); if (TLineType.isLetterOrUnderscoreOrDollar(varname.charAt(0)) == false) { throw new EaterException("a003"); @@ -151,7 +151,7 @@ public abstract class Eater { } final public void skipSpaces() { - while (i < s.length() && Character.isSpaceChar(s.charAt(i))) { + while (i < s.length() && Character.isWhitespace(s.charAt(i))) { i++; } } @@ -193,6 +193,14 @@ public abstract class Eater { i++; } + final protected boolean safeCheckAndEatChar(char ch) throws EaterException { + if (i >= s.length() || s.charAt(i) != ch) { + return false; + } + i++; + return true; + } + final protected void optionallyEatChar(char ch) throws EaterException { if (i >= s.length() || s.charAt(i) != ch) { return; @@ -241,16 +249,21 @@ public abstract class Eater { } final protected TFunctionImpl eatDeclareFunction(TContext context, TMemory memory, boolean unquoted, - LineLocation location) throws EaterException { + LineLocation location, boolean allowNoParenthesis) throws EaterException { final List args = new ArrayList(); - final String functionName = eatAntGetFunctionName(); + final String functionName = eatAndGetFunctionName(); skipSpaces(); - checkAndEatChar('('); + if (safeCheckAndEatChar('(') == false) { + if (allowNoParenthesis) { + return new TFunctionImpl(functionName, args, unquoted); + } + throw new EaterException("Missing opening parenthesis"); + } while (true) { skipSpaces(); char ch = peekChar(); if (TLineType.isLetterOrUnderscoreOrDollar(ch)) { - final String varname = eatAntGetVarname(); + final String varname = eatAndGetVarname(); skipSpaces(); final TValue defValue; if (peekChar() == '=') { @@ -278,7 +291,7 @@ public abstract class Eater { final protected TFunctionImpl eatDeclareFunctionWithOptionalReturn(TContext context, TMemory memory, boolean unquoted, LineLocation location) throws EaterException { - final TFunctionImpl result = eatDeclareFunction(context, memory, unquoted, location); + final TFunctionImpl result = eatDeclareFunction(context, memory, unquoted, location, false); if (peekChar() == 'r') { checkAndEatChar("return"); skipSpaces(); diff --git a/src/net/sourceforge/plantuml/tim/EaterAffectation.java b/src/net/sourceforge/plantuml/tim/EaterAffectation.java index d0dacacff..cb64e15c7 100644 --- a/src/net/sourceforge/plantuml/tim/EaterAffectation.java +++ b/src/net/sourceforge/plantuml/tim/EaterAffectation.java @@ -44,14 +44,21 @@ public class EaterAffectation extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!"); skipSpaces(); - final String varname = eatAntGetVarname(); + String varname = eatAndGetVarname(); + TVariableScope scope = null; skipSpaces(); + if (peekChar() != '=') { + scope = TVariableScope.valueOf(varname.toUpperCase()); + varname = eatAndGetVarname(); + skipSpaces(); + } checkAndEatChar('='); skipSpaces(); final TValue value = eatExpression(context, memory); - memory.put(varname, new TVariable(value)); + memory.putVariable(varname, new TVariable(value), scope); } } diff --git a/src/net/sourceforge/plantuml/tim/EaterAffectationDefine.java b/src/net/sourceforge/plantuml/tim/EaterAffectationDefine.java index 24effb6e5..7925f5d8c 100644 --- a/src/net/sourceforge/plantuml/tim/EaterAffectationDefine.java +++ b/src/net/sourceforge/plantuml/tim/EaterAffectationDefine.java @@ -44,12 +44,18 @@ public class EaterAffectationDefine extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!define"); skipSpaces(); - final String varname = eatAntGetVarname(); + final String varname = eatAndGetVarname(); skipSpaces(); - final TValue value = TValue.fromString(eatAllToEnd()); - memory.put(varname, new TVariable(value)); + final String tmp = eatAllToEnd(); + final String tmp2 = context.applyFunctionsAndVariables(memory, tmp); + final TValue value = TValue.fromString(tmp2); + // if (memory instanceof TMemoryLocal) { + // memory = ((TMemoryLocal) memory).getGlobalForInternalUseOnly(); + // } + memory.putVariable(varname, new TVariable(value), TVariableScope.GLOBAL); } } diff --git a/src/net/sourceforge/plantuml/tim/EaterAssert.java b/src/net/sourceforge/plantuml/tim/EaterAssert.java index caeb35f0d..c9095357f 100644 --- a/src/net/sourceforge/plantuml/tim/EaterAssert.java +++ b/src/net/sourceforge/plantuml/tim/EaterAssert.java @@ -44,6 +44,7 @@ public class EaterAssert extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!assert"); skipSpaces(); final TValue value = eatExpressionStopAtColon(context, memory); diff --git a/src/net/sourceforge/plantuml/tim/EaterDeclareFunction.java b/src/net/sourceforge/plantuml/tim/EaterDeclareFunction.java index 4064d6fb5..3ba0d87ec 100644 --- a/src/net/sourceforge/plantuml/tim/EaterDeclareFunction.java +++ b/src/net/sourceforge/plantuml/tim/EaterDeclareFunction.java @@ -41,6 +41,7 @@ public class EaterDeclareFunction extends Eater { private TFunctionImpl function; private final LineLocation location; + private boolean finalFlag; public EaterDeclareFunction(StringLocated s) { super(s.getStringTrimmed()); @@ -49,21 +50,39 @@ public class EaterDeclareFunction extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!"); - final boolean unquoted; - if (peekChar() == 'u') { - checkAndEatChar("unquoted function"); - unquoted = true; - } else { - checkAndEatChar("function"); - unquoted = false; + boolean unquoted = false; + while (peekUnquoted() || peekFinal()) { + if (peekUnquoted()) { + checkAndEatChar("unquoted"); + skipSpaces(); + unquoted = true; + } else if (peekFinal()) { + checkAndEatChar("final"); + skipSpaces(); + finalFlag = true; + } } + checkAndEatChar("function"); skipSpaces(); function = eatDeclareFunctionWithOptionalReturn(context, memory, unquoted, location); } + private boolean peekUnquoted() { + return peekChar() == 'u'; + } + + private boolean peekFinal() { + return peekChar() == 'f' && peekCharN2() == 'i'; + } + public TFunctionImpl getFunction() { return function; } + public final boolean getFinalFlag() { + return finalFlag; + } + } diff --git a/src/net/sourceforge/plantuml/tim/EaterDumpMemory.java b/src/net/sourceforge/plantuml/tim/EaterDumpMemory.java new file mode 100644 index 000000000..c7f4337d8 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/EaterDumpMemory.java @@ -0,0 +1,54 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + */ +package net.sourceforge.plantuml.tim; + +public class EaterDumpMemory extends Eater { + + public EaterDumpMemory(String s) { + super(s); + } + + @Override + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!dump_memory"); + skipSpaces(); + final String remain = this.eatAllToEnd(); + memory.dumpDebug(remain); + // final String logData = context.applyFunctionsAndVariables(memory, remain); + // Log.error(logData); + } + +} diff --git a/src/net/sourceforge/plantuml/suggest/VariatorAddOneChar.java b/src/net/sourceforge/plantuml/tim/EaterElseIf.java similarity index 70% rename from src/net/sourceforge/plantuml/suggest/VariatorAddOneChar.java rename to src/net/sourceforge/plantuml/tim/EaterElseIf.java index eb85ed511..4b8353337 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorAddOneChar.java +++ b/src/net/sourceforge/plantuml/tim/EaterElseIf.java @@ -5,12 +5,12 @@ * (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 @@ -31,34 +31,30 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim; -public class VariatorAddOneChar extends VariatorIteratorAdaptor { +import net.sourceforge.plantuml.tim.expression.TValue; - private final String data; - private final char toAdd; - private int i; +public class EaterElseIf extends Eater { - public VariatorAddOneChar(String data, char toAdd) { - this.data = data; - this.toAdd = toAdd; + private boolean booleanValue; + + public EaterElseIf(String s) { + super(s); } @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i > data.length()) { - return null; - } - return data.substring(0, i) + toAdd + data.substring(i); - } - - public void nextStep() { - i++; - } - }; + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!elseif"); + skipSpaces(); + final TValue value = eatExpression(context, memory); + this.booleanValue = value.toBoolean(); } + + public boolean isTrue() { + return this.booleanValue; + } + } diff --git a/src/net/sourceforge/plantuml/tim/EaterException.java b/src/net/sourceforge/plantuml/tim/EaterException.java index f3d04567c..f4fb9dec8 100644 --- a/src/net/sourceforge/plantuml/tim/EaterException.java +++ b/src/net/sourceforge/plantuml/tim/EaterException.java @@ -34,16 +34,28 @@ */ package net.sourceforge.plantuml.tim; +import net.sourceforge.plantuml.StringLocated; + public class EaterException extends Exception { private final String message; + private final StringLocated location; + + public EaterException(String message, StringLocated location) { + this.message = message; + this.location = location; + } public EaterException(String message) { - this.message = message; + this(message, null); } public final String getMessage() { return message; } + public final StringLocated getLocation() { + return location; + } + } diff --git a/src/net/sourceforge/plantuml/tim/EaterFunctionCall.java b/src/net/sourceforge/plantuml/tim/EaterFunctionCall.java index 2fb9e074d..adf740bf3 100644 --- a/src/net/sourceforge/plantuml/tim/EaterFunctionCall.java +++ b/src/net/sourceforge/plantuml/tim/EaterFunctionCall.java @@ -65,7 +65,11 @@ public class EaterFunctionCall extends Eater { while (true) { skipSpaces(); if (isLegacyDefine || unquoted) { - final TValue result = TValue.fromString(eatAndGetOptionalQuotedString()); + final String tmp = eatAndGetOptionalQuotedString(); + final String tmp2 = context.applyFunctionsAndVariables(memory, tmp); + // final TVariable var = memory.getVariable(tmp); + // final TValue result = var == null ? TValue.fromString(tmp) : var.getValue2(); + final TValue result = TValue.fromString(tmp2); values.add(result); } else { final TokenStack tokens = TokenStack.eatUntilCloseParenthesisOrComma(this).withoutSpace(); @@ -85,24 +89,7 @@ public class EaterFunctionCall extends Eater { } } - private void executeLegacyDefine(TContext context, TMemory memory) throws EaterException { - while (true) { - skipSpaces(); - final TValue result = TValue.fromString(eatAndGetOptionalQuotedString()); - values.add(result); - skipSpaces(); - final char ch = eatOneChar(); - if (ch == ',') { - continue; - } - if (ch == ')') { - break; - } - throw new EaterException("call001"); - } - } - - public final List getValues2() { + public final List getValues() { return Collections.unmodifiableList(values); } diff --git a/src/net/sourceforge/plantuml/tim/EaterIf.java b/src/net/sourceforge/plantuml/tim/EaterIf.java index 4e50bc92a..d6ba6b261 100644 --- a/src/net/sourceforge/plantuml/tim/EaterIf.java +++ b/src/net/sourceforge/plantuml/tim/EaterIf.java @@ -46,6 +46,7 @@ public class EaterIf extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!if"); skipSpaces(); final TValue value = eatExpression(context, memory); diff --git a/src/net/sourceforge/plantuml/tim/EaterIfdef.java b/src/net/sourceforge/plantuml/tim/EaterIfdef.java index 05fba5bfd..ae52254da 100644 --- a/src/net/sourceforge/plantuml/tim/EaterIfdef.java +++ b/src/net/sourceforge/plantuml/tim/EaterIfdef.java @@ -34,9 +34,12 @@ */ package net.sourceforge.plantuml.tim; +import net.sourceforge.plantuml.preproc.EvalBoolean; +import net.sourceforge.plantuml.preproc.Truth; + public class EaterIfdef extends Eater { - private String varname; + private String expression; public EaterIfdef(String s) { super(s); @@ -44,14 +47,22 @@ public class EaterIfdef extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!ifdef"); skipSpaces(); - varname = eatAntGetVarname(); + expression = eatAllToEnd(); } - public boolean isTrue(TContext context, TMemory memory) { - final TVariable currentValue = memory.getVariable(varname); - return currentValue != null || context.doesFunctionExist(varname); + public boolean isTrue(final TContext context, final TMemory memory) { + final EvalBoolean eval = new EvalBoolean(expression, new Truth() { + + public boolean isTrue(String varname) { + final TVariable currentValue = memory.getVariable(varname); + return currentValue != null || context.doesFunctionExist(varname); + } + }); + + return eval.eval(); } } diff --git a/src/net/sourceforge/plantuml/tim/EaterIfndef.java b/src/net/sourceforge/plantuml/tim/EaterIfndef.java index 0c5b8e472..cce7af168 100644 --- a/src/net/sourceforge/plantuml/tim/EaterIfndef.java +++ b/src/net/sourceforge/plantuml/tim/EaterIfndef.java @@ -44,9 +44,10 @@ public class EaterIfndef extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!ifndef"); skipSpaces(); - varname = eatAntGetVarname(); + varname = eatAndGetVarname(); } public boolean isTrue(TContext context, TMemory memory) { diff --git a/src/net/sourceforge/plantuml/tim/EaterImport.java b/src/net/sourceforge/plantuml/tim/EaterImport.java index 21f098777..bd368d115 100644 --- a/src/net/sourceforge/plantuml/tim/EaterImport.java +++ b/src/net/sourceforge/plantuml/tim/EaterImport.java @@ -44,6 +44,7 @@ public class EaterImport extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!import"); skipSpaces(); this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd()); diff --git a/src/net/sourceforge/plantuml/tim/EaterInclude.java b/src/net/sourceforge/plantuml/tim/EaterInclude.java index 59a4bae46..d88721bfc 100644 --- a/src/net/sourceforge/plantuml/tim/EaterInclude.java +++ b/src/net/sourceforge/plantuml/tim/EaterInclude.java @@ -34,9 +34,12 @@ */ package net.sourceforge.plantuml.tim; +import net.sourceforge.plantuml.preproc2.PreprocessorIncludeStrategy; + public class EaterInclude extends Eater { private String location; + private PreprocessorIncludeStrategy strategy = PreprocessorIncludeStrategy.DEFAULT; public EaterInclude(String s) { super(s); @@ -44,9 +47,21 @@ public class EaterInclude extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!include"); - if (peekChar() == 'u') { + final char peekChar = peekChar(); + if (peekChar == 'u') { checkAndEatChar("url"); + } else if (peekChar == '_') { + checkAndEatChar("_"); + final char peekChar2 = peekChar(); + if (peekChar2 == 'm') { + checkAndEatChar("many"); + this.strategy = PreprocessorIncludeStrategy.MANY; + } else { + checkAndEatChar("once"); + this.strategy = PreprocessorIncludeStrategy.ONCE; + } } skipSpaces(); this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd()); @@ -57,4 +72,8 @@ public class EaterInclude extends Eater { return location; } + public final PreprocessorIncludeStrategy getPreprocessorIncludeStrategy() { + return strategy; + } + } diff --git a/src/net/sourceforge/plantuml/suggest/VariatorSwapChar.java b/src/net/sourceforge/plantuml/tim/EaterIncludesub.java similarity index 71% rename from src/net/sourceforge/plantuml/suggest/VariatorSwapChar.java rename to src/net/sourceforge/plantuml/tim/EaterIncludesub.java index fb1241d46..27f94e320 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorSwapChar.java +++ b/src/net/sourceforge/plantuml/tim/EaterIncludesub.java @@ -5,12 +5,12 @@ * (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 @@ -31,32 +31,28 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim; -public class VariatorSwapChar extends VariatorIteratorAdaptor { +public class EaterIncludesub extends Eater { - private final String data; - private int i; + private String location; - public VariatorSwapChar(String data) { - this.data = data; + public EaterIncludesub(String s) { + super(s); } @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i >= data.length() - 1) { - return null; - } - return data.substring(0, i) + data.charAt(i + 1) + data.charAt(i) + data.substring(i + 2); - } + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!includesub"); + skipSpaces(); + this.location = context.applyFunctionsAndVariables(memory, this.eatAllToEnd()); - public void nextStep() { - i++; - } - }; } + + public final String getLocation() { + return location; + } + } diff --git a/src/net/sourceforge/plantuml/tim/EaterLegacyDefine.java b/src/net/sourceforge/plantuml/tim/EaterLegacyDefine.java index edd71c9c1..372151501 100644 --- a/src/net/sourceforge/plantuml/tim/EaterLegacyDefine.java +++ b/src/net/sourceforge/plantuml/tim/EaterLegacyDefine.java @@ -49,9 +49,10 @@ public class EaterLegacyDefine extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!define"); skipSpaces(); - function = eatDeclareFunction(context, memory, true, location); + function = eatDeclareFunction(context, memory, true, location, false); final String def = this.eatAllToEnd(); function.setFunctionType(TFunctionType.LEGACY_DEFINE); function.setLegacyDefinition(def); diff --git a/src/net/sourceforge/plantuml/tim/EaterLegacyDefineLong.java b/src/net/sourceforge/plantuml/tim/EaterLegacyDefineLong.java index 467c43338..79bfd1118 100644 --- a/src/net/sourceforge/plantuml/tim/EaterLegacyDefineLong.java +++ b/src/net/sourceforge/plantuml/tim/EaterLegacyDefineLong.java @@ -49,9 +49,10 @@ public class EaterLegacyDefineLong extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!definelong"); skipSpaces(); - function = eatDeclareFunction(context, memory, true, location); + function = eatDeclareFunction(context, memory, true, location, true); function.setFunctionType(TFunctionType.LEGACY_DEFINELONG); } diff --git a/src/net/sourceforge/plantuml/tim/EaterLog.java b/src/net/sourceforge/plantuml/tim/EaterLog.java new file mode 100644 index 000000000..f45a5147a --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/EaterLog.java @@ -0,0 +1,54 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + */ +package net.sourceforge.plantuml.tim; + +import net.sourceforge.plantuml.Log; + +public class EaterLog extends Eater { + + public EaterLog(String s) { + super(s); + } + + @Override + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!log"); + skipSpaces(); + final String logData = context.applyFunctionsAndVariables(memory, this.eatAllToEnd()); + Log.error("[Log] " + logData); + } + +} diff --git a/src/net/sourceforge/plantuml/tim/EaterReturn.java b/src/net/sourceforge/plantuml/tim/EaterReturn.java index 48d55e61e..cce09b38c 100644 --- a/src/net/sourceforge/plantuml/tim/EaterReturn.java +++ b/src/net/sourceforge/plantuml/tim/EaterReturn.java @@ -46,6 +46,7 @@ public class EaterReturn extends Eater { @Override public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); checkAndEatChar("!return"); skipSpaces(); this.value = eatExpression(context, memory); diff --git a/src/net/sourceforge/plantuml/tim/EaterStartsub.java b/src/net/sourceforge/plantuml/tim/EaterStartsub.java new file mode 100644 index 000000000..3c0221fe9 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/EaterStartsub.java @@ -0,0 +1,60 @@ +/* ======================================================================== + * 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.tim; + +public class EaterStartsub extends Eater { + + private String subname; + + public EaterStartsub(String s) { + super(s); + } + + @Override + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!startsub"); + skipSpaces(); + this.subname = eatAllToEnd(); + if (this.subname.matches("\\w+") == false) { + throw new EaterException("Bad sub name"); + } + } + + public final String getSubname() { + return subname; + } + +} diff --git a/src/net/sourceforge/plantuml/tim/EaterUndef.java b/src/net/sourceforge/plantuml/tim/EaterUndef.java new file mode 100644 index 000000000..b97dd5eef --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/EaterUndef.java @@ -0,0 +1,54 @@ +/* ======================================================================== + * PlantUML : a free UML diagram generator + * ======================================================================== + * + * (C) Copyright 2009-2020, Arnaud Roques + * + * Project Info: http://plantuml.com + * + * If you like this project or if you find it useful, you can support us at: + * + * http://plantuml.com/patreon (only 1$ per month!) + * http://plantuml.com/paypal + * + * This file is part of PlantUML. + * + * PlantUML is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlantUML distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * + * Original Author: Arnaud Roques + * + */ +package net.sourceforge.plantuml.tim; + +import net.sourceforge.plantuml.StringLocated; + +public class EaterUndef extends Eater { + + public EaterUndef(StringLocated s) { + super(s.getStringTrimmed()); + } + + @Override + public void execute(TContext context, TMemory memory) throws EaterException { + skipSpaces(); + checkAndEatChar("!undef"); + skipSpaces(); + final String varname = eatAndGetVarname(); + memory.removeVariable(varname); + } + +} diff --git a/src/net/sourceforge/plantuml/tim/TContext.java b/src/net/sourceforge/plantuml/tim/TContext.java index 96c3f9939..c6d66b886 100644 --- a/src/net/sourceforge/plantuml/tim/TContext.java +++ b/src/net/sourceforge/plantuml/tim/TContext.java @@ -35,21 +35,17 @@ package net.sourceforge.plantuml.tim; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; import java.io.Reader; -import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import net.sourceforge.plantuml.FileSystem; -import net.sourceforge.plantuml.Log; import net.sourceforge.plantuml.OptionFlags; import net.sourceforge.plantuml.StringLocated; import net.sourceforge.plantuml.command.CommandExecutionResult; @@ -58,26 +54,50 @@ import net.sourceforge.plantuml.preproc.FileWithSuffix; import net.sourceforge.plantuml.preproc.ImportedFiles; import net.sourceforge.plantuml.preproc.ReadLine; import net.sourceforge.plantuml.preproc.ReadLineReader; +import net.sourceforge.plantuml.preproc.StartDiagramExtractReader; +import net.sourceforge.plantuml.preproc.Sub2; +import net.sourceforge.plantuml.preproc.UncommentReadLine; import net.sourceforge.plantuml.preproc2.PreprocessorInclude; +import net.sourceforge.plantuml.preproc2.PreprocessorIncludeStrategy; +import net.sourceforge.plantuml.preproc2.ReadLineQuoteComment; import net.sourceforge.plantuml.tim.expression.Knowledge; import net.sourceforge.plantuml.tim.expression.TValue; +import net.sourceforge.plantuml.tim.stdlib.AlwaysFalse; +import net.sourceforge.plantuml.tim.stdlib.AlwaysTrue; +import net.sourceforge.plantuml.tim.stdlib.CallUserFunction; import net.sourceforge.plantuml.tim.stdlib.DateFunction; import net.sourceforge.plantuml.tim.stdlib.Dirpath; import net.sourceforge.plantuml.tim.stdlib.FileExists; import net.sourceforge.plantuml.tim.stdlib.Filename; +import net.sourceforge.plantuml.tim.stdlib.FunctionExists; +import net.sourceforge.plantuml.tim.stdlib.GetVariableValue; import net.sourceforge.plantuml.tim.stdlib.Getenv; +import net.sourceforge.plantuml.tim.stdlib.IntVal; +import net.sourceforge.plantuml.tim.stdlib.InvokeVoidFunction; +import net.sourceforge.plantuml.tim.stdlib.LogicalNot; +import net.sourceforge.plantuml.tim.stdlib.SetVariableValue; import net.sourceforge.plantuml.tim.stdlib.Strlen; import net.sourceforge.plantuml.tim.stdlib.Strpos; import net.sourceforge.plantuml.tim.stdlib.Substr; +import net.sourceforge.plantuml.tim.stdlib.VariableExists; public class TContext { - private final ArrayList result = new ArrayList(); + private final List result = new ArrayList(); + private final List debug = new ArrayList(); private final Map functions2 = new HashMap(); + private final Set functionsFinal = new HashSet(); private final Trie functions3 = new Trie(); - private final ImportedFiles importedFiles; + private ImportedFiles importedFiles; + private final String charset; private TFunctionImpl pendingFunction; + private Sub2 pendingSub; + private boolean inLongComment; + private final Map subs = new HashMap(); + + // private final Set usedFiles = new HashSet(); + private final Set filesUsedCurrent = new HashSet(); private void addStandardFunctions(Defines defines) { addFunction(new Strlen()); @@ -88,11 +108,30 @@ public class TContext { addFunction(new Filename(defines)); addFunction(new DateFunction()); addFunction(new Strpos()); + addFunction(new InvokeVoidFunction()); + addFunction(new AlwaysFalse()); + addFunction(new AlwaysTrue()); + addFunction(new LogicalNot()); + addFunction(new FunctionExists()); + addFunction(new VariableExists()); + addFunction(new CallUserFunction()); + addFunction(new SetVariableValue()); + addFunction(new GetVariableValue()); + addFunction(new IntVal()); + // !exit + // !log + // %min + // %max + // Regexp + // %plantuml_version + // %time + // %trim + // %str_replace } - - public TContext(ImportedFiles importedFiles, Defines defines) { + public TContext(ImportedFiles importedFiles, Defines defines, String charset) { this.importedFiles = importedFiles; + this.charset = charset; this.addStandardFunctions(defines); } @@ -109,7 +148,7 @@ public class TContext { }; } - private TFunction getFunctionSmart(TFunctionSignature searched) { + public TFunction getFunctionSmart(TFunctionSignature searched) { final TFunction func = functions2.get(searched); if (func != null) { return func; @@ -125,69 +164,142 @@ public class TContext { return null; } - public CommandExecutionResult executeOneLine(TMemory memory, TLineType type, StringLocated s, TFunctionType fromType) { + public void executeOneLine(TMemory memory, TLineType type, StringLocated s, TFunctionType fromType) + throws EaterException { + + this.debug.add(s); + assert type == TLineType.getFromLine(s.getString()); + + if (this.inLongComment == false && type == TLineType.STARTSUB) { + if (pendingSub != null) { + throw new EaterException("Cannot nest sub"); + } + final EaterStartsub eater = new EaterStartsub(s.getStringTrimmed()); + eater.execute(this, memory); + this.pendingSub = new Sub2(eater.getSubname()); + this.subs.put(eater.getSubname(), this.pendingSub); + return; + } + if (this.inLongComment == false && type == TLineType.ENDSUB) { + if (pendingSub == null) { + throw new EaterException("No corresponding !startsub"); + } + final Sub2 newly = this.pendingSub; + this.pendingSub = null; + this.runSub(memory, newly); + return; + } + if (this.inLongComment == false && type == TLineType.INCLUDESUB) { + this.executeIncludesub(memory, s); + return; + } + + if (pendingSub != null) { + pendingSub.add(s); + return; + } + if (this.getPendingFunction() != null) { - if (type == TLineType.END_FUNCTION) { + if (this.inLongComment == false && type == TLineType.END_FUNCTION) { this.executeEndfunction(); } else { this.getPendingFunction().addBody(s); } - return CommandExecutionResult.ok(); - } - assert type == TLineType.getFromLine(s.getString()); - try { - - if (type == TLineType.ASSERT) { - return this.executeAssert(memory, s.getStringTrimmed()); - } else if (type == TLineType.IF) { - return this.executeIf(memory, s.getStringTrimmed()); - } else if (type == TLineType.IFDEF) { - return this.executeIfdef(memory, s.getStringTrimmed()); - } else if (type == TLineType.IFNDEF) { - return this.executeIfndef(memory, s.getStringTrimmed()); - } else if (type == TLineType.ELSE) { - return this.executeElse(memory, s.getStringTrimmed()); - } else if (type == TLineType.ENDIF) { - return this.executeEndif(memory, s.getStringTrimmed()); - } - - final ConditionalContext conditionalContext = memory.peekConditionalContext(); - if (conditionalContext != null && conditionalContext.conditionIsOkHere() == false) { - return CommandExecutionResult.ok(); - } - - if (fromType != TFunctionType.RETURN && type == TLineType.PLAIN) { - return this.addPlain(memory, s); - } else if (fromType == TFunctionType.RETURN && type == TLineType.RETURN) { - // Actually, ignore because we are in a if - return CommandExecutionResult.ok(); - } else if (type == TLineType.LEGACY_DEFINE) { - return this.executeLegacyDefine(memory, s); - } else if (type == TLineType.LEGACY_DEFINELONG) { - return this.executeLegacyDefineLong(memory, s); - } else if (type == TLineType.AFFECTATION_DEFINE) { - return this.executeAffectationDefine(memory, s.getStringTrimmed()); - } else if (type == TLineType.AFFECTATION) { - return this.executeAffectation(memory, s.getStringTrimmed()); - } else if (fromType == null && type == TLineType.DECLARE_FUNCTION) { - return this.executeDeclareFunction(memory, s); - } else if (fromType == null && type == TLineType.END_FUNCTION) { - return CommandExecutionResult.error("error endfunc"); - } else if (type == TLineType.INCLUDE) { - return this.executeInclude(memory, s); - } else if (type == TLineType.IMPORT) { - return this.executeImport(memory, s); - } else { - throw new UnsupportedOperationException("type=" + type + " fromType=" + fromType); - } - } catch (EaterException e) { - e.printStackTrace(); - return CommandExecutionResult.error(e.getMessage()); + return; } + if (this.inLongComment && s.getStringTrimmed().endsWith("'/")) { + this.inLongComment = false; + return; + } + + if (type == TLineType.COMMENT_LONG_START) { + this.inLongComment = true; + return; + } + if (this.inLongComment) { + return; + } + if (type == TLineType.COMMENT_SIMPLE) { + return; + } + s = s.removeInnerComment(); + + if (type == TLineType.IF) { + this.executeIf(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.IFDEF) { + this.executeIfdef(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.IFNDEF) { + this.executeIfndef(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.ELSE) { + this.executeElse(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.ELSEIF) { + this.executeElseIf(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.ENDIF) { + this.executeEndif(memory, s.getStringTrimmed()); + return; + } + + final ConditionalContext conditionalContext = memory.peekConditionalContext(); + if (conditionalContext != null && memory.areAllIfOk() == false) { + return; + } + + if (type == TLineType.DUMP_MEMORY) { + this.executeDumpMemory(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.ASSERT) { + this.executeAssert(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.UNDEF) { + this.executeUndef(memory, s); + return; + } else if (fromType != TFunctionType.RETURN && type == TLineType.PLAIN) { + this.addPlain(memory, s); + return; + } else if (fromType == TFunctionType.RETURN && type == TLineType.RETURN) { + // Actually, ignore because we are in a if + return; + } else if (type == TLineType.LEGACY_DEFINE) { + this.executeLegacyDefine(memory, s); + return; + } else if (type == TLineType.LEGACY_DEFINELONG) { + this.executeLegacyDefineLong(memory, s); + return; + } else if (type == TLineType.AFFECTATION_DEFINE) { + this.executeAffectationDefine(memory, s.getStringTrimmed()); + return; + } else if (type == TLineType.AFFECTATION) { + this.executeAffectation(memory, s.getStringTrimmed()); + return; + } else if (fromType == null && type == TLineType.DECLARE_FUNCTION) { + this.executeDeclareFunction(memory, s); + return; + } else if (fromType == null && type == TLineType.END_FUNCTION) { + CommandExecutionResult.error("error endfunc"); + return; + } else if (type == TLineType.INCLUDE) { + this.executeInclude(memory, s); + return; + } else if (type == TLineType.IMPORT) { + this.executeImport(memory, s); + return; + } else if (type == TLineType.LOG) { + this.executeLog(memory, s); + return; + } else { + // Thread.dumpStack(); + throw new EaterException("Parsing Error"); + // throw new UnsupportedOperationException("type=" + type + " fromType=" + fromType); + } } - private CommandExecutionResult addPlain(TMemory memory, StringLocated s) throws EaterException { + private void addPlain(TMemory memory, StringLocated s) throws EaterException { StringLocated tmp = applyFunctionsAndVariables(memory, s); if (tmp != null) { if (pendingAdd != null) { @@ -196,109 +308,130 @@ public class TContext { } result.add(tmp); } - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeAffectationDefine(TMemory memory, String s) throws EaterException { + private void executeAffectationDefine(TMemory memory, String s) throws EaterException { new EaterAffectationDefine(s).execute(this, memory); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeAffectation(TMemory memory, String s) throws EaterException { + private void executeAffectation(TMemory memory, String s) throws EaterException { new EaterAffectation(s).execute(this, memory); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeIf(TMemory memory, String s) throws EaterException { + private void executeIf(TMemory memory, String s) throws EaterException { final EaterIf condition = new EaterIf(s); condition.execute(this, memory); final boolean isTrue = condition.isTrue(); memory.addConditionalContext(ConditionalContext.fromValue(isTrue)); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeAssert(TMemory memory, String s) throws EaterException { + private void executeElseIf(TMemory memory, String s) throws EaterException { + final ConditionalContext poll = memory.peekConditionalContext(); + if (poll == null) { + throw new EaterException("No if related to this else"); + } + + poll.enteringElseIf(); + if (poll.hasBeenBurn() == false) { + final EaterElseIf condition = new EaterElseIf(s); + condition.execute(this, memory); + final boolean isTrue = condition.isTrue(); + if (isTrue) { + poll.nowInSomeElseIf(); + } + } + } + + private void executeDumpMemory(TMemory memory, String s) throws EaterException { + final EaterDumpMemory condition = new EaterDumpMemory(s); + condition.execute(this, memory); + } + + private void executeAssert(TMemory memory, String s) throws EaterException { final EaterAssert condition = new EaterAssert(s); condition.execute(this, memory); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeIfdef(TMemory memory, String s) throws EaterException { + private void executeIfdef(TMemory memory, String s) throws EaterException { final EaterIfdef condition = new EaterIfdef(s); condition.execute(this, memory); final boolean isTrue = condition.isTrue(this, memory); memory.addConditionalContext(ConditionalContext.fromValue(isTrue)); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeIfndef(TMemory memory, String s) throws EaterException { + private void executeIfndef(TMemory memory, String s) throws EaterException { final EaterIfndef condition = new EaterIfndef(s); condition.execute(this, memory); final boolean isTrue = condition.isTrue(this, memory); memory.addConditionalContext(ConditionalContext.fromValue(isTrue)); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeElse(TMemory memory, String s) throws EaterException { + private void executeElse(TMemory memory, String s) throws EaterException { final ConditionalContext poll = memory.peekConditionalContext(); if (poll == null) { - return CommandExecutionResult.error("No if related to this else"); + throw new EaterException("No if related to this else"); } poll.nowInElse(); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeEndif(TMemory memory, String s) throws EaterException { + private void executeEndif(TMemory memory, String s) throws EaterException { final ConditionalContext poll = memory.pollConditionalContext(); if (poll == null) { - return CommandExecutionResult.error("No if related to this endif"); + throw new EaterException("No if related to this endif"); } - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeDeclareFunction(TMemory memory, StringLocated s) throws EaterException { + private void executeDeclareFunction(TMemory memory, StringLocated s) throws EaterException { if (this.pendingFunction != null) { throw new EaterException("already0068"); } final EaterDeclareFunction declareFunction = new EaterDeclareFunction(s); declareFunction.execute(this, memory); - if (functions2.containsKey(declareFunction.getFunction().getSignature())) { - throw new EaterException("already0046"); + final boolean finalFlag = declareFunction.getFinalFlag(); + final TFunctionSignature declaredSignature = declareFunction.getFunction().getSignature(); + final TFunction previous = functions2.get(declaredSignature); + if (previous != null && (finalFlag || functionsFinal.contains(declaredSignature))) { + throw new EaterException("This function is already defined"); + } + if (finalFlag) { + functionsFinal.add(declaredSignature); } if (declareFunction.getFunction().hasBody()) { addFunction(declareFunction.getFunction()); } else { this.pendingFunction = declareFunction.getFunction(); } - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeLegacyDefine(TMemory memory, StringLocated s) throws EaterException { + private void executeUndef(TMemory memory, StringLocated s) throws EaterException { + final EaterUndef undef = new EaterUndef(s); + undef.execute(this, memory); + } + + private void executeLegacyDefine(TMemory memory, StringLocated s) throws EaterException { if (this.pendingFunction != null) { throw new EaterException("already0048"); } final EaterLegacyDefine legacyDefine = new EaterLegacyDefine(s); legacyDefine.execute(this, memory); final TFunction function = legacyDefine.getFunction(); - if (functions2.containsKey(function.getSignature())) { - throw new EaterException("already0047"); - } + // if (functions2.containsKey(function.getSignature())) { + // throw new EaterException("already0047"); + // } this.functions2.put(function.getSignature(), function); this.functions3.add(function.getSignature().getFunctionName() + "("); - return CommandExecutionResult.ok(); } - private CommandExecutionResult executeLegacyDefineLong(TMemory memory, StringLocated s) throws EaterException { + private void executeLegacyDefineLong(TMemory memory, StringLocated s) throws EaterException { if (this.pendingFunction != null) { throw new EaterException("already0068"); } final EaterLegacyDefineLong legacyDefineLong = new EaterLegacyDefineLong(s); legacyDefineLong.execute(this, memory); - if (functions2.containsKey(legacyDefineLong.getFunction().getSignature())) { - throw new EaterException("already0066"); - } + // if (functions2.containsKey(legacyDefineLong.getFunction().getSignature())) { + // throw new EaterException("already0066"); + // } this.pendingFunction = legacyDefineLong.getFunction(); - return CommandExecutionResult.ok(); } private StringLocated applyFunctionsAndVariables(TMemory memory, StringLocated located) throws EaterException { @@ -333,29 +466,32 @@ public class TContext { final EaterFunctionCall call = new EaterFunctionCall(sub, isLegacyDefine(presentFunction), isUnquoted(presentFunction)); call.execute(this, memory); - final TFunction function = getFunctionSmart(new TFunctionSignature(presentFunction, call.getValues2() + final TFunction function = getFunctionSmart(new TFunctionSignature(presentFunction, call.getValues() .size())); if (function == null) { throw new EaterException("Function not found " + presentFunction); } if (function.getFunctionType() == TFunctionType.VOID) { - function.executeVoid(this, sub, memory); + executeVoid3(memory, sub, function); return null; } if (function.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) { this.pendingAdd = s.substring(0, i); - function.executeVoid(this, sub, memory); + executeVoid3(memory, sub, function); return null; } assert function.getFunctionType() == TFunctionType.RETURN || function.getFunctionType() == TFunctionType.LEGACY_DEFINE; - final TValue functionReturn = function.executeReturn(this, memory, call.getValues2()); + final TValue functionReturn = function.executeReturn(this, memory, call.getValues()); result.append(functionReturn.toString()); i += call.getCurrentPosition() - 1; continue; } final String presentVariable = getVarnameAt(memory, s, i); if (presentVariable != null) { + if (result.toString().endsWith("##")) { + result.setLength(result.length() - 2); + } result.append(memory.getVariable(presentVariable).getValue2().toString()); i += presentVariable.length() - 1; if (i + 2 < s.length() && s.charAt(i + 1) == '#' && s.charAt(i + 2) == '#') { @@ -368,7 +504,11 @@ public class TContext { return result.toString(); } - private CommandExecutionResult executeImport(TMemory memory, StringLocated s) throws EaterException { + private void executeVoid3(TMemory memory, String s, TFunction function) throws EaterException { + function.executeVoid(this, memory, s); + } + + private void executeImport(TMemory memory, StringLocated s) throws EaterException { final EaterImport _import = new EaterImport(s.getStringTrimmed()); _import.execute(this, memory); @@ -377,20 +517,63 @@ public class TContext { applyFunctionsAndVariables(memory, _import.getLocation())); if (file.exists() && file.isDirectory() == false) { importedFiles.add(file); - return CommandExecutionResult.ok(); + return; } } catch (IOException e) { e.printStackTrace(); - return CommandExecutionResult.error("Cannot import " + e.getMessage()); + throw new EaterException("Cannot import " + e.getMessage()); } - return CommandExecutionResult.error("Cannot import"); + throw new EaterException("Cannot import"); } - private CommandExecutionResult executeInclude(TMemory memory, StringLocated s) throws EaterException { + private void executeLog(TMemory memory, StringLocated s) throws EaterException { + final EaterLog log = new EaterLog(s.getStringTrimmed()); + log.execute(this, memory); + } + + private void executeIncludesub(TMemory memory, StringLocated s) throws EaterException { + final EaterIncludesub include = new EaterIncludesub(s.getStringTrimmed()); + include.execute(this, memory); + final String location = include.getLocation(); + final int idx = location.indexOf('!'); + Sub2 sub = null; + if (OptionFlags.ALLOW_INCLUDE && idx != -1) { + final String filename = location.substring(0, idx); + final String blocname = location.substring(idx + 1); + try { + final FileWithSuffix f2 = new FileWithSuffix(importedFiles, filename, null); + if (f2.fileOk()) { + final Reader reader = f2.getReader(charset); + ReadLine readerline = ReadLineReader.create(reader, location, s.getLocation()); + readerline = new UncommentReadLine(readerline); + readerline = new ReadLineQuoteComment(true).applyFilter(readerline); + sub = Sub2.fromFile(readerline, blocname, this, memory); + } + } catch (IOException e) { + e.printStackTrace(); + throw new EaterException("cannot include " + e); + } + } else { + sub = subs.get(location); + } + if (sub == null) { + throw new EaterException("cannot include " + location); + } + runSub(memory, sub); + } + + private void runSub(TMemory memory, final Sub2 sub) throws EaterException { + for (StringLocated sl : sub.lines()) { + executeOneLine(memory, TLineType.getFromLine(sl.getString()), sl, null); + } + } + + private void executeInclude(TMemory memory, StringLocated s) throws EaterException { final EaterInclude include = new EaterInclude(s.getStringTrimmed()); include.execute(this, memory); String location = include.getLocation(); + final PreprocessorIncludeStrategy strategy = include.getPreprocessorIncludeStrategy(); final int idx = location.lastIndexOf('!'); String suf = null; if (idx != -1) { @@ -398,13 +581,12 @@ public class TContext { location = location.substring(0, idx); } - final String charset = null; - ReadLine reader2 = null; + ImportedFiles saveImportedFiles = null; try { if (location.startsWith("http://") || location.startsWith("https://")) { final URL url = new URL(location); - reader2 = PreprocessorInclude.getReaderIncludeUrl(url, s, suf, charset); + reader2 = PreprocessorInclude.getReaderIncludeUrl2(url, s, suf, charset); } if (location.startsWith("<") && location.endsWith(">")) { @@ -412,40 +594,48 @@ public class TContext { } else if (OptionFlags.ALLOW_INCLUDE) { final FileWithSuffix f2 = new FileWithSuffix(importedFiles, location, suf); if (f2.fileOk()) { - final Reader reader = f2.getReader(charset); - reader2 = ReadLineReader.create(reader, location, s.getLocation()); + if (strategy == PreprocessorIncludeStrategy.DEFAULT && filesUsedCurrent.contains(f2)) { + return; + } + if (strategy == PreprocessorIncludeStrategy.ONCE && filesUsedCurrent.contains(f2)) { + throw new EaterException("This file has already been included"); + } + + if (StartDiagramExtractReader.containsStartDiagram(f2, s, charset)) { + reader2 = StartDiagramExtractReader.build(f2, s, charset); + } else { + final Reader reader = f2.getReader(charset); + reader2 = ReadLineReader.create(reader, location, s.getLocation()); + } + saveImportedFiles = this.importedFiles; + this.importedFiles = this.importedFiles.withCurrentDir(f2.getParentFile()); + assert reader2 != null; + filesUsedCurrent.add(f2); + // filesUsedGlobal.add(f2); } } if (reader2 != null) { - do { - final StringLocated sl = reader2.readLine(); - if (sl == null) { - return CommandExecutionResult.ok(); + reader2 = new ReadLineQuoteComment(true).applyFilter(reader2); + try { + do { + final StringLocated sl = reader2.readLine(); + if (sl == null) { + return; + } + executeOneLine(memory, TLineType.getFromLine(sl.getString()), sl, null); + } while (true); + } finally { + if (saveImportedFiles != null) { + this.importedFiles = saveImportedFiles; } - final CommandExecutionResult exe = executeOneLine(memory, TLineType.getFromLine(sl.getString()), - sl, null); - if (exe.isOk() == false) { - return exe; - } - } while (true); + } } } catch (IOException e) { e.printStackTrace(); - return CommandExecutionResult.error("cannot include " + e); + throw new EaterException("cannot include " + e); } - System.err.println("location=" + location); - return CommandExecutionResult.error("cannot include"); - } - - private Reader getReader(File file) throws FileNotFoundException, UnsupportedEncodingException { - final String charset = null; - if (charset == null) { - Log.info("Using default charset"); - return new InputStreamReader(new FileInputStream(file)); - } - Log.info("Using charset " + charset); - return new InputStreamReader(new FileInputStream(file), charset); + throw new EaterException("cannot include " + location); } public boolean isLegacyDefine(String functionName) { @@ -487,17 +677,6 @@ public class TContext { return null; } - private static String getVarnameAtOld(TMemory memory, String s, int pos) { - for (String varname : memory.variablesNames()) { - if (s.substring(pos).startsWith(varname)) - if (pos + varname.length() == s.length() - || Character.isLetterOrDigit(s.charAt(pos + varname.length())) == false) { - return varname; - } - } - return null; - } - private String getFunctionNameAt(String s, int pos) { final String fname = functions3.getLonguestMatchStartingIn(s.substring(pos)); if (fname.length() == 0) { @@ -506,22 +685,12 @@ public class TContext { return fname.substring(0, fname.length() - 1); } - private String getFunctionNameAtOld(String s, int pos) { - for (TFunctionSignature fname : functions2.keySet()) { - if (s.substring(pos).startsWith(fname.getFunctionName() + "(")) { - return fname.getFunctionName(); - } - } - return null; - } - public List getResult() { - return Collections.unmodifiableList(result); + return result; } - public List getResultWithError(StringLocated error) { - result.add(error); - return Collections.unmodifiableList(result); + public List getDebug() { + return debug; } public final TFunctionImpl getPendingFunction() { @@ -529,6 +698,9 @@ public class TContext { } private void addFunction(TFunction func) { + if (func.getFunctionType() == TFunctionType.LEGACY_DEFINELONG) { + ((TFunctionImpl) func).finalizeEnddefinelong(); + } this.functions2.put(func.getSignature(), func); this.functions3.add(func.getSignature().getFunctionName() + "("); } diff --git a/src/net/sourceforge/plantuml/tim/TFunction.java b/src/net/sourceforge/plantuml/tim/TFunction.java index beb645cce..1bffbe0c4 100644 --- a/src/net/sourceforge/plantuml/tim/TFunction.java +++ b/src/net/sourceforge/plantuml/tim/TFunction.java @@ -46,10 +46,12 @@ public interface TFunction { public TFunctionType getFunctionType(); - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException; + public void executeVoid(TContext context, TMemory memory, String s) throws EaterException; public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException; + public void executeVoidInternal(TContext context, TMemory memory, List args) throws EaterException; + public boolean isUnquoted(); } diff --git a/src/net/sourceforge/plantuml/tim/TFunctionImpl.java b/src/net/sourceforge/plantuml/tim/TFunctionImpl.java index 74b8be87d..6203523e5 100644 --- a/src/net/sourceforge/plantuml/tim/TFunctionImpl.java +++ b/src/net/sourceforge/plantuml/tim/TFunctionImpl.java @@ -35,10 +35,11 @@ package net.sourceforge.plantuml.tim; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import net.sourceforge.plantuml.StringLocated; -import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.tim.expression.TValue; public class TFunctionImpl implements TFunction { @@ -80,30 +81,31 @@ public class TFunctionImpl implements TFunction { } } - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - if (functionType != TFunctionType.VOID && functionType != TFunctionType.LEGACY_DEFINELONG) { - throw new IllegalStateException(); - } + public void executeVoid(TContext context, TMemory memory, String s) throws EaterException { final EaterFunctionCall call = new EaterFunctionCall(s, context.isLegacyDefine(signature.getFunctionName()), unquoted); call.execute(context, memory); - final TMemory copy = getNewMemory(memory, call.getValues2()); - for (StringLocated sl : body) { - final CommandExecutionResult exe = context.executeOneLine(copy, TLineType.getFromLine(sl.getString()), sl, - TFunctionType.VOID); - if (exe.isOk() == false) { - throw new EaterException(exe.getError()); - } - } + final List args = call.getValues(); + executeVoidInternal(context, memory, args); + } + public void executeVoidInternal(TContext context, TMemory memory, List args) throws EaterException { + if (functionType != TFunctionType.VOID && functionType != TFunctionType.LEGACY_DEFINELONG) { + throw new IllegalStateException(); + } + final TMemory copy = getNewMemory(memory, args); + for (StringLocated sl : body) { + context.executeOneLine(copy, TLineType.getFromLine(sl.getString()), sl, TFunctionType.VOID); + } } private TMemory getNewMemory(TMemory memory, List values) { - final TMemory copy = memory.forkFromGlobal(); + final Map foo = new HashMap(); for (int i = 0; i < args.size(); i++) { final TValue tmp = i < values.size() ? values.get(i) : args.get(i).getOptionalDefaultValue(); - copy.put(args.get(i).getName(), new TVariable(tmp)); + foo.put(args.get(i).getName(), new TVariable(tmp)); } + final TMemory copy = memory.forkFromGlobal(foo); return copy; } @@ -126,10 +128,7 @@ public class TFunctionImpl implements TFunction { // System.err.println("s3=" + eaterReturn.getValue2()); return eaterReturn.getValue2(); } - final CommandExecutionResult exe = context.executeOneLine(copy, lineType, sl, TFunctionType.RETURN); - if (exe.isOk() == false) { - throw new EaterException(exe.getError()); - } + context.executeOneLine(copy, lineType, sl, TFunctionType.RETURN); } throw new EaterException("no return"); // return TValue.fromString("(NONE)"); @@ -141,6 +140,9 @@ public class TFunctionImpl implements TFunction { } final TMemory copy = getNewMemory(memory, args); final String tmp = context.applyFunctionsAndVariables(copy, legacyDefinition); + if (tmp == null) { + return TValue.fromString(""); + } return TValue.fromString(tmp); // eaterReturn.execute(context, copy); // // System.err.println("s3=" + eaterReturn.getValue2()); @@ -171,4 +173,14 @@ public class TFunctionImpl implements TFunction { return body.size() > 0; } + public void finalizeEnddefinelong() { + if (functionType != TFunctionType.LEGACY_DEFINELONG) { + throw new UnsupportedOperationException(); + } + if (body.size() == 1) { + this.functionType = TFunctionType.LEGACY_DEFINE; + this.legacyDefinition = body.get(0).getString(); + } + } + } diff --git a/src/net/sourceforge/plantuml/tim/TLineType.java b/src/net/sourceforge/plantuml/tim/TLineType.java index d8c6b3fc6..d7b22fc99 100644 --- a/src/net/sourceforge/plantuml/tim/TLineType.java +++ b/src/net/sourceforge/plantuml/tim/TLineType.java @@ -36,54 +36,84 @@ package net.sourceforge.plantuml.tim; public enum TLineType { - PLAIN, AFFECTATION_DEFINE, AFFECTATION, ASSERT, IF, IFDEF, IFNDEF, ELSE, ENDIF, DECLARE_FUNCTION, END_FUNCTION, RETURN, LEGACY_DEFINE, LEGACY_DEFINELONG, INCLUDE, IMPORT; + PLAIN, AFFECTATION_DEFINE, AFFECTATION, ASSERT, IF, IFDEF, UNDEF, IFNDEF, ELSE, ELSEIF, ENDIF, DECLARE_FUNCTION, END_FUNCTION, RETURN, LEGACY_DEFINE, LEGACY_DEFINELONG, INCLUDE, IMPORT, STARTSUB, ENDSUB, INCLUDESUB, LOG, DUMP_MEMORY, COMMENT_SIMPLE, COMMENT_LONG_START; public static TLineType getFromLine(String s) { - if (s.matches("^!define\\s+[\\p{L}_][\\p{L}_0-9]*\\(.*")) { + if (s.matches("^\\s*!define\\s+[\\p{L}_][\\p{L}_0-9]*\\(.*")) { return LEGACY_DEFINE; } - if (s.matches("^!definelong\\s+[\\p{L}_][\\p{L}_0-9]*\\b.*")) { + if (s.matches("^\\s*!definelong\\s+[\\p{L}_][\\p{L}_0-9]*\\b.*")) { return LEGACY_DEFINELONG; } - if (s.matches("^!define\\s+[\\p{L}_][\\p{L}_0-9]*\\b.*")) { + if (s.matches("^\\s*!define\\s+[\\p{L}_][\\p{L}_0-9]*\\b.*")) { return AFFECTATION_DEFINE; } - if (s.matches("^!\\s*\\$?[\\p{L}_][\\p{L}_0-9]*\\s*=.*")) { + if (s.matches("^\\s*!\\s*(local|global)?\\s*\\$?[\\p{L}_][\\p{L}_0-9]*\\s*=.*")) { return AFFECTATION; } - if (s.matches("^!ifdef\\s+.*")) { + if (s.matches("^\\s*'.*")) { + return COMMENT_SIMPLE; + } + if (s.matches("^\\s*/'.*'/\\s*$")) { + return COMMENT_SIMPLE; + } + if (s.matches("^\\s*/'.*") && s.contains("'/") == false) { + return COMMENT_LONG_START; + } + if (s.matches("^\\s*!ifdef\\s+.*")) { return IFDEF; } - if (s.matches("^!ifndef\\s+.*")) { + if (s.matches("^\\s*!undef\\s+.*")) { + return UNDEF; + } + if (s.matches("^\\s*!ifndef\\s+.*")) { return IFNDEF; } - if (s.matches("^!assert\\s+.*")) { + if (s.matches("^\\s*!assert\\s+.*")) { return ASSERT; } - if (s.matches("^!if\\s+.*")) { + if (s.matches("^\\s*!if\\s+.*")) { return IF; } - if (s.matches("^!(unquoted\\s)?function\\s+\\$?[\\p{L}_][\\p{L}_0-9]*.*")) { + if (s.matches("^\\s*!(unquoted\\s|final\\s)*function\\s+\\$?[\\p{L}_][\\p{L}_0-9]*.*")) { return DECLARE_FUNCTION; } - if (s.matches("^!else\\b.*")) { + if (s.matches("^\\s*!else\\b.*")) { return ELSE; } - if (s.matches("^!endif\\b.*")) { + if (s.matches("^\\s*!elseif\\b.*")) { + return ELSEIF; + } + if (s.matches("^\\s*!endif\\b.*")) { return ENDIF; } - if (s.matches("^!(endfunction|enddefinelong)\\b.*")) { + if (s.matches("^\\s*!(endfunction|enddefinelong)\\b.*")) { return END_FUNCTION; } - if (s.matches("^!return\\b.*")) { + if (s.matches("^\\s*!return\\b.*")) { return RETURN; } - if (s.matches("^!(include|includeurl)\\b.*")) { + if (s.matches("^\\s*!(include|includeurl|include_many|include_once)\\b.*")) { return INCLUDE; } - if (s.matches("^!(import)\\b.*")) { + if (s.matches("^\\s*!(import)\\b.*")) { return IMPORT; } + if (s.matches("^\\s*!startsub\\s+.*")) { + return STARTSUB; + } + if (s.matches("^\\s*!endsub\\b.*")) { + return ENDSUB; + } + if (s.matches("^\\s*!includesub\\b.*")) { + return INCLUDESUB; + } + if (s.matches("^\\s*!(log)\\b.*")) { + return LOG; + } + if (s.matches("^\\s*!(dump_memory)\\b.*")) { + return DUMP_MEMORY; + } return PLAIN; } diff --git a/src/net/sourceforge/plantuml/tim/TMemory.java b/src/net/sourceforge/plantuml/tim/TMemory.java index 3c9e50a83..048946a5a 100644 --- a/src/net/sourceforge/plantuml/tim/TMemory.java +++ b/src/net/sourceforge/plantuml/tim/TMemory.java @@ -34,13 +34,16 @@ */ package net.sourceforge.plantuml.tim; +import java.util.Map; import java.util.Set; public interface TMemory { public TVariable getVariable(String varname); - public void put(String varname, TVariable value); + public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException; + + public void removeVariable(String varname); public boolean isEmpty(); @@ -48,11 +51,15 @@ public interface TMemory { public Trie variablesNames3(); - public TMemory forkFromGlobal(); + public TMemory forkFromGlobal(Map input); public ConditionalContext peekConditionalContext(); + public boolean areAllIfOk(); + public void addConditionalContext(ConditionalContext context); public ConditionalContext pollConditionalContext(); + + public void dumpDebug(String message); } diff --git a/src/net/sourceforge/plantuml/tim/TMemoryGlobal.java b/src/net/sourceforge/plantuml/tim/TMemoryGlobal.java index e1d8ed0af..5ec85c832 100644 --- a/src/net/sourceforge/plantuml/tim/TMemoryGlobal.java +++ b/src/net/sourceforge/plantuml/tim/TMemoryGlobal.java @@ -37,7 +37,12 @@ package net.sourceforge.plantuml.tim; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; + +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.tim.expression.TValue; public class TMemoryGlobal extends ConditionalContexts implements TMemory { @@ -48,11 +53,35 @@ public class TMemoryGlobal extends ConditionalContexts implements TMemory { return this.globalVariables.get(varname); } - public void put(String varname, TVariable value) { + public void dumpDebug(String message) { + Log.error("[MemGlobal] Start of memory_dump " + message); + dumpMemoryInternal(); + Log.error("[MemGlobal] End of memory_dump"); + } + + void dumpMemoryInternal() { + Log.error("[MemGlobal] Number of variable(s) : " + globalVariables.size()); + for (Entry ent : new TreeMap(globalVariables).entrySet()) { + final String name = ent.getKey(); + final TValue value = ent.getValue().getValue2(); + Log.error("[MemGlobal] " + name + " = " + value); + } + } + + public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException { + Log.info("[MemGlobal] Setting " + varname); + if (scope == TVariableScope.LOCAL) { + throw new EaterException("Cannot use local variable here"); + } this.globalVariables.put(varname, value); this.variables.add(varname); } + public void removeVariable(String varname) { + this.globalVariables.remove(varname); + this.variables.remove(varname); + } + public boolean isEmpty() { return globalVariables.isEmpty(); } @@ -65,8 +94,8 @@ public class TMemoryGlobal extends ConditionalContexts implements TMemory { return variables; } - public TMemory forkFromGlobal() { - return new TMemoryLocal(this); + public TMemory forkFromGlobal(Map input) { + return new TMemoryLocal(this, input); } } diff --git a/src/net/sourceforge/plantuml/tim/TMemoryLocal.java b/src/net/sourceforge/plantuml/tim/TMemoryLocal.java index 441919d7f..8f4082333 100644 --- a/src/net/sourceforge/plantuml/tim/TMemoryLocal.java +++ b/src/net/sourceforge/plantuml/tim/TMemoryLocal.java @@ -37,60 +37,109 @@ package net.sourceforge.plantuml.tim; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.tim.expression.TValue; public class TMemoryLocal extends ConditionalContexts implements TMemory { - private final TMemoryGlobal global; + private final TMemoryGlobal memoryGlobal; + private final Map overridenVariables = new HashMap(); private final Map localVariables = new HashMap(); - private Trie variables; - public TMemoryLocal(TMemoryGlobal global) { - this.global = global; + public TMemoryLocal(TMemoryGlobal global, Map input) { + this.memoryGlobal = global; + this.overridenVariables.putAll(input); + } + + public void dumpDebug(String message) { + Log.error("[MemLocal] Start of memory_dump " + message); + memoryGlobal.dumpMemoryInternal(); + Log.error("[MemLocal] Number of overriden variable(s) : " + overridenVariables.size()); + for (Entry ent : new TreeMap(overridenVariables).entrySet()) { + final String name = ent.getKey(); + final TValue value = ent.getValue().getValue2(); + Log.error("[MemLocal] " + name + " = " + value); + } + Log.error("[MemLocal] Number of local variable(s) : " + localVariables.size()); + for (Entry ent : new TreeMap(localVariables).entrySet()) { + final String name = ent.getKey(); + final TValue value = ent.getValue().getValue2(); + Log.error("[MemLocal] " + name + " = " + value); + } + Log.error("[MemGlobal] End of memory_dump"); } - private void initTrie() { - for (String name : global.variablesNames()) { - variables.add(name); + + public void putVariable(String varname, TVariable value, TVariableScope scope) throws EaterException { + if (scope == TVariableScope.GLOBAL) { + memoryGlobal.putVariable(varname, value, scope); + return; + } + if (scope == TVariableScope.LOCAL || overridenVariables.containsKey(varname)) { + this.overridenVariables.put(varname, value); + Log.info("[MemLocal/overrriden] Setting " + varname); + } else if (memoryGlobal.getVariable(varname) != null) { + memoryGlobal.putVariable(varname, value, scope); + } else { + this.localVariables.put(varname, value); + Log.info("[MemLocal/local] Setting " + varname); + } + } + + public void removeVariable(String varname) { + if (overridenVariables.containsKey(varname)) { + this.overridenVariables.remove(varname); + } else if (memoryGlobal.getVariable(varname) != null) { + memoryGlobal.removeVariable(varname); + } else { + this.localVariables.remove(varname); } } public TVariable getVariable(String varname) { - final TVariable result = localVariables.get(varname); + TVariable result = overridenVariables.get(varname); if (result != null) { return result; } - return global.getVariable(varname); + result = memoryGlobal.getVariable(varname); + if (result != null) { + return result; + } + result = localVariables.get(varname); + return result; } public Trie variablesNames3() { - if (variables == null) { - return global.variablesNames3(); + final Trie result = new Trie(); + for (String name : overridenVariables.keySet()) { + result.add(name); } - return variables; - } - - public void put(String varname, TVariable value) { - this.localVariables.put(varname, value); - if (this.variables == null) { - this.variables = new Trie(); - initTrie(); + for (String name : memoryGlobal.variablesNames()) { + result.add(name); } - this.variables.add(varname); + for (String name : localVariables.keySet()) { + result.add(name); + } + return result; } public boolean isEmpty() { - return global.isEmpty() && localVariables.isEmpty(); + return memoryGlobal.isEmpty() && localVariables.isEmpty() && overridenVariables.isEmpty(); } public Set variablesNames() { - // final Set result = new HashSet(localVariables.keySet()); - // result.addAll(global.variablesNames()); - // return Collections.unmodifiableSet(result); throw new UnsupportedOperationException(); } - public TMemory forkFromGlobal() { - return new TMemoryLocal(global); + public TMemory forkFromGlobal(Map input) { + return new TMemoryLocal(memoryGlobal, input); } + // public final TMemoryGlobal getGlobalForInternalUseOnly() { + // return memoryGlobal; + // } + } diff --git a/src/net/sourceforge/plantuml/suggest/Variator.java b/src/net/sourceforge/plantuml/tim/TVariableScope.java similarity index 91% rename from src/net/sourceforge/plantuml/suggest/Variator.java rename to src/net/sourceforge/plantuml/tim/TVariableScope.java index b220595f2..80edeccee 100644 --- a/src/net/sourceforge/plantuml/suggest/Variator.java +++ b/src/net/sourceforge/plantuml/tim/TVariableScope.java @@ -5,12 +5,12 @@ * (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 @@ -31,13 +31,10 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim; -public interface Variator { - - String getData(); - void nextStep(); +public enum TVariableScope { + LOCAL, GLOBAL } diff --git a/src/net/sourceforge/plantuml/tim/TimLoader.java b/src/net/sourceforge/plantuml/tim/TimLoader.java index 9323543a5..01e3c59a6 100644 --- a/src/net/sourceforge/plantuml/tim/TimLoader.java +++ b/src/net/sourceforge/plantuml/tim/TimLoader.java @@ -34,11 +34,9 @@ */ package net.sourceforge.plantuml.tim; -import java.util.ArrayList; import java.util.List; import net.sourceforge.plantuml.StringLocated; -import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.preproc.Defines; import net.sourceforge.plantuml.preproc.ImportedFiles; @@ -46,26 +44,45 @@ public class TimLoader { private final TContext context; private final TMemory global = new TMemoryGlobal(); + private boolean preprocessorError; + private List result; - public TimLoader(ImportedFiles importedFiles, Defines defines) { - this.context = new TContext(importedFiles, defines); + public TimLoader(ImportedFiles importedFiles, Defines defines, String charset) { + this.context = new TContext(importedFiles, defines, charset); } - public List load(List input) { - for (StringLocated s : input) { - if (s.getPreprocessorError() != null) { - return new ArrayList(input); - } - } - + public void load(List input) { for (StringLocated s : input) { final TLineType type = TLineType.getFromLine(s.getStringTrimmed()); - final CommandExecutionResult exe = context.executeOneLine(global, type, s, null); - if (exe.isOk() == false) { - return context.getResultWithError(s.withErrorPreprocessor(exe.getError())); + try { + context.executeOneLine(global, type, s, null); + } catch (EaterException e) { + context.getResult().add(s.withErrorPreprocessor(e.getMessage())); + this.result = context.getResult(); + changeLastLine(context.getDebug(), e.getMessage()); + this.preprocessorError = true; + return; } } - return context.getResult(); + this.result = context.getResult(); + } + + private void changeLastLine(List list, String message) { + final int num = list.size() - 1; + final StringLocated last = list.get(num); + list.set(num, last.withErrorPreprocessor(message)); + } + + public final List getResult() { + return result; + } + + public final List getDebug() { + return context.getDebug(); + } + + public final boolean isPreprocessorError() { + return preprocessorError; } } diff --git a/src/net/sourceforge/plantuml/tim/Trie.java b/src/net/sourceforge/plantuml/tim/Trie.java index eb060fd2c..420aab1d9 100644 --- a/src/net/sourceforge/plantuml/tim/Trie.java +++ b/src/net/sourceforge/plantuml/tim/Trie.java @@ -41,26 +41,47 @@ public class Trie { private final Map brothers = new HashMap(); - private boolean terminalWord = false; - public void add(String s) { - add(this, s); + if (s.indexOf('\0') != -1) { + throw new IllegalArgumentException(); + } + addInternal(this, s + "\0"); } - private static void add(Trie current, String s) { + private static void addInternal(Trie current, String s) { if (s.length() == 0) { throw new UnsupportedOperationException(); } - while (s.length() > 0) { final Character added = s.charAt(0); final Trie child = current.getOrCreate(added); s = s.substring(1); - if (s.length() == 0) { - child.terminalWord = true; + current = child; + } + } + + public boolean remove(String s) { + return removeInternal(this, s + "\0"); + } + + private static boolean removeInternal(Trie current, String s) { + if (s.length() <= 1) { + throw new UnsupportedOperationException(); + } + while (s.length() > 0) { + final Character first = s.charAt(0); + final Trie child = current.brothers.get(first); + if (child == null) { + return false; + } + s = s.substring(1); + if (s.length() == 1) { + assert s.charAt(0) == '\0'; + return child.brothers.remove('\0') != null; } current = child; } + throw new IllegalStateException(); } private Trie getOrCreate(Character added) { @@ -80,15 +101,15 @@ public class Trie { final StringBuilder result = new StringBuilder(); while (current != null) { if (s.length() == 0) { - if (current.terminalWord) { + if (current.brothers.containsKey('\0')) { return result.toString(); } else { return ""; } } final Trie child = current.brothers.get(s.charAt(0)); - if (child == null) { - if (current.terminalWord) { + if (child == null || child.brothers.size() == 0) { + if (current.brothers.containsKey('\0')) { return result.toString(); } else { return ""; diff --git a/src/net/sourceforge/plantuml/tim/expression/TValue.java b/src/net/sourceforge/plantuml/tim/expression/TValue.java index 5cb8ddbc5..fd0df15cd 100644 --- a/src/net/sourceforge/plantuml/tim/expression/TValue.java +++ b/src/net/sourceforge/plantuml/tim/expression/TValue.java @@ -93,6 +93,13 @@ public class TValue { return new TValue(toString() + v2.toString()); } + public TValue minus(TValue v2) { + if (this.isNumber() && v2.isNumber()) { + return new TValue(this.intValue - v2.intValue); + } + return new TValue(toString() + v2.toString()); + } + public TValue multiply(TValue v2) { if (this.isNumber() && v2.isNumber()) { return new TValue(this.intValue * v2.intValue); @@ -100,6 +107,13 @@ public class TValue { return new TValue(toString() + v2.toString()); } + public TValue dividedBy(TValue v2) { + if (this.isNumber() && v2.isNumber()) { + return new TValue(this.intValue / v2.intValue); + } + return new TValue(toString() + v2.toString()); + } + public boolean isNumber() { return this.stringValue == null; } diff --git a/src/net/sourceforge/plantuml/tim/expression/TokenOperator.java b/src/net/sourceforge/plantuml/tim/expression/TokenOperator.java index 5bbee81fd..97964ab4c 100644 --- a/src/net/sourceforge/plantuml/tim/expression/TokenOperator.java +++ b/src/net/sourceforge/plantuml/tim/expression/TokenOperator.java @@ -43,11 +43,21 @@ public enum TokenOperator { return v1.multiply(v2); } }, + DIVISION(100 - 3, "/") { + public TValue operate(TValue v1, TValue v2) { + return v1.dividedBy(v2); + } + }, ADDITION(100 - 4, "+") { public TValue operate(TValue v1, TValue v2) { return v1.add(v2); } }, + SUBSTRACTION(100 - 4, "-") { + public TValue operate(TValue v1, TValue v2) { + return v1.minus(v2); + } + }, LESS_THAN(100 - 6, "<") { public TValue operate(TValue v1, TValue v2) { return v1.lessThan(v2); diff --git a/src/net/sourceforge/plantuml/suggest/VariatorAddTwoChar.java b/src/net/sourceforge/plantuml/tim/stdlib/AlwaysFalse.java similarity index 64% rename from src/net/sourceforge/plantuml/suggest/VariatorAddTwoChar.java rename to src/net/sourceforge/plantuml/tim/stdlib/AlwaysFalse.java index d57627233..efdd0e50c 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorAddTwoChar.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/AlwaysFalse.java @@ -5,12 +5,12 @@ * (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 @@ -31,39 +31,28 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim.stdlib; -public class VariatorAddTwoChar extends VariatorIteratorAdaptor { +import java.util.List; - private final String data; - private final char toAdd; - private int i; - private int j = 1; +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; - public VariatorAddTwoChar(String data, char toAdd) { - this.data = data; - this.toAdd = toAdd; +public class AlwaysFalse extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%false", 0); } - @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i >= data.length()) { - return null; - } - return data.substring(0, i) + toAdd + data.substring(i, j) + toAdd + data.substring(j); - } + public boolean canCover(int nbArg) { + return nbArg == 0; + } - public void nextStep() { - j++; - if (j > data.length()) { - i++; - j = i + 1; - } - } - }; + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + return TValue.fromBoolean(false); } } diff --git a/src/net/sourceforge/plantuml/suggest/VariatorIteratorAdaptor.java b/src/net/sourceforge/plantuml/tim/stdlib/AlwaysTrue.java similarity index 65% rename from src/net/sourceforge/plantuml/suggest/VariatorIteratorAdaptor.java rename to src/net/sourceforge/plantuml/tim/stdlib/AlwaysTrue.java index 859925ad3..88a4f8df0 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorIteratorAdaptor.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/AlwaysTrue.java @@ -5,12 +5,12 @@ * (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 @@ -31,38 +31,28 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim.stdlib; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.util.List; -public abstract class VariatorIteratorAdaptor implements Iterator { +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; - private final Variator variator; +public class AlwaysTrue extends SimpleReturnFunction { - abstract Variator getVariator(); - - public VariatorIteratorAdaptor() { - this.variator = getVariator(); + public TFunctionSignature getSignature() { + return new TFunctionSignature("%true", 0); } - public boolean hasNext() { - return variator.getData() != null; + public boolean canCover(int nbArg) { + return nbArg == 0; } - public String next() { - final String result = variator.getData(); - if (result == null) { - throw new NoSuchElementException(); - } - this.variator.nextStep(); - return result; + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + return TValue.fromBoolean(true); } - - public void remove() { - throw new UnsupportedOperationException(); - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/CallUserFunction.java b/src/net/sourceforge/plantuml/tim/stdlib/CallUserFunction.java new file mode 100644 index 000000000..5021bf27e --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/CallUserFunction.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunction; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class CallUserFunction extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%call_user_func", 1); + } + + public boolean canCover(int nbArg) { + return nbArg > 0; + } + + public TValue executeReturn(TContext context, TMemory memory, List values) throws EaterException { + final String fname = values.get(0).toString(); + final List args = values.subList(1, values.size()); + final TFunctionSignature signature = new TFunctionSignature(fname, args.size()); + final TFunction func = context.getFunctionSmart(signature); + if (func == null) { + throw new EaterException("Cannot find void function " + fname); + } + return func.executeReturn(context, memory, args); + } + +} diff --git a/src/net/sourceforge/plantuml/tim/stdlib/DateFunction.java b/src/net/sourceforge/plantuml/tim/stdlib/DateFunction.java index 4c444fcf6..9e89afb7b 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/DateFunction.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/DateFunction.java @@ -40,13 +40,12 @@ import java.util.List; import net.sourceforge.plantuml.tim.EaterException; import net.sourceforge.plantuml.tim.TContext; -import net.sourceforge.plantuml.tim.TFunction; import net.sourceforge.plantuml.tim.TFunctionSignature; import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class DateFunction implements TFunction { +public class DateFunction extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%date", 1); @@ -56,14 +55,6 @@ public class DateFunction implements TFunction { return nbArg == 0 || nbArg == 1; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { if (args.size() == 0) { return TValue.fromString(new Date().toString()); @@ -75,9 +66,4 @@ public class DateFunction implements TFunction { throw new EaterException("Bad date pattern"); } } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Dirpath.java b/src/net/sourceforge/plantuml/tim/stdlib/Dirpath.java index e65641114..8fbbd0bfc 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Dirpath.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Dirpath.java @@ -47,7 +47,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Dirpath implements TFunction { +public class Dirpath extends SimpleReturnFunction { private final String value; @@ -63,23 +63,10 @@ public class Dirpath implements TFunction { return nbArg == 0; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { if (value == null) { return TValue.fromString(""); } return TValue.fromString(value); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/FileExists.java b/src/net/sourceforge/plantuml/tim/stdlib/FileExists.java index 157bf02e8..a153f01c6 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/FileExists.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/FileExists.java @@ -46,7 +46,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class FileExists implements TFunction { +public class FileExists extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%file_exists", 1); @@ -56,14 +56,6 @@ public class FileExists implements TFunction { return nbArg == 1; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { if (OptionFlags.ALLOW_INCLUDE == false) { return TValue.fromBoolean(false); @@ -76,9 +68,4 @@ public class FileExists implements TFunction { final File f = new File(path); return f.exists(); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Filename.java b/src/net/sourceforge/plantuml/tim/stdlib/Filename.java index d58c5d8d1..6f9038a6c 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Filename.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Filename.java @@ -47,7 +47,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Filename implements TFunction { +public class Filename extends SimpleReturnFunction { private final String value; @@ -63,23 +63,10 @@ public class Filename implements TFunction { return nbArg == 0; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { if (value == null) { return TValue.fromString(""); } return TValue.fromString(value); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/FunctionExists.java b/src/net/sourceforge/plantuml/tim/stdlib/FunctionExists.java new file mode 100644 index 000000000..93016d146 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/FunctionExists.java @@ -0,0 +1,60 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class FunctionExists extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%function_exists", 1); + } + + public boolean canCover(int nbArg) { + return nbArg == 1; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + final String name = args.get(0).toString(); + return TValue.fromBoolean(context.doesFunctionExist(name)); + } + +} diff --git a/src/net/sourceforge/plantuml/tim/stdlib/GetVariableValue.java b/src/net/sourceforge/plantuml/tim/stdlib/GetVariableValue.java new file mode 100644 index 000000000..2a4da96bb --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/GetVariableValue.java @@ -0,0 +1,65 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.TVariable; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class GetVariableValue extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%get_variable_value", 1); + } + + public boolean canCover(int nbArg) { + return nbArg == 1; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + final String name = args.get(0).toString(); + final TVariable variable = memory.getVariable(name); + if (variable == null) { + return TValue.fromString(""); + } + return variable.getValue2(); + } + +} diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Getenv.java b/src/net/sourceforge/plantuml/tim/stdlib/Getenv.java index 82fa48ecc..caac1deb7 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Getenv.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Getenv.java @@ -46,7 +46,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Getenv implements TFunction { +public class Getenv extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%getenv", 1); @@ -56,14 +56,6 @@ public class Getenv implements TFunction { return nbArg == 1; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { if (OptionFlags.ALLOW_INCLUDE == false) { return TValue.fromString(""); @@ -84,9 +76,4 @@ public class Getenv implements TFunction { final String getenv = System.getenv(name); return getenv; } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/suggest/VariatorSwapLetter.java b/src/net/sourceforge/plantuml/tim/stdlib/IntVal.java similarity index 59% rename from src/net/sourceforge/plantuml/suggest/VariatorSwapLetter.java rename to src/net/sourceforge/plantuml/tim/stdlib/IntVal.java index 5b400e1e3..5038e8220 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorSwapLetter.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/IntVal.java @@ -5,12 +5,12 @@ * (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 @@ -31,46 +31,35 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim.stdlib; -public class VariatorSwapLetter extends VariatorIteratorAdaptor { +import java.util.List; - private final String data; - private int i; +import net.sourceforge.plantuml.Log; +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; - public VariatorSwapLetter(String data) { - this.data = data; - ensureTwoLetters(); +public class IntVal extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%intval", 1); } - private void ensureTwoLetters() { - while (i < data.length() - 1 && areTwoLetters() == false) { - i++; + public boolean canCover(int nbArg) { + return nbArg == 1; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + final String s = args.get(0).toString(); + try { + return TValue.fromInt(Integer.parseInt(s)); + } catch (Exception e) { + Log.error("Cannot convert " + s); } - - } - - private boolean areTwoLetters() { - return Character.isLetter(data.charAt(i)) && Character.isLetter(data.charAt(i + 1)); - - } - - @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i >= data.length() - 1) { - return null; - } - return data.substring(0, i) + data.charAt(i + 1) + data.charAt(i) + data.substring(i + 2); - } - - public void nextStep() { - i++; - ensureTwoLetters(); - } - }; + return TValue.fromInt(0); } } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/InvokeVoidFunction.java b/src/net/sourceforge/plantuml/tim/stdlib/InvokeVoidFunction.java new file mode 100644 index 000000000..a62bb66bf --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/InvokeVoidFunction.java @@ -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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.EaterFunctionCall; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunction; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TFunctionType; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class InvokeVoidFunction implements TFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%invoke_void_func", 1); + } + + public boolean canCover(int nbArg) { + return nbArg > 0; + } + + public TFunctionType getFunctionType() { + return TFunctionType.VOID; + } + + public void executeVoid(TContext context, TMemory memory, String s) throws EaterException { + final EaterFunctionCall call = new EaterFunctionCall(s, false, isUnquoted()); + call.execute(context, memory); + final List values = call.getValues(); + final String fname = values.get(0).toString(); + final List args = values.subList(1, values.size()); + final TFunctionSignature signature = new TFunctionSignature(fname, args.size()); + final TFunction func = context.getFunctionSmart(signature); + if (func == null) { + throw new EaterException("Cannot find void function " + fname); + } + func.executeVoidInternal(context, memory, args); + } + + public void executeVoidInternal(TContext context, TMemory memory, List args) throws EaterException { + throw new UnsupportedOperationException(); + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + throw new UnsupportedOperationException(); + } + + public boolean isUnquoted() { + return false; + } + +} diff --git a/src/net/sourceforge/plantuml/tim/stdlib/LogicalNot.java b/src/net/sourceforge/plantuml/tim/stdlib/LogicalNot.java new file mode 100644 index 000000000..7b62151c8 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/LogicalNot.java @@ -0,0 +1,59 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class LogicalNot extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%not", 1); + } + + public boolean canCover(int nbArg) { + return nbArg == 1; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + final boolean arg = args.get(0).toBoolean(); + return TValue.fromBoolean(!arg); + } +} diff --git a/src/net/sourceforge/plantuml/tim/stdlib/SetVariableValue.java b/src/net/sourceforge/plantuml/tim/stdlib/SetVariableValue.java new file mode 100644 index 000000000..e1d88693b --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/SetVariableValue.java @@ -0,0 +1,67 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.TVariable; +import net.sourceforge.plantuml.tim.TVariableScope; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class SetVariableValue extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%set_variable_value", 2); + } + + public boolean canCover(int nbArg) { + return nbArg == 2; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + // if (memory instanceof TMemoryLocal) { + // memory = ((TMemoryLocal) memory).getGlobalForInternalUseOnly(); + // } + final String name = args.get(0).toString(); + final TValue value = args.get(1); + memory.putVariable(name, new TVariable(value), TVariableScope.GLOBAL); + return TValue.fromString(""); + } + +} diff --git a/src/net/sourceforge/plantuml/suggest/VariatorAddOneCharBetweenWords.java b/src/net/sourceforge/plantuml/tim/stdlib/SimpleReturnFunction.java similarity index 59% rename from src/net/sourceforge/plantuml/suggest/VariatorAddOneCharBetweenWords.java rename to src/net/sourceforge/plantuml/tim/stdlib/SimpleReturnFunction.java index c519116bc..3d3ca8bc0 100644 --- a/src/net/sourceforge/plantuml/suggest/VariatorAddOneCharBetweenWords.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/SimpleReturnFunction.java @@ -5,12 +5,12 @@ * (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 @@ -31,48 +31,36 @@ * * Original Author: Arnaud Roques * - * */ -package net.sourceforge.plantuml.suggest; +package net.sourceforge.plantuml.tim.stdlib; -public class VariatorAddOneCharBetweenWords extends VariatorIteratorAdaptor { +import java.util.List; - private final String data; - private final char toAdd; - private int i; +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunction; +import net.sourceforge.plantuml.tim.TFunctionType; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; - public VariatorAddOneCharBetweenWords(String data, char toAdd) { - this.data = data; - this.toAdd = toAdd; - i++; - ensureBetweenWords(); +public abstract class SimpleReturnFunction implements TFunction { + + final public TFunctionType getFunctionType() { + return TFunctionType.RETURN; } - private void ensureBetweenWords() { - while (i < data.length() && inWord()) { - i++; - } - + final public void executeVoid(TContext context, TMemory memory, String s) throws EaterException { + throw new UnsupportedOperationException(); } - private boolean inWord() { - return Character.isLetterOrDigit(data.charAt(i - 1)) && Character.isLetterOrDigit(data.charAt(i)); + final public void executeVoidInternal(TContext context, TMemory memory, List args) throws EaterException { + throw new UnsupportedOperationException(); + } + + final public boolean isUnquoted() { + return false; } - @Override - Variator getVariator() { - return new Variator() { - public String getData() { - if (i > data.length() - 1) { - return null; - } - return data.substring(0, i) + toAdd + data.substring(i); - } - public void nextStep() { - i++; - ensureBetweenWords(); - } - }; - } + } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Strlen.java b/src/net/sourceforge/plantuml/tim/stdlib/Strlen.java index a0b2f1d52..fd030e1da 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Strlen.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Strlen.java @@ -44,7 +44,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Strlen implements TFunction { +public class Strlen extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%strlen", 1); @@ -54,20 +54,7 @@ public class Strlen implements TFunction { return nbArg == 1; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { return TValue.fromInt(args.get(0).toString().length()); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Strpos.java b/src/net/sourceforge/plantuml/tim/stdlib/Strpos.java index 0d620e5ad..8b8413521 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Strpos.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Strpos.java @@ -44,7 +44,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Strpos implements TFunction { +public class Strpos extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%strpos", 2); @@ -54,22 +54,9 @@ public class Strpos implements TFunction { return nbArg == 2; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { final String full = args.get(0).toString(); final String searched = args.get(1).toString(); return TValue.fromInt(full.indexOf(searched)); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/Substr.java b/src/net/sourceforge/plantuml/tim/stdlib/Substr.java index 9635d8aff..b5352e298 100644 --- a/src/net/sourceforge/plantuml/tim/stdlib/Substr.java +++ b/src/net/sourceforge/plantuml/tim/stdlib/Substr.java @@ -46,7 +46,7 @@ import net.sourceforge.plantuml.tim.TFunctionType; import net.sourceforge.plantuml.tim.TMemory; import net.sourceforge.plantuml.tim.expression.TValue; -public class Substr implements TFunction { +public class Substr extends SimpleReturnFunction { public TFunctionSignature getSignature() { return new TFunctionSignature("%substr", 3); @@ -56,14 +56,6 @@ public class Substr implements TFunction { return nbArg == 2 || nbArg == 3; } - public TFunctionType getFunctionType() { - return TFunctionType.RETURN; - } - - public void executeVoid(TContext context, String s, TMemory memory) throws EaterException { - throw new UnsupportedOperationException(); - } - public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { final String full = args.get(0).toString(); final int pos = args.get(1).toInt(); @@ -79,9 +71,4 @@ public class Substr implements TFunction { } return TValue.fromString(result); } - - public boolean isUnquoted() { - return false; - } - } diff --git a/src/net/sourceforge/plantuml/tim/stdlib/VariableExists.java b/src/net/sourceforge/plantuml/tim/stdlib/VariableExists.java new file mode 100644 index 000000000..116239137 --- /dev/null +++ b/src/net/sourceforge/plantuml/tim/stdlib/VariableExists.java @@ -0,0 +1,60 @@ +/* ======================================================================== + * 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.tim.stdlib; + +import java.util.List; + +import net.sourceforge.plantuml.tim.EaterException; +import net.sourceforge.plantuml.tim.TContext; +import net.sourceforge.plantuml.tim.TFunctionSignature; +import net.sourceforge.plantuml.tim.TMemory; +import net.sourceforge.plantuml.tim.expression.TValue; + +public class VariableExists extends SimpleReturnFunction { + + public TFunctionSignature getSignature() { + return new TFunctionSignature("%variable_exists", 1); + } + + public boolean canCover(int nbArg) { + return nbArg == 1; + } + + public TValue executeReturn(TContext context, TMemory memory, List args) throws EaterException { + final String name = args.get(0).toString(); + return TValue.fromBoolean(memory.getVariable(name) != null); + } + +} diff --git a/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java b/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java index 3255e2202..bc39eaca4 100644 --- a/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java +++ b/src/net/sourceforge/plantuml/ugraphic/ImageBuilder.java @@ -79,6 +79,7 @@ import net.sourceforge.plantuml.graphic.HtmlColorSimple; import net.sourceforge.plantuml.graphic.HtmlColorTransparent; import net.sourceforge.plantuml.graphic.HtmlColorUtils; import net.sourceforge.plantuml.graphic.StringBounder; +import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.UDrawable; import net.sourceforge.plantuml.mjpeg.MJPEGGenerator; import net.sourceforge.plantuml.skin.rose.Rose; @@ -277,11 +278,16 @@ public class ImageBuilder { } public Dimension2D getFinalDimension(StringBounder stringBounder) { - final LimitFinder limitFinder = new LimitFinder(stringBounder, true); - udrawable.drawU(limitFinder); - Dimension2D dim = new Dimension2DDouble(limitFinder.getMaxX() + 1 + margin1 + margin2 + externalMargin(), - limitFinder.getMaxY() + 1 + margin1 + margin2 + externalMargin()); - return dim; + final Dimension2D dim; +// if (udrawable instanceof TextBlock) { +// dim = ((TextBlock) udrawable).calculateDimension(stringBounder); +// } else { + final LimitFinder limitFinder = new LimitFinder(stringBounder, true); + udrawable.drawU(limitFinder); + dim = new Dimension2DDouble(limitFinder.getMaxX(), limitFinder.getMaxY()); +// } + return new Dimension2DDouble(dim.getWidth() + 1 + margin1 + margin2 + externalMargin(), dim.getHeight() + 1 + + margin1 + margin2 + externalMargin()); } private UGraphic handwritten(UGraphic ug) { diff --git a/src/net/sourceforge/plantuml/version/IteratorCounter2.java b/src/net/sourceforge/plantuml/version/IteratorCounter2.java index fe0fe6299..034b24acf 100644 --- a/src/net/sourceforge/plantuml/version/IteratorCounter2.java +++ b/src/net/sourceforge/plantuml/version/IteratorCounter2.java @@ -35,6 +35,7 @@ package net.sourceforge.plantuml.version; import java.util.Iterator; +import java.util.List; import net.sourceforge.plantuml.StringLocated; @@ -50,4 +51,6 @@ public interface IteratorCounter2 extends Iterator { public void copyStateFrom(IteratorCounter2 other); + public List getTrace(); + } diff --git a/src/net/sourceforge/plantuml/version/IteratorCounter2Impl.java b/src/net/sourceforge/plantuml/version/IteratorCounter2Impl.java index 4cedf154d..9af3e4538 100644 --- a/src/net/sourceforge/plantuml/version/IteratorCounter2Impl.java +++ b/src/net/sourceforge/plantuml/version/IteratorCounter2Impl.java @@ -34,6 +34,8 @@ */ package net.sourceforge.plantuml.version; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import net.sourceforge.plantuml.StringLocated; @@ -41,21 +43,28 @@ import net.sourceforge.plantuml.StringLocated; public class IteratorCounter2Impl implements IteratorCounter2 { private List data; + private List trace; private int nb; public void copyStateFrom(IteratorCounter2 other) { final IteratorCounter2Impl source = (IteratorCounter2Impl) other; this.nb = source.nb; this.data = source.data; + this.trace = source.trace; } public IteratorCounter2Impl(List data) { - this(data, 0); + this(data, 0, new ArrayList()); } - private IteratorCounter2Impl(List data, int nb) { + private IteratorCounter2Impl(List data, int nb, List trace) { this.data = data; this.nb = nb; + this.trace = trace; + } + + public IteratorCounter2 cloneMe() { + return new IteratorCounter2Impl(data, nb, new ArrayList(trace)); } public int currentNum() { @@ -67,7 +76,10 @@ public class IteratorCounter2Impl implements IteratorCounter2 { } public StringLocated next() { - return data.get(nb++); + final StringLocated result = data.get(nb); + nb++; + trace.add(result); + return result; } public StringLocated peek() { @@ -85,8 +97,8 @@ public class IteratorCounter2Impl implements IteratorCounter2 { throw new UnsupportedOperationException(); } - public IteratorCounter2 cloneMe() { - return new IteratorCounter2Impl(data, nb); + public final List getTrace() { + return Collections.unmodifiableList(trace); } } diff --git a/src/net/sourceforge/plantuml/version/Version.java b/src/net/sourceforge/plantuml/version/Version.java index b4d5e022f..a288db04a 100644 --- a/src/net/sourceforge/plantuml/version/Version.java +++ b/src/net/sourceforge/plantuml/version/Version.java @@ -43,7 +43,7 @@ public class Version { private static final int MAJOR_SEPARATOR = 1000000; public static int version() { - return 1201905; + return 1201906; } public static int versionPatched() { @@ -88,7 +88,7 @@ public class Version { } public static long compileTime() { - return 1555778736375L; + return 1558717825131L; } public static String compileTimeString() { diff --git a/src/net/sourceforge/plantuml/wbs/WBSDiagram.java b/src/net/sourceforge/plantuml/wbs/WBSDiagram.java index c385d5152..860a12eb0 100644 --- a/src/net/sourceforge/plantuml/wbs/WBSDiagram.java +++ b/src/net/sourceforge/plantuml/wbs/WBSDiagram.java @@ -80,7 +80,8 @@ public class WBSDiagram extends UmlDiagram { final double dpiFactor = scale == null ? getScaleCoef(fileFormatOption) : scale.getScale(100, 100); final ISkinParam skinParam = getSkinParam(); final ImageBuilder imageBuilder = new ImageBuilder(skinParam.getColorMapper(), dpiFactor, - skinParam.getBackgroundColor(), "", "", 10, 10, null, skinParam.handwritten()); + skinParam.getBackgroundColor(), fileFormatOption.isWithMetadata() ? getMetadata() : null, "", 10, 10, + null, skinParam.handwritten()); TextBlock result = getTextBlock(); result = new AnnotatedWorker(this, skinParam, fileFormatOption.getDefaultStringBounder()).addAdd(result); diff --git a/stdlib/awslib-abx.repx b/stdlib/awslib-abx.repx new file mode 100644 index 0000000000000000000000000000000000000000..34b449f3a9de58b90bb8495910101220a5afc960 GIT binary patch literal 19066 zcmZU)V|bm>yX_s@wr$&7X=B^A)3C9f#&*)iw$a$OlO}0wy(|6i^PaQ!{+e9t!F=YN z_qcy!Or7dXZn%ILaR2xZSqrj-Otn{`N3gjO*UZ5?bG2TAn_7tZXAyp}l`0~{z;;Ds zDaP`SGBbv8J~UG$Y)Ia8Dznt1ei;bC4fo9eTijaZi{~es?t(GwcuD^?NBV-fG$8?j z)E91d8wKlAs_?&_eW=09`IBdlBIY}=z4E$!<>YiIi$(*$Im>rI)hHmkpvy_b- z+bN9=OWX!UtKi;KM~;;0JxlR6-|fmo;Kj%VOb;5^v^gt*c|*uM=?o@#31XCv{u2O$O5kz9TmR z7f8aBoawveCs%yv+aP86VebB3KvwTfhbRznM{ZDjZFxt>85x4~{&Dg41v}Nvj7A0B zR7C1@qT6k(HC3q|6`g>l@-N@TM(KRv@?7LO%3Rk`){DVJ^&c&@j}K+0BWL>qXM1zo z0YuAagwk`jQCtymad1m{1mDJK>>AEu>=@e7dWB=^_`efXkzpc>@~djkveSd$zFeM= z{%26T0EMftibtROP(^{1p^h4V?263mfmAUUc3gJ+^T*g2&_E)TED;-pu(acb#%|@r@)-Aso>-yGm96mQM939@6vz)dIb2+p`5QFgJK} z>6L9nI{32s%d!0iLbK8ay-zb0M=F^+ZCW$!Ym(+|V|W1j7#1~N@rCetzLz78AE6jZd2Fm-$uRx)VTi;b4Yw?MOP0_EaH&70`-c41~nGSH<`50%?tWn9v`Z^0^G#AS32iyz<6!U$AH5^Sot^ZaVvXYm3>J^F@{w@a zXO?rwB9Z$}2TiMba0i2P&6vN&Vs6~_Cw?njQ@jcy5e3>?e8=AP=!FYgoxQ*3u5=D} zaVvPao6NYe@skV`hIw;x+Vo@N^ocn9n^*l|KvyDN*-XyK|79>1@FXQr-Q~$#mw}w} z?$XLK`uhItmpHy*!Gu%&jQ|`TnOxtrdmAjM9=aPQ0nTrty{IgLVP7yT6q#03t@B#~ zly~_nb{~p_SpD(BcQ)Jm?zxi_U4`qZ4g?ijPHdO=<_U7F+>tjbJiAzp=s1J(-?A9# zmcv5PniqOa$Pt=nRQI6ufuUa&qa0&`r(>f;rydo*%DF_JZpmDI^eoM>-ZHj%^O!9-<;TNRi7~A01MY_!w!dJ7=fepm3BY9VG_5 zSsCzNG(VG3-^PstuoZV+p$xFKq_4e3VG(-s#Z8Q7;LTI;Y=wRS%yy|T-~)=bH^#q# z?=4yM%?~CJ6EamsP^#$eAS3_qojMpIB{QJ+h8rv(XUb=k=EDG+A5JoDjhQQ8$gLxa zs1Yce<}$?3OCuUTw!nqAl}bA5WCyeOKA=0r#Tsjo9~6tp6{orVO$X*D#PumOQp-C1 zH?MY|{P3t&>aP)!afH{oGAAyrlhoBL$3_zK{21g4xx?!^q6H#1GW`nlaDi7-#e%xo zOUA_mU$U3L%pcPS!6FE=9enjETIn*QZB71WVKi|iPI29FvHZ5EFurn$3{ljdPA@I^ zLtal<>o*->!_F3dnBAe5G19Spda&%s;B_gpk7wE_YymSLd^Ynk&85`a=oM zkE<3%%DIb7rIwI-f6A5ERgE;=Fm(4@-br6RZaZW{Lj#;O6)&R*2MpLvTm@0pgift; zUm3)*z@w3Ctw=#PFEdkjqvDa9nFM;^(kTZOQbT$&9!+Hgx}R9Bi1Vej(^e%JdoRME zXv#?+Xgg#WWaN2Y2xNFD7`}gxs~lmpPk8vtTeK`M^0YoxQObZ16_%io7LCi4n;UN_ z^e&5t2Z;*Q;TEhIBxSMdGcA<3B5m5@yzQ(0R{8PmuNvqXthXIRm%0A$^k?eF;7(7P(#-3Ef^r*vY#Mz{)zsBw8ev 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%0A&*Sehz>{72WY+ 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

EyWc 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 YBr-7o(R~KsV>t#OGY1gI5lH3$423jB-T(jq literal 0 HcmV?d00001 diff --git a/stdlib/home.repx b/stdlib/home.repx index c42df4086..4895d7746 100644 --- a/stdlib/home.repx +++ b/stdlib/home.repx @@ -1,5 +1,6 @@ azure aws +awslib cloudinsight cloudogu tupadr3