mirror of
https://github.com/octoleo/plantuml.git
synced 2024-11-24 13:57:33 +00:00
Merge branch 'plantuml:master' into ImproveDoc
This commit is contained in:
commit
7666511512
425
.github/actions/configure-workflow/package-lock.json
generated
vendored
425
.github/actions/configure-workflow/package-lock.json
generated
vendored
@ -125,28 +125,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz",
|
||||
"integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.15.6",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator/node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-compilation-targets": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz",
|
||||
@ -165,39 +157,35 @@
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz",
|
||||
"integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==",
|
||||
"node_modules/@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-get-function-arity": "^7.15.4",
|
||||
"@babel/template": "^7.15.4",
|
||||
"@babel/types": "^7.15.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-get-function-arity": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz",
|
||||
"integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==",
|
||||
"node_modules/@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-hoist-variables": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz",
|
||||
"integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -246,15 +234,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-optimise-call-expression": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz",
|
||||
@ -304,21 +283,30 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-split-export-declaration": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz",
|
||||
"integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==",
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
|
||||
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@ -348,13 +336,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/highlight": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
|
||||
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.14.5",
|
||||
"chalk": "^2.0.0",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -362,9 +350,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz",
|
||||
"integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@ -536,44 +524,46 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
|
||||
"integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==",
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/parser": "^7.15.4",
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template/node_modules/@babel/code-frame": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
|
||||
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.14.5"
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz",
|
||||
"integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/generator": "^7.15.4",
|
||||
"@babel/helper-function-name": "^7.15.4",
|
||||
"@babel/helper-hoist-variables": "^7.15.4",
|
||||
"@babel/helper-split-export-declaration": "^7.15.4",
|
||||
"@babel/parser": "^7.15.4",
|
||||
"@babel/types": "^7.15.4",
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
@ -582,39 +572,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse/node_modules/@babel/code-frame": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
|
||||
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.14.5"
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz",
|
||||
"integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": "^7.14.9",
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types/node_modules/@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bcoe/v8-coverage": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
|
||||
@ -1414,6 +1397,54 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.19",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
||||
@ -8506,22 +8537,15 @@
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz",
|
||||
"integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.6",
|
||||
"jsesc": "^2.5.1",
|
||||
"source-map": "^0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"dev": true
|
||||
}
|
||||
"@babel/types": "^7.23.0",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
"@jridgewell/trace-mapping": "^0.3.17",
|
||||
"jsesc": "^2.5.1"
|
||||
}
|
||||
},
|
||||
"@babel/helper-compilation-targets": {
|
||||
@ -8536,33 +8560,29 @@
|
||||
"semver": "^6.3.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz",
|
||||
"integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-get-function-arity": "^7.15.4",
|
||||
"@babel/template": "^7.15.4",
|
||||
"@babel/types": "^7.15.4"
|
||||
}
|
||||
"@babel/helper-environment-visitor": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-get-function-arity": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz",
|
||||
"integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==",
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/types": "^7.23.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-hoist-variables": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz",
|
||||
"integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-member-expression-to-functions": {
|
||||
@ -8597,14 +8617,6 @@
|
||||
"@babel/template": "^7.15.4",
|
||||
"@babel/traverse": "^7.15.4",
|
||||
"@babel/types": "^7.15.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/helper-optimise-call-expression": {
|
||||
@ -8644,18 +8656,24 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz",
|
||||
"integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==",
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-string-parser": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
|
||||
"integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/helper-validator-option": {
|
||||
@ -8676,20 +8694,20 @@
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
|
||||
"integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
||||
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.5",
|
||||
"chalk": "^2.0.0",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"chalk": "^2.4.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz",
|
||||
"integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/plugin-syntax-async-generators": {
|
||||
@ -8810,71 +8828,67 @@
|
||||
}
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
|
||||
"integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==",
|
||||
"version": "7.22.15",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/parser": "^7.15.4",
|
||||
"@babel/types": "^7.15.4"
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/parser": "^7.22.15",
|
||||
"@babel/types": "^7.22.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
|
||||
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.14.5"
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.15.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz",
|
||||
"integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.14.5",
|
||||
"@babel/generator": "^7.15.4",
|
||||
"@babel/helper-function-name": "^7.15.4",
|
||||
"@babel/helper-hoist-variables": "^7.15.4",
|
||||
"@babel/helper-split-export-declaration": "^7.15.4",
|
||||
"@babel/parser": "^7.15.4",
|
||||
"@babel/types": "^7.15.4",
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/types": "^7.23.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.15.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
|
||||
"integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
|
||||
"version": "7.22.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.14.5"
|
||||
"@babel/highlight": "^7.22.13",
|
||||
"chalk": "^2.4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.15.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz",
|
||||
"integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==",
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.14.9",
|
||||
"@babel/helper-string-parser": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
|
||||
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@bcoe/v8-coverage": {
|
||||
@ -9488,6 +9502,45 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
|
||||
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.19",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
|
||||
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
||||
|
11
attic.md
Normal file
11
attic.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Historical Code Archive
|
||||
|
||||
This document catalogs code that was previously part of PlantUML but has since been deprecated and removed due to its lack of use.
|
||||
It serves as a historical reference to ensure we remember and understand past decisions.
|
||||
|
||||
- [logo language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/logo)
|
||||
- [basic language](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/jasic)
|
||||
- [mjpeg export](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/mjpeg)
|
||||
- [animation](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/anim)
|
||||
- [ditherer quantization](https://github.com/plantuml/plantuml/tree/v1.2023.12/src/net/sourceforge/plantuml/quantization)
|
||||
- [syntax suggestion](https://github.com/plantuml/plantuml/blob/v1.2023.12/src/net/sourceforge/plantuml/syntax/SyntaxChecker.java)
|
@ -1,4 +1,4 @@
|
||||
# Warning, "version" should be the same in gradle.properties and Version.java
|
||||
# Any idea anyone how to magically synchronize those :-) ?
|
||||
version = 1.2023.12beta1
|
||||
version = 1.2023.13beta1
|
||||
org.gradle.workers.max = 3
|
@ -46,6 +46,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
@ -84,10 +85,12 @@ import net.sourceforge.plantuml.security.SecurityUtils;
|
||||
import net.sourceforge.plantuml.skin.UmlDiagramType;
|
||||
import net.sourceforge.plantuml.skin.VisibilityModifier;
|
||||
import net.sourceforge.plantuml.statediagram.StateDiagram;
|
||||
import net.sourceforge.plantuml.stereo.Stereotype;
|
||||
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
|
||||
import net.sourceforge.plantuml.svek.CucaDiagramFileMaker;
|
||||
import net.sourceforge.plantuml.svek.CucaDiagramFileMakerSvek;
|
||||
import net.sourceforge.plantuml.text.BackSlash;
|
||||
import net.sourceforge.plantuml.text.Guillemet;
|
||||
import net.sourceforge.plantuml.xmi.CucaDiagramXmiMaker;
|
||||
import net.sourceforge.plantuml.xmlsc.StateDiagramScxmlMaker;
|
||||
|
||||
@ -523,6 +526,41 @@ public abstract class CucaDiagram extends UmlDiagram implements GroupHierarchy,
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getVisibleStereotypeLabels(Entity entity) {
|
||||
Stereotype stereotype = entity.getStereotype();
|
||||
|
||||
if (stereotype == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<EntityHideOrShow> commands = new ArrayList<>();
|
||||
for (EntityHideOrShow hideOrShowEntry : hideOrShows) {
|
||||
if (hideOrShowEntry.portion == EntityPortion.STEREOTYPE) {
|
||||
commands.add(hideOrShowEntry);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> visibleStereotypeLabels = new ArrayList<>();
|
||||
for (String stereoTypeLabel: entity.getStereotype().getLabels(Guillemet.DOUBLE_COMPARATOR)) {
|
||||
if (isHiddenStereotypeLabel(stereoTypeLabel, commands)) {
|
||||
visibleStereotypeLabels.add(stereoTypeLabel);
|
||||
}
|
||||
}
|
||||
|
||||
return visibleStereotypeLabels;
|
||||
}
|
||||
|
||||
private boolean isHiddenStereotypeLabel(String stereoTypeLabel, List<EntityHideOrShow> commands) {
|
||||
for (EntityHideOrShow cmd : commands) {
|
||||
String gender = cmd.gender.getGender();
|
||||
if (gender != null && gender.equals(stereoTypeLabel)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public final void hideOrShow(EntityGender gender, EntityPortion portions, boolean show) {
|
||||
for (EntityPortion portion : portions.asSet())
|
||||
this.hideOrShows.add(new EntityHideOrShow(gender, portion, show));
|
||||
|
@ -37,8 +37,6 @@ package net.atmp;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -46,22 +44,16 @@ import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import com.plantuml.api.cheerpj.WasmLog;
|
||||
|
||||
import net.sourceforge.plantuml.AnimatedGifEncoder;
|
||||
import net.sourceforge.plantuml.AnnotatedBuilder;
|
||||
import net.sourceforge.plantuml.AnnotatedWorker;
|
||||
import net.sourceforge.plantuml.EmptyImageBuilder;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.FileUtils;
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.Scale;
|
||||
import net.sourceforge.plantuml.TitledDiagram;
|
||||
import net.sourceforge.plantuml.anim.AffineTransformation;
|
||||
import net.sourceforge.plantuml.anim.Animation;
|
||||
import net.sourceforge.plantuml.api.ImageDataComplex;
|
||||
import net.sourceforge.plantuml.api.ImageDataSimple;
|
||||
import net.sourceforge.plantuml.braille.UGraphicBraille;
|
||||
@ -87,14 +79,10 @@ import net.sourceforge.plantuml.klimt.drawing.tikz.UGraphicTikz;
|
||||
import net.sourceforge.plantuml.klimt.drawing.txt.UGraphicTxt;
|
||||
import net.sourceforge.plantuml.klimt.drawing.visio.UGraphicVdx;
|
||||
import net.sourceforge.plantuml.klimt.font.StringBounder;
|
||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
||||
import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
||||
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
||||
import net.sourceforge.plantuml.klimt.shape.URectangle;
|
||||
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
|
||||
import net.sourceforge.plantuml.security.SFile;
|
||||
import net.sourceforge.plantuml.security.SImageIO;
|
||||
import net.sourceforge.plantuml.skin.ColorParam;
|
||||
import net.sourceforge.plantuml.skin.CornerParam;
|
||||
import net.sourceforge.plantuml.skin.LineParam;
|
||||
@ -113,9 +101,6 @@ import net.sourceforge.plantuml.url.Url;
|
||||
|
||||
public class ImageBuilder {
|
||||
|
||||
// ::comment when __CORE__
|
||||
private Animation animation;
|
||||
// ::done
|
||||
private boolean annotations;
|
||||
private HColor backcolor = getDefaultHBackColor();
|
||||
|
||||
@ -223,9 +208,6 @@ public class ImageBuilder {
|
||||
public ImageBuilder styled(TitledDiagram diagram) {
|
||||
skinParam = diagram.getSkinParam();
|
||||
stringBounder = fileFormatOption.getDefaultStringBounder(skinParam);
|
||||
// ::comment when __CORE__
|
||||
animation = diagram.getAnimation();
|
||||
// ::done
|
||||
annotations = true;
|
||||
backcolor = diagram.calculateBackColor();
|
||||
margin = calculateMargin(diagram);
|
||||
@ -246,21 +228,7 @@ public class ImageBuilder {
|
||||
udrawable = annotatedWorker.addAdd((TextBlock) udrawable);
|
||||
}
|
||||
|
||||
// ::comment when __CORE__
|
||||
switch (fileFormatOption.getFileFormat()) {
|
||||
case MJPEG:
|
||||
return writeImageMjpeg(os);
|
||||
case ANIMATED_GIF:
|
||||
return writeImageAnimatedGif(os);
|
||||
default:
|
||||
return writeImageInternal(os, animation);
|
||||
// ::done
|
||||
// ::uncomment when __CORE__
|
||||
// return writeImageInternal(os);
|
||||
// ::done
|
||||
// ::comment when __CORE__
|
||||
}
|
||||
// ::done
|
||||
return writeImageInternal(os);
|
||||
}
|
||||
|
||||
public byte[] writeByteArray() throws IOException {
|
||||
@ -270,34 +238,16 @@ public class ImageBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// ::revert when __CORE__
|
||||
private ImageData writeImageInternal(OutputStream os, Animation animationArg) throws IOException {
|
||||
// private ImageData writeImageInternal(OutputStream os) throws IOException {
|
||||
// ::done
|
||||
private ImageData writeImageInternal(OutputStream os) throws IOException {
|
||||
XDimension2D dim = getFinalDimension();
|
||||
double dx = 0;
|
||||
double dy = 0;
|
||||
// ::comment when __CORE__
|
||||
if (animationArg != null) {
|
||||
final MinMax minmax = animationArg.getMinMax(dim);
|
||||
animationArg.setDimension(dim);
|
||||
dim = minmax.getDimension();
|
||||
dx = -minmax.getMinX();
|
||||
dy = -minmax.getMinY();
|
||||
}
|
||||
// ::done
|
||||
final Scale scale = titledDiagram == null ? null : titledDiagram.getScale();
|
||||
final double scaleFactor = (scale == null ? 1 : scale.getScale(dim.getWidth(), dim.getHeight())) * getDpi()
|
||||
/ 96.0;
|
||||
if (scaleFactor <= 0)
|
||||
throw new IllegalStateException("Bad scaleFactor");
|
||||
WasmLog.log("...image drawing...");
|
||||
// ::revert when __CORE__
|
||||
UGraphic ug = createUGraphic(dim, animationArg, dx, dy, scaleFactor,
|
||||
UGraphic ug = createUGraphic(dim, scaleFactor,
|
||||
titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
|
||||
// UGraphic ug = createUGraphic(dim, dx, dy, scaleFactor,
|
||||
// titledDiagram == null ? new Pragma() : titledDiagram.getPragma());
|
||||
// ::done
|
||||
maybeDrawBorder(ug, dim);
|
||||
if (randomPixel)
|
||||
drawRandomPoint(ug);
|
||||
@ -330,9 +280,9 @@ public class ImageBuilder {
|
||||
if (stroke == null)
|
||||
return;
|
||||
|
||||
final URectangle rectangle = URectangle.build(dim.getWidth() - stroke.getThickness(),
|
||||
dim.getHeight() - stroke.getThickness())
|
||||
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
|
||||
final URectangle rectangle = URectangle
|
||||
.build(dim.getWidth() - stroke.getThickness(), dim.getHeight() - stroke.getThickness())
|
||||
.rounded(skinParam.getRoundCorner(CornerParam.diagramBorder, null));
|
||||
|
||||
ug.apply(color == null ? HColors.BLACK : color).apply(stroke).draw(rectangle);
|
||||
}
|
||||
@ -364,83 +314,13 @@ public class ImageBuilder {
|
||||
return ug;
|
||||
}
|
||||
|
||||
// ::comment when __CORE__
|
||||
private ImageData writeImageMjpeg(OutputStream os) throws IOException {
|
||||
|
||||
final XDimension2D dim = getFinalDimension();
|
||||
|
||||
final SFile f = new SFile("c:/tmp.avi");
|
||||
|
||||
final int nbframe = 100;
|
||||
|
||||
final MJPEGGenerator m = new MJPEGGenerator(f, getAviImage(null).getWidth(null),
|
||||
getAviImage(null).getHeight(null), 12.0, nbframe);
|
||||
for (int i = 0; i < nbframe; i++) {
|
||||
// AffineTransform at = AffineTransform.getRotateInstance(1.0);
|
||||
AffineTransform at = AffineTransform.getTranslateInstance(dim.getWidth() / 2, dim.getHeight() / 2);
|
||||
at.rotate(90.0 * Math.PI / 180.0 * i / 100);
|
||||
at.translate(-dim.getWidth() / 2, -dim.getHeight() / 2);
|
||||
// final AffineTransform at = AffineTransform.getTranslateInstance(i, 0);
|
||||
// final ImageIcon ii = new ImageIcon(getAviImage(at));
|
||||
// m.addImage(ii.getImage());
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
m.finishAVI();
|
||||
|
||||
FileUtils.copyToStream(f, os);
|
||||
|
||||
return createImageData(dim);
|
||||
}
|
||||
|
||||
private ImageData writeImageAnimatedGif(OutputStream os) throws IOException {
|
||||
|
||||
final XDimension2D dim = getFinalDimension();
|
||||
|
||||
final MinMax minmax = animation.getMinMax(dim);
|
||||
|
||||
final AnimatedGifEncoder e = new AnimatedGifEncoder();
|
||||
// e.setQuality(1);
|
||||
e.setRepeat(0);
|
||||
e.start(os);
|
||||
// e.setDelay(1000); // 1 frame per sec
|
||||
// e.setDelay(100); // 10 frame per sec
|
||||
e.setDelay(60); // 16 frame per sec
|
||||
// e.setDelay(50); // 20 frame per sec
|
||||
|
||||
for (AffineTransformation at : animation.getAll()) {
|
||||
final ImageIcon ii = new ImageIcon(getAviImage(at));
|
||||
e.addFrame((BufferedImage) ii.getImage());
|
||||
}
|
||||
e.finish();
|
||||
return createImageData(dim);
|
||||
}
|
||||
|
||||
private Image getAviImage(AffineTransformation affineTransform) throws IOException {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
writeImageInternal(baos, Animation.singleton(affineTransform));
|
||||
baos.close();
|
||||
return SImageIO.read(baos.toByteArray());
|
||||
}
|
||||
// ::done
|
||||
|
||||
// ::revert when __CORE__
|
||||
private UGraphic createUGraphic(final XDimension2D dim, Animation animationArg, double dx, double dy,
|
||||
double scaleFactor, Pragma pragma) {
|
||||
// private UGraphic createUGraphic(final XDimension2D dim, double dx, double dy,
|
||||
// double scaleFactor, Pragma pragma) {
|
||||
// ::done
|
||||
private UGraphic createUGraphic(final XDimension2D dim, double scaleFactor, Pragma pragma) {
|
||||
final ColorMapper colorMapper = fileFormatOption.getColorMapper();
|
||||
switch (fileFormatOption.getFileFormat()) {
|
||||
case PNG:
|
||||
case RAW:
|
||||
// ::comment when __CORE__
|
||||
return createUGraphicPNG(scaleFactor, dim, animationArg, dx, dy, fileFormatOption.getWatermark(),
|
||||
return createUGraphicPNG(scaleFactor, dim, fileFormatOption.getWatermark(),
|
||||
fileFormatOption.getFileFormat());
|
||||
// ::done
|
||||
// ::uncomment when __CORE__
|
||||
// return createUGraphicPNG(scaleFactor, dim, dx, dy,
|
||||
// fileFormatOption.getWatermark(), fileFormatOption.getFileFormat());
|
||||
// ::done
|
||||
case SVG:
|
||||
return createUGraphicSVG(scaleFactor, dim, pragma);
|
||||
// ::comment when __CORE__
|
||||
@ -492,14 +372,8 @@ public class ImageBuilder {
|
||||
|
||||
}
|
||||
|
||||
// ::uncomment when __CORE__
|
||||
// private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D
|
||||
// dim, double dx, double dy, String watermark, FileFormat format) {
|
||||
// ::done
|
||||
// ::comment when __CORE__
|
||||
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, Animation affineTransforms,
|
||||
double dx, double dy, String watermark, FileFormat format) {
|
||||
// ::done
|
||||
private UGraphic createUGraphicPNG(double scaleFactor, final XDimension2D dim, String watermark,
|
||||
FileFormat format) {
|
||||
Color pngBackColor = new Color(0, 0, 0, 0);
|
||||
|
||||
if (this.backcolor instanceof HColorSimple)
|
||||
@ -513,15 +387,9 @@ public class ImageBuilder {
|
||||
(int) (dim.getHeight() * scaleFactor), pngBackColor, stringBounder);
|
||||
final Graphics2D graphics2D = builder.getGraphics2D();
|
||||
|
||||
// ::comment when __CORE__
|
||||
final UGraphicG2d ug = new UGraphicG2d(backcolor, fileFormatOption.getColorMapper(), stringBounder, graphics2D,
|
||||
scaleFactor, dx, dy, format, affineTransforms == null ? null : affineTransforms.getFirst());
|
||||
// ::done
|
||||
// ::uncomment when __CORE__
|
||||
// final UGraphicG2d ug = new UGraphicG2d(backcolor,
|
||||
// fileFormatOption.getColorMapper(), stringBounder, graphics2D,
|
||||
// scaleFactor, dx, dy, format);
|
||||
// ::done
|
||||
scaleFactor, format);
|
||||
|
||||
ug.setBufferedImage(builder.getBufferedImage());
|
||||
final BufferedImage im = ug.getBufferedImage();
|
||||
if (this.backcolor instanceof HColorGradient)
|
||||
|
@ -76,8 +76,6 @@ public enum FileFormat {
|
||||
SCXML("application/scxml+xml"), //
|
||||
GRAPHML("application/graphml+xml"), //
|
||||
PDF("application/pdf"), //
|
||||
MJPEG("video/x-msvideo"), //
|
||||
ANIMATED_GIF("image/gif"), //
|
||||
HTML("text/html"), //
|
||||
HTML5("text/html"), //
|
||||
VDX("application/vnd.visio.xml"), //
|
||||
@ -112,15 +110,9 @@ public enum FileFormat {
|
||||
if (name().startsWith("XMI"))
|
||||
return ".xmi";
|
||||
|
||||
if (this == MJPEG)
|
||||
return ".avi";
|
||||
|
||||
if (this == LATEX || this == LATEX_NO_PREAMBLE)
|
||||
return ".tex";
|
||||
|
||||
if (this == ANIMATED_GIF)
|
||||
return ".gif";
|
||||
|
||||
if (this == BRAILLE_PNG)
|
||||
return ".braille.png";
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class OptionFlags {
|
||||
static public void setMaxPixel(int max) {
|
||||
}
|
||||
|
||||
static public final boolean USE_HECTOR = false;
|
||||
// static public final boolean USE_HECTOR = false;
|
||||
static public boolean ADD_NICE_FOR_DOT = false;
|
||||
|
||||
// static public final boolean USE_IF_VERTICAL = true;
|
||||
|
@ -70,6 +70,7 @@ import net.sourceforge.plantuml.eggs.PSystemWelcomeFactory;
|
||||
import net.sourceforge.plantuml.emoji.PSystemListEmojiFactory;
|
||||
import net.sourceforge.plantuml.error.PSystemError;
|
||||
import net.sourceforge.plantuml.error.PSystemErrorUtils;
|
||||
import net.sourceforge.plantuml.error.PSystemUnsupported;
|
||||
import net.sourceforge.plantuml.filesdiagram.FilesDiagramFactory;
|
||||
import net.sourceforge.plantuml.flowdiagram.FlowDiagramFactory;
|
||||
import net.sourceforge.plantuml.font.PSystemListFontsFactory;
|
||||
@ -146,6 +147,9 @@ public class PSystemBuilder {
|
||||
}
|
||||
|
||||
final DiagramType diagramType = umlSource.getDiagramType();
|
||||
if (diagramType == DiagramType.UNKNOWN)
|
||||
return new PSystemUnsupported(umlSource);
|
||||
|
||||
final List<PSystemError> errors = new ArrayList<>();
|
||||
for (PSystemFactory systemFactory : factories) {
|
||||
if (diagramType != systemFactory.getDiagramType())
|
||||
@ -159,6 +163,8 @@ public class PSystemBuilder {
|
||||
}
|
||||
errors.add((PSystemError) sys);
|
||||
}
|
||||
if (errors.size() == 0)
|
||||
return new PSystemUnsupported(umlSource);
|
||||
|
||||
result = PSystemErrorUtils.merge(errors);
|
||||
return result;
|
||||
|
@ -42,8 +42,6 @@ import java.util.Map;
|
||||
import net.atmp.ImageBuilder;
|
||||
import net.sourceforge.plantuml.abel.DisplayPositioned;
|
||||
import net.sourceforge.plantuml.abel.DisplayPositionned;
|
||||
import net.sourceforge.plantuml.anim.Animation;
|
||||
import net.sourceforge.plantuml.anim.AnimationDecoder;
|
||||
import net.sourceforge.plantuml.api.ApiStable;
|
||||
import net.sourceforge.plantuml.command.CommandExecutionResult;
|
||||
import net.sourceforge.plantuml.core.Diagram;
|
||||
@ -88,10 +86,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
|
||||
|
||||
private final SkinParam skinParam;
|
||||
|
||||
// ::comment when __CORE__
|
||||
private Animation animation;
|
||||
// ::done
|
||||
|
||||
private final Pragma pragma = new Pragma();
|
||||
|
||||
public Pragma getPragma() {
|
||||
@ -218,21 +212,6 @@ public abstract class TitledDiagram extends AbstractPSystem implements Diagram,
|
||||
return ClockwiseTopRightBottomLeft.same(10);
|
||||
}
|
||||
|
||||
// ::comment when __CORE__
|
||||
final public void setAnimation(Iterable<CharSequence> animationData) {
|
||||
// try {
|
||||
final AnimationDecoder animationDecoder = new AnimationDecoder(animationData);
|
||||
this.animation = Animation.create(animationDecoder.decode());
|
||||
// } catch (ScriptException e) {
|
||||
// Logme.error(e);
|
||||
// }
|
||||
}
|
||||
|
||||
final public Animation getAnimation() {
|
||||
return animation;
|
||||
}
|
||||
// ::done
|
||||
|
||||
@Override
|
||||
public ImageBuilder createImageBuilder(FileFormatOption fileFormatOption) throws IOException {
|
||||
return super.createImageBuilder(fileFormatOption).styled(this);
|
||||
|
@ -38,10 +38,8 @@ package net.sourceforge.plantuml;
|
||||
import static net.atmp.ImageBuilder.plainImageBuilder;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
@ -74,10 +72,8 @@ import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
||||
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
||||
import net.sourceforge.plantuml.klimt.shape.UImage;
|
||||
import net.sourceforge.plantuml.log.Logme;
|
||||
import net.sourceforge.plantuml.mjpeg.MJPEGGenerator;
|
||||
import net.sourceforge.plantuml.pdf.PdfConverter;
|
||||
import net.sourceforge.plantuml.security.SFile;
|
||||
import net.sourceforge.plantuml.security.SImageIO;
|
||||
import net.sourceforge.plantuml.security.SecurityUtils;
|
||||
import net.sourceforge.plantuml.skin.UmlDiagramType;
|
||||
import net.sourceforge.plantuml.style.NoStyleAvailableException;
|
||||
@ -258,27 +254,6 @@ public abstract class UmlDiagram extends TitledDiagram implements Diagram, Annot
|
||||
}
|
||||
|
||||
// ::comment when __CORE__
|
||||
private void exportDiagramInternalMjpeg(OutputStream os) throws IOException {
|
||||
final SFile f = new SFile("c:/test.avi");
|
||||
final int nb = 150;
|
||||
final double framerate = 30;
|
||||
final MJPEGGenerator m = new MJPEGGenerator(f, 640, 480, framerate, nb);
|
||||
|
||||
for (int i = 0; i < nb; i++) {
|
||||
final AffineTransform at = new AffineTransform();
|
||||
final double coef = (nb - 1 - i) * 1.0 / nb;
|
||||
at.setToShear(coef, coef);
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
// exportDiagramTOxxBEREMOVED(baos, null, 0, new
|
||||
// FileFormatOption(FileFormat.PNG, at));
|
||||
baos.close();
|
||||
final BufferedImage im = SImageIO.read(baos.toByteArray());
|
||||
m.addImage(im);
|
||||
}
|
||||
m.finishAVI();
|
||||
|
||||
}
|
||||
|
||||
private ImageData exportDiagramInternalPdf(OutputStream os, int index) throws IOException {
|
||||
final File svg = FileUtils.createTempFileLegacy("pdf", ".svf");
|
||||
final File pdfFile = FileUtils.createTempFileLegacy("pdf", ".pdf");
|
||||
|
@ -37,4 +37,6 @@ package net.sourceforge.plantuml.abel;
|
||||
|
||||
public interface EntityGender {
|
||||
public boolean contains(Entity test);
|
||||
|
||||
public String getGender();
|
||||
}
|
||||
|
@ -44,6 +44,11 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return test.getLeafType() == type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return type.name();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -52,6 +57,11 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return test.getUid().equals(entity.getUid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return entity.getUid();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,7 +71,19 @@ public class EntityGenderUtils {
|
||||
if (test.getStereotype() == null) {
|
||||
return false;
|
||||
}
|
||||
return stereotype.equals(test.getStereotype().getLabel(Guillemet.DOUBLE_COMPARATOR));
|
||||
|
||||
for (String label : test.getStereotype().getLabels(Guillemet.DOUBLE_COMPARATOR)) {
|
||||
if (label.equals(stereotype)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return stereotype;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -80,6 +102,11 @@ public class EntityGenderUtils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -88,6 +115,11 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return g1.contains(test) && g2.contains(test);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -96,6 +128,11 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -104,6 +141,11 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return test.getBodier().getMethodsToDisplay().size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -112,7 +154,26 @@ public class EntityGenderUtils {
|
||||
public boolean contains(Entity test) {
|
||||
return test.getBodier().getFieldsToDisplay().size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
static public EntityGender byClassName(String className) {
|
||||
return new EntityGender() {
|
||||
@Override
|
||||
public boolean contains(Entity test) {
|
||||
return className.equals(test.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGender() {
|
||||
return className;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,157 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.anim;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Objects;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.sourceforge.plantuml.StringUtils;
|
||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
||||
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
|
||||
|
||||
public class AffineTransformation {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove folder when __CORE__
|
||||
|
||||
static private final Pattern rotate = Pattern.compile("rotate\\s+(-?\\d+\\.?\\d*)");
|
||||
static private final Pattern shear = Pattern.compile("shear\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
||||
static private final Pattern translate = Pattern.compile("translate\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
||||
static private final Pattern scale = Pattern.compile("scale\\s+(-?\\d+\\.?\\d*)\\s+(-?\\d+\\.?\\d*)");
|
||||
static private final Pattern color = Pattern.compile("color\\s+.*");
|
||||
|
||||
private final AffineTransform affineTransform;
|
||||
private XDimension2D dimension;
|
||||
|
||||
private AffineTransformation(AffineTransform affineTransform) {
|
||||
this.affineTransform = Objects.requireNonNull(affineTransform);
|
||||
}
|
||||
|
||||
private AffineTransformation compose(AffineTransformation other) {
|
||||
final AffineTransform tmp = new AffineTransform(this.affineTransform);
|
||||
tmp.concatenate(other.affineTransform);
|
||||
return new AffineTransformation(tmp);
|
||||
}
|
||||
|
||||
public static AffineTransformation from(AffineTransform affineTransform) {
|
||||
return new AffineTransformation(affineTransform);
|
||||
}
|
||||
|
||||
static AffineTransformation create(String value) {
|
||||
final StringTokenizer st = new StringTokenizer(value, "|");
|
||||
AffineTransformation result = null;
|
||||
while (st.hasMoreTokens()) {
|
||||
final String s = st.nextToken();
|
||||
final AffineTransformation tmp = createSimple(s);
|
||||
if (tmp != null) {
|
||||
if (result == null) {
|
||||
result = tmp;
|
||||
} else {
|
||||
result = result.compose(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static AffineTransformation createSimple(String value) {
|
||||
Matcher m = rotate.matcher(StringUtils.trin(value));
|
||||
if (m.find()) {
|
||||
final double angle = Double.parseDouble(m.group(1));
|
||||
return new AffineTransformation(AffineTransform.getRotateInstance(angle * Math.PI / 180.0));
|
||||
}
|
||||
m = shear.matcher(value);
|
||||
if (m.find()) {
|
||||
final double shx = Double.parseDouble(m.group(1));
|
||||
final double shy = Double.parseDouble(m.group(2));
|
||||
return new AffineTransformation(AffineTransform.getShearInstance(shx, shy));
|
||||
}
|
||||
m = translate.matcher(value);
|
||||
if (m.find()) {
|
||||
final double tx = Double.parseDouble(m.group(1));
|
||||
final double ty = Double.parseDouble(m.group(2));
|
||||
return new AffineTransformation(AffineTransform.getTranslateInstance(tx, ty));
|
||||
}
|
||||
m = scale.matcher(value);
|
||||
if (m.find()) {
|
||||
final double scalex = Double.parseDouble(m.group(1));
|
||||
final double scaley = Double.parseDouble(m.group(2));
|
||||
return new AffineTransformation(AffineTransform.getScaleInstance(scalex, scaley));
|
||||
}
|
||||
m = color.matcher(value);
|
||||
if (m.find()) {
|
||||
return new AffineTransformation(new AffineTransform());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final AffineTransform getAffineTransform() {
|
||||
return getAffineTransform(dimension);
|
||||
}
|
||||
|
||||
private AffineTransform getAffineTransform(XDimension2D dimension) {
|
||||
if (dimension == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
final AffineTransform at = AffineTransform.getTranslateInstance(dimension.getWidth() / 2,
|
||||
dimension.getHeight() / 2);
|
||||
at.concatenate(affineTransform);
|
||||
at.translate(-dimension.getWidth() / 2, -dimension.getHeight() / 2);
|
||||
|
||||
return at;
|
||||
}
|
||||
|
||||
public void setDimension(XDimension2D dim) {
|
||||
this.dimension = dim;
|
||||
|
||||
}
|
||||
|
||||
public MinMax getMinMax(XDimension2D rect) {
|
||||
MinMax result = MinMax.getEmpty(false);
|
||||
final AffineTransform tmp = getAffineTransform(rect);
|
||||
|
||||
result = result.addPoint(new XPoint2D(0, 0).transform(tmp));
|
||||
result = result.addPoint(new XPoint2D(0, rect.getHeight()).transform(tmp));
|
||||
result = result.addPoint(new XPoint2D(rect.getWidth(), 0).transform(tmp));
|
||||
result = result.addPoint(new XPoint2D(rect.getWidth(), rect.getHeight()).transform(tmp));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.anim;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.geom.MinMax;
|
||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
||||
|
||||
public class Animation {
|
||||
|
||||
private final List<AffineTransformation> all;
|
||||
|
||||
private Animation(List<AffineTransformation> all) {
|
||||
if (all.size() == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.all = all;
|
||||
}
|
||||
|
||||
public static Animation singleton(AffineTransformation affineTransformation) {
|
||||
if (affineTransformation == null) {
|
||||
return null;
|
||||
}
|
||||
return new Animation(Collections.singletonList(affineTransformation));
|
||||
}
|
||||
|
||||
public static Animation create(List<String> descriptions) {
|
||||
final List<AffineTransformation> all = new ArrayList<>();
|
||||
for (String s : descriptions) {
|
||||
final AffineTransformation tmp = AffineTransformation.create(s);
|
||||
if (tmp != null) {
|
||||
all.add(tmp);
|
||||
}
|
||||
}
|
||||
return new Animation(all);
|
||||
}
|
||||
|
||||
public Collection<AffineTransformation> getAll() {
|
||||
return Collections.unmodifiableCollection(all);
|
||||
}
|
||||
|
||||
public void setDimension(XDimension2D dim) {
|
||||
for (AffineTransformation affineTransform : all) {
|
||||
affineTransform.setDimension(dim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public AffineTransformation getFirst() {
|
||||
return all.get(0);
|
||||
}
|
||||
|
||||
public MinMax getMinMax(XDimension2D dim) {
|
||||
MinMax result = MinMax.getEmpty(false);
|
||||
for (AffineTransformation affineTransform : all) {
|
||||
final MinMax m = affineTransform.getMinMax(dim);
|
||||
result = result.addMinMax(m);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.anim;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class AnimationDecoder {
|
||||
|
||||
private final List<String> result = new ArrayList<>();
|
||||
|
||||
public AnimationDecoder(Iterable<CharSequence> data) {
|
||||
|
||||
for (final Iterator<CharSequence> it = data.iterator(); it.hasNext();) {
|
||||
String line = it.next().toString();
|
||||
if (line.matches("^\\s*\\[script\\]\\s*$")) {
|
||||
final StringBuilder scriptText = new StringBuilder();
|
||||
while (true) {
|
||||
line = it.next().toString();
|
||||
if (line.matches("^\\s*\\[/script\\]\\s*$")) {
|
||||
final AnimationScript script = new AnimationScript();
|
||||
final String out = script.eval(scriptText.toString());
|
||||
for (final StringTokenizer st = new StringTokenizer(out, "\n"); st.hasMoreTokens();) {
|
||||
result.add(st.nextToken());
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
scriptText.append(line);
|
||||
scriptText.append("\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.add(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> decode() {
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.anim;
|
||||
|
||||
public class AnimationScript {
|
||||
|
||||
// private final ScriptEngine engine;
|
||||
|
||||
public AnimationScript() {
|
||||
|
||||
// final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
// engine = manager.getEngineByName("js");
|
||||
|
||||
// ScriptEngineManager manager = new ScriptEngineManager();
|
||||
// List<ScriptEngineFactory> factories = manager.getEngineFactories();
|
||||
// for (ScriptEngineFactory factory : factories) {
|
||||
// System.out.println("Name : " + factory.getEngineName());
|
||||
// System.out.println("Version : " + factory.getEngineVersion());
|
||||
// System.out.println("Language name : " + factory.getLanguageName());
|
||||
// System.out.println("Language version : " + factory.getLanguageVersion());
|
||||
// System.out.println("Extensions : " + factory.getExtensions());
|
||||
// System.out.println("Mime types : " + factory.getMimeTypes());
|
||||
// System.out.println("Names : " + factory.getNames());
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
public String eval(String line) {
|
||||
throw new UnsupportedOperationException();
|
||||
// final ScriptContext context = engine.getContext();
|
||||
// final StringWriter sw = new StringWriter();
|
||||
// context.setWriter(new PrintWriter(sw));
|
||||
// engine.eval(line, context);
|
||||
// final String result = sw.toString();
|
||||
// return result;
|
||||
}
|
||||
}
|
@ -190,30 +190,35 @@ public class CommandHideShowByGender extends SingleLineCommand2<UmlDiagram> {
|
||||
} else {
|
||||
arg1 = StringUtils.eventuallyRemoveStartingAndEndingDoubleQuote(arg1);
|
||||
final Quark<Entity> quark = diagram.quarkInContext(true, diagram.cleanId(arg1));
|
||||
Entity entity = quark.getData();
|
||||
if (entity == null)
|
||||
return CommandExecutionResult.error("No such element " + quark.getName());
|
||||
gender = EntityGenderUtils.byEntityAlone(entity);
|
||||
}
|
||||
if (gender != null) {
|
||||
final boolean empty = arg.get("EMPTY", 0) != null;
|
||||
final boolean emptyMembers = empty && portion == EntityPortion.MEMBER;
|
||||
if (empty == true && emptyMembers == false)
|
||||
gender = EntityGenderUtils.and(gender, emptyByGender(portion));
|
||||
|
||||
if (diagram.getCurrentGroup().isRoot() == false)
|
||||
gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup()));
|
||||
|
||||
if (emptyMembers) {
|
||||
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)),
|
||||
EntityPortion.FIELD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)),
|
||||
EntityPortion.METHOD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
if (quark == null) {
|
||||
return CommandExecutionResult.error("No such quark " + arg1);
|
||||
}
|
||||
if (portion == EntityPortion.METHOD) {
|
||||
gender = EntityGenderUtils.byClassName(arg1);
|
||||
} else {
|
||||
diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
Entity entity = quark.getData();
|
||||
if (entity == null)
|
||||
return CommandExecutionResult.error("No such element " + quark.getName());
|
||||
gender = EntityGenderUtils.byEntityAlone(entity);
|
||||
}
|
||||
}
|
||||
return CommandExecutionResult.ok();
|
||||
final boolean empty = arg.get("EMPTY", 0) != null;
|
||||
final boolean emptyMembers = empty && portion == EntityPortion.MEMBER;
|
||||
if (empty && !emptyMembers)
|
||||
gender = EntityGenderUtils.and(gender, emptyByGender(portion));
|
||||
|
||||
if (!diagram.getCurrentGroup().isRoot())
|
||||
gender = EntityGenderUtils.and(gender, EntityGenderUtils.byPackage(diagram.getCurrentGroup()));
|
||||
|
||||
if (emptyMembers) {
|
||||
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.FIELD)),
|
||||
EntityPortion.FIELD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
diagram.hideOrShow(EntityGenderUtils.and(gender, emptyByGender(EntityPortion.METHOD)),
|
||||
EntityPortion.METHOD, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
} else {
|
||||
diagram.hideOrShow(gender, portion, arg.get("COMMAND", 0).equalsIgnoreCase("show"));
|
||||
}
|
||||
return CommandExecutionResult.ok();
|
||||
}
|
||||
|
||||
private EntityPortion getEntityPortion(String s) {
|
||||
|
@ -1,71 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://plantuml.com/paypal
|
||||
*
|
||||
* This file is part of PlantUML.
|
||||
*
|
||||
* PlantUML is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PlantUML distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
*
|
||||
* Original Author: Arnaud Roques
|
||||
*
|
||||
*
|
||||
*/
|
||||
package net.sourceforge.plantuml.command;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import net.sourceforge.plantuml.UmlDiagram;
|
||||
import net.sourceforge.plantuml.regex.IRegex;
|
||||
import net.sourceforge.plantuml.regex.RegexConcat;
|
||||
import net.sourceforge.plantuml.regex.RegexLeaf;
|
||||
import net.sourceforge.plantuml.regex.RegexResult;
|
||||
import net.sourceforge.plantuml.utils.LineLocation;
|
||||
|
||||
public class CommandAffineTransform extends SingleLineCommand2<UmlDiagram> {
|
||||
|
||||
public static final CommandAffineTransform ME = new CommandAffineTransform();
|
||||
|
||||
private CommandAffineTransform() {
|
||||
super(getRegexConcat());
|
||||
}
|
||||
|
||||
static IRegex getRegexConcat() {
|
||||
return RegexConcat.build(CommandAffineTransform.class.getName(), RegexLeaf.start(), //
|
||||
new RegexLeaf("!transformation"), //
|
||||
RegexLeaf.spaceOneOrMore(), //
|
||||
new RegexLeaf("ANIMATION", "([^{}]*)"), RegexLeaf.end()); //
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CommandExecutionResult executeArg(UmlDiagram diagram, LineLocation location, RegexResult arg) {
|
||||
final CharSequence value = arg.get("ANIMATION", 0);
|
||||
// ::comment when __CORE__
|
||||
diagram.setAnimation(Collections.singletonList(value));
|
||||
// ::done
|
||||
return CommandExecutionResult.ok();
|
||||
}
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://plantuml.com/paypal
|
||||
*
|
||||
* This file is part of PlantUML.
|
||||
*
|
||||
* PlantUML is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PlantUML distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
*
|
||||
* Original Author: Arnaud Roques
|
||||
*
|
||||
*
|
||||
*/
|
||||
package net.sourceforge.plantuml.command;
|
||||
|
||||
import net.sourceforge.plantuml.TitledDiagram;
|
||||
import net.sourceforge.plantuml.utils.BlocLines;
|
||||
|
||||
public class CommandAffineTransformMultiline extends CommandMultilines<TitledDiagram> {
|
||||
|
||||
public static final CommandAffineTransformMultiline ME = new CommandAffineTransformMultiline();
|
||||
|
||||
private CommandAffineTransformMultiline() {
|
||||
super("^!transformation[%s]+\\{[%s]*$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPatternEnd() {
|
||||
return "^[%s]*!\\}[%s]*$";
|
||||
}
|
||||
|
||||
public CommandExecutionResult execute(final TitledDiagram diagram, BlocLines lines) {
|
||||
// lines = lines.subExtract(1, 1);
|
||||
// diagram.setAnimation(lines);
|
||||
return CommandExecutionResult.error("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
@ -73,8 +73,6 @@ public final class CommonCommands {
|
||||
cmds.add(CommandScaleMaxWidth.ME);
|
||||
cmds.add(CommandScaleMaxHeight.ME);
|
||||
cmds.add(CommandScaleMaxWidthAndHeight.ME);
|
||||
cmds.add(CommandAffineTransform.ME);
|
||||
cmds.add(CommandAffineTransformMultiline.ME);
|
||||
final CommandFactorySprite factorySpriteCommand = new CommandFactorySprite();
|
||||
cmds.add(factorySpriteCommand.createMultiLine(false));
|
||||
cmds.add(factorySpriteCommand.createSingleLine());
|
||||
|
@ -39,7 +39,7 @@ import net.sourceforge.plantuml.utils.StartUtils;
|
||||
|
||||
public enum DiagramType {
|
||||
// ::remove folder when __HAXE__
|
||||
UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, JUNGLE, CUTE, MATH, LATEX, DEFINITION, GANTT, NW,
|
||||
UML, BPM, DITAA, DOT, PROJECT, JCCKIT, SALT, FLOW, CREOLE, MATH, LATEX, DEFINITION, GANTT, NW,
|
||||
MINDMAP, WBS, WIRE, JSON, GIT, BOARD, YAML, HCL, EBNF, REGEX, FILES, UNKNOWN;
|
||||
|
||||
static public DiagramType getTypeFromArobaseStart(String s) {
|
||||
@ -59,11 +59,15 @@ public enum DiagramType {
|
||||
if (StartUtils.startsWithSymbolAnd("startdot", s))
|
||||
return DOT;
|
||||
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
||||
if (StartUtils.startsWithSymbolAnd("startjcckit", s))
|
||||
return JCCKIT;
|
||||
// ::done
|
||||
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__
|
||||
if (StartUtils.startsWithSymbolAnd("startditaa", s))
|
||||
return DITAA;
|
||||
// ::done
|
||||
|
||||
if (StartUtils.startsWithSymbolAnd("startproject", s))
|
||||
return PROJECT;
|
||||
@ -77,12 +81,6 @@ public enum DiagramType {
|
||||
if (StartUtils.startsWithSymbolAnd("startcreole", s))
|
||||
return CREOLE;
|
||||
|
||||
if (StartUtils.startsWithSymbolAnd("starttree", s))
|
||||
return JUNGLE;
|
||||
|
||||
if (StartUtils.startsWithSymbolAnd("startcute", s))
|
||||
return CUTE;
|
||||
|
||||
if (StartUtils.startsWithSymbolAnd("startmath", s))
|
||||
return MATH;
|
||||
|
||||
|
@ -45,7 +45,6 @@ import net.sourceforge.plantuml.klimt.creole.Display;
|
||||
import net.sourceforge.plantuml.regex.Matcher2;
|
||||
import net.sourceforge.plantuml.regex.MyPattern;
|
||||
import net.sourceforge.plantuml.regex.Pattern2;
|
||||
import net.sourceforge.plantuml.text.BackSlash;
|
||||
import net.sourceforge.plantuml.text.StringLocated;
|
||||
import net.sourceforge.plantuml.utils.LineLocation;
|
||||
import net.sourceforge.plantuml.utils.StartUtils;
|
||||
|
@ -38,7 +38,11 @@ package net.sourceforge.plantuml.cucadiagram;
|
||||
import net.sourceforge.plantuml.abel.Entity;
|
||||
import net.sourceforge.plantuml.abel.EntityPortion;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PortionShower {
|
||||
|
||||
boolean showPortion(EntityPortion portion, Entity entity);
|
||||
|
||||
List<String> getVisibleStereotypeLabels(Entity entity);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ package net.sourceforge.plantuml.dot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -101,6 +102,11 @@ final public class DotData implements PortionShower {
|
||||
public boolean showPortion(EntityPortion portion, Entity entity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<String> getVisibleStereotypeLabels(Entity entity) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}, entityFactory, isHideEmptyDescriptionForState, dotMode, namespaceSeparator, pragma);
|
||||
}
|
||||
|
||||
@ -136,6 +142,10 @@ final public class DotData implements PortionShower {
|
||||
return portionShower.showPortion(portion, entity);
|
||||
}
|
||||
|
||||
public List<String> getVisibleStereotypeLabels(Entity entity) {
|
||||
return portionShower.getVisibleStereotypeLabels(entity);
|
||||
}
|
||||
|
||||
public Entity getRootGroup() {
|
||||
return entityFactory.getRootGroup();
|
||||
}
|
||||
|
@ -48,10 +48,10 @@ class GraphvizLinux extends AbstractGraphviz {
|
||||
|
||||
@Override
|
||||
protected File specificDotExe() {
|
||||
final File all[] = new File[] { new File("/usr/local/bin/dot"), new File("/usr/bin/dot"),
|
||||
new File("/opt/homebrew/bin/dot") };
|
||||
final File all[] = new File[] { new File("/usr/local/bin/dot"), new File("/opt/homebrew/bin/dot"),
|
||||
new File("/opt/homebrew/opt/graphviz/bin/dot"), new File("/usr/bin/dot") };
|
||||
for (File f : all)
|
||||
if (f.exists())
|
||||
if (f.exists() && f.canRead() && f.canExecute())
|
||||
return f;
|
||||
return new File("/opt/local/bin/dot");
|
||||
}
|
||||
|
@ -5,12 +5,12 @@
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://plantuml.com/paypal
|
||||
*
|
||||
*
|
||||
* This file is part of PlantUML.
|
||||
*
|
||||
* PlantUML is free software; you can redistribute it and/or modify it
|
||||
@ -30,31 +30,47 @@
|
||||
*
|
||||
*
|
||||
* Original Author: Arnaud Roques
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package net.sourceforge.plantuml.logo;
|
||||
package net.sourceforge.plantuml.error;
|
||||
|
||||
import net.sourceforge.plantuml.command.PSystemBasicFactory;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.PlainDiagram;
|
||||
import net.sourceforge.plantuml.core.DiagramDescription;
|
||||
import net.sourceforge.plantuml.core.UmlSource;
|
||||
import net.sourceforge.plantuml.klimt.shape.GraphicStrings;
|
||||
import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
||||
import net.sourceforge.plantuml.klimt.shape.UDrawable;
|
||||
import net.sourceforge.plantuml.version.License;
|
||||
import net.sourceforge.plantuml.version.Version;
|
||||
|
||||
public class PSystemLogoFactory extends PSystemBasicFactory<PSystemLogo> {
|
||||
public class PSystemUnsupported extends PlainDiagram {
|
||||
|
||||
@Override
|
||||
public PSystemLogo initDiagram(UmlSource source, String startLine) {
|
||||
return null;
|
||||
private final List<String> strings = new ArrayList<>();
|
||||
|
||||
public PSystemUnsupported(UmlSource source) {
|
||||
super(source);
|
||||
strings.add("<b>Diagram not supported by this release of PlantUML");
|
||||
strings.add(Version.fullDescription());
|
||||
strings.add("License " + new License().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PSystemLogo executeLine(UmlSource source, PSystemLogo system, String line) {
|
||||
if (system == null && line.equalsIgnoreCase("logo")) {
|
||||
return new PSystemLogo(source);
|
||||
}
|
||||
if (system == null) {
|
||||
return null;
|
||||
}
|
||||
system.doCommandLine(line);
|
||||
return system;
|
||||
protected UDrawable getRootDrawable(FileFormatOption fileFormatOption) throws IOException {
|
||||
return getGraphicStrings();
|
||||
}
|
||||
|
||||
public TextBlock getGraphicStrings() {
|
||||
return GraphicStrings.createBlackOnWhite(strings);
|
||||
}
|
||||
|
||||
public DiagramDescription getDescription() {
|
||||
return new DiagramDescription("(Unsupported)");
|
||||
}
|
||||
|
||||
}
|
@ -1,829 +0,0 @@
|
||||
package net.sourceforge.plantuml.jasic;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/*
|
||||
Jasic uses the MIT License:
|
||||
|
||||
Copyright (c) 2010 Robert Nystrom
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This defines a single class that contains an entire interpreter for a language very similar to the original BASIC.
|
||||
* Everything is here (albeit in very simplified form): tokenizing, parsing, and interpretation. The file is organized
|
||||
* in phases, with each appearing roughly in the order that they occur when a program is run. You should be able to read
|
||||
* this top-down to walk through the entire process of loading and running a program.
|
||||
*
|
||||
* Jasic language syntax ---------------------
|
||||
*
|
||||
* Comments start with ' and proceed to the end of the line:
|
||||
*
|
||||
* print "hi there" ' this is a comment
|
||||
*
|
||||
* Numbers and strings are supported. Strings should be in "double quotes", and only positive integers can be parsed
|
||||
* (though numbers are double internally).
|
||||
*
|
||||
* Variables are identified by name which must start with a letter and can contain letters or numbers. Case is
|
||||
* significant for names and keywords.
|
||||
*
|
||||
* Each statement is on its own line. Optionally, a line may have a label before the statement. A label is a name that
|
||||
* ends with a colon:
|
||||
*
|
||||
* foo:
|
||||
*
|
||||
*
|
||||
* The following statements are supported:
|
||||
*
|
||||
* <name> = <expression> Evaluates the expression and assigns the result to the given named variable. All variables are
|
||||
* globally scoped.
|
||||
*
|
||||
* pi = (314159 / 10000)
|
||||
*
|
||||
* print <expression> Evaluates the expression and prints the result.
|
||||
*
|
||||
* print "hello, " + "world"
|
||||
*
|
||||
* input <name> Reads in a line of input from the user and stores it in the variable with the given name.
|
||||
*
|
||||
* input guess
|
||||
*
|
||||
* goto <label> Jumps to the statement after the label with the given name.
|
||||
*
|
||||
* goto loop
|
||||
*
|
||||
* if <expression> then <label> Evaluates the expression. If it evaluates to a non-zero number, then jumps to the
|
||||
* statement after the given label.
|
||||
*
|
||||
* if a < b then dosomething
|
||||
*
|
||||
*
|
||||
* The following expressions are supported:
|
||||
*
|
||||
* <expression> = <expression> Evaluates to 1 if the two expressions are equal, 0 otherwise.
|
||||
*
|
||||
* <expression> + <expression> If the left-hand expression is a number, then adds the two expressions, otherwise
|
||||
* concatenates the two strings.
|
||||
*
|
||||
* <expression> - <expression> <expression> * <expression> <expression> / <expression> <expression> < <expression>
|
||||
* <expression> > <expression> You can figure it out.
|
||||
*
|
||||
* <name> A name in an expression simply returns the value of the variable with that name. If the variable was never
|
||||
* set, it defaults to 0.
|
||||
*
|
||||
* All binary operators have the same precedence. Sorry, I had to cut corners somewhere.
|
||||
*
|
||||
* To keep things simple, I've omitted some stuff or hacked things a bit. When possible, I'll leave a "HACK" note there
|
||||
* explaining what and why. If you make your own interpreter, you'll want to address those.
|
||||
*
|
||||
* @author Bob Nystrom
|
||||
*/
|
||||
public class Jasic {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove folder when __CORE__
|
||||
// ::remove folder when __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
||||
|
||||
// Tokenizing (lexing) -----------------------------------------------------
|
||||
|
||||
/**
|
||||
* This function takes a script as a string of characters and chunks it into a
|
||||
* sequence of tokens. Each token is a meaningful unit of program, like a
|
||||
* variable name, a number, a string, or an operator.
|
||||
*/
|
||||
private static List<Token> tokenize(String source) {
|
||||
List<Token> tokens = new ArrayList<>();
|
||||
|
||||
String token = "";
|
||||
TokenizeState state = TokenizeState.DEFAULT;
|
||||
|
||||
// Many tokens are a single character, like operators and ().
|
||||
String charTokens = "\n=+-*/<>()";
|
||||
TokenType[] tokenTypes = { TokenType.LINE, TokenType.EQUALS, TokenType.OPERATOR, TokenType.OPERATOR,
|
||||
TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.OPERATOR, TokenType.LEFT_PAREN,
|
||||
TokenType.RIGHT_PAREN };
|
||||
|
||||
// Scan through the code one character at a time, building up the list
|
||||
// of tokens.
|
||||
for (int i = 0; i < source.length(); i++) {
|
||||
char c = source.charAt(i);
|
||||
switch (state) {
|
||||
case DEFAULT:
|
||||
if (charTokens.indexOf(c) != -1) {
|
||||
tokens.add(new Token(Character.toString(c), tokenTypes[charTokens.indexOf(c)]));
|
||||
} else if (Character.isLetter(c)) {
|
||||
token += c;
|
||||
state = TokenizeState.WORD;
|
||||
} else if (Character.isDigit(c)) {
|
||||
token += c;
|
||||
state = TokenizeState.NUMBER;
|
||||
} else if (c == '"') {
|
||||
state = TokenizeState.STRING;
|
||||
} else if (c == '\'') {
|
||||
state = TokenizeState.COMMENT;
|
||||
}
|
||||
break;
|
||||
|
||||
case WORD:
|
||||
if (Character.isLetterOrDigit(c)) {
|
||||
token += c;
|
||||
} else if (c == ':') {
|
||||
tokens.add(new Token(token, TokenType.LABEL));
|
||||
token = "";
|
||||
state = TokenizeState.DEFAULT;
|
||||
} else {
|
||||
tokens.add(new Token(token, TokenType.WORD));
|
||||
token = "";
|
||||
state = TokenizeState.DEFAULT;
|
||||
i--; // Reprocess this character in the default state.
|
||||
}
|
||||
break;
|
||||
|
||||
case NUMBER:
|
||||
// HACK: Negative numbers and floating points aren't supported.
|
||||
// To get a negative number, just do 0 - <your number>.
|
||||
// To get a floating point, divide.
|
||||
if (Character.isDigit(c)) {
|
||||
token += c;
|
||||
} else {
|
||||
tokens.add(new Token(token, TokenType.NUMBER));
|
||||
token = "";
|
||||
state = TokenizeState.DEFAULT;
|
||||
i--; // Reprocess this character in the default state.
|
||||
}
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
if (c == '"') {
|
||||
tokens.add(new Token(token, TokenType.STRING));
|
||||
token = "";
|
||||
state = TokenizeState.DEFAULT;
|
||||
} else {
|
||||
token += c;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
if (c == '\n') {
|
||||
state = TokenizeState.DEFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: Silently ignore any in-progress token when we run out of
|
||||
// characters. This means that, for example, if a script has a string
|
||||
// that's missing the closing ", it will just ditch it.
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// Token data --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This defines the different kinds of tokens or meaningful chunks of code that
|
||||
* the parser knows how to consume. These let us distinguish, for example,
|
||||
* between a string "foo" and a variable named "foo".
|
||||
*
|
||||
* HACK: A typical tokenizer would actually have unique token types for each
|
||||
* keyword (print, goto, etc.) so that the parser doesn't have to look at the
|
||||
* names, but Jasic is a little more crude.
|
||||
*/
|
||||
private enum TokenType {
|
||||
WORD, NUMBER, STRING, LABEL, LINE, EQUALS, OPERATOR, LEFT_PAREN, RIGHT_PAREN, EOF
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a single meaningful chunk of code. It is created by the tokenizer and
|
||||
* consumed by the parser.
|
||||
*/
|
||||
private static class Token {
|
||||
public Token(String text, TokenType type) {
|
||||
this.text = text;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public final String text;
|
||||
public final TokenType type;
|
||||
}
|
||||
|
||||
/**
|
||||
* This defines the different states the tokenizer can be in while it's scanning
|
||||
* through the source code. Tokenizers are state machines, which means the only
|
||||
* data they need to store is where they are in the source code and this one
|
||||
* "state" or mode value.
|
||||
*
|
||||
* One of the main differences between tokenizing and parsing is this
|
||||
* regularity. Because the tokenizer stores only this one state value, it can't
|
||||
* handle nesting (which would require also storing a number to identify how
|
||||
* deeply nested you are). The parser is able to handle that.
|
||||
*/
|
||||
private enum TokenizeState {
|
||||
DEFAULT, WORD, NUMBER, STRING, COMMENT
|
||||
}
|
||||
|
||||
// Parsing -----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This defines the Jasic parser. The parser takes in a sequence of tokens and
|
||||
* generates an abstract syntax tree. This is the nested data structure that
|
||||
* represents the series of statements, and the expressions (which can nest
|
||||
* arbitrarily deeply) that they evaluate. In technical terms, what we have is a
|
||||
* recursive descent parser, the simplest kind to hand-write.
|
||||
*
|
||||
* As a side-effect, this phase also stores off the line numbers for each label
|
||||
* in the program. It's a bit gross, but it works.
|
||||
*/
|
||||
private class Parser {
|
||||
public Parser(List<Token> tokens) {
|
||||
this.tokens = tokens;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The top-level function to start parsing. This will keep consuming tokens and
|
||||
* routing to the other parse functions for the different grammar syntax until
|
||||
* we run out of code to parse.
|
||||
*
|
||||
* @param labels A map of label names to statement indexes. The parser will fill
|
||||
* this in as it scans the code.
|
||||
* @return The list of parsed statements.
|
||||
*/
|
||||
public List<Statement> parse(Map<String, Integer> labels) {
|
||||
List<Statement> statements = new ArrayList<>();
|
||||
|
||||
while (true) {
|
||||
// Ignore empty lines.
|
||||
while (match(TokenType.LINE))
|
||||
;
|
||||
|
||||
if (match(TokenType.LABEL)) {
|
||||
// Mark the index of the statement after the label.
|
||||
labels.put(last(1).text, statements.size());
|
||||
} else if (match(TokenType.WORD, TokenType.EQUALS)) {
|
||||
String name = last(2).text;
|
||||
Expression value = expression();
|
||||
statements.add(new AssignStatement(name, value));
|
||||
} else if (match("print")) {
|
||||
statements.add(new PrintStatement(expression()));
|
||||
} else if (match("input")) {
|
||||
statements.add(new InputStatement(consume(TokenType.WORD).text));
|
||||
} else if (match("goto")) {
|
||||
statements.add(new GotoStatement(consume(TokenType.WORD).text));
|
||||
} else if (match("if")) {
|
||||
Expression condition = expression();
|
||||
consume("then");
|
||||
String label = consume(TokenType.WORD).text;
|
||||
statements.add(new IfThenStatement(condition, label));
|
||||
} else
|
||||
break; // Unexpected token (likely EOF), so end.
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
// The following functions each represent one grammatical part of the
|
||||
// language. If this parsed English, these functions would be named like
|
||||
// noun() and verb().
|
||||
|
||||
/**
|
||||
* Parses a single expression. Recursive descent parsers start with the
|
||||
* lowest-precedent term and moves towards higher precedence. For Jasic, binary
|
||||
* operators (+, -, etc.) are the lowest.
|
||||
*
|
||||
* @return The parsed expression.
|
||||
*/
|
||||
private Expression expression() {
|
||||
return operator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a series of binary operator expressions into a single expression. In
|
||||
* Jasic, all operators have the same predecence and associate left-to-right.
|
||||
* That means it will interpret: 1 + 2 * 3 - 4 / 5 like: ((((1 + 2) * 3) - 4) /
|
||||
* 5)
|
||||
*
|
||||
* It works by building the expression tree one at a time. So, given this code:
|
||||
* 1 + 2 * 3, this will:
|
||||
*
|
||||
* 1. Parse (1) as an atomic expression. 2. See the (+) and start a new operator
|
||||
* expression. 3. Parse (2) as an atomic expression. 4. Build a (1 + 2)
|
||||
* expression and replace (1) with it. 5. See the (*) and start a new operator
|
||||
* expression. 6. Parse (3) as an atomic expression. 7. Build a ((1 + 2) * 3)
|
||||
* expression and replace (1 + 2) with it. 8. Return the last expression built.
|
||||
*
|
||||
* @return The parsed expression.
|
||||
*/
|
||||
private Expression operator() {
|
||||
Expression expression = atomic();
|
||||
|
||||
// Keep building operator expressions as long as we have operators.
|
||||
while (match(TokenType.OPERATOR) || match(TokenType.EQUALS)) {
|
||||
char operator = last(1).text.charAt(0);
|
||||
Expression right = atomic();
|
||||
expression = new OperatorExpression(expression, operator, right);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an "atomic" expression. This is the highest level of precedence and
|
||||
* contains single literal tokens like 123 and "foo", as well as parenthesized
|
||||
* expressions.
|
||||
*
|
||||
* @return The parsed expression.
|
||||
*/
|
||||
private Expression atomic() {
|
||||
if (match(TokenType.WORD)) {
|
||||
// A word is a reference to a variable.
|
||||
return new VariableExpression(last(1).text);
|
||||
} else if (match(TokenType.NUMBER)) {
|
||||
return new NumberValue(Double.parseDouble(last(1).text));
|
||||
} else if (match(TokenType.STRING)) {
|
||||
return new StringValue(last(1).text);
|
||||
} else if (match(TokenType.LEFT_PAREN)) {
|
||||
// The contents of a parenthesized expression can be any
|
||||
// expression. This lets us "restart" the precedence cascade
|
||||
// so that you can have a lower precedence expression inside
|
||||
// the parentheses.
|
||||
Expression expression = expression();
|
||||
consume(TokenType.RIGHT_PAREN);
|
||||
return expression;
|
||||
}
|
||||
throw new Error("Couldn't parse :(");
|
||||
}
|
||||
|
||||
// The following functions are the core low-level operations that the
|
||||
// grammar parser is built in terms of. They match and consume tokens in
|
||||
// the token stream.
|
||||
|
||||
/**
|
||||
* Consumes the next two tokens if they are the given type (in order). Consumes
|
||||
* no tokens if either check fais.
|
||||
*
|
||||
* @param type1 Expected type of the next token.
|
||||
* @param type2 Expected type of the subsequent token.
|
||||
* @return True if tokens were consumed.
|
||||
*/
|
||||
private boolean match(TokenType type1, TokenType type2) {
|
||||
if (get(0).type != type1)
|
||||
return false;
|
||||
if (get(1).type != type2)
|
||||
return false;
|
||||
position += 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the next token if it's the given type.
|
||||
*
|
||||
* @param type Expected type of the next token.
|
||||
* @return True if the token was consumed.
|
||||
*/
|
||||
private boolean match(TokenType type) {
|
||||
if (get(0).type != type)
|
||||
return false;
|
||||
position++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the next token if it's a word token with the given name.
|
||||
*
|
||||
* @param name Expected name of the next word token.
|
||||
* @return True if the token was consumed.
|
||||
*/
|
||||
private boolean match(String name) {
|
||||
if (get(0).type != TokenType.WORD)
|
||||
return false;
|
||||
if (!get(0).text.equals(name))
|
||||
return false;
|
||||
position++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the next token if it's the given type. If not, throws an exception.
|
||||
* This is for cases where the parser demands a token of a certain type in a
|
||||
* certain position, for example a matching ) after an opening (.
|
||||
*
|
||||
* @param type Expected type of the next token.
|
||||
* @return The consumed token.
|
||||
*/
|
||||
private Token consume(TokenType type) {
|
||||
if (get(0).type != type)
|
||||
throw new Error("Expected " + type + ".");
|
||||
return tokens.get(position++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes the next token if it's a word with the given name. If not, throws an
|
||||
* exception.
|
||||
*
|
||||
* @param name Expected name of the next word token.
|
||||
* @return The consumed token.
|
||||
*/
|
||||
private Token consume(String name) {
|
||||
if (!match(name))
|
||||
throw new Error("Expected " + name + ".");
|
||||
return last(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a previously consumed token, indexing backwards. last(1) will be the
|
||||
* token just consumed, last(2) the one before that, etc.
|
||||
*
|
||||
* @param offset How far back in the token stream to look.
|
||||
* @return The consumed token.
|
||||
*/
|
||||
private Token last(int offset) {
|
||||
return tokens.get(position - offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an unconsumed token, indexing forward. get(0) will be the next token to
|
||||
* be consumed, get(1) the one after that, etc.
|
||||
*
|
||||
* @param offset How far forward in the token stream to look.
|
||||
* @return The yet-to-be-consumed token.
|
||||
*/
|
||||
private Token get(int offset) {
|
||||
if (position + offset >= tokens.size()) {
|
||||
return new Token("", TokenType.EOF);
|
||||
}
|
||||
return tokens.get(position + offset);
|
||||
}
|
||||
|
||||
private final List<Token> tokens;
|
||||
private int position;
|
||||
}
|
||||
|
||||
// Abstract syntax tree (AST) ----------------------------------------------
|
||||
|
||||
// These classes define the syntax tree data structures. This is how code is
|
||||
// represented internally in a way that's easy for the interpreter to
|
||||
// understand.
|
||||
//
|
||||
// HACK: Unlike most real compilers or interpreters, the logic to execute
|
||||
// the code is baked directly into these classes. Typically, it would be
|
||||
// separated out so that the AST us just a static data structure.
|
||||
|
||||
/**
|
||||
* Base interface for a Jasic statement. The different supported statement types
|
||||
* like "print" and "goto" implement this.
|
||||
*/
|
||||
public interface Statement {
|
||||
/**
|
||||
* Statements implement this to actually perform whatever behavior the statement
|
||||
* causes. "print" statements will display text here, "goto" statements will
|
||||
* change the current statement, etc.
|
||||
*/
|
||||
void execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Base interface for an expression. An expression is like a statement except
|
||||
* that it also returns a value when executed. Expressions do not appear at the
|
||||
* top level in Jasic programs, but are used in many statements. For example,
|
||||
* the value printed by a "print" statement is an expression. Unlike statements,
|
||||
* expressions can nest.
|
||||
*/
|
||||
public interface Expression {
|
||||
/**
|
||||
* Expression classes implement this to evaluate the expression and return the
|
||||
* value.
|
||||
*
|
||||
* @return The value of the calculated expression.
|
||||
*/
|
||||
Value evaluate();
|
||||
}
|
||||
|
||||
/**
|
||||
* A "print" statement evaluates an expression, converts the result to a string,
|
||||
* and displays it to the user.
|
||||
*/
|
||||
public class PrintStatement implements Statement {
|
||||
public PrintStatement(Expression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
System.out.println(expression.evaluate().toString());
|
||||
}
|
||||
|
||||
private final Expression expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* An "input" statement reads input from the user and stores it in a variable.
|
||||
*/
|
||||
public class InputStatement implements Statement {
|
||||
public InputStatement(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
String input = lineIn.readLine();
|
||||
|
||||
// Store it as a number if possible, otherwise use a string.
|
||||
try {
|
||||
double value = Double.parseDouble(input);
|
||||
variables.put(name, new NumberValue(value));
|
||||
} catch (NumberFormatException e) {
|
||||
variables.put(name, new StringValue(input));
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
// HACK: Just ignore the problem.
|
||||
}
|
||||
}
|
||||
|
||||
private final String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* An assignment statement evaluates an expression and stores the result in a
|
||||
* variable.
|
||||
*/
|
||||
public class AssignStatement implements Statement {
|
||||
public AssignStatement(String name, Expression value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
variables.put(name, value.evaluate());
|
||||
}
|
||||
|
||||
private final String name;
|
||||
private final Expression value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A "goto" statement jumps execution to another place in the program.
|
||||
*/
|
||||
public class GotoStatement implements Statement {
|
||||
public GotoStatement(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
if (labels.containsKey(label)) {
|
||||
currentStatement = labels.get(label).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
private final String label;
|
||||
}
|
||||
|
||||
/**
|
||||
* An if then statement jumps execution to another place in the program, but
|
||||
* only if an expression evaluates to something other than 0.
|
||||
*/
|
||||
public class IfThenStatement implements Statement {
|
||||
public IfThenStatement(Expression condition, String label) {
|
||||
this.condition = condition;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
if (labels.containsKey(label)) {
|
||||
double value = condition.evaluate().toNumber();
|
||||
if (value != 0) {
|
||||
currentStatement = labels.get(label).intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Expression condition;
|
||||
private final String label;
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable expression evaluates to the current value stored in that variable.
|
||||
*/
|
||||
public class VariableExpression implements Expression {
|
||||
public VariableExpression(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Value evaluate() {
|
||||
if (variables.containsKey(name)) {
|
||||
return variables.get(name);
|
||||
}
|
||||
return new NumberValue(0);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* An operator expression evaluates two expressions and then performs some
|
||||
* arithmetic operation on the results.
|
||||
*/
|
||||
public class OperatorExpression implements Expression {
|
||||
public OperatorExpression(Expression left, char operator, Expression right) {
|
||||
this.left = left;
|
||||
this.operator = operator;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public Value evaluate() {
|
||||
Value leftVal = left.evaluate();
|
||||
Value rightVal = right.evaluate();
|
||||
|
||||
switch (operator) {
|
||||
case '=':
|
||||
// Coerce to the left argument's type, then compare.
|
||||
if (leftVal instanceof NumberValue) {
|
||||
return new NumberValue((leftVal.toNumber() == rightVal.toNumber()) ? 1 : 0);
|
||||
} else {
|
||||
return new NumberValue(leftVal.toString().equals(rightVal.toString()) ? 1 : 0);
|
||||
}
|
||||
case '+':
|
||||
// Addition if the left argument is a number, otherwise do
|
||||
// string concatenation.
|
||||
if (leftVal instanceof NumberValue) {
|
||||
return new NumberValue(leftVal.toNumber() + rightVal.toNumber());
|
||||
} else {
|
||||
return new StringValue(leftVal.toString() + rightVal.toString());
|
||||
}
|
||||
case '-':
|
||||
return new NumberValue(leftVal.toNumber() - rightVal.toNumber());
|
||||
case '*':
|
||||
return new NumberValue(leftVal.toNumber() * rightVal.toNumber());
|
||||
case '/':
|
||||
return new NumberValue(leftVal.toNumber() / rightVal.toNumber());
|
||||
case '<':
|
||||
// Coerce to the left argument's type, then compare.
|
||||
if (leftVal instanceof NumberValue) {
|
||||
return new NumberValue((leftVal.toNumber() < rightVal.toNumber()) ? 1 : 0);
|
||||
} else {
|
||||
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) < 0) ? 1 : 0);
|
||||
}
|
||||
case '>':
|
||||
// Coerce to the left argument's type, then compare.
|
||||
if (leftVal instanceof NumberValue) {
|
||||
return new NumberValue((leftVal.toNumber() > rightVal.toNumber()) ? 1 : 0);
|
||||
} else {
|
||||
return new NumberValue((leftVal.toString().compareTo(rightVal.toString()) > 0) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
throw new Error("Unknown operator.");
|
||||
}
|
||||
|
||||
private final Expression left;
|
||||
private final char operator;
|
||||
private final Expression right;
|
||||
}
|
||||
|
||||
// Value types -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This is the base interface for a value. Values are the data that the
|
||||
* interpreter processes. They are what gets stored in variables, printed, and
|
||||
* operated on.
|
||||
*
|
||||
* There is an implementation of this interface for each of the different
|
||||
* primitive types (really just double and string) that Jasic supports. Wrapping
|
||||
* them in a single Value interface lets Jasic be dynamically-typed and convert
|
||||
* between different representations as needed.
|
||||
*
|
||||
* Note that Value extends Expression. This is a bit of a hack, but it lets us
|
||||
* use values (which are typically only ever seen by the interpreter and not the
|
||||
* parser) as both runtime values, and as object representing literals in code.
|
||||
*/
|
||||
public interface Value extends Expression {
|
||||
/**
|
||||
* Value types override this to convert themselves to a string representation.
|
||||
*/
|
||||
String toString();
|
||||
|
||||
/**
|
||||
* Value types override this to convert themselves to a numeric representation.
|
||||
*/
|
||||
double toNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* A numeric value. Jasic uses doubles internally for all numbers.
|
||||
*/
|
||||
public class NumberValue implements Value {
|
||||
public NumberValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Double.toString(value);
|
||||
}
|
||||
|
||||
public double toNumber() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Value evaluate() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private final double value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A string value.
|
||||
*/
|
||||
public class StringValue implements Value {
|
||||
public StringValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public double toNumber() {
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
public Value evaluate() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private final String value;
|
||||
}
|
||||
|
||||
// Interpreter -------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructs a new Jasic instance. The instance stores the global state of the
|
||||
* interpreter such as the values of all of the variables and the current
|
||||
* statement.
|
||||
*/
|
||||
public Jasic() {
|
||||
variables = new HashMap<String, Value>();
|
||||
labels = new HashMap<String, Integer>();
|
||||
|
||||
InputStreamReader converter = new InputStreamReader(System.in);
|
||||
lineIn = new BufferedReader(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is where the magic happens. This runs the code through the parsing
|
||||
* pipeline to generate the AST. Then it executes each statement. It keeps track
|
||||
* of the current line in a member variable that the statement objects have
|
||||
* access to. This lets "goto" and "if then" do flow control by simply setting
|
||||
* the index of the current statement.
|
||||
*
|
||||
* In an interpreter that didn't mix the interpretation logic in with the AST
|
||||
* node classes, this would be doing a lot more work.
|
||||
*
|
||||
* @param source A string containing the source code of a .jas script to
|
||||
* interpret.
|
||||
*/
|
||||
public void interpret(String source) {
|
||||
// Tokenize.
|
||||
List<Token> tokens = tokenize(source);
|
||||
|
||||
// Parse.
|
||||
Parser parser = new Parser(tokens);
|
||||
List<Statement> statements = parser.parse(labels);
|
||||
|
||||
// Interpret until we're done.
|
||||
currentStatement = 0;
|
||||
while (currentStatement < statements.size()) {
|
||||
int thisStatement = currentStatement;
|
||||
currentStatement++;
|
||||
statements.get(thisStatement).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<String, Value> variables;
|
||||
private final Map<String, Integer> labels;
|
||||
|
||||
private final BufferedReader lineIn;
|
||||
|
||||
private int currentStatement;
|
||||
|
||||
}
|
@ -37,7 +37,6 @@ package net.sourceforge.plantuml.klimt.drawing.g2d;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
@ -50,7 +49,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.anim.AffineTransformation;
|
||||
import net.sourceforge.plantuml.klimt.UAntiAliasing;
|
||||
import net.sourceforge.plantuml.klimt.UChange;
|
||||
import net.sourceforge.plantuml.klimt.UClip;
|
||||
@ -88,10 +86,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
||||
private List<Url> urls = new ArrayList<>();
|
||||
private Set<Url> allUrls = new HashSet<>();
|
||||
|
||||
// ::comment when __CORE__
|
||||
private final boolean hasAffineTransform;
|
||||
// ::done
|
||||
|
||||
public final Set<Url> getAllUrlsEncountered() {
|
||||
return Collections.unmodifiableSet(allUrls);
|
||||
}
|
||||
@ -114,9 +108,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
||||
private UGraphicG2d(UGraphicG2d other) {
|
||||
super(other.getStringBounder());
|
||||
copy(other);
|
||||
// ::comment when __CORE__
|
||||
this.hasAffineTransform = other.hasAffineTransform;
|
||||
// ::done
|
||||
this.dpiFactor = other.dpiFactor;
|
||||
this.bufferedImage = other.bufferedImage;
|
||||
this.urls = other.urls;
|
||||
@ -128,20 +119,6 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
||||
|
||||
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
||||
double dpiFactor, FileFormat format) {
|
||||
// ::revert when __CORE__
|
||||
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0, format, null);
|
||||
// this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, 0, 0,
|
||||
// format);
|
||||
// ::done
|
||||
}
|
||||
|
||||
// ::revert when __CORE__
|
||||
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
|
||||
double dpiFactor, double dx, double dy, FileFormat format, AffineTransformation affineTransform) {
|
||||
// public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper,
|
||||
// StringBounder stringBounder, Graphics2D g2d,
|
||||
// double dpiFactor, double dx, double dy, FileFormat format) {
|
||||
// ::done
|
||||
super(stringBounder);
|
||||
copy(defaultBackground, colorMapper, g2d);
|
||||
this.format = format;
|
||||
@ -149,21 +126,13 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
|
||||
if (dpiFactor != 1.0)
|
||||
g2d.scale(dpiFactor, dpiFactor);
|
||||
|
||||
// ::comment when __CORE__
|
||||
this.hasAffineTransform = affineTransform != null;
|
||||
if (this.hasAffineTransform) {
|
||||
if (dx != 0 || dy != 0)
|
||||
getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy));
|
||||
getGraphicObject().transform(affineTransform.getAffineTransform());
|
||||
}
|
||||
// ::done
|
||||
register(dpiFactor);
|
||||
}
|
||||
|
||||
private void register(double dpiFactor) {
|
||||
registerDriver(URectangle.class, new DriverRectangleG2d(dpiFactor, this));
|
||||
// ::comment when __CORE__
|
||||
if (this.hasAffineTransform || dpiFactor != 1.0)
|
||||
if (dpiFactor != 1.0)
|
||||
registerDriver(UText.class, new DriverTextAsPathG2d(this, getStringBounder()));
|
||||
else
|
||||
// ::done
|
||||
|
@ -1,174 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.logo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class LogoScanner {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove folder when __CORE__
|
||||
// ::remove folder when __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
||||
final private Map<String, Integer> keywordTable = new HashMap<String, Integer>();
|
||||
private char sourceString[];
|
||||
private int sourceLength;
|
||||
private int i;
|
||||
|
||||
public LogoScanner() {
|
||||
keywordTable.put("forward", LogoToken.FORWARD);
|
||||
keywordTable.put("fd", LogoToken.FORWARD);
|
||||
keywordTable.put("back", LogoToken.BACK);
|
||||
keywordTable.put("bk", LogoToken.BACK);
|
||||
keywordTable.put("right", LogoToken.RIGHT);
|
||||
keywordTable.put("rt", LogoToken.RIGHT);
|
||||
keywordTable.put("left", LogoToken.LEFT);
|
||||
keywordTable.put("lt", LogoToken.LEFT);
|
||||
keywordTable.put("penup", LogoToken.PENUP);
|
||||
keywordTable.put("pu", LogoToken.PENUP);
|
||||
keywordTable.put("pendown", LogoToken.PENDOWN);
|
||||
keywordTable.put("pd", LogoToken.PENDOWN);
|
||||
keywordTable.put("hideturtle", LogoToken.HIDETURTLE);
|
||||
keywordTable.put("ht", LogoToken.HIDETURTLE);
|
||||
keywordTable.put("showturtle", LogoToken.SHOWTURTLE);
|
||||
keywordTable.put("st", LogoToken.SHOWTURTLE);
|
||||
keywordTable.put("clearscreen", LogoToken.CLEARSCREEN);
|
||||
keywordTable.put("cs", LogoToken.CLEARSCREEN);
|
||||
keywordTable.put("repeat", LogoToken.REPEAT);
|
||||
keywordTable.put("rep", LogoToken.REPEAT);
|
||||
keywordTable.put("to", LogoToken.TO);
|
||||
keywordTable.put("setpc", LogoToken.SETPC);
|
||||
keywordTable.put("pc", LogoToken.SETPC);
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return i;
|
||||
}
|
||||
|
||||
public void setPosition(int newPosition) {
|
||||
if (i >= 0 && i <= sourceLength) {
|
||||
i = newPosition;
|
||||
} else {
|
||||
i = sourceLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSourceString(String newSourceString) {
|
||||
sourceLength = newSourceString.length();
|
||||
sourceString = newSourceString.concat("\0").toCharArray();
|
||||
i = 0;
|
||||
}
|
||||
|
||||
public String getSourceString() {
|
||||
return new String(sourceString);
|
||||
}
|
||||
|
||||
public String getRestAsString() {
|
||||
skipWhitespace();
|
||||
final String rest = new String(sourceString, i, sourceLength - i + 1);
|
||||
i = sourceLength;
|
||||
return rest;
|
||||
}
|
||||
|
||||
void skipWhitespace() {
|
||||
char c;
|
||||
do {
|
||||
c = sourceString[i++];
|
||||
} while (c == ' ' || c == '\t');
|
||||
i--;
|
||||
}
|
||||
|
||||
public LogoToken getToken() {
|
||||
final LogoToken token = new LogoToken();
|
||||
final StringBuilder lexeme = new StringBuilder();
|
||||
|
||||
if (i >= sourceLength) {
|
||||
token.kind = LogoToken.END_OF_INPUT;
|
||||
return token;
|
||||
}
|
||||
|
||||
// Skip whitespace.
|
||||
skipWhitespace();
|
||||
char c = sourceString[i++];
|
||||
|
||||
// Now figure out what kind of token we've got.
|
||||
if (c == '[' || c == ']') {
|
||||
token.kind = c;
|
||||
token.lexeme = String.valueOf(c);
|
||||
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
do {
|
||||
lexeme.append(c);
|
||||
c = sourceString[i++];
|
||||
} while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
|
||||
i--;
|
||||
token.lexeme = lexeme.toString();
|
||||
token.kind = LogoToken.IDENTIFIER;
|
||||
final Integer keyword = keywordTable.get(token.lexeme);
|
||||
if (keyword != null) {
|
||||
token.kind = keyword;
|
||||
}
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
do {
|
||||
lexeme.append(c);
|
||||
c = sourceString[i++];
|
||||
} while (c >= '0' && c <= '9');
|
||||
boolean hasDecimalPart = false;
|
||||
if (c == '.') {
|
||||
do {
|
||||
lexeme.append(c);
|
||||
c = sourceString[i++];
|
||||
} while (c >= '0' && c <= '9');
|
||||
hasDecimalPart = true;
|
||||
}
|
||||
i--;
|
||||
token.lexeme = lexeme.toString();
|
||||
token.value = Float.parseFloat(token.lexeme);
|
||||
if (hasDecimalPart) {
|
||||
token.kind = LogoToken.FLOAT;
|
||||
} else {
|
||||
token.kind = LogoToken.INTEGER;
|
||||
token.intValue = Integer.parseInt(token.lexeme);
|
||||
}
|
||||
} else if (c == 0) {
|
||||
i--;
|
||||
token.kind = LogoToken.END_OF_INPUT;
|
||||
} else {
|
||||
i--;
|
||||
token.kind = LogoToken.INVALID_TOKEN;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.logo;
|
||||
|
||||
class LogoToken {
|
||||
public final static int END_OF_INPUT = 256;
|
||||
public final static int INVALID_TOKEN = 257;
|
||||
public final static int IDENTIFIER = 258;
|
||||
public final static int FLOAT = 259;
|
||||
public final static int INTEGER = 270;
|
||||
|
||||
public final static int FORWARD = 260;
|
||||
public final static int BACK = 261;
|
||||
public final static int LEFT = 262;
|
||||
public final static int RIGHT = 263;
|
||||
public final static int PENUP = 264;
|
||||
public final static int PENDOWN = 265;
|
||||
public final static int HIDETURTLE = 266;
|
||||
public final static int SHOWTURTLE = 267;
|
||||
public final static int CLEARSCREEN = 268;
|
||||
public final static int REPEAT = 269;
|
||||
public final static int TO = 271;
|
||||
public final static int SETPC = 272;
|
||||
|
||||
public int kind;
|
||||
public String lexeme;
|
||||
public float value;
|
||||
public int intValue;
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.logo;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.plantuml.AbstractPSystem;
|
||||
import net.sourceforge.plantuml.EmptyImageBuilder;
|
||||
import net.sourceforge.plantuml.FileFormat;
|
||||
import net.sourceforge.plantuml.FileFormatOption;
|
||||
import net.sourceforge.plantuml.api.ImageDataSimple;
|
||||
import net.sourceforge.plantuml.core.DiagramDescription;
|
||||
import net.sourceforge.plantuml.core.ImageData;
|
||||
import net.sourceforge.plantuml.core.UmlSource;
|
||||
import net.sourceforge.plantuml.klimt.color.ColorMapper;
|
||||
import net.sourceforge.plantuml.klimt.color.HColors;
|
||||
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
|
||||
import net.sourceforge.plantuml.klimt.drawing.g2d.UGraphicG2d;
|
||||
import net.sourceforge.plantuml.klimt.font.StringBounder;
|
||||
import net.sourceforge.plantuml.png.PngIO;
|
||||
|
||||
public class PSystemLogo extends AbstractPSystem {
|
||||
|
||||
private final List<String> lines = new ArrayList<>();
|
||||
|
||||
public PSystemLogo(UmlSource source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
final protected ImageData exportDiagramNow(OutputStream os, int num, FileFormatOption fileFormat)
|
||||
throws IOException {
|
||||
final int width = 640;
|
||||
final int height = 480;
|
||||
final StringBounder stringBounder = FileFormat.PNG.getDefaultStringBounder();
|
||||
final EmptyImageBuilder builder = new EmptyImageBuilder(fileFormat.getWatermark(), width, height, Color.WHITE,
|
||||
stringBounder);
|
||||
final BufferedImage im = builder.getBufferedImage();
|
||||
final UGraphic ug = new UGraphicG2d(HColors.WHITE, ColorMapper.IDENTITY, stringBounder, builder.getGraphics2D(),
|
||||
1.0, FileFormat.PNG);
|
||||
((UGraphicG2d) ug).setBufferedImage(im);
|
||||
|
||||
final TurtleGraphicsPane turtleGraphicsPane = new TurtleGraphicsPane(width, height);
|
||||
final TinyJavaLogo tinyJavaLogo = new TinyJavaLogo(turtleGraphicsPane);
|
||||
for (String line : lines) {
|
||||
tinyJavaLogo.doCommandLine(line);
|
||||
}
|
||||
turtleGraphicsPane.paint(ug);
|
||||
PngIO.write(im, ColorMapper.IDENTITY, os, null, 96);
|
||||
return new ImageDataSimple(im.getWidth(), im.getHeight());
|
||||
}
|
||||
|
||||
// private GraphicStrings getGraphicStrings() throws IOException {
|
||||
// final UFont font = new UFont("SansSerif", Font.PLAIN, 12);
|
||||
// final GraphicStrings result = new GraphicStrings(strings, font,
|
||||
// HtmlColorUtils.BLACK, HtmlColorUtils.WHITE,
|
||||
// image,
|
||||
// GraphicPosition.BOTTOM, false);
|
||||
// result.setMinWidth(200);
|
||||
// return result;
|
||||
// }
|
||||
|
||||
public DiagramDescription getDescription() {
|
||||
return new DiagramDescription("(Logo)");
|
||||
}
|
||||
|
||||
public void doCommandLine(String line) {
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.logo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.color.HColor;
|
||||
import net.sourceforge.plantuml.klimt.color.HColorSet;
|
||||
|
||||
public class TinyJavaLogo {
|
||||
private final LogoScanner scanner = new LogoScanner();
|
||||
|
||||
private final TurtleGraphicsPane turtleGraphicsPane;
|
||||
|
||||
private final Map<String, String> dictionary = new HashMap<String, String>();
|
||||
private HColor penColor;
|
||||
|
||||
public TinyJavaLogo(TurtleGraphicsPane turtleGraphicsPane) {
|
||||
this.turtleGraphicsPane = turtleGraphicsPane;
|
||||
}
|
||||
|
||||
private void message(String messageText) {
|
||||
// turtleGraphicsPane.message(messageText);
|
||||
}
|
||||
|
||||
private void error(String messageText) {
|
||||
turtleGraphicsPane.message("Error: " + messageText);
|
||||
}
|
||||
|
||||
private void parseCommandBlock(int nestLevel) {
|
||||
String commandName;
|
||||
String code;
|
||||
LogoToken token = scanner.getToken();
|
||||
while (token.kind != LogoToken.END_OF_INPUT && token.kind != LogoToken.INVALID_TOKEN) {
|
||||
switch (token.kind) {
|
||||
case LogoToken.FORWARD:
|
||||
token = scanner.getToken();
|
||||
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
|
||||
turtleGraphicsPane.forward(token.value);
|
||||
token = scanner.getToken();
|
||||
} else {
|
||||
error("FORWARD requires distance");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case LogoToken.BACK:
|
||||
token = scanner.getToken();
|
||||
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
|
||||
turtleGraphicsPane.back(token.value);
|
||||
token = scanner.getToken();
|
||||
} else {
|
||||
error("BACK requires distance");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case LogoToken.LEFT:
|
||||
token = scanner.getToken();
|
||||
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
|
||||
turtleGraphicsPane.left(token.value);
|
||||
token = scanner.getToken();
|
||||
} else {
|
||||
error("LEFT requires turn angle");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case LogoToken.RIGHT:
|
||||
token = scanner.getToken();
|
||||
if (token.kind == LogoToken.FLOAT || token.kind == LogoToken.INTEGER) {
|
||||
turtleGraphicsPane.right(token.value);
|
||||
token = scanner.getToken();
|
||||
} else {
|
||||
error("RIGHT requires turn angle");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case LogoToken.PENUP:
|
||||
turtleGraphicsPane.penUp();
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.PENDOWN:
|
||||
turtleGraphicsPane.penDown();
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.HIDETURTLE:
|
||||
turtleGraphicsPane.hideTurtle();
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.SHOWTURTLE:
|
||||
turtleGraphicsPane.showTurtle();
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.CLEARSCREEN:
|
||||
turtleGraphicsPane.clearScreen();
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.REPEAT:
|
||||
token = scanner.getToken();
|
||||
if (token.kind != LogoToken.INTEGER) {
|
||||
error("REPEAT requires positive integer count");
|
||||
return;
|
||||
}
|
||||
int count = token.intValue;
|
||||
token = scanner.getToken();
|
||||
if (token.kind != '[') {
|
||||
error("REPEAT requires block in []");
|
||||
return;
|
||||
}
|
||||
final int blockStart = scanner.getPosition();
|
||||
while (count-- > 0) {
|
||||
scanner.setPosition(blockStart);
|
||||
parseCommandBlock(nestLevel + 1);
|
||||
}
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.TO:
|
||||
token = scanner.getToken();
|
||||
if (token.kind != LogoToken.IDENTIFIER) {
|
||||
error("TO requires name for new definition");
|
||||
return;
|
||||
}
|
||||
commandName = token.lexeme;
|
||||
if (dictionary.get(commandName) == null) {
|
||||
message("Defining new command " + commandName);
|
||||
} else {
|
||||
message("Redefining command " + commandName);
|
||||
}
|
||||
code = scanner.getRestAsString();
|
||||
dictionary.put(commandName, code);
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.IDENTIFIER:
|
||||
commandName = token.lexeme;
|
||||
code = dictionary.get(commandName);
|
||||
if (code == null) {
|
||||
error("Undefined command " + commandName);
|
||||
return;
|
||||
}
|
||||
final String savedCommand = scanner.getSourceString();
|
||||
final int savedPosition = scanner.getPosition();
|
||||
scanner.setSourceString(code);
|
||||
parseCommandBlock(0);
|
||||
scanner.setSourceString(savedCommand);
|
||||
scanner.setPosition(savedPosition);
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case LogoToken.SETPC:
|
||||
token = scanner.getToken();
|
||||
String s = token.lexeme;
|
||||
final HColor newPenColor = s == null ? null : HColorSet.instance().getColorOrWhite(s);
|
||||
if (newPenColor == null) {
|
||||
error("Unrecognized color name");
|
||||
return;
|
||||
}
|
||||
penColor = newPenColor;
|
||||
turtleGraphicsPane.setPenColor(penColor);
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case '[':
|
||||
token = scanner.getToken();
|
||||
break;
|
||||
|
||||
case ']':
|
||||
if (nestLevel == 0) {
|
||||
error("] without matching [");
|
||||
token = scanner.getToken();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
error("Unrecognized symbol in input");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doCommandLine(String commandLine) {
|
||||
message(commandLine);
|
||||
scanner.setSourceString(commandLine);
|
||||
parseCommandBlock(0);
|
||||
}
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.logo;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.UTranslate;
|
||||
import net.sourceforge.plantuml.klimt.color.HColor;
|
||||
import net.sourceforge.plantuml.klimt.color.HColorSet;
|
||||
import net.sourceforge.plantuml.klimt.color.HColors;
|
||||
import net.sourceforge.plantuml.klimt.creole.Display;
|
||||
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
|
||||
import net.sourceforge.plantuml.klimt.font.FontConfiguration;
|
||||
import net.sourceforge.plantuml.klimt.font.UFont;
|
||||
import net.sourceforge.plantuml.klimt.geom.HorizontalAlignment;
|
||||
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
|
||||
import net.sourceforge.plantuml.klimt.shape.TextBlock;
|
||||
import net.sourceforge.plantuml.klimt.shape.ULine;
|
||||
import net.sourceforge.plantuml.klimt.shape.UPolygon;
|
||||
import net.sourceforge.plantuml.klimt.sprite.SpriteContainerEmpty;
|
||||
|
||||
class TurtleGraphicsPane {
|
||||
final private double width;
|
||||
final private double height;
|
||||
private double x;
|
||||
private double y;
|
||||
private double turtleDirection = 90;
|
||||
private boolean penIsDown = true;
|
||||
private boolean showTurtle = true;
|
||||
private HColor penColor = HColors.BLACK;
|
||||
private List<Rectangle2D.Double> lines = new ArrayList<Rectangle2D.Double>();
|
||||
private List<HColor> colors = new ArrayList<>();
|
||||
|
||||
private String message;
|
||||
|
||||
public TurtleGraphicsPane(int width, int height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
clearScreen();
|
||||
}
|
||||
|
||||
public void clearScreen() {
|
||||
x = width / 2;
|
||||
y = -height / 2;
|
||||
turtleDirection = 90;
|
||||
lines.clear();
|
||||
colors.clear();
|
||||
}
|
||||
|
||||
private double dtor(double degrees) {
|
||||
return degrees * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
private void drawTurtle(UGraphic ug) {
|
||||
if (showTurtle == false) {
|
||||
return;
|
||||
}
|
||||
final UPolygon poly = new UPolygon();
|
||||
double size = 2;
|
||||
double deltax = 4.5 * size;
|
||||
poly.addPoint(0 * size - deltax, 0);
|
||||
poly.addPoint(0 * size - deltax, -2 * size);
|
||||
poly.addPoint(1 * size - deltax, -2 * size);
|
||||
poly.addPoint(1 * size - deltax, -4 * size);
|
||||
poly.addPoint(2 * size - deltax, -4 * size);
|
||||
poly.addPoint(2 * size - deltax, -6 * size);
|
||||
poly.addPoint(3 * size - deltax, -6 * size);
|
||||
poly.addPoint(3 * size - deltax, -8 * size);
|
||||
poly.addPoint(4 * size - deltax, -8 * size);
|
||||
poly.addPoint(4 * size - deltax, -9 * size);
|
||||
poly.addPoint(5 * size - deltax, -9 * size);
|
||||
poly.addPoint(5 * size - deltax, -8 * size);
|
||||
poly.addPoint(6 * size - deltax, -8 * size);
|
||||
poly.addPoint(6 * size - deltax, -6 * size);
|
||||
poly.addPoint(7 * size - deltax, -6 * size);
|
||||
poly.addPoint(7 * size - deltax, -4 * size);
|
||||
poly.addPoint(8 * size - deltax, -4 * size);
|
||||
poly.addPoint(8 * size - deltax, -2 * size);
|
||||
poly.addPoint(9 * size - deltax, -2 * size);
|
||||
poly.addPoint(9 * size - deltax, 0);
|
||||
poly.addPoint(0 * size - deltax, 0);
|
||||
final double angle = -dtor(turtleDirection - 90);
|
||||
poly.rotate(angle);
|
||||
// ug.setAntiAliasing(false);
|
||||
final HColorSet htmlColorSet = HColorSet.instance();
|
||||
final HColor turtleColor1 = htmlColorSet.getColorOrWhite("OliveDrab");
|
||||
final HColor turtleColor2 = htmlColorSet.getColorOrWhite("MediumSpringGreen");
|
||||
|
||||
ug.apply(turtleColor1).apply(turtleColor2.bg()).apply(new UTranslate(x, -y)).draw(poly);
|
||||
// ug.setAntiAliasing(true);
|
||||
}
|
||||
|
||||
public void showTurtle() {
|
||||
showTurtle = true;
|
||||
}
|
||||
|
||||
public void hideTurtle() {
|
||||
showTurtle = false;
|
||||
}
|
||||
|
||||
public void setPenColor(HColor newPenColor) {
|
||||
penColor = newPenColor;
|
||||
}
|
||||
|
||||
void addLine(double x1, double y1, double x2, double y2) {
|
||||
lines.add(new Rectangle2D.Double(x1, y1, x2, y2));
|
||||
colors.add(penColor);
|
||||
}
|
||||
|
||||
public void forward(double distance) {
|
||||
double angle = dtor(turtleDirection);
|
||||
double newX = x + distance * Math.cos(angle);
|
||||
double newY = y + distance * Math.sin(angle);
|
||||
if (penIsDown) {
|
||||
addLine(x, y, newX, newY);
|
||||
x = newX;
|
||||
y = newY;
|
||||
} else {
|
||||
x = newX;
|
||||
y = newY;
|
||||
}
|
||||
}
|
||||
|
||||
public void back(double distance) {
|
||||
forward(-distance);
|
||||
}
|
||||
|
||||
public void left(double turnAngle) {
|
||||
turtleDirection += turnAngle;
|
||||
while (turtleDirection > 360) {
|
||||
turtleDirection -= 360;
|
||||
}
|
||||
while (turtleDirection < 0) {
|
||||
turtleDirection += 360;
|
||||
}
|
||||
}
|
||||
|
||||
public void right(double turnAngle) {
|
||||
left(-turnAngle);
|
||||
}
|
||||
|
||||
public void penUp() {
|
||||
penIsDown = false;
|
||||
}
|
||||
|
||||
public void penDown() {
|
||||
penIsDown = true;
|
||||
}
|
||||
|
||||
public void paint(UGraphic ug) {
|
||||
int n = lines.size();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
final HColor color = colors.get(i);
|
||||
final Rectangle2D.Double r = lines.get(i);
|
||||
final ULine line = new ULine(r.width - r.x, -r.height + r.y);
|
||||
ug.apply(color).apply(new UTranslate(r.x, -r.y)).draw(line);
|
||||
|
||||
}
|
||||
drawTurtle(ug);
|
||||
if (message != null) {
|
||||
final FontConfiguration font = FontConfiguration.blackBlueTrue(UFont.build("", Font.PLAIN, 14));
|
||||
final TextBlock text = Display.create(message).create(font, HorizontalAlignment.LEFT,
|
||||
new SpriteContainerEmpty());
|
||||
final XDimension2D dim = text.calculateDimension(ug.getStringBounder());
|
||||
final double textHeight = dim.getHeight();
|
||||
text.drawU(ug.apply(UTranslate.dy((height - textHeight))));
|
||||
}
|
||||
}
|
||||
|
||||
public void message(String messageText) {
|
||||
this.message = messageText;
|
||||
}
|
||||
|
||||
}
|
@ -1,493 +0,0 @@
|
||||
/*
|
||||
* MJPEGGenerator.java
|
||||
*
|
||||
* Created on April 17, 2006, 11:48 PM
|
||||
*
|
||||
* To change this template, choose Tools | Options and locate the template under
|
||||
* the Source Creation and Management node. Right-click the template and choose
|
||||
* Open. You can then make changes to the template in the Source Editor.
|
||||
*/
|
||||
|
||||
package net.sourceforge.plantuml.mjpeg;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sourceforge.plantuml.security.SFile;
|
||||
import net.sourceforge.plantuml.security.SImageIO;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author monceaux
|
||||
*/
|
||||
public class MJPEGGenerator {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove folder when __CORE__
|
||||
/*
|
||||
* Info needed for MJPEG AVI
|
||||
*
|
||||
* - size of file minus "RIFF & 4 byte file size"
|
||||
*
|
||||
*/
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
double framerate = 0;
|
||||
int numFrames = 0;
|
||||
SFile aviFile = null;
|
||||
FileOutputStream aviOutput = null;
|
||||
FileChannel aviChannel = null;
|
||||
|
||||
long riffOffset = 0;
|
||||
long aviMovieOffset = 0;
|
||||
|
||||
AVIIndexList indexlist = null;
|
||||
|
||||
/** Creates a new instance of MJPEGGenerator */
|
||||
public MJPEGGenerator(SFile aviFile, int width, int height, double framerate, int numFrames) throws IOException {
|
||||
this.aviFile = aviFile;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.framerate = framerate;
|
||||
this.numFrames = numFrames;
|
||||
aviOutput = aviFile.createFileOutputStream();
|
||||
aviChannel = aviOutput.getChannel();
|
||||
|
||||
RIFFHeader rh = new RIFFHeader();
|
||||
aviOutput.write(rh.toBytes());
|
||||
aviOutput.write(new AVIMainHeader().toBytes());
|
||||
aviOutput.write(new AVIStreamList().toBytes());
|
||||
aviOutput.write(new AVIStreamHeader().toBytes());
|
||||
aviOutput.write(new AVIStreamFormat().toBytes());
|
||||
aviOutput.write(new AVIJunk().toBytes());
|
||||
aviMovieOffset = aviChannel.position();
|
||||
aviOutput.write(new AVIMovieList().toBytes());
|
||||
indexlist = new AVIIndexList();
|
||||
}
|
||||
|
||||
public void addImage(Image image) throws IOException {
|
||||
byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
|
||||
byte[] imagedata = writeImageToBytes(image);
|
||||
int useLength = imagedata.length;
|
||||
long position = aviChannel.position();
|
||||
int extra = (useLength + (int) position) % 4;
|
||||
if (extra > 0)
|
||||
useLength = useLength + extra;
|
||||
|
||||
indexlist.addAVIIndex((int) position, useLength);
|
||||
|
||||
aviOutput.write(fcc);
|
||||
aviOutput.write(intBytes(swapInt(useLength)));
|
||||
aviOutput.write(imagedata);
|
||||
if (extra > 0) {
|
||||
for (int i = 0; i < extra; i++)
|
||||
aviOutput.write(0);
|
||||
}
|
||||
imagedata = null;
|
||||
}
|
||||
|
||||
public void finishAVI() throws IOException {
|
||||
byte[] indexlistBytes = indexlist.toBytes();
|
||||
aviOutput.write(indexlistBytes);
|
||||
aviOutput.close();
|
||||
long size = aviFile.length();
|
||||
RandomAccessFile raf = new RandomAccessFile(aviFile.conv(), "rw");
|
||||
raf.seek(4);
|
||||
raf.write(intBytes(swapInt((int) size - 8)));
|
||||
raf.seek(aviMovieOffset + 4);
|
||||
raf.write(intBytes(swapInt((int) (size - 8 - aviMovieOffset - indexlistBytes.length))));
|
||||
raf.close();
|
||||
}
|
||||
|
||||
// public void writeAVI(File file) throws Exception
|
||||
// {
|
||||
// OutputStream os = SecurityUtils.FileOutputStream(file);
|
||||
//
|
||||
// // RIFFHeader
|
||||
// // AVIMainHeader
|
||||
// // AVIStreamList
|
||||
// // AVIStreamHeader
|
||||
// // AVIStreamFormat
|
||||
// // write 00db and image bytes...
|
||||
// }
|
||||
|
||||
public static int swapInt(int v) {
|
||||
return (v >>> 24) | (v << 24) | ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00);
|
||||
}
|
||||
|
||||
public static short swapShort(short v) {
|
||||
return (short) ((v >>> 8) | (v << 8));
|
||||
}
|
||||
|
||||
public static byte[] intBytes(int i) {
|
||||
byte[] b = new byte[4];
|
||||
b[0] = (byte) (i >>> 24);
|
||||
b[1] = (byte) ((i >>> 16) & 0x000000FF);
|
||||
b[2] = (byte) ((i >>> 8) & 0x000000FF);
|
||||
b[3] = (byte) (i & 0x000000FF);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public static byte[] shortBytes(short i) {
|
||||
byte[] b = new byte[2];
|
||||
b[0] = (byte) (i >>> 8);
|
||||
b[1] = (byte) (i & 0x000000FF);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private class RIFFHeader {
|
||||
public byte[] fcc = new byte[] { 'R', 'I', 'F', 'F' };
|
||||
public int fileSize = 0;
|
||||
public byte[] fcc2 = new byte[] { 'A', 'V', 'I', ' ' };
|
||||
public byte[] fcc3 = new byte[] { 'L', 'I', 'S', 'T' };
|
||||
public int listSize = 200;
|
||||
public byte[] fcc4 = new byte[] { 'h', 'd', 'r', 'l' };
|
||||
|
||||
public RIFFHeader() {
|
||||
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(fileSize)));
|
||||
baos.write(fcc2);
|
||||
baos.write(fcc3);
|
||||
baos.write(intBytes(swapInt(listSize)));
|
||||
baos.write(fcc4);
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIMainHeader {
|
||||
/*
|
||||
*
|
||||
* FOURCC fcc; DWORD cb; DWORD dwMicroSecPerFrame; DWORD dwMaxBytesPerSec; DWORD
|
||||
* dwPaddingGranularity; DWORD dwFlags; DWORD dwTotalFrames; DWORD
|
||||
* dwInitialFrames; DWORD dwStreams; DWORD dwSuggestedBufferSize; DWORD dwWidth;
|
||||
* DWORD dwHeight; DWORD dwReserved[4];
|
||||
*/
|
||||
|
||||
public byte[] fcc = new byte[] { 'a', 'v', 'i', 'h' };
|
||||
public int cb = 56;
|
||||
public int dwMicroSecPerFrame = 0; // (1 / frames per sec) * 1,000,000
|
||||
public int dwMaxBytesPerSec = 10000000;
|
||||
public int dwPaddingGranularity = 0;
|
||||
public int dwFlags = 65552;
|
||||
public int dwTotalFrames = 0; // replace with correct value
|
||||
public int dwInitialFrames = 0;
|
||||
public int dwStreams = 1;
|
||||
public int dwSuggestedBufferSize = 0;
|
||||
public int dwWidth = 0; // replace with correct value
|
||||
public int dwHeight = 0; // replace with correct value
|
||||
public int[] dwReserved = new int[4];
|
||||
|
||||
public AVIMainHeader() {
|
||||
dwMicroSecPerFrame = (int) ((1.0 / framerate) * 1000000.0);
|
||||
dwWidth = width;
|
||||
dwHeight = height;
|
||||
dwTotalFrames = numFrames;
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(cb)));
|
||||
baos.write(intBytes(swapInt(dwMicroSecPerFrame)));
|
||||
baos.write(intBytes(swapInt(dwMaxBytesPerSec)));
|
||||
baos.write(intBytes(swapInt(dwPaddingGranularity)));
|
||||
baos.write(intBytes(swapInt(dwFlags)));
|
||||
baos.write(intBytes(swapInt(dwTotalFrames)));
|
||||
baos.write(intBytes(swapInt(dwInitialFrames)));
|
||||
baos.write(intBytes(swapInt(dwStreams)));
|
||||
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
|
||||
baos.write(intBytes(swapInt(dwWidth)));
|
||||
baos.write(intBytes(swapInt(dwHeight)));
|
||||
baos.write(intBytes(swapInt(dwReserved[0])));
|
||||
baos.write(intBytes(swapInt(dwReserved[1])));
|
||||
baos.write(intBytes(swapInt(dwReserved[2])));
|
||||
baos.write(intBytes(swapInt(dwReserved[3])));
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIStreamList {
|
||||
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
|
||||
public int size = 124;
|
||||
public byte[] fcc2 = new byte[] { 's', 't', 'r', 'l' };
|
||||
|
||||
public AVIStreamList() {
|
||||
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(size)));
|
||||
baos.write(fcc2);
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIStreamHeader {
|
||||
/*
|
||||
* FOURCC fcc; DWORD cb; FOURCC fccType; FOURCC fccHandler; DWORD dwFlags; WORD
|
||||
* wPriority; WORD wLanguage; DWORD dwInitialFrames; DWORD dwScale; DWORD
|
||||
* dwRate; DWORD dwStart; DWORD dwLength; DWORD dwSuggestedBufferSize; DWORD
|
||||
* dwQuality; DWORD dwSampleSize; struct { short int left; short int top; short
|
||||
* int right; short int bottom; } rcFrame;
|
||||
*/
|
||||
|
||||
public byte[] fcc = new byte[] { 's', 't', 'r', 'h' };
|
||||
public int cb = 64;
|
||||
public byte[] fccType = new byte[] { 'v', 'i', 'd', 's' };
|
||||
public byte[] fccHandler = new byte[] { 'M', 'J', 'P', 'G' };
|
||||
public int dwFlags = 0;
|
||||
public short wPriority = 0;
|
||||
public short wLanguage = 0;
|
||||
public int dwInitialFrames = 0;
|
||||
public int dwScale = 0; // microseconds per frame
|
||||
public int dwRate = 1000000; // dwRate / dwScale = frame rate
|
||||
public int dwStart = 0;
|
||||
public int dwLength = 0; // num frames
|
||||
public int dwSuggestedBufferSize = 0;
|
||||
public int dwQuality = -1;
|
||||
public int dwSampleSize = 0;
|
||||
public int left = 0;
|
||||
public int top = 0;
|
||||
public int right = 0;
|
||||
public int bottom = 0;
|
||||
|
||||
public AVIStreamHeader() {
|
||||
dwScale = (int) ((1.0 / framerate) * 1000000.0);
|
||||
dwLength = numFrames;
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(cb)));
|
||||
baos.write(fccType);
|
||||
baos.write(fccHandler);
|
||||
baos.write(intBytes(swapInt(dwFlags)));
|
||||
baos.write(shortBytes(swapShort(wPriority)));
|
||||
baos.write(shortBytes(swapShort(wLanguage)));
|
||||
baos.write(intBytes(swapInt(dwInitialFrames)));
|
||||
baos.write(intBytes(swapInt(dwScale)));
|
||||
baos.write(intBytes(swapInt(dwRate)));
|
||||
baos.write(intBytes(swapInt(dwStart)));
|
||||
baos.write(intBytes(swapInt(dwLength)));
|
||||
baos.write(intBytes(swapInt(dwSuggestedBufferSize)));
|
||||
baos.write(intBytes(swapInt(dwQuality)));
|
||||
baos.write(intBytes(swapInt(dwSampleSize)));
|
||||
baos.write(intBytes(swapInt(left)));
|
||||
baos.write(intBytes(swapInt(top)));
|
||||
baos.write(intBytes(swapInt(right)));
|
||||
baos.write(intBytes(swapInt(bottom)));
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIStreamFormat {
|
||||
/*
|
||||
* FOURCC fcc; DWORD cb; DWORD biSize; LONG biWidth; LONG biHeight; WORD
|
||||
* biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG
|
||||
* biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;
|
||||
*/
|
||||
|
||||
public byte[] fcc = new byte[] { 's', 't', 'r', 'f' };
|
||||
public int cb = 40;
|
||||
public int biSize = 40; // same as cb
|
||||
public int biWidth = 0;
|
||||
public int biHeight = 0;
|
||||
public short biPlanes = 1;
|
||||
public short biBitCount = 24;
|
||||
public byte[] biCompression = new byte[] { 'M', 'J', 'P', 'G' };
|
||||
public int biSizeImage = 0; // width x height in pixels
|
||||
public int biXPelsPerMeter = 0;
|
||||
public int biYPelsPerMeter = 0;
|
||||
public int biClrUsed = 0;
|
||||
public int biClrImportant = 0;
|
||||
|
||||
public AVIStreamFormat() {
|
||||
biWidth = width;
|
||||
biHeight = height;
|
||||
biSizeImage = width * height;
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(cb)));
|
||||
baos.write(intBytes(swapInt(biSize)));
|
||||
baos.write(intBytes(swapInt(biWidth)));
|
||||
baos.write(intBytes(swapInt(biHeight)));
|
||||
baos.write(shortBytes(swapShort(biPlanes)));
|
||||
baos.write(shortBytes(swapShort(biBitCount)));
|
||||
baos.write(biCompression);
|
||||
baos.write(intBytes(swapInt(biSizeImage)));
|
||||
baos.write(intBytes(swapInt(biXPelsPerMeter)));
|
||||
baos.write(intBytes(swapInt(biYPelsPerMeter)));
|
||||
baos.write(intBytes(swapInt(biClrUsed)));
|
||||
baos.write(intBytes(swapInt(biClrImportant)));
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIMovieList {
|
||||
public byte[] fcc = new byte[] { 'L', 'I', 'S', 'T' };
|
||||
public int listSize = 0;
|
||||
public byte[] fcc2 = new byte[] { 'm', 'o', 'v', 'i' };
|
||||
// 00db size jpg image data ...
|
||||
|
||||
public AVIMovieList() {
|
||||
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(listSize)));
|
||||
baos.write(fcc2);
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIIndexList {
|
||||
public byte[] fcc = new byte[] { 'i', 'd', 'x', '1' };
|
||||
public int cb = 0;
|
||||
public ArrayList ind = new ArrayList();
|
||||
|
||||
public AVIIndexList() {
|
||||
|
||||
}
|
||||
|
||||
public void addAVIIndex(AVIIndex ai) {
|
||||
ind.add(ai);
|
||||
}
|
||||
|
||||
public void addAVIIndex(int dwOffset, int dwSize) {
|
||||
ind.add(new AVIIndex(dwOffset, dwSize));
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
cb = 16 * ind.size();
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(cb)));
|
||||
for (int i = 0; i < ind.size(); i++) {
|
||||
AVIIndex in = (AVIIndex) ind.get(i);
|
||||
baos.write(in.toBytes());
|
||||
}
|
||||
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIIndex {
|
||||
public byte[] fcc = new byte[] { '0', '0', 'd', 'b' };
|
||||
public int dwFlags = 16;
|
||||
public int dwOffset = 0;
|
||||
public int dwSize = 0;
|
||||
|
||||
public AVIIndex(int dwOffset, int dwSize) {
|
||||
this.dwOffset = dwOffset;
|
||||
this.dwSize = dwSize;
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(dwFlags)));
|
||||
baos.write(intBytes(swapInt(dwOffset)));
|
||||
baos.write(intBytes(swapInt(dwSize)));
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class AVIJunk {
|
||||
public byte[] fcc = new byte[] { 'J', 'U', 'N', 'K' };
|
||||
public int size = 1808;
|
||||
public byte[] data = new byte[size];
|
||||
|
||||
public AVIJunk() {
|
||||
Arrays.fill(data, (byte) 0);
|
||||
}
|
||||
|
||||
public byte[] toBytes() throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
baos.write(fcc);
|
||||
baos.write(intBytes(swapInt(size)));
|
||||
baos.write(data);
|
||||
baos.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] writeImageToBytes(Image image) throws IOException {
|
||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
Graphics2D g = bi.createGraphics();
|
||||
g.drawImage(image, 0, 0, width, height, null);
|
||||
SImageIO.write(bi, "jpg", baos);
|
||||
baos.close();
|
||||
bi = null;
|
||||
g = null;
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
// public static void main(String[] args) throws Exception {
|
||||
// double framerate = 12.0;
|
||||
// double transitionDuration = 1; // seconds
|
||||
// double slideDuration = 3; // seconds
|
||||
//
|
||||
// File photoDir = SecurityUtils.file(args[0]);
|
||||
// File[] files = photoDir.listFiles(new FilenameFilter() {
|
||||
// public boolean accept(java.io.File dir, String name) {
|
||||
// if (StringUtils.goLowerCase(name).endsWith("jpg"))
|
||||
// return true;
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// int numFrames = (int) (files.length * framerate * (slideDuration + transitionDuration)
|
||||
// + (transitionDuration * framerate));
|
||||
// MJPEGGenerator m = new MJPEGGenerator(SecurityUtils.file(args[1]), 640, 480, framerate, numFrames);
|
||||
// for (int i = 0; i < files.length; i++) {
|
||||
// System.out.println("processing file " + i);
|
||||
// ImageIcon ii = new ImageIcon(files[i].getCanonicalPath());
|
||||
// m.addImage(ii.getImage());
|
||||
// }
|
||||
// m.finishAVI();
|
||||
// }
|
||||
|
||||
}
|
@ -35,23 +35,20 @@
|
||||
*/
|
||||
package net.sourceforge.plantuml.png;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.color.ColorMapper;
|
||||
import net.sourceforge.plantuml.quantization.Quantizer;
|
||||
import net.sourceforge.plantuml.security.SFile;
|
||||
import net.sourceforge.plantuml.security.SImageIO;
|
||||
import net.sourceforge.plantuml.utils.Log;
|
||||
|
||||
public class PngIO {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove folder when __HAXE__
|
||||
|
||||
// ::comment when __CORE__
|
||||
private static final String copyleft = "Generated by https://plantuml.com";
|
||||
public static boolean USE_QUANTIZATION = false;
|
||||
|
||||
public static void write(RenderedImage image, ColorMapper mapper, SFile file, String metadata, int dpi)
|
||||
throws IOException {
|
||||
@ -76,9 +73,6 @@ public class PngIO {
|
||||
String debugData) throws IOException {
|
||||
|
||||
// ::comment when __CORE__
|
||||
if (USE_QUANTIZATION)
|
||||
image = Quantizer.quantizeNow(mapper, (BufferedImage) image);
|
||||
|
||||
if (metadata == null)
|
||||
// ::done
|
||||
SImageIO.write(image, "png", os);
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Provides a stable ordering of objects, such that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>compare(a, b) == 0 iff a == b</li>
|
||||
* <li>sign(compare(a, b)) == -sign(compare(b, a))</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Similar to Guava's {code Ordering.arbitrary()}.
|
||||
*/
|
||||
final class ArbitraryComparator implements Comparator<Object> {
|
||||
public static final ArbitraryComparator INSTANCE = new ArbitraryComparator();
|
||||
|
||||
/**
|
||||
* If we have no other way to order two objects in a stable manner, we will
|
||||
* register both in this map and order them according to their associated
|
||||
* values. The map's values are just integers corresponding to the order in
|
||||
* which objects were added.
|
||||
*/
|
||||
private static final WeakHashMap<Object, Integer> objectIds = new WeakHashMap<>();
|
||||
|
||||
private ArbitraryComparator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(Object a, Object b) {
|
||||
if (a == b)
|
||||
return 0;
|
||||
if (a == null)
|
||||
return -1;
|
||||
if (b == null)
|
||||
return 1;
|
||||
|
||||
int identityHashCodeDifference = System.identityHashCode(a) - System.identityHashCode(b);
|
||||
if (identityHashCodeDifference != 0) {
|
||||
return identityHashCodeDifference;
|
||||
}
|
||||
|
||||
// We have an identityHashCode collision.
|
||||
return getObjectId(a) - getObjectId(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of an object, adding it to the ID map if it isn't already
|
||||
* registered.
|
||||
*/
|
||||
private static int getObjectId(Object object) {
|
||||
synchronized (objectIds) {
|
||||
Integer id = objectIds.get(object);
|
||||
if (id == null) {
|
||||
id = objectIds.size();
|
||||
objectIds.put(object, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface ColorQuantizer {
|
||||
/**
|
||||
* Quantize the given set of colors, returning a set no larger than
|
||||
* {@code maxColors}.
|
||||
*
|
||||
* <p>
|
||||
* The intent is to pick a set of colors which are representative of the
|
||||
* original color set, but no specific guarantees are made.
|
||||
*
|
||||
* @param originalColors the colors in the original image
|
||||
* @param maxColorCount the maximum number of colors to allow
|
||||
* @return a quantized collection of colors no larger than {@code maxColors}
|
||||
*/
|
||||
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface Ditherer {
|
||||
// ::remove folder when __HAXE__
|
||||
/**
|
||||
* Dither the given image, producing a new image which only contains colors from
|
||||
* the given color set.
|
||||
*
|
||||
* @param image the original, unquantized image
|
||||
* @param newColors the quantized set of colors to be used in the new image
|
||||
* @return a new image containing only of colors from {@code newColors}
|
||||
*/
|
||||
public QImage dither(QImage image, Set<QColor> newColors);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class FloydSteinbergDitherer implements Ditherer {
|
||||
public static final FloydSteinbergDitherer INSTANCE = new FloydSteinbergDitherer();
|
||||
|
||||
private static final ErrorComponent[] ERROR_DISTRIBUTION = { new ErrorComponent(1, 0, 7.0 / 16.0),
|
||||
new ErrorComponent(-1, 1, 3.0 / 16.0), new ErrorComponent(0, 1, 5.0 / 16.0),
|
||||
new ErrorComponent(1, 1, 1.0 / 16.0) };
|
||||
|
||||
private FloydSteinbergDitherer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public QImage dither(QImage image, Set<QColor> newColors) {
|
||||
final int width = image.getWidth();
|
||||
final int height = image.getHeight();
|
||||
QColor[][] colors = new QColor[height][width];
|
||||
for (int y = 0; y < height; ++y)
|
||||
for (int x = 0; x < width; ++x)
|
||||
colors[y][x] = image.getColor(x, y);
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
for (int x = 0; x < width; ++x) {
|
||||
final QColor originalColor = colors[y][x];
|
||||
final QColor replacementColor = originalColor.getNearestColor(newColors);
|
||||
colors[y][x] = replacementColor;
|
||||
final QColor error = originalColor.minus(replacementColor);
|
||||
|
||||
for (ErrorComponent component : ERROR_DISTRIBUTION) {
|
||||
int siblingX = x + component.deltaX, siblingY = y + component.deltaY;
|
||||
if (siblingX >= 0 && siblingY >= 0 && siblingX < width && siblingY < height) {
|
||||
QColor errorComponent = error.scaled(component.errorFraction);
|
||||
colors[siblingY][siblingX] = colors[siblingY][siblingX].plus(errorComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QImage.fromColors(colors);
|
||||
}
|
||||
|
||||
private static final class ErrorComponent {
|
||||
final int deltaX, deltaY;
|
||||
final double errorFraction;
|
||||
|
||||
ErrorComponent(int deltaX, int deltaY, double errorFraction) {
|
||||
this.deltaX = deltaX;
|
||||
this.deltaY = deltaY;
|
||||
this.errorFraction = errorFraction;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
public final class HashMultiset<E> extends AbstractCollection<E> implements Multiset<E> {
|
||||
private final Map<E, Count> elementCounts = new HashMap<>();
|
||||
private int size;
|
||||
|
||||
public HashMultiset() {
|
||||
}
|
||||
|
||||
public HashMultiset(Collection<E> source) {
|
||||
addAll(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(E element, int n) {
|
||||
Count count = elementCounts.get(element);
|
||||
if (count != null)
|
||||
count.value += n;
|
||||
else
|
||||
elementCounts.put(element, new Count(n));
|
||||
|
||||
size += n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E element) {
|
||||
add(element, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remove(Object element, int n) {
|
||||
Count count = elementCounts.get(element);
|
||||
if (count == null)
|
||||
return 0;
|
||||
|
||||
if (n < count.value) {
|
||||
count.value -= n;
|
||||
size -= n;
|
||||
return n;
|
||||
}
|
||||
|
||||
elementCounts.remove(element);
|
||||
size -= count.value;
|
||||
return count.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object element) {
|
||||
return remove(element, 1) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new HashMultisetIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int count(Object element) {
|
||||
Count countOrNull = elementCounts.get(element);
|
||||
return countOrNull != null ? countOrNull.value : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<E> getDistinctElements() {
|
||||
return elementCounts.keySet();
|
||||
}
|
||||
|
||||
private final class HashMultisetIterator implements Iterator<E> {
|
||||
final private Iterator<Map.Entry<E, Count>> distinctElementIterator;
|
||||
private E currentElement;
|
||||
private int currentCount;
|
||||
private boolean currentElementRemoved;
|
||||
|
||||
HashMultisetIterator() {
|
||||
this.distinctElementIterator = elementCounts.entrySet().iterator();
|
||||
this.currentCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return currentCount > 0 || distinctElementIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (hasNext() == false)
|
||||
throw new NoSuchElementException("iterator has been exhausted");
|
||||
|
||||
if (currentCount == 0) {
|
||||
Map.Entry<E, Count> next = distinctElementIterator.next();
|
||||
currentElement = next.getKey();
|
||||
currentCount = next.getValue().value;
|
||||
}
|
||||
|
||||
currentCount--;
|
||||
currentElementRemoved = false;
|
||||
return currentElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (currentElement == null)
|
||||
throw new IllegalStateException("next() has not been called");
|
||||
|
||||
if (currentElementRemoved)
|
||||
throw new IllegalStateException("remove() already called for current element");
|
||||
|
||||
HashMultiset.this.remove(currentElement);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Count {
|
||||
private int value;
|
||||
|
||||
Count(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Uses k-means clustering for color quantization. This tends to yield good
|
||||
* results, but convergence can be slow. It is not recommended for large images.
|
||||
*/
|
||||
public final class KMeansQuantizer implements ColorQuantizer {
|
||||
public static final KMeansQuantizer INSTANCE = new KMeansQuantizer();
|
||||
|
||||
private KMeansQuantizer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
|
||||
Map<QColor, Multiset<QColor>> clustersByCentroid = new LinkedHashMap<>();
|
||||
Set<QColor> centroidsToRecompute = getInitialCentroids(originalColors, maxColorCount);
|
||||
for (QColor centroid : centroidsToRecompute)
|
||||
clustersByCentroid.put(centroid, new HashMultiset<QColor>());
|
||||
|
||||
for (QColor color : originalColors.getDistinctElements()) {
|
||||
final int count = originalColors.count(color);
|
||||
clustersByCentroid.get(color.getNearestColor(centroidsToRecompute)).add(color, count);
|
||||
}
|
||||
|
||||
while (centroidsToRecompute.isEmpty() == false) {
|
||||
recomputeCentroids(clustersByCentroid, centroidsToRecompute);
|
||||
centroidsToRecompute.clear();
|
||||
|
||||
Set<QColor> allCentroids = clustersByCentroid.keySet();
|
||||
for (QColor centroid : clustersByCentroid.keySet()) {
|
||||
Multiset<QColor> cluster = clustersByCentroid.get(centroid);
|
||||
for (QColor color : new ArrayList<>(cluster.getDistinctElements())) {
|
||||
QColor newCentroid = color.getNearestColor(allCentroids);
|
||||
if (newCentroid != centroid) {
|
||||
final int count = cluster.count(color);
|
||||
final Multiset<QColor> newCluster = clustersByCentroid.get(newCentroid);
|
||||
|
||||
cluster.remove(color, count);
|
||||
newCluster.add(color, count);
|
||||
|
||||
centroidsToRecompute.add(centroid);
|
||||
centroidsToRecompute.add(newCentroid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clustersByCentroid.keySet();
|
||||
}
|
||||
|
||||
private static void recomputeCentroids(Map<QColor, Multiset<QColor>> clustersByCentroid,
|
||||
Set<QColor> centroidsToRecompute) {
|
||||
for (QColor oldCentroid : centroidsToRecompute) {
|
||||
final Multiset<QColor> cluster = clustersByCentroid.get(oldCentroid);
|
||||
final QColor newCentroid = QColor.getCentroid(cluster);
|
||||
clustersByCentroid.remove(oldCentroid);
|
||||
clustersByCentroid.put(newCentroid, cluster);
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<QColor> getInitialCentroids(Multiset<QColor> originalColors, int maxColorCount) {
|
||||
// We use the Forgy initialization method: choose random colors as initial
|
||||
// cluster centroids.
|
||||
final List<QColor> colorList = new ArrayList<>(originalColors.getDistinctElements());
|
||||
Collections.shuffle(colorList);
|
||||
return new HashSet<>(colorList.subList(0, maxColorCount));
|
||||
}
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Implements median cut quantization.
|
||||
*
|
||||
* <p>
|
||||
* The algorithm works as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Begin with one cluster containing all the original colors.</li>
|
||||
* <li>Find the cluster containing the greatest spread along a single color
|
||||
* component (red, green or blue).</li>
|
||||
* <li>Find the median of that color component among colors in the cluster.</li>
|
||||
* <li>Split the cluster into two halves, using that median as a threshold.</li>
|
||||
* <li>Repeat this process until the desired number of clusters is reached.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class MedianCutQuantizer implements ColorQuantizer {
|
||||
public static final MedianCutQuantizer INSTANCE = new MedianCutQuantizer();
|
||||
|
||||
private MedianCutQuantizer() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<QColor> quantize(Multiset<QColor> originalColors, int maxColorCount) {
|
||||
TreeSet<Cluster> clusters = new TreeSet<>(new ClusterSpreadComparator());
|
||||
clusters.add(new Cluster(originalColors));
|
||||
|
||||
while (clusters.size() < maxColorCount) {
|
||||
Cluster clusterWithLargestSpread = clusters.pollFirst();
|
||||
clusters.addAll(clusterWithLargestSpread.split());
|
||||
}
|
||||
|
||||
Set<QColor> clusterCentroids = new HashSet<>();
|
||||
for (Cluster cluster : clusters) {
|
||||
clusterCentroids.add(QColor.getCentroid(cluster.colors));
|
||||
}
|
||||
return clusterCentroids;
|
||||
}
|
||||
|
||||
private static final class Cluster {
|
||||
final Multiset<QColor> colors;
|
||||
double largestSpread;
|
||||
int componentWithLargestSpread;
|
||||
|
||||
Cluster(Multiset<QColor> colors) {
|
||||
this.colors = colors;
|
||||
this.largestSpread = -1;
|
||||
for (int component = 0; component < 3; ++component) {
|
||||
double componentSpread = getComponentSpread(component);
|
||||
if (componentSpread > largestSpread) {
|
||||
largestSpread = componentSpread;
|
||||
componentWithLargestSpread = component;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double getComponentSpread(int component) {
|
||||
double min = Double.POSITIVE_INFINITY;
|
||||
double max = Double.NEGATIVE_INFINITY;
|
||||
for (QColor color : colors) {
|
||||
min = Math.min(min, color.getComponent(component));
|
||||
max = Math.max(max, color.getComponent(component));
|
||||
}
|
||||
return max - min;
|
||||
}
|
||||
|
||||
Collection<Cluster> split() {
|
||||
List<QColor> orderedColors = new ArrayList<>(colors);
|
||||
Collections.sort(orderedColors, new ColorComponentComparator(componentWithLargestSpread));
|
||||
int medianIndex = orderedColors.size() / 2;
|
||||
return Arrays.asList(new Cluster(new HashMultiset<>(orderedColors.subList(0, medianIndex))),
|
||||
new Cluster(new HashMultiset<>(orderedColors.subList(medianIndex, orderedColors.size()))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders clusters according to their maximum spread, in descending order.
|
||||
*/
|
||||
static final class ClusterSpreadComparator implements Comparator<Cluster> {
|
||||
@Override
|
||||
public int compare(Cluster a, Cluster b) {
|
||||
double spreadDifference = b.largestSpread - a.largestSpread;
|
||||
if (spreadDifference == 0) {
|
||||
return ArbitraryComparator.INSTANCE.compare(a, b);
|
||||
}
|
||||
return (int) Math.signum(spreadDifference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders colors according to the value of one particular component, in
|
||||
* ascending order.
|
||||
*/
|
||||
static final class ColorComponentComparator implements Comparator<QColor> {
|
||||
final int component;
|
||||
|
||||
ColorComponentComparator(int component) {
|
||||
this.component = component;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(QColor a, QColor b) {
|
||||
double componentDifference = a.getComponent(component) - b.getComponent(component);
|
||||
if (componentDifference == 0) {
|
||||
return ArbitraryComparator.INSTANCE.compare(a, b);
|
||||
}
|
||||
return (int) Math.signum(componentDifference);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A collection which permits duplicates, and provides methods adding/removing
|
||||
* several counts of an element.
|
||||
*
|
||||
* @param <E> the element type
|
||||
*/
|
||||
public interface Multiset<E> extends Collection<E> {
|
||||
/**
|
||||
* Add n counts of an element.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @param n how many to add
|
||||
*/
|
||||
public void add(E element, int n);
|
||||
|
||||
/**
|
||||
* Remove up to n counts of an element.
|
||||
*
|
||||
* @param element the element the remove
|
||||
* @param n how many to remove
|
||||
* @return the number of elements removed
|
||||
*/
|
||||
public int remove(Object element, int n);
|
||||
|
||||
public int count(Object element);
|
||||
|
||||
public Set<E> getDistinctElements();
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.color.ColorMapper;
|
||||
|
||||
/**
|
||||
* An RGB representation of a color, which stores each component as a double in
|
||||
* the range [0, 1]. Values outside of [0, 1] are permitted though, as this is
|
||||
* convenient e.g. for representing color deltas.
|
||||
*/
|
||||
public final class QColor {
|
||||
public static final QColor BLACK = new QColor(0, 0, 0);
|
||||
public static final QColor WHITE = new QColor(1, 1, 1);
|
||||
public static final QColor RED = new QColor(1, 0, 0);
|
||||
public static final QColor GREEN = new QColor(0, 1, 0);
|
||||
public static final QColor BLUE = new QColor(0, 0, 1);
|
||||
|
||||
private final double red;
|
||||
private final double green;
|
||||
private final double blue;
|
||||
|
||||
public QColor(double red, double green, double blue) {
|
||||
this.red = red;
|
||||
this.green = green;
|
||||
this.blue = blue;
|
||||
}
|
||||
|
||||
public static QColor fromArgbInt(ColorMapper mapper, int rgb) {
|
||||
final double alpha = (rgb >>> 24 & 0xFF) / 255.0;
|
||||
double red = (rgb >>> 16 & 0xFF) / 255.0;
|
||||
double green = (rgb >>> 8 & 0xFF) / 255.0;
|
||||
double blue = (rgb & 0xFF) / 255.0;
|
||||
|
||||
if (mapper == ColorMapper.DARK_MODE) {
|
||||
red = alpha * red;
|
||||
green = alpha * green;
|
||||
blue = alpha * blue;
|
||||
} else {
|
||||
red = 1 - alpha * (1 - red);
|
||||
green = 1 - alpha * (1 - green);
|
||||
blue = 1 - alpha * (1 - blue);
|
||||
}
|
||||
return new QColor(red, green, blue);
|
||||
}
|
||||
|
||||
public static QColor fromRgbInt(int rgb) {
|
||||
final double red = (rgb >>> 16 & 0xFF) / 255.0;
|
||||
final double green = (rgb >>> 8 & 0xFF) / 255.0;
|
||||
final double blue = (rgb & 0xFF) / 255.0;
|
||||
return new QColor(red, green, blue);
|
||||
}
|
||||
|
||||
public static QColor getCentroid(Multiset<QColor> colors) {
|
||||
QColor sum = QColor.BLACK;
|
||||
for (QColor color : colors.getDistinctElements()) {
|
||||
int weight = colors.count(color);
|
||||
sum = sum.plus(color.scaled(weight));
|
||||
}
|
||||
return sum.scaled(1.0 / colors.size());
|
||||
}
|
||||
|
||||
public double getComponent(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return red;
|
||||
case 1:
|
||||
return green;
|
||||
case 2:
|
||||
return blue;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected component index: " + index);
|
||||
}
|
||||
}
|
||||
|
||||
public QColor scaled(double s) {
|
||||
return new QColor(s * red, s * green, s * blue);
|
||||
}
|
||||
|
||||
public QColor plus(QColor that) {
|
||||
return new QColor(this.red + that.red, this.green + that.green, this.blue + that.blue);
|
||||
}
|
||||
|
||||
public QColor minus(QColor that) {
|
||||
return new QColor(this.red - that.red, this.green - that.green, this.blue - that.blue);
|
||||
}
|
||||
|
||||
public double getEuclideanDistanceTo(QColor that) {
|
||||
final QColor d = this.minus(that);
|
||||
final double sumOfSquares = d.red * d.red + d.green * d.green + d.blue * d.blue;
|
||||
return Math.sqrt(sumOfSquares);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find this color's nearest neighbor, based on Euclidean distance, among some
|
||||
* set of colors.
|
||||
*/
|
||||
public QColor getNearestColor(Collection<QColor> colors) {
|
||||
QColor nearestCentroid = null;
|
||||
double nearestCentroidDistance = Double.POSITIVE_INFINITY;
|
||||
for (QColor color : colors) {
|
||||
final double distance = getEuclideanDistanceTo(color);
|
||||
if (distance < nearestCentroidDistance) {
|
||||
nearestCentroid = color;
|
||||
nearestCentroidDistance = distance;
|
||||
}
|
||||
}
|
||||
return nearestCentroid;
|
||||
}
|
||||
|
||||
public int getRgbInt() {
|
||||
final int redComponent = (int) (red * 255);
|
||||
final int greenComponent = (int) (green * 255);
|
||||
final int blueComponent = (int) (blue * 255);
|
||||
return redComponent << 16 | greenComponent << 8 | blueComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof QColor))
|
||||
return false;
|
||||
final QColor that = (QColor) o;
|
||||
return this.red == that.red && this.green == that.green && this.blue == that.blue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(red);
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(green);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(blue);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Color[%f, %f, %f]", red, green, blue);
|
||||
}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.color.ColorMapper;
|
||||
|
||||
/**
|
||||
* An immutable grid of pixel colors.
|
||||
*/
|
||||
public final class QImage {
|
||||
/**
|
||||
* The first index corresponds to the row, while the second index corresponds
|
||||
* the column.
|
||||
*/
|
||||
private final QColor[][] colors;
|
||||
|
||||
private QImage(QColor[][] colors) {
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public static QImage fromBufferedImage(ColorMapper mapper, BufferedImage img) {
|
||||
final int height = img.getHeight();
|
||||
final int width = img.getWidth();
|
||||
final QColor[][] colors = new QColor[height][width];
|
||||
|
||||
if (img.getType() == BufferedImage.TYPE_INT_ARGB) {
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
colors[y][x] = QColor.fromArgbInt(mapper, img.getRGB(x, y));
|
||||
} else if (img.getType() == BufferedImage.TYPE_INT_RGB) {
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
colors[y][x] = QColor.fromRgbInt(img.getRGB(x, y));
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return new QImage(colors);
|
||||
}
|
||||
|
||||
public static QImage fromColors(QColor[][] colors) {
|
||||
return new QImage(colors);
|
||||
}
|
||||
|
||||
public QColor getColor(int x, int y) {
|
||||
return colors[y][x];
|
||||
}
|
||||
|
||||
public QColor getColor(int index) {
|
||||
return colors[index / getWidth()][index % getWidth()];
|
||||
}
|
||||
|
||||
Multiset<QColor> getColors() {
|
||||
final Multiset<QColor> colorCounts = new HashMultiset<>();
|
||||
for (int i = 0; i < getNumPixels(); ++i) {
|
||||
final QColor color = getColor(i);
|
||||
colorCounts.add(color);
|
||||
}
|
||||
return colorCounts;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return colors[0].length;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return colors.length;
|
||||
}
|
||||
|
||||
public int getNumPixels() {
|
||||
return getWidth() * getHeight();
|
||||
}
|
||||
|
||||
public BufferedImage toBufferedImage() {
|
||||
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||
for (int i = 0; i < result.getWidth(); i++)
|
||||
for (int j = 0; j < result.getHeight(); j++)
|
||||
result.setRGB(i, j, colors[j][i].getRgbInt());
|
||||
return result;
|
||||
}
|
||||
|
||||
public BufferedImage toBufferedImageKeepTransparency(BufferedImage orig) {
|
||||
final BufferedImage result = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
|
||||
for (int i = 0; i < result.getWidth(); i++)
|
||||
for (int j = 0; j < result.getHeight(); j++) {
|
||||
if ((orig.getRGB(i, j)) != 0x00000000)
|
||||
result.setRGB(i, j, colors[j][i].getRgbInt() | 0xFF000000);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
package net.sourceforge.plantuml.quantization;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.plantuml.klimt.color.ColorMapper;
|
||||
|
||||
public final class Quantizer {
|
||||
// ::remove folder when __CORE__
|
||||
private static final int MAX_COLOR_COUNT = 256;
|
||||
|
||||
private static QImage quantizeNow(QImage image) throws IOException {
|
||||
|
||||
Multiset<QColor> originalColors = image.getColors();
|
||||
Set<QColor> distinctColors = originalColors.getDistinctElements();
|
||||
if (distinctColors.size() > MAX_COLOR_COUNT) {
|
||||
// distinctColors = KMeansQuantizer.INSTANCE.quantize(originalColors,
|
||||
// MAX_COLOR_COUNT);
|
||||
distinctColors = MedianCutQuantizer.INSTANCE.quantize(originalColors, MAX_COLOR_COUNT);
|
||||
image = FloydSteinbergDitherer.INSTANCE.dither(image, distinctColors);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
public static BufferedImage quantizeNow(ColorMapper mapper, BufferedImage orig) throws IOException {
|
||||
final QImage raw = QImage.fromBufferedImage(mapper, orig);
|
||||
final QImage result = quantizeNow(raw);
|
||||
|
||||
if (orig.getType() == BufferedImage.TYPE_INT_RGB)
|
||||
return result.toBufferedImage();
|
||||
else if (orig.getType() == BufferedImage.TYPE_INT_ARGB)
|
||||
return result.toBufferedImageKeepTransparency(orig);
|
||||
else
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
}
|
||||
}
|
@ -68,6 +68,8 @@ import net.sourceforge.plantuml.svek.HeaderLayout;
|
||||
import net.sourceforge.plantuml.svek.ShapeType;
|
||||
import net.sourceforge.plantuml.text.Guillemet;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EntityImageClassHeader extends AbstractEntityImage {
|
||||
|
||||
final private HeaderLayout headerLayout;
|
||||
@ -112,11 +114,12 @@ public class EntityImageClassHeader extends AbstractEntityImage {
|
||||
}
|
||||
|
||||
final TextBlock stereo;
|
||||
List<String> stereotypeLabels = portionShower.getVisibleStereotypeLabels(entity);
|
||||
if (stereotype == null || stereotype.getLabel(Guillemet.DOUBLE_COMPARATOR) == null
|
||||
|| portionShower.showPortion(EntityPortion.STEREOTYPE, entity) == false)
|
||||
|| stereotypeLabels.isEmpty())
|
||||
stereo = null;
|
||||
else
|
||||
stereo = TextBlockUtils.withMargin(Display.create(stereotype.getLabels(skinParam.guillemet())).create(
|
||||
stereo = TextBlockUtils.withMargin(Display.create(stereotypeLabels).create(
|
||||
FontConfiguration.create(getSkinParam(), FontParam.CLASS_STEREOTYPE, stereotype),
|
||||
HorizontalAlignment.CENTER, skinParam), 1, 0);
|
||||
|
||||
|
@ -1,161 +0,0 @@
|
||||
/* ========================================================================
|
||||
* PlantUML : a free UML diagram generator
|
||||
* ========================================================================
|
||||
*
|
||||
* (C) Copyright 2009-2024, Arnaud Roques
|
||||
*
|
||||
* Project Info: https://plantuml.com
|
||||
*
|
||||
* If you like this project or if you find it useful, you can support us at:
|
||||
*
|
||||
* https://plantuml.com/patreon (only 1$ per month!)
|
||||
* https://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.syntax;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.plantuml.BlockUml;
|
||||
import net.sourceforge.plantuml.ErrorUml;
|
||||
import net.sourceforge.plantuml.OptionFlags;
|
||||
import net.sourceforge.plantuml.SourceStringReader;
|
||||
import net.sourceforge.plantuml.UmlDiagram;
|
||||
import net.sourceforge.plantuml.annotation.DeadCode;
|
||||
import net.sourceforge.plantuml.core.Diagram;
|
||||
import net.sourceforge.plantuml.error.PSystemError;
|
||||
import net.sourceforge.plantuml.preproc.Defines;
|
||||
import net.sourceforge.plantuml.text.BackSlash;
|
||||
import net.sourceforge.plantuml.utils.LineLocation;
|
||||
import net.sourceforge.plantuml.utils.LineLocationImpl;
|
||||
|
||||
@DeadCode(comment = "used too much CPU")
|
||||
public class SyntaxChecker {
|
||||
// ::remove folder when __HAXE__
|
||||
// ::remove file when __CORE__
|
||||
|
||||
public static SyntaxResult checkSyntax(List<String> source) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (String s : source) {
|
||||
sb.append(s);
|
||||
sb.append(BackSlash.NEWLINE);
|
||||
}
|
||||
return checkSyntax(sb.toString());
|
||||
}
|
||||
|
||||
public static SyntaxResult checkSyntax(String source) {
|
||||
OptionFlags.getInstance().setQuiet(true);
|
||||
final SyntaxResult result = new SyntaxResult();
|
||||
|
||||
if (source.startsWith("@startuml\n") == false) {
|
||||
result.setError(true);
|
||||
result.setLineLocation(new LineLocationImpl("", null).oneLineRead());
|
||||
result.addErrorText("No @startuml/@enduml found");
|
||||
return result;
|
||||
}
|
||||
if (source.endsWith("@enduml\n") == false && source.endsWith("@enduml") == false) {
|
||||
result.setError(true);
|
||||
result.setLineLocation(lastLineNumber2(source));
|
||||
result.addErrorText("No @enduml found");
|
||||
return result;
|
||||
}
|
||||
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
|
||||
Collections.<String>emptyList());
|
||||
|
||||
final List<BlockUml> blocks = sourceStringReader.getBlocks();
|
||||
if (blocks.size() == 0) {
|
||||
result.setError(true);
|
||||
result.setLineLocation(lastLineNumber2(source));
|
||||
result.addErrorText("No @enduml found");
|
||||
return result;
|
||||
}
|
||||
final Diagram system = blocks.get(0).getDiagram();
|
||||
result.setCmapData(system.hasUrl());
|
||||
if (system instanceof UmlDiagram) {
|
||||
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
|
||||
result.setDescription(system.getDescription().getDescription());
|
||||
} else if (system instanceof PSystemError) {
|
||||
result.setError(true);
|
||||
final PSystemError sys = (PSystemError) system;
|
||||
result.setLineLocation(sys.getLineLocation());
|
||||
result.setSystemError(sys);
|
||||
for (ErrorUml er : sys.getErrorsUml())
|
||||
result.addErrorText(er.getError());
|
||||
} else {
|
||||
result.setDescription(system.getDescription().getDescription());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SyntaxResult checkSyntaxFair(String source) {
|
||||
final SyntaxResult result = new SyntaxResult();
|
||||
final SourceStringReader sourceStringReader = new SourceStringReader(Defines.createEmpty(), source,
|
||||
Collections.<String>emptyList());
|
||||
|
||||
final List<BlockUml> blocks = sourceStringReader.getBlocks();
|
||||
if (blocks.size() == 0) {
|
||||
result.setError(true);
|
||||
result.setLineLocation(lastLineNumber2(source));
|
||||
result.addErrorText("No @enduml found");
|
||||
return result;
|
||||
}
|
||||
|
||||
final Diagram system = blocks.get(0).getDiagram();
|
||||
result.setCmapData(system.hasUrl());
|
||||
if (system instanceof UmlDiagram) {
|
||||
result.setUmlDiagramType(((UmlDiagram) system).getUmlDiagramType());
|
||||
result.setDescription(system.getDescription().getDescription());
|
||||
} else if (system instanceof PSystemError) {
|
||||
result.setError(true);
|
||||
final PSystemError sys = (PSystemError) system;
|
||||
result.setLineLocation(sys.getLineLocation());
|
||||
for (ErrorUml er : sys.getErrorsUml()) {
|
||||
result.addErrorText(er.getError());
|
||||
}
|
||||
result.setSystemError(sys);
|
||||
} else {
|
||||
result.setDescription(system.getDescription().getDescription());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int lastLineNumber(String source) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < source.length(); i++)
|
||||
if (source.charAt(i) == '\n')
|
||||
result++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static LineLocation lastLineNumber2(String source) {
|
||||
LineLocationImpl result = new LineLocationImpl("", null).oneLineRead();
|
||||
for (int i = 0; i < source.length(); i++)
|
||||
if (source.charAt(i) == '\n')
|
||||
result = result.oneLineRead();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -55,14 +55,14 @@ public class StartUtils {
|
||||
boolean inside = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
final String tmp = s.substring(i, s.length());
|
||||
if (startsWithSymbolAnd("start", tmp)) {
|
||||
if (startsWithSymbolAnd("start", tmp))
|
||||
return s.substring(0, i);
|
||||
}
|
||||
|
||||
final String single = s.substring(i, i + 1);
|
||||
if (inside) {
|
||||
if (single.equals(">")) {
|
||||
if (single.equals(">"))
|
||||
inside = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (single.equals("<")) {
|
||||
@ -81,9 +81,9 @@ public class StartUtils {
|
||||
|
||||
public static boolean isArobaseStartDiagram(String s) {
|
||||
final String s2 = StringUtils.trinNoTrace(s);
|
||||
if (s2.startsWith("@") == false && s2.startsWith("\\") == false) {
|
||||
if (s2.startsWith("@") == false && s2.startsWith("\\") == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return DiagramType.getTypeFromArobaseStart(s2) != DiagramType.UNKNOWN;
|
||||
}
|
||||
|
||||
@ -97,9 +97,9 @@ public class StartUtils {
|
||||
|
||||
public static boolean startOrEnd(final StringLocated s) {
|
||||
final String s2 = StringUtils.trinNoTrace(s.getString());
|
||||
if (s2.startsWith("@") == false && s2.startsWith("\\") == false) {
|
||||
if (s2.startsWith("@") == false && s2.startsWith("\\") == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return startsWithSymbolAnd("end", s2) || DiagramType.getTypeFromArobaseStart(s2) != DiagramType.UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class License {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__ or __GPLV2__
|
||||
return "GPL";
|
||||
// ::done
|
||||
// ::uncomment when __CORE__ or __MIT__
|
||||
@ -76,6 +76,9 @@ public class License {
|
||||
// ::uncomment when __LGPL__
|
||||
// return "LGPL";
|
||||
// ::done
|
||||
// ::uncomment when __GPLV2__
|
||||
// return "GPLv2";
|
||||
// ::done
|
||||
}
|
||||
|
||||
public static License getCurrent() {
|
||||
@ -155,7 +158,7 @@ public class License {
|
||||
}
|
||||
|
||||
private void end3(final LicenseInfo licenseInfo, final List<String> text) {
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__
|
||||
// ::comment when __CORE__ or __MIT__ or __EPL__ or __BSD__ or __ASL__ or __LGPL__ or __GPLV2__
|
||||
text.add("PlantUML is free software; you can redistribute it and/or modify it");
|
||||
text.add("under the terms of the GNU General Public License as published by");
|
||||
text.add("the Free Software Foundation, either version 3 of the License, or");
|
||||
@ -188,6 +191,9 @@ public class License {
|
||||
// ::uncomment when __LGPL__
|
||||
// addLgpl(licenseInfo, text);
|
||||
// ::done
|
||||
// ::uncomment when __GPLV2__
|
||||
// addGplv2(licenseInfo, text);
|
||||
// ::done
|
||||
|
||||
text.add(" ");
|
||||
if (licenseInfo.isValid() == false) {
|
||||
@ -370,22 +376,39 @@ public class License {
|
||||
// }
|
||||
// ::done
|
||||
|
||||
// ::uncomment when __LGPL__
|
||||
// private void addLgpl(final LicenseInfo licenseInfo, final List<String> text) {
|
||||
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
|
||||
// text.add("under the terms of the GNU Lesser General Public License as published by");
|
||||
// text.add("the Free Software Foundation, either version 3 of the License, or");
|
||||
// text.add("(at your option) any later version.");
|
||||
// text.add(" ");
|
||||
// text.add("PlantUML distributed in the hope that it will be useful, but");
|
||||
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
|
||||
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
|
||||
// text.add("License for more details.");
|
||||
// text.add(" ");
|
||||
// text.add("You should have received a copy of the GNU Lesser General Public License");
|
||||
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/>.");
|
||||
// }
|
||||
// ::done
|
||||
// ::uncomment when __LGPL__
|
||||
// private void addLgpl(final LicenseInfo licenseInfo, final List<String> text) {
|
||||
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
|
||||
// text.add("under the terms of the GNU Lesser General Public License as published by");
|
||||
// text.add("the Free Software Foundation, either version 3 of the License, or");
|
||||
// text.add("(at your option) any later version.");
|
||||
// text.add(" ");
|
||||
// text.add("PlantUML distributed in the hope that it will be useful, but");
|
||||
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
|
||||
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
|
||||
// text.add("License for more details.");
|
||||
// text.add(" ");
|
||||
// text.add("You should have received a copy of the GNU Lesser General Public License");
|
||||
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/>.");
|
||||
// }
|
||||
// ::done
|
||||
|
||||
// ::uncomment when __GPLV2__
|
||||
// private void addGplv2(final LicenseInfo licenseInfo, final List<String> text) {
|
||||
// text.add("PlantUML is free software; you can redistribute it and/or modify it");
|
||||
// text.add("under the terms of the GNU General Public License V2 as published by");
|
||||
// text.add("the Free Software Foundation, either version 2 of the License, or");
|
||||
// text.add("(at your option) any later version.");
|
||||
// text.add(" ");
|
||||
// text.add("PlantUML distributed in the hope that it will be useful, but");
|
||||
// text.add("WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY");
|
||||
// text.add("or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public");
|
||||
// text.add("License for more details.");
|
||||
// text.add(" ");
|
||||
// text.add("You should have received a copy of the GNU Lesser General Public License");
|
||||
// text.add("along with this library. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.");
|
||||
// }
|
||||
// ::done
|
||||
|
||||
public static void addLicenseInfo(final List<String> text, LicenseInfo licenseInfo) {
|
||||
if (licenseInfo.getLicenseType() == LicenseType.NAMED) {
|
||||
|
@ -46,7 +46,7 @@ public class Version {
|
||||
|
||||
// Warning, "version" should be the same in gradle.properties and Version.java
|
||||
// Any idea anyone how to magically synchronize those :-) ?
|
||||
private static final String version = "1.2023.12beta1";
|
||||
private static final String version = "1.2023.13beta1";
|
||||
|
||||
public static String versionString() {
|
||||
return version;
|
||||
@ -80,7 +80,7 @@ public class Version {
|
||||
}
|
||||
|
||||
public static long compileTime() {
|
||||
return 1694629593289L;
|
||||
return 1697809794384L;
|
||||
}
|
||||
|
||||
public static String compileTimeString() {
|
||||
|
Loading…
Reference in New Issue
Block a user