Compare commits
541 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 140236c774 | |||
| cc3d7dfbf0 | |||
| 112c15ed75 | |||
| a08b04a079 | |||
| 811bf87d0e | |||
| 93c3ef7b2f | |||
| ad94f88217 | |||
| c2f7d03413 | |||
| f2b2c8b4e7 | |||
| f9688fbde7 | |||
| 51621458b5 | |||
| c25ed7e162 | |||
| 2a4335302f | |||
| 69ed88ac2c | |||
| 1f946e6c9a | |||
| ac76ba280d | |||
| ceab748ba1 | |||
| e1232a5e6e | |||
| 5cc0693e61 | |||
| 387b19eed9 | |||
| 18ff9bcf26 | |||
| 5da8804871 | |||
| dbeb4d2f5d | |||
| d2d0b7f018 | |||
| c28d5659a0 | |||
| 812c1e0f56 | |||
| 99f719e81c | |||
| da58eb2681 | |||
| c084eef7a3 | |||
| 24036a8046 | |||
| db8729ec74 | |||
| 015d6396ff | |||
| 6df100f5b7 | |||
| 7cb9ba470c | |||
| 1e6f84a59c | |||
| 2292eecb4e | |||
| 5fc5203ff7 | |||
| e8547f7588 | |||
| eade03c006 | |||
| cef5e6f4ab | |||
| 9331c0d939 | |||
| decc354b80 | |||
| f24c64c96c | |||
| 689f6595fb | |||
| 3a2e799300 | |||
| c643e5e340 | |||
| 8ee6153f4b | |||
| bf38d42f15 | |||
| 6fa8bba4fd | |||
| 33c85ba1f2 | |||
| 9f200d4404 | |||
| 50f6650fac | |||
| 5db5fc3886 | |||
| 28ca0cf7b1 | |||
| b470cfeaf1 | |||
| 352678f4e2 | |||
| f87ed0c454 | |||
| c42a4cb21c | |||
| f638619964 | |||
| 8dc3b71989 | |||
| 4984bd9f05 | |||
| 27c893f71f | |||
| 6c51bebf14 | |||
| 32d45ac97d | |||
| a46cc55da1 | |||
| d11bec9688 | |||
| 0069419c8b | |||
| b06c0ccd86 | |||
| c85023415a | |||
| db858e1f0a | |||
| 010a632e5d | |||
| 9d7793ecb9 | |||
| 418ebb7958 | |||
| e30f7bf920 | |||
| 1b26292d3c | |||
| 0afcf099df | |||
| 691c0709be | |||
| 05d35e1e6f | |||
| 1edab5611b | |||
| e5beb5ab2b | |||
| c67d9b0ee9 | |||
| 6ce250ddf8 | |||
| 75acf045a6 | |||
| 2a254e937f | |||
| 444de2c8af | |||
| fd60f29965 | |||
| 217c8630f6 | |||
| dc48c5debd | |||
| a8606ce05c | |||
| adbe29f1dc | |||
| 3b09334501 | |||
| e909322fb9 | |||
| a304bcc59a | |||
| 83d0fa6730 | |||
| 9d54041102 | |||
| 1021098106 | |||
| 7001caea9a | |||
| 3d597b797a | |||
| 13db192fca | |||
| dc57327e7f | |||
| 75d8371d2b | |||
| 9b2b0e0acf | |||
| c7c43fcf4b | |||
| 2949ab1a2b | |||
| fdcfd4c565 | |||
| 866da5980c | |||
| 460d153d6c | |||
| 2326186428 | |||
| b50e0485d9 | |||
| 317c6afd45 | |||
| a427c1e99e | |||
| e916f8afbb | |||
| 59b945dcc3 | |||
| d5921e08ec | |||
| 898b1007b9 | |||
| 7b377a216b | |||
| 82bbe47d68 | |||
| 22829f8a24 | |||
| 448b1ec9f3 | |||
| 9a70b165cc | |||
| e428337ffc | |||
| e07cfa09bb | |||
| 9763ed29e2 | |||
| 19230c83ef | |||
| 3678a525a2 | |||
| 2cf0c49955 | |||
| f16c3f36a9 | |||
| b80cd6a417 | |||
| c6459bb7d3 | |||
| 9da0f369b1 | |||
| 3cd34e1c38 | |||
| bae8050fac | |||
| f99abec58e | |||
| 80cd03cded | |||
| df50dca01b | |||
| c6aa3c91e6 | |||
| 473c2efc38 | |||
| f2c1f35aaf | |||
| d847d309b0 | |||
| bc37be0c54 | |||
| 779128b5f4 | |||
| 3af5cfaed6 | |||
| 9a3258c9da | |||
| 9de8b33bb4 | |||
| 0c797ae6a8 | |||
| d162d9371c | |||
| d13db0ea4c | |||
| 657f04908f | |||
| 27bfa083b2 | |||
| d69888b74d | |||
| e8f3227191 | |||
| 3a86b17194 | |||
| a84220cd21 | |||
| 8acfd5bce7 | |||
| 175ecbc50f | |||
| 8ee773362e | |||
| 073bf3215c | |||
| 1f07083d4a | |||
| cd208c5477 | |||
| 6a06f60ee3 | |||
| 7db925d991 | |||
| d7313598aa | |||
| 02bc430fac | |||
| 2b04b01edc | |||
| 6b6df27df8 | |||
| 45b9f2a7aa | |||
| 7de296b60e | |||
| 14668197d1 | |||
| 999f3b85ee | |||
| 1b2f0063a1 | |||
| 175d2cf2dd | |||
| 4ec9c381d4 | |||
| 0cd8fb12f3 | |||
| 93525ff7eb | |||
| e9890c0798 | |||
| 360b4282f7 | |||
| 1aa897d450 | |||
| 8573d9f8b2 | |||
| 5234d9bc67 | |||
| f87d9bd626 | |||
| 9894964eb6 | |||
| e53e231677 | |||
| c955372ecf | |||
| 393352387d | |||
| 830b3944db | |||
| 15e3e86c5a | |||
| b12e7a8ad6 | |||
| ad8bb4dc69 | |||
| 620c273c4e | |||
| b308da5387 | |||
| 00e7eae6f8 | |||
| ad0f1147f7 | |||
| ea79771afd | |||
| a91e32a6f4 | |||
| 37511553f7 | |||
| d298a7101c | |||
| 51f3727d3c | |||
| f78412c75b | |||
| ccfa6cd9e5 | |||
| 89803987a1 | |||
| 22763c9e4f | |||
| 69932742d2 | |||
| 4de0e8244e | |||
| a527daa4b3 | |||
| 54a4e02514 | |||
| 012fe8d9b6 | |||
| 7de8a14b37 | |||
| 256c4cd086 | |||
| 9e2ee47b01 | |||
| 82da0065c4 | |||
| b7cc7261b8 | |||
| cd32457b60 | |||
| 818a890512 | |||
| 86fc7298a1 | |||
| 40395a0a57 | |||
| 166306469a | |||
| e678620cbd | |||
| a83fc8acd1 | |||
| 4b0c125d61 | |||
| 5f4ea420b0 | |||
| b70d8d3781 | |||
| 4c2946c8a4 | |||
| 6843a461e6 | |||
| bbecc3f296 | |||
| 8c6ffc99e3 | |||
| 1ee1aee10e | |||
| 125d5b6360 | |||
| a0eb2e9de7 | |||
| 4b44c54cfa | |||
| 4d4adb932b | |||
| 74c75b86a0 | |||
| 6cfd7d21e8 | |||
| 8d56879305 | |||
| 4089cbfbf2 | |||
| ac421ffd0e | |||
| 87db9dccb5 | |||
| 94f6279a67 | |||
| da4b05fdcc | |||
| b6cd635cc1 | |||
| f3e941a382 | |||
| 6b2882e01f | |||
| 8998c9847d | |||
| e7a9081097 | |||
| b416c42d58 | |||
| 0d34449613 | |||
| 0a4488462c | |||
| 9db32a3911 | |||
| e1eeabc86c | |||
| 8dad6cf84d | |||
| 35919e2a75 | |||
| 796d722072 | |||
| b310a3e503 | |||
| 0678946103 | |||
| 4ccd24fe14 | |||
| 7b02f492fa | |||
| e9bb9afc3b | |||
| 68a499574a | |||
| f4891488d3 | |||
| dbea942dda | |||
| 967c7fff65 | |||
| 7c98361447 | |||
| a922605821 | |||
| 1a346722f8 | |||
| 4a052dc34a | |||
| f94aecad70 | |||
| 1adff3f917 | |||
| b7097e4bd5 | |||
| 28698a41e3 | |||
| db9aeefea1 | |||
| 9fcb98d9c6 | |||
| 60e419068b | |||
| f64916dc5e | |||
| 0a6d271121 | |||
| a4a8acd445 | |||
| bbcc8b2c5c | |||
| 063fd56f5f | |||
| 6b09da9ab6 | |||
| c23a30b916 | |||
| 8e253cb4c8 | |||
| 8edc9b142d | |||
| 39abd5433e | |||
| 642b261fb0 | |||
| 64fe6c269a | |||
| 60cc7cfcf1 | |||
| 97a52a991a | |||
| fb1a7af360 | |||
| 4b47d38eb6 | |||
| 81be38ea8d | |||
| 08d1e382e1 | |||
| 5b6ba058a7 | |||
| 7814faa6fd | |||
| 6c89e6dc73 | |||
| 453abff2fe | |||
| a1a4b89ba8 | |||
| 7e79686986 | |||
| e89ebba736 | |||
| 79df90a45c | |||
| d8ca3093d0 | |||
| b85e9b1fe4 | |||
| ea7efbf96b | |||
| 68e337670e | |||
| 3158be46ad | |||
| 02b66ca461 | |||
| 74c2ad4bf0 | |||
| 522c91ce79 | |||
| e8d65c22d6 | |||
| 166eee5eed | |||
| 3af54a7dda | |||
| 7fa294fd7a | |||
| 7400b11870 | |||
| 915371aa70 | |||
| 7b225789da | |||
| c0cccf7f7e | |||
| 5219718eb0 | |||
| 4b1004b33a | |||
| 9aa14b36a3 | |||
| 876ef07480 | |||
| 9e68e5f290 | |||
| 27a36156f6 | |||
| 09f1b14cc9 | |||
| e0487b62a6 | |||
| 741fdc53c7 | |||
| 832f181ec0 | |||
| 2a8f85d95c | |||
| 227e568b4f | |||
| f0e735ed33 | |||
| ebd1afc5d9 | |||
| 9065058265 | |||
| 0a79760745 | |||
| ac3390de12 | |||
| c2cfccf268 | |||
| 505de3215b | |||
| 4f91499ada | |||
| 4813e30703 | |||
| 8bbf9b8347 | |||
| 3528c626e7 | |||
| a06cc956c5 | |||
| e2856395a3 | |||
| a3a97d7b5e | |||
| 0c43dab796 | |||
| 298fb8983d | |||
| 75546946db | |||
| 4d19e611f8 | |||
| 47a5a6302e | |||
| 7b0b83a2e4 | |||
| d81b016b2a | |||
| 5a432fe9ac | |||
| e6a6d838a6 | |||
| f3a8edcb5e | |||
| baa1105a53 | |||
| 6c1c63cffe | |||
| 9ef72fcd06 | |||
| 7521cfc7a0 | |||
| 6d23205704 | |||
| 30706f4d0f | |||
| 6a877f7e29 | |||
| 007a5b351a | |||
| 9010b88b22 | |||
| a106f55ebe | |||
| b8434f2ddc | |||
| 6e587d130d | |||
| 38ec63cba1 | |||
| fbb5555f27 | |||
| 9b5aabe458 | |||
| 9dc93b8f99 | |||
| c8337118ba | |||
| d13ecc1efa | |||
| 1b65b3f600 | |||
| f89f032231 | |||
| 083a27dc68 | |||
| d4c180e953 | |||
| fdaca02994 | |||
| 4c3c23776d | |||
| 19ffd1ca94 | |||
| fa9c78611e | |||
| 825d95314e | |||
| 10c6d6eabf | |||
| b54b3e6e32 | |||
| 6bb6bb4d24 | |||
| 8fb5ce3c43 | |||
| 43a14ab4df | |||
| dd00c46a8c | |||
| 10edc03ec1 | |||
| 53e02bc851 | |||
| d17954276c | |||
| c4fec57368 | |||
| d8bf4dfeb9 | |||
| 7225e5f0ba | |||
| 68e8c19aaf | |||
| 8d5a957eb0 | |||
| e5fb5a6f27 | |||
| ecb1b3c3cc | |||
| 9a4ab21f2b | |||
| 9d7b7af48c | |||
| 28c269cc5f | |||
| 0f9ea612b6 | |||
| 4148a33d15 | |||
| d7d22b1e7e | |||
| 5864e17d9d | |||
| 920e8e0469 | |||
| c9cffae11d | |||
| c143d91978 | |||
| f401cbe832 | |||
| 2e4dcfc22a | |||
| b06f247f9f | |||
| e05e9a7247 | |||
| 5792c502bf | |||
| ef1a835f4f | |||
| 18eb44d120 | |||
| d0323e13c1 | |||
| f31544dca8 | |||
| f256e3caf4 | |||
| 0c6c3e5211 | |||
| 9570d88a39 | |||
| 6449e1bcf7 | |||
| 47bb1408da | |||
| 77627bbc23 | |||
| b9b21ddac5 | |||
| 242083bbf7 | |||
| eff8ecaafc | |||
| 80bdc3f960 | |||
| b4489422a5 | |||
| 8349a78dde | |||
| fd47f2253a | |||
| 3cccd4d69e | |||
| 721f253c59 | |||
| 29cc754cfd | |||
| af811b34b3 | |||
| 07422d2abe | |||
| 6462cdf231 | |||
| 9156d591c9 | |||
| 4223e5d84d | |||
| 7955c0dfac | |||
| 681d961254 | |||
| 332cb9ec2f | |||
| 34300c600f | |||
| f7c64c7322 | |||
| 7e638a624e | |||
| b5b5375fe4 | |||
| 23d65cc9f2 | |||
| 75a8998432 | |||
| 6e97e9570c | |||
| 27e3f3c153 | |||
| a42e1b0223 | |||
| 176cf0d144 | |||
| 4d7e550d97 | |||
| 3fe354718c | |||
| 8567ef1849 | |||
| 67c506d39e | |||
| 9c8b21f5f4 | |||
| f37574e809 | |||
| 0d6b5b7f30 | |||
| f7f85464a3 | |||
| 31047be9fb | |||
| ca9355b5cb | |||
| fc7f3f4e3d | |||
| 704feadc7c | |||
| e41879c6ea | |||
| 2b0dd54fe7 | |||
| d73f9e3762 | |||
| 134fa8b7ea | |||
| e8f1bde367 | |||
| 2d32de3cd2 | |||
| 56d289997c | |||
| 4dab407fbe | |||
| 34502193a2 | |||
| d540de8bee | |||
| acfbc72f50 | |||
| 3c1e446c2f | |||
| 2d5400f923 | |||
| be16e1f52b | |||
| be8a4037db | |||
| 977127012e | |||
| 89432a969d | |||
| 7b204c01db | |||
| ee4f4e8cb7 | |||
| 297e3520ec | |||
| 8891394d5a | |||
| d223d4362c | |||
| 213bf1ec61 | |||
| d860c4bb2d | |||
| a0c0b2616c | |||
| 07e38636b9 | |||
| a4b2bf584d | |||
| 477eed10a4 | |||
| 9946a3916e | |||
| a67701b85b | |||
| 2de25dd04e | |||
| 3f04bf7b4d | |||
| 8c123bad50 | |||
| eda43a2ef9 | |||
| 81d6401455 | |||
| 5542bc9970 | |||
| 3dfb51d3ee | |||
| 79a5cde3b5 | |||
| 33556d8a56 | |||
| b8952aaeb8 | |||
| 819cfd7a11 | |||
| d447d75882 | |||
| d920a5bf4d | |||
| 35c872d4f2 | |||
| 98cb5d50af | |||
| 62f65e12e2 | |||
| f7b9a70ee5 | |||
| 03f3852617 | |||
| 537acfdddd | |||
| 307cb3cda8 | |||
| 0b574523e9 | |||
| 8edb3e64cc | |||
| e13e3bcea3 | |||
| c2e34be393 | |||
| c5296fbb92 | |||
| 1723196166 | |||
| 37d2492719 | |||
| 47125d8fda | |||
| d3d96816ce | |||
| 7907b0f8b3 | |||
| c4cd127499 | |||
| 919271ed5e | |||
| 79c218ad9a | |||
| 7b79c9697c | |||
| 30f8015e71 | |||
| f94ab3ec84 | |||
| b47f8d2605 | |||
| 8e1a23eadf | |||
| 391c9a6bbf | |||
| bf6dbd4606 | |||
| 8676d67a87 | |||
| a80d9e5ef8 | |||
| b07be87677 | |||
| bd853e5ef2 | |||
| 4c2972cb23 | |||
| 975b8eac52 | |||
| 836c6b889a | |||
| 4474db7f50 | |||
| ccdbf99341 | |||
| 18120f8bcd | |||
| a21a5a2032 | |||
| 5ae3a0866e | |||
| 07d7ced8ec | |||
| 7630ee024b |
@@ -0,0 +1,66 @@
|
||||
# Generated from CLion C/C++ Code Style settings
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignOperands: DontAlign
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
ColumnLimit: 100
|
||||
CompactNamespaces: false
|
||||
ContinuationIndentWidth: 4
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PointerAlignment: Left
|
||||
ReflowComments: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 0
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
+490
@@ -0,0 +1,490 @@
|
||||
---
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,boost-*,bugprone-*,
|
||||
performance-*,readability-*,portability-*,modernize-*,cppcoreguidelines-*,
|
||||
concurrency-*,-modernize-use-trailing-return-type, -modernize-use-nodiscard'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: file
|
||||
User: florians
|
||||
CheckOptions:
|
||||
- key: readability-suspicious-call-argument.PrefixSimilarAbove
|
||||
value: '30'
|
||||
- key: cppcoreguidelines-no-malloc.Reallocations
|
||||
value: '::realloc'
|
||||
- key: cppcoreguidelines-owning-memory.LegacyResourceConsumers
|
||||
value: '::free;::realloc;::freopen;::fclose'
|
||||
- key: bugprone-reserved-identifier.Invert
|
||||
value: 'false'
|
||||
- key: bugprone-narrowing-conversions.PedanticMode
|
||||
value: 'false'
|
||||
- key: bugprone-unused-return-value.CheckedFunctions
|
||||
value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty;::std::back_inserter;::std::distance;::std::find;::std::find_if;::std::inserter;::std::lower_bound;::std::make_pair;::std::map::count;::std::map::find;::std::map::lower_bound;::std::multimap::equal_range;::std::multimap::upper_bound;::std::set::count;::std::set::find;::std::setfill;::std::setprecision;::std::setw;::std::upper_bound;::std::vector::at;::bsearch;::ferror;::feof;::isalnum;::isalpha;::isblank;::iscntrl;::isdigit;::isgraph;::islower;::isprint;::ispunct;::isspace;::isupper;::iswalnum;::iswprint;::iswspace;::isxdigit;::memchr;::memcmp;::strcmp;::strcoll;::strncmp;::strpbrk;::strrchr;::strspn;::strstr;::wcscmp;::access;::bind;::connect;::difftime;::dlsym;::fnmatch;::getaddrinfo;::getopt;::htonl;::htons;::iconv_open;::inet_addr;::isascii;::isatty;::mmap;::newlocale;::openat;::pathconf;::pthread_equal;::pthread_getspecific;::pthread_mutex_trylock;::readdir;::readlink;::recvmsg;::regexec;::scandir;::semget;::setjmp;::shm_open;::shmget;::sigismember;::strcasecmp;::strsignal;::ttyname'
|
||||
- key: modernize-use-auto.MinTypeNameLength
|
||||
value: '5'
|
||||
- key: cppcoreguidelines-macro-usage.CheckCapsOnly
|
||||
value: 'false'
|
||||
- key: readability-inconsistent-declaration-parameter-name.Strict
|
||||
value: 'false'
|
||||
- key: readability-suspicious-call-argument.DiceDissimilarBelow
|
||||
value: '60'
|
||||
- key: bugprone-assert-side-effect.IgnoredFunctions
|
||||
value: __builtin_expect
|
||||
- key: readability-suspicious-call-argument.Equality
|
||||
value: 'true'
|
||||
- key: bugprone-easily-swappable-parameters.QualifiersMix
|
||||
value: 'false'
|
||||
- key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
|
||||
value: 'true'
|
||||
- key: bugprone-argument-comment.CommentNullPtrs
|
||||
value: '0'
|
||||
- key: cppcoreguidelines-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-init-variables.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nodiscard.ReplacementString
|
||||
value: '[[nodiscard]]'
|
||||
- key: modernize-loop-convert.MakeReverseRangeHeader
|
||||
value: ''
|
||||
- key: readability-suspicious-call-argument.SuffixSimilarAbove
|
||||
value: '30'
|
||||
- key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerNarrowingConversion
|
||||
value: 'true'
|
||||
- key: bugprone-easily-swappable-parameters.IgnoredParameterNames
|
||||
value: '"";iterator;Iterator;begin;Begin;end;End;first;First;last;Last;lhs;LHS;rhs;RHS'
|
||||
- key: modernize-loop-convert.UseCxx20ReverseRanges
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-prefer-member-initializer.UseAssignment
|
||||
value: 'false'
|
||||
- key: performance-type-promotion-in-math-fn.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-function-cognitive-complexity.DescribeBasicIncrements
|
||||
value: 'true'
|
||||
- key: bugprone-suspicious-include.ImplementationFileExtensions
|
||||
value: 'c;cc;cpp;cxx'
|
||||
- key: modernize-loop-convert.MakeReverseRangeFunction
|
||||
value: ''
|
||||
- key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: bugprone-suspicious-missing-comma.SizeThreshold
|
||||
value: '5'
|
||||
- key: readability-identifier-naming.IgnoreFailedSplit
|
||||
value: 'false'
|
||||
- key: readability-qualified-auto.AddConstToQualified
|
||||
value: 'true'
|
||||
- key: bugprone-sizeof-expression.WarnOnSizeOfThis
|
||||
value: 'true'
|
||||
- key: bugprone-string-constructor.WarnOnLargeLength
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-explicit-virtual-functions.OverrideSpelling
|
||||
value: override
|
||||
- key: readability-uppercase-literal-suffix.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: modernize-make-shared.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: bugprone-dynamic-static-initializers.HeaderFileExtensions
|
||||
value: ';h;hh;hpp;hxx'
|
||||
- key: bugprone-suspicious-enum-usage.StrictMode
|
||||
value: 'false'
|
||||
- key: performance-unnecessary-copy-initialization.AllowedTypes
|
||||
value: ''
|
||||
- key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
|
||||
value: '5'
|
||||
- key: modernize-use-transparent-functors.SafeMode
|
||||
value: 'false'
|
||||
- key: readability-suspicious-call-argument.Levenshtein
|
||||
value: 'true'
|
||||
- key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
|
||||
value: 'true'
|
||||
- key: bugprone-string-constructor.LargeLengthThreshold
|
||||
value: '8388608'
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
|
||||
value: 'false'
|
||||
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
|
||||
value: 'false'
|
||||
- key: bugprone-exception-escape.FunctionsThatShouldNotThrow
|
||||
value: ''
|
||||
- key: performance-inefficient-vector-operation.EnableProto
|
||||
value: 'false'
|
||||
- key: modernize-make-shared.MakeSmartPtrFunction
|
||||
value: 'std::make_shared'
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: '16'
|
||||
- key: readability-suspicious-call-argument.PrefixDissimilarBelow
|
||||
value: '25'
|
||||
- key: readability-function-size.LineThreshold
|
||||
value: '4294967295'
|
||||
- key: bugprone-easily-swappable-parameters.MinimumLength
|
||||
value: '2'
|
||||
- key: portability-simd-intrinsics.Suggest
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader
|
||||
value: ''
|
||||
- key: modernize-use-override.IgnoreDestructors
|
||||
value: 'false'
|
||||
- key: modernize-make-shared.MakeSmartPtrFunctionHeader
|
||||
value: '<memory>'
|
||||
- key: bugprone-sizeof-expression.WarnOnSizeOfConstant
|
||||
value: 'true'
|
||||
- key: readability-redundant-string-init.StringNames
|
||||
value: '::std::basic_string_view;::std::basic_string'
|
||||
- key: modernize-make-unique.IgnoreDefaultInitialization
|
||||
value: 'true'
|
||||
- key: modernize-use-emplace.ContainersWithPushBack
|
||||
value: '::std::vector;::std::list;::std::deque'
|
||||
- key: readability-magic-numbers.IgnoreBitFieldsWidths
|
||||
value: 'true'
|
||||
- key: modernize-make-unique.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-override.OverrideSpelling
|
||||
value: override
|
||||
- key: readability-suspicious-call-argument.LevenshteinDissimilarBelow
|
||||
value: '50'
|
||||
- key: bugprone-argument-comment.CommentStringLiterals
|
||||
value: '0'
|
||||
- key: concurrency-mt-unsafe.FunctionSet
|
||||
value: any
|
||||
- key: readability-identifier-length.IgnoredExceptionVariableNames
|
||||
value: '^[e]$'
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: bugprone-reserved-identifier.AllowedIdentifiers
|
||||
value: ''
|
||||
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
|
||||
value: 'false'
|
||||
- key: readability-else-after-return.WarnOnUnfixable
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
|
||||
value: '1.0;100.0;'
|
||||
- key: modernize-use-emplace.IgnoreImplicitConstructors
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-macro-usage.IgnoreCommandLineMacros
|
||||
value: 'true'
|
||||
- key: readability-suspicious-call-argument.Substring
|
||||
value: 'true'
|
||||
- key: modernize-use-equals-delete.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: readability-identifier-length.IgnoredVariableNames
|
||||
value: ''
|
||||
- key: readability-magic-numbers.IgnoreAllFloatingPointValues
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-suspicious-call-argument.Abbreviations
|
||||
value: 'arr=array;cnt=count;idx=index;src=source;stmt=statement;cpy=copy;dest=destination;dist=distancedst=distance;ptr=pointer;wdth=width;str=string;ln=line;srv=server;attr=attribute;ref=reference;buf=buffer;col=column;nr=number;vec=vector;len=length;elem=element;val=value;i=index;var=variable;hght=height;cl=client;num=number;pos=position;lst=list;addr=address'
|
||||
- key: bugprone-misplaced-widening-cast.CheckImplicitCasts
|
||||
value: 'false'
|
||||
- key: readability-uppercase-literal-suffix.NewSuffixes
|
||||
value: ''
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: performance-unnecessary-value-param.AllowedTypes
|
||||
value: ''
|
||||
- key: readability-uniqueptr-delete-release.PreferResetCall
|
||||
value: 'false'
|
||||
- key: readability-identifier-length.MinimumExceptionNameLength
|
||||
value: '2'
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
|
||||
value: 'false'
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: '2'
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreBitFieldsWidths
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
|
||||
value: '1;2;3;4;'
|
||||
- key: cppcoreguidelines-no-malloc.Allocations
|
||||
value: '::malloc;::calloc'
|
||||
- key: bugprone-narrowing-conversions.IgnoreConversionFromTypes
|
||||
value: ''
|
||||
- key: readability-function-size.BranchThreshold
|
||||
value: '4294967295'
|
||||
- key: bugprone-suspicious-missing-comma.RatioThreshold
|
||||
value: '0.200000'
|
||||
- key: readability-implicit-bool-conversion.AllowIntegerConditions
|
||||
value: 'false'
|
||||
- key: readability-identifier-length.IgnoredParameterNames
|
||||
value: '^[n]$'
|
||||
- key: readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: readability-identifier-naming.IgnoreMainLikeFunctions
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-init-variables.MathHeader
|
||||
value: '<math.h>'
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: '800'
|
||||
- key: bugprone-reserved-identifier.AggressiveDependentMemberLookup
|
||||
value: 'false'
|
||||
- key: readability-suspicious-call-argument.DiceSimilarAbove
|
||||
value: '70'
|
||||
- key: modernize-use-equals-default.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: readability-suspicious-call-argument.Abbreviation
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
|
||||
value: 'false'
|
||||
- key: readability-identifier-length.MinimumLoopCounterNameLength
|
||||
value: '2'
|
||||
- key: modernize-use-emplace.SmartPointers
|
||||
value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr'
|
||||
- key: cppcoreguidelines-no-malloc.Deallocations
|
||||
value: '::free'
|
||||
- key: bugprone-dangling-handle.HandleClasses
|
||||
value: 'std::basic_string_view;std::experimental::basic_string_view'
|
||||
- key: readability-magic-numbers.IgnorePowersOf2IntegerValues
|
||||
value: 'false'
|
||||
- key: readability-suspicious-call-argument.JaroWinklerSimilarAbove
|
||||
value: '85'
|
||||
- key: readability-simplify-subscript-expr.Types
|
||||
value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
|
||||
- key: performance-unnecessary-copy-initialization.ExcludedContainerTypes
|
||||
value: ''
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: performance-move-const-arg.CheckTriviallyCopyableMove
|
||||
value: 'true'
|
||||
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
|
||||
value: '3'
|
||||
- key: readability-function-size.VariableThreshold
|
||||
value: '4294967295'
|
||||
- key: cert-dcl16-c.NewSuffixes
|
||||
value: 'L;LL;LU;LLU'
|
||||
- key: bugprone-narrowing-conversions.WarnOnFloatingPointNarrowingConversion
|
||||
value: 'true'
|
||||
- key: readability-identifier-naming.GetConfigPerFile
|
||||
value: 'true'
|
||||
- key: modernize-use-default-member-init.UseAssignment
|
||||
value: 'false'
|
||||
- key: readability-function-size.NestingThreshold
|
||||
value: '4294967295'
|
||||
- key: modernize-use-override.AllowOverrideAndFinal
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-narrowing-conversions.IgnoreConversionFromTypes
|
||||
value: ''
|
||||
- key: readability-function-size.ParameterThreshold
|
||||
value: '4294967295'
|
||||
- key: modernize-pass-by-value.ValuesOnly
|
||||
value: 'false'
|
||||
- key: readability-function-cognitive-complexity.IgnoreMacros
|
||||
value: 'false'
|
||||
- key: modernize-loop-convert.IncludeStyle
|
||||
value: llvm
|
||||
- key: cert-str34-c.DiagnoseSignedUnsignedCharComparisons
|
||||
value: 'false'
|
||||
- key: bugprone-narrowing-conversions.WarnWithinTemplateInstantiation
|
||||
value: 'false'
|
||||
- key: cert-err33-c.CheckedFunctions
|
||||
value: '::aligned_alloc;::asctime_s;::at_quick_exit;::atexit;::bsearch;::bsearch_s;::btowc;::c16rtomb;::c32rtomb;::calloc;::clock;::cnd_broadcast;::cnd_init;::cnd_signal;::cnd_timedwait;::cnd_wait;::ctime_s;::fclose;::fflush;::fgetc;::fgetpos;::fgets;::fgetwc;::fopen;::fopen_s;::fprintf;::fprintf_s;::fputc;::fputs;::fputwc;::fputws;::fread;::freopen;::freopen_s;::fscanf;::fscanf_s;::fseek;::fsetpos;::ftell;::fwprintf;::fwprintf_s;::fwrite;::fwscanf;::fwscanf_s;::getc;::getchar;::getenv;::getenv_s;::gets_s;::getwc;::getwchar;::gmtime;::gmtime_s;::localtime;::localtime_s;::malloc;::mbrtoc16;::mbrtoc32;::mbsrtowcs;::mbsrtowcs_s;::mbstowcs;::mbstowcs_s;::memchr;::mktime;::mtx_init;::mtx_lock;::mtx_timedlock;::mtx_trylock;::mtx_unlock;::printf_s;::putc;::putwc;::raise;::realloc;::remove;::rename;::scanf;::scanf_s;::setlocale;::setvbuf;::signal;::snprintf;::snprintf_s;::sprintf;::sprintf_s;::sscanf;::sscanf_s;::strchr;::strerror_s;::strftime;::strpbrk;::strrchr;::strstr;::strtod;::strtof;::strtoimax;::strtok;::strtok_s;::strtol;::strtold;::strtoll;::strtoul;::strtoull;::strtoumax;::strxfrm;::swprintf;::swprintf_s;::swscanf;::swscanf_s;::thrd_create;::thrd_detach;::thrd_join;::thrd_sleep;::time;::timespec_get;::tmpfile;::tmpfile_s;::tmpnam;::tmpnam_s;::tss_create;::tss_get;::tss_set;::ungetc;::ungetwc;::vfprintf;::vfprintf_s;::vfscanf;::vfscanf_s;::vfwprintf;::vfwprintf_s;::vfwscanf;::vfwscanf_s;::vprintf_s;::vscanf;::vscanf_s;::vsnprintf;::vsnprintf_s;::vsprintf;::vsprintf_s;::vsscanf;::vsscanf_s;::vswprintf;::vswprintf_s;::vswscanf;::vswscanf_s;::vwprintf_s;::vwscanf;::vwscanf_s;::wcrtomb;::wcschr;::wcsftime;::wcspbrk;::wcsrchr;::wcsrtombs;::wcsrtombs_s;::wcsstr;::wcstod;::wcstof;::wcstoimax;::wcstok;::wcstok_s;::wcstol;::wcstold;::wcstoll;::wcstombs;::wcstombs_s;::wcstoul;::wcstoull;::wcstoumax;::wcsxfrm;::wctob;::wctrans;::wctype;::wmemchr;::wprintf_s;::wscanf;::wscanf_s;'
|
||||
- key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
|
||||
value: 'false'
|
||||
- key: readability-redundant-smartptr-get.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-explicit-virtual-functions.AllowOverrideAndFinal
|
||||
value: 'false'
|
||||
- key: readability-identifier-naming.AggressiveDependentMemberLookup
|
||||
value: 'false'
|
||||
- key: readability-identifier-length.MinimumParameterNameLength
|
||||
value: '2'
|
||||
- key: modernize-use-emplace.TupleTypes
|
||||
value: '::std::pair;::std::tuple'
|
||||
- key: modernize-use-emplace.TupleMakeFunctions
|
||||
value: '::std::make_pair;::std::make_tuple'
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-owning-memory.LegacyResourceProducers
|
||||
value: '::malloc;::aligned_alloc;::realloc;::calloc;::fopen;::freopen;::tmpfile'
|
||||
- key: bugprone-easily-swappable-parameters.SuppressParametersUsedTogether
|
||||
value: 'true'
|
||||
- key: bugprone-argument-comment.StrictMode
|
||||
value: '0'
|
||||
- key: modernize-replace-random-shuffle.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-bool-literals.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
|
||||
value: 'true'
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: '10'
|
||||
- key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
|
||||
value: ''
|
||||
- key: modernize-avoid-bind.PermissiveParameterList
|
||||
value: 'false'
|
||||
- key: bugprone-easily-swappable-parameters.NamePrefixSuffixSilenceDissimilarityTreshold
|
||||
value: '1'
|
||||
- key: readability-suspicious-call-argument.Suffix
|
||||
value: 'true'
|
||||
- key: readability-suspicious-call-argument.JaroWinklerDissimilarBelow
|
||||
value: '75'
|
||||
- key: modernize-use-noexcept.ReplacementString
|
||||
value: ''
|
||||
- key: modernize-use-override.FinalSpelling
|
||||
value: final
|
||||
- key: modernize-use-using.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-explicit-virtual-functions.FinalSpelling
|
||||
value: final
|
||||
- key: readability-suspicious-call-argument.MinimumIdentifierNameLength
|
||||
value: '3'
|
||||
- key: bugprone-narrowing-conversions.WarnOnIntegerNarrowingConversion
|
||||
value: 'true'
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: cppcoreguidelines-pro-type-member-init.UseAssignment
|
||||
value: 'false'
|
||||
- key: bugprone-suspicious-include.HeaderFileExtensions
|
||||
value: ';h;hh;hpp;hxx'
|
||||
- key: performance-no-automatic-move.AllowedTypes
|
||||
value: ''
|
||||
- key: readability-suspicious-call-argument.SubstringDissimilarBelow
|
||||
value: '40'
|
||||
- key: bugprone-argument-comment.CommentIntegerLiterals
|
||||
value: '0'
|
||||
- key: bugprone-stringview-nullptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: performance-for-range-copy.WarnOnAllAutoCopies
|
||||
value: 'false'
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: bugprone-argument-comment.CommentFloatLiterals
|
||||
value: '0'
|
||||
- key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
|
||||
value: '16'
|
||||
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
|
||||
value: 'false'
|
||||
- key: readability-else-after-return.WarnOnConditionVariables
|
||||
value: 'true'
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: 'NULL'
|
||||
- key: readability-suspicious-call-argument.SuffixDissimilarBelow
|
||||
value: '25'
|
||||
- key: bugprone-argument-comment.CommentCharacterLiterals
|
||||
value: '0'
|
||||
- key: cppcoreguidelines-macro-usage.AllowedRegexp
|
||||
value: '^DEBUG_*'
|
||||
- key: readability-suspicious-call-argument.LevenshteinSimilarAbove
|
||||
value: '66'
|
||||
- key: cppcoreguidelines-narrowing-conversions.PedanticMode
|
||||
value: 'false'
|
||||
- key: modernize-make-shared.IgnoreDefaultInitialization
|
||||
value: 'true'
|
||||
- key: readability-suspicious-call-argument.JaroWinkler
|
||||
value: 'true'
|
||||
- key: bugprone-implicit-widening-of-multiplication-result.UseCXXHeadersInCppSources
|
||||
value: 'true'
|
||||
- key: modernize-make-shared.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-suspicious-call-argument.Prefix
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
|
||||
value: 'false'
|
||||
- key: bugprone-implicit-widening-of-multiplication-result.UseCXXStaticCastsInCppSources
|
||||
value: 'true'
|
||||
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
|
||||
value: ''
|
||||
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
|
||||
value: 'false'
|
||||
- key: modernize-make-unique.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: performance-for-range-copy.AllowedTypes
|
||||
value: ''
|
||||
- key: bugprone-argument-comment.CommentBoolLiterals
|
||||
value: '0'
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '0'
|
||||
- key: bugprone-argument-comment.CommentUserDefinedLiterals
|
||||
value: '0'
|
||||
- key: readability-magic-numbers.IgnoredFloatingPointValues
|
||||
value: '1.0;100.0;'
|
||||
- key: performance-inefficient-string-concatenation.StrictMode
|
||||
value: 'false'
|
||||
- key: readability-redundant-declaration.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: bugprone-easily-swappable-parameters.IgnoredParameterTypeSuffixes
|
||||
value: 'bool;Bool;_Bool;it;It;iterator;Iterator;inputit;InputIt;forwardit;ForwardIt;bidirit;BidirIt;constiterator;const_iterator;Const_Iterator;Constiterator;ConstIterator;RandomIt;randomit;random_iterator;ReverseIt;reverse_iterator;reverse_const_iterator;ConstReverseIterator;Const_Reverse_Iterator;const_reverse_iterator;Constreverseiterator;constreverseiterator'
|
||||
- key: modernize-make-unique.MakeSmartPtrFunction
|
||||
value: 'std::make_unique'
|
||||
- key: portability-restrict-system-includes.Includes
|
||||
value: '*'
|
||||
- key: readability-implicit-bool-conversion.AllowPointerConditions
|
||||
value: 'true'
|
||||
- key: modernize-make-unique.MakeSmartPtrFunctionHeader
|
||||
value: '<memory>'
|
||||
- key: bugprone-signal-handler.AsyncSafeFunctionSet
|
||||
value: POSIX
|
||||
- key: bugprone-easily-swappable-parameters.ModelImplicitConversions
|
||||
value: 'true'
|
||||
- key: readability-suspicious-call-argument.SubstringSimilarAbove
|
||||
value: '50'
|
||||
- key: cppcoreguidelines-narrowing-conversions.WarnWithinTemplateInstantiation
|
||||
value: 'false'
|
||||
- key: readability-identifier-length.MinimumVariableNameLength
|
||||
value: '2'
|
||||
- key: cppcoreguidelines-narrowing-conversions.WarnOnEquivalentBitWidth
|
||||
value: 'true'
|
||||
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnorePublicMemberVariables
|
||||
value: 'false'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
|
||||
value: 'false'
|
||||
- key: modernize-use-noexcept.UseNoexceptFalse
|
||||
value: 'true'
|
||||
- key: readability-function-cognitive-complexity.Threshold
|
||||
value: '25'
|
||||
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||
value: 'true'
|
||||
- key: bugprone-argument-comment.IgnoreSingleArgument
|
||||
value: '0'
|
||||
- key: bugprone-narrowing-conversions.WarnOnEquivalentBitWidth
|
||||
value: 'true'
|
||||
- key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
|
||||
value: 'false'
|
||||
- key: performance-faster-string-find.StringLikeClasses
|
||||
value: '::std::basic_string;::std::basic_string_view'
|
||||
- key: cppcoreguidelines-narrowing-conversions.WarnOnIntegerToFloatingPointNarrowingConversion
|
||||
value: 'true'
|
||||
- key: bugprone-assert-side-effect.CheckFunctionCalls
|
||||
value: 'false'
|
||||
- key: bugprone-string-constructor.StringNames
|
||||
value: '::std::basic_string;::std::basic_string_view'
|
||||
- key: bugprone-assert-side-effect.AssertMacros
|
||||
value: assert,NSAssert,NSCAssert
|
||||
- key: bugprone-exception-escape.IgnoredExceptions
|
||||
value: ''
|
||||
- key: bugprone-signed-char-misuse.DiagnoseSignedUnsignedCharComparisons
|
||||
value: 'true'
|
||||
- key: modernize-use-default-member-init.IgnoreMacros
|
||||
value: 'true'
|
||||
- key: llvm-qualified-auto.AddConstToQualified
|
||||
value: 'false'
|
||||
- key: llvm-else-after-return.WarnOnConditionVariables
|
||||
value: 'false'
|
||||
- key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
|
||||
value: 'true'
|
||||
- key: modernize-raw-string-literal.DelimiterStem
|
||||
value: lit
|
||||
- key: readability-suspicious-call-argument.Dice
|
||||
value: 'true'
|
||||
- key: readability-identifier-length.IgnoredLoopCounterNames
|
||||
value: '^[ijk_]$'
|
||||
- key: modernize-raw-string-literal.ReplaceShorterLiterals
|
||||
value: 'false'
|
||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||
value: '1;2;3;4;'
|
||||
- key: performance-inefficient-vector-operation.VectorLikeClasses
|
||||
value: '::std::vector'
|
||||
- key: modernize-use-auto.RemoveStars
|
||||
value: 'false'
|
||||
- key: bugprone-implicit-widening-of-multiplication-result.IncludeStyle
|
||||
value: llvm
|
||||
- key: portability-simd-intrinsics.Std
|
||||
value: ''
|
||||
- key: performance-unnecessary-value-param.IncludeStyle
|
||||
value: llvm
|
||||
- key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
|
||||
value: 'false'
|
||||
- key: modernize-replace-disallow-copy-and-assign-macro.MacroName
|
||||
value: DISALLOW_COPY_AND_ASSIGN
|
||||
- key: llvm-else-after-return.WarnOnUnfixable
|
||||
value: 'false'
|
||||
...
|
||||
|
||||
@@ -19,7 +19,9 @@ body:
|
||||
id: forum_link
|
||||
attributes:
|
||||
label: Forums discussion
|
||||
description: Please start a discussion about your issue at [the FreeCAD Forum](https://forum.freecad.org) and wait for confirmation there before creating an issue
|
||||
description: |
|
||||
Please start a discussion about your issue at [the FreeCAD Forum](https://forum.freecad.org) and wait for confirmation there before creating an issue.
|
||||
**Note:** Bug reports without a prior forum discussion will most likely not be accepted.
|
||||
placeholder: Paste link to forum discussion here
|
||||
validations:
|
||||
required: true
|
||||
@@ -29,8 +31,8 @@ body:
|
||||
label: Version
|
||||
description: What version of FreeCAD are you running?
|
||||
options:
|
||||
- 0.19 (Release)
|
||||
- 0.20 (Development)
|
||||
- 0.20 (Release)
|
||||
- 0.21 (Development)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -9,6 +9,6 @@ Thank you for creating a pull request to contribute to FreeCAD! To ease integrat
|
||||
- [ ] Commit messages include `issue #<id>` or `fixes #<id>` where `<id>` is the issue ID number from our [Issues database](https://github.com/FreeCAD/FreeCAD/issues) in case a particular commit solves or is related to an existing issue. Ex: `Draft: fix typos - fixes #4805`
|
||||
|
||||
And please remember to update the Wiki with the features added or changed once this PR is merged.
|
||||
**Note**: If you don't have wiki access, then please mention your contribution on the [0.20 Changelog Forum Thread](https://forum.freecadweb.org/viewtopic.php?f=10&t=56135).
|
||||
**Note**: If you don't have wiki access, then please mention your contribution on the [1.0 Changelog Forum Thread](https://forum.freecad.org/viewtopic.php?f=10&t=69438).
|
||||
|
||||
---
|
||||
|
||||
@@ -33,6 +33,7 @@ hist
|
||||
indicies
|
||||
inout
|
||||
ist
|
||||
itsel
|
||||
lod
|
||||
mantatory
|
||||
mata
|
||||
@@ -43,6 +44,7 @@ nin
|
||||
normale
|
||||
normaly
|
||||
numer
|
||||
oce
|
||||
ontop
|
||||
ot
|
||||
parm
|
||||
@@ -54,6 +56,7 @@ recurrance
|
||||
rougly
|
||||
seh
|
||||
serie
|
||||
siz
|
||||
som
|
||||
strack
|
||||
substraction
|
||||
@@ -62,6 +65,7 @@ te
|
||||
thist
|
||||
tread
|
||||
ue
|
||||
upto
|
||||
uptodate
|
||||
usind
|
||||
vas
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "black-warning",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(would reformat (.*))$",
|
||||
"file": 2,
|
||||
"message": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "clang",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):([0-9]+):([0-9]+): (error|warning|note): (.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "codespell-matcher",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):(\\d+):\\s+(.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "cpplint",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):([0-9]+): (.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "grepMatcher-warning",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+):([0-9]+):(.+)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"message": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "pylint-error",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+?):([0-9]+):([0-9]+): ([([E|F][0-9]+): (.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "pylint-warning",
|
||||
"severity": "warning",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.+?):([0-9]+):([0-9]+): ([^E|F][0-9]+): (.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+6
-4
@@ -1,5 +1,9 @@
|
||||
# file types to ignore
|
||||
|
||||
.*
|
||||
!/.gitignore
|
||||
!/.clang-format
|
||||
!/.git-blame-ignore-revs
|
||||
!/.gitattributes
|
||||
*.DS_Store
|
||||
*.pyc
|
||||
*.obj
|
||||
@@ -34,12 +38,10 @@ install_manifest.txt
|
||||
/src/Tools/offlinedoc/localwiki/
|
||||
/src/Tools/offlinedoc/*.txt
|
||||
OpenSCAD_rc.py
|
||||
/\.idea/
|
||||
.tags
|
||||
tags
|
||||
/\.vscode/
|
||||
|
||||
# crowdin file
|
||||
src/Tools/freecad.zip
|
||||
tsupdate_stderr.log
|
||||
tsupdate_stdout.log
|
||||
files_to_translate.txt
|
||||
|
||||
@@ -0,0 +1,614 @@
|
||||
[MAIN]
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Load and enable all available extensions. Use --list-extensions to see a list
|
||||
# all available extensions.
|
||||
#enable-all-extensions=
|
||||
|
||||
# In error mode, messages with a category besides ERROR or FATAL are
|
||||
# suppressed, and no reports are done by default. Error mode is compatible with
|
||||
# disabling specific errors.
|
||||
#errors-only=
|
||||
|
||||
# Always return a 0 (non-error) status code, even if lint errors are found.
|
||||
# This is primarily useful in continuous integration scripts.
|
||||
#exit-zero=
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code.
|
||||
extension-pkg-allow-list=
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||
# for backward compatibility.)
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Return non-zero exit code if any of these messages/categories are detected,
|
||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
||||
# specified are enabled, while categories only check already-enabled messages.
|
||||
fail-on=
|
||||
|
||||
# Specify a score threshold to be exceeded before program exits with error.
|
||||
fail-under=10
|
||||
|
||||
# Interpret the stdin as a python script, whose filename needs to be passed as
|
||||
# the module_or_package argument.
|
||||
#from-stdin=
|
||||
|
||||
# Files or directories to be skipped. They should be base names, not paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regex patterns to the ignore-list. The
|
||||
# regex matches against paths and can be in Posix or Windows format.
|
||||
ignore-paths=
|
||||
|
||||
# Files or directories matching the regex patterns are skipped. The regex
|
||||
# matches against base names, not paths. The default value ignores Emacs file
|
||||
# locks
|
||||
ignore-patterns=^\.#
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis). It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||
# number of processors available to use, and will cap the count on Windows to
|
||||
# avoid hangs.
|
||||
jobs=1
|
||||
|
||||
# Control the amount of potential inferred values when inferring a single
|
||||
# object. This can help the performance when dealing with large functions or
|
||||
# complex, nested conditions.
|
||||
limit-inference-results=100
|
||||
|
||||
# List of plugins (as comma separated values of python module names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Minimum Python version to use for version dependent checks. Will default to
|
||||
# the version used to run pylint.
|
||||
py-version=3.10
|
||||
|
||||
# Discover python modules and packages in the file system subtree.
|
||||
recursive=no
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages.
|
||||
suggestion-mode=yes
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
# In verbose mode, extra non-checker-related info will be displayed.
|
||||
#verbose=
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a score less than or equal to 10. You
|
||||
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
||||
# 'convention', and 'info' which contain the number of messages in each
|
||||
# category, as well as 'statement' which is the total number of statements
|
||||
# analyzed. This score is used by the global evaluation report (RP0004).
|
||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details.
|
||||
msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio). You can also give a reporter class, e.g.
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
#output-format=
|
||||
|
||||
# Tells whether to display a full report or only the messages.
|
||||
reports=yes
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
||||
# UNDEFINED.
|
||||
confidence=HIGH,
|
||||
CONTROL_FLOW,
|
||||
INFERENCE,
|
||||
INFERENCE_FAILURE,
|
||||
UNDEFINED
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once). You can also use "--disable=all" to
|
||||
# disable everything first and then re-enable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||
# --disable=W".
|
||||
disable=raw-checker-failed,
|
||||
bad-inline-option,
|
||||
locally-disabled,
|
||||
file-ignored,
|
||||
suppressed-message,
|
||||
useless-suppression,
|
||||
deprecated-pragma,
|
||||
use-symbolic-message-instead,
|
||||
invalid-name,
|
||||
wrong-import-order,
|
||||
import-error,
|
||||
undefined-variable
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=c-extension-no-member
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names.
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style. If left empty, argument names will be checked with the set
|
||||
# naming style.
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names.
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style. If left empty, attribute names will be checked with the set naming
|
||||
# style.
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma.
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be refused
|
||||
bad-names-rgxs=
|
||||
|
||||
# Naming style matching correct class attribute names.
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
||||
# with the set naming style.
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class constant names.
|
||||
class-const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct class constant names. Overrides class-
|
||||
# const-naming-style. If left empty, class constant names will be checked with
|
||||
# the set naming style.
|
||||
#class-const-rgx=
|
||||
|
||||
# Naming style matching correct class names.
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-
|
||||
# style. If left empty, class names will be checked with the set naming style.
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names.
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style. If left empty, constant names will be checked with the set naming
|
||||
# style.
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names.
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style. If left empty, function names will be checked with the set
|
||||
# naming style.
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be accepted
|
||||
good-names-rgxs=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name.
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names.
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
||||
# with the set naming style.
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names.
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style. If left empty, method names will be checked with the set naming style.
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names.
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style. If left empty, module names will be checked with the set naming style.
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
# These decorators are taken in consideration only for invalid-name.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Regular expression matching correct type variable names. If left empty, type
|
||||
# variable names will be checked with the set naming style.
|
||||
#typevar-rgx=
|
||||
|
||||
# Naming style matching correct variable names.
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style. If left empty, variable names will be checked with the set
|
||||
# naming style.
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# Warn about protected attribute access inside special methods
|
||||
check-protected-access-in-special-methods=no
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp,
|
||||
__post_init__
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=cls
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# List of regular expressions of class ancestor names to ignore when counting
|
||||
# public methods (see R0903)
|
||||
exclude-too-few-public-methods=
|
||||
|
||||
# List of qualified class names to ignore when counting class parents (see
|
||||
# R0901)
|
||||
ignored-parents=
|
||||
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=5
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when caught.
|
||||
overgeneral-exceptions=BaseException,
|
||||
Exception
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=1000
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# List of modules that can be imported at any level, not just the top level
|
||||
# one.
|
||||
allow-any-import-level=
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma.
|
||||
deprecated-modules=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of external dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
ext-import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||
# external) dependencies to the given file (report RP0402 must not be
|
||||
# disabled).
|
||||
import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
# Couples of modules and preferred modules, separated by a comma.
|
||||
preferred-modules=
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# The type of string formatting that logging methods do. `old` means using %
|
||||
# formatting, `new` is for `{}` formatting.
|
||||
logging-format-style=old
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format.
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
# Regular expression of note tags to take in consideration.
|
||||
notes-rgx=
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Comments are removed from the similarity computation
|
||||
ignore-comments=yes
|
||||
|
||||
# Docstrings are removed from the similarity computation
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Imports are removed from the similarity computation
|
||||
ignore-imports=yes
|
||||
|
||||
# Signatures are removed from the similarity computation
|
||||
ignore-signatures=yes
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes.
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
||||
# install the 'python-enchant' package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should be considered directives if they
|
||||
# appear at the beginning of a comment and should not be checked.
|
||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains the private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to the private dictionary (see the
|
||||
# --spelling-private-dict-file option) instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=no
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
# Tells whether to warn about missing members when the owner of the attribute
|
||||
# is inferred to be None.
|
||||
ignore-none=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of symbolic message names to ignore for Mixin members.
|
||||
ignored-checks-for-mixins=no-member,
|
||||
not-async-context-manager,
|
||||
not-context-manager,
|
||||
attribute-defined-outside-init
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
# Regex pattern to define which classes are considered mixins.
|
||||
mixin-class-rgx=.*[Mm]ixin
|
||||
|
||||
# List of decorators that change the signature of a decorated function.
|
||||
signature-mutators=
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid defining new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of names allowed to shadow builtins
|
||||
allowed-redefined-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||
# not be used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore.
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
+3
-2
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR)
|
||||
# relates to FindOpenGL module
|
||||
# and cache variables OPENGL_gl_LIBRARY, OPENGL_glu_LIBRARY
|
||||
if (POLICY CMP0072)
|
||||
cmake_policy(SET CMP0072 OLD)
|
||||
set(OpenGL_GL_PREFERENCE LEGACY)
|
||||
endif(POLICY CMP0072)
|
||||
|
||||
find_program(CCACHE_PROGRAM ccache) #This check should occur before project()
|
||||
@@ -17,9 +17,10 @@ project(FreeCAD)
|
||||
|
||||
set(PACKAGE_VERSION_NAME "Vulcan")
|
||||
set(PACKAGE_VERSION_MAJOR "0")
|
||||
set(PACKAGE_VERSION_MINOR "20")
|
||||
set(PACKAGE_VERSION_MINOR "21")
|
||||
set(PACKAGE_VERSION_PATCH "0")
|
||||
set(PACKAGE_VERSION_SUFFIX "dev") # either "dev" for development snapshot or "" (empty string)
|
||||
|
||||
set(FREECAD_VERSION_PATCH "0") # number of patch release (e.g. "4" for the 0.18.4 release)
|
||||
|
||||
set(FREECAD_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}")
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -1,7 +1,50 @@
|
||||

|
||||
<h6 align="center"><img src="FreeCAD-toponaming-logo.png"/></h6>
|
||||
|
||||
### Your own 3D parametric modeler
|
||||
<h1 align="center">FreeCAD Topological Naming (toponaming) Branch</h1>
|
||||
|
||||
### About
|
||||
|
||||
This branch is dedicated to integrating code that improves the [topological naming problem](https://wiki.freecad.org/Topological_naming_problem) in FreeCAD. There have been several attempts to address it over the years within FreeCAD. In reality, toponaming is an issue that no modern CAD software is fully immune to. This is because the solutions are complex.
|
||||
|
||||
Thanks to an independent developer named Zheng Lei ('realthunder'), who has gone the farthest in the effort of fixing toponaming in FreeCAD, and has provided a proof of concept fix in his own branch named 'Link' branch.
|
||||
|
||||
* [@Realthunder](https://github.com/realthunder)'s Link branch: https://github.com/realthunder/FreeCAD
|
||||
* Official FreeCAD main ('master') branch: https://github.com/FreeCAD/FreeCAD/
|
||||
* Official FreeCAD toponaming git repository: https://github.com/FreeCAD/FreeCAD/tree/development/toponaming
|
||||
|
||||
|
||||
### Objective
|
||||
|
||||
Per the FreeCAD developer meetings that occurred during the pre-release of v0.20, 'toponaming' was identified as one of the main targets for merge in the v0.21/v1.0 release cycle.
|
||||
|
||||
### Contributing
|
||||
|
||||
During this development cycle there will be nightly builds provided for testers to test and report results back to the developers.
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Expand this section to learn about testing toponaming on different platforms/distros</summary>
|
||||
|
||||
#### Linux
|
||||
|
||||
##### Snap packages
|
||||
A nightly Snap package of the 'toponaming' branch will be available to testers. Refer to the [Snap wiki page](https://wiki.freecad.org/Ubuntu_Snap#Notes)
|
||||
|
||||
#### Windows
|
||||
|
||||
TBD
|
||||
|
||||
#### macOS
|
||||
|
||||
TBD
|
||||
|
||||
#### FreeBSD
|
||||
|
||||
N/A
|
||||
|
||||
</details>
|
||||
|
||||
<!--
|
||||
[Website](https://www.freecadweb.org) •
|
||||
[Documentation](https://wiki.freecadweb.org) •
|
||||
[Forum](https://forum.freecadweb.org/) •
|
||||
@@ -11,7 +54,7 @@
|
||||
|
||||
[](https://github.com/freecad/freecad/releases/latest) [![Master][freecad-master-status]][gitlab-branch-master] [](https://crowdin.com/project/freecad) [](https://gitter.im/freecad/freecad?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://lgtm.com/projects/g/FreeCAD/FreeCAD/context:python) [](https://lgtm.com/projects/g/FreeCAD/FreeCAD/context:cpp) [](https://liberapay.com/FreeCAD)
|
||||
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/1828501/174066870-1692005b-f8d7-43fb-a289-6d2f07f73d7f.png" width="800"/>
|
||||
|
||||
Overview
|
||||
--------
|
||||
@@ -55,13 +98,13 @@ Other options are described at the [wiki Download page](https://wiki.freecadweb.
|
||||
Build Status
|
||||
------------
|
||||
|
||||
| Master | 0.19 | Translation |
|
||||
| Master | 0.20 | Translation |
|
||||
|:------:|:----:|:-----------:|
|
||||
|[![Master][freecad-master-status]][gitlab-branch-master]|[![0.19][freecad-0.19-status]][gitlab-branch-0.19]|[](https://crowdin.com/project/freecad)|
|
||||
|[![Master][freecad-master-status]][gitlab-branch-master]|[![0.20][freecad-0.20-status]][gitlab-branch-0.20]|[](https://crowdin.com/project/freecad)|
|
||||
|
||||
[freecad-0.19-status]: https://gitlab.com/freecad/FreeCAD-CI/badges/releases/FreeCAD-0-19/pipeline.svg
|
||||
[freecad-0.20-status]: https://gitlab.com/freecad/FreeCAD-CI/badges/releases/FreeCAD-0-20/pipeline.svg
|
||||
[freecad-master-status]: https://gitlab.com/freecad/FreeCAD-CI/badges/master/pipeline.svg
|
||||
[gitlab-branch-0.19]: https://gitlab.com/freecad/FreeCAD-CI/-/commits/releases/FreeCAD-0-19
|
||||
[gitlab-branch-0.20]: https://gitlab.com/freecad/FreeCAD-CI/-/commits/releases/FreeCAD-0-20
|
||||
[gitlab-branch-master]: https://gitlab.com/freecad/FreeCAD-CI/-/commits/master
|
||||
[travis-builds]: https://travis-ci.org/FreeCAD/FreeCAD/builds
|
||||
|
||||
@@ -99,7 +142,7 @@ To report an issue please:
|
||||
For more detail see:
|
||||
- [Wiki Page about the Bug Tracker](https://wiki.freecadweb.org/Tracker)
|
||||
- [Bug Tracker](https://tracker.freecadweb.org)
|
||||
- [Help Forum](http://forum.freecadweb.org/viewforum.php?f=3)
|
||||
- [Help Forum](https://forum.freecadweb.org/viewforum.php?f=3)
|
||||
|
||||
|
||||
Usage & Getting help
|
||||
@@ -126,3 +169,5 @@ learning to use FreeCAD.
|
||||
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="91px">
|
||||
</a> and <a href="https://www.kipro-pcb.com/">KiCad Services Corp.</a>
|
||||
</p>
|
||||
|
||||
-->
|
||||
|
||||
+39
-9
@@ -5,28 +5,55 @@
|
||||
# SMESH_INCLUDE_DIR - where the Salome SMESH include directory can be found
|
||||
# SMESH_LIBRARIES - Link this to use Salome SMESH
|
||||
#
|
||||
|
||||
|
||||
# SMESH needs VTK
|
||||
find_package(VTK REQUIRED)
|
||||
|
||||
# If this definition is not set, linker errors will occur against SMESH on 64 bit machines.
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_definitions(-DSALOME_USE_64BIT_IDS)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
|
||||
IF (CMAKE_COMPILER_IS_GNUCC)
|
||||
FIND_PATH(SMESH_INCLUDE_DIR SMESH_Mesh.hxx
|
||||
# These are default search paths, why specify them?
|
||||
# /usr/include
|
||||
# /usr/local/include
|
||||
PATH_SUFFIXES smesh
|
||||
)
|
||||
FIND_LIBRARY(SMESH_LIBRARY SMESH
|
||||
# /usr/lib
|
||||
# /usr/local/lib
|
||||
PATH_SUFFIXES smesh SMESH smesh/SMESH
|
||||
)
|
||||
FIND_LIBRARY(SMESH_LIBRARY SMESH)
|
||||
ELSE (CMAKE_COMPILER_IS_GNUCC)
|
||||
# Not yet implemented
|
||||
ENDIF (CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
IF(SMESH_INCLUDE_DIR)
|
||||
SET(SMESH_INC_ROOT "${SMESH_INCLUDE_DIR}/..")
|
||||
# Append extra include dirs
|
||||
SET(SMESH_INCLUDE_DIR
|
||||
"${SMESH_INCLUDE_DIR};
|
||||
${SMESH_INC_ROOT}/Controls;
|
||||
${SMESH_INC_ROOT}/Driver;
|
||||
${SMESH_INC_ROOT}/DriverDAT;
|
||||
${SMESH_INC_ROOT}/DriverGMF;
|
||||
${SMESH_INC_ROOT}/DriverSTL;
|
||||
${SMESH_INC_ROOT}/DriverUNV;
|
||||
${SMESH_INC_ROOT}/Geom;
|
||||
${SMESH_INC_ROOT}/Kernel;
|
||||
${SMESH_INC_ROOT}/MEFISTO2;
|
||||
${SMESH_INC_ROOT}/MeshVSLink;
|
||||
${SMESH_INC_ROOT}/Netgen;
|
||||
${SMESH_INC_ROOT}/NETGENPlugin;
|
||||
${SMESH_INC_ROOT}/SMDS;
|
||||
${SMESH_INC_ROOT}/SMESHDS;
|
||||
${SMESH_INC_ROOT}/SMESHUtils;
|
||||
${SMESH_INC_ROOT}/StdMeshers;")
|
||||
ELSE(SMESH_INCLUDE_DIR)
|
||||
message(FATAL_ERROR "SMESH include directories not found!")
|
||||
ENDIF(SMESH_INCLUDE_DIR)
|
||||
|
||||
SET(SMESH_FOUND FALSE)
|
||||
IF(SMESH_LIBRARY)
|
||||
SET(SMESH_FOUND TRUE)
|
||||
GET_FILENAME_COMPONENT(SMESH_LIBRARY_DIR ${SMESH_LIBRARY} PATH)
|
||||
set(SMESH_LIBRARIES
|
||||
set(SMESH_LIBRARIES
|
||||
${SMESH_LIBRARY_DIR}/libDriver.so
|
||||
${SMESH_LIBRARY_DIR}/libDriverDAT.so
|
||||
${SMESH_LIBRARY_DIR}/libDriverSTL.so
|
||||
@@ -36,5 +63,8 @@ IF(SMESH_LIBRARY)
|
||||
${SMESH_LIBRARY_DIR}/libSMESHDS.so
|
||||
${SMESH_LIBRARY_DIR}/libStdMeshers.so
|
||||
)
|
||||
set(EXTERNAL_SMESH_LIBS ${SMESH_LIBRARIES})
|
||||
ELSE(SMESH_LIBRARY)
|
||||
message(FATAL_ERROR "SMESH libraries NOT FOUND!")
|
||||
ENDIF(SMESH_LIBRARY)
|
||||
|
||||
|
||||
@@ -37,5 +37,5 @@ macro(CheckInterModuleDependencies)
|
||||
REQUIRES_MODS(BUILD_SKETCHER BUILD_PART)
|
||||
REQUIRES_MODS(BUILD_SPREADSHEET BUILD_DRAFT)
|
||||
REQUIRES_MODS(BUILD_START BUILD_WEB)
|
||||
REQUIRES_MODS(BUILD_TECHDRAW BUILD_PART BUILD_SPREADSHEET BUILD_DRAWING)
|
||||
REQUIRES_MODS(BUILD_TECHDRAW BUILD_PART BUILD_SPREADSHEET)
|
||||
endmacro(CheckInterModuleDependencies)
|
||||
|
||||
@@ -10,6 +10,7 @@ macro(InitializeFreeCADBuildOptions)
|
||||
option(FREECAD_USE_EXTERNAL_KDL "Use system installed orocos-kdl instead of the bundled." OFF)
|
||||
option(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" ON)
|
||||
option(FREECAD_BUILD_DEBIAN "Prepare for a build of a Debian package" OFF)
|
||||
option(FREECAD_TOPONAMING_BRANDING "Enable branding for TopoNaming branch" ON)
|
||||
option(BUILD_WITH_CONDA "Set ON if you build FreeCAD with conda" OFF)
|
||||
option(BUILD_DYNAMIC_LINK_PYTHON "If OFF extension-modules do not link against python-libraries" ON)
|
||||
option(INSTALL_TO_SITEPACKAGES "If ON the freecad root namespace (python) is installed into python's site-packages" OFF)
|
||||
@@ -113,7 +114,7 @@ macro(InitializeFreeCADBuildOptions)
|
||||
option(BUILD_ARCH "Build the FreeCAD Architecture module" ON)
|
||||
option(BUILD_COMPLETE "Build the FreeCAD complete module" OFF)
|
||||
option(BUILD_DRAFT "Build the FreeCAD draft module" ON)
|
||||
option(BUILD_DRAWING "Build the FreeCAD drawing module" ON)
|
||||
option(BUILD_DRAWING "Build the FreeCAD drawing module" OFF)
|
||||
option(BUILD_IDF "Build the FreeCAD idf module" ON)
|
||||
option(BUILD_IMAGE "Build the FreeCAD image module" ON)
|
||||
option(BUILD_IMPORT "Build the FreeCAD import module" ON)
|
||||
|
||||
@@ -27,7 +27,7 @@ macro(PrintFinalReport)
|
||||
message(STATUS "pybind11: not enabled")
|
||||
endif(DEFINED pybind11_FOUND)
|
||||
|
||||
message(STATUS "Boost: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION} (${Boost_VERSION})")
|
||||
message(STATUS "Boost: ${Boost_VERSION}")
|
||||
|
||||
message(STATUS "XercesC: ${XercesC_VERSION} [${XercesC_LIBRARIES}] [${XercesC_INCLUDE_DIRS}]")
|
||||
|
||||
@@ -41,10 +41,10 @@ macro(PrintFinalReport)
|
||||
if(FREECAD_USE_EXTERNAL_SMESH)
|
||||
message(STATUS "SMESH: ${SMESH_VERSION_MAJOR}.${SMESH_VERSION_MINOR}.${SMESH_VERSION_PATCH}.${SMESH_VERSION_TWEAK}")
|
||||
else(FREECAD_USE_EXTERNAL_SMESH)
|
||||
message(STATUS "SMESH: build internal")
|
||||
message(STATUS " MEDFile: ${MEDFILE_VERSION} [${MEDFILE_LIBRARIES}] [${MEDFILE_INCLUDE_DIRS}]")
|
||||
message(STATUS " HDF5: ${HDF5_VERSION}")
|
||||
message(STATUS " VTK: ${VTK_VERSION}")
|
||||
message(STATUS "SMESH: ${SMESH_VERSION_MAJOR}.${SMESH_VERSION_MINOR}.${SMESH_VERSION_PATCH}.${SMESH_VERSION_TWEAK} build internal")
|
||||
message(STATUS "MEDFile: ${MEDFILE_VERSION} [${MEDFILE_LIBRARIES}] [${MEDFILE_INCLUDE_DIRS}]")
|
||||
message(STATUS "HDF5: ${HDF5_VERSION}")
|
||||
message(STATUS "VTK: ${VTK_VERSION}")
|
||||
endif(FREECAD_USE_EXTERNAL_SMESH)
|
||||
else(BUILD_SMESH)
|
||||
message(STATUS "SMESH: do not build")
|
||||
@@ -191,11 +191,11 @@ macro(PrintFinalReport)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
message(STATUS "Doxygen: ${DOXYGEN_VERSION}")
|
||||
message(STATUS " Language: ${DOXYGEN_LANGUAGE}")
|
||||
message(STATUS "Language: ${DOXYGEN_LANGUAGE}")
|
||||
if(COIN3D_DOC_FOUND)
|
||||
message(STATUS " Coin3D_DOC: found [${COIN3D_DOC_PATH}]")
|
||||
message(STATUS "Coin3D_DOC: found [${COIN3D_DOC_PATH}]")
|
||||
else(COIN3D_DOC_FOUND)
|
||||
message(STATUS " Coin3D_DOC: not found")
|
||||
message(STATUS "Coin3D_DOC: not found")
|
||||
endif(COIN3D_DOC_FOUND)
|
||||
else(DOXYGEN_FOUND)
|
||||
message(STATUS "Doxygen: not found")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
macro(SetupOpenCasCade)
|
||||
# -------------------------------- OpenCasCade --------------------------------
|
||||
|
||||
find_package(OpenCasCade)
|
||||
find_package(OCC)
|
||||
if(NOT OCC_FOUND)
|
||||
message(FATAL_ERROR "================================================================\n"
|
||||
"Neither OpenCASCADE Community Edition nor OpenCASCADE was found!\n"
|
||||
|
||||
@@ -119,13 +119,21 @@ macro(SetupSalomeSMESH)
|
||||
|
||||
else(NOT FREECAD_USE_EXTERNAL_SMESH)
|
||||
find_package(SMESH CONFIG)
|
||||
# If this definition is not set, linker errors will occur against SMESH on 64 bit machines.
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_definitions(-DSALOME_USE_64BIT_IDS)
|
||||
endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
if(NOT SMESH_FOUND)
|
||||
find_package(SMESH REQUIRED)
|
||||
if(NOT SMESH_FOUND)
|
||||
message(ERROR "================\n"
|
||||
"SMESH not found.\n"
|
||||
"================\n")
|
||||
endif()
|
||||
endif()
|
||||
set (SMESH_INCLUDE_DIR ${SMESH_INCLUDE_PATH})
|
||||
set(EXTERNAL_SMESH_LIBS ${SMESH_LIBRARIES})
|
||||
if(NOT SMESH_FOUND)
|
||||
message(ERROR "================\n"
|
||||
"SMESH not found.\n"
|
||||
"================\n")
|
||||
endif()
|
||||
|
||||
include_directories(${SMESH_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
|
||||
+17
-4
@@ -102,6 +102,7 @@
|
||||
#include "OriginFeature.h"
|
||||
#include "OriginGroupExtension.h"
|
||||
#include "OriginGroupExtensionPy.h"
|
||||
#include "StringHasherPy.h"
|
||||
#include "Part.h"
|
||||
#include "PartPy.h"
|
||||
#include "Placement.h"
|
||||
@@ -277,6 +278,7 @@ void Application::setupPythonTypes()
|
||||
Base::Interpreter().addType(&Base::PlacementPy::Type, pAppModule, "Placement");
|
||||
Base::Interpreter().addType(&Base::RotationPy::Type, pAppModule, "Rotation");
|
||||
Base::Interpreter().addType(&Base::AxisPy::Type, pAppModule, "Axis");
|
||||
Base::Interpreter().addType(&App::StringHasherPy::Type, pAppModule, "StringHasher");
|
||||
|
||||
// Note: Create an own module 'Base' which should provide the python
|
||||
// binding classes from the base module. At a later stage we should
|
||||
@@ -1127,7 +1129,8 @@ std::string Application::getUserMacroDir()
|
||||
std::string Application::getResourceDir()
|
||||
{
|
||||
#ifdef RESOURCEDIR
|
||||
std::string path(RESOURCEDIR);
|
||||
// #6892: Conda may inject null characters => remove them
|
||||
std::string path = std::string(RESOURCEDIR).c_str();
|
||||
path.append("/");
|
||||
QDir dir(QString::fromStdString(path));
|
||||
if (dir.isAbsolute())
|
||||
@@ -1141,7 +1144,8 @@ std::string Application::getResourceDir()
|
||||
std::string Application::getLibraryDir()
|
||||
{
|
||||
#ifdef LIBRARYDIR
|
||||
std::string path(LIBRARYDIR);
|
||||
// #6892: Conda may inject null characters => remove them
|
||||
std::string path = std::string(LIBRARYDIR).c_str();
|
||||
QDir dir(QString::fromStdString(path));
|
||||
if (dir.isAbsolute())
|
||||
return path;
|
||||
@@ -1154,7 +1158,8 @@ std::string Application::getLibraryDir()
|
||||
std::string Application::getHelpDir()
|
||||
{
|
||||
#ifdef DOCDIR
|
||||
std::string path(DOCDIR);
|
||||
// #6892: Conda may inject null characters => remove them
|
||||
std::string path = std::string(DOCDIR).c_str();
|
||||
path.append("/");
|
||||
QDir dir(QString::fromStdString(path));
|
||||
if (dir.isAbsolute())
|
||||
@@ -1901,6 +1906,9 @@ void Application::initTypes()
|
||||
Data::ComplexGeoData ::init();
|
||||
Data::Segment ::init();
|
||||
|
||||
App::StringID ::init();
|
||||
App::StringHasher ::init();
|
||||
|
||||
// Properties
|
||||
App ::Property ::init();
|
||||
App ::PropertyContainer ::init();
|
||||
@@ -2160,7 +2168,7 @@ void parseProgramOptions(int ac, char ** av, const string& exe, variables_map& v
|
||||
("log-file", value<string>(), "Unlike --write-log this allows logging to an arbitrary file")
|
||||
("user-cfg,u", value<string>(),"User config file to load/save user settings")
|
||||
("system-cfg,s", value<string>(),"System config file to load/save system settings")
|
||||
("run-test,t", value<string>() ,"Test case - or 0 for all")
|
||||
("run-test,t", value<string>()->implicit_value(""),"Run a given test case (use 0 (zero) to run all tests). If no argument is provided then return list of all available tests.")
|
||||
("module-path,M", value< vector<string> >()->composing(),"Additional module paths")
|
||||
("python-path,P", value< vector<string> >()->composing(),"Additional python paths")
|
||||
("single-instance", "Allow to run a single instance of the application")
|
||||
@@ -2394,6 +2402,9 @@ void processProgramOptions(const variables_map& vm, std::map<std::string,std::st
|
||||
if ( "0" == testCase) {
|
||||
testCase = "TestApp.All";
|
||||
}
|
||||
else if (testCase.empty()) {
|
||||
testCase = "TestApp.PrintAll";
|
||||
}
|
||||
mConfig["TestCase"] = testCase;
|
||||
mConfig["RunMode"] = "Internal";
|
||||
mConfig["ScriptFileName"] = "FreeCADTest";
|
||||
@@ -2457,6 +2468,8 @@ void Application::initConfig(int argc, char ** argv)
|
||||
Branding brand;
|
||||
QString binDir = QString::fromUtf8((mConfig["AppHomePath"] + "bin").c_str());
|
||||
QFileInfo fi(binDir, QString::fromLatin1("branding.xml"));
|
||||
if (!fi.exists())
|
||||
fi = QFileInfo(binDir, QString::fromLatin1("branding_toponaming.xml"));
|
||||
if (fi.exists() && brand.readFile(fi.absoluteFilePath())) {
|
||||
Branding::XmlConfig cfg = brand.getUserDefines();
|
||||
for (Branding::XmlConfig::iterator it = cfg.begin(); it != cfg.end(); ++it) {
|
||||
|
||||
+16
-16
@@ -243,14 +243,14 @@ PyObject* Application::sOpenDocument(PyObject * /*self*/, PyObject *args, PyObje
|
||||
char* Name;
|
||||
PyObject *hidden = Py_False;
|
||||
static char *kwlist[] = {"name","hidden",nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwd, "et|O", kwlist,
|
||||
"utf-8", &Name, &hidden))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwd, "et|O!", kwlist,
|
||||
"utf-8", &Name, &PyBool_Type, &hidden))
|
||||
return nullptr;
|
||||
std::string EncodedName = std::string(Name);
|
||||
PyMem_Free(Name);
|
||||
try {
|
||||
// return new document
|
||||
return (GetApplication().openDocument(EncodedName.c_str(),!PyObject_IsTrue(hidden))->getPyObject());
|
||||
return (GetApplication().openDocument(EncodedName.c_str(),PyObject_IsTrue(hidden) ? false : true)->getPyObject());
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_IOError, e.what());
|
||||
@@ -270,14 +270,14 @@ PyObject* Application::sNewDocument(PyObject * /*self*/, PyObject *args, PyObjec
|
||||
PyObject *hidden = Py_False;
|
||||
PyObject *temp = Py_False;
|
||||
static char *kwlist[] = {"name","label","hidden","temp",nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwd, "|etetOO", kwlist,
|
||||
"utf-8", &docName, "utf-8", &usrName, &hidden, &temp))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwd, "|etetO!O!", kwlist,
|
||||
"utf-8", &docName, "utf-8", &usrName, &PyBool_Type, &hidden, &PyBool_Type, &temp))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
App::Document* doc = GetApplication().newDocument(docName, usrName,
|
||||
!PyObject_IsTrue(hidden),
|
||||
PyObject_IsTrue(temp));
|
||||
PyObject_IsTrue(hidden) ? false : true,
|
||||
PyObject_IsTrue(temp) ? true : false);
|
||||
PyMem_Free(docName);
|
||||
PyMem_Free(usrName);
|
||||
return doc->getPyObject();
|
||||
@@ -317,7 +317,7 @@ PyObject* Application::sCloseDocument(PyObject * /*self*/, PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (GetApplication().closeDocument(pstr) == false) {
|
||||
if (!GetApplication().closeDocument(pstr)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -333,7 +333,7 @@ PyObject* Application::sSaveDocument(PyObject * /*self*/, PyObject *args)
|
||||
|
||||
Document* doc = GetApplication().getDocument(pDoc);
|
||||
if ( doc ) {
|
||||
if ( doc->save() == false ) {
|
||||
if (!doc->save()) {
|
||||
PyErr_Format(Base::PyExc_FC_GeneralError, "Cannot save document '%s'", pDoc);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -701,7 +701,7 @@ PyObject* Application::sGetUserMacroPath(PyObject * /*self*/, PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
std::string macroDir = Application::getUserMacroDir();
|
||||
if (PyObject_IsTrue(actual)) {
|
||||
if (PyObject_IsTrue(actual) ? true : false) {
|
||||
macroDir = App::GetApplication().
|
||||
GetParameterGroupByPath("User parameter:BaseApp/Preferences/Macro")
|
||||
->GetASCII("MacroPath",macroDir.c_str());
|
||||
@@ -732,7 +732,7 @@ PyObject* Application::sGetHomePath(PyObject * /*self*/, PyObject *args)
|
||||
PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *sort = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O",&sort))
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
PyObject *pDict = PyDict_New();
|
||||
@@ -740,7 +740,7 @@ PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args)
|
||||
Base::PyObjectBase* pValue;
|
||||
|
||||
std::vector<Document*> docs = GetApplication().getDocuments();;
|
||||
if(PyObject_IsTrue(sort))
|
||||
if(PyObject_IsTrue(sort) ? true : false)
|
||||
docs = Document::getDependentDocuments(docs,true);
|
||||
|
||||
for (auto doc : docs) {
|
||||
@@ -942,11 +942,11 @@ PyObject *Application::sSetActiveTransaction(PyObject * /*self*/, PyObject *args
|
||||
{
|
||||
char *name;
|
||||
PyObject *persist = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &name,&persist))
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &name, &PyBool_Type, &persist))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
Py::Int ret(GetApplication().setActiveTransaction(name,PyObject_IsTrue(persist)));
|
||||
Py::Int ret(GetApplication().setActiveTransaction(name,PyObject_IsTrue(persist) ? true : false));
|
||||
return Py::new_reference_to(ret);
|
||||
}PY_CATCH;
|
||||
}
|
||||
@@ -972,11 +972,11 @@ PyObject *Application::sCloseActiveTransaction(PyObject * /*self*/, PyObject *ar
|
||||
{
|
||||
PyObject *abort = Py_False;
|
||||
int id = 0;
|
||||
if (!PyArg_ParseTuple(args, "|Oi", &abort,&id))
|
||||
if (!PyArg_ParseTuple(args, "|O!i", &PyBool_Type, &abort,&id))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
GetApplication().closeActiveTransaction(PyObject_IsTrue(abort),id);
|
||||
GetApplication().closeActiveTransaction(PyObject_IsTrue(abort) ? true : false, id);
|
||||
Py_Return;
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ Branding::Branding()
|
||||
filter.push_back("SplashAlignment");
|
||||
filter.push_back("SplashTextColor");
|
||||
filter.push_back("SplashInfoColor");
|
||||
filter.push_back("SplashInfoVersion");
|
||||
|
||||
filter.push_back("StartWorkbench");
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@ else()
|
||||
)
|
||||
endif()
|
||||
|
||||
generate_from_xml(StringIDPy)
|
||||
generate_from_xml(StringHasherPy)
|
||||
generate_from_xml(DocumentPy)
|
||||
generate_from_xml(DocumentObjectPy)
|
||||
generate_from_xml(ExtensionPy)
|
||||
@@ -109,6 +111,8 @@ generate_from_py(FreeCADInit InitScript.h)
|
||||
generate_from_py(FreeCADTest TestScript.h)
|
||||
|
||||
SET(FreeCADApp_XML_SRCS
|
||||
StringIDPy.xml
|
||||
StringHasherPy.xml
|
||||
ExtensionPy.xml
|
||||
ExtensionContainerPy.xml
|
||||
DocumentObjectExtensionPy.xml
|
||||
@@ -131,7 +135,11 @@ SOURCE_GROUP("XML" FILES ${FreeCADApp_XML_SRCS})
|
||||
# The document stuff
|
||||
SET(Document_CPP_SRCS
|
||||
Annotation.cpp
|
||||
StringHasher.cpp
|
||||
StringHasherPyImp.cpp
|
||||
StringIDPyImp.cpp
|
||||
Document.cpp
|
||||
DocumentParams.cpp
|
||||
DocumentObject.cpp
|
||||
Extension.cpp
|
||||
ExtensionPyImp.cpp
|
||||
@@ -178,7 +186,9 @@ SET(Document_CPP_SRCS
|
||||
|
||||
SET(Document_HPP_SRCS
|
||||
Annotation.h
|
||||
StringHasher.h
|
||||
Document.h
|
||||
DocumentParams.h
|
||||
DocumentObject.h
|
||||
Extension.h
|
||||
ExtensionContainer.h
|
||||
@@ -263,6 +273,7 @@ SET(FreeCADApp_CPP_SRCS
|
||||
AutoTransaction.cpp
|
||||
Branding.cpp
|
||||
ColorModel.cpp
|
||||
MappedElement.cpp
|
||||
ComplexGeoData.cpp
|
||||
ComplexGeoDataPyImp.cpp
|
||||
Enumeration.cpp
|
||||
@@ -279,6 +290,7 @@ SET(FreeCADApp_HPP_SRCS
|
||||
AutoTransaction.h
|
||||
Branding.h
|
||||
ColorModel.h
|
||||
MappedElement.h
|
||||
ComplexGeoData.h
|
||||
Enumeration.h
|
||||
Material.h
|
||||
|
||||
+2104
-16
File diff suppressed because it is too large
Load Diff
+269
-2
@@ -24,9 +24,17 @@
|
||||
#ifndef _AppComplexGeoData_h_
|
||||
#define _AppComplexGeoData_h_
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <Base/Handle.h>
|
||||
#include <Base/Matrix.h>
|
||||
#include <Base/Persistence.h>
|
||||
#include "StringHasher.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
# include <cstdint>
|
||||
@@ -44,6 +52,16 @@ typedef BoundBox3<double> BoundBox3d;
|
||||
namespace Data
|
||||
{
|
||||
|
||||
class ElementMap;
|
||||
typedef std::shared_ptr<ElementMap> ElementMapPtr;
|
||||
|
||||
typedef QVector<App::StringIDRef> ElementIDRefs;
|
||||
|
||||
class IndexedName;
|
||||
class MappedName;
|
||||
struct MappedElement;
|
||||
struct MappedChildElements;
|
||||
|
||||
/** Segments
|
||||
* Subelement type of the ComplexGeoData type
|
||||
* It is used to split an object in further sub-parts.
|
||||
@@ -83,7 +101,7 @@ public:
|
||||
* List of different subelement types
|
||||
* its NOT a list of the subelements itself
|
||||
*/
|
||||
virtual std::vector<const char*> getElementTypes() const=0;
|
||||
virtual const std::vector<const char*>& getElementTypes() const=0;
|
||||
virtual unsigned long countSubElements(const char* Type) const=0;
|
||||
/// get the subelement by type and number
|
||||
virtual Segment* getSubElement(const char* Type, unsigned long) const=0;
|
||||
@@ -165,8 +183,12 @@ public:
|
||||
//@{
|
||||
/// Special prefix to mark the beginning of a mapped sub-element name
|
||||
static const std::string &elementMapPrefix();
|
||||
/// Special postfix to mark the following tag
|
||||
/// Special postfix to mark the following tag encoded as hex number
|
||||
static const std::string &tagPostfix();
|
||||
/// Special postfix to mark the following tag encoded as decimal number
|
||||
static const std::string &decTagPostfix();
|
||||
/// Special postfix to mark the name includes encoding from an external object
|
||||
static const std::string &externalTagPostfix();
|
||||
/// Special postfix to mark the index of an array element
|
||||
static const std::string &indexPostfix();
|
||||
/// Special prefix to mark a missing element
|
||||
@@ -191,12 +213,246 @@ public:
|
||||
/// Find the start of an element name in a subname
|
||||
static const char *findElementName(const char *subname);
|
||||
|
||||
/// Check if the given subname contains element name
|
||||
static bool hasElementName(const char *subname) {
|
||||
subname = findElementName(subname);
|
||||
return subname && *subname;
|
||||
}
|
||||
|
||||
/// Return the element name portion of the subname without mapping prefix
|
||||
static inline const char *hasMappedElementName(const char *subname) {
|
||||
return isMappedElement(findElementName(subname));
|
||||
}
|
||||
|
||||
/** Get element indexed name
|
||||
*
|
||||
* @param name: the input name
|
||||
* @param sid: optional output of and App::StringID involved forming this mapped name
|
||||
*
|
||||
* @return Returns an indexed name.
|
||||
*/
|
||||
IndexedName getIndexedName(const MappedName & name,
|
||||
ElementIDRefs *sid = nullptr) const;
|
||||
|
||||
/** Get element mapped name
|
||||
*
|
||||
* @param name: the input name
|
||||
* @param allowUnmapped: If the queried element is not mapped, then return
|
||||
* an empty name if \c allowUnmapped is false, or
|
||||
* else, return the indexed name.
|
||||
* @param sid: optional output of and App::StringID involved forming this mapped name
|
||||
* @return Returns the mapped name.
|
||||
*/
|
||||
MappedName getMappedName(const IndexedName & element,
|
||||
bool allowUnmapped = false,
|
||||
ElementIDRefs *sid = nullptr) const;
|
||||
|
||||
/** Return a pair of indexed name and mapped name
|
||||
*
|
||||
* @param name: the input name.
|
||||
* @param sid: optional output of and App::StringID involved forming this
|
||||
* mapped name
|
||||
* @param copy: if true, copy the name string, or else use it as constant
|
||||
* string, and caller must make sure the memory is not freed.
|
||||
*
|
||||
* @return Returns the MappedElement which contains both the indexed and
|
||||
* mapped name.
|
||||
*
|
||||
* This function guesses whether the input name is an indexed name or
|
||||
* mapped, and perform a lookup and return the names found. If the input
|
||||
* name contains only alphabets and underscore followed by optional digits,
|
||||
* it will be treated as indexed name. Or else, it will be treated as
|
||||
* mapped name.
|
||||
*/
|
||||
MappedElement getElementName(const char * name,
|
||||
ElementIDRefs *sid = nullptr,
|
||||
bool copy = false) const;
|
||||
|
||||
/** Get mapped element with a given prefix */
|
||||
std::vector<MappedElement> getElementNamesWithPrefix(const char *prefix) const;
|
||||
|
||||
/** Get mapped element names
|
||||
*
|
||||
* @param element: original element name with \c Type + \c Index
|
||||
* @param needUnmapped: if true, return the original element name if no
|
||||
* mapping is found
|
||||
*
|
||||
* @return a list of mapped names of the give element along with their
|
||||
* associated string ID references
|
||||
*/
|
||||
std::vector<std::pair<MappedName, ElementIDRefs> >
|
||||
getElementMappedNames(const IndexedName & element, bool needUnmapped=false) const;
|
||||
|
||||
/** Add a sub-element name mapping.
|
||||
*
|
||||
* @param element: the original \c Type + \c Index element name
|
||||
* @param name: the mapped sub-element name. May or may not start with
|
||||
* elementMapPrefix().
|
||||
* @param sid: in case you use a hasher to hash the element name, pass in
|
||||
* the string id reference using this parameter. You can have more than one
|
||||
* string id associated with the same name.
|
||||
* @param overwrite: if true, it will overwrite existing names
|
||||
*
|
||||
* @return Returns the stored mapped element name.
|
||||
*
|
||||
* An element can have multiple mapped names. However, a name can only be
|
||||
* mapped to one element
|
||||
*/
|
||||
MappedName setElementName(const IndexedName & element,
|
||||
const MappedName & name,
|
||||
const ElementIDRefs * sid = nullptr,
|
||||
bool overwrite = false);
|
||||
|
||||
void setMappedChildElements(const std::vector<MappedChildElements> & children);
|
||||
std::vector<MappedChildElements> getMappedChildElements() const;
|
||||
|
||||
/** Convenience method to hash the main element name
|
||||
*
|
||||
* @param name: main element name
|
||||
* @param sid: store any output string ID references
|
||||
* @return the hashed element name;
|
||||
*/
|
||||
MappedName hashElementName(const MappedName & name, ElementIDRefs &sid) const;
|
||||
|
||||
/// Hash the child element map postfixes to shorten element name from hierarchical maps
|
||||
void hashChildMaps();
|
||||
|
||||
/// Check if there is child element map
|
||||
bool hasChildElementMap() const;
|
||||
|
||||
/// Reverse hashElementName()
|
||||
MappedName dehashElementName(const MappedName & name) const;
|
||||
|
||||
/// Append the Tag (if and only if it is non zero) into the element map
|
||||
virtual void reTagElementMap(long tag, App::StringHasherRef hasher, const char *postfix=0) {
|
||||
(void)tag;
|
||||
(void)hasher;
|
||||
(void)postfix;
|
||||
}
|
||||
|
||||
long getElementHistory(const char *name,
|
||||
MappedName *original=0, std::vector<MappedName> *history=0) const;
|
||||
|
||||
long getElementHistory(const MappedName & name,
|
||||
MappedName *original=0, std::vector<MappedName> *history=0) const;
|
||||
|
||||
void encodeElementName(char element_type, MappedName & name, std::ostringstream &ss,
|
||||
ElementIDRefs *sids, const char* postfix=0, long tag=0, bool forceTag=false) const;
|
||||
|
||||
char elementType(const Data::MappedName &) const;
|
||||
char elementType(const Data::IndexedName &) const;
|
||||
char elementType(const char *name) const;
|
||||
|
||||
/** Reset/swap the element map
|
||||
*
|
||||
* @param elementMap: optional new element map
|
||||
*
|
||||
* @return Returns the existing element map.
|
||||
*/
|
||||
virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap=ElementMapPtr()) {
|
||||
_ElementMap.swap(elementMap);
|
||||
return elementMap;
|
||||
}
|
||||
|
||||
/// Get the entire element map
|
||||
std::vector<MappedElement> getElementMap() const;
|
||||
|
||||
/// Set the entire element map
|
||||
void setElementMap(const std::vector<MappedElement> &elements);
|
||||
|
||||
/// Get the current element map size
|
||||
size_t getElementMapSize(bool flush=true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
/// Return the current element map version
|
||||
virtual std::string getElementMapVersion() const;
|
||||
|
||||
/// Return true to signal element map version change
|
||||
virtual bool checkElementMapVersion(const char * ver) const;
|
||||
|
||||
/// Check if the given subname only contains an element name
|
||||
static bool isElementName(const char *subname) {
|
||||
return subname && *subname && findElementName(subname)==subname;
|
||||
}
|
||||
|
||||
/** Extract tag and other information from a encoded element name
|
||||
*
|
||||
* @param name: encoded element name
|
||||
* @param tag: optional pointer to receive the extracted tag
|
||||
* @param len: optional pointer to receive the length field after the tag field.
|
||||
* This gives the length of the previous hashsed element name starting
|
||||
* from the beginning of the give element name.
|
||||
* @param postfix: optional pointer to receive the postfix starting at the found tag field.
|
||||
* @param type: optional pointer to receive the element type character
|
||||
* @param negative: return negative tag as it is. If disabled, then always return positive tag.
|
||||
* Negative tag is sometimes used for element disambiguation.
|
||||
* @param recursive: recursively find the last non-zero tag
|
||||
*
|
||||
* @return Return the end position of the tag field, or return -1 if not found.
|
||||
*/
|
||||
static int findTagInElementName(const MappedName & name,
|
||||
long *tag=0,
|
||||
int *len=0,
|
||||
std::string *postfix=0,
|
||||
char *type=0,
|
||||
bool negative=false,
|
||||
bool recursive=true);
|
||||
|
||||
/** Element trace callback
|
||||
*
|
||||
* The callback has the following call signature
|
||||
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
|
||||
*
|
||||
* @param name: the current element name.
|
||||
* @param offset: the offset skipping the encoded element name for the next iteration.
|
||||
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
|
||||
* of the previous step in the shape history.
|
||||
* @param tag: the tag of the current shape element.
|
||||
*
|
||||
* @sa traceElement()
|
||||
*/
|
||||
typedef std::function<bool(const MappedName &, int, long, long)> TraceCallback;
|
||||
|
||||
/** Iterate through the history of the give element name with a given callback
|
||||
*
|
||||
* @param name: the input element name
|
||||
* @param cb: trace callback with call signature.
|
||||
* @sa TraceCallback
|
||||
*/
|
||||
void traceElement(const MappedName &name, TraceCallback cb) const;
|
||||
|
||||
/** Flush an internal buffering for element mapping */
|
||||
virtual void flushElementMap() const;
|
||||
virtual unsigned long getElementMapReserve() const { return 0; }
|
||||
//@}
|
||||
|
||||
/** @name Save/restore */
|
||||
//@{
|
||||
void Save (Base::Writer &writer) const;
|
||||
void Restore(Base::XMLReader &reader);
|
||||
void SaveDocFile(Base::Writer &writer) const;
|
||||
void RestoreDocFile(Base::Reader &reader);
|
||||
unsigned int getMemSize (void) const;
|
||||
void setPersistenceFileName(const char *name) const;
|
||||
virtual void beforeSave() const;
|
||||
bool isRestoreFailed() const { return _restoreFailed; }
|
||||
void resetRestoreFailure() const { _restoreFailed = true; }
|
||||
//@}
|
||||
|
||||
public:
|
||||
/// String hasher for element name shortening
|
||||
mutable App::StringHasherRef Hasher;
|
||||
|
||||
protected:
|
||||
virtual MappedName renameDuplicateElement(int index,
|
||||
const IndexedName & element,
|
||||
const IndexedName & element2,
|
||||
const MappedName & name,
|
||||
ElementIDRefs &sids);
|
||||
|
||||
void restoreStream(std::istream &s, std::size_t count);
|
||||
|
||||
/// from local to outside
|
||||
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
|
||||
@@ -215,8 +471,19 @@ protected:
|
||||
static_cast<float>(tmp.y),
|
||||
static_cast<float>(tmp.z));
|
||||
}
|
||||
|
||||
public:
|
||||
mutable long Tag;
|
||||
|
||||
protected:
|
||||
ElementMapPtr elementMap(bool flush=true) const;
|
||||
|
||||
protected:
|
||||
mutable std::string _PersistenceName;
|
||||
mutable bool _restoreFailed = false;
|
||||
|
||||
private:
|
||||
ElementMapPtr _ElementMap;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
|
||||
@@ -64,6 +64,37 @@
|
||||
<UserDocu>Apply a transformation to the underlying geometry</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setElementName" Keyword="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setElementName(element,name=None,postfix=None,overwrite=False,sid=None), Set an element name
|
||||
|
||||
element : the original element name, e.g. Edge1, Vertex2
|
||||
name : the new name for the element, None to remove the mapping
|
||||
postfix : postfix of the name that will not be hashed
|
||||
overwrite: if true, it will overwrite exiting name
|
||||
sid : to hash the name any way you want, provide your own string id(s) in this parameter
|
||||
|
||||
An element can have multiple mapped names. However, a name can only be mapped
|
||||
to one element
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementName" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>getElementName(name,direction=0) - Return a mapped element name or reverse</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementIndexedName" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>getElementIndexedName(name) - Return the indexed element name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getElementMappedName" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>getElementMappedName(name) - Return the mapped element name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="BoundBox" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the BoundBox of the object</UserDocu>
|
||||
@@ -88,5 +119,35 @@
|
||||
</Documentation>
|
||||
<Parameter Name="Tag" Type="Int"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Hasher">
|
||||
<Documentation>
|
||||
<UserDocu>Get/Set the string hasher of this object</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Hasher" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="ElementMapSize" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the current element map size</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ElementMapSize" Type="Int" />
|
||||
</Attribute>
|
||||
<Attribute Name="ElementMap">
|
||||
<Documentation>
|
||||
<UserDocu>Get/Set a dict of element mapping</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ElementMap" Type="Dict" />
|
||||
</Attribute>
|
||||
<Attribute Name="ElementReverseMap" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get a dict of element reverse mapping</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ElementReverseMap" Type="Dict" />
|
||||
</Attribute>
|
||||
<Attribute Name="ElementMapVersion" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Element map version</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ElementMapVersion" Type="String" />
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include "ComplexGeoData.h"
|
||||
#include "MappedElement.h"
|
||||
|
||||
// inclusion of the generated files (generated out of ComplexGeoDataPy.xml)
|
||||
#include <App/ComplexGeoDataPy.h>
|
||||
@@ -36,6 +37,8 @@
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/GeometryPyCXX.h>
|
||||
#include <App/StringHasherPy.h>
|
||||
#include <App/StringIDPy.h>
|
||||
|
||||
using namespace Data;
|
||||
using namespace Base;
|
||||
@@ -51,10 +54,9 @@ PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return nullptr;
|
||||
|
||||
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
|
||||
Py::List list;
|
||||
for (auto it : types) {
|
||||
list.append(Py::String(it));
|
||||
for (const auto &type : getComplexGeoDataPtr()->getElementTypes()) {
|
||||
list.append(Py::String(type));
|
||||
}
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
@@ -302,6 +304,183 @@ PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getElementName(PyObject *args)
|
||||
{
|
||||
char* input;
|
||||
int direction = 0;
|
||||
if (!PyArg_ParseTuple(args, "s|i", &input,&direction))
|
||||
return NULL;
|
||||
|
||||
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(input);
|
||||
std::string s;
|
||||
if (direction == 1)
|
||||
return Py::new_reference_to(Py::String(res.name.toString(s)));
|
||||
else if (direction == 0)
|
||||
return Py::new_reference_to(Py::String(res.index.toString(s)));
|
||||
else if (Data::IndexedName(input))
|
||||
return Py::new_reference_to(Py::String(res.name.toString(s)));
|
||||
else
|
||||
return Py::new_reference_to(Py::String(res.index.toString(s)));
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getElementIndexedName(PyObject *args)
|
||||
{
|
||||
char* input;
|
||||
PyObject *returnID = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &input,&returnID))
|
||||
return NULL;
|
||||
|
||||
ElementIDRefs ids;
|
||||
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(
|
||||
input, PyObject_IsTrue(returnID)?&ids:nullptr);
|
||||
std::string s;
|
||||
Py::String name(res.index.toString(s));
|
||||
if (!PyObject_IsTrue(returnID))
|
||||
return Py::new_reference_to(name);
|
||||
|
||||
Py::List list;
|
||||
for (auto &id : ids)
|
||||
list.append(Py::Long(id.value()));
|
||||
return Py::new_reference_to(Py::TupleN(name, list));
|
||||
}
|
||||
|
||||
PyObject* ComplexGeoDataPy::getElementMappedName(PyObject *args)
|
||||
{
|
||||
char* input;
|
||||
PyObject *returnID = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &input,&returnID))
|
||||
return NULL;
|
||||
|
||||
ElementIDRefs ids;
|
||||
Data::MappedElement res = getComplexGeoDataPtr()->getElementName(
|
||||
input, PyObject_IsTrue(returnID)?&ids:nullptr);
|
||||
std::string s;
|
||||
Py::String name(res.name.toString(s));
|
||||
if (!PyObject_IsTrue(returnID))
|
||||
return Py::new_reference_to(name);
|
||||
|
||||
Py::List list;
|
||||
for (auto &id : ids)
|
||||
list.append(Py::Long(id.value()));
|
||||
return Py::new_reference_to(Py::TupleN(name, list));
|
||||
}
|
||||
|
||||
PyObject *ComplexGeoDataPy::setElementName(PyObject *args, PyObject *kwds) {
|
||||
const char *element;
|
||||
const char *name = 0;
|
||||
const char *postfix = 0;
|
||||
int tag = 0;
|
||||
PyObject *pySid = Py_None;
|
||||
PyObject *overwrite = Py_False;
|
||||
|
||||
static char *kwlist[] = {"element", "name", "postfix", "overwrite", "sid", "tag", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|sssOOi", kwlist,
|
||||
&element,&name,&postfix,&overwrite,&pySid,&tag))
|
||||
return NULL;
|
||||
ElementIDRefs sids;
|
||||
if(pySid != Py_None) {
|
||||
if(PyObject_TypeCheck(pySid,&App::StringIDPy::Type))
|
||||
sids.push_back(static_cast<App::StringIDPy*>(pySid)->getStringIDPtr());
|
||||
else if(PySequence_Check(pySid)) {
|
||||
Py::Sequence seq(pySid);
|
||||
for(auto it=seq.begin();it!=seq.end();++it) {
|
||||
auto ptr = (*it).ptr();
|
||||
if(PyObject_TypeCheck(ptr,&App::StringIDPy::Type))
|
||||
sids.push_back(static_cast<App::StringIDPy*>(ptr)->getStringIDPtr());
|
||||
else
|
||||
throw Py::TypeError("expect StringID in sid sequence");
|
||||
}
|
||||
} else
|
||||
throw Py::TypeError("expect sid to contain either StringID or sequence of StringID");
|
||||
}
|
||||
PY_TRY {
|
||||
Data::IndexedName index(element, getComplexGeoDataPtr()->getElementTypes());
|
||||
Data::MappedName mapped = Data::MappedName::fromRawData(name);
|
||||
std::ostringstream ss;
|
||||
getComplexGeoDataPtr()->encodeElementName(getComplexGeoDataPtr()->elementType(index),
|
||||
mapped, ss, &sids, postfix, tag);
|
||||
Data::MappedName res = getComplexGeoDataPtr()->setElementName(
|
||||
index, mapped, &sids, PyObject_IsTrue(overwrite));
|
||||
return Py::new_reference_to(Py::String(res.toString(0)));
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
Py::Object ComplexGeoDataPy::getHasher() const {
|
||||
auto self = getComplexGeoDataPtr();
|
||||
if(!self->Hasher)
|
||||
return Py::None();
|
||||
return Py::Object(self->Hasher->getPyObject(),true);
|
||||
}
|
||||
|
||||
Py::Dict ComplexGeoDataPy::getElementMap() const {
|
||||
Py::Dict ret;
|
||||
std::string s;
|
||||
for(auto &v : getComplexGeoDataPtr()->getElementMap()) {
|
||||
s.clear();
|
||||
ret.setItem(v.name.toString(0), Py::String(v.index.toString(s)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ComplexGeoDataPy::setElementMap(Py::Dict dict) {
|
||||
std::vector<Data::MappedElement> map;
|
||||
const auto & types = getComplexGeoDataPtr()->getElementTypes();
|
||||
for(auto it=dict.begin();it!=dict.end();++it) {
|
||||
const auto &value = *it;
|
||||
if(!value.first.isString() || !value.second.isString())
|
||||
throw Py::TypeError("expect only strings in the dict");
|
||||
map.emplace_back(Data::MappedName(value.first.as_string().c_str()),
|
||||
Data::IndexedName(Py::Object(value.second).as_string().c_str(), types));
|
||||
}
|
||||
getComplexGeoDataPtr()->setElementMap(map);
|
||||
}
|
||||
|
||||
Py::Dict ComplexGeoDataPy::getElementReverseMap() const {
|
||||
Py::Dict ret;
|
||||
std::string s;
|
||||
for(auto &v : getComplexGeoDataPtr()->getElementMap()) {
|
||||
s.clear();
|
||||
auto value = ret[Py::String(v.index.toString(s))];
|
||||
Py::Object item(value);
|
||||
if(item.isNone()) {
|
||||
s.clear();
|
||||
value = Py::String(v.name.toString(s));
|
||||
} else if(item.isList()) {
|
||||
Py::List list(item);
|
||||
s.clear();
|
||||
list.append(Py::String(v.name.toString(s)));
|
||||
} else {
|
||||
Py::List list;
|
||||
list.append(item);
|
||||
s.clear();
|
||||
list.append(Py::String(v.name.toString(s)));
|
||||
value = list;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Py::Int ComplexGeoDataPy::getElementMapSize() const {
|
||||
return Py::Int((long)getComplexGeoDataPtr()->getElementMapSize());
|
||||
}
|
||||
|
||||
void ComplexGeoDataPy::setHasher(Py::Object obj) {
|
||||
auto self = getComplexGeoDataPtr();
|
||||
if(obj.isNone()) {
|
||||
if(self->Hasher) {
|
||||
self->Hasher = App::StringHasherRef();
|
||||
self->resetElementMap();
|
||||
}
|
||||
}else if(PyObject_TypeCheck(obj.ptr(),&App::StringHasherPy::Type)) {
|
||||
App::StringHasherRef ref(static_cast<App::StringHasherPy*>(obj.ptr())->getStringHasherPtr());
|
||||
if(self->Hasher != ref) {
|
||||
self->Hasher = ref;
|
||||
self->resetElementMap();
|
||||
}
|
||||
}else
|
||||
throw Py::TypeError("invalid type");
|
||||
}
|
||||
|
||||
Py::Object ComplexGeoDataPy::getBoundBox() const
|
||||
{
|
||||
return Py::BoundingBox(getComplexGeoDataPtr()->getBoundBox());
|
||||
@@ -334,6 +513,11 @@ void ComplexGeoDataPy::setPlacement(Py::Object arg)
|
||||
}
|
||||
}
|
||||
|
||||
Py::String ComplexGeoDataPy::getElementMapVersion() const
|
||||
{
|
||||
return Py::String(getComplexGeoDataPtr()->getElementMapVersion());
|
||||
}
|
||||
|
||||
Py::Int ComplexGeoDataPy::getTag() const
|
||||
{
|
||||
return Py::Int(getComplexGeoDataPtr()->Tag);
|
||||
|
||||
+214
-37
@@ -65,6 +65,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/graph/graphviz.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/graph/strong_components.hpp>
|
||||
|
||||
#ifdef USE_OLD_DAG
|
||||
@@ -95,6 +96,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
|
||||
#include <Base/Stream.h>
|
||||
|
||||
#include "Document.h"
|
||||
#include "DocumentParams.h"
|
||||
#include "Application.h"
|
||||
#include "AutoTransaction.h"
|
||||
#include "DocumentObserver.h"
|
||||
@@ -106,6 +108,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
|
||||
#include "MergeDocuments.h"
|
||||
#include "Origin.h"
|
||||
#include "OriginGroupExtension.h"
|
||||
#include "StringHasher.h"
|
||||
#include "Transactions.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -116,7 +119,6 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
|
||||
#include <zipios++/zipoutputstream.h>
|
||||
#include <zipios++/meta-iostreams.h>
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("App", true, true, true)
|
||||
|
||||
using Base::Console;
|
||||
@@ -151,8 +153,10 @@ typedef std::vector <size_t> Path;
|
||||
|
||||
namespace App {
|
||||
|
||||
typedef boost::bimap<StringHasherRef,int> HasherMap;
|
||||
|
||||
static bool _IsRestoring;
|
||||
static bool _IsRelabeling;
|
||||
|
||||
// Pimpl class
|
||||
struct DocumentP
|
||||
{
|
||||
@@ -178,6 +182,7 @@ struct DocumentP
|
||||
unsigned int UndoMemSize;
|
||||
unsigned int UndoMaxStackSize;
|
||||
std::string programVersion;
|
||||
mutable HasherMap hashers;
|
||||
#ifdef USE_OLD_DAG
|
||||
DependencyList DepList;
|
||||
std::map<DocumentObject*,Vertex> VertexObjectList;
|
||||
@@ -186,7 +191,15 @@ struct DocumentP
|
||||
std::multimap<const App::DocumentObject*,
|
||||
std::unique_ptr<App::DocumentObjectExecReturn> > _RecomputeLog;
|
||||
|
||||
StringHasherRef Hasher;
|
||||
|
||||
// restored files
|
||||
std::set<std::string> files;
|
||||
|
||||
DocumentP() {
|
||||
#ifdef FC_NO_RANDOM_ID
|
||||
lastObjectId = 10;
|
||||
#else
|
||||
static std::random_device _RD;
|
||||
static std::mt19937 _RGEN(_RD());
|
||||
static std::uniform_int_distribution<> _RDIST(0,5000);
|
||||
@@ -194,6 +207,8 @@ struct DocumentP
|
||||
// copying shape from other document. It is probably better to randomize
|
||||
// on each object ID.
|
||||
lastObjectId = _RDIST(_RGEN);
|
||||
#endif
|
||||
Hasher.reset(new StringHasher);
|
||||
activeObject = nullptr;
|
||||
activeUndoTransaction = nullptr;
|
||||
iTransactionMode = 0;
|
||||
@@ -1466,7 +1481,6 @@ void Document::onChanged(const Property* prop)
|
||||
|
||||
// the Name property is a label for display purposes
|
||||
if (prop == &Label) {
|
||||
Base::FlagToggler<> flag(_IsRelabeling);
|
||||
App::GetApplication().signalRelabelDocument(*this);
|
||||
} else if(prop == &ShowHidden) {
|
||||
App::GetApplication().signalShowHidden(*this);
|
||||
@@ -1501,6 +1515,12 @@ void Document::onChanged(const Property* prop)
|
||||
// recursive call of onChanged()
|
||||
this->Uid.setValue(id);
|
||||
}
|
||||
} else if(prop == &UseHasher) {
|
||||
for(auto obj : d->objectArray) {
|
||||
auto geofeature = dynamic_cast<GeoFeature*>(obj);
|
||||
if(geofeature && geofeature->getPropertyOfGeometry())
|
||||
geofeature->enforceRecompute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,8 +1528,8 @@ void Document::onBeforeChangeProperty(const TransactionalObject *Who, const Prop
|
||||
{
|
||||
if(Who->isDerivedFrom(App::DocumentObject::getClassTypeId()))
|
||||
signalBeforeChangeObject(*static_cast<const App::DocumentObject*>(Who), *What);
|
||||
if(!d->rollback && !_IsRelabeling) {
|
||||
_checkTransaction(nullptr,What,__LINE__);
|
||||
if(!d->rollback) {
|
||||
_checkTransaction(nullptr, What, __LINE__);
|
||||
if (d->activeUndoTransaction)
|
||||
d->activeUndoTransaction->addObjectChange(Who,What);
|
||||
}
|
||||
@@ -1544,10 +1564,8 @@ Document::Document(const char *name)
|
||||
Console().Log("+App::Document: %p\n",this);
|
||||
#endif
|
||||
std::string CreationDateString = Base::TimeInfo::currentDateTimeString();
|
||||
std::string Author = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefAuthor","");
|
||||
std::string AuthorComp = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefCompany","");
|
||||
std::string Author = DocumentParams::getprefAuthor();
|
||||
std::string AuthorComp = DocumentParams::getprefCompany();
|
||||
ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document");
|
||||
ADD_PROPERTY_TYPE(FileName,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),"The path to the file where the document is saved to");
|
||||
ADD_PROPERTY_TYPE(CreatedBy,(Author.c_str()),0,Prop_None,"The creator of the document");
|
||||
@@ -1568,8 +1586,7 @@ Document::Document(const char *name)
|
||||
ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract");
|
||||
|
||||
// license stuff
|
||||
int licenseId = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/Document")->GetInt("prefLicenseType",0);
|
||||
int licenseId = DocumentParams::getprefLicenseType();
|
||||
std::string license;
|
||||
std::string licenseUrl;
|
||||
switch (licenseId) {
|
||||
@@ -1614,13 +1631,17 @@ Document::Document(const char *name)
|
||||
break;
|
||||
}
|
||||
|
||||
licenseUrl = App::GetApplication().GetParameterGroupByPath
|
||||
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefLicenseUrl", licenseUrl.c_str());
|
||||
if(DocumentParams::getprefLicenseUrl().empty())
|
||||
licenseUrl = DocumentParams::getprefLicenseUrl();
|
||||
|
||||
ADD_PROPERTY_TYPE(License,(license.c_str()),0,Prop_None,"License string of the Item");
|
||||
ADD_PROPERTY_TYPE(LicenseURL,(licenseUrl.c_str()),0,Prop_None,"URL to the license text/contract");
|
||||
ADD_PROPERTY_TYPE(ShowHidden,(false), 0,PropertyType(Prop_None),
|
||||
"Whether to show hidden object items in the tree view");
|
||||
ADD_PROPERTY_TYPE(UseHasher,(true), 0,PropertyType(Prop_Hidden),
|
||||
"Whether to use hasher on topological naming");
|
||||
if(!DocumentParams::getUseHasher())
|
||||
UseHasher.setValue(false);
|
||||
|
||||
// this creates and sets 'TransientDir' in onChanged()
|
||||
ADD_PROPERTY_TYPE(TransientDir,(""),0,PropertyType(Prop_Transient|Prop_ReadOnly),
|
||||
@@ -1690,11 +1711,31 @@ std::string Document::getTransientDirectoryName(const std::string& uuid, const s
|
||||
|
||||
void Document::Save (Base::Writer &writer) const
|
||||
{
|
||||
d->hashers.clear();
|
||||
addStringHasher(d->Hasher);
|
||||
|
||||
writer.Stream() << "<Document SchemaVersion=\"4\" ProgramVersion=\""
|
||||
<< App::Application::Config()["BuildVersionMajor"] << "."
|
||||
<< App::Application::Config()["BuildVersionMinor"] << "R"
|
||||
<< App::Application::Config()["BuildRevision"]
|
||||
<< "\" FileVersion=\"" << writer.getFileVersion() << "\">" << endl;
|
||||
<< "\" FileVersion=\"" << writer.getFileVersion()
|
||||
<< "\" Uid=\"" << Uid.getValueStr()
|
||||
<< "\" StringHasher=\"1\">\n";
|
||||
|
||||
writer.incInd();
|
||||
|
||||
if (writer.isForceXML())
|
||||
d->Hasher->setPersistenceFileName(0);
|
||||
else
|
||||
d->Hasher->setPersistenceFileName("StringHasher.Table");
|
||||
|
||||
for (auto o : d->objectArray)
|
||||
o->beforeSave();
|
||||
beforeSave();
|
||||
|
||||
d->Hasher->Save(writer);
|
||||
|
||||
writer.decInd();
|
||||
|
||||
PropertyContainer::Save(writer);
|
||||
|
||||
@@ -1706,7 +1747,12 @@ void Document::Save (Base::Writer &writer) const
|
||||
void Document::Restore(Base::XMLReader &reader)
|
||||
{
|
||||
int i,Cnt;
|
||||
d->hashers.clear();
|
||||
d->touchedObjs.clear();
|
||||
addStringHasher(d->Hasher);
|
||||
|
||||
Base::ReaderContext rctx(getName());
|
||||
|
||||
setStatus(Document::PartialDoc,false);
|
||||
|
||||
reader.readElement("Document");
|
||||
@@ -1723,6 +1769,11 @@ void Document::Restore(Base::XMLReader &reader)
|
||||
reader.FileVersion = 0;
|
||||
}
|
||||
|
||||
if (reader.hasAttribute("StringHasher")) {
|
||||
Base::ReaderContext rctx("StringHasher");
|
||||
d->Hasher->Restore(reader);
|
||||
} else
|
||||
d->Hasher->clear();
|
||||
// When this document was created the FileName and Label properties
|
||||
// were set to the absolute path or file name, respectively. To save
|
||||
// the document to the file it was loaded from or to show the file name
|
||||
@@ -1765,6 +1816,7 @@ void Document::Restore(Base::XMLReader &reader)
|
||||
for (i=0 ;i<Cnt ;i++) {
|
||||
reader.readElement("Feature");
|
||||
string name = reader.getAttribute("name");
|
||||
Base::ReaderContext rctx(name);
|
||||
DocumentObject* pObj = getObject(name.c_str());
|
||||
if (pObj) { // check if this feature has been registered
|
||||
pObj->setStatus(ObjectStatus::Restore, true);
|
||||
@@ -1787,6 +1839,36 @@ void Document::Restore(Base::XMLReader &reader)
|
||||
reader.readEndElement("Document");
|
||||
}
|
||||
|
||||
std::pair<bool,int> Document::addStringHasher(const StringHasherRef & hasher) const {
|
||||
if (!hasher)
|
||||
return std::make_pair(false, 0);
|
||||
auto ret = d->hashers.left.insert(HasherMap::left_map::value_type(hasher,(int)d->hashers.size()));
|
||||
if (ret.second)
|
||||
hasher->clearMarks();
|
||||
return std::make_pair(ret.second,ret.first->second);
|
||||
}
|
||||
|
||||
StringHasherRef Document::getHasher() const {
|
||||
return d->Hasher;
|
||||
}
|
||||
|
||||
StringHasherRef Document::getStringHasher(int idx) const {
|
||||
StringHasherRef hasher;
|
||||
if(idx<0) {
|
||||
if(UseHasher.getValue())
|
||||
return d->Hasher;
|
||||
return hasher;
|
||||
}
|
||||
|
||||
auto it = d->hashers.right.find(idx);
|
||||
if(it == d->hashers.right.end()) {
|
||||
hasher = new StringHasher;
|
||||
d->hashers.right.insert(HasherMap::right_map::value_type(idx,hasher));
|
||||
}else
|
||||
hasher = it->second;
|
||||
return hasher;
|
||||
}
|
||||
|
||||
struct DocExportStatus {
|
||||
Document::ExportStatus status;
|
||||
std::set<const App::DocumentObject*> objs;
|
||||
@@ -1823,6 +1905,7 @@ Document::ExportStatus Document::isExporting(const App::DocumentObject *obj) con
|
||||
void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::ostream& out) {
|
||||
|
||||
DocumentExporting exporting(obj);
|
||||
d->hashers.clear();
|
||||
|
||||
if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
for(auto o : obj) {
|
||||
@@ -1859,6 +1942,7 @@ void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::
|
||||
|
||||
// write additional files
|
||||
writer.writeFiles();
|
||||
d->hashers.clear();
|
||||
}
|
||||
|
||||
#define FC_ATTR_DEPENDENCIES "Dependencies"
|
||||
@@ -2162,14 +2246,16 @@ Document::readObjects(Base::XMLReader& reader)
|
||||
|
||||
void Document::addRecomputeObject(DocumentObject *obj) {
|
||||
if(testStatus(Status::Restoring) && obj) {
|
||||
setStatus(Status::RecomputeOnRestore, true);
|
||||
d->touchedObjs.insert(obj);
|
||||
obj->touch();
|
||||
obj->enforceRecompute();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<App::DocumentObject*>
|
||||
Document::importObjects(Base::XMLReader& reader)
|
||||
{
|
||||
d->hashers.clear();
|
||||
Base::FlagToggler<> flag(_IsRestoring,false);
|
||||
Base::ObjectStatusLocker<Status, Document> restoreBit(Status::Restoring, this);
|
||||
Base::ObjectStatusLocker<Status, Document> restoreBit2(Status::Importing, this);
|
||||
@@ -2188,6 +2274,7 @@ Document::importObjects(Base::XMLReader& reader)
|
||||
reader.FileVersion = 0;
|
||||
}
|
||||
|
||||
Base::ReaderContext rctx(getName());
|
||||
std::vector<App::DocumentObject*> objs = readObjects(reader);
|
||||
for(auto o : objs) {
|
||||
if(o && o->getNameInDocument()) {
|
||||
@@ -2220,7 +2307,7 @@ Document::importObjects(Base::XMLReader& reader)
|
||||
if(o && o->getNameInDocument())
|
||||
o->setStatus(App::ObjImporting,false);
|
||||
}
|
||||
|
||||
d->hashers.clear();
|
||||
return objs;
|
||||
}
|
||||
|
||||
@@ -2233,6 +2320,8 @@ unsigned int Document::getMemSize (void) const
|
||||
for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it)
|
||||
size += (*it)->getMemSize();
|
||||
|
||||
size += d->Hasher->getMemSize();
|
||||
|
||||
// size of the document properties...
|
||||
size += PropertyContainer::getMemSize();
|
||||
|
||||
@@ -2402,7 +2491,7 @@ private:
|
||||
fn = str.str();
|
||||
}
|
||||
|
||||
if (fi.renameFile(fn.c_str()) == false)
|
||||
if (!fi.renameFile(fn.c_str()))
|
||||
Base::Console().Warning("Cannot rename project file to backup file\n");
|
||||
}
|
||||
else {
|
||||
@@ -2411,7 +2500,7 @@ private:
|
||||
}
|
||||
|
||||
Base::FileInfo tmp(sourcename);
|
||||
if (tmp.renameFile(targetname.c_str()) == false) {
|
||||
if (!tmp.renameFile(targetname.c_str())) {
|
||||
throw Base::FileException(
|
||||
"Cannot rename tmp save file to project file", targetname);
|
||||
}
|
||||
@@ -2511,7 +2600,7 @@ private:
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (renameFileNoErase(fi, fn+".FCBak") == false) {
|
||||
if (!renameFileNoErase(fi, fn+".FCBak")) {
|
||||
fn = fn + "-";
|
||||
}
|
||||
else {
|
||||
@@ -2555,7 +2644,7 @@ private:
|
||||
}
|
||||
|
||||
Base::FileInfo tmp(sourcename);
|
||||
if (tmp.renameFile(targetname.c_str()) == false) {
|
||||
if (!tmp.renameFile(targetname.c_str())) {
|
||||
throw Base::FileException(
|
||||
"Save interrupted: Cannot rename temporary file to project file", tmp);
|
||||
}
|
||||
@@ -2699,6 +2788,37 @@ bool Document::saveToFile(const char* filename) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void Document::save(Base::Writer &writer, bool archive) const {
|
||||
(void)archive;
|
||||
|
||||
writer.putNextEntry("Document.xml");
|
||||
|
||||
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
|
||||
if (hGrp->GetBool("SaveBinaryBrep", false)) {
|
||||
writer.setMode("BinaryBrep");
|
||||
writer.setPreferBinary(true);
|
||||
} else if(writer.getFileVersion() > 1)
|
||||
writer.setPreferBinary(false);
|
||||
|
||||
writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>\n"
|
||||
<< "<!--\n"
|
||||
<< " FreeCAD Document, see http://www.freecadweb.org for more information...\n"
|
||||
<< "-->\n";
|
||||
Document::Save(writer);
|
||||
|
||||
// Special handling for Gui document.
|
||||
signalSaveDocument(writer);
|
||||
|
||||
// write additional files
|
||||
writer.writeFiles();
|
||||
|
||||
if (writer.hasErrors()) {
|
||||
throw Base::FileException("Failed to write all data to file");
|
||||
}
|
||||
|
||||
GetApplication().signalSaveDocument(*this);
|
||||
}
|
||||
|
||||
bool Document::isAnyRestoring() {
|
||||
return _IsRestoring;
|
||||
}
|
||||
@@ -2707,8 +2827,48 @@ bool Document::isAnyRestoring() {
|
||||
void Document::restore (const char *filename,
|
||||
bool delaySignal, const std::vector<std::string> &objNames)
|
||||
{
|
||||
if(!filename)
|
||||
filename = FileName.getValue();
|
||||
Base::FileInfo fi(filename);
|
||||
if(fi.isDir()) {
|
||||
fi.setFile(std::string(filename)+'/'+"Document.xml");
|
||||
if(!fi.exists())
|
||||
throw Base::FileException("Project file not found",fi.filePath());
|
||||
}
|
||||
|
||||
std::unique_ptr<Base::Reader> _reader;
|
||||
std::unique_ptr<Base::XMLReader> _xmlReader;
|
||||
std::unique_ptr<zipios::ZipInputStream> zipstream;
|
||||
std::string dirname;
|
||||
|
||||
if(fi.fileNamePure() == "Document" && fi.hasExtension("xml")) {
|
||||
Base::FileInfo di(fi.dirPath());
|
||||
_reader.reset(new Base::FileReader(fi,di.fileName()+"/Document.xml"));
|
||||
_xmlReader.reset(new Base::XMLReader(*_reader));
|
||||
} else {
|
||||
// file.open(fi, std::ios::in | std::ios::binary);
|
||||
// std::streambuf* buf = file.rdbuf();
|
||||
// std::streamoff size = buf->pubseekoff(0, std::ios::end, std::ios::in);
|
||||
// buf->pubseekoff(0, std::ios::beg, std::ios::in);
|
||||
// if (size < 22) // an empty zip archive has 22 bytes
|
||||
// throw Base::FileException("Invalid project file",filename);
|
||||
zipstream.reset(new zipios::ZipInputStream(filename));
|
||||
_reader.reset(new Base::ZipReader(*zipstream,filename));
|
||||
_xmlReader.reset(new Base::XMLReader(*_reader));
|
||||
}
|
||||
|
||||
restore(*_xmlReader, delaySignal, objNames);
|
||||
}
|
||||
|
||||
void Document::restore(Base::XMLReader &reader,
|
||||
bool delaySignal, const std::vector<std::string> &objNames)
|
||||
{
|
||||
if (!reader.isValid())
|
||||
throw Base::FileException("Error reading project file", FileName.getValue());
|
||||
|
||||
clearUndos();
|
||||
d->activeObject = nullptr;
|
||||
d->files.clear();
|
||||
|
||||
bool signal = false;
|
||||
Document *activeDoc = GetApplication().getActiveDocument();
|
||||
@@ -2734,21 +2894,6 @@ void Document::restore (const char *filename,
|
||||
GetApplication().setActiveDocument(this);
|
||||
}
|
||||
|
||||
if(!filename)
|
||||
filename = FileName.getValue();
|
||||
Base::FileInfo fi(filename);
|
||||
Base::ifstream file(fi, std::ios::in | std::ios::binary);
|
||||
std::streambuf* buf = file.rdbuf();
|
||||
std::streamoff size = buf->pubseekoff(0, std::ios::end, std::ios::in);
|
||||
buf->pubseekoff(0, std::ios::beg, std::ios::in);
|
||||
if (size < 22) // an empty zip archive has 22 bytes
|
||||
throw Base::FileException("Invalid project file",filename);
|
||||
|
||||
zipios::ZipInputStream zipstream(file);
|
||||
Base::XMLReader reader(filename, zipstream);
|
||||
|
||||
if (!reader.isValid())
|
||||
throw Base::FileException("Error reading compression file",filename);
|
||||
|
||||
GetApplication().signalStartRestoreDocument(*this);
|
||||
setStatus(Document::Restoring, true);
|
||||
@@ -2758,6 +2903,8 @@ void Document::restore (const char *filename,
|
||||
d->partialLoadObjects.emplace(name,true);
|
||||
try {
|
||||
Document::Restore(reader);
|
||||
} catch (const Base::XMLParseException &) {
|
||||
throw;
|
||||
} catch (const Base::Exception& e) {
|
||||
Base::Console().Error("Invalid Document.xml: %s\n", e.what());
|
||||
setStatus(Document::RestoreError, true);
|
||||
@@ -2771,7 +2918,13 @@ void Document::restore (const char *filename,
|
||||
// Note: This file doesn't need to be available if the document has been created
|
||||
// without GUI. But if available then follow after all data files of the App document.
|
||||
signalRestoreDocument(reader);
|
||||
reader.readFiles(zipstream);
|
||||
|
||||
reader.readFiles();
|
||||
|
||||
for(auto &f : reader.getFilenames()) {
|
||||
FC_TRACE("document " << getName() << " file: " << f);
|
||||
d->files.insert(f);
|
||||
}
|
||||
|
||||
if (reader.testStatus(Base::XMLReader::ReaderStatus::PartialRestore)) {
|
||||
setStatus(Document::PartialRestore, true);
|
||||
@@ -2919,10 +3072,19 @@ const char* Document::getName() const
|
||||
return myName.c_str();
|
||||
}
|
||||
|
||||
std::string Document::getFullName() const {
|
||||
std::string Document::getFullName(bool python) const {
|
||||
if(python) {
|
||||
std::ostringstream ss;
|
||||
ss << "FreeCAD.getDocument('" << myName << "')";
|
||||
return ss.str();
|
||||
}
|
||||
return myName;
|
||||
}
|
||||
|
||||
App::Document *Document::getOwnerDocument() const {
|
||||
return const_cast<App::Document*>(this);
|
||||
}
|
||||
|
||||
const char* Document::getProgramVersion() const
|
||||
{
|
||||
return d->programVersion.c_str();
|
||||
@@ -3762,6 +3924,21 @@ const char * Document::getErrorDescription(const App::DocumentObject*Obj) const
|
||||
return d->findRecomputeLog(Obj);
|
||||
}
|
||||
|
||||
void Document::setErrorDescription(App::DocumentObject *Obj, const char *msg)
|
||||
{
|
||||
if (msg && msg[0] && Obj)
|
||||
d->addRecomputeLog(msg, Obj);
|
||||
}
|
||||
|
||||
void Document::setErrorDescription(App::Property *Prop, const char *msg)
|
||||
{
|
||||
if (msg && msg[0] && Prop) {
|
||||
auto obj = Base::freecad_dynamic_cast<DocumentObject>(Prop->getContainer());
|
||||
if (obj)
|
||||
d->addRecomputeLog(msg, obj);
|
||||
}
|
||||
}
|
||||
|
||||
// call the recompute of the Feature and handle the exceptions and errors.
|
||||
int Document::_recomputeFeature(DocumentObject* Feat)
|
||||
{
|
||||
|
||||
+60
-3
@@ -23,13 +23,22 @@
|
||||
#ifndef APP_DOCUMENT_H
|
||||
#define APP_DOCUMENT_H
|
||||
|
||||
#include <CXX/Objects.hxx>
|
||||
#include <Base/Observer.h>
|
||||
#include <Base/Persistence.h>
|
||||
#include <Base/Type.h>
|
||||
#include <Base/Handle.h>
|
||||
|
||||
#include "PropertyContainer.h"
|
||||
#include "PropertyLinks.h"
|
||||
#include "PropertyStandard.h"
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class QByteArray;
|
||||
|
||||
namespace Base {
|
||||
class Writer;
|
||||
}
|
||||
@@ -43,6 +52,8 @@ namespace App
|
||||
class DocumentPy; // the python document class
|
||||
class Application;
|
||||
class Transaction;
|
||||
class StringHasher;
|
||||
typedef Base::Reference<StringHasher> StringHasherRef;
|
||||
}
|
||||
|
||||
namespace App
|
||||
@@ -68,6 +79,7 @@ public:
|
||||
RestoreError = 10,
|
||||
LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed
|
||||
IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed
|
||||
RecomputeOnRestore = 13, // Mark pending recompute on restore for migration purpose
|
||||
};
|
||||
|
||||
/** @name Properties */
|
||||
@@ -109,6 +121,8 @@ public:
|
||||
PropertyString TipName;
|
||||
/// Whether to show hidden items in TreeView
|
||||
PropertyBool ShowHidden;
|
||||
/// Whether to use hasher on topological naming
|
||||
PropertyBool UseHasher;
|
||||
//@}
|
||||
|
||||
/** @name Signals of the document */
|
||||
@@ -186,11 +200,13 @@ public:
|
||||
bool save (void);
|
||||
bool saveAs(const char* file);
|
||||
bool saveCopy(const char* file) const;
|
||||
void save(Base::Writer &writer, bool archive) const;
|
||||
/// Restore the document from the file in Property Path
|
||||
void restore (const char *filename=nullptr,
|
||||
bool delaySignal=false, const std::vector<std::string> &objNames={});
|
||||
bool afterRestore(bool checkPartial=false);
|
||||
bool afterRestore(const std::vector<App::DocumentObject *> &, bool checkPartial=false);
|
||||
/// Restore the document from a pre-constructed xml reader
|
||||
void restore (Base::XMLReader &xmlReader,
|
||||
bool delaySignal=false, const std::vector<std::string> &objNames={});
|
||||
enum ExportStatus {
|
||||
NotExporting,
|
||||
Exporting,
|
||||
@@ -343,6 +359,10 @@ public:
|
||||
bool recomputeFeature(DocumentObject* Feat,bool recursive=false);
|
||||
/// get the text of the error of a specified object
|
||||
const char* getErrorDescription(const App::DocumentObject*) const;
|
||||
/// set the text of the error of a specified object
|
||||
void setErrorDescription(App::DocumentObject *, const char *);
|
||||
/// set the text of the error of a specified object
|
||||
void setErrorDescription(App::Property *, const char *);
|
||||
/// return the status bits
|
||||
bool testStatus(Status pos) const;
|
||||
/// set the status bits
|
||||
@@ -467,6 +487,38 @@ public:
|
||||
(const App::DocumentObject* from, const App::DocumentObject* to) const;
|
||||
//@}
|
||||
|
||||
/** Called by property during properly save its containing StringHasher
|
||||
*
|
||||
* @param hasher: the input hasher
|
||||
* @return Returns a pair<bool,int>. Boolean member indicate if the
|
||||
* StringHasher has been saved before. The Integer is the hasher index.
|
||||
*
|
||||
* The StringHasher object is designed to be shared among multiple objects.
|
||||
* So, we must not save duplicate copies of the same hasher. And must be
|
||||
* able to restore with the same sharing relationship. This function returns
|
||||
* whether the hasher has been saved before by other objects, and the index
|
||||
* of the hasher. If the hasher has not been saved before, the object must
|
||||
* save the hasher by calling StringHasher::Save
|
||||
*/
|
||||
std::pair<bool,int> addStringHasher(const StringHasherRef & hasher) const;
|
||||
|
||||
/** Called by property to restore its containing StringHasher
|
||||
*
|
||||
* @param index: the index previously returned by calling addStringHasher()
|
||||
* during save. Or if is negative, then return document's own string hasher
|
||||
* if UseHasher is True
|
||||
*
|
||||
* @return Return the resulting string hasher.
|
||||
*
|
||||
* The caller is responsible to restore the hasher itself if it is the first
|
||||
* owner of the hasher, i.e. return addStringHasher() returns true during
|
||||
* save
|
||||
*/
|
||||
StringHasherRef getStringHasher(int index=-1) const;
|
||||
|
||||
/// Return the document's own hasher regardless of UseHasher
|
||||
StringHasherRef getHasher() const;
|
||||
|
||||
/** Return the links to a given object
|
||||
*
|
||||
* @param links: holds the links found
|
||||
@@ -493,7 +545,9 @@ public:
|
||||
|
||||
virtual PyObject *getPyObject(void) override;
|
||||
|
||||
virtual std::string getFullName() const override;
|
||||
virtual std::string getFullName(bool python=false) const override;
|
||||
|
||||
virtual App::Document *getOwnerDocument() const override;
|
||||
|
||||
/// Indicate if there is any document restoring/importing
|
||||
static bool isAnyRestoring();
|
||||
@@ -512,6 +566,9 @@ protected:
|
||||
/// Construction
|
||||
Document(const char *name = "");
|
||||
|
||||
bool afterRestore(bool checkPartial=false);
|
||||
bool afterRestore(const std::vector<App::DocumentObject *> &, bool checkPartial=false);
|
||||
|
||||
void _removeObject(DocumentObject* pcObject);
|
||||
void _addObject(DocumentObject* pcObject, const char* pObjectName);
|
||||
/// checks if a valid transaction is open
|
||||
|
||||
+78
-76
@@ -165,14 +165,13 @@ App::DocumentObjectExecReturn* DocumentObject::executeExtensions()
|
||||
{
|
||||
//execute extensions but stop on error
|
||||
this->setStatus(App::RecomputeExtension, false); // reset the flag
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector) {
|
||||
auto ret = ext->extensionExecute();
|
||||
if (ret != StdReturn)
|
||||
return ret;
|
||||
}
|
||||
App::DocumentObjectExecReturn *res = StdReturn;
|
||||
foreachExtension<DocumentObjectExtension>([&res](DocumentObjectExtension *ext) {
|
||||
res = ext->extensionExecute();
|
||||
return res != StdReturn;
|
||||
});
|
||||
|
||||
return StdReturn;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DocumentObject::recomputeFeature(bool recursive)
|
||||
@@ -234,16 +233,10 @@ bool DocumentObject::mustRecompute(void) const
|
||||
|
||||
short DocumentObject::mustExecute(void) const
|
||||
{
|
||||
if (ExpressionEngine.isTouched())
|
||||
if (ExpressionEngine.isTouched()
|
||||
|| queryExtension(&DocumentObjectExtension::extensionMustExecute))
|
||||
return 1;
|
||||
|
||||
//ask all extensions
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector) {
|
||||
if (ext->extensionMustExecute())
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -259,13 +252,24 @@ const char* DocumentObject::getStatusString(void) const
|
||||
return "Valid";
|
||||
}
|
||||
|
||||
std::string DocumentObject::getFullName() const {
|
||||
if(!getDocument() || !pcNameInDocument)
|
||||
return "?";
|
||||
std::string name(getDocument()->getName());
|
||||
name += '#';
|
||||
name += *pcNameInDocument;
|
||||
return name;
|
||||
std::string DocumentObject::getFullName(bool python) const {
|
||||
if(!getDocument() || !pcNameInDocument) {
|
||||
if(python)
|
||||
return std::string("None");
|
||||
return std::string("?") + Base::Tools::getIdentifier(oldLabel);
|
||||
}
|
||||
|
||||
std::ostringstream ss;
|
||||
if(python) {
|
||||
ss << "FreeCAD.getDocument('" << getDocument()->getName()
|
||||
<< "').getObject('" << *pcNameInDocument << "')";
|
||||
}else
|
||||
ss << getDocument()->getName() << '#' << *pcNameInDocument;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
App::Document *DocumentObject::getOwnerDocument() const {
|
||||
return _pDoc;
|
||||
}
|
||||
|
||||
const char *DocumentObject::getNameInDocument() const
|
||||
@@ -708,13 +712,13 @@ bool DocumentObject::removeDynamicProperty(const char* name)
|
||||
auto expressions = ExpressionEngine.getExpressions();
|
||||
std::vector<App::ObjectIdentifier> removeExpr;
|
||||
|
||||
for (auto it : expressions) {
|
||||
for (const auto& it : expressions) {
|
||||
if (it.first.getProperty() == prop) {
|
||||
removeExpr.push_back(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it : removeExpr) {
|
||||
for (const auto& it : removeExpr) {
|
||||
ExpressionEngine.setValue(it, std::shared_ptr<Expression>());
|
||||
}
|
||||
|
||||
@@ -723,9 +727,9 @@ bool DocumentObject::removeDynamicProperty(const char* name)
|
||||
|
||||
App::Property* DocumentObject::addDynamicProperty(
|
||||
const char* type, const char* name, const char* group, const char* doc,
|
||||
short attr, bool ro, bool hidden)
|
||||
short attr, bool readonly, bool hidden)
|
||||
{
|
||||
auto prop = TransactionalObject::addDynamicProperty(type,name,group,doc,attr,ro,hidden);
|
||||
auto prop = TransactionalObject::addDynamicProperty(type,name,group,doc,attr,readonly,hidden);
|
||||
if(prop && _pDoc)
|
||||
_pDoc->addOrRemovePropertyOfObject(this, prop, true);
|
||||
return prop;
|
||||
@@ -744,8 +748,7 @@ void DocumentObject::onBeforeChange(const Property* prop)
|
||||
signalBeforeChange(*this,*prop);
|
||||
}
|
||||
|
||||
/// get called by the container when a Property was changed
|
||||
void DocumentObject::onChanged(const Property* prop)
|
||||
void DocumentObject::onEarlyChange(const Property *prop)
|
||||
{
|
||||
if(GetApplication().isClosingAll())
|
||||
return;
|
||||
@@ -763,6 +766,15 @@ void DocumentObject::onChanged(const Property* prop)
|
||||
}
|
||||
}
|
||||
|
||||
signalEarlyChanged(*this, *prop);
|
||||
}
|
||||
|
||||
/// get called by the container when a Property was changed
|
||||
void DocumentObject::onChanged(const Property* prop)
|
||||
{
|
||||
if(GetApplication().isClosingAll())
|
||||
return;
|
||||
|
||||
// Delay signaling view provider until the document object has handled the
|
||||
// change
|
||||
// if (_pDoc)
|
||||
@@ -814,14 +826,13 @@ DocumentObject *DocumentObject::getSubObject(const char *subname,
|
||||
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const
|
||||
{
|
||||
DocumentObject *ret = nullptr;
|
||||
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : exts) {
|
||||
if(ext->extensionGetSubObject(ret,subname,pyObj,mat,transform, depth))
|
||||
return ret;
|
||||
}
|
||||
if(queryExtension(&DocumentObjectExtension::extensionGetSubObject, ret, subname, pyObj, mat, transform, depth))
|
||||
return ret;
|
||||
|
||||
std::string name;
|
||||
const char *dot=nullptr;
|
||||
while(subname && *subname=='.')
|
||||
++subname; // skip leading .
|
||||
if(!subname || !(dot=strchr(subname,'.'))) {
|
||||
ret = const_cast<DocumentObject*>(this);
|
||||
}else if(subname[0]=='$') {
|
||||
@@ -879,11 +890,7 @@ std::vector<DocumentObject*> DocumentObject::getSubObjectList(const char *subnam
|
||||
|
||||
std::vector<std::string> DocumentObject::getSubObjects(int reason) const {
|
||||
std::vector<std::string> ret;
|
||||
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : exts) {
|
||||
if(ext->extensionGetSubObjects(ret,reason))
|
||||
return ret;
|
||||
}
|
||||
callExtension(&DocumentObjectExtension::extensionGetSubObjects,ret,reason);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -919,11 +926,8 @@ DocumentObject *DocumentObject::getLinkedObject(
|
||||
bool recursive, Base::Matrix4D *mat, bool transform, int depth) const
|
||||
{
|
||||
DocumentObject *ret = nullptr;
|
||||
auto exts = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : exts) {
|
||||
if(ext->extensionGetLinkedObject(ret,recursive,mat,transform,depth))
|
||||
return ret;
|
||||
}
|
||||
if(queryExtension(&DocumentObjectExtension::extensionGetLinkedObject, ret, recursive, mat, transform, depth))
|
||||
return ret;
|
||||
if(transform && mat) {
|
||||
auto pla = dynamic_cast<PropertyPlacement*>(getPropertyByName("Placement"));
|
||||
if(pla)
|
||||
@@ -934,8 +938,6 @@ DocumentObject *DocumentObject::getLinkedObject(
|
||||
|
||||
void DocumentObject::Save (Base::Writer &writer) const
|
||||
{
|
||||
if (this->getNameInDocument())
|
||||
writer.ObjectName = this->getNameInDocument();
|
||||
App::ExtensionContainer::Save(writer);
|
||||
}
|
||||
|
||||
@@ -991,9 +993,7 @@ void DocumentObject::renameObjectIdentifiers(const std::map<ObjectIdentifier, Ob
|
||||
void DocumentObject::onDocumentRestored()
|
||||
{
|
||||
//call all extensions
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector)
|
||||
ext->onExtendedDocumentRestored();
|
||||
callExtension(&DocumentObjectExtension::onExtendedDocumentRestored);
|
||||
if(Visibility.testStatus(Property::Output))
|
||||
Visibility.setStatus(Property::NoModify,true);
|
||||
}
|
||||
@@ -1006,25 +1006,19 @@ void DocumentObject::onUndoRedoFinished()
|
||||
void DocumentObject::onSettingDocument()
|
||||
{
|
||||
//call all extensions
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector)
|
||||
ext->onExtendedSettingDocument();
|
||||
callExtension(&DocumentObjectExtension::onExtendedSettingDocument);
|
||||
}
|
||||
|
||||
void DocumentObject::setupObject()
|
||||
{
|
||||
//call all extensions
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector)
|
||||
ext->onExtendedSetupObject();
|
||||
callExtension(&DocumentObjectExtension::onExtendedSetupObject);
|
||||
}
|
||||
|
||||
void DocumentObject::unsetupObject()
|
||||
{
|
||||
//call all extensions
|
||||
auto vector = getExtensionsDerivedFromType<App::DocumentObjectExtension>();
|
||||
for(auto ext : vector)
|
||||
ext->onExtendedUnsetupObject();
|
||||
callExtension(&DocumentObjectExtension::onExtendedUnsetupObject);
|
||||
}
|
||||
|
||||
void App::DocumentObject::_removeBackLink(DocumentObject* rmvObj)
|
||||
@@ -1054,31 +1048,25 @@ void App::DocumentObject::_addBackLink(DocumentObject* newObj)
|
||||
}
|
||||
|
||||
int DocumentObject::setElementVisible(const char *element, bool visible) {
|
||||
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
|
||||
int ret = ext->extensionSetElementVisible(element,visible);
|
||||
if(ret>=0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -1;
|
||||
int res = -1;
|
||||
foreachExtension<DocumentObjectExtension>([&res,element,visible](DocumentObjectExtension *ext) {
|
||||
res = ext->extensionSetElementVisible(element,visible);
|
||||
return res>=0;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
int DocumentObject::isElementVisible(const char *element) const {
|
||||
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
|
||||
int ret = ext->extensionIsElementVisible(element);
|
||||
if(ret>=0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return -1;
|
||||
int res = -1;
|
||||
foreachExtension<DocumentObjectExtension>([&res,element](DocumentObjectExtension *ext) {
|
||||
res = ext->extensionIsElementVisible(element);
|
||||
return res>=0;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
bool DocumentObject::hasChildElement() const {
|
||||
for(auto ext : getExtensionsDerivedFromType<DocumentObjectExtension>()) {
|
||||
if(ext->extensionHasChildElement())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return queryExtension(&DocumentObjectExtension::extensionHasChildElement);
|
||||
}
|
||||
|
||||
DocumentObject *DocumentObject::resolve(const char *subname,
|
||||
@@ -1253,6 +1241,20 @@ bool DocumentObject::adjustRelativeLinks(
|
||||
return touched;
|
||||
}
|
||||
|
||||
std::string DocumentObject::getElementMapVersion(const App::Property *_prop, bool restored) const {
|
||||
auto prop = Base::freecad_dynamic_cast<const PropertyComplexGeoData>(_prop);
|
||||
if(!prop)
|
||||
return std::string();
|
||||
return prop->getElementMapVersion(restored);
|
||||
}
|
||||
|
||||
bool DocumentObject::checkElementMapVersion(const App::Property *_prop, const char *ver) const {
|
||||
auto prop = Base::freecad_dynamic_cast<const PropertyComplexGeoData>(_prop);
|
||||
if(!prop)
|
||||
return false;
|
||||
return prop->checkElementMapVersion(ver);
|
||||
}
|
||||
|
||||
const std::string &DocumentObject::hiddenMarker() {
|
||||
static std::string marker("!hide");
|
||||
return marker;
|
||||
|
||||
@@ -66,7 +66,6 @@ enum ObjectStatus {
|
||||
NoAutoExpand = 17, // disable tree item auto expand on selection for this object
|
||||
PendingTransactionUpdate = 18, // mark that the object expects a call to onUndoRedoFinished() after transaction is finished.
|
||||
RecomputeExtension = 19, // mark the object to recompute its extensions
|
||||
TouchOnColorChange = 20, // inform view provider touch object on color change
|
||||
};
|
||||
|
||||
/** Return object for feature execution
|
||||
@@ -110,6 +109,8 @@ public:
|
||||
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChange;
|
||||
/// signal on changed property of this object
|
||||
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChanged;
|
||||
/// signal on changed property of this object before document scoped signalChangedObject
|
||||
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalEarlyChanged;
|
||||
|
||||
/// returns the type name of the ViewProvider
|
||||
virtual const char* getViewProviderName(void) const {
|
||||
@@ -139,7 +140,8 @@ public:
|
||||
/// returns the name that is safe to be exported to other document
|
||||
std::string getExportName(bool forced=false) const;
|
||||
/// Return the object full name of the form DocName#ObjName
|
||||
virtual std::string getFullName() const override;
|
||||
virtual std::string getFullName(bool python=false) const override;
|
||||
virtual App::Document *getOwnerDocument() const override;
|
||||
virtual bool isAttachedToDocument() const override;
|
||||
virtual const char* detachFromDocument() override;
|
||||
/// gets the document in which this Object is handled
|
||||
@@ -287,6 +289,20 @@ public:
|
||||
bool testIfLinkDAGCompatible(App::PropertyLinkSubList &linksTo) const;
|
||||
bool testIfLinkDAGCompatible(App::PropertyLinkSub &linkTo) const;
|
||||
|
||||
/** Return the element map version of the geometry data stored in the given property
|
||||
*
|
||||
* @param prop: the geometry property to query for element map version
|
||||
* @param restored: whether to query for the restored element map version.
|
||||
* In case of version upgrade, the restored version may
|
||||
* be different from the current version.
|
||||
*
|
||||
* @return Return the element map version string.
|
||||
*/
|
||||
virtual std::string getElementMapVersion(const App::Property *prop, bool restored=false) const;
|
||||
|
||||
/// Return true to signal re-generation of geometry element names
|
||||
virtual bool checkElementMapVersion(const App::Property *prop, const char *ver) const;
|
||||
|
||||
public:
|
||||
/** mustExecute
|
||||
* We call this method to check if the object was modified to
|
||||
@@ -442,7 +458,7 @@ public:
|
||||
virtual App::Property* addDynamicProperty(
|
||||
const char* type, const char* name=nullptr,
|
||||
const char* group=nullptr, const char* doc=nullptr,
|
||||
short attr=0, bool ro=false, bool hidden=false) override;
|
||||
short attr=0, bool readonly=false, bool hidden=false) override;
|
||||
|
||||
/** Resolve the last document object referenced in the subname
|
||||
*
|
||||
@@ -600,6 +616,8 @@ protected:
|
||||
virtual void onBeforeChange(const Property* prop) override;
|
||||
/// get called by the container when a property was changed
|
||||
virtual void onChanged(const Property* prop) override;
|
||||
/// get called by the container when a property was changed
|
||||
virtual void onEarlyChange(const Property* prop) override;
|
||||
/// get called after a document has been fully restored
|
||||
virtual void onDocumentRestored();
|
||||
/// get called after an undo/redo transaction is finished
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
Base::Matrix4D *mat, bool transform, int depth) const;
|
||||
|
||||
virtual int extensionSetElementVisible(const char *, bool) {return -1;}
|
||||
virtual int extensionIsElementVisible(const char *) {return -1;}
|
||||
virtual int extensionIsElementVisible(const char *) const {return -1;}
|
||||
virtual bool extensionHasChildElement() const {return false;}
|
||||
};
|
||||
|
||||
|
||||
@@ -374,12 +374,12 @@ PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
|
||||
|
||||
PyObject* DocumentObjectPy::recompute(PyObject *args)
|
||||
{
|
||||
PyObject *recursive=Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O",&recursive))
|
||||
PyObject *recursive = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive))
|
||||
return nullptr;
|
||||
|
||||
try {
|
||||
bool ok = getDocumentObjectPtr()->recomputeFeature(PyObject_IsTrue(recursive));
|
||||
bool ok = getDocumentObjectPtr()->recomputeFeature(PyObject_IsTrue(recursive) ? true : false);
|
||||
return Py_BuildValue("O", (ok ? Py_True : Py_False));
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
@@ -434,8 +434,8 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
short depth = 0;
|
||||
|
||||
static char *kwlist[] = {"subname", "retType", "matrix", "transform", "depth", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hO!Oh", kwlist,
|
||||
&obj, &retType, &Base::MatrixPy::Type, &pyMat, &doTransform, &depth))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hO!O!h", kwlist,
|
||||
&obj, &retType, &Base::MatrixPy::Type, &pyMat, &PyBool_Type, &doTransform, &depth))
|
||||
return nullptr;
|
||||
|
||||
if (retType < 0 || retType > 6) {
|
||||
@@ -469,7 +469,7 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool transform = PyObject_IsTrue(doTransform);
|
||||
bool transform = PyObject_IsTrue(doTransform) ? true : false;
|
||||
|
||||
struct SubInfo {
|
||||
App::DocumentObject *sobj;
|
||||
@@ -578,8 +578,8 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
|
||||
PyObject *transform = Py_True;
|
||||
short depth = 0;
|
||||
static char *kwlist[] = {"recursive","matrix","transform","depth", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|OOOh", kwlist,
|
||||
&recursive,&pyMat,&transform,&depth))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O!OO!h", kwlist,
|
||||
&PyBool_Type,&recursive,&pyMat,&PyBool_Type,&transform,&depth))
|
||||
return nullptr;
|
||||
|
||||
Base::Matrix4D _mat;
|
||||
@@ -595,7 +595,7 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
|
||||
|
||||
PY_TRY {
|
||||
auto linked = getDocumentObjectPtr()->getLinkedObject(
|
||||
PyObject_IsTrue(recursive), mat, PyObject_IsTrue(transform),depth);
|
||||
PyObject_IsTrue(recursive) ? true : false, mat, PyObject_IsTrue(transform) ? true : false, depth);
|
||||
if(!linked)
|
||||
linked = getDocumentObjectPtr();
|
||||
auto pyObj = Py::Object(linked->getPyObject(),true);
|
||||
@@ -623,10 +623,10 @@ PyObject* DocumentObjectPy::setElementVisible(PyObject *args)
|
||||
{
|
||||
char *element = nullptr;
|
||||
PyObject *visible = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &element,&visible))
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible))
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element,PyObject_IsTrue(visible)));
|
||||
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element,PyObject_IsTrue(visible) ? true : false));
|
||||
} PY_CATCH;
|
||||
}
|
||||
|
||||
@@ -830,13 +830,13 @@ PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
|
||||
const char *subname;
|
||||
PyObject *append = Py_False;
|
||||
int type = 0;
|
||||
if (!PyArg_ParseTuple(args, "s|Oi",&subname,&append,&type))
|
||||
if (!PyArg_ParseTuple(args, "s|O!i",&subname,&PyBool_Type,&append,&type))
|
||||
return nullptr;
|
||||
|
||||
PY_TRY {
|
||||
std::pair<std::string,std::string> elementName;
|
||||
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
|
||||
PyObject_IsTrue(append),(GeoFeature::ElementNameType)type);
|
||||
PyObject_IsTrue(append) ? true : false,(GeoFeature::ElementNameType)type);
|
||||
Py::Tuple ret(3);
|
||||
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
|
||||
ret.setItem(1,Py::String(elementName.first));
|
||||
@@ -866,7 +866,7 @@ PyObject *DocumentObjectPy::adjustRelativeLinks(PyObject *args) {
|
||||
std::set<App::DocumentObject *> visited;
|
||||
return Py::new_reference_to(Py::Boolean(
|
||||
getDocumentObjectPtr()->adjustRelativeLinks(inList,
|
||||
PyObject_IsTrue(recursive)?&visited:nullptr)));
|
||||
PyObject_IsTrue(recursive) ? &visited : nullptr)));
|
||||
}PY_CATCH
|
||||
}
|
||||
|
||||
|
||||
+217
-24
@@ -24,10 +24,12 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include <Base/Interpreter.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include "Application.h"
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "DocumentObserver.h"
|
||||
#include "GeoFeature.h"
|
||||
|
||||
@@ -199,6 +201,18 @@ bool DocumentObjectT::operator==(const DocumentObjectT &other) const {
|
||||
&& property == other.property;
|
||||
}
|
||||
|
||||
bool DocumentObjectT::operator<(const DocumentObjectT &other) const {
|
||||
if(getDocumentName() < other.getDocumentName())
|
||||
return true;
|
||||
if(getDocumentName() > other.getDocumentName())
|
||||
return false;
|
||||
if(getObjectName() < other.getObjectName())
|
||||
return true;
|
||||
if(getObjectName() > other.getObjectName())
|
||||
return false;
|
||||
return getPropertyName() < other.getPropertyName();
|
||||
}
|
||||
|
||||
Document* DocumentObjectT::getDocument() const
|
||||
{
|
||||
return GetApplication().getDocument(document.c_str());
|
||||
@@ -298,6 +312,44 @@ SubObjectT::SubObjectT(const char *docName, const char *objName, const char *s)
|
||||
{
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(const std::vector<App::DocumentObject*> &objs, const char *s)
|
||||
{
|
||||
if (objs.empty())
|
||||
return;
|
||||
|
||||
static_cast<DocumentObjectT&>(*this) = objs.front();
|
||||
std::ostringstream ss;
|
||||
for (auto it = objs.begin()+1; it!=objs.end(); ++it) {
|
||||
auto obj = *it;
|
||||
if (!obj || !obj->getNameInDocument())
|
||||
continue;
|
||||
ss << obj->getNameInDocument() << ".";
|
||||
}
|
||||
if (s)
|
||||
ss << s;
|
||||
subname = ss.str();
|
||||
}
|
||||
|
||||
SubObjectT::SubObjectT(std::vector<App::DocumentObject*>::const_iterator begin,
|
||||
std::vector<App::DocumentObject*>::const_iterator end,
|
||||
const char *s)
|
||||
{
|
||||
if (begin == end)
|
||||
return;
|
||||
|
||||
static_cast<DocumentObjectT&>(*this) = *begin;
|
||||
std::ostringstream ss;
|
||||
for (auto it = begin+1; it != end; ++it) {
|
||||
auto obj = *it;
|
||||
if (!obj || !obj->getNameInDocument())
|
||||
continue;
|
||||
ss << obj->getNameInDocument() << ".";
|
||||
}
|
||||
if (s)
|
||||
ss << s;
|
||||
subname = ss.str();
|
||||
}
|
||||
|
||||
bool SubObjectT::operator<(const SubObjectT &other) const {
|
||||
if(getDocumentName() < other.getDocumentName())
|
||||
return true;
|
||||
@@ -357,45 +409,107 @@ void SubObjectT::setSubName(const char *s) {
|
||||
subname = s?s:"";
|
||||
}
|
||||
|
||||
bool SubObjectT::normalize()
|
||||
{
|
||||
std::ostringstream ss;
|
||||
auto objs = getSubObjectList();
|
||||
for (unsigned i=1; i<objs.size(); ++i)
|
||||
ss << objs[i]->getNameInDocument() << ".";
|
||||
if (objs.front()->getSubObject(ss.str().c_str()) != objs.back()) {
|
||||
// something went wrong
|
||||
return false;
|
||||
}
|
||||
ss << getOldElementName();
|
||||
std::string sub = ss.str();
|
||||
if (subname != sub) {
|
||||
subname = std::move(sub);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SubObjectT App::SubObjectT::normalized() const
|
||||
{
|
||||
SubObjectT res(*this);
|
||||
res.normalize();
|
||||
return res;
|
||||
}
|
||||
|
||||
const std::string &SubObjectT::getSubName() const {
|
||||
return subname;
|
||||
}
|
||||
|
||||
std::string SubObjectT::getSubNameNoElement() const {
|
||||
return Data::ComplexGeoData::noElementName(subname.c_str());
|
||||
std::string SubObjectT::getSubNameNoElement(bool withObjName) const {
|
||||
if (!withObjName)
|
||||
return Data::ComplexGeoData::noElementName(subname.c_str());
|
||||
std::string res(getObjectName());
|
||||
res += ".";
|
||||
const char * element = Data::ComplexGeoData::findElementName(subname.c_str());
|
||||
if(element)
|
||||
return res.insert(res.size(), subname.c_str(), element - subname.c_str());
|
||||
return res;
|
||||
}
|
||||
|
||||
const char *SubObjectT::getElementName() const {
|
||||
return Data::ComplexGeoData::findElementName(subname.c_str());
|
||||
}
|
||||
|
||||
std::string SubObjectT::getNewElementName() const {
|
||||
std::pair<std::string, std::string> element;
|
||||
auto obj = getObject();
|
||||
if(!obj)
|
||||
return std::string();
|
||||
GeoFeature::resolveElement(obj,subname.c_str(),element);
|
||||
return std::move(element.first);
|
||||
bool SubObjectT::hasSubObject() const {
|
||||
return Data::ComplexGeoData::findElementName(subname.c_str()) != subname.c_str();
|
||||
}
|
||||
|
||||
std::string SubObjectT::getOldElementName(int *index) const {
|
||||
bool SubObjectT::hasSubElement() const {
|
||||
auto element = getElementName();
|
||||
return element && element[0];
|
||||
}
|
||||
|
||||
std::string SubObjectT::getNewElementName(bool fallback) const {
|
||||
const char *elementName = Data::ComplexGeoData::findElementName(subname.c_str());
|
||||
if (!elementName || !elementName[0])
|
||||
return std::string();
|
||||
std::string name = Data::ComplexGeoData::newElementName(elementName);
|
||||
if (name.size())
|
||||
return name;
|
||||
|
||||
std::pair<std::string, std::string> element;
|
||||
auto obj = getObject();
|
||||
if(!obj)
|
||||
return std::string();
|
||||
GeoFeature::resolveElement(obj,subname.c_str(),element);
|
||||
if(!index)
|
||||
return std::move(element.second);
|
||||
std::size_t pos = element.second.find_first_of("0123456789");
|
||||
if(pos == std::string::npos)
|
||||
*index = -1;
|
||||
else {
|
||||
*index = std::atoi(element.second.c_str()+pos);
|
||||
element.second.resize(pos);
|
||||
}
|
||||
if (!element.first.empty() || !fallback)
|
||||
return std::move(element.first);
|
||||
return std::move(element.second);
|
||||
}
|
||||
|
||||
std::string SubObjectT::getOldElementName(int *index, bool fallback) const {
|
||||
const char *elementName = Data::ComplexGeoData::findElementName(subname.c_str());
|
||||
if (!elementName || !elementName[0])
|
||||
return std::string();
|
||||
std::string name = Data::ComplexGeoData::oldElementName(elementName);
|
||||
if (name.empty()) {
|
||||
std::pair<std::string, std::string> element;
|
||||
auto obj = getObject();
|
||||
if(!obj)
|
||||
return std::string();
|
||||
GeoFeature::resolveElement(obj,subname.c_str(),element);
|
||||
if (!element.second.empty())
|
||||
name = std::move(element.second);
|
||||
else if (fallback && !element.first.empty())
|
||||
name = std::move(element.first);
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
if(index) {
|
||||
std::size_t pos = name.find_first_of("0123456789");
|
||||
if(pos == std::string::npos)
|
||||
*index = -1;
|
||||
else {
|
||||
*index = std::atoi(name.c_str()+pos);
|
||||
name.resize(pos);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
App::DocumentObject *SubObjectT::getSubObject() const {
|
||||
auto obj = getObject();
|
||||
if(obj)
|
||||
@@ -407,8 +521,8 @@ std::string SubObjectT::getSubObjectPython(bool force) const {
|
||||
if(!force && subname.empty())
|
||||
return getObjectPython();
|
||||
std::stringstream str;
|
||||
str << "(" << getObjectPython() << ",u'"
|
||||
<< Base::Tools::escapedUnicodeFromUtf8(subname.c_str()) << "')";
|
||||
str << "(" << getObjectPython() << ", '"
|
||||
<< Base::Tools::escapeEncodeString(normalized().subname) << "')";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
@@ -419,6 +533,38 @@ std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
SubObjectT SubObjectT::getParent() const {
|
||||
const char *pos = Data::ComplexGeoData::findElementName(subname.c_str());
|
||||
if (!pos || pos == subname.c_str())
|
||||
return SubObjectT();
|
||||
|
||||
if(*pos != '.')
|
||||
--pos;
|
||||
if(--pos <= subname.c_str())
|
||||
return SubObjectT();
|
||||
|
||||
bool found = false;
|
||||
for(;pos!=subname.c_str();--pos) {
|
||||
if(*pos != '.') {
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
if(found)
|
||||
return SubObjectT(getDocumentName().c_str(),
|
||||
getObjectName().c_str(), std::string(subname.c_str(), pos+1).c_str());
|
||||
}
|
||||
return SubObjectT(getDocumentName().c_str(), getObjectName().c_str(), nullptr);
|
||||
}
|
||||
|
||||
SubObjectT SubObjectT::getChild(const App::DocumentObject *child) const
|
||||
{
|
||||
if (getObjectName().empty())
|
||||
return SubObjectT(child);
|
||||
SubObjectT res = *this;
|
||||
res.setSubName(getSubNameNoElement() + child->getNameInDocument() + ".");
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string SubObjectT::getObjectFullName(const char *docName) const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
@@ -456,6 +602,43 @@ std::string SubObjectT::getSubObjectFullName(const char *docName) const
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
PyObject *SubObjectT::getPyObject() const
|
||||
{
|
||||
auto obj = getObject();
|
||||
if (!obj)
|
||||
return Py::new_reference_to(Py::Object());
|
||||
if (subname.empty())
|
||||
return obj->getPyObject();
|
||||
return Py::new_reference_to(Py::TupleN(
|
||||
Py::asObject(obj->getPyObject()), Py::String(subname)));
|
||||
}
|
||||
|
||||
void SubObjectT::setPyObject(PyObject *pyobj)
|
||||
{
|
||||
try {
|
||||
if (!pyobj)
|
||||
throw Base::ValueError("Invalid object");
|
||||
if (PyObject_TypeCheck(pyobj, &App::DocumentObjectPy::Type)) {
|
||||
this->operator=(static_cast<App::DocumentObjectPy*>(pyobj)->getDocumentObjectPtr());
|
||||
return;
|
||||
} else if (PySequence_Check(pyobj) && PySequence_Size(pyobj)==2) {
|
||||
Py::Sequence seq(pyobj);
|
||||
App::DocumentObject *obj;
|
||||
PropertyString tmp;
|
||||
if (PyObject_TypeCheck(seq[0].ptr(), &App::DocumentObjectPy::Type)) {
|
||||
obj = static_cast<App::DocumentObjectPy*>(seq[0].ptr())->getDocumentObjectPtr();
|
||||
tmp.setPyObject(seq[1].ptr());
|
||||
this->operator=(App::SubObjectT(obj, tmp.getValue()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Py::Exception &) {
|
||||
Base::PyException e;
|
||||
} catch (...) {
|
||||
}
|
||||
throw Base::ValueError("Expect either document object or tuple(obj, subname)");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PropertyLinkT::PropertyLinkT()
|
||||
@@ -593,7 +776,12 @@ bool DocumentWeakPtrT::expired() const noexcept
|
||||
return (d->_document == nullptr);
|
||||
}
|
||||
|
||||
App::Document* DocumentWeakPtrT::operator->() noexcept
|
||||
App::Document* DocumentWeakPtrT::operator*() const noexcept
|
||||
{
|
||||
return d->_document;
|
||||
}
|
||||
|
||||
App::Document* DocumentWeakPtrT::operator->() const noexcept
|
||||
{
|
||||
return d->_document;
|
||||
}
|
||||
@@ -686,7 +874,12 @@ DocumentObjectWeakPtrT& DocumentObjectWeakPtrT::operator= (App::DocumentObject*
|
||||
return *this;
|
||||
}
|
||||
|
||||
App::DocumentObject* DocumentObjectWeakPtrT::operator->() noexcept
|
||||
App::DocumentObject* DocumentObjectWeakPtrT::operator*() const noexcept
|
||||
{
|
||||
return d->get();
|
||||
}
|
||||
|
||||
App::DocumentObject* DocumentObjectWeakPtrT::operator->() const noexcept
|
||||
{
|
||||
return d->get();
|
||||
}
|
||||
|
||||
@@ -118,6 +118,8 @@ public:
|
||||
void operator=(const Property*);
|
||||
/*! Equality operator */
|
||||
bool operator==(const DocumentObjectT&) const;
|
||||
/*! Less than operator */
|
||||
bool operator<(const DocumentObjectT &other) const;
|
||||
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
|
||||
Document* getDocument() const;
|
||||
@@ -182,6 +184,14 @@ public:
|
||||
/*! Constructor */
|
||||
SubObjectT(const char *docName, const char *objName, const char *subname);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const std::vector<App::DocumentObject*> & objs, const char *subname = nullptr);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(std::vector<App::DocumentObject*>::const_iterator begin,
|
||||
std::vector<App::DocumentObject*>::const_iterator end,
|
||||
const char *subname = nullptr);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT &operator=(const SubObjectT&);
|
||||
|
||||
@@ -219,19 +229,32 @@ public:
|
||||
* if it is different then the given 'doc'.
|
||||
*/
|
||||
std::string getSubObjectFullName(const char *docName=nullptr) const;
|
||||
|
||||
/// Return the subname path without sub-element
|
||||
std::string getSubNameNoElement() const;
|
||||
std::string getSubNameNoElement(bool withObjName=false) const;
|
||||
|
||||
/// Return the sub-element (Face, Edge, etc) of the subname path
|
||||
const char *getElementName() const;
|
||||
|
||||
/// Return the new style sub-element name
|
||||
std::string getNewElementName() const;
|
||||
/// Check if there is any sub object reference
|
||||
bool hasSubObject() const;
|
||||
|
||||
/// Check if there is any sub element reference
|
||||
bool hasSubElement() const;
|
||||
|
||||
/** Return the new style sub-element name
|
||||
*
|
||||
* @param fallback: if true, then fallback to old style element name if
|
||||
* there is no new style name.
|
||||
*/
|
||||
std::string getNewElementName(bool fallback=true) const;
|
||||
|
||||
/** Return the old style sub-element name
|
||||
* @param index: if given, then return the element type, and extract the index
|
||||
* @param fallback: if true, then fallback to new style element name if
|
||||
* there is no old style name.
|
||||
*/
|
||||
std::string getOldElementName(int *index=nullptr) const;
|
||||
std::string getOldElementName(int *index=nullptr, bool fallback=true) const;
|
||||
|
||||
/// Return the sub-object
|
||||
DocumentObject *getSubObject() const;
|
||||
@@ -241,8 +264,29 @@ public:
|
||||
|
||||
bool operator<(const SubObjectT &other) const;
|
||||
|
||||
/** Obtain a string to access the sub object using DocumentObject.getSubObject() API
|
||||
*
|
||||
* @param force: whether to call getSubObject() even if there is no subname
|
||||
*/
|
||||
std::string getSubObjectPython(bool force=true) const;
|
||||
|
||||
/** Normalize the subname path to use only the object internal name and old style element name
|
||||
* @return Return whether the subname has been changed
|
||||
*/
|
||||
bool normalize();
|
||||
|
||||
/// Return a normalize copy of itself
|
||||
SubObjectT normalized() const;
|
||||
|
||||
/// Return the parent object
|
||||
SubObjectT getParent() const;
|
||||
|
||||
/// Return the child object
|
||||
SubObjectT getChild(const App::DocumentObject *) const;
|
||||
|
||||
PyObject *getPyObject() const;
|
||||
void setPyObject(PyObject *);
|
||||
|
||||
private:
|
||||
std::string subname;
|
||||
};
|
||||
@@ -294,11 +338,16 @@ public:
|
||||
* \return true if the managed object has already been deleted, false otherwise.
|
||||
*/
|
||||
bool expired() const noexcept;
|
||||
/*!
|
||||
* \brief operator *
|
||||
* \return pointer to the document
|
||||
*/
|
||||
App::Document* operator*() const noexcept;
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document
|
||||
*/
|
||||
App::Document* operator->() noexcept;
|
||||
App::Document* operator->() const noexcept;
|
||||
|
||||
private:
|
||||
// disable
|
||||
@@ -334,10 +383,15 @@ public:
|
||||
*/
|
||||
DocumentObjectWeakPtrT& operator= (App::DocumentObject* p);
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document
|
||||
* \brief operator *
|
||||
* \return pointer to the document object
|
||||
*/
|
||||
App::DocumentObject* operator->() noexcept;
|
||||
App::DocumentObject* operator*() const noexcept;
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document object
|
||||
*/
|
||||
App::DocumentObject* operator->() const noexcept;
|
||||
/*!
|
||||
* \brief operator ==
|
||||
* \return true if both objects are equal, false otherwise
|
||||
@@ -400,6 +454,13 @@ public:
|
||||
ptr = p;
|
||||
return *this;
|
||||
}
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document object
|
||||
*/
|
||||
T* operator*() const {
|
||||
return ptr.get<T>();
|
||||
}
|
||||
/*!
|
||||
* \brief operator ->
|
||||
* \return pointer to the document object
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,359 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DOCUMENT_PARAMS_H
|
||||
#define DOCUMENT_PARAMS_H
|
||||
|
||||
/*[[[cog
|
||||
import DocumentParams
|
||||
DocumentParams.declare()
|
||||
]]]*/
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:68)
|
||||
#include <Base/Parameter.h>
|
||||
#include <boost_signals2.hpp>
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:74)
|
||||
namespace App {
|
||||
/** Convenient class to obtain App::Document related parameters
|
||||
|
||||
* The parameters are under group "User parameter:BaseApp/Preferences/Document"
|
||||
*
|
||||
* This class is auto generated by App/DocumentParams.py. Modify that file
|
||||
* instead of this one, if you want to add any parameter. You need
|
||||
* to install Cog Python package for code generation:
|
||||
* @code
|
||||
* pip install cogapp
|
||||
* @endcode
|
||||
*
|
||||
* Once modified, you can regenerate the header and the source file,
|
||||
* @code
|
||||
* python3 -m cogapp -r App/DocumentParams.h App/DocumentParams.cpp
|
||||
* @endcode
|
||||
*
|
||||
* You can add a new parameter by adding lines in App/DocumentParams.py. Available
|
||||
* parameter types are 'Int, UInt, String, Bool, Float'. For example, to add
|
||||
* a new Int type parameter,
|
||||
* @code
|
||||
* ParamInt(parameter_name, default_value, documentation, on_change=False)
|
||||
* @endcode
|
||||
*
|
||||
* If there is special handling on parameter change, pass in on_change=True.
|
||||
* And you need to provide a function implementation in App/DocumentParams.cpp with
|
||||
* the following signature.
|
||||
* @code
|
||||
* void DocumentParams:on<parameter_name>Changed()
|
||||
* @endcode
|
||||
*/
|
||||
class AppExport DocumentParams {
|
||||
public:
|
||||
static ParameterGrp::handle getHandle();
|
||||
|
||||
static boost::signals2::signal<void (const char*)> &signalParamChanged();
|
||||
static void signalAll();
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter prefAuthor
|
||||
static const std::string & getprefAuthor();
|
||||
static const std::string & defaultprefAuthor();
|
||||
static void removeprefAuthor();
|
||||
static void setprefAuthor(const std::string &v);
|
||||
static const char *docprefAuthor();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter prefSetAuthorOnSave
|
||||
static const bool & getprefSetAuthorOnSave();
|
||||
static const bool & defaultprefSetAuthorOnSave();
|
||||
static void removeprefSetAuthorOnSave();
|
||||
static void setprefSetAuthorOnSave(const bool &v);
|
||||
static const char *docprefSetAuthorOnSave();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter prefCompany
|
||||
static const std::string & getprefCompany();
|
||||
static const std::string & defaultprefCompany();
|
||||
static void removeprefCompany();
|
||||
static void setprefCompany(const std::string &v);
|
||||
static const char *docprefCompany();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter prefLicenseType
|
||||
static const long & getprefLicenseType();
|
||||
static const long & defaultprefLicenseType();
|
||||
static void removeprefLicenseType();
|
||||
static void setprefLicenseType(const long &v);
|
||||
static const char *docprefLicenseType();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter prefLicenseUrl
|
||||
static const std::string & getprefLicenseUrl();
|
||||
static const std::string & defaultprefLicenseUrl();
|
||||
static void removeprefLicenseUrl();
|
||||
static void setprefLicenseUrl(const std::string &v);
|
||||
static const char *docprefLicenseUrl();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter CompressionLevel
|
||||
static const long & getCompressionLevel();
|
||||
static const long & defaultCompressionLevel();
|
||||
static void removeCompressionLevel();
|
||||
static void setCompressionLevel(const long &v);
|
||||
static const char *docCompressionLevel();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter CheckExtension
|
||||
static const bool & getCheckExtension();
|
||||
static const bool & defaultCheckExtension();
|
||||
static void removeCheckExtension();
|
||||
static void setCheckExtension(const bool &v);
|
||||
static const char *docCheckExtension();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter ForceXML
|
||||
static const long & getForceXML();
|
||||
static const long & defaultForceXML();
|
||||
static void removeForceXML();
|
||||
static void setForceXML(const long &v);
|
||||
static const char *docForceXML();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter SplitXML
|
||||
static const bool & getSplitXML();
|
||||
static const bool & defaultSplitXML();
|
||||
static void removeSplitXML();
|
||||
static void setSplitXML(const bool &v);
|
||||
static const char *docSplitXML();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter PreferBinary
|
||||
static const bool & getPreferBinary();
|
||||
static const bool & defaultPreferBinary();
|
||||
static void removePreferBinary();
|
||||
static void setPreferBinary(const bool &v);
|
||||
static const char *docPreferBinary();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter AutoRemoveFile
|
||||
static const bool & getAutoRemoveFile();
|
||||
static const bool & defaultAutoRemoveFile();
|
||||
static void removeAutoRemoveFile();
|
||||
static void setAutoRemoveFile(const bool &v);
|
||||
static const char *docAutoRemoveFile();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter BackupPolicy
|
||||
static const bool & getBackupPolicy();
|
||||
static const bool & defaultBackupPolicy();
|
||||
static void removeBackupPolicy();
|
||||
static void setBackupPolicy(const bool &v);
|
||||
static const char *docBackupPolicy();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter CreateBackupFiles
|
||||
static const bool & getCreateBackupFiles();
|
||||
static const bool & defaultCreateBackupFiles();
|
||||
static void removeCreateBackupFiles();
|
||||
static void setCreateBackupFiles(const bool &v);
|
||||
static const char *docCreateBackupFiles();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter UseFCBakExtension
|
||||
static const bool & getUseFCBakExtension();
|
||||
static const bool & defaultUseFCBakExtension();
|
||||
static void removeUseFCBakExtension();
|
||||
static void setUseFCBakExtension(const bool &v);
|
||||
static const char *docUseFCBakExtension();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter SaveBackupDateFormat
|
||||
static const std::string & getSaveBackupDateFormat();
|
||||
static const std::string & defaultSaveBackupDateFormat();
|
||||
static void removeSaveBackupDateFormat();
|
||||
static void setSaveBackupDateFormat(const std::string &v);
|
||||
static const char *docSaveBackupDateFormat();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter CountBackupFiles
|
||||
static const long & getCountBackupFiles();
|
||||
static const long & defaultCountBackupFiles();
|
||||
static void removeCountBackupFiles();
|
||||
static void setCountBackupFiles(const long &v);
|
||||
static const char *docCountBackupFiles();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter OptimizeRecompute
|
||||
static const bool & getOptimizeRecompute();
|
||||
static const bool & defaultOptimizeRecompute();
|
||||
static void removeOptimizeRecompute();
|
||||
static void setOptimizeRecompute(const bool &v);
|
||||
static const char *docOptimizeRecompute();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter CanAbortRecompute
|
||||
static const bool & getCanAbortRecompute();
|
||||
static const bool & defaultCanAbortRecompute();
|
||||
static void removeCanAbortRecompute();
|
||||
static void setCanAbortRecompute(const bool &v);
|
||||
static const char *docCanAbortRecompute();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter UseHasher
|
||||
static const bool & getUseHasher();
|
||||
static const bool & defaultUseHasher();
|
||||
static void removeUseHasher();
|
||||
static void setUseHasher(const bool &v);
|
||||
static const char *docUseHasher();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter ViewObjectTransaction
|
||||
static const bool & getViewObjectTransaction();
|
||||
static const bool & defaultViewObjectTransaction();
|
||||
static void removeViewObjectTransaction();
|
||||
static void setViewObjectTransaction(const bool &v);
|
||||
static const char *docViewObjectTransaction();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter WarnRecomputeOnRestore
|
||||
static const bool & getWarnRecomputeOnRestore();
|
||||
static const bool & defaultWarnRecomputeOnRestore();
|
||||
static void removeWarnRecomputeOnRestore();
|
||||
static void setWarnRecomputeOnRestore(const bool &v);
|
||||
static const char *docWarnRecomputeOnRestore();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter NoPartialLoading
|
||||
static const bool & getNoPartialLoading();
|
||||
static const bool & defaultNoPartialLoading();
|
||||
static void removeNoPartialLoading();
|
||||
static void setNoPartialLoading(const bool &v);
|
||||
static const char *docNoPartialLoading();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter ThumbnailNoBackground
|
||||
static const bool & getThumbnailNoBackground();
|
||||
static const bool & defaultThumbnailNoBackground();
|
||||
static void removeThumbnailNoBackground();
|
||||
static void setThumbnailNoBackground(const bool &v);
|
||||
static const char *docThumbnailNoBackground();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter ThumbnailSampleSize
|
||||
static const long & getThumbnailSampleSize();
|
||||
static const long & defaultThumbnailSampleSize();
|
||||
static void removeThumbnailSampleSize();
|
||||
static void setThumbnailSampleSize(const long &v);
|
||||
static const char *docThumbnailSampleSize();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter DuplicateLabels
|
||||
static const bool & getDuplicateLabels();
|
||||
static const bool & defaultDuplicateLabels();
|
||||
static void removeDuplicateLabels();
|
||||
static void setDuplicateLabels(const bool &v);
|
||||
static const char *docDuplicateLabels();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter TransactionOnRecompute
|
||||
static const bool & getTransactionOnRecompute();
|
||||
static const bool & defaultTransactionOnRecompute();
|
||||
static void removeTransactionOnRecompute();
|
||||
static void setTransactionOnRecompute(const bool &v);
|
||||
static const char *docTransactionOnRecompute();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter RelativeStringID
|
||||
static const bool & getRelativeStringID();
|
||||
static const bool & defaultRelativeStringID();
|
||||
static void removeRelativeStringID();
|
||||
static void setRelativeStringID(const bool &v);
|
||||
static const char *docRelativeStringID();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:118)
|
||||
//@{
|
||||
/// Accessor for parameter EnableMaterialEdit
|
||||
static const bool & getEnableMaterialEdit();
|
||||
static const bool & defaultEnableMaterialEdit();
|
||||
static void removeEnableMaterialEdit();
|
||||
static void setEnableMaterialEdit(const bool &v);
|
||||
static const char *docEnableMaterialEdit();
|
||||
//@}
|
||||
|
||||
// Auto generated code (Tools/params_utils.py:146)
|
||||
}; // class DocumentParams
|
||||
} // namespace App
|
||||
//[[[end]]]
|
||||
|
||||
#endif // DOCUMENT_PARAMS_H
|
||||
+10
-10
@@ -212,13 +212,13 @@ PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
|
||||
PyObject* view=nullptr;
|
||||
PyObject *attach=Py_False;
|
||||
static char *kwlist[] = {"type","name","objProxy","viewProxy","attach","viewType",nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args,kwd,"s|sOOOs",
|
||||
kwlist, &sType,&sName,&obj,&view,&attach,&sViewType))
|
||||
if (!PyArg_ParseTupleAndKeywords(args,kwd,"s|sOOO!s",
|
||||
kwlist, &sType,&sName,&obj,&view,&PyBool_Type,&attach,&sViewType))
|
||||
return nullptr;
|
||||
|
||||
DocumentObject *pcFtr = nullptr;
|
||||
|
||||
if (!obj || !PyObject_IsTrue(attach)) {
|
||||
if (!obj || (PyObject_IsTrue(attach) ? false : true)) {
|
||||
pcFtr = getDocumentPtr()->addObject(sType,sName,true,sViewType);
|
||||
}
|
||||
else {
|
||||
@@ -248,7 +248,7 @@ PyObject* DocumentPy::addObject(PyObject *args, PyObject *kwd)
|
||||
}
|
||||
pyftr.setAttr("Proxy", pyobj);
|
||||
|
||||
if (PyObject_IsTrue(attach)) {
|
||||
if (PyObject_IsTrue(attach) ? true : false) {
|
||||
getDocumentPtr()->addObject(pcFtr,sName);
|
||||
|
||||
try {
|
||||
@@ -307,7 +307,7 @@ PyObject* DocumentPy::removeObject(PyObject *args)
|
||||
PyObject* DocumentPy::copyObject(PyObject *args)
|
||||
{
|
||||
PyObject *obj, *rec=Py_False, *retAll=Py_False;
|
||||
if (!PyArg_ParseTuple(args, "O|OO",&obj,&rec,&retAll))
|
||||
if (!PyArg_ParseTuple(args, "O|O!O!",&obj,&PyBool_Type,&rec,&PyBool_Type,&retAll))
|
||||
return nullptr;
|
||||
|
||||
std::vector<App::DocumentObject*> objs;
|
||||
@@ -333,7 +333,7 @@ PyObject* DocumentPy::copyObject(PyObject *args)
|
||||
}
|
||||
|
||||
PY_TRY {
|
||||
auto ret = getDocumentPtr()->copyObject(objs, PyObject_IsTrue(rec), PyObject_IsTrue(retAll));
|
||||
auto ret = getDocumentPtr()->copyObject(objs, PyObject_IsTrue(rec) ? true : false, PyObject_IsTrue(retAll) ? true : false);
|
||||
if (ret.size()==1 && single)
|
||||
return ret[0]->getPyObject();
|
||||
|
||||
@@ -525,10 +525,10 @@ PyObject* DocumentPy::recompute(PyObject * args)
|
||||
}
|
||||
|
||||
int options = 0;
|
||||
if (PyObject_IsTrue(checkCycle))
|
||||
if (PyObject_IsTrue(checkCycle) ? true : false)
|
||||
options = Document::DepNoCycle;
|
||||
|
||||
int objectCount = getDocumentPtr()->recompute(objs, PyObject_IsTrue(force), nullptr, options);
|
||||
int objectCount = getDocumentPtr()->recompute(objs, PyObject_IsTrue(force) ? true : false, nullptr, options);
|
||||
|
||||
// Document::recompute() hides possibly raised Python exceptions by its features
|
||||
// So, check if an error is set and return null if yes
|
||||
@@ -901,10 +901,10 @@ Py::List DocumentPy::getOutList(void) const
|
||||
|
||||
PyObject *DocumentPy::getDependentDocuments(PyObject *args) {
|
||||
PyObject *sort = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "|O", &sort))
|
||||
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &sort))
|
||||
return nullptr;
|
||||
PY_TRY {
|
||||
auto docs = getDocumentPtr()->getDependentDocuments(PyObject_IsTrue(sort));
|
||||
auto docs = getDocumentPtr()->getDependentDocuments(PyObject_IsTrue(sort) ? true : false);
|
||||
Py::List ret;
|
||||
for (auto doc : docs)
|
||||
ret.append(Py::Object(doc->getPyObject(), true));
|
||||
|
||||
+111
-177
@@ -28,76 +28,81 @@
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include "Enumeration.h"
|
||||
#include <string_view>
|
||||
|
||||
using namespace App;
|
||||
|
||||
namespace {
|
||||
struct StringCopy : public Enumeration::Object {
|
||||
StringCopy(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const {
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const {
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string d;
|
||||
};
|
||||
|
||||
struct StringView : public Enumeration::Object {
|
||||
StringView(const char* str) : d(str) {
|
||||
}
|
||||
const char* data() const {
|
||||
return d.data();
|
||||
}
|
||||
bool isEqual(const char* str) const {
|
||||
return d == str;
|
||||
}
|
||||
bool isCustom() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view d;
|
||||
};
|
||||
}
|
||||
|
||||
Enumeration::Enumeration()
|
||||
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
|
||||
: _index(0)
|
||||
{
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const Enumeration &other)
|
||||
: _EnumArray(nullptr), _ownEnumArray(false), _index(0), _maxVal(-1)
|
||||
{
|
||||
if (other._ownEnumArray) {
|
||||
setEnums(other.getEnumVector());
|
||||
} else {
|
||||
_EnumArray = other._EnumArray;
|
||||
}
|
||||
|
||||
_ownEnumArray = other._ownEnumArray;
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
_maxVal = other._maxVal;
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char *valStr)
|
||||
: _ownEnumArray(true), _index(0), _maxVal(0)
|
||||
: _index(0)
|
||||
{
|
||||
_EnumArray = new const char*[2];
|
||||
#if defined (_MSC_VER)
|
||||
_EnumArray[0] = _strdup(valStr);
|
||||
#else
|
||||
_EnumArray[0] = strdup(valStr);
|
||||
#endif
|
||||
_EnumArray[1] = nullptr;
|
||||
enumArray.push_back(std::make_shared<StringCopy>(valStr));
|
||||
setValue(valStr);
|
||||
}
|
||||
|
||||
Enumeration::Enumeration(const char **list, const char *valStr)
|
||||
: _EnumArray(list), _ownEnumArray(false)
|
||||
: _index(0)
|
||||
{
|
||||
findMaxVal();
|
||||
while (list && *list) {
|
||||
enumArray.push_back(std::make_shared < StringView>(*list));
|
||||
list++;
|
||||
}
|
||||
setValue(valStr);
|
||||
}
|
||||
|
||||
Enumeration::~Enumeration()
|
||||
{
|
||||
if (_ownEnumArray) {
|
||||
if (_EnumArray != nullptr) {
|
||||
tearDown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::tearDown(void)
|
||||
{
|
||||
// Ugly...
|
||||
for(char **plEnums = (char **)_EnumArray; *plEnums != nullptr; ++plEnums) {
|
||||
// Delete C Strings first
|
||||
free(*plEnums);
|
||||
}
|
||||
|
||||
delete [] _EnumArray;
|
||||
|
||||
_EnumArray = nullptr;
|
||||
_ownEnumArray = false;
|
||||
_maxVal = -1;
|
||||
enumArray.clear();
|
||||
}
|
||||
|
||||
void Enumeration::setEnums(const char **plEnums)
|
||||
{
|
||||
if(plEnums == _EnumArray)
|
||||
return;
|
||||
|
||||
std::string oldValue;
|
||||
bool preserve = (isValid() && plEnums != nullptr);
|
||||
if (preserve) {
|
||||
@@ -106,23 +111,15 @@ void Enumeration::setEnums(const char **plEnums)
|
||||
oldValue = str;
|
||||
}
|
||||
|
||||
// set _ownEnumArray
|
||||
if (isValid() && _ownEnumArray) {
|
||||
tearDown();
|
||||
enumArray.clear();
|
||||
while (plEnums && *plEnums) {
|
||||
enumArray.push_back(std::make_shared<StringView>(*plEnums));
|
||||
plEnums++;
|
||||
}
|
||||
|
||||
// set...
|
||||
_EnumArray = plEnums;
|
||||
|
||||
// set _maxVal
|
||||
findMaxVal();
|
||||
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
_index = 0;
|
||||
else if (_index > _maxVal)
|
||||
_index = _maxVal;
|
||||
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
@@ -143,30 +140,14 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
oldValue = str;
|
||||
}
|
||||
|
||||
if (isValid() && _ownEnumArray) {
|
||||
tearDown();
|
||||
}
|
||||
|
||||
_EnumArray = new const char*[values.size() + 1];
|
||||
int i = 0;
|
||||
enumArray.clear();
|
||||
for (std::vector<std::string>::const_iterator it = values.begin(); it != values.end(); ++it) {
|
||||
#if defined (_MSC_VER)
|
||||
_EnumArray[i++] = _strdup(it->c_str());
|
||||
#else
|
||||
_EnumArray[i++] = strdup(it->c_str());
|
||||
#endif
|
||||
enumArray.push_back(std::make_shared<StringCopy>(it->c_str()));
|
||||
}
|
||||
|
||||
_EnumArray[i] = nullptr; // null termination
|
||||
|
||||
// Other state variables
|
||||
_maxVal = static_cast<int>(values.size() - 1);
|
||||
_ownEnumArray = true;
|
||||
// set _index
|
||||
if (_index < 0)
|
||||
_index = 0;
|
||||
else if (_index > _maxVal)
|
||||
_index = _maxVal;
|
||||
|
||||
if (preserve) {
|
||||
setValue(oldValue);
|
||||
}
|
||||
@@ -174,36 +155,18 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
|
||||
|
||||
void Enumeration::setValue(const char *value)
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!_EnumArray) {
|
||||
_index = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// search for the right entry
|
||||
while (1) {
|
||||
// end of list? set zero
|
||||
if (*plEnums == nullptr) {
|
||||
_index = 0;
|
||||
_index = 0;
|
||||
for (std::size_t i = 0; i < enumArray.size(); i++) {
|
||||
if (enumArray[i]->isEqual(value)) {
|
||||
_index = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
if (strcmp(*plEnums, value) == 0) {
|
||||
_index = i;
|
||||
break;
|
||||
}
|
||||
++plEnums;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void Enumeration::setValue(long value, bool checkRange)
|
||||
{
|
||||
if (value >= 0 && value <= _maxVal) {
|
||||
if (value >= 0 && value < countItems()) {
|
||||
_index = value;
|
||||
} else {
|
||||
if (checkRange) {
|
||||
@@ -216,116 +179,104 @@ void Enumeration::setValue(long value, bool checkRange)
|
||||
|
||||
bool Enumeration::isValue(const char *value) const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
int i = getInt();
|
||||
|
||||
if (i == -1) {
|
||||
return false;
|
||||
} else {
|
||||
return strcmp(_EnumArray[i], value) == 0;
|
||||
return enumArray[i]->isEqual(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool Enumeration::contains(const char *value) const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!getEnums()) {
|
||||
if (!isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// search for the right entry
|
||||
while (1) {
|
||||
// end of list?
|
||||
if (*plEnums == nullptr)
|
||||
return false;
|
||||
if (strcmp(*plEnums, value) == 0)
|
||||
for (const auto& it : enumArray) {
|
||||
if (it->isEqual(value))
|
||||
return true;
|
||||
++plEnums;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char * Enumeration::getCStr(void) const
|
||||
const char * Enumeration::getCStr() const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
//assert(_EnumArray);
|
||||
|
||||
if (!isValid() || _index < 0 || _index > _maxVal) {
|
||||
if (!isValid() || _index < 0 || _index >= countItems()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _EnumArray[_index];
|
||||
return enumArray[_index]->data();
|
||||
}
|
||||
|
||||
int Enumeration::getInt(void) const
|
||||
int Enumeration::getInt() const
|
||||
{
|
||||
if (!isValid() || _index < 0 || _index > _maxVal) {
|
||||
if (!isValid() || _index < 0 || _index >= countItems()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _index;
|
||||
}
|
||||
|
||||
std::vector<std::string> Enumeration::getEnumVector(void) const
|
||||
std::vector<std::string> Enumeration::getEnumVector() const
|
||||
{
|
||||
// using string methods without set, use setEnums(const char** plEnums) first!
|
||||
if (!_EnumArray)
|
||||
return std::vector<std::string>();
|
||||
std::vector<std::string> list;
|
||||
for (const auto& it : enumArray)
|
||||
list.emplace_back(it->data());
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<std::string> result;
|
||||
const char **plEnums = _EnumArray;
|
||||
bool Enumeration::hasEnums() const
|
||||
{
|
||||
return (!enumArray.empty());
|
||||
}
|
||||
|
||||
// end of list?
|
||||
while (*plEnums != nullptr) {
|
||||
result.push_back(*plEnums);
|
||||
++plEnums;
|
||||
bool Enumeration::isValid() const
|
||||
{
|
||||
return (!enumArray.empty() && _index >= 0 && _index < countItems());
|
||||
}
|
||||
|
||||
int Enumeration::maxValue() const
|
||||
{
|
||||
int num = -1;
|
||||
if (!enumArray.empty())
|
||||
num = static_cast<int>(enumArray.size()) - 1;
|
||||
return num;
|
||||
}
|
||||
|
||||
bool Enumeration::isCustom() const
|
||||
{
|
||||
for (const auto& it : enumArray) {
|
||||
if (it->isCustom())
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char ** Enumeration::getEnums(void) const
|
||||
{
|
||||
return _EnumArray;
|
||||
}
|
||||
|
||||
bool Enumeration::isValid(void) const
|
||||
{
|
||||
return (_EnumArray != nullptr && _index >= 0 && _index <= _maxVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration & Enumeration::operator=(const Enumeration &other)
|
||||
{
|
||||
if (other._ownEnumArray) {
|
||||
setEnums(other.getEnumVector());
|
||||
} else {
|
||||
_EnumArray = other._EnumArray;
|
||||
}
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
_ownEnumArray = other._ownEnumArray;
|
||||
enumArray = other.enumArray;
|
||||
_index = other._index;
|
||||
_maxVal = other._maxVal;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Enumeration::operator==(const Enumeration &other) const
|
||||
{
|
||||
if(_index != other._index || _maxVal != other._maxVal)
|
||||
if (_index != other._index || enumArray.size() != other.enumArray.size()) {
|
||||
return false;
|
||||
if (_EnumArray == other._EnumArray)
|
||||
return true;
|
||||
for (int i=0; i<=_maxVal; ++i) {
|
||||
if (_EnumArray[i] == other._EnumArray[i])
|
||||
}
|
||||
for (size_t i = 0; i < enumArray.size(); ++i) {
|
||||
if (enumArray[i]->data() == other.enumArray[i]->data())
|
||||
continue;
|
||||
if (_EnumArray[i] == nullptr || other._EnumArray[i] == nullptr)
|
||||
if (enumArray[i]->data() == nullptr || other.enumArray[i]->data() == nullptr)
|
||||
return false;
|
||||
if (strcmp(_EnumArray[i], other._EnumArray[i]) != 0)
|
||||
if (!enumArray[i]->isEqual(other.enumArray[i]->data()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -340,24 +291,7 @@ bool Enumeration::operator==(const char *other) const
|
||||
return (strcmp(getCStr(), other) == 0);
|
||||
}
|
||||
|
||||
void Enumeration::findMaxVal(void)
|
||||
int Enumeration::countItems() const
|
||||
{
|
||||
if (_EnumArray == nullptr) {
|
||||
_maxVal = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
const char **plEnums = _EnumArray;
|
||||
|
||||
// the NULL terminator doesn't belong to the range of
|
||||
// valid values
|
||||
int i = -1;
|
||||
while (*(plEnums++) != nullptr) {
|
||||
++i;
|
||||
// very unlikely to have enums with more then 5000 entries!
|
||||
assert(i < 5000);
|
||||
}
|
||||
|
||||
_maxVal = i;
|
||||
return static_cast<int>(enumArray.size());
|
||||
}
|
||||
|
||||
|
||||
+110
-114
@@ -24,14 +24,13 @@
|
||||
#ifndef BASE_ENUMERATION_H
|
||||
#define BASE_ENUMERATION_H
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class PropertyEnumeration;
|
||||
|
||||
/// A bidirectional string-integer mapping
|
||||
/*!
|
||||
* This is mainly intended for two purposes: working around the difficulty
|
||||
@@ -52,144 +51,141 @@ namespace App
|
||||
*/
|
||||
class AppExport Enumeration
|
||||
{
|
||||
friend class App::PropertyEnumeration;
|
||||
public:
|
||||
class Object {
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
virtual ~Object() {}
|
||||
virtual const char* data() const = 0;
|
||||
virtual bool isEqual(const char*) const = 0;
|
||||
virtual bool isCustom() const = 0;
|
||||
};
|
||||
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
public:
|
||||
/// Constructs an empty Enumeration object
|
||||
Enumeration();
|
||||
|
||||
/// Constructs an Enumeration with a single element
|
||||
Enumeration(const char *valStr);
|
||||
/// Standard copy constructor
|
||||
Enumeration(const Enumeration& other);
|
||||
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char **list, const char *valStr);
|
||||
/// Constructs an Enumeration with a single element
|
||||
Enumeration(const char *valStr);
|
||||
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
/// Constructs an Enumeration using val within list
|
||||
Enumeration(const char **list, const char *valStr);
|
||||
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char **plEnums);
|
||||
/// Standard destructor
|
||||
~Enumeration();
|
||||
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string> &values);
|
||||
/** Sets the enumeration string list
|
||||
* The list is a NULL terminated array of pointers to const
|
||||
* char* strings.
|
||||
* \code
|
||||
* const char enums[] = {"Black","White","Other",NULL}
|
||||
* \endcode
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*
|
||||
* Enumeration does not take ownership of the passed object
|
||||
*/
|
||||
void setEnums(const char **plEnums);
|
||||
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char *value);
|
||||
/// Set all enum values as vector of strings
|
||||
/*!
|
||||
* This method causes the Enumeration to dynamically allocate
|
||||
* it's own array of C Strings, which will be deleted by the
|
||||
* destructor or subsequent calls to setEnums(). So, it is
|
||||
* important to make sure the Enumeration stays in scope as
|
||||
* long as values returned by getCStr are in use.
|
||||
*
|
||||
* If Enumeration was already valid, will attempt to preserve
|
||||
* the string-representation value of the Enumeration
|
||||
*/
|
||||
void setEnums(const std::vector<std::string> &values);
|
||||
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string &value) {setValue(value.c_str());}
|
||||
/// Set the enum using a C string
|
||||
void setValue(const char *value);
|
||||
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
/// Overload of setValue(const char *value)
|
||||
void setValue(const std::string &value) {setValue(value.c_str());}
|
||||
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char *value) const;
|
||||
/// Set the enum using a long
|
||||
/*!
|
||||
* if checkRange is set to true, throws Base::ValueError when
|
||||
* values are set out of range
|
||||
*
|
||||
* Checks for boundaries via assert()
|
||||
*/
|
||||
void setValue(long value, bool checkRange = false);
|
||||
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char *value) const;
|
||||
/// Checks if the property is set to a certain string value
|
||||
bool isValue(const char *value) const;
|
||||
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char * getCStr(void) const;
|
||||
/// Checks if a string is included in the enumeration
|
||||
bool contains(const char *value) const;
|
||||
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt(void) const;
|
||||
/// Return the value as C string
|
||||
/*!
|
||||
* Returns NULL if the enumeration is invalid.
|
||||
*/
|
||||
const char * getCStr() const;
|
||||
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector(void) const;
|
||||
/// Return value as integer
|
||||
/*!
|
||||
* Returns -1 if the Enumeration isn't valid
|
||||
*/
|
||||
int getInt() const;
|
||||
|
||||
/// get pointer to the enum list
|
||||
const char ** getEnums(void) const;
|
||||
/// get all possible enum values as vector of strings
|
||||
std::vector<std::string> getEnumVector() const;
|
||||
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid(void) const;
|
||||
/// returns true if the enum list is non-empty, false otherwise
|
||||
bool hasEnums() const;
|
||||
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue(void) const {return _maxVal;}
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid() const;
|
||||
|
||||
/// Assignment operator
|
||||
Enumeration & operator=(const Enumeration &other);
|
||||
/// Returns the highest usable integer value for this enum
|
||||
/*!
|
||||
* Returns -1 if the enumeration is not valid according to isValid()
|
||||
*/
|
||||
int maxValue() const;
|
||||
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration &other) const;
|
||||
/// Returns true if any of the items is a user-defined string
|
||||
bool isCustom() const;
|
||||
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char *other) const;
|
||||
protected:
|
||||
/// Returns true if instance was not initialized via static string list
|
||||
bool isCustom(void) const {return _ownEnumArray;}
|
||||
/// Assignment operator
|
||||
Enumeration & operator=(const Enumeration &other);
|
||||
|
||||
/// Updates _maxVal
|
||||
void findMaxVal(void);
|
||||
/// true iff our string representation matches other's
|
||||
/*!
|
||||
* Returns false if either Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const Enumeration &other) const;
|
||||
|
||||
/// De-allocates memory used in _EnumArray
|
||||
/*!
|
||||
* Important to not call this unless this Enumeration owns array.
|
||||
*/
|
||||
void tearDown(void);
|
||||
/// true iff our string representation matches other
|
||||
/*!
|
||||
* Returns false if Enumeration is not valid.
|
||||
*/
|
||||
bool operator==(const char *other) const;
|
||||
protected:
|
||||
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
const char **_EnumArray;
|
||||
/// Number of items
|
||||
int countItems() const;
|
||||
|
||||
/// Whether instance owns _EnumArray
|
||||
bool _ownEnumArray;
|
||||
private:
|
||||
/// Handle to C Strings of possible enumeration values
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
std::vector<ObjectPtr> enumArray;
|
||||
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into _EnumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
/// Integer value of the enumeration
|
||||
/*!
|
||||
* This serves as an index into enumArray to get the string
|
||||
* representation.
|
||||
*/
|
||||
int _index;
|
||||
|
||||
/*! Cached result from findMaxVal()
|
||||
* Value should either be the maximum allowable integer value for
|
||||
* the Enumeration, or -1 if not initialized
|
||||
*/
|
||||
int _maxVal;
|
||||
friend class PropertyEnumeration;
|
||||
}; // class Enumeration
|
||||
} // namespace App
|
||||
|
||||
|
||||
@@ -1517,7 +1517,7 @@ void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
|
||||
leftOperator = static_cast<OperatorExpression*>(left)->op;
|
||||
if (left->priority() < priority()) // Check on operator priority first
|
||||
needsParens = true;
|
||||
else if (leftOperator == op) { // Equal priority?
|
||||
else if (leftOperator == op) { // Same operator ?
|
||||
if (!isLeftAssociative())
|
||||
needsParens = true;
|
||||
//else if (!isCommutative())
|
||||
@@ -1588,14 +1588,14 @@ void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
|
||||
rightOperator = static_cast<OperatorExpression*>(right)->op;
|
||||
if (right->priority() < priority()) // Check on operator priority first
|
||||
needsParens = true;
|
||||
else if (rightOperator == op) { // Equal priority?
|
||||
else if (rightOperator == op) { // Same operator ?
|
||||
if (!isRightAssociative())
|
||||
needsParens = true;
|
||||
else if (!isCommutative())
|
||||
needsParens = true;
|
||||
}
|
||||
else if (right->priority() == priority()) {
|
||||
if (!isRightAssociative())
|
||||
else if (right->priority() == priority()) { // Same priority ?
|
||||
if (!isRightAssociative() || rightOperator == MOD)
|
||||
needsParens = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ ExtensionContainer::ExtensionContainer() {
|
||||
ExtensionContainer::~ExtensionContainer() {
|
||||
|
||||
//we need to delete all dynamically added extensions
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->isPythonExtension())
|
||||
delete entry.second;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext)
|
||||
|
||||
//no duplicate extensions (including base classes)
|
||||
if(hasExtension(extension)) {
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
|
||||
_extensions.erase(entry.first);
|
||||
break;
|
||||
@@ -73,7 +73,7 @@ bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
|
||||
bool found = _extensions.find(t) != _extensions.end();
|
||||
if(!found && derived) {
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(t))
|
||||
return true;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {
|
||||
bool ExtensionContainer::hasExtension(const std::string& name) const {
|
||||
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->name() == name)
|
||||
return true;
|
||||
}
|
||||
@@ -98,11 +98,11 @@ Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_
|
||||
auto result = _extensions.find(t);
|
||||
if((result == _extensions.end()) && derived) {
|
||||
//we need to check for derived types
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(t))
|
||||
return entry.second;
|
||||
}
|
||||
if(no_except)
|
||||
if(no_except)
|
||||
return nullptr;
|
||||
//if we arrive here we don't have anything matching
|
||||
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
|
||||
@@ -111,7 +111,7 @@ Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_
|
||||
return result->second;
|
||||
}
|
||||
else {
|
||||
if(no_except)
|
||||
if(no_except)
|
||||
return nullptr;
|
||||
//if we arrive here we don't have anything matching
|
||||
throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
|
||||
@@ -126,7 +126,7 @@ bool ExtensionContainer::hasExtensions() const {
|
||||
Extension* ExtensionContainer::getExtension(const std::string& name) const {
|
||||
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.second->name() == name)
|
||||
return entry.second;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Typ
|
||||
|
||||
std::vector<Extension*> vec;
|
||||
//and for types derived from it, as they can be cast to the extension
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(type))
|
||||
vec.push_back(entry.second);
|
||||
}
|
||||
@@ -146,13 +146,13 @@ std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Typ
|
||||
|
||||
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
|
||||
App::PropertyContainer::getPropertyList(List);
|
||||
for(auto entry : _extensions)
|
||||
for(const auto& entry : _extensions)
|
||||
entry.second->extensionGetPropertyList(List);
|
||||
}
|
||||
|
||||
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
|
||||
App::PropertyContainer::getPropertyMap(Map);
|
||||
for(auto entry : _extensions)
|
||||
for(const auto& entry : _extensions)
|
||||
entry.second->extensionGetPropertyMap(Map);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ Property* ExtensionContainer::getPropertyByName(const char* name) const {
|
||||
if(prop)
|
||||
return prop;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
auto prop = entry.second->extensionGetPropertyByName(name);
|
||||
if(prop)
|
||||
return prop;
|
||||
@@ -176,7 +176,7 @@ short int ExtensionContainer::getPropertyType(const Property* prop) const {
|
||||
if(res != 0)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyType(prop);
|
||||
if(res != 0)
|
||||
return res;
|
||||
@@ -191,7 +191,7 @@ short int ExtensionContainer::getPropertyType(const char* name) const {
|
||||
if(res != 0)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyType(name);
|
||||
if(res != 0)
|
||||
return res;
|
||||
@@ -207,7 +207,7 @@ const char* ExtensionContainer::getPropertyName(const Property* prop) const {
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyName(prop);
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
@@ -222,7 +222,7 @@ const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyGroup(prop);
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
@@ -237,7 +237,7 @@ const char* ExtensionContainer::getPropertyGroup(const char* name) const {
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyGroup(name);
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
@@ -253,7 +253,7 @@ const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) c
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyDocumentation(prop);
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
@@ -268,7 +268,7 @@ const char* ExtensionContainer::getPropertyDocumentation(const char* name) const
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
res = entry.second->extensionGetPropertyDocumentation(name);
|
||||
if(res != nullptr)
|
||||
return res;
|
||||
@@ -281,7 +281,7 @@ void ExtensionContainer::onChanged(const Property* prop) {
|
||||
|
||||
//inform all extensions about changed property. This includes all properties from the
|
||||
//extended object (this) as well as all extension properties
|
||||
for(auto entry : _extensions)
|
||||
for(const auto& entry : _extensions)
|
||||
entry.second->extensionOnChanged(prop);
|
||||
|
||||
App::PropertyContainer::onChanged(prop);
|
||||
@@ -318,7 +318,7 @@ void ExtensionContainer::saveExtensions(Base::Writer& writer) const {
|
||||
//save dynamic extensions
|
||||
writer.incInd(); // indentation for 'Extensions'
|
||||
writer.Stream() << writer.ind() << "<Extensions Count=\"" << _extensions.size() << "\">" << std::endl;
|
||||
for(auto entry : _extensions) {
|
||||
for(const auto& entry : _extensions) {
|
||||
|
||||
auto ext = entry.second;
|
||||
writer.incInd(); // indentation for 'Extension name'
|
||||
|
||||
@@ -132,12 +132,74 @@ public:
|
||||
return static_cast<ExtensionT*>(getExtension(ExtensionT::getExtensionClassTypeId(),derived,no_except));
|
||||
}
|
||||
|
||||
/** Helpers for iterator over extensions of a given type */
|
||||
//@{
|
||||
|
||||
/** Helper structs to deduce the class type of a class function pointer type */
|
||||
//@{
|
||||
template<typename T> struct ClassOf {};
|
||||
template<typename R, typename C>
|
||||
struct ClassOf<R (C::*)>{ using type = C; };
|
||||
//@}
|
||||
|
||||
/** Call an extension member function for each extension of the given type
|
||||
* @param f: the member function pointer of some extension class
|
||||
* @param args: variadic parameters passed to the member function
|
||||
*/
|
||||
template<typename F, class... Args>
|
||||
void callExtension(F&& f, Args&&... args) const {
|
||||
for (const auto &entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(ClassOf<F>::type::getExtensionClassTypeId()))
|
||||
(static_cast<typename ClassOf<F>::type*>(entry.second)->*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/** Query using an extension member function
|
||||
* @param f: the member function pointer of some extension class
|
||||
* @param args: variadic parameters passed to the member function
|
||||
*
|
||||
* @return Returns true if the iteratorion is terminated prematurely, or else false.
|
||||
*
|
||||
* The iteration over the contained extensions is terminated as soon as the
|
||||
* extension method call returns true.
|
||||
*/
|
||||
template<typename F, class... Args>
|
||||
bool queryExtension(F&& f, Args&&... args) const {
|
||||
for (const auto &entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(ClassOf<F>::type::getExtensionClassTypeId())) {
|
||||
if((static_cast<typename ClassOf<F>::type*>(entry.second)->*f)(std::forward<Args>(args)...))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Invoke a callable for each extension of a given type
|
||||
* @param f: the callable that accepts one argument of an extension, and
|
||||
* returns any value that is convertible to boolean.
|
||||
*
|
||||
* @return Returns true if the iteratorion is terminated prematurely, or else false.
|
||||
*
|
||||
* The iteration over the contained extensions is terminated as soon as the
|
||||
* extension method call returns true.
|
||||
*/
|
||||
template<typename T, typename F>
|
||||
bool foreachExtension(F f) const {
|
||||
for (const auto &entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(T::getExtensionClassTypeId())) {
|
||||
if(f(static_cast<T*>(entry.second)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//get all extensions which have the given base class
|
||||
std::vector<Extension*> getExtensionsDerivedFrom(Base::Type type) const;
|
||||
template<typename ExtensionT>
|
||||
std::vector<ExtensionT*> getExtensionsDerivedFromType() const {
|
||||
std::vector<ExtensionT*> typevec;
|
||||
for(auto entry : _extensions) {
|
||||
for (const auto &entry : _extensions) {
|
||||
if(entry.first.isDerivedFrom(ExtensionT::getExtensionClassTypeId()))
|
||||
typevec.push_back(static_cast<ExtensionT*>(entry.second));
|
||||
}
|
||||
|
||||
@@ -174,11 +174,11 @@ PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
|
||||
|
||||
char *type;
|
||||
PyObject *deriv = Py_True;
|
||||
if (!PyArg_ParseTuple(args, "s|O", &type, &deriv))
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &type, &PyBool_Type, &deriv))
|
||||
return nullptr;
|
||||
|
||||
//get the extension type asked for
|
||||
bool derived = PyObject_IsTrue(deriv);
|
||||
bool derived = PyObject_IsTrue(deriv) ? true : false;
|
||||
Base::Type extension = Base::Type::fromName(type);
|
||||
if (extension.isBad() || !extension.isDerivedFrom(App::Extension::getExtensionClassTypeId())) {
|
||||
std::stringstream str;
|
||||
|
||||
@@ -48,6 +48,11 @@ public:
|
||||
}
|
||||
virtual ~ExtensionPythonT() {
|
||||
}
|
||||
|
||||
ExtensionPythonT(const ExtensionPythonT&) = delete;
|
||||
ExtensionPythonT(ExtensionPythonT&&) = delete;
|
||||
ExtensionPythonT& operator= (const ExtensionPythonT&) = delete;
|
||||
ExtensionPythonT& operator= (ExtensionPythonT&&) = delete;
|
||||
};
|
||||
|
||||
typedef ExtensionPythonT<App::Extension> ExtensionPython;
|
||||
|
||||
@@ -85,6 +85,11 @@ protected:
|
||||
virtual void onSettingDocument() {
|
||||
FeatureT::onSettingDocument();
|
||||
}
|
||||
|
||||
FeatureCustomT(const FeatureCustomT&) = delete;
|
||||
FeatureCustomT(FeatureCustomT&&) = delete;
|
||||
FeatureCustomT& operator= (const FeatureCustomT&) = delete;
|
||||
FeatureCustomT& operator= (FeatureCustomT&&) = delete;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
|
||||
@@ -342,6 +342,12 @@ protected:
|
||||
FeatureT::onDocumentRestored();
|
||||
}
|
||||
|
||||
public:
|
||||
FeaturePythonT(const FeaturePythonT&) = delete;
|
||||
FeaturePythonT(FeaturePythonT&&) = delete;
|
||||
FeaturePythonT& operator= (const FeaturePythonT&) = delete;
|
||||
FeaturePythonT& operator= (FeaturePythonT&&) = delete;
|
||||
|
||||
private:
|
||||
FeaturePythonImp* imp;
|
||||
PropertyPythonObject Proxy;
|
||||
|
||||
+37
-4
@@ -100,7 +100,7 @@ FeatureTest::FeatureTest()
|
||||
ADD_PROPERTY_TYPE(TypeTransient,(4711),group,Prop_Transient ,"An example property which has the type 'Transient'" );
|
||||
ADD_PROPERTY_TYPE(TypeNoRecompute,(4711),group,Prop_NoRecompute,"An example property which has the type 'NoRecompute'");
|
||||
ADD_PROPERTY_TYPE(TypeAll ,(4711),group,(App::PropertyType) (Prop_Output|Prop_ReadOnly |Prop_Hidden ),
|
||||
"An example property which has the types 'Output', 'ReadOnly', and 'Hidden'");
|
||||
"An example property which has the types 'Output', 'ReadOnly' and 'Hidden'");
|
||||
|
||||
ADD_PROPERTY(QuantityLength,(1.0));
|
||||
QuantityLength.setUnit(Base::Unit::Length);
|
||||
@@ -118,13 +118,46 @@ FeatureTest::~FeatureTest()
|
||||
|
||||
}
|
||||
|
||||
short FeatureTest::mustExecute(void) const
|
||||
short FeatureTest::mustExecute() const
|
||||
{
|
||||
return DocumentObject::mustExecute();
|
||||
}
|
||||
|
||||
DocumentObjectExecReturn *FeatureTest::execute(void)
|
||||
DocumentObjectExecReturn *FeatureTest::execute()
|
||||
{
|
||||
// Enum handling
|
||||
Enumeration enumObj1 = Enum.getEnum();
|
||||
enumObj1.setValue(7, false);
|
||||
enumObj1.setValue(4, true);
|
||||
|
||||
Enumeration enumObj2 = Enum.getEnum();
|
||||
enumObj2.setValue(4, true);
|
||||
|
||||
Enumeration enumObj3(enumObj2);
|
||||
const char* val = enumObj3.getCStr();
|
||||
enumObj3.isValue(val);
|
||||
enumObj3.getEnumVector();
|
||||
|
||||
Enumeration enumObj4("Single item");
|
||||
enumObj4.setEnums(enums);
|
||||
std::ignore = enumObj4 == enumObj2;
|
||||
enumObj4.setEnums(nullptr);
|
||||
enumObj4 = enumObj2;
|
||||
std::ignore = enumObj4 == enumObj4.getCStr();
|
||||
|
||||
Enumeration enumObj5(enums, enums[3]);
|
||||
enumObj5.isValue(enums[2]);
|
||||
enumObj5.isValue(enums[3]);
|
||||
enumObj5.contains(enums[1]);
|
||||
|
||||
Enumeration enumObj6;
|
||||
enumObj6.setEnums(enums);
|
||||
enumObj6.setValue(enums[1]);
|
||||
std::vector<std::string> list;
|
||||
list.emplace_back("Hello");
|
||||
list.emplace_back("World");
|
||||
enumObj6.setEnums(list);
|
||||
enumObj6.setValue(list.back());
|
||||
/*
|
||||
doc=App.newDocument()
|
||||
obj=doc.addObject("App::FeatureTest")
|
||||
@@ -189,7 +222,7 @@ FeatureTestException::FeatureTestException()
|
||||
ADD_PROPERTY(ExceptionType,(Base::Exception::getClassTypeId().getKey()) );
|
||||
}
|
||||
|
||||
DocumentObjectExecReturn *FeatureTestException::execute(void)
|
||||
DocumentObjectExecReturn *FeatureTestException::execute()
|
||||
{
|
||||
//ExceptionType;
|
||||
throw Base::RuntimeError("FeatureTestException::execute(): Testexception ;-)");
|
||||
|
||||
@@ -111,7 +111,8 @@ def InitApplications():
|
||||
AddPath = FreeCAD.ConfigGet("AdditionalModulePaths").split(";")
|
||||
HomeMod = FreeCAD.getUserAppDataDir()+"Mod"
|
||||
HomeMod = os.path.realpath(HomeMod)
|
||||
MacroDir = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro").GetString("MacroPath")
|
||||
MacroStd = App.getUserMacroDir(False)
|
||||
MacroDir = App.getUserMacroDir(True)
|
||||
MacroMod = os.path.realpath(MacroDir+"/Mod")
|
||||
SystemWideMacroDir = FreeCAD.getHomePath()+'Macro'
|
||||
SystemWideMacroDir = os.path.realpath(SystemWideMacroDir)
|
||||
@@ -278,6 +279,7 @@ def InitApplications():
|
||||
for i in path:
|
||||
Log(" " + i + "\n")
|
||||
# add MacroDir to path (RFE #0000504)
|
||||
sys.path.append(MacroStd)
|
||||
sys.path.append(MacroDir)
|
||||
# add SystemWideMacroDir to path
|
||||
sys.path.append(SystemWideMacroDir)
|
||||
|
||||
+129
-8
@@ -25,10 +25,15 @@
|
||||
|
||||
#include <App/GeoFeaturePy.h>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <App/Link.h>
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Document.h"
|
||||
#include "GeoFeature.h"
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
#include "ComplexGeoData.h"
|
||||
#include "MappedElement.h"
|
||||
|
||||
FC_LOG_LEVEL_INIT("GeoFeature",true,true)
|
||||
|
||||
using namespace App;
|
||||
|
||||
@@ -43,6 +48,8 @@ PROPERTY_SOURCE(App::GeoFeature, App::DocumentObject)
|
||||
GeoFeature::GeoFeature(void)
|
||||
{
|
||||
ADD_PROPERTY_TYPE(Placement,(Base::Placement()),nullptr,Prop_NoRecompute,nullptr);
|
||||
ADD_PROPERTY_TYPE(_ElementMapVersion,(""),"Base",
|
||||
(App::PropertyType)(Prop_Output|Prop_Hidden|Prop_Transient),"");
|
||||
}
|
||||
|
||||
GeoFeature::~GeoFeature(void)
|
||||
@@ -81,16 +88,48 @@ PyObject* GeoFeature::getPyObject(void)
|
||||
}
|
||||
|
||||
|
||||
std::pair<std::string,std::string> GeoFeature::getElementName(
|
||||
const char *name, ElementNameType type) const
|
||||
std::pair<std::string,std::string>
|
||||
GeoFeature::getElementName(const char *name, ElementNameType type) const
|
||||
{
|
||||
(void)type;
|
||||
|
||||
std::pair<std::string,std::string> ret;
|
||||
if(!name)
|
||||
if(!name)
|
||||
return ret;
|
||||
|
||||
ret.second = name;
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if(!prop) return std::make_pair("", name);
|
||||
|
||||
auto geo = prop->getComplexData();
|
||||
if(!geo) return std::make_pair("", name);
|
||||
|
||||
return _getElementName(name, geo->getElementName(name));
|
||||
}
|
||||
|
||||
std::pair<std::string,std::string>
|
||||
GeoFeature::_getElementName(const char *name, const Data::MappedElement &mapped) const
|
||||
{
|
||||
std::pair<std::string,std::string> ret;
|
||||
if (mapped.index && mapped.name) {
|
||||
std::ostringstream ss;
|
||||
ss << Data::ComplexGeoData::elementMapPrefix()
|
||||
<< mapped.name << '.' << mapped.index;
|
||||
ret.first = ss.str();
|
||||
mapped.index.toString(ret.second);
|
||||
} else if (mapped.name) {
|
||||
FC_TRACE("element mapped name " << name << " not found in " << getFullName());
|
||||
ret.first = name;
|
||||
const char *dot = strrchr(name,'.');
|
||||
if(dot) {
|
||||
// deliberately mangle the old style element name to signal a
|
||||
// missing reference
|
||||
ret.second = Data::ComplexGeoData::missingPrefix();
|
||||
ret.second += dot+1;
|
||||
}
|
||||
} else {
|
||||
mapped.index.toString(ret.second);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -99,6 +138,8 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
ElementNameType type, const DocumentObject *filter,
|
||||
const char **_element, GeoFeature **geoFeature)
|
||||
{
|
||||
elementName.first.clear();
|
||||
elementName.second.clear();
|
||||
if(!obj || !obj->getNameInDocument())
|
||||
return nullptr;
|
||||
if(!subname)
|
||||
@@ -108,11 +149,16 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
auto sobj = obj->getSubObject(subname);
|
||||
if(!sobj)
|
||||
return nullptr;
|
||||
obj = sobj->getLinkedObject(true);
|
||||
auto geo = dynamic_cast<GeoFeature*>(obj);
|
||||
auto linked = sobj->getLinkedObject(true);
|
||||
auto geo = Base::freecad_dynamic_cast<GeoFeature>(linked);
|
||||
if(!geo && linked) {
|
||||
auto ext = linked->getExtensionByType<LinkBaseExtension>(true);
|
||||
if(ext)
|
||||
geo = Base::freecad_dynamic_cast<GeoFeature>(ext->getTrueLinkedObject(true));
|
||||
}
|
||||
if(geoFeature)
|
||||
*geoFeature = geo;
|
||||
if(!obj || (filter && obj!=filter))
|
||||
if(filter && geo!=filter)
|
||||
return nullptr;
|
||||
if(!element || !element[0]) {
|
||||
if(append)
|
||||
@@ -139,3 +185,78 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn
|
||||
return sobj;
|
||||
}
|
||||
|
||||
bool GeoFeature::hasMissingElement(const char *subname) {
|
||||
return Data::ComplexGeoData::hasMissingElement(subname);
|
||||
if(!subname)
|
||||
return false;
|
||||
auto dot = strrchr(subname,'.');
|
||||
if(!dot)
|
||||
return subname[0]=='?';
|
||||
return dot[1]=='?';
|
||||
}
|
||||
|
||||
void GeoFeature::updateElementReference() {
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if(!prop) return;
|
||||
auto geo = prop->getComplexData();
|
||||
if(!geo) return;
|
||||
bool reset = false;
|
||||
auto version = getElementMapVersion(prop);
|
||||
if(_ElementMapVersion.getStrValue().empty())
|
||||
_ElementMapVersion.setValue(version);
|
||||
else if(_ElementMapVersion.getStrValue()!=version) {
|
||||
reset = true;
|
||||
_ElementMapVersion.setValue(version);
|
||||
}
|
||||
PropertyLinkBase::updateElementReferences(this,reset);
|
||||
}
|
||||
|
||||
void GeoFeature::onChanged(const Property *prop) {
|
||||
if(prop==getPropertyOfGeometry()) {
|
||||
if(getDocument() && !getDocument()->testStatus(Document::Restoring)
|
||||
&& !getDocument()->isPerformingTransaction())
|
||||
{
|
||||
updateElementReference();
|
||||
}
|
||||
}
|
||||
DocumentObject::onChanged(prop);
|
||||
}
|
||||
|
||||
void GeoFeature::onDocumentRestored() {
|
||||
if(!getDocument()->testStatus(Document::Status::Importing))
|
||||
_ElementMapVersion.setValue(getElementMapVersion(getPropertyOfGeometry(),true));
|
||||
DocumentObject::onDocumentRestored();
|
||||
}
|
||||
|
||||
const std::vector<std::string>&
|
||||
GeoFeature::searchElementCache(const std::string &element,
|
||||
bool checkGeometry,
|
||||
double tol,
|
||||
double atol) const
|
||||
{
|
||||
static std::vector<std::string> none;
|
||||
(void)element;
|
||||
(void)checkGeometry;
|
||||
(void)tol;
|
||||
(void)atol;
|
||||
return none;
|
||||
}
|
||||
|
||||
const std::vector<const char *>&
|
||||
GeoFeature::getElementTypes(bool /*all*/) const
|
||||
{
|
||||
static std::vector<const char *> nil;
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if (!prop)
|
||||
return nil;
|
||||
return prop->getComplexData()->getElementTypes();
|
||||
}
|
||||
|
||||
std::vector<Data::IndexedName>
|
||||
GeoFeature::getHigherElements(const char *element, bool silent) const
|
||||
{
|
||||
auto prop = getPropertyOfGeometry();
|
||||
if (!prop)
|
||||
return {};
|
||||
return prop->getComplexData()->getHigherElements(element, silent);
|
||||
}
|
||||
|
||||
+55
-3
@@ -24,7 +24,9 @@
|
||||
#ifndef APP_GEOFEATURE_H
|
||||
#define APP_GEOFEATURE_H
|
||||
|
||||
#include <memory>
|
||||
#include "DocumentObject.h"
|
||||
#include "MappedElement.h"
|
||||
#include "PropertyGeo.h"
|
||||
|
||||
|
||||
@@ -40,6 +42,7 @@ class AppExport GeoFeature : public App::DocumentObject
|
||||
|
||||
public:
|
||||
PropertyPlacement Placement;
|
||||
PropertyString _ElementMapVersion;
|
||||
|
||||
/// Constructor
|
||||
GeoFeature(void);
|
||||
@@ -80,10 +83,17 @@ public:
|
||||
* @param name: input name
|
||||
* @param type: desired element name type to return
|
||||
*
|
||||
* @return a pair(newName,oldName). New element name may be empty.
|
||||
* This function relies on ComplexGeoData::elementMapPrefix() to decide
|
||||
* whether it is a forward query, i.e. mapped -> original, or reverse
|
||||
* query. The reason being that, unlike ComplexGeoData who deals with the
|
||||
* actual element map data, GeoFeature here sits at a higher level.
|
||||
* GeoFeature should be dealing with whatever various PropertyLinkSub(s) is
|
||||
* assigned.
|
||||
*
|
||||
* This function currently is does nothing. The new style element name
|
||||
* generation will be added in the next batch of patches.
|
||||
* This function is made virtual, so that inherited class can do something
|
||||
* unusual, such as Sketcher::SketcherObject, which uses this to expose its
|
||||
* private geometries without a corresponding TopoShape, and yet being
|
||||
* source code compatible.
|
||||
*/
|
||||
virtual std::pair<std::string,std::string> getElementName(
|
||||
const char *name, ElementNameType type=Normal) const;
|
||||
@@ -107,6 +117,8 @@ public:
|
||||
bool append=false, ElementNameType type=Normal,
|
||||
const DocumentObject *filter=nullptr,const char **element=nullptr, GeoFeature **geo=nullptr);
|
||||
|
||||
static bool hasMissingElement(const char *subname);
|
||||
|
||||
/**
|
||||
* @brief Calculates the placement in the global reference coordinate system
|
||||
*
|
||||
@@ -120,6 +132,46 @@ public:
|
||||
* @return Base::Placement The transformation from the global reference coordinate system
|
||||
*/
|
||||
Base::Placement globalPlacement() const;
|
||||
|
||||
/** Search sub element using internal cached geometry
|
||||
*
|
||||
* @param element: element name
|
||||
* @param checkGeometry: search element by comparing geometry
|
||||
* @param tol: coordinate tolerance
|
||||
* @param atol: angle tolerance
|
||||
*
|
||||
* @return Returns a list of found element reference to the new goemetry.
|
||||
* The returned value will be invalidated when the geometry is changed.
|
||||
*
|
||||
* Before changing the property of geometry, GeoFeature will internally
|
||||
* make a snapshot of all referenced element geometry. After change, user
|
||||
* code may call this function to search for the new element name that
|
||||
* reference to the same geometry of the old element.
|
||||
*/
|
||||
virtual const std::vector<std::string>& searchElementCache(const std::string &element,
|
||||
bool checkGeometry = true,
|
||||
double tol = 1e-7,
|
||||
double atol = 1e-10) const;
|
||||
|
||||
|
||||
/// Return the object that owns the shape that contains the give element name
|
||||
virtual DocumentObject *getElementOwner(const Data::MappedName & /*name*/) const
|
||||
{return nullptr;}
|
||||
|
||||
virtual const std::vector<const char *>& getElementTypes(bool all=true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
virtual std::vector<Data::IndexedName> getHigherElements(const char *name, bool silent=false) const;
|
||||
|
||||
protected:
|
||||
virtual void onChanged(const Property* prop);
|
||||
virtual void onDocumentRestored();
|
||||
void updateElementReference();
|
||||
std::pair<std::string,std::string> _getElementName(const char *name, const Data::MappedElement &mapped) const;
|
||||
|
||||
private:
|
||||
std::vector<Data::MappedElement> _elementMapCache;
|
||||
std::string _elementMapVersion;
|
||||
};
|
||||
|
||||
} //namespace App
|
||||
|
||||
+23
-14
@@ -11,37 +11,46 @@
|
||||
FatherNamespace="App">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Jürgen Riegel" EMail="FreeCAD@juergen-riegel.net" />
|
||||
<UserDocu>This class does the whole placement and position handling</UserDocu>
|
||||
<UserDocu>App.GeoFeature class.\n
|
||||
Base class of all geometric document objects.
|
||||
This class does the whole placement and position handling.
|
||||
With the method `getPropertyOfGeometry` is possible to obtain
|
||||
the main geometric property in general form, without reference
|
||||
to any particular property name.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getPaths">
|
||||
<Documentation>
|
||||
<UserDocu>returns all possible paths to the root of the document</UserDocu>
|
||||
<UserDocu>getPaths()\n
|
||||
Returns all possible paths to the root of the document.
|
||||
Note: Not implemented.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getGlobalPlacement">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the placement of the object in the global coordinate space, respecting all stacked relationships.
|
||||
Note: This function is not available during recompute, as there the placements of parents can change
|
||||
after the execution of this object, rendering the result wrong.</UserDocu>
|
||||
<UserDocu>getGlobalPlacement() -> Base.Placement\n
|
||||
Returns the placement of the object in the global coordinate space, respecting all stacked
|
||||
relationships.
|
||||
Note: This function is not available during recompute, as there the placements of parents
|
||||
can change after the execution of this object, rendering the result wrong.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPropertyNameOfGeometry">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the property name of the actual geometry or None.
|
||||
For example for a part object it returns the value Shape,
|
||||
for a mesh the value Mesh and so on.
|
||||
<UserDocu>getPropertyNameOfGeometry() -> str or None\n
|
||||
Returns the property name of the actual geometry.
|
||||
For example for a Part feature it returns the value 'Shape', for a mesh feature the value
|
||||
'Mesh' and so on.
|
||||
If an object has no such property then None is returned.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPropertyOfGeometry">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the property of the actual geometry or None.
|
||||
For example for a part object it returns its Shape property,
|
||||
for a mesh its Mesh property and so on.
|
||||
<UserDocu>getPropertyOfGeometry() -> object or None\n
|
||||
Returns the property of the actual geometry.
|
||||
For example for a Part feature it returns its Shape property, for a Mesh feature its
|
||||
Mesh property and so on.
|
||||
If an object has no such property then None is returned.
|
||||
Unlike to getPropertyNameOfGeometry this function returns the geometry,
|
||||
not its name.
|
||||
</UserDocu>
|
||||
Unlike to getPropertyNameOfGeometry this function returns the geometry, not its name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<CustomAttributes />
|
||||
|
||||
@@ -256,12 +256,12 @@ PyObject* GroupExtensionPy::getObject(PyObject *args)
|
||||
PyObject* GroupExtensionPy::hasObject(PyObject *args)
|
||||
{
|
||||
PyObject *object;
|
||||
PyObject *recursivePy = nullptr;
|
||||
int recursive = 0;
|
||||
if (!PyArg_ParseTuple(args, "O!|O", &(DocumentObjectPy::Type), &object, &recursivePy))
|
||||
PyObject *recursivePy = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "O!|O!", &(DocumentObjectPy::Type), &object, &PyBool_Type, &recursivePy))
|
||||
return nullptr;
|
||||
|
||||
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
|
||||
bool recursive = PyObject_IsTrue(recursivePy) ? true : false;
|
||||
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->getNameInDocument()) {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an invalid object");
|
||||
return nullptr;
|
||||
@@ -270,14 +270,6 @@ PyObject* GroupExtensionPy::hasObject(PyObject *args)
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "Cannot check an object from another document with this group");
|
||||
return nullptr;
|
||||
}
|
||||
if (recursivePy) {
|
||||
recursive = PyObject_IsTrue(recursivePy);
|
||||
if ( recursive == -1) {
|
||||
// Note: shouldn't happen
|
||||
PyErr_SetString(PyExc_ValueError, "The recursive parameter should be of boolean type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool v = getGroupExtensionPtr()->hasObject(docObj->getDocumentObjectPtr(), recursive);
|
||||
return PyBool_FromLong(v ? 1 : 0);
|
||||
|
||||
+78
-13
@@ -232,14 +232,14 @@ void LinkBaseExtension::setProperty(int idx, Property *prop) {
|
||||
case PropLinkMode: {
|
||||
static const char *linkModeEnums[] = {"None","Auto Delete","Auto Link","Auto Unlink",nullptr};
|
||||
auto propLinkMode = static_cast<PropertyEnumeration*>(prop);
|
||||
if(!propLinkMode->getEnums())
|
||||
if(!propLinkMode->hasEnums())
|
||||
propLinkMode->setEnums(linkModeEnums);
|
||||
break;
|
||||
}
|
||||
case PropLinkCopyOnChange: {
|
||||
static const char *enums[] = {"Disabled","Enabled","Owned","Tracking",nullptr};
|
||||
auto propEnum = static_cast<PropertyEnumeration*>(prop);
|
||||
if(!propEnum->getEnums())
|
||||
if(!propEnum->hasEnums())
|
||||
propEnum->setEnums(enums);
|
||||
break;
|
||||
}
|
||||
@@ -554,7 +554,7 @@ void LinkBaseExtension::syncCopyOnChange()
|
||||
// so the last object will be the copy of the original linked object
|
||||
auto newLinked = copiedObjs.back();
|
||||
|
||||
// We are coping from the original linked object and we've already mutated
|
||||
// We are copying from the original linked object and we've already mutated
|
||||
// it, so we need to copy all CopyOnChange properties from the mutated
|
||||
// object to the new copy.
|
||||
std::vector<App::Property*> propList;
|
||||
@@ -905,7 +905,6 @@ void LinkBaseExtension::monitorOnChangeCopyObjects(
|
||||
if (getLinkCopyOnChangeValue() == CopyOnChangeDisabled)
|
||||
return;
|
||||
for(auto obj : objs) {
|
||||
obj->setStatus(App::ObjectStatus::TouchOnColorChange, true);
|
||||
copyOnChangeSrcConns.push_back(obj->signalChanged.connect(
|
||||
[this](const DocumentObject &, const Property &) {
|
||||
if (auto prop = this->getLinkCopyOnChangeTouchedProperty()) {
|
||||
@@ -1012,7 +1011,7 @@ int LinkBaseExtension::extensionSetElementVisible(const char *element, bool visi
|
||||
return -1;
|
||||
}
|
||||
|
||||
int LinkBaseExtension::extensionIsElementVisible(const char *element) {
|
||||
int LinkBaseExtension::extensionIsElementVisible(const char *element) const {
|
||||
int index = _getShowElementValue()?getElementIndex(element):getArrayIndex(element);
|
||||
if(index>=0) {
|
||||
auto propElementVis = getVisibilityListProperty();
|
||||
@@ -1409,12 +1408,21 @@ bool LinkBaseExtension::extensionGetSubObject(DocumentObject *&ret, const char *
|
||||
void LinkBaseExtension::checkGeoElementMap(const App::DocumentObject *obj,
|
||||
const App::DocumentObject *linked, PyObject **pyObj, const char *postfix) const
|
||||
{
|
||||
if(!pyObj || !*pyObj || (!postfix && obj->getDocument()==linked->getDocument()) ||
|
||||
!PyObject_TypeCheck(*pyObj, &Data::ComplexGeoDataPy::Type))
|
||||
if(!pyObj || !*pyObj || !PyObject_TypeCheck(*pyObj, &Data::ComplexGeoDataPy::Type))
|
||||
return;
|
||||
|
||||
// auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
|
||||
// geoData->reTagElementMap(obj->getID(),obj->getDocument()->Hasher,postfix);
|
||||
auto geoData = static_cast<Data::ComplexGeoDataPy*>(*pyObj)->getComplexGeoDataPtr();
|
||||
std::string _postfix;
|
||||
if (linked && obj && linked->getDocument() != obj->getDocument()) {
|
||||
_postfix = Data::ComplexGeoData::externalTagPostfix();
|
||||
if (postfix) {
|
||||
if (!boost::starts_with(postfix, Data::ComplexGeoData::elementMapPrefix()))
|
||||
_postfix += Data::ComplexGeoData::elementMapPrefix();
|
||||
_postfix += postfix;
|
||||
}
|
||||
postfix = _postfix.c_str();
|
||||
}
|
||||
geoData->reTagElementMap(obj->getID(),obj->getDocument()->getStringHasher(),postfix);
|
||||
}
|
||||
|
||||
void LinkBaseExtension::onExtendedUnsetupObject() {
|
||||
@@ -2177,10 +2185,12 @@ void LinkBaseExtension::expandSubname(std::string &subname) const {
|
||||
}
|
||||
|
||||
static bool isExcludedProperties(const char *name) {
|
||||
#define CHECK_EXCLUDE_PROP(_name) if(strcmp(name,#_name)==0) return true;
|
||||
CHECK_EXCLUDE_PROP(Shape);
|
||||
CHECK_EXCLUDE_PROP(Proxy);
|
||||
CHECK_EXCLUDE_PROP(Placement);
|
||||
if (boost::equals(name, "Shape"))
|
||||
return true;
|
||||
if (boost::equals(name, "Proxy"))
|
||||
return true;
|
||||
if (boost::equals(name, "Placement"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2204,6 +2214,61 @@ Property *LinkBaseExtension::extensionGetPropertyByName(const char* name) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<std::string> LinkBaseExtension::getHiddenSubnames(
|
||||
const App::DocumentObject *obj, const char *prefix)
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
if(!obj || !obj->getNameInDocument())
|
||||
return res;
|
||||
PropertyLinkSubHidden *prop;
|
||||
int depth=0;
|
||||
while((prop=Base::freecad_dynamic_cast<PropertyLinkSubHidden>(
|
||||
obj->getPropertyByName("ColoredElements"))))
|
||||
{
|
||||
for(auto &v : prop->getShadowSubs()) {
|
||||
if(prefix && !boost::starts_with(v.first,prefix) && !boost::starts_with(v.second,prefix))
|
||||
continue;
|
||||
auto &s = v.second;
|
||||
if(boost::ends_with(s,DocumentObject::hiddenMarker()))
|
||||
res.push_back(s.substr(0,s.size()-DocumentObject::hiddenMarker().size()));
|
||||
}
|
||||
auto o = Base::freecad_dynamic_cast<DocumentObject>(prop->getContainer());
|
||||
if(!o)
|
||||
break;
|
||||
o = o->getLinkedObject(false);
|
||||
if(o==obj || !GetApplication().checkLinkDepth(++depth,true))
|
||||
break;
|
||||
obj = o;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool LinkBaseExtension::isSubnameHidden(const App::DocumentObject *obj, const char *subname)
|
||||
{
|
||||
if(!obj || !obj->getNameInDocument() || !subname || !subname[0])
|
||||
return false;
|
||||
PropertyLinkSubHidden *prop;
|
||||
int depth=0;
|
||||
while((prop=Base::freecad_dynamic_cast<PropertyLinkSubHidden>(
|
||||
obj->getPropertyByName("ColoredElements"))))
|
||||
{
|
||||
for(auto &v : prop->getShadowSubs()) {
|
||||
if((boost::starts_with(v.first,subname) || boost::starts_with(v.second,subname))
|
||||
&& boost::ends_with(v.second, DocumentObject::hiddenMarker()))
|
||||
return true;
|
||||
}
|
||||
auto o = Base::freecad_dynamic_cast<DocumentObject>(prop->getContainer());
|
||||
if(!o)
|
||||
break;
|
||||
o = o->getLinkedObject(false);
|
||||
if(o==obj || !GetApplication().checkLinkDepth(++depth,true))
|
||||
break;
|
||||
obj = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LinkBaseExtension::isLinkMutated() const
|
||||
{
|
||||
return getLinkCopyOnChangeValue() != CopyOnChangeDisabled
|
||||
|
||||
+6
-1
@@ -293,7 +293,7 @@ public:
|
||||
virtual void onExtendedDocumentRestored() override;
|
||||
|
||||
virtual int extensionSetElementVisible(const char *, bool) override;
|
||||
virtual int extensionIsElementVisible(const char *) override;
|
||||
virtual int extensionIsElementVisible(const char *) const override;
|
||||
virtual bool extensionHasChildElement() const override;
|
||||
|
||||
virtual PyObject* getExtensionPyObject(void) override;
|
||||
@@ -304,6 +304,11 @@ public:
|
||||
int getElementIndex(const char *subname, const char **psubname=nullptr) const;
|
||||
void elementNameFromIndex(int idx, std::ostream &ss) const;
|
||||
|
||||
static std::vector<std::string> getHiddenSubnames(
|
||||
const App::DocumentObject *obj, const char *prefix=0);
|
||||
|
||||
static bool isSubnameHidden(const App::DocumentObject *obj, const char *subname);
|
||||
|
||||
DocumentObject *getContainer();
|
||||
const DocumentObject *getContainer() const;
|
||||
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cstdlib>
|
||||
# include <unordered_set>
|
||||
#endif
|
||||
|
||||
#include <QHash>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "DocumentObject.h"
|
||||
#include "MappedElement.h"
|
||||
|
||||
using namespace Data;
|
||||
|
||||
struct ByteArray
|
||||
{
|
||||
ByteArray(const QByteArray &b)
|
||||
:bytes(b)
|
||||
{}
|
||||
|
||||
ByteArray(const ByteArray &other)
|
||||
:bytes(other.bytes)
|
||||
{}
|
||||
|
||||
ByteArray(ByteArray &&other)
|
||||
:bytes(std::move(other.bytes))
|
||||
{}
|
||||
|
||||
void mutate() const
|
||||
{
|
||||
QByteArray copy;
|
||||
copy.append(bytes.constData(), bytes.size());
|
||||
bytes = copy;
|
||||
}
|
||||
|
||||
bool operator==(const ByteArray & other) const {
|
||||
return bytes == other.bytes;
|
||||
}
|
||||
|
||||
mutable QByteArray bytes;
|
||||
};
|
||||
|
||||
struct ByteArrayHasher
|
||||
{
|
||||
std::size_t operator()(const ByteArray &bytes) const
|
||||
{
|
||||
return qHash(bytes.bytes);
|
||||
}
|
||||
|
||||
std::size_t operator()(const QByteArray &bytes) const
|
||||
{
|
||||
return qHash(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
void IndexedName::set(const char *name,
|
||||
int len,
|
||||
const std::vector<const char*> &types,
|
||||
bool allowOthers)
|
||||
{
|
||||
static std::unordered_set<ByteArray, ByteArrayHasher> NameSet;
|
||||
|
||||
if (len < 0)
|
||||
len = static_cast<int>(std::strlen(name));
|
||||
int i;
|
||||
for (i=len-1; i>=0; --i) {
|
||||
if (name[i]<'0' || name[i]>'9')
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
this->index = std::atoi(name+i);
|
||||
|
||||
for (int j=0; j<i; ++j) {
|
||||
if (name[j] == '_'
|
||||
|| (name[j] >= 'a' && name[j] <= 'z' )
|
||||
|| (name[j] >= 'A' && name[j] <= 'Z'))
|
||||
continue;
|
||||
this->type = "";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const char * type : types) {
|
||||
int j=0;
|
||||
for (const char *n=name, *t=type; *n; ++n) {
|
||||
if (*n != *t || j >= i)
|
||||
break;
|
||||
++j;
|
||||
++t;
|
||||
if (!*t) {
|
||||
this->type = type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowOthers) {
|
||||
auto res = NameSet.insert(QByteArray::fromRawData(name, i));
|
||||
if (res.second)
|
||||
res.first->mutate();
|
||||
this->type = res.first->bytes.constData();
|
||||
} else
|
||||
this->type = "";
|
||||
}
|
||||
|
||||
void MappedName::compact() const
|
||||
{
|
||||
auto self = const_cast<MappedName*>(this);
|
||||
|
||||
if (this->raw) {
|
||||
self->data = QByteArray(self->data.constData(), self->data.size());
|
||||
self->raw = false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static std::unordered_set<QByteArray, ByteArrayHasher> PostfixSet;
|
||||
if (this->postfix.size()) {
|
||||
auto res = PostfixSet.insert(this->postfix);
|
||||
if (!res.second)
|
||||
self->postfix = *res.first;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ElementNameComp::operator()(const MappedName &a, const MappedName &b) const {
|
||||
size_t size = std::min(a.size(),b.size());
|
||||
if(!size)
|
||||
return a.size()<b.size();
|
||||
size_t i=0;
|
||||
if(b[0] == '#') {
|
||||
if(a[0]!='#')
|
||||
return true;
|
||||
// If both string starts with '#', compare the following hex digits by
|
||||
// its integer value.
|
||||
int res = 0;
|
||||
for(i=1;i<size;++i) {
|
||||
unsigned char ac = (unsigned char)a[i];
|
||||
unsigned char bc = (unsigned char)b[i];
|
||||
if(std::isxdigit(bc)) {
|
||||
if(!std::isxdigit(ac))
|
||||
return true;
|
||||
if(res==0) {
|
||||
if(ac<bc)
|
||||
res = -1;
|
||||
else if(ac>bc)
|
||||
res = 1;
|
||||
}
|
||||
}else if(std::isxdigit(ac))
|
||||
return false;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(res < 0)
|
||||
return true;
|
||||
else if(res > 0)
|
||||
return false;
|
||||
|
||||
for (; i<size; ++i) {
|
||||
char ac = a[i];
|
||||
char bc = b[i];
|
||||
if (ac < bc)
|
||||
return true;
|
||||
if (ac > bc)
|
||||
return false;
|
||||
}
|
||||
return a.size()<b.size();
|
||||
}
|
||||
else if (a[0] == '#')
|
||||
return false;
|
||||
|
||||
// If the string does not start with '#', compare the non-digits prefix
|
||||
// using lexical order.
|
||||
for(i=0;i<size;++i) {
|
||||
unsigned char ac = (unsigned char)a[i];
|
||||
unsigned char bc = (unsigned char)b[i];
|
||||
if(!std::isdigit(bc)) {
|
||||
if(std::isdigit(ac))
|
||||
return true;
|
||||
if(ac<bc)
|
||||
return true;
|
||||
if(ac>bc)
|
||||
return false;
|
||||
} else if(!std::isdigit(ac)) {
|
||||
return false;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// Then compare the following digits part by integer value
|
||||
int res = 0;
|
||||
for(;i<size;++i) {
|
||||
unsigned char ac = (unsigned char)a[i];
|
||||
unsigned char bc = (unsigned char)b[i];
|
||||
if(std::isdigit(bc)) {
|
||||
if(!std::isdigit(ac))
|
||||
return true;
|
||||
if(res==0) {
|
||||
if(ac<bc)
|
||||
res = -1;
|
||||
else if(ac>bc)
|
||||
res = 1;
|
||||
}
|
||||
}else if(std::isdigit(ac))
|
||||
return false;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if(res < 0)
|
||||
return true;
|
||||
else if(res > 0)
|
||||
return false;
|
||||
|
||||
// Finally, compare the remaining tail using lexical order
|
||||
for (; i<size; ++i) {
|
||||
char ac = a[i];
|
||||
char bc = b[i];
|
||||
if (ac < bc)
|
||||
return true;
|
||||
if (ac > bc)
|
||||
return false;
|
||||
}
|
||||
return a.size()<b.size();
|
||||
}
|
||||
|
||||
HistoryItem::HistoryItem(App::DocumentObject *obj, const Data::MappedName &name)
|
||||
:obj(obj),tag(0),element(name)
|
||||
{
|
||||
if(obj)
|
||||
tag = obj->getID();
|
||||
}
|
||||
|
||||
const std::string & MappedChildElements::prefix()
|
||||
{
|
||||
static std::string _prefix(ComplexGeoData::elementMapPrefix() + ":R");
|
||||
return _prefix;
|
||||
}
|
||||
Executable
+847
@@ -0,0 +1,847 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2022 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef _AppMappedElement_h_
|
||||
#define _AppMappedElement_h_
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include "ComplexGeoData.h"
|
||||
#include "StringHasher.h"
|
||||
|
||||
namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
}
|
||||
|
||||
namespace Data
|
||||
{
|
||||
|
||||
class AppExport IndexedName {
|
||||
public:
|
||||
explicit IndexedName(const char *name = nullptr, int _index = 0)
|
||||
: index(0)
|
||||
{
|
||||
if (!name)
|
||||
this->type = "";
|
||||
else {
|
||||
set(name);
|
||||
if (_index)
|
||||
this->index = _index;
|
||||
}
|
||||
}
|
||||
|
||||
IndexedName(const char *name,
|
||||
const std::vector<const char*> & types,
|
||||
bool allowOthers=true)
|
||||
{
|
||||
set(name, -1, types, allowOthers);
|
||||
}
|
||||
|
||||
explicit IndexedName(const QByteArray & data)
|
||||
{
|
||||
set(data.constData(), data.size());
|
||||
}
|
||||
|
||||
IndexedName(const IndexedName &other)
|
||||
: type(other.type), index(other.index)
|
||||
{}
|
||||
|
||||
static IndexedName fromConst(const char *name, int index) {
|
||||
IndexedName res;
|
||||
res.type = name;
|
||||
res.index = index;
|
||||
return res;
|
||||
}
|
||||
|
||||
IndexedName & operator=(const IndexedName & other)
|
||||
{
|
||||
this->index = other.index;
|
||||
this->type = other.type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & s, const IndexedName & e)
|
||||
{
|
||||
s << e.type;
|
||||
if (e.index > 0)
|
||||
s << e.index;
|
||||
return s;
|
||||
}
|
||||
|
||||
bool operator==(const IndexedName & other) const
|
||||
{
|
||||
return this->index == other.index
|
||||
&& (this->type == other.type
|
||||
|| std::strcmp(this->type, other.type)==0);
|
||||
}
|
||||
|
||||
IndexedName & operator+=(int offset)
|
||||
{
|
||||
this->index += offset;
|
||||
assert(this->index >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IndexedName & operator++()
|
||||
{
|
||||
++this->index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IndexedName & operator--()
|
||||
{
|
||||
--this->index;
|
||||
assert(this->index >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const IndexedName & other) const
|
||||
{
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
const char * toString(std::string & s) const
|
||||
{
|
||||
// Note! s is not cleared on purpose.
|
||||
std::size_t offset = s.size();
|
||||
s += this->type;
|
||||
if (this->index > 0)
|
||||
s += std::to_string(this->index);
|
||||
return s.c_str() + offset;
|
||||
}
|
||||
|
||||
int compare(const IndexedName & other) const
|
||||
{
|
||||
int res = std::strcmp(this->type, other.type);
|
||||
if (res)
|
||||
return res;
|
||||
if (this->index < other.index)
|
||||
return -1;
|
||||
if (this->index > other.index)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator<(const IndexedName & other) const
|
||||
{
|
||||
return compare(other) < 0;
|
||||
}
|
||||
|
||||
char operator[](int index) const
|
||||
{
|
||||
return this->type[index];
|
||||
}
|
||||
|
||||
const char * getType() const { return this->type; }
|
||||
|
||||
int getIndex() const { return this->index; }
|
||||
|
||||
void setIndex(int index) { assert(index>=0); this->index = index; }
|
||||
|
||||
bool isNull() const { return !this->type[0]; }
|
||||
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
protected:
|
||||
void set(const char *,
|
||||
int len = -1,
|
||||
const std::vector<const char *> &types = {},
|
||||
bool allowOthers = true);
|
||||
|
||||
private:
|
||||
const char * type;
|
||||
int index;
|
||||
};
|
||||
|
||||
class AppExport MappedName
|
||||
{
|
||||
public:
|
||||
MappedName()
|
||||
:raw(false)
|
||||
{}
|
||||
|
||||
#if QT_VERSION >= 0x050200
|
||||
MappedName(MappedName &&other)
|
||||
:data(std::move(other.data))
|
||||
,postfix(std::move(other.postfix))
|
||||
,raw(other.raw)
|
||||
{}
|
||||
|
||||
MappedName & operator=(MappedName &&other)
|
||||
{
|
||||
this->data = std::move(other.data);
|
||||
this->postfix = std::move(other.postfix);
|
||||
this->raw = other.raw;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
explicit MappedName(const char * name, int size = -1)
|
||||
:raw(false)
|
||||
{
|
||||
if (!name) return;
|
||||
if (boost::starts_with(name, ComplexGeoData::elementMapPrefix()))
|
||||
name += ComplexGeoData::elementMapPrefix().size();
|
||||
if (size < 0)
|
||||
data = QByteArray(name);
|
||||
else
|
||||
data = QByteArray(name, size);
|
||||
}
|
||||
|
||||
explicit MappedName(const std::string & name)
|
||||
{
|
||||
int size = name.size();
|
||||
const char *n = name.c_str();
|
||||
if (boost::starts_with(name, ComplexGeoData::elementMapPrefix())) {
|
||||
n += ComplexGeoData::elementMapPrefix().size();
|
||||
size -= ComplexGeoData::elementMapPrefix().size();
|
||||
}
|
||||
data = QByteArray(n, size);
|
||||
}
|
||||
|
||||
explicit MappedName(const IndexedName & element)
|
||||
:data(element.getType()), raw(false)
|
||||
{
|
||||
if (element.getIndex() > 0)
|
||||
data += QByteArray::number(element.getIndex());
|
||||
}
|
||||
|
||||
explicit MappedName(const App::StringIDRef & sid)
|
||||
:raw(false)
|
||||
{
|
||||
sid.toBytes(this->data);
|
||||
}
|
||||
|
||||
MappedName(const MappedName & other)
|
||||
:data(other.data), postfix(other.postfix), raw(other.raw)
|
||||
{}
|
||||
|
||||
MappedName(const MappedName & other, int from, int size = -1)
|
||||
: raw(false)
|
||||
{
|
||||
append(other, from, size);
|
||||
}
|
||||
|
||||
MappedName(const MappedName & other, const char *postfix)
|
||||
:data(other.data + other.postfix)
|
||||
,postfix(postfix)
|
||||
,raw(false)
|
||||
{}
|
||||
|
||||
static MappedName fromRawData(const char * name, int size = -1)
|
||||
{
|
||||
MappedName res;
|
||||
if (name) {
|
||||
res.data = QByteArray::fromRawData(name,
|
||||
size>=0 ? size: qstrlen(name));
|
||||
res.raw = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static MappedName fromRawData(const QByteArray & data)
|
||||
{
|
||||
return fromRawData(data.constData(), data.size());
|
||||
}
|
||||
|
||||
static MappedName fromRawData(const MappedName &other, int from, int size = -1)
|
||||
{
|
||||
if (from < 0)
|
||||
from = 0;
|
||||
|
||||
if (from >= other.size())
|
||||
return MappedName();
|
||||
|
||||
if (from >= other.data.size())
|
||||
return MappedName(other, from, size);
|
||||
|
||||
MappedName res;
|
||||
res.raw = true;
|
||||
if (size < 0)
|
||||
size = other.size() - from;
|
||||
|
||||
if (size < other.data.size()-from)
|
||||
res.data = QByteArray::fromRawData(
|
||||
other.data.constData()+from, size);
|
||||
else {
|
||||
res.data = QByteArray::fromRawData(
|
||||
other.data.constData()+from, other.data.size()-from);
|
||||
size -= other.data.size() - from;
|
||||
if (size == other.postfix.size())
|
||||
res.postfix = other.postfix;
|
||||
else if (size)
|
||||
res.postfix.append(other.postfix.constData(), size);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
MappedName & operator=(const MappedName & other)
|
||||
{
|
||||
this->data = other.data;
|
||||
this->postfix = other.postfix;
|
||||
this->raw = other.raw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedName & operator=(const std::string & other)
|
||||
{
|
||||
*this = MappedName(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedName & operator=(const char * other)
|
||||
{
|
||||
*this = MappedName(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream & operator<<(std::ostream & s, const MappedName & n)
|
||||
{
|
||||
s.write(n.data.constData(), n.data.size());
|
||||
s.write(n.postfix.constData(), n.postfix.size());
|
||||
return s;
|
||||
}
|
||||
|
||||
bool operator==(const MappedName & other) const
|
||||
{
|
||||
if (this->size() != other.size())
|
||||
return false;
|
||||
if (this->data.size() == other.data.size())
|
||||
return this->data == other.data && this->postfix == other.postfix;
|
||||
const auto &a = this->data.size() < other.data.size() ? *this : other;
|
||||
const auto &b = this->data.size() < other.data.size() ? other: *this;
|
||||
if (!b.data.startsWith(a.data))
|
||||
return false;
|
||||
QByteArray tmp = QByteArray::fromRawData(
|
||||
b.data.constData() + a.data.size(),
|
||||
b.data.size() - a.data.size());
|
||||
if (!a.postfix.startsWith(tmp))
|
||||
return false;
|
||||
tmp = QByteArray::fromRawData(
|
||||
a.postfix.constData() + tmp.size(),
|
||||
a.postfix.size() - tmp.size());
|
||||
return tmp == b.postfix;
|
||||
}
|
||||
|
||||
bool operator!=(const MappedName & other) const
|
||||
{
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
MappedName operator+(const MappedName & other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
res += other;
|
||||
return res;
|
||||
}
|
||||
|
||||
MappedName operator+(const char * other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
res += other;
|
||||
return res;
|
||||
}
|
||||
|
||||
MappedName operator+(const std::string & other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
res += other;
|
||||
return res;
|
||||
}
|
||||
|
||||
MappedName operator+(const QByteArray & other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
res += other;
|
||||
return res;
|
||||
}
|
||||
|
||||
MappedName & operator+=(const char * other)
|
||||
{
|
||||
if (other && other[0])
|
||||
this->postfix.append(other, -1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedName & operator+=(const std::string & other)
|
||||
{
|
||||
if (other.size()) {
|
||||
this->postfix.reserve(this->postfix.size() + other.size());
|
||||
this->postfix.append(other.c_str(), other.size());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedName & operator+=(const QByteArray & other)
|
||||
{
|
||||
this->postfix += other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedName & operator+=(const MappedName & other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void append(const char * d, int size = -1)
|
||||
{
|
||||
if (d && size) {
|
||||
if (size < 0)
|
||||
size = qstrlen(d);
|
||||
if (empty())
|
||||
this->data.append(d, size);
|
||||
else
|
||||
this->postfix.append(d, size);
|
||||
}
|
||||
}
|
||||
|
||||
void append(const MappedName & other, int from = 0, int size = -1)
|
||||
{
|
||||
if (from < 0)
|
||||
from = 0;
|
||||
else if (from > other.size())
|
||||
return;
|
||||
if (size < 0 || size + from > other.size())
|
||||
size = other.size() - from;
|
||||
|
||||
int count = size;
|
||||
if (from < other.data.size()) {
|
||||
if (count > other.data.size() - from)
|
||||
count = other.data.size() - from;
|
||||
if (from == 0 && count == other.data.size() && this->empty()) {
|
||||
this->data = other.data;
|
||||
this->raw = other.raw;
|
||||
} else
|
||||
append(other.data.constData() + from, count);
|
||||
from = 0;
|
||||
size -= count;
|
||||
} else
|
||||
from -= other.data.size();
|
||||
if (size) {
|
||||
if (from == 0 && size == other.postfix.size()) {
|
||||
if (this->empty())
|
||||
this->data = other.postfix;
|
||||
else if (this->postfix.isEmpty())
|
||||
this->postfix = other.postfix;
|
||||
else
|
||||
this->postfix += other.postfix;
|
||||
} else
|
||||
append(other.postfix.constData() + from, size);
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString(int from, int len=-1) const
|
||||
{
|
||||
std::string res;
|
||||
return toString(res, from, len);
|
||||
}
|
||||
|
||||
const char * toString(std::string &s, int from=0, int len=-1) const
|
||||
{
|
||||
std::size_t offset = s.size();
|
||||
int count = this->size();
|
||||
if (from < 0)
|
||||
from = 0;
|
||||
else if (from >= count)
|
||||
return s.c_str()+s.size();
|
||||
if (len < 0 || len > count - from)
|
||||
len = count - from;
|
||||
s.reserve(s.size() + len);
|
||||
if (from < this->data.size()) {
|
||||
count = this->data.size() - from;
|
||||
if (len < count)
|
||||
count = len;
|
||||
s.append(this->data.constData()+from, count);
|
||||
len -= count;
|
||||
}
|
||||
s.append(this->postfix.constData(), len);
|
||||
return s.c_str() + offset;
|
||||
}
|
||||
|
||||
const char * toConstString(int offset, int &size) const
|
||||
{
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
if (offset > this->data.size()) {
|
||||
offset -= this->data.size();
|
||||
if (offset > this->postfix.size()) {
|
||||
size = 0;
|
||||
return "";
|
||||
}
|
||||
size = this->postfix.size() - offset;
|
||||
return this->postfix.constData() + offset;
|
||||
}
|
||||
size = this->data.size() - offset;
|
||||
return this->data.constData() + offset;
|
||||
}
|
||||
|
||||
QByteArray toRawBytes(int offset=0, int size=-1) const
|
||||
{
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
if (offset >= this->size())
|
||||
return QByteArray();
|
||||
if (size < 0 || size > this->size() - offset)
|
||||
size = this->size() - offset;
|
||||
if (offset >= this->data.size()) {
|
||||
offset -= this->data.size();
|
||||
return QByteArray::fromRawData(this->postfix.constData()+offset, size);
|
||||
}
|
||||
if (size <= this->data.size() - offset)
|
||||
return QByteArray::fromRawData(this->data.constData()+offset, size);
|
||||
|
||||
QByteArray res(this->data.constData()+offset, this->data.size()-offset);
|
||||
res.append(this->postfix.constData(), size - this->data.size() + offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
const QByteArray & dataBytes() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
const QByteArray & postfixBytes() const
|
||||
{
|
||||
return this->postfix;
|
||||
}
|
||||
|
||||
const char * constPostfix() const
|
||||
{
|
||||
return this->postfix.constData();
|
||||
}
|
||||
|
||||
// No constData() because 'data' is allow to contain raw data, which may
|
||||
// not end with 0.
|
||||
#if 0
|
||||
void char * constData() const
|
||||
{
|
||||
return this->data.constData();
|
||||
}
|
||||
#endif
|
||||
|
||||
QByteArray toBytes() const
|
||||
{
|
||||
if (this->postfix.isEmpty())
|
||||
return this->data;
|
||||
if (this->data.isEmpty())
|
||||
return this->postfix;
|
||||
return this->data + this->postfix;
|
||||
}
|
||||
|
||||
IndexedName toIndexedName() const
|
||||
{
|
||||
if (this->postfix.isEmpty())
|
||||
return IndexedName(this->data);
|
||||
return IndexedName();
|
||||
}
|
||||
|
||||
std::string toPrefixedString() const
|
||||
{
|
||||
std::string res;
|
||||
toPrefixedString(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
const char *toPrefixedString(std::string &buf) const
|
||||
{
|
||||
if (!toIndexedName())
|
||||
buf += ComplexGeoData::elementMapPrefix();
|
||||
toString(buf);
|
||||
return buf.c_str();
|
||||
}
|
||||
|
||||
int compare(const MappedName &other) const
|
||||
{
|
||||
int asize = this->size();
|
||||
int bsize = other.size();
|
||||
for (int i=0, count=std::min(asize, bsize); i<count; ++i) {
|
||||
char a = this->operator[](i);
|
||||
char b = other[i];
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a > b)
|
||||
return 1;
|
||||
}
|
||||
if (asize < bsize)
|
||||
return -1;
|
||||
if (asize > bsize)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool operator<(const MappedName & other) const
|
||||
{
|
||||
return compare(other) < 0;
|
||||
}
|
||||
|
||||
char operator[](int index) const
|
||||
{
|
||||
if (index >= this->data.size())
|
||||
return this->postfix[index - this->data.size()];
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return this->data.size() + this->postfix.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->data.isEmpty() && this->postfix.isEmpty();
|
||||
}
|
||||
|
||||
bool isRaw() const
|
||||
{
|
||||
return this->raw;
|
||||
}
|
||||
|
||||
MappedName copy() const
|
||||
{
|
||||
if (!this->raw)
|
||||
return *this;
|
||||
MappedName res;
|
||||
res.data.append(this->data.constData(), this->data.size());
|
||||
res.postfix = this->postfix;
|
||||
return res;
|
||||
}
|
||||
|
||||
void compact() const;
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !empty();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->data.clear();
|
||||
this->postfix.clear();
|
||||
this->raw = false;
|
||||
}
|
||||
|
||||
int find(const char *d, int from = 0) const
|
||||
{
|
||||
if (!d)
|
||||
return -1;
|
||||
if (from < 0)
|
||||
from = 0;
|
||||
if (from < this->data.size()) {
|
||||
int res = this->data.indexOf(d, from);
|
||||
if (res >= 0)
|
||||
return res;
|
||||
from = 0;
|
||||
} else
|
||||
from -= this->data.size();
|
||||
int res = this->postfix.indexOf(d, from);
|
||||
if (res < 0)
|
||||
return res;
|
||||
return res + this->data.size();
|
||||
}
|
||||
|
||||
int find(const std::string &d, int from = 0) const
|
||||
{
|
||||
return find(d.c_str(), from);
|
||||
}
|
||||
|
||||
int rfind(const char *d, int from = -1) const
|
||||
{
|
||||
if (!d)
|
||||
return -1;
|
||||
if (from < 0 || from > this->postfix.size()) {
|
||||
if (from > postfix.size())
|
||||
from -= postfix.size();
|
||||
int res = this->postfix.lastIndexOf(d, from);
|
||||
if (res >= 0)
|
||||
return res + this->data.size();
|
||||
from = -1;
|
||||
}
|
||||
return this->data.lastIndexOf(d, from);
|
||||
}
|
||||
|
||||
int rfind(const std::string &d, int from = -1) const
|
||||
{
|
||||
return rfind(d.c_str(), from);
|
||||
}
|
||||
|
||||
bool endsWith(const char *s) const
|
||||
{
|
||||
if (!s)
|
||||
return false;
|
||||
if (this->postfix.size())
|
||||
return this->postfix.endsWith(s);
|
||||
return this->data.endsWith(s);
|
||||
}
|
||||
|
||||
bool endsWith(const std::string &s) const
|
||||
{
|
||||
return endsWith(s.c_str());
|
||||
}
|
||||
|
||||
bool startsWith(const QByteArray & s, int offset = 0) const
|
||||
{
|
||||
if (s.size() > size() - offset)
|
||||
return false;
|
||||
if (offset || (this->data.size() && this->data.size() < s.size()))
|
||||
return toRawBytes(offset, s.size()) == s;
|
||||
if (this->data.size())
|
||||
return this->data.startsWith(s);
|
||||
return this->postfix.startsWith(s);
|
||||
}
|
||||
|
||||
bool startsWith(const char *s, int offset = 0) const
|
||||
{
|
||||
if (!s)
|
||||
return false;
|
||||
return startsWith(QByteArray::fromRawData(s, qstrlen(s)), offset);
|
||||
}
|
||||
|
||||
bool startsWith(const std::string &s, int offset = 0) const
|
||||
{
|
||||
return startsWith(QByteArray::fromRawData(s.c_str(), s.size()), offset);
|
||||
}
|
||||
|
||||
std::size_t hash() const
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return qHash(data, qHash(postfix));
|
||||
#else
|
||||
return qHash(data) ^ qHash(postfix);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray data;
|
||||
QByteArray postfix;
|
||||
bool raw;
|
||||
};
|
||||
|
||||
struct AppExport MappedElement
|
||||
{
|
||||
IndexedName index;
|
||||
MappedName name;
|
||||
|
||||
MappedElement()
|
||||
{}
|
||||
|
||||
MappedElement(const IndexedName & idx, const MappedName & n)
|
||||
: index(idx), name(n)
|
||||
{}
|
||||
|
||||
MappedElement(const MappedName & n, const IndexedName & idx)
|
||||
: index(idx), name(n)
|
||||
{}
|
||||
|
||||
MappedElement(const MappedElement & other)
|
||||
: index(other.index), name(other.name)
|
||||
{}
|
||||
|
||||
MappedElement(MappedElement && other)
|
||||
: index(std::move(other.index)), name(std::move(other.name))
|
||||
{}
|
||||
|
||||
MappedElement & operator=(MappedElement && other)
|
||||
{
|
||||
this->index = std::move(other.index);
|
||||
this->name = std::move(other.name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MappedElement & operator=(const MappedElement & other)
|
||||
{
|
||||
this->index = other.index;
|
||||
this->name = other.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const MappedElement &other) const
|
||||
{
|
||||
return this->index == other.index && this->name == other.name;
|
||||
}
|
||||
|
||||
bool operator!=(const MappedElement &other) const
|
||||
{
|
||||
return this->index != other.index || this->name != other.name;
|
||||
}
|
||||
|
||||
bool operator<(const MappedElement &other) const
|
||||
{
|
||||
int res = this->index.compare(other.index);
|
||||
if (res < 0)
|
||||
return true;
|
||||
if (res > 0)
|
||||
return false;
|
||||
return this->name < other.name;
|
||||
}
|
||||
};
|
||||
|
||||
struct AppExport HistoryItem {
|
||||
App::DocumentObject *obj;
|
||||
long tag;
|
||||
Data::MappedName element;
|
||||
Data::IndexedName index;
|
||||
std::vector<Data::MappedName> intermediates;
|
||||
HistoryItem(App::DocumentObject *obj, const Data::MappedName &name);
|
||||
};
|
||||
|
||||
struct AppExport ElementNameComp {
|
||||
/** Comparison function to make topo name more stable
|
||||
*
|
||||
* The sorting decompose the name into either of the following two forms
|
||||
* '#' + hex_digits + tail
|
||||
* non_digits + digits + tail
|
||||
*
|
||||
* The non-digits part is compared lexically, while the digits part is
|
||||
* compared by its integer value.
|
||||
*
|
||||
* The reason for this is to prevent name with bigger digits (usually means
|
||||
* comes late in history) comes early when sorting.
|
||||
*/
|
||||
bool operator()(const MappedName &a, const MappedName &b) const;
|
||||
};
|
||||
|
||||
typedef QVector<App::StringIDRef> ElementIDRefs;
|
||||
|
||||
struct AppExport MappedChildElements
|
||||
{
|
||||
IndexedName indexedName;
|
||||
int count;
|
||||
int offset;
|
||||
long tag;
|
||||
ElementMapPtr elementMap;
|
||||
QByteArray postfix;
|
||||
ElementIDRefs sids;
|
||||
|
||||
static const std::string & prefix();
|
||||
};
|
||||
|
||||
} //namespace Data
|
||||
|
||||
|
||||
#endif
|
||||
@@ -41,8 +41,8 @@ namespace App {
|
||||
class XMLMergeReader : public Base::XMLReader
|
||||
{
|
||||
public:
|
||||
XMLMergeReader(std::map<std::string, std::string>& name, const char* FileName, std::istream& str)
|
||||
: Base::XMLReader(FileName, str), nameMap(name)
|
||||
XMLMergeReader(std::map<std::string, std::string>& name, Base::Reader &reader)
|
||||
: Base::XMLReader(reader), nameMap(name)
|
||||
{}
|
||||
|
||||
void addName(const char* s1, const char* s2)
|
||||
@@ -152,7 +152,8 @@ MergeDocuments::importObjects(std::istream& input)
|
||||
{
|
||||
this->nameMap.clear();
|
||||
this->stream = new zipios::ZipInputStream(input);
|
||||
XMLMergeReader reader(this->nameMap,"<memory>", *stream);
|
||||
Base::ZipReader zreader(*this->stream,std::string("<memory>"));
|
||||
XMLMergeReader reader(this->nameMap, zreader);
|
||||
reader.setVerbose(isVerbose());
|
||||
std::vector<App::DocumentObject*> objs = appdoc->importObjects(reader);
|
||||
|
||||
@@ -166,7 +167,7 @@ void MergeDocuments::importObject(const std::vector<App::DocumentObject*>& o, Ba
|
||||
{
|
||||
objects = o;
|
||||
Restore(r);
|
||||
r.readFiles(*this->stream);
|
||||
r.readFiles();
|
||||
}
|
||||
|
||||
void MergeDocuments::exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer & w)
|
||||
|
||||
@@ -458,7 +458,7 @@ bool Metadata::satisfies(const Meta::Dependency& dep)
|
||||
}
|
||||
auto parsedExpression = App::Expression::parse(nullptr, dep.condition);
|
||||
auto result = parsedExpression->eval();
|
||||
if (boost::any_cast<bool> (result->getValueAsAny()) == false)
|
||||
if (!boost::any_cast<bool> (result->getValueAsAny()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+88
-62
@@ -16,181 +16,207 @@
|
||||
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Chris Hennes" EMail="chennes@pioneerlibrarysystem.org" />
|
||||
<UserDocu>
|
||||
Metadata
|
||||
A Metadata object reads an XML-formatted package metadata file and provides read-only access to its contents.
|
||||
|
||||
A single constructor is supported:
|
||||
Metadata(file) -- Reads the XML file and provides access to the metadata it specifies.
|
||||
</UserDocu>
|
||||
<UserDocu>App.Metadata class.\n
|
||||
A Metadata object reads an XML-formatted package metadata file and provides
|
||||
read-only access to its contents.\n
|
||||
The following constructors are supported:\n
|
||||
Metadata()
|
||||
Empty constructor.\n
|
||||
Metadata(metadata)
|
||||
Copy constructor.
|
||||
metadata : App.Metadata\n
|
||||
Metadata(file)
|
||||
Reads the XML file and provides access to the metadata it specifies.
|
||||
file : str\n XML file name.</UserDocu>
|
||||
<DeveloperDocu>Metadata</DeveloperDocu>
|
||||
</Documentation>
|
||||
|
||||
<Attribute Name="Name" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>String: the name of this item</UserDocu>
|
||||
<UserDocu>String representing the name of this item.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Name" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Version" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>String: the version of this item in semantic triplet format</UserDocu>
|
||||
<UserDocu>String representing the version of this item in semantic triplet format.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Version" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Description" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>String: the description of this item (text only, no markup allowed)</UserDocu>
|
||||
<UserDocu>String representing the description of this item (text only, no markup allowed).</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Description" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Maintainer" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of maintainer objects with 'name' and 'email' string attributes</UserDocu>
|
||||
<UserDocu>List of maintainer objects with 'name' and 'email' string attributes.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Maintainer" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="License" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of applicable licenses as objects with 'name' and 'file' string attributes</UserDocu>
|
||||
<UserDocu>List of applicable licenses as objects with 'name' and 'file' string attributes.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="License" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Urls" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
List of URLs as objects with 'location' and 'type' string attributes, where type is one of:
|
||||
* website
|
||||
* repository
|
||||
* bugtracker
|
||||
* readme
|
||||
* documentation
|
||||
</UserDocu>
|
||||
<UserDocu>List of URLs as objects with 'location' and 'type' string attributes, where type
|
||||
is one of:
|
||||
* website
|
||||
* repository
|
||||
* bugtracker
|
||||
* readme
|
||||
* documentation</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Urls" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Author" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of author objects, each with a 'name' and a (potentially empty) 'email' string attribute</UserDocu>
|
||||
<UserDocu>List of author objects, each with a 'name' and a (potentially empty) 'email'
|
||||
string attribute.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Author" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Depend" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
List of dependencies, as objects with the following attributes:
|
||||
* package -- Required: must exactly match the contents of the 'name' element in the referenced package's package.xml file
|
||||
* version_lt -- Optional: The dependency to the package is restricted to versions less than the stated version number
|
||||
* version_lte -- Optional: The dependency to the package is restricted to versions less or equal than the stated version number
|
||||
* version_eq -- Optional: The dependency to the package is restricted to a version equal than the stated version number
|
||||
* version_gte -- Optional: The dependency to the package is restricted to versions greater or equal than the stated version number
|
||||
* version_gt -- Optional: The dependency to the package is restricted to versions greater than the stated version number
|
||||
* condition -- Optional: Conditional expression as documented in REP149
|
||||
</UserDocu>
|
||||
<UserDocu>List of dependencies, as objects with the following attributes:
|
||||
* package
|
||||
Required. Must exactly match the contents of the 'name' element in the
|
||||
referenced package's package.xml file.
|
||||
* version_lt
|
||||
Optional. The dependency to the package is restricted to versions less than
|
||||
the stated version number.
|
||||
* version_lte
|
||||
Optional. The dependency to the package is restricted to versions less or
|
||||
equal than the stated version number.
|
||||
* version_eq
|
||||
Optional. The dependency to the package is restricted to a version equal
|
||||
than the stated version number.
|
||||
* version_gte
|
||||
Optional. The dependency to the package is restricted to versions greater
|
||||
or equal than the stated version number.
|
||||
* version_gt
|
||||
Optional. The dependency to the package is restricted to versions greater
|
||||
than the stated version number.
|
||||
* condition
|
||||
Optional. Conditional expression as documented in REP149.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Depend" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Conflict" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of conflicts, format identical to dependencies</UserDocu>
|
||||
<UserDocu>List of conflicts, format identical to dependencies.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Conflict" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Replace" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of things this item is considered by its author to replace: format identical to dependencies</UserDocu>
|
||||
<UserDocu>List of things this item is considered by its author to replace. The format is
|
||||
identical to dependencies.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Replace" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Tag" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of strings</UserDocu>
|
||||
<UserDocu>List of strings.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Tag" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Icon" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Relative path to an icon file</UserDocu>
|
||||
<UserDocu>Relative path to an icon file.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Icon" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Classname" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>String: the name of the main Python class this item creates/represents</UserDocu>
|
||||
<UserDocu>String representing the name of the main Python class this item
|
||||
creates/represents.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Classname" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Subdirectory" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>String: the name of the subdirectory this content item is located in. If empty, the item is in a directory named the same as the content item.</UserDocu>
|
||||
<UserDocu>String representing the name of the subdirectory this content item is located in.
|
||||
If empty, the item is in a directory named the same as the content item.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Subdirectory" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="File" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of files associated with this item -- the meaning of each file is implementation-defined</UserDocu>
|
||||
<UserDocu>List of files associated with this item.
|
||||
The meaning of each file is implementation-defined.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="File" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Content" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A dictionary of lists of content items: defined recursively, each item is itself a Metadata object -- see package.xml file format documentation for details</UserDocu>
|
||||
<UserDocu>Dictionary of lists of content items: defined recursively, each item is itself
|
||||
a Metadata object.
|
||||
See package.xml file format documentation for details.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Content" Type="Object" />
|
||||
</Attribute>
|
||||
|
||||
<Attribute Name="FreeCADMin">
|
||||
<Documentation>
|
||||
<UserDocu>A string representing the minimum version of FreeCAD needed for this item. If unset it will be 0.0.0.</UserDocu>
|
||||
<UserDocu>String representing the minimum version of FreeCAD needed for this item.
|
||||
If unset it will be 0.0.0.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="FreeCADMin" Type="Object" />
|
||||
</Attribute>
|
||||
|
||||
<Attribute Name="FreeCADMax">
|
||||
<Documentation>
|
||||
<UserDocu>A string representing the maximum version of FreeCAD needed for this item. If unset it will be 0.0.0.</UserDocu>
|
||||
<UserDocu>String representing the maximum version of FreeCAD needed for this item.
|
||||
If unset it will be 0.0.0.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="FreeCADMax" Type="Object" />
|
||||
</Attribute>
|
||||
|
||||
<Methode Name="getLastSupportedFreeCADVersion">
|
||||
<Documentation>
|
||||
<UserDocu>getLastSupportedFreeCADVersion()
|
||||
Search through all content package items, and determine if a maximum supported version of FreeCAD
|
||||
is set. Returns None if no maximum version is set, or if *any* content item fails to provide a
|
||||
maximum version (implying that that content item will work with all known versions).
|
||||
</UserDocu>
|
||||
<UserDocu>getLastSupportedFreeCADVersion() -> str or None\n
|
||||
Search through all content package items, and determine if a maximum supported
|
||||
version of FreeCAD is set.
|
||||
Returns None if no maximum version is set, or if *any* content item fails to
|
||||
provide a maximum version (implying that that content item will work with all
|
||||
known versions).</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
<Methode Name="getFirstSupportedFreeCADVersion">
|
||||
<Documentation>
|
||||
<UserDocu>getFirstSupportedFreeCADVersion()
|
||||
Search through all content package items, and determine if a minimum supported version of FreeCAD
|
||||
is set. Returns 0.0 if no minimum version is set, or if *any* content item fails to provide a
|
||||
minimum version (implying that that content item will work with all known versions -- technically
|
||||
limited to 0.20 as the lowest known version since the metadata standard was added then).
|
||||
</UserDocu>
|
||||
<UserDocu>getFirstSupportedFreeCADVersion() -> str or None\n
|
||||
Search through all content package items, and determine if a minimum supported
|
||||
version of FreeCAD is set.
|
||||
Returns 0.0 if no minimum version is set, or if *any* content item fails to
|
||||
provide a minimum version (implying that that content item will work with all
|
||||
known versions. Technically limited to 0.20 as the lowest known version since
|
||||
the metadata standard was added then).</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
<Methode Name="supportsCurrentFreeCAD">
|
||||
<Documentation>
|
||||
<UserDocu>supportsCurrentFreeCAD()
|
||||
Returns false if this metadata object directly indicates that it does not support the current
|
||||
version of FreeCAD, or true if it makes no indication, or specifically indicates that it does
|
||||
support the current version. Does not recurse into Content items.
|
||||
</UserDocu>
|
||||
<UserDocu>supportsCurrentFreeCAD() -> bool\n
|
||||
Returns False if this metadata object directly indicates that it does not
|
||||
support the current version of FreeCAD, or True if it makes no indication, or
|
||||
specifically indicates that it does support the current version. Does not
|
||||
recurse into Content items.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
<Methode Name="getGenericMetadata">
|
||||
<Documentation>
|
||||
<UserDocu>getGenericMetadata(name)
|
||||
Get the list of GenericMetadata objects with key 'name'. Generic metadata objects are Python objects with
|
||||
a string 'contents' and a dictionary of strings, 'attributes'. They represent unrecognized simple XML tags
|
||||
in the metadata file.
|
||||
</UserDocu>
|
||||
<UserDocu>getGenericMetadata(name) -> list\n
|
||||
Get the list of GenericMetadata objects with key 'name'.
|
||||
Generic metadata objects are Python objects with a string 'contents' and a
|
||||
dictionary of strings, 'attributes'. They represent unrecognized simple XML tags
|
||||
in the metadata file.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
|
||||
+17
-10
@@ -23,6 +23,7 @@
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "Metadata.h"
|
||||
#include <Base/FileInfo.h>
|
||||
|
||||
// inclusion of the generated files (generated out of MetadataPy.xml)
|
||||
#include "MetadataPy.h"
|
||||
@@ -34,7 +35,7 @@ XERCES_CPP_NAMESPACE_USE
|
||||
// Returns a string which represents the object e.g. when printed in Python
|
||||
std::string MetadataPy::representation(void) const
|
||||
{
|
||||
MetadataPy::PointerType ptr = reinterpret_cast<MetadataPy::PointerType>(_pcTwinPointer);
|
||||
MetadataPy::PointerType ptr = getMetadataPtr();
|
||||
std::stringstream str;
|
||||
str << "Metadata [Name=(";
|
||||
str << ptr->name();
|
||||
@@ -64,10 +65,13 @@ int MetadataPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
|
||||
// Main class constructor -- takes a file path, loads the metadata from it
|
||||
PyErr_Clear();
|
||||
const char* filename;
|
||||
if (PyArg_ParseTuple(args, "s", &filename)) {
|
||||
char* filename;
|
||||
if (PyArg_ParseTuple(args, "et", "utf-8", &filename)) {
|
||||
try {
|
||||
auto md = new Metadata(filename);
|
||||
std::string utf8Name = std::string(filename);
|
||||
PyMem_Free(filename);
|
||||
|
||||
auto md = new Metadata(Base::FileInfo::stringToPath(utf8Name));
|
||||
setTwinPointer(md);
|
||||
return 0;
|
||||
}
|
||||
@@ -288,10 +292,11 @@ Py::Object MetadataPy::getContent(void) const
|
||||
PyObject* MetadataPy::getGenericMetadata(PyObject* args)
|
||||
{
|
||||
const char* name;
|
||||
if (!PyArg_ParseTuple(args, "s!", &name))
|
||||
if (!PyArg_ParseTuple(args, "s", &name))
|
||||
return nullptr;
|
||||
|
||||
auto gm = (*getMetadataPtr())[name];
|
||||
auto pyGenericMetadata = new Py::List;
|
||||
Py::List pyGenericMetadata;
|
||||
for (const auto& item : gm) {
|
||||
Py::Dict pyItem;
|
||||
pyItem["contents"] = Py::String(item.contents);
|
||||
@@ -300,12 +305,12 @@ PyObject* MetadataPy::getGenericMetadata(PyObject* args)
|
||||
pyAttributes[attribute.first] = Py::String(attribute.second);
|
||||
}
|
||||
pyItem["attributes"] = pyAttributes;
|
||||
pyGenericMetadata->append(pyItem);
|
||||
pyGenericMetadata.append(pyItem);
|
||||
}
|
||||
return pyGenericMetadata->ptr();
|
||||
return Py::new_reference_to(pyGenericMetadata);
|
||||
}
|
||||
|
||||
Py::Object MetadataPy::getFreeCADMin() const
|
||||
Py::Object MetadataPy::getFreeCADMin() const
|
||||
{
|
||||
return Py::String(getMetadataPtr()->freecadmin().str());
|
||||
}
|
||||
@@ -316,10 +321,11 @@ void MetadataPy::setFreeCADMin(Py::Object args)
|
||||
PyObject* p = args.ptr();
|
||||
if (!PyArg_ParseTuple(p, "s", &version))
|
||||
return;
|
||||
|
||||
getMetadataPtr()->setFreeCADMin(App::Meta::Version(version));
|
||||
}
|
||||
|
||||
Py::Object MetadataPy::getFreeCADMax() const
|
||||
Py::Object MetadataPy::getFreeCADMax() const
|
||||
{
|
||||
return Py::String(getMetadataPtr()->freecadmax().str());
|
||||
}
|
||||
@@ -330,6 +336,7 @@ void MetadataPy::setFreeCADMax(Py::Object args)
|
||||
PyObject* p = args.ptr();
|
||||
if (!PyArg_ParseTuple(p, "s", &version))
|
||||
return;
|
||||
|
||||
getMetadataPtr()->setFreeCADMax(App::Meta::Version(version));
|
||||
}
|
||||
|
||||
|
||||
+52
-14
@@ -28,15 +28,18 @@
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <CXX/Objects.hxx>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "Property.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
#include "PropertyContainer.h"
|
||||
|
||||
|
||||
using namespace App;
|
||||
|
||||
|
||||
@@ -78,17 +81,40 @@ bool Property::isValidName(const char* name)
|
||||
return name && name[0] != '\0';
|
||||
}
|
||||
|
||||
std::string Property::getFullName() const {
|
||||
std::string name;
|
||||
if(myName) {
|
||||
if(father)
|
||||
name = father->getFullName() + ".";
|
||||
void Property::SetRestoreError(const char * msg)
|
||||
{
|
||||
if (auto doc = father->getOwnerDocument())
|
||||
doc->setErrorDescription(this, msg);
|
||||
}
|
||||
|
||||
std::string Property::getFullName(bool python) const {
|
||||
if(!myName || (python && !father))
|
||||
return std::string(python?"None":"?");
|
||||
std::ostringstream ss;
|
||||
if(father)
|
||||
ss << father->getFullName(python)
|
||||
<< '.' << father->getPropertyPrefix();
|
||||
ss << myName;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string Property::getFileName(const char *postfix, const char *prefix) const {
|
||||
std::ostringstream ss;
|
||||
if(prefix)
|
||||
ss << prefix;
|
||||
if(!myName)
|
||||
ss << "Property";
|
||||
else {
|
||||
std::string name = getFullName();
|
||||
auto pos = name.find('#');
|
||||
if(pos == std::string::npos)
|
||||
ss << name;
|
||||
else
|
||||
name = "?.";
|
||||
name += myName;
|
||||
}else
|
||||
return "?";
|
||||
return name;
|
||||
ss << (name.c_str()+pos+1);
|
||||
}
|
||||
if(postfix)
|
||||
ss << postfix;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
short Property::getType(void) const
|
||||
@@ -213,10 +239,15 @@ void Property::destroy(Property *p) {
|
||||
|
||||
void Property::touch()
|
||||
{
|
||||
if(GetApplication().isClosingAll())
|
||||
return;
|
||||
|
||||
PropertyCleaner guard(this);
|
||||
if (father)
|
||||
father->onChanged(this);
|
||||
StatusBits.set(Touched);
|
||||
if (getName() && father) {
|
||||
father->onEarlyChange(this);
|
||||
father->onChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Property::setReadOnly(bool readOnly)
|
||||
@@ -291,13 +322,20 @@ void Property::setStatus(Status pos, bool on) {
|
||||
}
|
||||
|
||||
bool Property::isSame(const Property &other) const {
|
||||
return isSameContent(other);
|
||||
}
|
||||
|
||||
bool Property::isSameContent(const Property &other) const {
|
||||
if(&other == this)
|
||||
return true;
|
||||
|
||||
if(other.getTypeId() != getTypeId() || getMemSize() != other.getMemSize())
|
||||
return false;
|
||||
|
||||
Base::StringWriter writer,writer2;
|
||||
FC_STATIC Base::StringWriter writer,writer2;
|
||||
writer.clear();
|
||||
Save(writer);
|
||||
writer2.clear();
|
||||
other.Save(writer2);
|
||||
return writer.getString() == writer2.getString();
|
||||
}
|
||||
|
||||
+18
-1
@@ -32,6 +32,10 @@
|
||||
#include <string>
|
||||
#include <FCGlobal.h>
|
||||
|
||||
// NOTE! define this to static thread_local if FreeCAD ever decides to use
|
||||
// multi-threading recomputation.
|
||||
#define FC_STATIC static
|
||||
|
||||
namespace Py {
|
||||
class Object;
|
||||
}
|
||||
@@ -132,7 +136,10 @@ public:
|
||||
*/
|
||||
static bool isValidName(const char* name);
|
||||
|
||||
std::string getFullName() const;
|
||||
/** Return a fully qualified property name that include its own's name
|
||||
* @param python: if true, then return an expression for accessing this property in Python
|
||||
*/
|
||||
virtual std::string getFullName(bool python=false) const;
|
||||
|
||||
/// Get the class name of the associated property editor item
|
||||
virtual const char* getEditorName(void) const { return ""; }
|
||||
@@ -251,6 +258,8 @@ public:
|
||||
/// Compare if this property has the same content as the given one
|
||||
virtual bool isSame(const Property &other) const;
|
||||
|
||||
virtual void SetRestoreError(const char *) override;
|
||||
|
||||
/** Return a unique ID for the property
|
||||
*
|
||||
* The ID of a property is generated from a monotonically increasing
|
||||
@@ -261,6 +270,11 @@ public:
|
||||
*/
|
||||
int64_t getID() const {return _id;}
|
||||
|
||||
/// Compare property by comparing their XML content
|
||||
bool isSameContent(const Property &other) const;
|
||||
|
||||
virtual void beforeSave() const {}
|
||||
|
||||
friend class PropertyContainer;
|
||||
friend struct PropertyData;
|
||||
friend class DynamicProperty;
|
||||
@@ -286,6 +300,9 @@ protected:
|
||||
/// Verify a path for the current property
|
||||
virtual void verifyPath(const App::ObjectIdentifier & p) const;
|
||||
|
||||
/// Return a file name suitable for saving this property
|
||||
std::string getFileName(const char *postfix=0, const char *prefix=0) const;
|
||||
|
||||
private:
|
||||
// forbidden
|
||||
Property(const Property&);
|
||||
|
||||
+100
-28
@@ -69,15 +69,15 @@ unsigned int PropertyContainer::getMemSize (void) const
|
||||
|
||||
App::Property* PropertyContainer::addDynamicProperty(
|
||||
const char* type, const char* name, const char* group, const char* doc,
|
||||
short attr, bool ro, bool hidden)
|
||||
short attr, bool readonly, bool hidden)
|
||||
{
|
||||
return dynamicProps.addDynamicProperty(*this,type,name,group,doc,attr,ro,hidden);
|
||||
return dynamicProps.addDynamicProperty(*this,type,name,group,doc,attr,readonly,hidden);
|
||||
}
|
||||
|
||||
Property *PropertyContainer::getPropertyByName(const char* name) const
|
||||
{
|
||||
auto prop = dynamicProps.getDynamicPropertyByName(name);
|
||||
if(prop)
|
||||
if(prop)
|
||||
return prop;
|
||||
return getPropertyData().getPropertyByName(this,name);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ short PropertyContainer::getPropertyType(const char *name) const
|
||||
const char* PropertyContainer::getPropertyGroup(const Property* prop) const
|
||||
{
|
||||
auto group = dynamicProps.getPropertyGroup(prop);
|
||||
if(group)
|
||||
if(group)
|
||||
return group;
|
||||
return getPropertyData().getGroup(this,prop);
|
||||
}
|
||||
@@ -129,7 +129,7 @@ const char* PropertyContainer::getPropertyGroup(const Property* prop) const
|
||||
const char* PropertyContainer::getPropertyGroup(const char *name) const
|
||||
{
|
||||
auto group = dynamicProps.getPropertyGroup(name);
|
||||
if(group)
|
||||
if(group)
|
||||
return group;
|
||||
return getPropertyData().getGroup(this,name);
|
||||
}
|
||||
@@ -137,7 +137,7 @@ const char* PropertyContainer::getPropertyGroup(const char *name) const
|
||||
const char* PropertyContainer::getPropertyDocumentation(const Property* prop) const
|
||||
{
|
||||
auto doc = dynamicProps.getPropertyDocumentation(prop);
|
||||
if(doc)
|
||||
if(doc)
|
||||
return doc;
|
||||
return getPropertyData().getDocumentation(this,prop);
|
||||
}
|
||||
@@ -145,7 +145,7 @@ const char* PropertyContainer::getPropertyDocumentation(const Property* prop) co
|
||||
const char* PropertyContainer::getPropertyDocumentation(const char *name) const
|
||||
{
|
||||
auto doc = dynamicProps.getPropertyDocumentation(name);
|
||||
if(doc)
|
||||
if(doc)
|
||||
return doc;
|
||||
return getPropertyData().getDocumentation(this,name);
|
||||
}
|
||||
@@ -221,15 +221,52 @@ void PropertyContainer::handleChangedPropertyType(XMLReader &reader, const char
|
||||
|
||||
PropertyData PropertyContainer::propertyData;
|
||||
|
||||
void PropertyContainer::Save (Base::Writer &writer) const
|
||||
namespace App {
|
||||
class PropertyContainerP
|
||||
{
|
||||
std::map<std::string,Property*> Map;
|
||||
public:
|
||||
std::map<std::string, Property*> propertyMap;
|
||||
std::vector<Property*> transients;
|
||||
|
||||
void clear()
|
||||
{
|
||||
propertyMap.clear();
|
||||
transients.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct PropertyContainerPGuard
|
||||
{
|
||||
PropertyContainerPGuard(PropertyContainerP & priv)
|
||||
:priv(priv)
|
||||
{}
|
||||
|
||||
~PropertyContainerPGuard()
|
||||
{
|
||||
priv.clear();
|
||||
}
|
||||
|
||||
PropertyContainerP & priv;
|
||||
};
|
||||
}
|
||||
|
||||
void PropertyContainer::beforeSave() const
|
||||
{
|
||||
if (!_pimpl)
|
||||
_pimpl.reset(new PropertyContainerP);
|
||||
else
|
||||
_pimpl->clear();
|
||||
|
||||
auto & Map = _pimpl->propertyMap;
|
||||
auto & transients = _pimpl->transients;
|
||||
|
||||
getPropertyMap(Map);
|
||||
|
||||
std::vector<Property*> transients;
|
||||
for(auto it=Map.begin();it!=Map.end();) {
|
||||
auto prop = it->second;
|
||||
if(prop->testStatus(Property::PropNoPersist)) {
|
||||
if (prop->getContainer() != this
|
||||
|| prop->testStatus(Property::PropNoPersist))
|
||||
{
|
||||
it = Map.erase(it);
|
||||
continue;
|
||||
}
|
||||
@@ -239,9 +276,22 @@ void PropertyContainer::Save (Base::Writer &writer) const
|
||||
{
|
||||
transients.push_back(prop);
|
||||
it = Map.erase(it);
|
||||
}else
|
||||
} else {
|
||||
prop->beforeSave();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyContainer::Save (Base::Writer &writer) const
|
||||
{
|
||||
if (!_pimpl || _pimpl->propertyMap.empty())
|
||||
beforeSave();
|
||||
|
||||
PropertyContainerPGuard guard(*_pimpl);
|
||||
|
||||
auto & Map = _pimpl->propertyMap;
|
||||
auto & transients = _pimpl->transients;
|
||||
|
||||
writer.incInd(); // indentation for 'Properties Count'
|
||||
writer.Stream() << writer.ind() << "<Properties Count=\"" << Map.size()
|
||||
@@ -275,8 +325,8 @@ void PropertyContainer::Save (Base::Writer &writer) const
|
||||
if(it->second->testStatus(Property::Transient)
|
||||
|| it->second->getType() & Prop_Transient)
|
||||
{
|
||||
writer.Stream() << "</Property>\n";
|
||||
writer.decInd();
|
||||
writer.Stream() << "</Property>" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -326,14 +376,21 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
|
||||
reader.readElement("_Property");
|
||||
Property* prop = getPropertyByName(reader.getAttribute("name"));
|
||||
if(prop)
|
||||
FC_TRACE("restore transient '" << prop->getName() << "'");
|
||||
if(prop && reader.hasAttribute("status"))
|
||||
prop->setStatusValue(reader.getAttributeAsUnsigned("status"));
|
||||
FC_TRACE("restore transient '" << prop->getFullName() << "'");
|
||||
if(prop && reader.hasAttribute("status")) {
|
||||
decltype(Property::StatusBits) status(reader.getAttributeAsUnsigned("status"));
|
||||
status.reset(Property::User1);
|
||||
status.reset(Property::User2);
|
||||
status.reset(Property::User3);
|
||||
prop->setStatusValue(status.to_ulong());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0 ;i<Cnt ;i++) {
|
||||
reader.readElement("Property");
|
||||
int guard;
|
||||
reader.readElement("Property",&guard);
|
||||
std::string PropName = reader.getAttribute("name");
|
||||
Base::ReaderContext rctx(PropName);
|
||||
std::string TypeName = reader.getAttribute("type");
|
||||
// NOTE: We must also check the type of the current property because a
|
||||
// subclass of PropertyContainer might change the type of a property but
|
||||
@@ -346,7 +403,13 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
|
||||
|
||||
decltype(Property::StatusBits) status;
|
||||
if(reader.hasAttribute("status")) {
|
||||
status = decltype(status)(reader.getAttributeAsUnsigned("status"));
|
||||
status = decltype(Property::StatusBits)(reader.getAttributeAsUnsigned("status"));
|
||||
|
||||
// User1~3 are currently reserved for various temporary usage.
|
||||
// To avoid some potential problems, no persistence at the moment.
|
||||
status.reset(Property::User1);
|
||||
status.reset(Property::User2);
|
||||
status.reset(Property::User3);
|
||||
if(prop)
|
||||
prop->setStatusValue(status.to_ulong());
|
||||
}
|
||||
@@ -357,10 +420,10 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
|
||||
&& !status.test(Property::PropTransient)
|
||||
&& !prop->testStatus(Property::PropTransient))
|
||||
{
|
||||
FC_TRACE("restore property '" << prop->getName() << "'");
|
||||
FC_TRACE("restoring property " << prop->getFullName());
|
||||
prop->Restore(reader);
|
||||
}else
|
||||
FC_TRACE("skip transient '" << prop->getName() << "'");
|
||||
FC_TRACE("skip transient " << prop->getFullName());
|
||||
}
|
||||
// name matches but not the type
|
||||
else if (prop) {
|
||||
@@ -377,29 +440,38 @@ void PropertyContainer::Restore(Base::XMLReader &reader)
|
||||
reader.clearPartialRestoreProperty();
|
||||
}
|
||||
}
|
||||
catch (const Base::XMLParseException&) {
|
||||
catch (Base::XMLParseException &e) {
|
||||
FC_ERR(e.what() << " while parsing " << getFullName() << '.' << PropName);
|
||||
e.setReported(true);
|
||||
throw; // re-throw
|
||||
}
|
||||
catch (const Base::RestoreError &) {
|
||||
catch (const Base::RestoreError &e) {
|
||||
e.ReportException();
|
||||
reader.setPartialRestore(true);
|
||||
reader.clearPartialRestoreProperty();
|
||||
Base::Console().Error("Property %s of type %s was subject to a partial restore.\n",PropName.c_str(),TypeName.c_str());
|
||||
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
|
||||
<< "): was subject to a partial restore.");
|
||||
}
|
||||
catch (const Base::Exception &e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
e.ReportException();
|
||||
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
|
||||
<< ") restore error.");
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
Base::Console().Error("%s\n", e.what());
|
||||
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
|
||||
<< ") restore error: " << e.what());
|
||||
}
|
||||
catch (const char* e) {
|
||||
Base::Console().Error("%s\n", e);
|
||||
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
|
||||
<< ") restore error: " << e);
|
||||
}
|
||||
#ifndef FC_DEBUG
|
||||
catch (...) {
|
||||
Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown\n");
|
||||
FC_ERR(getFullName() << '.' << PropName << " (" << TypeName
|
||||
<< ") restore error: Unknown C++ exception thrown\n");
|
||||
}
|
||||
#endif
|
||||
reader.readEndElement("Property");
|
||||
reader.readEndElement("Property",&guard);
|
||||
}
|
||||
reader.readEndElement("Properties");
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace App
|
||||
class Property;
|
||||
class PropertyContainer;
|
||||
class DocumentObject;
|
||||
class Document;
|
||||
class Extension;
|
||||
|
||||
enum PropertyType
|
||||
@@ -135,6 +136,7 @@ struct AppExport PropertyData
|
||||
void split(PropertyData *other);
|
||||
};
|
||||
|
||||
class PropertyContainerP;
|
||||
|
||||
/** Base class of all classes with properties
|
||||
*/
|
||||
@@ -158,7 +160,17 @@ public:
|
||||
|
||||
virtual unsigned int getMemSize (void) const;
|
||||
|
||||
virtual std::string getFullName() const {return std::string();}
|
||||
/** Return a fully qualified name for this container
|
||||
* @param python: if true, then return an expression for accessing this container in Python
|
||||
*/
|
||||
virtual std::string getFullName(bool python=false) const {
|
||||
(void)python;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
/// Return owner document of this container
|
||||
virtual App::Document *getOwnerDocument() const
|
||||
{return nullptr;}
|
||||
|
||||
/// find a property by its name
|
||||
virtual Property *getPropertyByName(const char* name) const;
|
||||
@@ -196,7 +208,7 @@ public:
|
||||
virtual App::Property* addDynamicProperty(
|
||||
const char* type, const char* name=nullptr,
|
||||
const char* group=nullptr, const char* doc=nullptr,
|
||||
short attr=0, bool ro=false, bool hidden=false);
|
||||
short attr=0, bool readonly=false, bool hidden=false);
|
||||
|
||||
DynamicProperty::PropData getDynamicPropertyData(const Property* prop) const {
|
||||
return dynamicProps.getDynamicPropertyData(prop);
|
||||
@@ -220,6 +232,7 @@ public:
|
||||
|
||||
virtual void Save (Base::Writer &writer) const;
|
||||
virtual void Restore(Base::XMLReader &reader);
|
||||
virtual void beforeSave() const;
|
||||
|
||||
virtual void editProperty(const char * /*propName*/) {}
|
||||
|
||||
@@ -236,6 +249,11 @@ public:
|
||||
|
||||
|
||||
protected:
|
||||
/** get called by the container when a property has changed
|
||||
*
|
||||
* This function is called before onChanged()
|
||||
*/
|
||||
virtual void onEarlyChange(const Property* /*prop*/){}
|
||||
/// get called by the container when a property has changed
|
||||
virtual void onChanged(const Property* /*prop*/){}
|
||||
/// get called before the value is changed
|
||||
@@ -256,9 +274,12 @@ private:
|
||||
protected:
|
||||
DynamicProperty dynamicProps;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
std::string _propertyPrefix;
|
||||
static PropertyData propertyData;
|
||||
static PropertyData propertyData;
|
||||
|
||||
mutable std::unique_ptr<PropertyContainerP> _pimpl;
|
||||
};
|
||||
|
||||
/// Property define
|
||||
|
||||
@@ -12,126 +12,139 @@
|
||||
DisableNotify="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Juergen Riegel" EMail="FreeCAD@juergen-riegel.net" />
|
||||
<UserDocu>This is a Persistence class</UserDocu>
|
||||
<UserDocu>App.PropertyContainer class.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getPropertyByName">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getPropertyByName(name,checkOwner=0)
|
||||
|
||||
Return the value of a named property. Note that the returned property may not
|
||||
always belong to this container (e.g. from a linked object).
|
||||
|
||||
* name: name of the property
|
||||
* checkOwner: 0: just return the property
|
||||
1: raise exception if not found or the property
|
||||
does not belong to this container
|
||||
2: return a tuple(owner,property_value)
|
||||
</UserDocu>
|
||||
<UserDocu>getPropertyByName(name, checkOwner=0) -> object or Tuple\n
|
||||
Returns the value of a named property. Note that the returned property may not
|
||||
always belong to this container (e.g. from a linked object).\n
|
||||
name : str\n Name of the property.
|
||||
checkOwner : int\n 0: just return the property.
|
||||
1: raise exception if not found or the property does not belong to this container.
|
||||
2: return a tuple (owner, propertyValue).</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPropertyTouchList">
|
||||
<Documentation>
|
||||
<UserDocu>Return a list of index of touched values for list type properties.</UserDocu>
|
||||
<UserDocu>getPropertyTouchList(name) -> tuple\n
|
||||
Returns a list of index of touched values for list type properties.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getTypeOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Return the type of a named property. This can be (Hidden,ReadOnly,Output) or any combination. </UserDocu>
|
||||
<UserDocu>getTypeOfProperty(name) -> list\n
|
||||
Returns the type of a named property. This can be a list conformed by elements in
|
||||
(Hidden, NoRecompute, NoPersist, Output, ReadOnly, Transient).\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getTypeIdOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Returns the C++ class name of a named property.</UserDocu>
|
||||
<UserDocu>getTypeIdOfProperty(name) -> str\n
|
||||
Returns the C++ class name of a named property.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setEditorMode">
|
||||
<Documentation>
|
||||
<UserDocu>Set the behaviour of the property in the property editor.
|
||||
0 - default behaviour
|
||||
1 - item is ready-only
|
||||
2 - item is hidden
|
||||
</UserDocu>
|
||||
<UserDocu>setEditorMode(name, type) -> None\n
|
||||
Set the behaviour of the property in the property editor.\n
|
||||
name : str\n Property name.
|
||||
type : int, sequence of str\n Property type.
|
||||
0: default behaviour. 1: item is ready-only. 2: item is hidden. 3: item is hidden and read-only.
|
||||
If sequence, the available items are 'ReadOnly' and 'Hidden'.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getEditorMode">
|
||||
<Documentation>
|
||||
<UserDocu>Get the behaviour of the property in the property editor.
|
||||
It returns a list of strings with the current mode. If the list is empty there are no special restrictions.
|
||||
If the list contains 'ReadOnly' then the item appears in the property editor but is disabled.
|
||||
If the list contains 'Hidden' then the item even doesn't appear in the property editor.
|
||||
</UserDocu>
|
||||
<UserDocu>getEditorMode(name) -> list\n
|
||||
Get the behaviour of the property in the property editor.
|
||||
It returns a list of strings with the current mode. If the list is empty there are no
|
||||
special restrictions.
|
||||
If the list contains 'ReadOnly' then the item appears in the property editor but is
|
||||
disabled.
|
||||
If the list contains 'Hidden' then the item even doesn't appear in the property editor.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getGroupOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Return the name of the group which the property belongs to in this class. The properties sorted in different named groups for convenience.</UserDocu>
|
||||
<UserDocu>getGroupOfProperty(name) -> str\n
|
||||
Returns the name of the group which the property belongs to in this class.
|
||||
The properties are sorted in different named groups for convenience.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setGroupOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Set the name of the group of a dynamic property.</UserDocu>
|
||||
<UserDocu>setGroupOfProperty(name, group) -> None\n
|
||||
Set the name of the group of a dynamic property.\n
|
||||
name : str\n Property name.
|
||||
group : str\n Group name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setPropertyStatus">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
setPropertyStatus(name,val): Set property status
|
||||
|
||||
name(String): property name
|
||||
|
||||
val(String|Int|[String|Int...]): text or integer value, or list/tuple of
|
||||
values. Call getPropertyStatus() to get a list of supported text value.
|
||||
If the text start with '-' or the integer value is negative, then the
|
||||
status is cleared.
|
||||
</UserDocu>
|
||||
<UserDocu>setPropertyStatus(name, val) -> None\n
|
||||
Set property status.\n
|
||||
name : str\n Property name.
|
||||
val : int, str, sequence of str or int\n Call getPropertyStatus() to get a list of supported text value.
|
||||
If the text start with '-' or the integer value is negative, then the status is cleared.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPropertyStatus">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getPropertyStatus(name=''): Get property status.
|
||||
|
||||
name(String): property name. If name is empty, return a list of supported
|
||||
text names of the status.
|
||||
</UserDocu>
|
||||
<UserDocu>getPropertyStatus(name='') -> list\n
|
||||
Get property status.\n
|
||||
name : str\n Property name. If empty, returns a list of supported text names of the status.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getDocumentationOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Return the documentation string of the property of this class.</UserDocu>
|
||||
<UserDocu>getDocumentationOfProperty(name) -> str\n
|
||||
Returns the documentation string of the property of this class.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setDocumentationOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Set the documentation string of a dynamic property of this class.</UserDocu>
|
||||
<UserDocu>setDocumentationOfProperty(name, docstring) -> None\n
|
||||
Set the documentation string of a dynamic property of this class.\n
|
||||
name : str\n Property name.
|
||||
docstring : str\n Documentation string.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getEnumerationsOfProperty">
|
||||
<Documentation>
|
||||
<UserDocu>Return all enumeration strings of the property of this class or None if not a PropertyEnumeration.</UserDocu>
|
||||
<UserDocu>getEnumerationsOfProperty(name) -> list or None\n
|
||||
Return all enumeration strings of the property of this class or None if not a
|
||||
PropertyEnumeration.\n
|
||||
name : str\n Property name.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="dumpPropertyContent" Keyword="true" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Dumps the content of the property, both the XML representation as well as the additional datafiles
|
||||
required, into a byte representation. It will be returned as byte array.
|
||||
dumpPropertyContent(propertyname) -- returns a byte array with full content
|
||||
dumpPropertyContent(propertyname, [Compression=1-9]) -- Sets the data compression from 0 (no) to 9 (max)
|
||||
</UserDocu>
|
||||
<UserDocu>dumpPropertyContent(Property, Compression=3) -> bytearray\n
|
||||
Dumps the content of the property, both the XML representation and the additional
|
||||
data files required, into a byte representation.\n
|
||||
Property : str\n Property Name.
|
||||
Compression : int\n Set the data compression level in the range [0, 9]. Set to 0 for no compression.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="restorePropertyContent">
|
||||
<Documentation>
|
||||
<UserDocu>Restore the content of given property from a byte representation as stored by \"dumpContent\".
|
||||
It could be restored from any python object implementing the buffer protocol.
|
||||
restorePropertyContent(propertyname, buffer) -- restores from the given byte array
|
||||
</UserDocu>
|
||||
<UserDocu>restorePropertyContent(name, obj) -> None\n
|
||||
Restore the content of the object from a byte representation as stored by `dumpPropertyContent`.
|
||||
It could be restored from any Python object implementing the buffer protocol.\n
|
||||
name : str\n Property name.
|
||||
obj : buffer\n Object with buffer protocol support.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="PropertiesList" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>A list of all property names</UserDocu>
|
||||
<UserDocu>A list of all property names.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="PropertiesList" Type="List"/>
|
||||
</Attribute>
|
||||
|
||||
@@ -54,16 +54,24 @@ PyObject* PropertyContainerPy::getPropertyByName(PyObject *args)
|
||||
int checkOwner=0;
|
||||
if (!PyArg_ParseTuple(args, "s|i", &pstr, &checkOwner))
|
||||
return nullptr;
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(pstr);
|
||||
if (prop) {
|
||||
if(!checkOwner || (checkOwner==1 && prop->getContainer()==getPropertyContainerPtr()))
|
||||
return prop->getPyObject();
|
||||
Py::TupleN res(Py::asObject(prop->getContainer()->getPyObject()),
|
||||
Py::asObject(prop->getPyObject()));
|
||||
return Py::new_reference_to(res);
|
||||
|
||||
if (checkOwner < 0 || checkOwner > 2) {
|
||||
PyErr_SetString(PyExc_ValueError, "'checkOwner' expected in the range [0, 2]");
|
||||
return nullptr;
|
||||
}
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", pstr);
|
||||
return nullptr;
|
||||
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(pstr);
|
||||
if (!prop) {
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!checkOwner || (checkOwner==1 && prop->getContainer()==getPropertyContainerPtr()))
|
||||
return prop->getPyObject();
|
||||
|
||||
Py::TupleN res(Py::asObject(prop->getContainer()->getPyObject()), Py::asObject(prop->getPyObject()));
|
||||
|
||||
return Py::new_reference_to(res);
|
||||
}
|
||||
|
||||
PyObject* PropertyContainerPy::getPropertyTouchList(PyObject *args)
|
||||
@@ -71,6 +79,7 @@ PyObject* PropertyContainerPy::getPropertyTouchList(PyObject *args)
|
||||
char *pstr;
|
||||
if (!PyArg_ParseTuple(args, "s", &pstr))
|
||||
return nullptr;
|
||||
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(pstr);
|
||||
if (prop && prop->isDerivedFrom(PropertyLists::getClassTypeId())) {
|
||||
const auto &touched = static_cast<PropertyLists*>(prop)->getTouchList();
|
||||
@@ -80,11 +89,14 @@ PyObject* PropertyContainerPy::getPropertyTouchList(PyObject *args)
|
||||
ret.setItem(i++,Py::Long(idx));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
else if(!prop)
|
||||
else if (!prop) {
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", pstr);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_AttributeError, "Property '%s' is not of list type", pstr);
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* PropertyContainerPy::getTypeOfProperty(PyObject *args)
|
||||
@@ -168,7 +180,7 @@ PyObject* PropertyContainerPy::setEditorMode(PyObject *args)
|
||||
status.reset(Property::ReadOnly);
|
||||
status.reset(Property::Hidden);
|
||||
for (Py::Sequence::iterator it = seq.begin();it!=seq.end();++it) {
|
||||
std::string str = (std::string)Py::String(*it);
|
||||
std::string str = static_cast<std::string>(Py::String(*it));
|
||||
if (str == "ReadOnly")
|
||||
status.set(Property::ReadOnly);
|
||||
else if (str == "Hidden")
|
||||
@@ -210,28 +222,30 @@ PyObject* PropertyContainerPy::setPropertyStatus(PyObject *args)
|
||||
PyObject *pyValue;
|
||||
if (!PyArg_ParseTuple(args, "sO", &name, &pyValue))
|
||||
return nullptr;
|
||||
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(name);
|
||||
if (!prop) {
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", name);
|
||||
return nullptr;
|
||||
}
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
std::bitset<32> status(prop->getStatus());
|
||||
size_t count = 1;
|
||||
bool isSeq = false;
|
||||
if(PyList_Check(pyValue) || PyTuple_Check(pyValue)) {
|
||||
if (PyList_Check(pyValue) || PyTuple_Check(pyValue)) {
|
||||
isSeq = true;
|
||||
count = PySequence_Size(pyValue);
|
||||
}
|
||||
for(size_t i=0;i<count;++i) {
|
||||
|
||||
for(size_t i=0; i<count; ++i) {
|
||||
Py::Object item;
|
||||
if(isSeq)
|
||||
if (isSeq)
|
||||
item = Py::Object(PySequence_GetItem(pyValue,i));
|
||||
else
|
||||
item = Py::Object(pyValue);
|
||||
bool value = true;
|
||||
if(item.isString()) {
|
||||
if (item.isString()) {
|
||||
const auto &statusMap = getStatusMap();
|
||||
auto v = (std::string)Py::String(item);
|
||||
if(v.size()>1 && v[0] == '-') {
|
||||
@@ -248,7 +262,8 @@ PyObject* PropertyContainerPy::setPropertyStatus(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
status.set(it->second,value);
|
||||
}else if(item.isNumeric()) {
|
||||
}
|
||||
else if (item.isNumeric()) {
|
||||
int v = Py::Int(item);
|
||||
if(v<0) {
|
||||
value = false;
|
||||
@@ -257,7 +272,8 @@ PyObject* PropertyContainerPy::setPropertyStatus(PyObject *args)
|
||||
if(v==0 || v>31)
|
||||
PyErr_Format(PyExc_ValueError, "Status value out of range '%d'", v);
|
||||
status.set(v,value);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "Expects status type to be Int or String");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -275,31 +291,34 @@ PyObject* PropertyContainerPy::getPropertyStatus(PyObject *args)
|
||||
|
||||
Py::List ret;
|
||||
const auto &statusMap = getStatusMap();
|
||||
if(!name[0]) {
|
||||
if (!name[0]) {
|
||||
for(auto &v : statusMap)
|
||||
ret.append(Py::String(v.first.c_str()));
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(name);
|
||||
if (prop) {
|
||||
if (!prop) {
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
if(linkProp && linkProp->testFlag(App::PropertyLinkBase::LinkAllowPartial))
|
||||
ret.append(Py::String("AllowPartial"));
|
||||
auto linkProp = Base::freecad_dynamic_cast<App::PropertyLinkBase>(prop);
|
||||
if (linkProp && linkProp->testFlag(App::PropertyLinkBase::LinkAllowPartial))
|
||||
ret.append(Py::String("AllowPartial"));
|
||||
|
||||
std::bitset<32> bits(prop->getStatus());
|
||||
for(size_t i=1;i<bits.size();++i) {
|
||||
if(!bits[i]) continue;
|
||||
bool found = false;
|
||||
for(auto &v : statusMap) {
|
||||
if(v.second == (int)i) {
|
||||
ret.append(Py::String(v.first.c_str()));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
std::bitset<32> bits(prop->getStatus());
|
||||
for(size_t i=1; i<bits.size(); ++i) {
|
||||
if(!bits[i]) continue;
|
||||
bool found = false;
|
||||
for(auto &v : statusMap) {
|
||||
if(v.second == static_cast<int>(i)) {
|
||||
ret.append(Py::String(v.first.c_str()));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found)
|
||||
ret.append(Py::Int((long)i));
|
||||
}
|
||||
if (!found)
|
||||
ret.append(Py::Int(static_cast<long>(i)));
|
||||
}
|
||||
}
|
||||
return Py::new_reference_to(ret);
|
||||
@@ -312,6 +331,11 @@ PyObject* PropertyContainerPy::getEditorMode(PyObject *args)
|
||||
return nullptr;
|
||||
|
||||
App::Property* prop = getPropertyContainerPtr()->getPropertyByName(name);
|
||||
if (!prop) {
|
||||
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py::List ret;
|
||||
if (prop) {
|
||||
short Type = prop->getType();
|
||||
@@ -357,7 +381,8 @@ PyObject* PropertyContainerPy::setGroupOfProperty(PyObject *args)
|
||||
}
|
||||
prop->getContainer()->changeDynamicProperty(prop,group,nullptr);
|
||||
Py_Return;
|
||||
} PY_CATCH
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
|
||||
@@ -373,9 +398,9 @@ PyObject* PropertyContainerPy::getDocumentationOfProperty(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* Group = getPropertyContainerPtr()->getPropertyDocumentation(prop);
|
||||
if (Group)
|
||||
return Py::new_reference_to(Py::String(Group));
|
||||
const char* docstr = getPropertyContainerPtr()->getPropertyDocumentation(prop);
|
||||
if (docstr)
|
||||
return Py::new_reference_to(Py::String(docstr));
|
||||
else
|
||||
return Py::new_reference_to(Py::String(""));
|
||||
}
|
||||
@@ -395,7 +420,8 @@ PyObject* PropertyContainerPy::setDocumentationOfProperty(PyObject *args)
|
||||
}
|
||||
prop->getContainer()->changeDynamicProperty(prop,nullptr,doc);
|
||||
Py_Return;
|
||||
} PY_CATCH
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
|
||||
PyObject* PropertyContainerPy::getEnumerationsOfProperty(PyObject *args)
|
||||
@@ -411,13 +437,10 @@ PyObject* PropertyContainerPy::getEnumerationsOfProperty(PyObject *args)
|
||||
}
|
||||
|
||||
PropertyEnumeration *enumProp = dynamic_cast<PropertyEnumeration*>(prop);
|
||||
if (!enumProp) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
if (!enumProp)
|
||||
Py_Return;
|
||||
|
||||
std::vector<std::string> enumerations = enumProp->getEnumVector();
|
||||
|
||||
Py::List ret;
|
||||
for (std::vector<std::string>::const_iterator it = enumerations.begin(); it != enumerations.end(); ++it) {
|
||||
ret.append(Py::String(*it));
|
||||
@@ -432,7 +455,7 @@ Py::List PropertyContainerPy::getPropertiesList(void) const
|
||||
|
||||
getPropertyContainerPtr()->getPropertyMap(Map);
|
||||
|
||||
for (std::map<std::string,Property*>::const_iterator It=Map.begin();It!=Map.end();++It)
|
||||
for (std::map<std::string,Property*>::const_iterator It=Map.begin(); It!=Map.end(); ++It)
|
||||
ret.append(Py::String(It->first));
|
||||
|
||||
return ret;
|
||||
@@ -442,12 +465,11 @@ Py::List PropertyContainerPy::getPropertiesList(void) const
|
||||
PyObject* PropertyContainerPy::dumpPropertyContent(PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int compression = 3;
|
||||
char* property;
|
||||
static char* kwds_def[] = {"Property", "Compression",nullptr};
|
||||
const char* property;
|
||||
static char* kwds_def[] = {"Property", "Compression", nullptr};
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwds_def, &property, &compression)) {
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwds_def, &property, &compression))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Property* prop = getPropertyContainerPtr()->getPropertyByName(property);
|
||||
if (!prop) {
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
#ifndef EXPRESSIONENGINE_H
|
||||
#define EXPRESSIONENGINE_H
|
||||
|
||||
#include <functional>
|
||||
#include <boost/unordered/unordered_map.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost_signals2.hpp>
|
||||
#include <boost_graph_adjacency_list.hpp>
|
||||
#include <boost/graph/topological_sort.hpp>
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
virtual Property *CopyOnLinkReplace(const App::DocumentObject *parent,
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj) const override;
|
||||
|
||||
typedef boost::function<std::string (const App::ObjectIdentifier & path, std::shared_ptr<const App::Expression> expr)> ValidatorFunc;
|
||||
typedef std::function<std::string (const App::ObjectIdentifier & path, std::shared_ptr<const App::Expression> expr)> ValidatorFunc;
|
||||
|
||||
/**
|
||||
* @brief The ExpressionInfo struct encapsulates an expression.
|
||||
@@ -179,7 +179,7 @@ private:
|
||||
typedef boost::adjacency_list< boost::listS, boost::vecS, boost::directedS > DiGraph;
|
||||
typedef std::pair<int, int> Edge;
|
||||
// Note: use std::map instead of unordered_map to keep the binding order stable
|
||||
#ifdef FC_OS_MACOSX
|
||||
#if defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||
typedef std::map<App::ObjectIdentifier, ExpressionInfo> ExpressionMap;
|
||||
#else
|
||||
typedef std::map<const App::ObjectIdentifier, ExpressionInfo> ExpressionMap;
|
||||
|
||||
@@ -354,19 +354,17 @@ void PropertyFileIncluded::Save (Base::Writer &writer) const
|
||||
_cValue = fi.filePath();
|
||||
}
|
||||
|
||||
if (writer.isForceXML()) {
|
||||
if (writer.isForceXML()>3) {
|
||||
if (!_cValue.empty()) {
|
||||
Base::FileInfo file(_cValue.c_str());
|
||||
writer.Stream() << writer.ind() << "<FileIncluded data=\""
|
||||
<< file.fileName() << "\">" << std::endl;
|
||||
<< encodeAttribute(file.fileName()) << "\">\n";
|
||||
// write the file in the XML stream
|
||||
writer.incInd();
|
||||
writer.insertBinFile(_cValue.c_str());
|
||||
writer.decInd();
|
||||
writer.Stream() << writer.ind() <<"</FileIncluded>" << endl;
|
||||
writer.Stream() << writer.ind() <<"</FileIncluded>\n";
|
||||
}
|
||||
else {
|
||||
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>" << std::endl;
|
||||
writer.Stream() << writer.ind() << "<FileIncluded data=\"\"/>\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -406,7 +404,7 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
||||
// is in the document transient path
|
||||
aboutToSetValue();
|
||||
_cValue = getDocTransientPath() + "/" + file;
|
||||
reader.readBinFile(_cValue.c_str());
|
||||
reader.readCharacters(_cValue.c_str(),true);
|
||||
reader.readEndElement("FileIncluded");
|
||||
_BaseFileName = file;
|
||||
// set read-only after restoring the file
|
||||
@@ -427,12 +425,7 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
|
||||
throw Base::FileSystemError(str.str());
|
||||
}
|
||||
|
||||
// copy plain data
|
||||
unsigned char c;
|
||||
std::ostream& to = writer.Stream();
|
||||
while (from.get((char&)c)) {
|
||||
to.put((char)c);
|
||||
}
|
||||
writer.Stream() << from.rdbuf();
|
||||
}
|
||||
|
||||
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||
@@ -443,7 +436,7 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||
// same file of another object (e.g. for copy&paste of objects inside the same document).
|
||||
return;
|
||||
}
|
||||
Base::ofstream to(fi, std::ios::out | std::ios::binary);
|
||||
Base::ofstream to(fi, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||
if (!to) {
|
||||
std::stringstream str;
|
||||
str << "PropertyFileIncluded::RestoreDocFile(): "
|
||||
@@ -453,10 +446,8 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||
|
||||
// copy plain data
|
||||
aboutToSetValue();
|
||||
unsigned char c;
|
||||
while (reader.get((char&)c)) {
|
||||
to.put((char)c);
|
||||
}
|
||||
|
||||
reader >> to.rdbuf();
|
||||
to.close();
|
||||
|
||||
// set read-only after restoring the file
|
||||
|
||||
+59
-3
@@ -23,19 +23,30 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <Base/MatrixPy.h>
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <Base/Reader.h>
|
||||
#ifndef _PreComp_
|
||||
# include <assert.h>
|
||||
#endif
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/MatrixPy.h>
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <Base/Rotation.h>
|
||||
#include <Base/RotationPy.h>
|
||||
#include <Base/Stream.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/Writer.h>
|
||||
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "PropertyGeo.h"
|
||||
#include "Placement.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
@@ -1136,3 +1147,48 @@ PropertyComplexGeoData::~PropertyComplexGeoData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string PropertyComplexGeoData::getElementMapVersion(bool) const {
|
||||
auto data = getComplexData();
|
||||
if(!data)
|
||||
return std::string();
|
||||
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
std::ostringstream ss;
|
||||
if(owner && owner->getDocument()
|
||||
&& owner->getDocument()->getStringHasher()==data->Hasher)
|
||||
ss << "1.";
|
||||
else
|
||||
ss << "0.";
|
||||
ss << data->getElementMapVersion();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool PropertyComplexGeoData::checkElementMapVersion(const char * ver) const
|
||||
{
|
||||
auto data = getComplexData();
|
||||
if(!data)
|
||||
return false;
|
||||
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
std::ostringstream ss;
|
||||
const char *prefix;
|
||||
if(owner && owner->getDocument()
|
||||
&& owner->getDocument()->getStringHasher() == data->Hasher)
|
||||
prefix = "1.";
|
||||
else
|
||||
prefix = "0.";
|
||||
if (!boost::starts_with(ver, prefix))
|
||||
return true;
|
||||
return data->checkElementMapVersion(ver+2);
|
||||
}
|
||||
|
||||
void PropertyComplexGeoData::afterRestore()
|
||||
{
|
||||
auto data = getComplexData();
|
||||
if (data && data->isRestoreFailed()) {
|
||||
data->resetRestoreFailure();
|
||||
auto owner = Base::freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
if (owner && owner->getDocument() && !owner->getDocument()->testStatus(App::Document::PartialDoc))
|
||||
owner->getDocument()->addRecomputeObject(owner);
|
||||
}
|
||||
PropertyGeometry::afterRestore();
|
||||
}
|
||||
|
||||
@@ -508,6 +508,10 @@ public:
|
||||
|
||||
/** @name Modification */
|
||||
//@{
|
||||
/// Set the placement of the geometry
|
||||
virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
|
||||
/// Get the placement of the geometry
|
||||
virtual Base::Matrix4D getTransform() const = 0;
|
||||
/// Applies a transformation on the real geometric data type
|
||||
virtual void transformGeometry(const Base::Matrix4D &rclMat) = 0;
|
||||
/// Retrieve bounding box information
|
||||
@@ -537,6 +541,18 @@ public:
|
||||
virtual const Data::ComplexGeoData* getComplexData() const = 0;
|
||||
virtual Base::BoundBox3d getBoundingBox() const = 0;
|
||||
//@}
|
||||
|
||||
/** Return the element map version
|
||||
*
|
||||
* @param persisted: if true, return the restored element map version. Or
|
||||
* else, return the current element map version
|
||||
*/
|
||||
virtual std::string getElementMapVersion(bool restored=false) const;
|
||||
|
||||
/// Return true to signal element map version change
|
||||
virtual bool checkElementMapVersion(const char * ver) const;
|
||||
|
||||
virtual void afterRestore();
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
+353
-117
@@ -26,22 +26,28 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost_bind_bind.hpp>
|
||||
#include <boost/iostreams/device/array.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Tools.h>
|
||||
|
||||
#include "PropertyLinks.h"
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "DocumentObjectPy.h"
|
||||
#include "DocumentObserver.h"
|
||||
#include "GeoFeature.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("PropertyLinks",true,true)
|
||||
FC_LOG_LEVEL_INIT("App",true,true)
|
||||
|
||||
using namespace App;
|
||||
using namespace Base;
|
||||
@@ -56,6 +62,9 @@ namespace bp = boost::placeholders;
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLinkBase , App::Property)
|
||||
|
||||
static std::unordered_map<std::string, std::set<PropertyLinkBase*> > _LabelMap;
|
||||
|
||||
static std::unordered_map<App::DocumentObject *, std::unordered_set<PropertyLinkBase*> > _ElementRefMap;
|
||||
|
||||
PropertyLinkBase::PropertyLinkBase()
|
||||
{}
|
||||
|
||||
@@ -68,6 +77,11 @@ void PropertyLinkBase::setAllowExternal(bool allow) {
|
||||
setFlag(LinkAllowExternal,allow);
|
||||
}
|
||||
|
||||
void PropertyLinkBase::setReturnNewElement(bool enable)
|
||||
{
|
||||
setFlag(LinkNewElement, enable);
|
||||
}
|
||||
|
||||
void PropertyLinkBase::hasSetValue() {
|
||||
auto owner = dynamic_cast<DocumentObject*>(getContainer());
|
||||
if(owner)
|
||||
@@ -99,6 +113,15 @@ bool PropertyLinkBase::isSame(const Property &other) const
|
||||
}
|
||||
|
||||
void PropertyLinkBase::unregisterElementReference() {
|
||||
for(auto obj : _ElementRefs) {
|
||||
auto it = _ElementRefMap.find(obj);
|
||||
if(it != _ElementRefMap.end()) {
|
||||
it->second.erase(this);
|
||||
if(it->second.empty())
|
||||
_ElementRefMap.erase(it);
|
||||
}
|
||||
}
|
||||
_ElementRefs.clear();
|
||||
}
|
||||
|
||||
void PropertyLinkBase::unregisterLabelReferences()
|
||||
@@ -203,39 +226,76 @@ static std::string propertyName(const Property *prop) {
|
||||
return prop->getFullName();
|
||||
}
|
||||
|
||||
std::vector<App::SubObjectT>
|
||||
PropertyLinkBase::linkedElementsT(bool all) const
|
||||
{
|
||||
std::vector<App::DocumentObject*> objs;
|
||||
std::vector<std::string> subs;
|
||||
getLinks(objs,all,&subs,true);
|
||||
std::vector<App::SubObjectT> res;
|
||||
res.reserve(objs.size());
|
||||
assert(objs.size() == subs.size());
|
||||
for (unsigned i=0; i<objs.size(); ++i)
|
||||
res.emplace_back(objs[i], subs[i].c_str());
|
||||
return res;
|
||||
}
|
||||
|
||||
const std::unordered_set<PropertyLinkBase*>&
|
||||
PropertyLinkBase::getElementReferences(DocumentObject *feature)
|
||||
{
|
||||
static std::unordered_set<PropertyLinkBase*> none;
|
||||
|
||||
auto it = _ElementRefMap.find(feature);
|
||||
if(it == _ElementRefMap.end())
|
||||
return none;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PropertyLinkBase::updateElementReferences(DocumentObject *feature, bool reverse) {
|
||||
(void)feature;
|
||||
(void)reverse;
|
||||
if(!feature || !feature->getNameInDocument())
|
||||
return;
|
||||
auto it = _ElementRefMap.find(feature);
|
||||
if(it == _ElementRefMap.end())
|
||||
return;
|
||||
std::vector<PropertyLinkBase*> props;
|
||||
props.reserve(it->second.size());
|
||||
props.insert(props.end(),it->second.begin(),it->second.end());
|
||||
for(auto prop : props) {
|
||||
if(prop->getContainer()) {
|
||||
try {
|
||||
prop->updateElementReference(feature,reverse,true);
|
||||
}catch(Base::Exception &e) {
|
||||
e.ReportException();
|
||||
FC_ERR("Failed to update element reference of " << propertyName(prop));
|
||||
}catch(std::exception &e) {
|
||||
FC_ERR("Failed to update element reference of " << propertyName(prop)
|
||||
<< ": " << e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyLinkBase::_registerElementReference(App::DocumentObject *obj, std::string &sub, ShadowSub &shadow)
|
||||
{
|
||||
(void)obj;
|
||||
(void)sub;
|
||||
(void)shadow;
|
||||
if(!obj || !obj->getNameInDocument() || sub.empty())
|
||||
return;
|
||||
if(shadow.first.empty()) {
|
||||
_updateElementReference(0,obj,sub,shadow,false);
|
||||
return;
|
||||
}
|
||||
GeoFeature *geo = 0;
|
||||
const char *element = 0;
|
||||
std::pair<std::string, std::string> elementName;
|
||||
GeoFeature::resolveElement(obj,sub.c_str(), elementName,true,
|
||||
GeoFeature::ElementNameType::Export,0,&element,&geo);
|
||||
if(!geo || !element || !element[0])
|
||||
return;
|
||||
|
||||
if(_ElementRefs.insert(geo).second)
|
||||
_ElementRefMap[geo].insert(this);
|
||||
}
|
||||
|
||||
class StringGuard {
|
||||
public:
|
||||
StringGuard(char *c)
|
||||
:c(c)
|
||||
{
|
||||
v1 = c[0];
|
||||
v2 = c[1];
|
||||
c[0] = '.';
|
||||
c[1] = 0;
|
||||
}
|
||||
~StringGuard()
|
||||
{
|
||||
c[0] = v1;
|
||||
c[1] = v2;
|
||||
}
|
||||
|
||||
char *c;
|
||||
char v1;
|
||||
char v2;
|
||||
};
|
||||
|
||||
void PropertyLinkBase::restoreLabelReference(const DocumentObject *obj,
|
||||
std::string &subname, ShadowSub *shadow)
|
||||
{
|
||||
@@ -277,12 +337,139 @@ bool PropertyLinkBase::_updateElementReference(DocumentObject *feature,
|
||||
App::DocumentObject *obj, std::string &sub, ShadowSub &shadow,
|
||||
bool reverse, bool notify)
|
||||
{
|
||||
(void)feature;
|
||||
(void)obj;
|
||||
(void)reverse;
|
||||
(void)notify;
|
||||
shadow.second = sub;
|
||||
return false;
|
||||
if(!obj || !obj->getNameInDocument()) return false;
|
||||
ShadowSub elementName;
|
||||
const char *subname;
|
||||
if(shadow.first.size())
|
||||
subname = shadow.first.c_str();
|
||||
else if(shadow.second.size())
|
||||
subname = shadow.second.c_str();
|
||||
else
|
||||
subname = sub.c_str();
|
||||
GeoFeature *geo = 0;
|
||||
const char *element=0;
|
||||
auto ret = GeoFeature::resolveElement(obj,subname, elementName,true,
|
||||
GeoFeature::ElementNameType::Export,feature,&element,&geo);
|
||||
if(!ret || !geo || !element || !element[0]) {
|
||||
if(elementName.second.size())
|
||||
shadow.second.swap(elementName.second);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(_ElementRefs.insert(geo).second)
|
||||
_ElementRefMap[geo].insert(this);
|
||||
|
||||
if (!reverse) {
|
||||
if (elementName.first.empty()) {
|
||||
shadow.second.swap(elementName.second);
|
||||
return false;
|
||||
}
|
||||
if(shadow==elementName)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool missing = GeoFeature::hasMissingElement(elementName.second.c_str());
|
||||
if (feature == geo && (missing || reverse)) {
|
||||
// If the referenced element is missing, or we are generating element
|
||||
// map for the first time, or we are re-generating the element map due
|
||||
// to version change, i.e. 'reverse', try search by geometry first
|
||||
const char *oldElement = Data::ComplexGeoData::findElementName(shadow.second.c_str());
|
||||
if(!Data::ComplexGeoData::hasMissingElement(oldElement)) {
|
||||
const auto &names = geo->searchElementCache(oldElement);
|
||||
if(names.size()) {
|
||||
missing = false;
|
||||
std::string newsub(subname, strlen(subname) - strlen(element));
|
||||
newsub += names.front();
|
||||
GeoFeature::resolveElement(obj, newsub.c_str(), elementName,true,
|
||||
GeoFeature::ElementNameType::Export,feature);
|
||||
const auto &oldSub = shadow.first.size()?shadow.first:shadow.second;
|
||||
const auto &newSub = elementName.first.size()?elementName.first:elementName.second;
|
||||
if (oldSub != newSub) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " auto change element reference " << ret->getFullName() << " "
|
||||
<< oldSub << " -> " << newSub);
|
||||
}
|
||||
}
|
||||
// Note: the following code proves to be too risky. There is no way
|
||||
// (so far) to ensure the recompute do not change the geometry. If
|
||||
// the geometry does remain the same, the above geometry search
|
||||
// should be able to find the new reference any way!
|
||||
#if 0
|
||||
else if (missing && reverse && shadow.first.size()) {
|
||||
// reverse means we are trying to either generate the element
|
||||
// name for the first time, or upgrade to a new map version. In
|
||||
// case of upgrading, we still consult the original mapped name
|
||||
// in first try. Here means the first try failed, and the
|
||||
// geometry search cannot find any match, so we try the
|
||||
// non-mapped name as a last resort.
|
||||
//
|
||||
// WARNING! We are assuming the recomputation is done with no
|
||||
// actual property change, and the resulting geometry remains
|
||||
// the same. If this condition is not met, the result may be
|
||||
// undesirable. TODO: find a way to ensure this condition.
|
||||
|
||||
GeoFeature::resolveElement(obj, shadow.second.c_str(), elementName, true,
|
||||
GeoFeature::ElementNameType::Export,feature);
|
||||
if(!elementName.second.empty()) {
|
||||
missing = Data::ComplexGeoData::hasMissingElement(elementName.second.c_str());
|
||||
if (!missing) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " element reference changed " << ret->getFullName() << " "
|
||||
<< shadow.first << " -> " << elementName.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if(notify)
|
||||
aboutToSetValue();
|
||||
if(missing) {
|
||||
FC_WARN(propertyName(this)
|
||||
<< " missing element reference " << ret->getFullName() << " "
|
||||
<< (elementName.first.size()?elementName.first:elementName.second));
|
||||
shadow.second.swap(elementName.second);
|
||||
} else {
|
||||
FC_TRACE(propertyName(this)
|
||||
<< " element reference shadow update " << ret->getFullName() << " "
|
||||
<< shadow.first << " -> " << elementName.first);
|
||||
shadow.swap(elementName);
|
||||
if(shadow.first.size() && Data::ComplexGeoData::hasMappedElementName(sub.c_str()))
|
||||
sub = shadow.first;
|
||||
}
|
||||
|
||||
if(reverse) {
|
||||
if(shadow.first.size() && Data::ComplexGeoData::hasMappedElementName(sub.c_str()))
|
||||
sub = shadow.first;
|
||||
else
|
||||
sub = shadow.second;
|
||||
return true;
|
||||
}
|
||||
if (missing) {
|
||||
if (sub != shadow.first)
|
||||
sub = shadow.second;
|
||||
return true;
|
||||
}
|
||||
auto pos2 = shadow.first.rfind('.');
|
||||
if(pos2 == std::string::npos)
|
||||
return true;
|
||||
++pos2;
|
||||
auto pos = sub.rfind('.');
|
||||
if(pos == std::string::npos)
|
||||
pos = 0;
|
||||
else
|
||||
++pos;
|
||||
if(pos==pos2) {
|
||||
if(sub.compare(pos,sub.size()-pos,&shadow.first[pos2])!=0) {
|
||||
FC_LOG("element reference update " << sub << " -> " << shadow.first);
|
||||
sub.replace(pos,sub.size()-pos,&shadow.first[pos2]);
|
||||
}
|
||||
} else if(sub!=shadow.second) {
|
||||
FC_LOG("element reference update " << sub << " -> " << shadow.second);
|
||||
sub = shadow.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<DocumentObject*, std::string>
|
||||
@@ -291,6 +478,8 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
{
|
||||
std::pair<DocumentObject*, std::string> res;
|
||||
res.first = 0;
|
||||
if (!obj)
|
||||
return res;
|
||||
|
||||
if(oldObj == obj) {
|
||||
if(owner == parent) {
|
||||
@@ -310,6 +499,11 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
} else if (newObj == obj) {
|
||||
// This means the new object is already sub-object of this parent
|
||||
// (consider a case of swapping the tool and base object of the Cut
|
||||
// feature). We'll swap the old and new object.
|
||||
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
|
||||
}
|
||||
if(!subname || !subname[0])
|
||||
return res;
|
||||
@@ -320,6 +514,8 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
for(auto pos=sub.find('.');pos!=std::string::npos;pos=sub.find('.',pos)) {
|
||||
++pos;
|
||||
char c = sub[pos];
|
||||
if (c == '.')
|
||||
continue;
|
||||
sub[pos] = 0;
|
||||
auto sobj = obj->getSubObject(sub.c_str());
|
||||
sub[pos] = c;
|
||||
@@ -344,6 +540,8 @@ PropertyLinkBase::tryReplaceLink(const PropertyContainer *owner, DocumentObject
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}else if(sobj == newObj) {
|
||||
return tryReplaceLink(owner, obj, parent, newObj, oldObj, subname);
|
||||
}else if(prev == parent)
|
||||
break;
|
||||
prev = sobj;
|
||||
@@ -359,6 +557,8 @@ PropertyLinkBase::tryReplaceLinkSubs(const PropertyContainer *owner,
|
||||
{
|
||||
std::pair<DocumentObject*,std::vector<std::string> > res;
|
||||
res.first = 0;
|
||||
if (!obj)
|
||||
return res;
|
||||
|
||||
auto r = tryReplaceLink(owner,obj,parent,oldObj,newObj);
|
||||
if(r.first) {
|
||||
@@ -918,7 +1118,7 @@ TYPESYSTEM_SOURCE(App::PropertyLinkSubHidden, App::PropertyLinkSub)
|
||||
|
||||
|
||||
PropertyLinkSub::PropertyLinkSub()
|
||||
: _pcLinkSub(nullptr), _restoreLabel(false)
|
||||
: _pcLinkSub(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -975,9 +1175,10 @@ void PropertyLinkSub::setValue(App::DocumentObject * lValue,
|
||||
#endif
|
||||
_pcLinkSub=lValue;
|
||||
_cSubList=std::move(subs);
|
||||
if(shadows.size()==_cSubList.size())
|
||||
if(shadows.size()==_cSubList.size()) {
|
||||
_ShadowSubList = std::move(shadows);
|
||||
else
|
||||
onContainerRestored(); // re-register element references
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_cSubList);
|
||||
hasSetValue();
|
||||
@@ -994,13 +1195,22 @@ const std::vector<std::string>& PropertyLinkSub::getSubValues(void) const
|
||||
}
|
||||
|
||||
static inline const std::string &getSubNameWithStyle(const std::string &subName,
|
||||
const PropertyLinkBase::ShadowSub &shadow, bool newStyle)
|
||||
const PropertyLinkBase::ShadowSub &shadow, bool newStyle, std::string &tmp)
|
||||
{
|
||||
if(!newStyle) {
|
||||
if(shadow.second.size())
|
||||
return shadow.second;
|
||||
}else if(shadow.first.size())
|
||||
}else if(shadow.first.size()) {
|
||||
if (Data::ComplexGeoData::hasMissingElement(shadow.second.c_str())) {
|
||||
auto pos = shadow.first.rfind('.');
|
||||
if (pos != std::string::npos) {
|
||||
tmp = shadow.first.substr(0, pos+1);
|
||||
tmp += shadow.second;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
return shadow.first;
|
||||
}
|
||||
return subName;
|
||||
}
|
||||
|
||||
@@ -1008,20 +1218,24 @@ std::vector<std::string> PropertyLinkSub::getSubValues(bool newStyle) const {
|
||||
assert(_cSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_cSubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> PropertyLinkSub::getSubValuesStartsWith(const char* starter, bool newStyle) const
|
||||
{
|
||||
(void)newStyle;
|
||||
|
||||
std::vector<std::string> temp;
|
||||
for(std::vector<std::string>::const_iterator it=_cSubList.begin();it!=_cSubList.end();++it)
|
||||
if(strncmp(starter,it->c_str(),strlen(starter))==0)
|
||||
temp.push_back(*it);
|
||||
return temp;
|
||||
assert(_cSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i) {
|
||||
const auto &sub = getSubNameWithStyle(_cSubList[i],_ShadowSubList[i],newStyle,tmp);
|
||||
auto element = Data::ComplexGeoData::findElementName(sub.c_str());
|
||||
if(element && boost::starts_with(element,starter))
|
||||
ret.emplace_back(element);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
App::DocumentObject * PropertyLinkSub::getValue(Base::Type t) const
|
||||
@@ -1036,8 +1250,9 @@ PyObject *PropertyLinkSub::getPyObject(void)
|
||||
if (_pcLinkSub) {
|
||||
_pcLinkSub->getPyObject();
|
||||
tup[0] = Py::asObject(_pcLinkSub->getPyObject());
|
||||
for(unsigned int i = 0;i<_cSubList.size(); i++)
|
||||
list[i] = Py::String(_cSubList[i]);
|
||||
int i = 0;
|
||||
for (auto &sub : getSubValues(testFlag(LinkNewElement)))
|
||||
list[i++] = Py::String(sub);
|
||||
tup[1] = list;
|
||||
return Py::new_reference_to(tup);
|
||||
}
|
||||
@@ -1310,12 +1525,9 @@ std::string PropertyLinkBase::tryImportSubName(const App::DocumentObject *obj, c
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#define ATTR_SHADOWED "shadowed"
|
||||
#define ATTR_SHADOW "shadow"
|
||||
#define ATTR_MAPPED "mapped"
|
||||
|
||||
// We do not have topo naming yet, ignore shadow sub for now
|
||||
#define IGNORE_SHADOW true
|
||||
static const char *AttrShadowed = "shadowed";
|
||||
static const char *AttrShadow = "shadow";
|
||||
static const char *AttrMapped = "mapped";
|
||||
|
||||
void PropertyLinkSub::Save (Base::Writer &writer) const
|
||||
{
|
||||
@@ -1328,7 +1540,7 @@ void PropertyLinkSub::Save (Base::Writer &writer) const
|
||||
internal_name = _pcLinkSub->getExportName();
|
||||
writer.Stream() << writer.ind() << "<LinkSub value=\""
|
||||
<< internal_name <<"\" count=\"" << _cSubList.size();
|
||||
writer.Stream() << "\">" << std::endl;
|
||||
writer.Stream() << "\">\n";
|
||||
writer.incInd();
|
||||
auto owner = dynamic_cast<DocumentObject*>(getContainer());
|
||||
bool exporting = owner && owner->isExporting();
|
||||
@@ -1343,18 +1555,18 @@ void PropertyLinkSub::Save (Base::Writer &writer) const
|
||||
std::string exportName;
|
||||
writer.Stream() << encodeAttribute(exportSubName(exportName,_pcLinkSub,sub.c_str()));
|
||||
if(shadow.second.size() && shadow.first == _cSubList[i])
|
||||
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
|
||||
writer.Stream() << "\" " << AttrMapped << "=\"1";
|
||||
} else {
|
||||
writer.Stream() << encodeAttribute(sub);
|
||||
if(_cSubList[i].size()) {
|
||||
if(sub!=_cSubList[i]) {
|
||||
// Stores the actual value that is shadowed. For new version FC,
|
||||
// we will restore this shadowed value instead.
|
||||
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_cSubList[i]);
|
||||
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_cSubList[i]);
|
||||
}else if(shadow.first.size()){
|
||||
// Here means the user set value is old style element name.
|
||||
// We shall then store the shadow somewhere else.
|
||||
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
|
||||
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1395,15 +1607,15 @@ void PropertyLinkSub::Restore(Base::XMLReader &reader)
|
||||
for (int i = 0; i < count; i++) {
|
||||
reader.readElement("Sub");
|
||||
shadows[i].second = importSubName(reader,reader.getAttribute("value"),restoreLabel);
|
||||
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW) {
|
||||
if(reader.hasAttribute(AttrShadowed)) {
|
||||
values[i] = shadows[i].first =
|
||||
importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
|
||||
importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
|
||||
} else {
|
||||
values[i] = shadows[i].second;
|
||||
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
|
||||
shadows[i].first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadow))
|
||||
shadows[i].first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
|
||||
}
|
||||
if(reader.hasAttribute(ATTR_MAPPED))
|
||||
if(reader.hasAttribute(AttrMapped))
|
||||
mapped.push_back(i);
|
||||
}
|
||||
setFlag(LinkRestoreLabel,restoreLabel);
|
||||
@@ -1503,6 +1715,7 @@ Property *PropertyLinkSub::Copy(void) const
|
||||
PropertyLinkSub *p= new PropertyLinkSub();
|
||||
p->_pcLinkSub = _pcLinkSub;
|
||||
p->_cSubList = _cSubList;
|
||||
p->_ShadowSubList = _ShadowSubList;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1773,9 +1986,10 @@ void PropertyLinkSubList::setValues(std::vector<DocumentObject*>&& lValue,
|
||||
aboutToSetValue();
|
||||
_lValueList = std::move(lValue);
|
||||
_lSubList = std::move(lSubNames);
|
||||
if(ShadowSubList.size()==_lSubList.size())
|
||||
if(ShadowSubList.size()==_lSubList.size()) {
|
||||
_ShadowSubList = std::move(ShadowSubList);
|
||||
else
|
||||
onContainerRestored(); // re-register element references
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_lSubList);
|
||||
hasSetValue();
|
||||
@@ -2000,7 +2214,7 @@ std::vector<PropertyLinkSubList::SubSet> PropertyLinkSubList::getSubListValues(b
|
||||
PyObject *PropertyLinkSubList::getPyObject(void)
|
||||
{
|
||||
#if 1
|
||||
std::vector<SubSet> subLists = getSubListValues();
|
||||
std::vector<SubSet> subLists = getSubListValues(testFlag(LinkNewElement));
|
||||
std::size_t count = subLists.size();
|
||||
#if 0//FIXME: Should switch to tuple
|
||||
Py::Tuple sequence(count);
|
||||
@@ -2191,18 +2405,18 @@ void PropertyLinkSubList::Save (Base::Writer &writer) const
|
||||
std::string exportName;
|
||||
writer.Stream() << encodeAttribute(exportSubName(exportName,obj,sub.c_str()));
|
||||
if(shadow.second.size() && _lSubList[i]==shadow.first)
|
||||
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
|
||||
writer.Stream() << "\" " << AttrMapped << "=\"1";
|
||||
} else {
|
||||
writer.Stream() << encodeAttribute(sub);
|
||||
if(_lSubList[i].size()) {
|
||||
if(sub!=_lSubList[i]) {
|
||||
// Stores the actual value that is shadowed. For new version FC,
|
||||
// we will restore this shadowed value instead.
|
||||
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_lSubList[i]);
|
||||
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_lSubList[i]);
|
||||
}else if(shadow.first.size()) {
|
||||
// Here means the user set value is old style element name.
|
||||
// We shall then store the shadow somewhere else.
|
||||
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
|
||||
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2243,15 +2457,15 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader)
|
||||
shadows.emplace_back();
|
||||
auto &shadow = shadows.back();
|
||||
shadow.second = importSubName(reader,reader.getAttribute("sub"),restoreLabel);
|
||||
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW) {
|
||||
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadowed)) {
|
||||
shadow.first = importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
|
||||
SubNames.push_back(shadow.first);
|
||||
}else{
|
||||
SubNames.push_back(shadow.second);
|
||||
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
|
||||
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadow))
|
||||
shadow.first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
|
||||
}
|
||||
if(reader.hasAttribute(ATTR_MAPPED))
|
||||
if(reader.hasAttribute(AttrMapped))
|
||||
mapped.push_back(i);
|
||||
} else if (reader.isVerbose())
|
||||
Base::Console().Warning("Lost link to '%s' while loading, maybe "
|
||||
@@ -2262,7 +2476,7 @@ void PropertyLinkSubList::Restore(Base::XMLReader &reader)
|
||||
reader.readEndElement("LinkSubList");
|
||||
|
||||
// assignment
|
||||
setValues(values,SubNames,std::move(shadows));
|
||||
setValues(values,std::move(SubNames),std::move(shadows));
|
||||
_mapped.swap(mapped);
|
||||
}
|
||||
|
||||
@@ -2451,6 +2665,7 @@ Property *PropertyLinkSubList::Copy(void) const
|
||||
PropertyLinkSubList *p = new PropertyLinkSubList();
|
||||
p->_lValueList = _lValueList;
|
||||
p->_lSubList = _lSubList;
|
||||
p->_ShadowSubList = _ShadowSubList;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2474,8 +2689,9 @@ std::vector<std::string> PropertyLinkSubList::getSubValues(bool newStyle) const
|
||||
assert(_lSubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_ShadowSubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_lSubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2628,7 +2844,7 @@ public:
|
||||
App::Document *pDoc,PropertyXLink *l, const char *objName)
|
||||
{
|
||||
QString path;
|
||||
l->filePath = getDocPath(filename,pDoc,true,&path);
|
||||
l->filePath = getDocPath(filename,pDoc,false,&path);
|
||||
|
||||
FC_LOG("finding doc " << filename);
|
||||
|
||||
@@ -2979,6 +3195,7 @@ PropertyXLink::PropertyXLink(bool _allowPartial, PropertyLinkBase *parent)
|
||||
setAllowPartial(_allowPartial);
|
||||
setAllowExternal(true);
|
||||
setSyncSubObject(true);
|
||||
// setReturnNewElement(true);
|
||||
if(parent)
|
||||
setContainer(parent->getContainer());
|
||||
}
|
||||
@@ -3010,18 +3227,27 @@ void PropertyXLink::detach() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string PropertyXLink::getFullName(bool python) const {
|
||||
if((getName() && getName()[0]) || python || !parentProp)
|
||||
return inherited::getFullName(python);
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << parentProp->getFullName() << ":" << this;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void PropertyXLink::aboutToSetValue() {
|
||||
if(parentProp)
|
||||
parentProp->aboutToSetChildValue(*this);
|
||||
else
|
||||
PropertyLinkBase::aboutToSetValue();
|
||||
inherited::aboutToSetValue();
|
||||
}
|
||||
|
||||
void PropertyXLink::hasSetValue() {
|
||||
if(parentProp)
|
||||
parentProp->hasSetChildValue(*this);
|
||||
else
|
||||
PropertyLinkBase::hasSetValue();
|
||||
inherited::hasSetValue();
|
||||
}
|
||||
|
||||
void PropertyXLink::setSubName(const char *subname)
|
||||
@@ -3035,13 +3261,14 @@ void PropertyXLink::setSubName(const char *subname)
|
||||
}
|
||||
|
||||
void PropertyXLink::setSubValues(std::vector<std::string> &&subs,
|
||||
std::vector<ShadowSub> &&shadows)
|
||||
std::vector<ShadowSub> &&shadows)
|
||||
{
|
||||
_SubList = std::move(subs);
|
||||
_ShadowSubList.clear();
|
||||
if(shadows.size() == _SubList.size())
|
||||
if(shadows.size() == _SubList.size()) {
|
||||
_ShadowSubList = std::move(shadows);
|
||||
else
|
||||
onContainerRestored(); // re-register element references
|
||||
} else
|
||||
updateElementReference(nullptr);
|
||||
checkLabelReferences(_SubList);
|
||||
}
|
||||
@@ -3330,9 +3557,11 @@ void PropertyXLink::Save (Base::Writer &writer) const {
|
||||
}else
|
||||
FC_WARN("PropertyXLink export without saving the document");
|
||||
}
|
||||
if(_path.size())
|
||||
path = _path.c_str();
|
||||
}
|
||||
} else if (filePath.size())
|
||||
_path = DocInfo::getDocPath(filePath.c_str(),owner->getDocument(),true);
|
||||
|
||||
if(_path.size())
|
||||
path = _path.c_str();
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<XLink file=\"" << encodeAttribute(path)
|
||||
<< "\" stamp=\"" << (docInfo&&docInfo->pcDoc?docInfo->pcDoc->LastModifiedDate.getValue():"")
|
||||
@@ -3353,14 +3582,14 @@ void PropertyXLink::Save (Base::Writer &writer) const {
|
||||
writer.Stream() << "\" sub=\"" <<
|
||||
encodeAttribute(exportSubName(exportName,_pcLink,sub.c_str()));
|
||||
if(shadowSub.second.size() && shadowSub.first==subName)
|
||||
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
|
||||
writer.Stream() << "\" " << AttrMapped << "=\"1";
|
||||
}else{
|
||||
writer.Stream() << "\" sub=\"" << encodeAttribute(sub);
|
||||
if(sub.size()) {
|
||||
if(sub!=subName)
|
||||
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(subName);
|
||||
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(subName);
|
||||
else if(shadowSub.first.size())
|
||||
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadowSub.first);
|
||||
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadowSub.first);
|
||||
}
|
||||
}
|
||||
writer.Stream() << "\"/>" << std::endl;
|
||||
@@ -3378,14 +3607,14 @@ void PropertyXLink::Save (Base::Writer &writer) const {
|
||||
std::string exportName;
|
||||
writer.Stream() << encodeAttribute(exportSubName(exportName,_pcLink,sub.c_str()));
|
||||
if(shadow.second.size() && shadow.first == _SubList[i])
|
||||
writer.Stream() << "\" " ATTR_MAPPED "=\"1";
|
||||
writer.Stream() << "\" " << AttrMapped << "=\"1";
|
||||
} else {
|
||||
writer.Stream() << encodeAttribute(sub);
|
||||
if(_SubList[i].size()) {
|
||||
if(sub!=_SubList[i])
|
||||
writer.Stream() << "\" " ATTR_SHADOWED "=\"" << encodeAttribute(_SubList[i]);
|
||||
writer.Stream() << "\" " << AttrShadowed << "=\"" << encodeAttribute(_SubList[i]);
|
||||
else if(shadow.first.size())
|
||||
writer.Stream() << "\" " ATTR_SHADOW "=\"" << encodeAttribute(shadow.first);
|
||||
writer.Stream() << "\" " << AttrShadow << "=\"" << encodeAttribute(shadow.first);
|
||||
}
|
||||
}
|
||||
writer.Stream()<<"\"/>" << endl;
|
||||
@@ -3432,19 +3661,19 @@ void PropertyXLink::Restore(Base::XMLReader &reader)
|
||||
std::vector<int> mapped;
|
||||
bool restoreLabel = false;
|
||||
if(reader.hasAttribute("sub")) {
|
||||
if(reader.hasAttribute(ATTR_MAPPED))
|
||||
if(reader.hasAttribute(AttrMapped))
|
||||
mapped.push_back(0);
|
||||
subs.emplace_back();
|
||||
auto &subname = subs.back();
|
||||
shadows.emplace_back();
|
||||
auto &shadow = shadows.back();
|
||||
shadow.second = importSubName(reader,reader.getAttribute("sub"),restoreLabel);
|
||||
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW)
|
||||
subname = shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadowed))
|
||||
subname = shadow.first = importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
|
||||
else {
|
||||
subname = shadow.second;
|
||||
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
|
||||
shadow.first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadow))
|
||||
shadow.first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
|
||||
}
|
||||
}else if(reader.hasAttribute("count")) {
|
||||
int count = reader.getAttributeAsInteger("count");
|
||||
@@ -3453,15 +3682,15 @@ void PropertyXLink::Restore(Base::XMLReader &reader)
|
||||
for (int i = 0; i < count; i++) {
|
||||
reader.readElement("Sub");
|
||||
shadows[i].second = importSubName(reader,reader.getAttribute("value"),restoreLabel);
|
||||
if(reader.hasAttribute(ATTR_SHADOWED) && !IGNORE_SHADOW)
|
||||
subs[i] = shadows[i].first =
|
||||
importSubName(reader,reader.getAttribute(ATTR_SHADOWED),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadowed))
|
||||
subs[i] = shadows[i].first =
|
||||
importSubName(reader,reader.getAttribute(AttrShadowed),restoreLabel);
|
||||
else {
|
||||
subs[i] = shadows[i].second;
|
||||
if(reader.hasAttribute(ATTR_SHADOW) && !IGNORE_SHADOW)
|
||||
shadows[i].first = importSubName(reader,reader.getAttribute(ATTR_SHADOW),restoreLabel);
|
||||
if(reader.hasAttribute(AttrShadow))
|
||||
shadows[i].first = importSubName(reader,reader.getAttribute(AttrShadow),restoreLabel);
|
||||
}
|
||||
if(reader.hasAttribute(ATTR_MAPPED))
|
||||
if(reader.hasAttribute(AttrMapped))
|
||||
mapped.push_back(i);
|
||||
}
|
||||
reader.readEndElement("XLink");
|
||||
@@ -3542,8 +3771,10 @@ void PropertyXLink::copyTo(PropertyXLink &other,
|
||||
}
|
||||
if(subs)
|
||||
other._SubList = std::move(*subs);
|
||||
else
|
||||
else {
|
||||
other._SubList = _SubList;
|
||||
other._ShadowSubList = _ShadowSubList;
|
||||
}
|
||||
other._Flags = _Flags;
|
||||
}
|
||||
|
||||
@@ -3662,7 +3893,7 @@ PyObject *PropertyXLink::getPyObject(void)
|
||||
{
|
||||
if(!_pcLink)
|
||||
Py_Return;
|
||||
const auto &subs = getSubValues(false);
|
||||
const auto &subs = getSubValues(testFlag(LinkNewElement));
|
||||
if(subs.empty())
|
||||
return _pcLink->getPyObject();
|
||||
Py::Tuple ret(2);
|
||||
@@ -3726,7 +3957,7 @@ void PropertyXLink::setPyObject(PyObject *value) {
|
||||
const char *PropertyXLink::getSubName(bool newStyle) const {
|
||||
if(_SubList.empty() || _ShadowSubList.empty())
|
||||
return "";
|
||||
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle).c_str();
|
||||
return getSubNameWithStyle(_SubList[0],_ShadowSubList[0],newStyle,tmpShadow).c_str();
|
||||
}
|
||||
|
||||
void PropertyXLink::getLinks(std::vector<App::DocumentObject *> &objs,
|
||||
@@ -3757,20 +3988,24 @@ std::vector<std::string> PropertyXLink::getSubValues(bool newStyle) const {
|
||||
assert(_SubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
ret.reserve(_SubList.size());
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i)
|
||||
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle));
|
||||
ret.push_back(getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> PropertyXLink::getSubValuesStartsWith(const char* starter, bool newStyle) const
|
||||
{
|
||||
(void)newStyle;
|
||||
|
||||
std::vector<std::string> temp;
|
||||
for(std::vector<std::string>::const_iterator it=_SubList.begin();it!=_SubList.end();++it)
|
||||
if(strncmp(starter,it->c_str(),strlen(starter))==0)
|
||||
temp.push_back(*it);
|
||||
return temp;
|
||||
assert(_SubList.size() == _ShadowSubList.size());
|
||||
std::vector<std::string> ret;
|
||||
std::string tmp;
|
||||
for(size_t i=0;i<_ShadowSubList.size();++i) {
|
||||
const auto &sub = getSubNameWithStyle(_SubList[i],_ShadowSubList[i],newStyle,tmp);
|
||||
auto element = Data::ComplexGeoData::findElementName(sub.c_str());
|
||||
if(element && boost::starts_with(element,starter))
|
||||
ret.emplace_back(element);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PropertyXLink::setAllowPartial(bool enable) {
|
||||
@@ -3826,7 +4061,7 @@ PyObject *PropertyXLinkSub::getPyObject(void)
|
||||
Py_Return;
|
||||
Py::Tuple ret(2);
|
||||
ret.setItem(0,Py::Object(_pcLink->getPyObject(),true));
|
||||
const auto &subs = getSubValues(false);
|
||||
const auto &subs = getSubValues(testFlag(LinkNewElement));
|
||||
Py::List list(subs.size());
|
||||
int i = 0;
|
||||
PropertyString propString;
|
||||
@@ -3852,6 +4087,7 @@ PropertyXLinkSubList::PropertyXLinkSubList()
|
||||
{
|
||||
_pcScope = LinkScope::Global;
|
||||
setSyncSubObject(true);
|
||||
// setReturnNewElement(true);
|
||||
}
|
||||
|
||||
PropertyXLinkSubList::~PropertyXLinkSubList()
|
||||
@@ -4087,7 +4323,7 @@ PyObject *PropertyXLinkSubList::getPyObject(void)
|
||||
Py::Tuple tup(2);
|
||||
tup[0] = Py::asObject(obj->getPyObject());
|
||||
|
||||
const auto &subs = link.getSubValues();
|
||||
const auto &subs = link.getSubValues(testFlag(LinkNewElement));
|
||||
Py::Tuple items(subs.size());
|
||||
for (std::size_t j = 0; j < subs.size(); j++) {
|
||||
items[j] = Py::String(subs[j]);
|
||||
@@ -4107,7 +4343,7 @@ void PropertyXLinkSubList::setPyObject(PyObject *value)
|
||||
this->setValue(dummy.getValue(), dummy.getSubValues());
|
||||
return;
|
||||
}
|
||||
catch (Base::Exception&) {}
|
||||
catch (Base::TypeError&) {}
|
||||
|
||||
if (!PyTuple_Check(value) && !PyList_Check(value))
|
||||
throw Base::TypeError("Invalid type. Accepts (DocumentObject, (subname...)) or sequence of such type.");
|
||||
|
||||
+19
-4
@@ -26,8 +26,11 @@
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include "Property.h"
|
||||
|
||||
namespace Base {
|
||||
@@ -38,6 +41,8 @@ namespace App
|
||||
{
|
||||
class DocumentObject;
|
||||
class Document;
|
||||
class GeoFeature;
|
||||
class SubObjectT;
|
||||
|
||||
class DocInfo;
|
||||
typedef std::shared_ptr<DocInfo> DocInfoPtr;
|
||||
@@ -254,7 +259,7 @@ public:
|
||||
|
||||
/// Helper function to return linked objects using an std::inserter
|
||||
template<class T>
|
||||
void getLinkedObjects(T &inserter, bool all=false) const {
|
||||
void getLinkedObjects(T inserter, bool all=false) const {
|
||||
std::vector<App::DocumentObject*> ret;
|
||||
getLinks(ret,all);
|
||||
std::copy(ret.begin(),ret.end(),inserter);
|
||||
@@ -262,7 +267,7 @@ public:
|
||||
|
||||
/// Helper function to return a map of linked object and its subname references
|
||||
void getLinkedElements(std::map<App::DocumentObject*, std::vector<std::string> > &elements,
|
||||
bool newStyle=true, bool all=true) const
|
||||
bool newStyle=true, bool all=false) const
|
||||
{
|
||||
std::vector<App::DocumentObject*> ret;
|
||||
std::vector<std::string> subs;
|
||||
@@ -275,12 +280,14 @@ public:
|
||||
|
||||
/// Helper function to return a map of linked object and its subname references
|
||||
std::map<App::DocumentObject*, std::vector<std::string> >
|
||||
linkedElements(bool newStyle=true, bool all=true) const
|
||||
linkedElements(bool newStyle=true, bool all=false) const
|
||||
{
|
||||
std::map<App::DocumentObject*, std::vector<std::string> > ret;
|
||||
getLinkedElements(ret,newStyle,all);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<App::SubObjectT> linkedElementsT(bool all) const;
|
||||
//@}
|
||||
|
||||
virtual bool isSame(const Property &other) const override;
|
||||
@@ -346,6 +353,8 @@ public:
|
||||
/// Update all element references in all link properties of \a feature
|
||||
static void updateElementReferences(DocumentObject *feature, bool reverse=false);
|
||||
|
||||
/// Obtain link properties that contain element references to a given object
|
||||
static const std::unordered_set<PropertyLinkBase*>& getElementReferences(DocumentObject *);
|
||||
|
||||
/** Helper function for update individual element reference
|
||||
*
|
||||
@@ -538,6 +547,7 @@ public:
|
||||
LinkAllowPartial,
|
||||
LinkRestoreLabel,
|
||||
LinkSyncSubObject, // used by DlgPropertyLink
|
||||
LinkNewElement, // return new element name in getPyObject
|
||||
};
|
||||
inline bool testFlag(int flag) const {
|
||||
return _Flags.test((std::size_t)flag);
|
||||
@@ -545,6 +555,8 @@ public:
|
||||
|
||||
virtual void setAllowPartial(bool enable) { (void)enable; }
|
||||
|
||||
void setReturnNewElement(bool enable);
|
||||
|
||||
protected:
|
||||
virtual void hasSetValue() override;
|
||||
|
||||
@@ -1052,6 +1064,7 @@ class PropertyXLinkSubList;
|
||||
class AppExport PropertyXLink : public PropertyLinkGlobal
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
typedef PropertyLinkGlobal inherited;
|
||||
|
||||
public:
|
||||
PropertyXLink(bool allowPartial=false, PropertyLinkBase *parent=nullptr);
|
||||
@@ -1137,6 +1150,7 @@ public:
|
||||
|
||||
virtual void setAllowPartial(bool enable) override;
|
||||
|
||||
virtual std::string getFullName(bool python=false) const override;
|
||||
const char *getFilePath() const {
|
||||
return filePath.c_str();
|
||||
}
|
||||
@@ -1169,6 +1183,7 @@ protected:
|
||||
std::vector<ShadowSub> _ShadowSubList;
|
||||
std::vector<int> _mapped;
|
||||
PropertyLinkBase *parentProp;
|
||||
mutable std::string tmpShadow;
|
||||
};
|
||||
|
||||
|
||||
@@ -1198,10 +1213,10 @@ class AppExport PropertyXLinkSubList: public PropertyLinkBase
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
typedef typename AtomicPropertyChangeInterface<PropertyXLinkSubList>::AtomicPropertyChange atomic_change;
|
||||
friend atomic_change;
|
||||
|
||||
public:
|
||||
PropertyXLinkSubList();
|
||||
virtual ~PropertyXLinkSubList();
|
||||
|
||||
|
||||
@@ -392,9 +392,9 @@ void PropertyEnumeration::setEnumVector(const std::vector<std::string> &values)
|
||||
hasSetValue();
|
||||
}
|
||||
|
||||
const char ** PropertyEnumeration::getEnums() const
|
||||
bool PropertyEnumeration::hasEnums() const
|
||||
{
|
||||
return _enum.getEnums();
|
||||
return _enum.hasEnums();
|
||||
}
|
||||
|
||||
bool PropertyEnumeration::isValid() const
|
||||
@@ -447,7 +447,7 @@ void PropertyEnumeration::Restore(Base::XMLReader &reader)
|
||||
|
||||
if (val < 0) {
|
||||
// If the enum is empty at this stage do not print a warning
|
||||
if (_enum.getEnums())
|
||||
if (_enum.hasEnums())
|
||||
Base::Console().Warning("Enumeration index %d is out of range, ignore it\n", val);
|
||||
val = getValue();
|
||||
}
|
||||
@@ -598,13 +598,13 @@ bool PropertyEnumeration::getPyPathValue(const ObjectIdentifier &path, Py::Objec
|
||||
if (p == ".Enum" || p == ".All") {
|
||||
Base::PyGILStateLocker lock;
|
||||
Py::Tuple res(_enum.maxValue()+1);
|
||||
const char **enums = _enum.getEnums();
|
||||
std::vector<std::string> enums = _enum.getEnumVector();
|
||||
PropertyString tmp;
|
||||
for(int i=0;i<=_enum.maxValue();++i) {
|
||||
for(int i=0;i< int(enums.size());++i) {
|
||||
tmp.setValue(enums[i]);
|
||||
res.setItem(i,Py::asObject(tmp.getPyObject()));
|
||||
}
|
||||
if(p == ".Enum")
|
||||
if (p == ".Enum")
|
||||
r = res;
|
||||
else {
|
||||
Py::Tuple tuple(2);
|
||||
@@ -1374,7 +1374,7 @@ PropertyString::~PropertyString()
|
||||
|
||||
void PropertyString::setValue(const char* newLabel)
|
||||
{
|
||||
if(!newLabel)
|
||||
if(!newLabel)
|
||||
return;
|
||||
|
||||
if(_cValue == newLabel)
|
||||
@@ -2065,10 +2065,9 @@ PyObject *PropertyBool::getPyObject()
|
||||
|
||||
void PropertyBool::setPyObject(PyObject *value)
|
||||
{
|
||||
if (PyBool_Check(value))
|
||||
setValue(PyObject_IsTrue(value)!=0);
|
||||
else if(PyLong_Check(value))
|
||||
setValue(PyLong_AsLong(value)!=0);
|
||||
if (PyBool_Check(value) || PyLong_Check(value)) {
|
||||
setValue(PyObject_IsTrue(value) ? true : false);
|
||||
}
|
||||
else {
|
||||
std::string error = std::string("type must be bool, not ");
|
||||
error += value->ob_type->tp_name;
|
||||
|
||||
@@ -206,7 +206,7 @@ public:
|
||||
/// set enum values as vector of strings
|
||||
void setEnumVector(const std::vector<std::string> &);
|
||||
/// get the pointer to the enum list
|
||||
const char ** getEnums(void) const;
|
||||
bool hasEnums() const;
|
||||
|
||||
/// Returns true if the instance is in a usable state
|
||||
bool isValid(void) const;
|
||||
|
||||
@@ -193,14 +193,14 @@ void PropertyQuantityConstraint::setPyObject(PyObject *value)
|
||||
quant.setValue(temp);
|
||||
|
||||
if (unit.isEmpty()){
|
||||
PropertyFloat::setValue(quant.getValue());
|
||||
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
|
||||
return;
|
||||
}
|
||||
|
||||
if (unit != _Unit)
|
||||
throw Base::UnitsMismatchError("Not matching Unit!");
|
||||
|
||||
PropertyFloat::setValue(quant.getValue());
|
||||
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
|
||||
+23
-9
@@ -37,7 +37,7 @@ using namespace App;
|
||||
const int App::CellAddress::MAX_ROWS = 16384;
|
||||
const int App::CellAddress::MAX_COLUMNS = 26 * 26 + 26;
|
||||
|
||||
Range::Range(const char * range)
|
||||
Range::Range(const char * range, bool normalize)
|
||||
{
|
||||
std::string from;
|
||||
std::string to;
|
||||
@@ -62,28 +62,42 @@ Range::Range(const char * range)
|
||||
row_end = end.row();
|
||||
col_end = end.col();
|
||||
|
||||
if (normalize)
|
||||
this->normalize();
|
||||
row_curr = row_begin;
|
||||
col_curr = col_begin;
|
||||
}
|
||||
|
||||
Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end)
|
||||
: row_curr(_row_begin)
|
||||
, col_curr(_col_begin)
|
||||
, row_begin(_row_begin)
|
||||
Range::Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize)
|
||||
: row_begin(_row_begin)
|
||||
, col_begin(_col_begin)
|
||||
, row_end(_row_end)
|
||||
, col_end(_col_end)
|
||||
{
|
||||
if (normalize)
|
||||
this->normalize();
|
||||
row_curr = row_begin;
|
||||
col_curr = col_begin;
|
||||
}
|
||||
|
||||
Range::Range(const CellAddress &from, const CellAddress &to)
|
||||
: row_curr(from.row())
|
||||
, col_curr(from.col())
|
||||
, row_begin(from.row())
|
||||
Range::Range(const CellAddress &from, const CellAddress &to, bool normalize)
|
||||
: row_begin(from.row())
|
||||
, col_begin(from.col())
|
||||
, row_end(to.row())
|
||||
, col_end(to.col())
|
||||
{
|
||||
if (normalize)
|
||||
this->normalize();
|
||||
row_curr = row_begin;
|
||||
col_curr = col_begin;
|
||||
}
|
||||
|
||||
void Range::normalize()
|
||||
{
|
||||
if (row_begin > row_end)
|
||||
std::swap(row_begin, row_end);
|
||||
if (col_begin > col_end)
|
||||
std::swap(col_begin, col_end);
|
||||
}
|
||||
|
||||
bool Range::next()
|
||||
|
||||
+6
-3
@@ -117,14 +117,17 @@ protected:
|
||||
|
||||
class AppExport Range {
|
||||
public:
|
||||
Range(const char *range);
|
||||
Range(const char *range, bool normalize=false);
|
||||
|
||||
Range(int _row_begin, int _col_begin, int _row_end, int _col_end);
|
||||
Range(int _row_begin, int _col_begin, int _row_end, int _col_end, bool normalize=false);
|
||||
|
||||
Range(const CellAddress & from, const CellAddress & to);
|
||||
Range(const CellAddress & from, const CellAddress & to, bool normalize=false);
|
||||
|
||||
bool next();
|
||||
|
||||
/** Make sure the range starts from top left and ends with bottom right corner **/
|
||||
void normalize();
|
||||
|
||||
/** Current row */
|
||||
inline int row() const { return row_curr; }
|
||||
|
||||
|
||||
@@ -0,0 +1,749 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include <deque>
|
||||
#include <QCryptographicHash>
|
||||
#include <QHash>
|
||||
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Writer.h>
|
||||
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/bimap/set_of.hpp>
|
||||
#include <boost/bimap/unordered_set_of.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
|
||||
#include "StringHasher.h"
|
||||
#include "StringHasherPy.h"
|
||||
#include "DocumentParams.h"
|
||||
#include "MappedElement.h"
|
||||
#include "StringIDPy.h"
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("App",true,true)
|
||||
|
||||
namespace bio = boost::iostreams;
|
||||
using namespace App;
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
struct StringIDHasher {
|
||||
std::size_t operator()(const StringID *sid) const {
|
||||
if (!sid)
|
||||
return 0;
|
||||
return qHash(sid->data(), qHash(sid->postfix()));
|
||||
}
|
||||
|
||||
bool operator()(const StringID *IDa, const StringID *IDb) const {
|
||||
if (IDa == IDb)
|
||||
return true;
|
||||
if (!IDa || !IDb)
|
||||
return false;
|
||||
return IDa->data() == IDb->data() && IDa->postfix() == IDb->postfix();
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::bimap<
|
||||
boost::bimaps::unordered_set_of<StringID *,
|
||||
StringIDHasher,
|
||||
StringIDHasher>,
|
||||
boost::bimaps::set_of<long>>
|
||||
HashMapBase;
|
||||
|
||||
class StringHasher::HashMap: public HashMapBase
|
||||
{
|
||||
public:
|
||||
bool SaveAll = false;
|
||||
int Threshold = 0;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(App::StringID, Base::BaseClass)
|
||||
|
||||
StringID::~StringID()
|
||||
{
|
||||
if (_hasher)
|
||||
_hasher->_hashes->right.erase(_id);
|
||||
}
|
||||
|
||||
PyObject *StringID::getPyObject() {
|
||||
return new StringIDPy(this);
|
||||
}
|
||||
|
||||
PyObject *StringID::getPyObjectWithIndex(int index) {
|
||||
auto res = new StringIDPy(this);
|
||||
res->_index = index;
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string StringID::toString(int index) const {
|
||||
std::ostringstream ss;
|
||||
ss << '#' << std::hex << value();
|
||||
if (index)
|
||||
ss << ':' << index;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
StringID::IndexID StringID::fromString(const char *name, bool eof, int size) {
|
||||
IndexID res;
|
||||
res.id = 0;
|
||||
res.index = 0;
|
||||
if (!name) {
|
||||
res.id = -1;
|
||||
return res;
|
||||
}
|
||||
if (size < 0)
|
||||
size = std::strlen(name);
|
||||
bio::stream<bio::array_source> iss(name, size);
|
||||
char sep = 0;
|
||||
char sep2 = 0;
|
||||
iss >> sep >> std::hex >> res.id >> sep2 >> res.index;
|
||||
if ((eof && !iss.eof()) || sep != '#' || (sep2 != 0 && sep2 != ':')) {
|
||||
res.id = -1;
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string StringID::dataToText(int index) const {
|
||||
if(isHashed() || isBinary())
|
||||
return _data.toBase64().constData();
|
||||
|
||||
std::string res(_data.constData());
|
||||
if (index)
|
||||
res += std::to_string(index);
|
||||
if (_postfix.size())
|
||||
res += _postfix.constData();
|
||||
return res;
|
||||
}
|
||||
|
||||
void StringID::mark() const
|
||||
{
|
||||
if (isMarked())
|
||||
return;
|
||||
_flags.setFlag(Flag::Marked);
|
||||
for (auto &sid : _sids)
|
||||
sid.deref().mark();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
TYPESYSTEM_SOURCE(App::StringHasher, Base::Persistence)
|
||||
|
||||
StringHasher::StringHasher()
|
||||
:_hashes(new HashMap)
|
||||
{}
|
||||
|
||||
StringHasher::~StringHasher() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void StringHasher::setSaveAll(bool enable) {
|
||||
if (_hashes->SaveAll == enable)
|
||||
return;
|
||||
_hashes->SaveAll = enable;
|
||||
compact();
|
||||
}
|
||||
|
||||
void StringHasher::compact()
|
||||
{
|
||||
if (_hashes->SaveAll)
|
||||
return;
|
||||
|
||||
std::deque<StringIDRef> pendings;
|
||||
for (auto &v : _hashes->right) {
|
||||
if (!v.second->isPersistent() && v.second->getRefCount() == 1)
|
||||
pendings.emplace_back(v.second);
|
||||
}
|
||||
while (pendings.size()) {
|
||||
StringIDRef sid = pendings.front();
|
||||
pendings.pop_front();
|
||||
if (!_hashes->right.erase(sid.value()))
|
||||
continue;
|
||||
sid._sid->_hasher = nullptr;
|
||||
sid._sid->unref();
|
||||
for (auto &s : sid._sid->_sids) {
|
||||
if (s._sid->_hasher == this
|
||||
&& !s._sid->isPersistent()
|
||||
&& s._sid->getRefCount() == 2)
|
||||
pendings.push_back(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool StringHasher::getSaveAll() const {
|
||||
return _hashes->SaveAll;
|
||||
}
|
||||
|
||||
void StringHasher::setThreshold(int threshold) {
|
||||
_hashes->Threshold = threshold;
|
||||
}
|
||||
|
||||
int StringHasher::getThreshold() const {
|
||||
return _hashes->Threshold;
|
||||
}
|
||||
|
||||
long StringHasher::lastID() const {
|
||||
if(_hashes->right.empty())
|
||||
return 0;
|
||||
auto it = _hashes->right.end();
|
||||
--it;
|
||||
return it->first;
|
||||
}
|
||||
|
||||
StringIDRef StringHasher::getID(const char *text, int len, bool hashable) {
|
||||
if (len < 0)
|
||||
len = strlen(text);
|
||||
return getID(QByteArray::fromRawData(text, len), hashable ? Option::Hashable : Option::None);
|
||||
}
|
||||
|
||||
StringIDRef StringHasher::getID(const QByteArray &data, Options options)
|
||||
{
|
||||
bool binary = options.testFlag(Option::Binary);
|
||||
bool hashable = options.testFlag(Option::Hashable);
|
||||
bool nocopy = options.testFlag(Option::NoCopy);
|
||||
|
||||
bool hashed = hashable && _hashes->Threshold > 0
|
||||
&& (int)data.size() > _hashes->Threshold;
|
||||
|
||||
StringID dataID;
|
||||
if (hashed) {
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
hasher.addData(data);
|
||||
dataID._data = hasher.result();
|
||||
}
|
||||
else
|
||||
dataID._data = data;
|
||||
|
||||
auto it = _hashes->left.find(&dataID);
|
||||
if (it != _hashes->left.end())
|
||||
return StringIDRef(it->first);
|
||||
|
||||
if (!hashed && !nocopy)
|
||||
// if not hashed, make a deep copy of the data
|
||||
dataID._data = QByteArray(data.constData(), data.size());
|
||||
|
||||
StringID::Flags flags(StringID::Flag::None);
|
||||
if (binary)
|
||||
flags.setFlag(StringID::Flag::Binary);
|
||||
if (hashed)
|
||||
flags.setFlag(StringID::Flag::Hashed);
|
||||
StringIDRef sid(new StringID(lastID() + 1, dataID._data, flags));
|
||||
return StringIDRef(insert(sid));
|
||||
}
|
||||
|
||||
StringIDRef StringHasher::getID(const Data::MappedName &name,
|
||||
const QVector<StringIDRef> & sids)
|
||||
{
|
||||
StringID anID;
|
||||
anID._postfix = name.postfixBytes();
|
||||
|
||||
Data::IndexedName indexed;
|
||||
if (!anID._postfix.size())
|
||||
indexed = Data::IndexedName(name.dataBytes());
|
||||
if (indexed)
|
||||
anID._data = QByteArray::fromRawData(indexed.getType(), strlen(indexed.getType()));
|
||||
else
|
||||
anID._data = name.dataBytes();
|
||||
|
||||
auto it = _hashes->left.find(&anID);
|
||||
if (it != _hashes->left.end()) {
|
||||
auto res = StringIDRef(it->first);
|
||||
if (indexed)
|
||||
res._index = indexed.getIndex();
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!indexed && name.isRaw())
|
||||
anID._data = QByteArray(name.dataBytes().constData(),
|
||||
name.dataBytes().size());
|
||||
|
||||
StringIDRef postfixRef;
|
||||
if (anID._postfix.size() && anID._postfix.indexOf("#") < 0) {
|
||||
postfixRef = getID(anID._postfix);
|
||||
postfixRef.toBytes(anID._postfix);
|
||||
}
|
||||
|
||||
StringIDRef indexRef;
|
||||
if (indexed)
|
||||
indexRef = getID(anID._data);
|
||||
|
||||
StringIDRef sid(new StringID(lastID() + 1, anID._data));
|
||||
StringID &id = *sid._sid;
|
||||
if (anID._postfix.size()) {
|
||||
id._flags.setFlag(StringID::Flag::Postfixed);
|
||||
id._postfix = anID._postfix;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (auto &sid : sids) {
|
||||
if (sid && sid._sid->_hasher == this)
|
||||
++count;
|
||||
}
|
||||
|
||||
int extra = (postfixRef ? 1 : 0) + (indexRef ? 1 : 0);
|
||||
if (count == sids.size() && !postfixRef && !indexRef)
|
||||
id._sids = sids;
|
||||
else {
|
||||
id._sids.reserve(count + extra);
|
||||
if (postfixRef) {
|
||||
id._flags.setFlag(StringID::Flag::PostfixEncoded);
|
||||
id._sids.push_back(postfixRef);
|
||||
}
|
||||
if (indexRef) {
|
||||
id._flags.setFlag(StringID::Flag::Indexed);
|
||||
id._sids.push_back(indexRef);
|
||||
}
|
||||
for (auto &s : sids) {
|
||||
if (s && s._sid->_hasher == this)
|
||||
id._sids.push_back(s);
|
||||
}
|
||||
}
|
||||
if (id._sids.size() > 10) {
|
||||
std::sort(id._sids.begin() + extra, id._sids.end());
|
||||
id._sids.erase(std::unique(id._sids.begin() + extra, id._sids.end()), id._sids.end());
|
||||
}
|
||||
|
||||
if (id._postfix.size() && !indexed) {
|
||||
StringID::IndexID res = StringID::fromString(id._data);
|
||||
if (res.id > 0) {
|
||||
int offset = id.isPostfixEncoded() ? 1 : 0;
|
||||
for (int i = offset; i < id._sids.size(); ++i) {
|
||||
if (id._sids[i].value() == res.id) {
|
||||
if (i!=offset)
|
||||
std::swap(id._sids[offset], id._sids[i]);
|
||||
if (res.index != 0)
|
||||
id._flags.setFlag(StringID::Flag::PrefixIDIndex);
|
||||
else
|
||||
id._flags.setFlag(StringID::Flag::PrefixID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StringIDRef(insert(sid), indexed.getIndex());
|
||||
}
|
||||
|
||||
StringIDRef StringHasher::getID(long id, int index) const {
|
||||
if (id<=0)
|
||||
return StringIDRef();
|
||||
auto it = _hashes->right.find(id);
|
||||
if (it == _hashes->right.end())
|
||||
return StringIDRef();
|
||||
StringIDRef res(it->second);
|
||||
res._index = index;
|
||||
return res;
|
||||
}
|
||||
|
||||
void StringHasher::setPersistenceFileName(const char *filename) const {
|
||||
if (!filename)
|
||||
filename = "";
|
||||
_filename = filename;
|
||||
}
|
||||
|
||||
const std::string &StringHasher::getPersistenceFileName() const {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
void StringHasher::Save(Base::Writer &writer) const {
|
||||
|
||||
size_t count;
|
||||
if (_hashes->SaveAll)
|
||||
count = _hashes->size();
|
||||
else {
|
||||
count = 0;
|
||||
for (auto &v : _hashes->right) {
|
||||
if (v.second->isMarked() || v.second->isPersistent())
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<StringHasher saveall=\"" << _hashes->SaveAll
|
||||
<< "\" threshold=\"" << _hashes->Threshold << "\"";
|
||||
|
||||
if (!count) {
|
||||
writer.Stream() << " count=\"0\"></StringHasher>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
writer.Stream() << " count=\"0\" new=\"1\"/>\n";
|
||||
|
||||
writer.Stream() << writer.ind() << "<StringHasher2 ";
|
||||
if (_filename.size()) {
|
||||
writer.Stream() << " file=\""
|
||||
<< writer.addFile(_filename + ".txt", this)
|
||||
<< "\"/>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
writer.Stream() << " count=\"" << count << "\">\n";
|
||||
saveStream(writer.beginCharStream(false) << '\n');
|
||||
writer.endCharStream() << '\n';
|
||||
writer.Stream() << writer.ind() << "</StringHasher2>\n";
|
||||
}
|
||||
|
||||
void StringHasher::SaveDocFile(Base::Writer &writer) const {
|
||||
std::size_t count = _hashes->SaveAll?this->size():this->count();
|
||||
writer.Stream() << "StringTableStart v1 " << count << '\n';
|
||||
saveStream(writer.Stream());
|
||||
}
|
||||
|
||||
void StringHasher::saveStream(std::ostream &s) const {
|
||||
Base::OutputStream str(s,false);
|
||||
boost::io::ios_flags_saver ifs(s);
|
||||
s << std::hex;
|
||||
|
||||
bool allowRealtive = DocumentParams::getRelativeStringID();
|
||||
long anchor = 0;
|
||||
const StringID *last = nullptr;
|
||||
long lastid = 0;
|
||||
bool relative = false;
|
||||
|
||||
for (auto &v : _hashes->right) {
|
||||
auto &d = *v.second;
|
||||
long id = d._id;
|
||||
if (!_hashes->SaveAll && !d.isMarked() && !d.isPersistent())
|
||||
continue;
|
||||
|
||||
if (!allowRealtive)
|
||||
s << id;
|
||||
else {
|
||||
// We use relative coding to save space. But in order to have some
|
||||
// minimum protection against corruption, write an absolute value every
|
||||
// once a while.
|
||||
relative = (id - anchor) < 1000;
|
||||
if (relative)
|
||||
s << '-' << id - lastid;
|
||||
else {
|
||||
anchor = id;
|
||||
s << id;
|
||||
}
|
||||
lastid = id;
|
||||
}
|
||||
|
||||
int offset = d.isPostfixEncoded() ? 1 : 0;
|
||||
|
||||
StringID::IndexID prefixid;
|
||||
prefixid.id = 0;
|
||||
prefixid.index = 0;
|
||||
if (d.isPrefixID()) {
|
||||
assert(d._sids.size() > offset);
|
||||
prefixid.id = d._sids[offset].value();
|
||||
}
|
||||
else if (d.isPrefixIDIndex()) {
|
||||
prefixid = StringID::fromString(d._data);
|
||||
assert(d._sids.size() > offset && d._sids[offset].value() == prefixid.id);
|
||||
}
|
||||
|
||||
auto flags = d._flags;
|
||||
flags.setFlag(StringID::Flag::Marked, false);
|
||||
s << '.' << flags.toUnderlyingType();
|
||||
|
||||
int i = 0;
|
||||
if (!relative) {
|
||||
for (; i < d._sids.size(); ++i)
|
||||
s << '.' << d._sids[i].value();
|
||||
}
|
||||
else {
|
||||
if (last) {
|
||||
for (; i < d._sids.size() && i < last->_sids.size(); ++i) {
|
||||
long m = last->_sids[i].value();
|
||||
long n = d._sids[i].value();
|
||||
if (n < m)
|
||||
s << ".-" << m-n;
|
||||
else
|
||||
s << '.' << n - m;
|
||||
}
|
||||
}
|
||||
for (; i < d._sids.size(); ++i)
|
||||
s << '.' << id - d._sids[i].value();
|
||||
}
|
||||
|
||||
last = &d;
|
||||
|
||||
// Having postfix means it is a geometry element name, which
|
||||
// guarantees to be a single line without space. So it is safe to
|
||||
// store in raw stream.
|
||||
if (d.isPostfixed()) {
|
||||
if (d.isPrefixIDIndex())
|
||||
s << ' ' << prefixid.index;
|
||||
else if (!d.isIndexed() && !d.isPrefixID())
|
||||
s << ' ' << d._data.constData();
|
||||
|
||||
if (!d.isPostfixEncoded())
|
||||
s << ' ' << d._postfix.constData();
|
||||
s << '\n';
|
||||
}
|
||||
else {
|
||||
// Reaching here means the string may contain space and newlines
|
||||
// We rely on OutputStream (i.e. str) to save the string.
|
||||
s << ' ';
|
||||
str << d._data.constData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StringHasher::RestoreDocFile(Base::Reader &reader) {
|
||||
std::string marker, ver;
|
||||
reader >> marker;
|
||||
std::size_t count;
|
||||
_hashes->clear();
|
||||
if (marker == "StringTableStart") {
|
||||
reader >> ver >> count;
|
||||
if (ver != "v1")
|
||||
FC_WARN("Unknown string table format");
|
||||
restoreStreamNew(reader, count);
|
||||
return;
|
||||
}
|
||||
count = atoi(marker.c_str());
|
||||
restoreStream(reader, count);
|
||||
}
|
||||
|
||||
void StringHasher::restoreStreamNew(std::istream &s, std::size_t count) {
|
||||
Base::InputStream str(s, false);
|
||||
_hashes->clear();
|
||||
std::string content;
|
||||
boost::io::ios_flags_saver ifs(s);
|
||||
s >> std::hex;
|
||||
std::vector<std::string> tokens;
|
||||
long lastid = 0;
|
||||
const StringID *last = nullptr;
|
||||
|
||||
std::string tmp;
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (!(s >> tmp))
|
||||
FC_THROWM(Base::RuntimeError, "Invalid string table");
|
||||
|
||||
tokens.clear();
|
||||
boost::split(tokens, tmp, boost::is_any_of("."));
|
||||
if (tokens.size() < 2)
|
||||
FC_THROWM(Base::RuntimeError, "Invalid string table");
|
||||
|
||||
long id;
|
||||
bool relative = false;
|
||||
if (tokens[0][0] == '-') {
|
||||
relative = true;
|
||||
id = lastid + strtol(tokens[0].c_str() + 1, nullptr, 16);
|
||||
}
|
||||
else
|
||||
id = strtol(tokens[0].c_str(), nullptr, 16);
|
||||
|
||||
lastid = id;
|
||||
|
||||
unsigned long flag = strtol(tokens[1].c_str(), nullptr, 16);
|
||||
StringIDRef sid(new StringID(id, QByteArray(), static_cast<StringID::Flag>(flag)));
|
||||
|
||||
StringID &d = *sid._sid;
|
||||
d._sids.reserve(tokens.size() - 2);
|
||||
|
||||
int j = 2;
|
||||
if (relative && last) {
|
||||
for (; j < (int)tokens.size() && j - 2 < last->_sids.size(); ++j) {
|
||||
long m = last->_sids[j - 2].value();
|
||||
long n;
|
||||
if (tokens[j][0] == '-')
|
||||
n = -strtol(&tokens[j][1], nullptr, 16);
|
||||
else
|
||||
n = strtol(&tokens[j][0], nullptr, 16);
|
||||
StringIDRef sid = getID(m + n);
|
||||
if (!sid)
|
||||
FC_THROWM(Base::RuntimeError, "Invalid string id reference");
|
||||
d._sids.push_back(sid);
|
||||
}
|
||||
}
|
||||
for (; j < (int)tokens.size(); ++j) {
|
||||
long n = strtol(&tokens[j][0], nullptr, 16);
|
||||
StringIDRef sid = getID(relative ? id - n : n);
|
||||
if (!sid)
|
||||
FC_THROWM(Base::RuntimeError, "Invalid string id reference");
|
||||
d._sids.push_back(sid);
|
||||
}
|
||||
|
||||
if (!d.isPostfixed()) {
|
||||
str >> content;
|
||||
if (d.isHashed() || d.isBinary())
|
||||
d._data = QByteArray::fromBase64(content.c_str());
|
||||
else
|
||||
d._data = content.c_str();
|
||||
}
|
||||
else {
|
||||
int offset = 0;
|
||||
if (d.isPostfixEncoded()) {
|
||||
offset = 1;
|
||||
if (d._sids.empty())
|
||||
FC_THROWM(Base::RuntimeError, "Missing string postfix");
|
||||
d._postfix = d._sids[0]._sid->_data;
|
||||
}
|
||||
if (d.isIndexed()) {
|
||||
if (d._sids.size() <= offset)
|
||||
FC_THROWM(Base::RuntimeError, "Missing string prefix");
|
||||
d._data = d._sids[offset]._sid->_data;
|
||||
}
|
||||
else if (d.isPrefixID() || d.isPrefixIDIndex()) {
|
||||
if (d._sids.size() <= offset)
|
||||
FC_THROWM(Base::RuntimeError, "Missing string prefix id");
|
||||
int index = 0;
|
||||
if (d.isPrefixIDIndex()) {
|
||||
if (!(s >> index))
|
||||
FC_THROWM(Base::RuntimeError, "Missing string prefix index");
|
||||
}
|
||||
d._data = d._sids[offset]._sid->toString(index).c_str();
|
||||
}
|
||||
else {
|
||||
s >> content;
|
||||
d._data = content.c_str();
|
||||
}
|
||||
if (!d.isPostfixEncoded()) {
|
||||
s >> content;
|
||||
d._postfix = content.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
last = insert(sid);
|
||||
}
|
||||
}
|
||||
|
||||
StringID *StringHasher::insert(const StringIDRef &sid)
|
||||
{
|
||||
assert(sid && sid._sid->_hasher == nullptr);
|
||||
auto &d = *sid._sid;
|
||||
d._hasher = this;
|
||||
d.ref();
|
||||
auto res = _hashes->right.insert(_hashes->right.end(),
|
||||
HashMap::right_map::value_type(sid.value(), &d));
|
||||
if (res->second != &d) {
|
||||
d._hasher = nullptr;
|
||||
d.unref();
|
||||
}
|
||||
return res->second;
|
||||
}
|
||||
|
||||
void StringHasher::restoreStream(std::istream &s, std::size_t count) {
|
||||
Base::InputStream str(s, false);
|
||||
_hashes->clear();
|
||||
std::string content;
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
int32_t id;
|
||||
uint8_t type;
|
||||
str >> id >> type >> content;
|
||||
StringIDRef sid = new StringID(id, QByteArray(), static_cast<StringID::Flag>(type));
|
||||
if (sid.isHashed() || sid.isBinary())
|
||||
sid._sid->_data = QByteArray::fromBase64(content.c_str());
|
||||
else
|
||||
sid._sid->_data = QByteArray(content.c_str());
|
||||
insert(sid);
|
||||
}
|
||||
}
|
||||
|
||||
void StringHasher::clear() {
|
||||
for (auto & v : _hashes->right) {
|
||||
v.second->_hasher = nullptr;
|
||||
v.second->unref();
|
||||
}
|
||||
_hashes->clear();
|
||||
}
|
||||
|
||||
size_t StringHasher::size() const {
|
||||
return _hashes->size();
|
||||
}
|
||||
|
||||
size_t StringHasher::count() const {
|
||||
size_t count = 0;
|
||||
for (auto &v : _hashes->right)
|
||||
if (v.second->getRefCount() > 1)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
void StringHasher::Restore(Base::XMLReader &reader) {
|
||||
clear();
|
||||
reader.readElement("StringHasher");
|
||||
_hashes->SaveAll = reader.getAttributeAsInteger("saveall") ? true : false;
|
||||
_hashes->Threshold = reader.getAttributeAsInteger("threshold");
|
||||
|
||||
bool newtag = false;
|
||||
if (reader.getAttributeAsInteger("new", "0") > 0) {
|
||||
reader.readElement("StringHasher2");
|
||||
newtag = true;
|
||||
}
|
||||
|
||||
if (reader.hasAttribute("file")) {
|
||||
const char *file = reader.getAttribute("file");
|
||||
if(*file)
|
||||
reader.addFile(file, this);
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t count = reader.getAttributeAsUnsigned("count");
|
||||
if (newtag) {
|
||||
restoreStreamNew(reader.beginCharStream(false), count);
|
||||
reader.readEndElement("StringHasher2");
|
||||
return;
|
||||
}
|
||||
else if (count && reader.FileVersion > 1)
|
||||
restoreStream(reader.beginCharStream(false), count);
|
||||
else {
|
||||
for (std::size_t i = 0; i < count; ++i) {
|
||||
reader.readElement("Item");
|
||||
StringIDRef sid;
|
||||
long id = reader.getAttributeAsInteger("id");
|
||||
bool hashed = reader.hasAttribute("hash");
|
||||
if (hashed || reader.hasAttribute("data")) {
|
||||
const char *value = hashed ? reader.getAttribute("hash") : reader.getAttribute("data");
|
||||
sid = new StringID(id, QByteArray::fromBase64(value), StringID::Flag::Hashed);
|
||||
}
|
||||
else
|
||||
sid = new StringID(id, QByteArray(reader.getAttribute("text")));
|
||||
insert(sid);
|
||||
}
|
||||
}
|
||||
reader.readEndElement("StringHasher");
|
||||
}
|
||||
|
||||
unsigned int StringHasher::getMemSize (void) const {
|
||||
return (_hashes->SaveAll?size():count()) * 10;
|
||||
}
|
||||
|
||||
PyObject *StringHasher::getPyObject() {
|
||||
return new StringHasherPy(this);
|
||||
}
|
||||
|
||||
std::map<long, StringIDRef> StringHasher::getIDMap() const {
|
||||
std::map<long,StringIDRef> ret;
|
||||
for (auto &v : _hashes->right)
|
||||
ret.emplace_hint(ret.end(), v.first, StringIDRef(v.second));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void StringHasher::clearMarks() const
|
||||
{
|
||||
for (auto &v : _hashes->right)
|
||||
v.second->_flags.setFlag(StringID::Flag::Marked, false);
|
||||
}
|
||||
@@ -0,0 +1,680 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef APP_STRINGID_H
|
||||
#define APP_STRINGID_H
|
||||
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QVector>
|
||||
|
||||
#include <Base/Bitmask.h>
|
||||
#include <Base/Handle.h>
|
||||
#include <Base/Persistence.h>
|
||||
#include <CXX/Objects.hxx>
|
||||
|
||||
|
||||
namespace Data{
|
||||
class MappedName;
|
||||
}
|
||||
|
||||
namespace App {
|
||||
|
||||
class StringHasher;
|
||||
class StringID;
|
||||
class StringIDRef;
|
||||
typedef Base::Reference<StringHasher> StringHasherRef;
|
||||
|
||||
/** Class to store a string
|
||||
*
|
||||
* The main purpose of this class is to provide an efficient storage of the
|
||||
* mapped geometry element name (i.e. the new Topological Naming), but it can
|
||||
* also be used as a general purpose string table.
|
||||
*
|
||||
* The StringID is to be stored in a string table (StringHasher), and be
|
||||
* referred to by an integer ID. The stored data can be optionally divided into
|
||||
* two parts, prefix and postfix. This is because a new mapped name is often
|
||||
* created by adding some common postfix to an existing name, so data sharing
|
||||
* can be improved using the following techniques:
|
||||
*
|
||||
* a) reference count (through QByteArray) the main data part,
|
||||
*
|
||||
* b) (recursively) encode prefix and/or postfix as an integer (in the
|
||||
* format of #<hex>, e.g. #1b) that references another StringID,
|
||||
*
|
||||
* c) Check index based name in prefix, e.g. Edge1, Vertex2, and encode
|
||||
* only the text part as StringID. The index is stored separately in
|
||||
* reference class StringIDRef to maximize data sharing.
|
||||
*/
|
||||
class AppExport StringID: public Base::BaseClass, public Base::Handled {
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
public:
|
||||
/// Flag of the stored string data
|
||||
enum class Flag {
|
||||
/// No flag
|
||||
None = 0,
|
||||
/// The stored data is binary
|
||||
Binary = 1 << 0,
|
||||
/// The stored data is the sha1 hash of the original content
|
||||
Hashed = 1 << 1,
|
||||
/** Postfix is encoded as #<hex>, e.g. #1b, where the hex integer part
|
||||
* refers to another StringID.
|
||||
*/
|
||||
PostfixEncoded = 1 << 2,
|
||||
/// The data is splited as prefix and postfix
|
||||
Postfixed = 1 << 3,
|
||||
/// The prefix data is split as text + index
|
||||
Indexed = 1 << 4,
|
||||
/** The prefix data is encoded as #<hex>, e.g. #1b, where the hex
|
||||
* integer part refers to another StringID.
|
||||
*/
|
||||
PrefixID = 1 << 5,
|
||||
/** The prefix split as text + index, where the text is encoded
|
||||
* using another StringID.
|
||||
*/
|
||||
PrefixIDIndex = 1 << 6,
|
||||
/// The string ID is persistent regardless of internal mark */
|
||||
Persistent = 1 << 7,
|
||||
/// Internal marked used to check if the string ID is used
|
||||
Marked = 1 << 8,
|
||||
};
|
||||
typedef Base::Flags<Flag> Flags;
|
||||
|
||||
/** Constructor
|
||||
* @param id: integer ID of this StringID
|
||||
* @param data: input data
|
||||
* @param flags: flags describes the data
|
||||
*
|
||||
* User code is not supposed to create StringID directly, but through StringHasher::getID()
|
||||
*/
|
||||
StringID(long id, const QByteArray &data, const Flags &flags=Flag::None)
|
||||
:_id(id),_data(data),_flags(flags)
|
||||
{}
|
||||
|
||||
/// Constructs an empty StringID
|
||||
StringID()
|
||||
:_id(0), _flags(Flag::None)
|
||||
{}
|
||||
|
||||
virtual ~StringID();
|
||||
|
||||
/// Returns the ID of this StringID
|
||||
long value() const {return _id;}
|
||||
|
||||
/// Returns all related StringIDs that used to encode this StringID
|
||||
const QVector<StringIDRef> &relatedIDs() const {return _sids;}
|
||||
|
||||
/// @name Flag accessors
|
||||
//@{
|
||||
bool isBinary() const;
|
||||
bool isHashed() const;
|
||||
bool isPostfixed() const;
|
||||
bool isPostfixEncoded() const;
|
||||
bool isIndexed() const;
|
||||
bool isPrefixID() const;
|
||||
bool isPrefixIDIndex() const;
|
||||
bool isMarked() const;
|
||||
bool isPersistent() const;
|
||||
//@}
|
||||
|
||||
/// Checks if this StringID is from the input hasher
|
||||
bool isFromSameHasher(const StringHasherRef & hasher) const
|
||||
{
|
||||
return this->_hasher == hasher;
|
||||
}
|
||||
|
||||
/// Returns the owner hasher
|
||||
StringHasherRef getHasher() const
|
||||
{
|
||||
return StringHasherRef(_hasher);
|
||||
}
|
||||
|
||||
/// Returns the data (prefix)
|
||||
const QByteArray data() const {return _data;}
|
||||
/// Returns the postfix
|
||||
const QByteArray postfix() const {return _postfix;}
|
||||
|
||||
virtual PyObject *getPyObject() override;
|
||||
/// Returns a Python tuple containing both the text and index
|
||||
PyObject *getPyObjectWithIndex(int index);
|
||||
|
||||
/** Convert to string represtation of this StringID
|
||||
* @param index: optional index
|
||||
*
|
||||
* The format is #<id>. And if index is non zero, then #<id>:<index>. Both
|
||||
* <id> and <index> are in hex format.
|
||||
*/
|
||||
std::string toString(int index) const;
|
||||
|
||||
/// Light weight structure of holding a string ID and associated index
|
||||
struct IndexID {
|
||||
long id;
|
||||
int index;
|
||||
|
||||
explicit operator bool() const {
|
||||
return id > 0;
|
||||
}
|
||||
|
||||
friend std::ostream & operator << (std::ostream &s, const IndexID & id) {
|
||||
s << id.id;
|
||||
if (id.index)
|
||||
s << ':' << id.index;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
/** Parse string to get ID and index
|
||||
* @param name: input string
|
||||
* @param eof: Whether to check the end of string. If true, then the input
|
||||
* string must contain only the string representation of this
|
||||
* StringID
|
||||
* @param size: input string size, or -1 if the input string is zero terminated.
|
||||
* @return Return the integer ID and index.
|
||||
*
|
||||
* The input string is expected to be in the format of #<id> or with index
|
||||
* #<id>:<index>, where both id and index are in hex digits.
|
||||
*/
|
||||
static IndexID fromString(const char *name, bool eof=true, int size = -1);
|
||||
|
||||
/** Parse string to get ID and index
|
||||
* @param bytes: input data
|
||||
* @param eof: Whether to check the end of string. If true, then the input
|
||||
* string must contain only the string representation of this
|
||||
* StringID
|
||||
*
|
||||
* The input string is expected to be in the format of #<id> or with index
|
||||
* #<id>:<index>, where both id and index are in hex digits.
|
||||
*/
|
||||
static IndexID fromString(const QByteArray &bytes, bool eof=true) {
|
||||
return fromString(bytes.constData(), eof, bytes.size());
|
||||
}
|
||||
|
||||
/** Get the text content of this StringID
|
||||
* @param index: optional index
|
||||
* @return Return the text content of this StringID. If the data is binary,
|
||||
* then output in base64 encoded string.
|
||||
*/
|
||||
std::string dataToText(int index) const;
|
||||
|
||||
/** Get the content of this StringID as QByteArray
|
||||
* @param bytes: output bytes
|
||||
* @param index: opttional index.
|
||||
*/
|
||||
void toBytes(QByteArray &bytes, int index) const {
|
||||
if (_postfix.size())
|
||||
bytes = _data + _postfix;
|
||||
else if (index)
|
||||
bytes = _data + QByteArray::number(index);
|
||||
else
|
||||
bytes = _data;
|
||||
}
|
||||
|
||||
/// Mark this StringID as used
|
||||
void mark() const;
|
||||
|
||||
/// Mark the StringID as persistent regardless of usage mark
|
||||
void setPersistent(bool enable);
|
||||
|
||||
bool operator<(const StringID &other) const {
|
||||
return compare(other) < 0;
|
||||
}
|
||||
|
||||
/** Compare StringID
|
||||
* @param other: the other StringID for comparison
|
||||
* @return Returns -1 if less than the other StringID, 1 if greater, or 0 if equal
|
||||
*/
|
||||
int compare(const StringID &other) const {
|
||||
if (_hasher < other._hasher)
|
||||
return -1;
|
||||
if (_hasher > other._hasher)
|
||||
return 1;
|
||||
if (_id < other._id)
|
||||
return -1;
|
||||
if (_id > other._id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
friend class StringHasher;
|
||||
|
||||
private:
|
||||
long _id;
|
||||
QByteArray _data;
|
||||
QByteArray _postfix;
|
||||
StringHasher *_hasher = nullptr;
|
||||
mutable Flags _flags;
|
||||
mutable QVector<StringIDRef> _sids;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Counted reference to a StringID instance
|
||||
*/
|
||||
class StringIDRef
|
||||
{
|
||||
public:
|
||||
StringIDRef()
|
||||
:_sid(nullptr), _index(0)
|
||||
{}
|
||||
|
||||
StringIDRef(StringID* p, int index=0)
|
||||
: _sid(p), _index(index)
|
||||
{
|
||||
if (_sid)
|
||||
_sid->ref();
|
||||
}
|
||||
|
||||
StringIDRef(const StringIDRef & other)
|
||||
: _sid(other._sid)
|
||||
, _index(other._index)
|
||||
{
|
||||
if (_sid)
|
||||
_sid->ref();
|
||||
}
|
||||
|
||||
StringIDRef(StringIDRef && other)
|
||||
: _sid(other._sid)
|
||||
, _index(other._index)
|
||||
{
|
||||
other._sid = nullptr;
|
||||
}
|
||||
|
||||
StringIDRef(const StringIDRef & other, int index)
|
||||
: _sid(other._sid)
|
||||
, _index(index)
|
||||
{
|
||||
if (_sid)
|
||||
_sid->ref();
|
||||
}
|
||||
|
||||
~StringIDRef()
|
||||
{
|
||||
if (_sid)
|
||||
_sid->unref();
|
||||
}
|
||||
|
||||
void reset(const StringIDRef & p = StringIDRef()) {
|
||||
*this = p;
|
||||
}
|
||||
|
||||
void reset(const StringIDRef &p, int index) {
|
||||
*this = p;
|
||||
this->_index = index;
|
||||
}
|
||||
|
||||
void swap(StringIDRef &p) {
|
||||
if(*this != p) {
|
||||
auto tmp = p;
|
||||
p = *this;
|
||||
*this = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
StringIDRef & operator=(StringID* p) {
|
||||
if (_sid == p)
|
||||
return *this;
|
||||
if (_sid)
|
||||
_sid->unref();
|
||||
_sid = p;
|
||||
if (_sid)
|
||||
_sid->ref();
|
||||
this->_index = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringIDRef & operator=(const StringIDRef & p) {
|
||||
if (_sid != p._sid) {
|
||||
if (_sid)
|
||||
_sid->unref();
|
||||
_sid = p._sid;
|
||||
if (_sid)
|
||||
_sid->ref();
|
||||
}
|
||||
this->_index = p._index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringIDRef & operator=(StringIDRef && p) {
|
||||
if (_sid != p._sid) {
|
||||
if (_sid)
|
||||
_sid->unref();
|
||||
_sid = p._sid;
|
||||
p._sid = nullptr;
|
||||
}
|
||||
this->_index = p._index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const StringIDRef & p) const {
|
||||
if (!_sid)
|
||||
return true;
|
||||
if (!p._sid)
|
||||
return false;
|
||||
int res = _sid->compare(*p._sid);
|
||||
if (res < 0)
|
||||
return true;
|
||||
if (res > 0)
|
||||
return false;
|
||||
return _index < p._index;
|
||||
}
|
||||
|
||||
bool operator==(const StringIDRef & p) const {
|
||||
return _sid == p._sid && _index == p._index;
|
||||
}
|
||||
|
||||
bool operator!=(const StringIDRef & p) const {
|
||||
return _sid != p._sid || _index != p._index;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return _sid != nullptr;
|
||||
}
|
||||
|
||||
int getRefCount(void) const {
|
||||
if (_sid)
|
||||
return _sid->getRefCount();
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
if (_sid)
|
||||
return _sid->toString(_index);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string dataToText() const {
|
||||
if (_sid)
|
||||
return _sid->dataToText(_index);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
const char * constData() const {
|
||||
if (_sid) {
|
||||
assert(_index == 0);
|
||||
assert(_sid->postfix().isEmpty());
|
||||
return _sid->data().constData();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const StringID & deref() const {
|
||||
return *_sid;
|
||||
}
|
||||
|
||||
long value() const {
|
||||
if (_sid)
|
||||
return _sid->value();
|
||||
return 0;
|
||||
}
|
||||
|
||||
QVector<StringIDRef> relatedIDs() const {
|
||||
if (_sid)
|
||||
return _sid->relatedIDs();
|
||||
return QVector<StringIDRef>();
|
||||
}
|
||||
|
||||
bool isBinary() const {
|
||||
if (_sid)
|
||||
return _sid->isBinary();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isHashed() const {
|
||||
if (_sid)
|
||||
return _sid->isHashed();
|
||||
return false;
|
||||
}
|
||||
|
||||
void toBytes(QByteArray &bytes) const {
|
||||
if (_sid)
|
||||
_sid->toBytes(bytes, _index);
|
||||
}
|
||||
|
||||
PyObject *getPyObject(void) {
|
||||
if (_sid)
|
||||
return _sid->getPyObjectWithIndex(_index);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
void mark() const {
|
||||
if (_sid)
|
||||
_sid->mark();
|
||||
}
|
||||
|
||||
bool isMarked() const {
|
||||
return _sid && _sid->isMarked();
|
||||
}
|
||||
|
||||
bool isFromSameHasher(const StringHasherRef & hasher) const
|
||||
{
|
||||
return _sid && _sid->isFromSameHasher(hasher);
|
||||
}
|
||||
|
||||
StringHasherRef getHasher() const
|
||||
{
|
||||
if (_sid)
|
||||
return _sid->getHasher();
|
||||
return StringHasherRef();
|
||||
}
|
||||
|
||||
void setPersistent(bool enable)
|
||||
{
|
||||
if (_sid)
|
||||
_sid->setPersistent(enable);
|
||||
}
|
||||
|
||||
friend class StringHasher;
|
||||
|
||||
private:
|
||||
StringID *_sid;
|
||||
int _index;
|
||||
};
|
||||
|
||||
/// A String table to map string from/to a unique integer
|
||||
class AppExport StringHasher: public Base::Persistence, public Base::Handled {
|
||||
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
StringHasher();
|
||||
virtual ~StringHasher();
|
||||
|
||||
virtual unsigned int getMemSize (void) const override;
|
||||
virtual void Save (Base::Writer &/*writer*/) const override;
|
||||
virtual void Restore(Base::XMLReader &/*reader*/) override;
|
||||
virtual void SaveDocFile (Base::Writer &/*writer*/) const override;
|
||||
virtual void RestoreDocFile (Base::Reader &/*reader*/) override;
|
||||
void setPersistenceFileName(const char *name) const;
|
||||
const std::string &getPersistenceFileName() const;
|
||||
|
||||
/** Maps an arbitrary string to an integer
|
||||
*
|
||||
* @param text: input string.
|
||||
* @param len: length of the string, or -1 if the string is 0 terminated.
|
||||
* @param hashable: whether the string is hashable.
|
||||
* @return Return a shared pointer to the internally stored StringID.
|
||||
*
|
||||
* The function maps an arbitrary text string to a unique integer ID, which
|
||||
* is returned as a shared pointer to reference count the ID so that it is
|
||||
* possible to prune any unused strings.
|
||||
*
|
||||
* If \c hashable is true and the string is longer than the threshold
|
||||
* setting of this StringHasher, it will be sha1 hashed before storing, and
|
||||
* the original content of the string is discarded. If else, the string is
|
||||
* copied and stored inside a StringID instance.
|
||||
*
|
||||
* The purpose of function is to provide a short form of a stable string
|
||||
* identification.
|
||||
*/
|
||||
StringIDRef getID(const char *text, int len=-1, bool hashable=false);
|
||||
|
||||
/// Option for string string data
|
||||
enum class Option {
|
||||
/// No option
|
||||
None = 0,
|
||||
/// The input data is binary
|
||||
Binary = 1 << 0,
|
||||
/** The input data is hashable. If the data length is longer than the
|
||||
* threshold setting of the StringHasher, it will be sha1 hashed before
|
||||
* storing, and the original content of the string is discarded.
|
||||
*/
|
||||
Hashable = 1 << 1,
|
||||
/// Do not copy the data, assuming the data is constant. If this option
|
||||
//is not set, the data will be copied before storing.
|
||||
NoCopy = 1 << 2,
|
||||
};
|
||||
typedef Base::Flags<Option> Options;
|
||||
|
||||
/** Map text or binary data to an integer
|
||||
*
|
||||
* @param data: input data.
|
||||
* @param options: options describing how to store the data. @sa Option.
|
||||
* @return Return a shared pointer to the internally stored StringID.
|
||||
*
|
||||
* The function maps an arbitrary text string to a unique integer ID, which
|
||||
* is returned as a shared pointer to reference count the ID so that it is
|
||||
* possible to prune any unused strings.
|
||||
*
|
||||
* The purpose of function is to provide a short form of a stable string
|
||||
* identification.
|
||||
*/
|
||||
StringIDRef getID(const QByteArray & data, Options options=Option::Hashable);
|
||||
|
||||
/** Map geometry element name to an integer */
|
||||
StringIDRef getID(const Data::MappedName & name,
|
||||
const QVector<StringIDRef> & sids);
|
||||
|
||||
/** Obtain the reference counted StringID object from numerical id
|
||||
*
|
||||
* @param id: string ID
|
||||
* @param index: optional index of the string ID
|
||||
* @return Return a shared pointer to the internally stored StringID.
|
||||
*
|
||||
* This function exists because the stored string may be one way hashed,
|
||||
* and the original text is not persistent. The caller use this function to
|
||||
* retrieve the reference count ID object after restore
|
||||
*/
|
||||
StringIDRef getID(long id, int index = 0) const;
|
||||
|
||||
/** Obtain the reference counted StringID object from numerical id and index
|
||||
*
|
||||
* @param id: string ID with index
|
||||
* @return Return a shared pointer to the internally stored StringID.
|
||||
*/
|
||||
StringIDRef getID(const StringID::IndexID &id) const {
|
||||
return getID(id.id, id.index);
|
||||
}
|
||||
|
||||
std::map<long,StringIDRef> getIDMap() const;
|
||||
|
||||
/// Clear all string hashes
|
||||
void clear();
|
||||
|
||||
/// Size of the hash table
|
||||
size_t size() const;
|
||||
|
||||
/// Return the number of hashes that are used by others
|
||||
size_t count() const;
|
||||
|
||||
virtual PyObject *getPyObject(void) override;
|
||||
|
||||
/** Enable/disable saving all string ID
|
||||
*
|
||||
* If disabled, then only save string ID that are used.
|
||||
*/
|
||||
void setSaveAll(bool enable);
|
||||
bool getSaveAll() const;
|
||||
|
||||
/** Set threshold of string hashing
|
||||
*
|
||||
* For hashable string that are longer than the threshold, the string will
|
||||
* be replaced by its sha1 hash.
|
||||
*/
|
||||
void setThreshold(int threshold);
|
||||
int getThreshold() const;
|
||||
|
||||
/** Clear internal marks
|
||||
*
|
||||
* The internal marks on internally stored StringID instances are used to
|
||||
* check if the StringID is used.
|
||||
*/
|
||||
void clearMarks() const;
|
||||
|
||||
/// Compact string storage
|
||||
void compact();
|
||||
|
||||
class HashMap;
|
||||
friend class StringID;
|
||||
|
||||
protected:
|
||||
StringID * insert(const StringIDRef & sid);
|
||||
long lastID() const;
|
||||
void saveStream(std::ostream &s) const;
|
||||
void restoreStream(std::istream &s, std::size_t count);
|
||||
void restoreStreamNew(std::istream &s, std::size_t count);
|
||||
|
||||
private:
|
||||
std::unique_ptr<HashMap> _hashes;
|
||||
mutable std::string _filename;
|
||||
};
|
||||
} //namespace App
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(App::StringID::Flag)
|
||||
ENABLE_BITMASK_OPERATORS(App::StringHasher::Option)
|
||||
|
||||
namespace App {
|
||||
inline bool StringID::isBinary() const {
|
||||
return _flags.testFlag(Flag::Binary);
|
||||
}
|
||||
inline bool StringID::isHashed() const {
|
||||
return _flags.testFlag(Flag::Hashed);
|
||||
}
|
||||
inline bool StringID::isPostfixed() const {
|
||||
return _flags.testFlag(Flag::Postfixed);
|
||||
}
|
||||
inline bool StringID::isPostfixEncoded() const {
|
||||
return _flags.testFlag(Flag::PostfixEncoded);
|
||||
}
|
||||
inline bool StringID::isIndexed() const {
|
||||
return _flags.testFlag(Flag::Indexed);
|
||||
}
|
||||
inline bool StringID::isPrefixID() const {
|
||||
return _flags.testFlag(Flag::PrefixID);
|
||||
}
|
||||
inline bool StringID::isPrefixIDIndex() const {
|
||||
return _flags.testFlag(Flag::PrefixIDIndex);
|
||||
}
|
||||
inline bool StringID::isMarked() const {
|
||||
return _flags.testFlag(Flag::Marked);
|
||||
}
|
||||
inline bool StringID::isPersistent() const {
|
||||
return _flags.testFlag(Flag::Persistent);
|
||||
}
|
||||
inline void StringID::setPersistent(bool enable) {
|
||||
_flags.setFlag(Flag::Persistent, enable);
|
||||
}
|
||||
} //namespace App
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="StringHasherPy"
|
||||
Twin="StringHasher"
|
||||
TwinPointer="StringHasher"
|
||||
Include="App/StringHasher.h"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
Namespace="App"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Reference="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<DeveloperDocu>This is the StringHasher class</DeveloperDocu>
|
||||
<UserDocu>This is the StringHasher class</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getID">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
getID(txt|id, base64=False) -> StringID
|
||||
|
||||
If the input is text, return a StringID object that is unique within this hasher. This
|
||||
StringID object is reference counted. The hasher may only save hash ID's that are used.
|
||||
|
||||
If the input is an integer, then the hasher will try to find the StringID object stored
|
||||
with the same integer value.
|
||||
|
||||
base64: indicate if the input 'txt' is base64 encoded binary data
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isSame" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if two hasher are the same</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Count" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return count of used hashes</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Count" Type="Int" />
|
||||
</Attribute>
|
||||
<Attribute Name="Size" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the size of the hashes</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Size" Type="Int"/>
|
||||
</Attribute>
|
||||
<Attribute Name="SaveAll">
|
||||
<Documentation>
|
||||
<UserDocu>Whether to save all string hashes regardless of its use count</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="SaveAll" Type="Boolean"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Threshold">
|
||||
<Documentation>
|
||||
<UserDocu>Data length exceed this threshold will be hashed before storing</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Threshold" Type="Int"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Table" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the entire string table as Int->String dictionary</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Table" Type="Dict"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
@@ -0,0 +1,150 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2018 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "StringHasher.h"
|
||||
|
||||
#include "StringHasherPy.h"
|
||||
#include "StringHasherPy.cpp"
|
||||
|
||||
using namespace App;
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string StringHasherPy::representation(void) const
|
||||
{
|
||||
std::ostringstream str;
|
||||
str << "<StringHasher at " << getStringHasherPtr() << ">";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject *StringHasherPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
|
||||
{
|
||||
return new StringHasherPy(new StringHasher);
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int StringHasherPy::PyInit(PyObject* , PyObject* )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyObject* StringHasherPy::isSame(PyObject *args)
|
||||
{
|
||||
PyObject *other;
|
||||
if (!PyArg_ParseTuple(args, "O!", &StringHasherPy::Type, &other)){ // convert args: Python->C
|
||||
return Py::new_reference_to(Py::False());
|
||||
}
|
||||
auto otherHasher = static_cast<StringHasherPy*>(other)->getStringHasherPtr();
|
||||
return Py::new_reference_to(Py::Boolean(getStringHasherPtr() == otherHasher));
|
||||
}
|
||||
|
||||
PyObject* StringHasherPy::getID(PyObject *args)
|
||||
{
|
||||
long id = -1;
|
||||
int index = 0;
|
||||
PyObject *value = 0;
|
||||
PyObject *base64 = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "l|i",&id,&index)) {
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTuple(args, "O|O",&value,&base64))
|
||||
return NULL; // NULL triggers exception
|
||||
}
|
||||
if(id>0) {
|
||||
PY_TRY {
|
||||
auto sid = getStringHasherPtr()->getID(id, index);
|
||||
if(!sid) Py_Return;
|
||||
return sid.getPyObject();
|
||||
}PY_CATCH;
|
||||
}
|
||||
std::string txt;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
if (PyUnicode_Check(value)) {
|
||||
txt = PyUnicode_AsUTF8(value);
|
||||
}
|
||||
#else
|
||||
if (PyUnicode_Check(value)) {
|
||||
PyObject* unicode = PyUnicode_AsLatin1String(value);
|
||||
txt = PyString_AsString(unicode);
|
||||
Py_DECREF(unicode);
|
||||
}
|
||||
else if (PyString_Check(value)) {
|
||||
txt = PyString_AsString(value);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
throw Py::TypeError("expect argument of type string");
|
||||
PY_TRY {
|
||||
QByteArray data;
|
||||
StringIDRef sid;
|
||||
if(PyObject_IsTrue(base64)) {
|
||||
data = QByteArray::fromBase64(QByteArray::fromRawData(txt.c_str(),txt.size()));
|
||||
sid = getStringHasherPtr()->getID(data,true);
|
||||
}else
|
||||
sid = getStringHasherPtr()->getID(txt.c_str(),txt.size());
|
||||
return sid.getPyObject();
|
||||
}PY_CATCH;
|
||||
}
|
||||
|
||||
Py::Int StringHasherPy::getCount(void) const {
|
||||
return Py::Int((long)getStringHasherPtr()->count());
|
||||
}
|
||||
|
||||
Py::Int StringHasherPy::getSize(void) const {
|
||||
return Py::Int((long)getStringHasherPtr()->size());
|
||||
}
|
||||
|
||||
Py::Boolean StringHasherPy::getSaveAll(void) const {
|
||||
return Py::Boolean(getStringHasherPtr()->getSaveAll());
|
||||
}
|
||||
|
||||
void StringHasherPy::setSaveAll(Py::Boolean value) {
|
||||
getStringHasherPtr()->setSaveAll(value);
|
||||
}
|
||||
|
||||
Py::Int StringHasherPy::getThreshold(void) const {
|
||||
return Py::Int((long)getStringHasherPtr()->getThreshold());
|
||||
}
|
||||
|
||||
void StringHasherPy::setThreshold(Py::Int value) {
|
||||
getStringHasherPtr()->setThreshold(value);
|
||||
}
|
||||
|
||||
Py::Dict StringHasherPy::getTable() const {
|
||||
Py::Dict dict;
|
||||
for(auto &v : getStringHasherPtr()->getIDMap())
|
||||
dict.setItem(Py::Int(v.first),Py::String(v.second.dataToText()));
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject *StringHasherPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StringHasherPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="StringIDPy"
|
||||
Twin="StringID"
|
||||
TwinPointer="StringID"
|
||||
Include="App/StringHasher.h"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
Namespace="App"
|
||||
FatherNamespace="Base"
|
||||
Reference="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Zheng, Lei" EMail="realthunder.dev@gmail.com" />
|
||||
<DeveloperDocu>This is the StringID class</DeveloperDocu>
|
||||
<UserDocu>This is the StringID class</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="isSame" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if two StringIDs are the same</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Value" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the integer value of this ID</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Value" Type="Int"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Related" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the related string IDs</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Related" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Data" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Return the data associated with this ID</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Data" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="IsBinary" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the data is binary, </UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="IsBinary" Type="Boolean"/>
|
||||
</Attribute>
|
||||
<Attribute Name="IsHashed" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the data is hash, if so 'Data' returns a base64 encoded string of the raw hash</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="IsHashed" Type="Boolean"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Index" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Geometry index. Only meaningful for geometry element name</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Index" Type="Int"/>
|
||||
</Attribute>
|
||||
<ClassDeclarations>private:
|
||||
friend class StringID;
|
||||
int _index = 0;
|
||||
</ClassDeclarations>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
* Copyright (c) 2018 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is 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 Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "StringHasher.h"
|
||||
|
||||
#include "StringIDPy.h"
|
||||
#include "StringIDPy.cpp"
|
||||
|
||||
using namespace App;
|
||||
|
||||
// returns a string which represent the object e.g. when printed in python
|
||||
std::string StringIDPy::representation(void) const
|
||||
{
|
||||
return getStringIDPtr()->toString(_index);
|
||||
}
|
||||
|
||||
PyObject* StringIDPy::isSame(PyObject *args)
|
||||
{
|
||||
PyObject *other;
|
||||
if (!PyArg_ParseTuple(args, "O!", &StringIDPy::Type, &other)) { // convert args: Python->C
|
||||
return Py::new_reference_to(Py::False());
|
||||
}
|
||||
auto otherPy = static_cast<StringIDPy*>(other);
|
||||
return Py::new_reference_to(Py::Boolean(
|
||||
otherPy->getStringIDPtr() == this->getStringIDPtr()
|
||||
&& otherPy->_index == this->_index));
|
||||
}
|
||||
|
||||
Py::Int StringIDPy::getValue(void) const {
|
||||
return Py::Int(getStringIDPtr()->value());
|
||||
}
|
||||
|
||||
Py::List StringIDPy::getRelated(void) const {
|
||||
Py::List list;
|
||||
for (auto &id : getStringIDPtr()->relatedIDs())
|
||||
list.append(Py::Long(id.value()));
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::String StringIDPy::getData(void) const {
|
||||
return Py::String(getStringIDPtr()->dataToText(this->_index));
|
||||
}
|
||||
|
||||
Py::Boolean StringIDPy::getIsBinary(void) const {
|
||||
return Py::Boolean(getStringIDPtr()->isBinary());
|
||||
}
|
||||
|
||||
Py::Boolean StringIDPy::getIsHashed(void) const {
|
||||
return Py::Boolean(getStringIDPtr()->isHashed());
|
||||
}
|
||||
|
||||
Py::Int StringIDPy::getIndex(void) const {
|
||||
return Py::Int(this->_index);
|
||||
}
|
||||
|
||||
void StringIDPy::setIndex(Py::Int index) {
|
||||
this->_index = index;
|
||||
}
|
||||
|
||||
PyObject *StringIDPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StringIDPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ int AxisPy::PyInit(PyObject* args, PyObject* /*kwd*/)
|
||||
|
||||
PyErr_Clear();
|
||||
PyObject* d;
|
||||
if (PyArg_ParseTuple(args, "O!O", &(Base::VectorPy::Type), &o,
|
||||
if (PyArg_ParseTuple(args, "O!O!", &(Base::VectorPy::Type), &o,
|
||||
&(Base::VectorPy::Type), &d)) {
|
||||
// NOTE: The first parameter defines the base (origin) and the second the direction.
|
||||
*getAxisPtr() = Base::Axis(static_cast<Base::VectorPy*>(o)->value(),
|
||||
|
||||
+52
-25
@@ -22,11 +22,17 @@
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
*/
|
||||
|
||||
|
||||
Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com)
|
||||
|
||||
* Added support of in-line transformation using boost iostream for memory
|
||||
efficiency
|
||||
*/
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
#endif
|
||||
|
||||
@@ -39,12 +45,31 @@ static const std::string base64_chars =
|
||||
"0123456789+/";
|
||||
|
||||
|
||||
static inline bool is_base64(unsigned char c) {
|
||||
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||
const signed char *Base::base64_decode_table() {
|
||||
static const signed char _table[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -1, -2, -1, -1, // 0-15
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
|
||||
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, // 48-63
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
|
||||
};
|
||||
return _table;
|
||||
}
|
||||
|
||||
std::string Base::base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
|
||||
std::string ret;
|
||||
std::size_t Base::base64_encode(char *out, void const* in, std::size_t in_len) {
|
||||
char *ret = out;
|
||||
unsigned char const *bytes_to_encode = reinterpret_cast<unsigned char const*>(in);
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
unsigned char char_array_3[3];
|
||||
@@ -59,7 +84,7 @@ std::string Base::base64_encode(unsigned char const* bytes_to_encode, unsigned i
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for(i = 0; (i <4) ; i++)
|
||||
ret += base64_chars[char_array_4[i]];
|
||||
*ret++ = base64_chars[char_array_4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
@@ -75,37 +100,41 @@ std::string Base::base64_encode(unsigned char const* bytes_to_encode, unsigned i
|
||||
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||
|
||||
for (j = 0; (j < i + 1); j++)
|
||||
ret += base64_chars[char_array_4[j]];
|
||||
*ret++ = base64_chars[char_array_4[j]];
|
||||
|
||||
while((i++ < 3))
|
||||
ret += '=';
|
||||
*ret++ = '=';
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
return ret-out;
|
||||
}
|
||||
|
||||
std::string Base::base64_decode(std::string const& encoded_string) {
|
||||
int in_len = encoded_string.size();
|
||||
std::pair<std::size_t, std::size_t> Base::base64_decode(
|
||||
void *_out, char const *in, std::size_t in_len)
|
||||
{
|
||||
unsigned char *out = reinterpret_cast<unsigned char*>(_out);
|
||||
unsigned char *ret = out;
|
||||
char const *input = in;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
unsigned char char_array_4[4], char_array_3[3];
|
||||
std::string ret;
|
||||
|
||||
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||
static const signed char *table = base64_decode_table();
|
||||
|
||||
while (in_len-- && *in != '=') {
|
||||
const signed char v = table[(int)(*in++)];
|
||||
if(v < 0)
|
||||
break;
|
||||
|
||||
char_array_4[i++] = (unsigned char)v;
|
||||
if (i ==4) {
|
||||
for (i = 0; i <4; i++)
|
||||
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (i = 0; (i < 3); i++)
|
||||
ret += char_array_3[i];
|
||||
*ret++ = char_array_3[i];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
@@ -114,15 +143,13 @@ std::string Base::base64_decode(std::string const& encoded_string) {
|
||||
for (j = i; j <4; j++)
|
||||
char_array_4[j] = 0;
|
||||
|
||||
for (j = 0; j <4; j++)
|
||||
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
|
||||
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||
for (j = 0; (j < i - 1); j++) *ret++ = char_array_3[j];
|
||||
}
|
||||
|
||||
return ret;
|
||||
return std::make_pair((std::size_t)(ret-out), (std::size_t)(in-input));
|
||||
}
|
||||
|
||||
|
||||
+366
-5
@@ -23,20 +23,381 @@
|
||||
|
||||
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
Copyright (C) 2019 Zheng Lei (realthunder.dev@gmail.com)
|
||||
|
||||
* Added support of in-line transformation using boost iostream for memory
|
||||
efficiency
|
||||
*/
|
||||
#ifndef BASE_BASE64_H
|
||||
#define BASE_BASE64_H
|
||||
|
||||
#include <FCGlobal.h>
|
||||
#include <string>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/iostreams/concepts.hpp>
|
||||
#include <boost/iostreams/operations.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/device/file.hpp>
|
||||
|
||||
namespace Base
|
||||
{
|
||||
|
||||
std::string BaseExport base64_encode(unsigned char const* , unsigned int len);
|
||||
std::string BaseExport base64_decode(std::string const& s);
|
||||
/// Returns the max bytes of a encoded base64 string
|
||||
inline std::size_t base64_encode_size(std::size_t len) {
|
||||
return 4 * ((len + 2) / 3);
|
||||
}
|
||||
|
||||
}
|
||||
/// Returns the max bytes of a decoded base64 binary string
|
||||
inline std::size_t base64_decode_size(std::size_t len) {
|
||||
return len / 4 * 3;
|
||||
}
|
||||
|
||||
/** Encode input binary with base64
|
||||
* @param out: output buffer with minimum size of base64_encode(len)
|
||||
* appending new data.
|
||||
* @param in: input binary data
|
||||
* @param len: input length
|
||||
* @return The character count written to output.
|
||||
*/
|
||||
BaseExport std::size_t base64_encode(char *out, void const *in , std::size_t len);
|
||||
|
||||
/** Return the internal base64 decoding table
|
||||
*
|
||||
* The table maps from any 8-bit character to the decoded binary bits.
|
||||
* Valid base64 characters are mapped to the corresponding 6-bit binary
|
||||
* data. White space (space, tab, vtab, CR and LF) characters are mapped
|
||||
* to -2. Other invalid characters are mapped to -1.
|
||||
*/
|
||||
BaseExport const signed char *base64_decode_table();
|
||||
|
||||
/** Decode the input base64 string into binary data
|
||||
* @param out: output buffer with minimum size of base64_encode(len)
|
||||
* appending new data.
|
||||
* @param in: input binary data
|
||||
* @param len: input length
|
||||
* @return Return a pair of output size and input read size. Compare the
|
||||
* read size to input size to check for error.
|
||||
*/
|
||||
BaseExport std::pair<std::size_t, std::size_t> base64_decode(
|
||||
void *out, char const *, std::size_t len);
|
||||
|
||||
/** Encode input binary into base64 string
|
||||
* @param out: output string. Note that the string is not cleared before
|
||||
* adding new content.
|
||||
* @param in: input binary data
|
||||
* @param len: input length
|
||||
*/
|
||||
inline void base64_encode(std::string &out, void const* in , std::size_t len) {
|
||||
std::size_t size = out.size();
|
||||
out.resize(size + base64_encode_size(len));
|
||||
len = base64_encode(&out[size],in,len);
|
||||
out.resize(size+len);
|
||||
}
|
||||
|
||||
/** Encode input binary into base64 string
|
||||
* @param in: input binary data
|
||||
* @param len: input length
|
||||
* @return Return the base64 string.
|
||||
*/
|
||||
inline std::string base64_encode(void const* in , std::size_t len) {
|
||||
std::string out;
|
||||
base64_encode(out,in,len);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Decode base64 string into binary data
|
||||
* @param out: output binary data. Note that the data is not cleared before
|
||||
* adding new content.
|
||||
* @param in: input base64 string
|
||||
* @param len: input length
|
||||
* @return Return the processed input length. Compare this with the
|
||||
* argument \c len to check for error.
|
||||
*/
|
||||
template<typename T>
|
||||
inline std::size_t base64_decode(T &out, char const *in, std::size_t len) {
|
||||
std::size_t size = out.size();
|
||||
out.resize(size + base64_decode_size(len));
|
||||
std::pair<std::size_t,std::size_t> res = base64_decode(&out[size],in,len);
|
||||
out.resize(size + res.first);
|
||||
return res.second;
|
||||
}
|
||||
|
||||
/** Decode base64 string into binary data
|
||||
* @param out: output binary data. Note that the data is not cleared before
|
||||
* adding new content.
|
||||
* @param s: input base64 string
|
||||
* @return Return the processed input length. Compare this with the
|
||||
* argument \c len to check for error.
|
||||
*/
|
||||
template<typename T>
|
||||
inline std::size_t base64_decode(T &out, std::string const &s) {
|
||||
return base64_decode(out,s.c_str(),s.size());
|
||||
}
|
||||
|
||||
/** Decode base64 string into binary data
|
||||
* @param out adding new content.
|
||||
* @param s: input base64 string
|
||||
* @return Return the decoded binary data.
|
||||
*/
|
||||
inline std::string base64_decode(std::string const& s) {
|
||||
std::string out;
|
||||
base64_decode(out,s.c_str(),s.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace bio = boost::iostreams;
|
||||
|
||||
/** A base64 encoder that can be used as a boost iostream filter
|
||||
*
|
||||
* @sa See create_base64_encoder() for example usage
|
||||
*/
|
||||
struct base64_encoder {
|
||||
|
||||
typedef char char_type;
|
||||
struct category : bio::multichar_output_filter_tag
|
||||
, bio::closable_tag
|
||||
, bio::optimally_buffered_tag
|
||||
{};
|
||||
|
||||
/** Constructor
|
||||
* @param line_size: line size for the output base64 string, 0 to
|
||||
* disable segmentation.
|
||||
*/
|
||||
base64_encoder(std::size_t line_size)
|
||||
:line_size(line_size)
|
||||
{
|
||||
}
|
||||
|
||||
std::streamsize optimal_buffer_size() const {
|
||||
return base64_decode_size(line_size);
|
||||
}
|
||||
|
||||
template<typename Device>
|
||||
void close(Device &dev)
|
||||
{
|
||||
if(pending_size)
|
||||
base64_encode(buffer,pending,pending_size);
|
||||
if(buffer.size()) {
|
||||
bio::write(dev,buffer.c_str(),buffer.size());
|
||||
if(line_size)
|
||||
bio::put(dev,'\n');
|
||||
buffer.clear();
|
||||
}else if(pos && line_size)
|
||||
bio::put(dev,'\n');
|
||||
}
|
||||
|
||||
template<typename Device>
|
||||
std::streamsize write(Device& dev, const char_type* s, std::streamsize n) {
|
||||
std::streamsize res = n;
|
||||
|
||||
if(pending_size) {
|
||||
while(n && pending_size < 3) {
|
||||
pending[pending_size++] = *s++;
|
||||
--n;
|
||||
}
|
||||
if(pending_size!=3)
|
||||
return res;
|
||||
|
||||
base64_encode(buffer,pending,3);
|
||||
}
|
||||
pending_size = n%3;
|
||||
n = n/3*3;
|
||||
base64_encode(buffer,s,n);
|
||||
s += n;
|
||||
for(unsigned i=0;i<pending_size;++i)
|
||||
pending[i] = s[i];
|
||||
|
||||
const char *buf = buffer.c_str();
|
||||
const char *end = buf + buffer.size();
|
||||
if(line_size && buffer.size()>=line_size-pos) {
|
||||
bio::write(dev,buf,line_size-pos);
|
||||
bio::put(dev,'\n');
|
||||
buf += line_size-pos;
|
||||
pos = 0;
|
||||
for(; end-buf>=(int)line_size; buf+=line_size) {
|
||||
bio::write(dev,buf,line_size);
|
||||
bio::put(dev,'\n');
|
||||
}
|
||||
}
|
||||
pos += end-buf;
|
||||
bio::write(dev,buf,end-buf);
|
||||
buffer.clear();
|
||||
return n;
|
||||
}
|
||||
|
||||
std::size_t line_size;
|
||||
std::size_t pos = 0;
|
||||
std::size_t pending_size = 0;
|
||||
unsigned char pending[3];
|
||||
std::string buffer;
|
||||
};
|
||||
|
||||
/** A base64 decoder that can be used as a boost iostream filter
|
||||
*
|
||||
* @sa See create_base64_decoder() for example usage
|
||||
*/
|
||||
struct base64_decoder {
|
||||
|
||||
typedef char char_type;
|
||||
struct category : bio::multichar_input_filter_tag
|
||||
, bio::optimally_buffered_tag
|
||||
{};
|
||||
|
||||
/** Constructor
|
||||
* @param line_size: line size of the encoded base64 string. This is
|
||||
* used just as a suggestion for better buffering.
|
||||
* @param silent: whether to throw on invalid non white space character.
|
||||
*/
|
||||
base64_decoder(std::size_t line_size, bool silent)
|
||||
:line_size(line_size), silent(silent)
|
||||
{
|
||||
}
|
||||
|
||||
std::streamsize optimal_buffer_size() const {
|
||||
return base64_encode_size(line_size?line_size:1024);
|
||||
}
|
||||
|
||||
template<typename Device>
|
||||
std::streamsize read(Device& dev, char_type* s, std::streamsize n) {
|
||||
static const signed char *table = base64_decode_table();
|
||||
|
||||
if(!n)
|
||||
return 0;
|
||||
|
||||
std::streamsize count = 0;
|
||||
|
||||
for(;;) {
|
||||
while(pending_out<out_count) {
|
||||
*s++ = char_array_3[pending_out++];
|
||||
++count;
|
||||
if(--n == 0)
|
||||
return count;
|
||||
}
|
||||
|
||||
if(eof)
|
||||
return count?count:-1;
|
||||
|
||||
for(;;) {
|
||||
int d = bio::get(dev);
|
||||
if(d < 0) {
|
||||
eof = true;
|
||||
if(pending_in<=1) {
|
||||
if(pending_in == 1 && !silent)
|
||||
throw BOOST_IOSTREAMS_FAILURE("Unexpected ending of base64 string");
|
||||
return count?count:-1;
|
||||
}
|
||||
out_count = pending_in-1;
|
||||
pending_in = 4;
|
||||
} else {
|
||||
signed char c = table[d];
|
||||
if(c < 0) {
|
||||
if(c==-2 || silent)
|
||||
continue;
|
||||
throw BOOST_IOSTREAMS_FAILURE("Invalid character in base64 string");
|
||||
}
|
||||
char_array_4[pending_in++] = (char)c;
|
||||
}
|
||||
if(pending_in == 4) {
|
||||
pending_out = pending_in = 0;
|
||||
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t line_size;
|
||||
std::uint8_t pending_in = 0;
|
||||
char char_array_4[4];
|
||||
std::uint8_t pending_out = 3;
|
||||
std::uint8_t out_count = 3;
|
||||
char char_array_3[3];
|
||||
bool silent;
|
||||
bool eof = false;
|
||||
};
|
||||
|
||||
/** Create an output stream that transforms the input binary data to base64 strings
|
||||
*
|
||||
* @param out: the downstream output stream that will be fed with base64 string
|
||||
* @param line_size: line size of the base64 string. Zero to disable segmenting.
|
||||
*
|
||||
* @return A unique pointer to an output stream that can transforms the
|
||||
* input binary data to base64 strings.
|
||||
*/
|
||||
inline std::unique_ptr<std::ostream> create_base64_encoder(
|
||||
std::ostream &out, std::size_t line_size=80)
|
||||
{
|
||||
std::unique_ptr<std::ostream> res(new bio::filtering_ostream);
|
||||
bio::filtering_ostream *f = static_cast<bio::filtering_ostream*>(res.get());
|
||||
f->push(base64_encoder(line_size));
|
||||
f->push(out);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Create an output stream that stores the input binary data to file as base64 strings
|
||||
*
|
||||
* @param filename: the output file path
|
||||
* @param line_size: line size of the base64 string. Zero to disable segmenting.
|
||||
*
|
||||
* @return A unique pointer to an output stream that can transforms the
|
||||
* input binary data to base64 strings.
|
||||
*/
|
||||
inline std::unique_ptr<std::ostream> create_base64_encoder(
|
||||
const std::string &filepath, std::size_t line_size=80)
|
||||
{
|
||||
std::unique_ptr<std::ostream> res(new bio::filtering_ostream);
|
||||
bio::filtering_ostream *f = static_cast<bio::filtering_ostream*>(res.get());
|
||||
f->push(base64_encoder(line_size));
|
||||
f->push(bio::file_sink(filepath));
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Create an input stream that can transform base64 into binary
|
||||
*
|
||||
* @param in: input upstream.
|
||||
* @param line_size: line size of the encoded base64 string. This is
|
||||
* used just as a suggestion for better buffering.
|
||||
* @param silent: whether to throw on invalid non white space character.
|
||||
*
|
||||
* @return A unique pointer to an input stream that read from the given
|
||||
* upstream and transform the read base64 strings into binary data.
|
||||
*/
|
||||
inline std::unique_ptr<std::istream> create_base64_decoder(
|
||||
std::istream &in, std::size_t line_size=80, bool silent=true)
|
||||
{
|
||||
std::unique_ptr<std::istream> res(new bio::filtering_istream);
|
||||
bio::filtering_istream *f = static_cast<bio::filtering_istream*>(res.get());
|
||||
f->push(base64_decoder(line_size,silent));
|
||||
f->push(in);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Create an input stream that can transform base64 into binary
|
||||
*
|
||||
* @param filepath: input file.
|
||||
* @param ending: optional ending character. If non zero, the filter
|
||||
* will signal EOF when encounter this character.
|
||||
* @param putback: if true and the filter read the ending character
|
||||
* it will put it back into upstream
|
||||
* @param line_size: line size of the encoded base64 string. This is
|
||||
* used just as a suggestion for better buffering.
|
||||
* @param silent: whether to throw on invalid non white space character.
|
||||
*
|
||||
* @return A unique pointer to an input stream that read from the given
|
||||
* file and transform the read base64 strings into binary data.
|
||||
*/
|
||||
inline std::unique_ptr<std::istream> create_base64_decoder(
|
||||
const std::string &filepath, std::size_t line_size=80, bool silent=true)
|
||||
{
|
||||
std::unique_ptr<std::istream> res(new bio::filtering_istream);
|
||||
bio::filtering_istream *f = static_cast<bio::filtering_istream*>(res.get());
|
||||
f->push(base64_decoder(line_size,silent));
|
||||
f->push(bio::file_source(filepath));
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace Base
|
||||
|
||||
#endif
|
||||
|
||||
@@ -109,6 +109,7 @@ template <typename Enum>
|
||||
class Flags {
|
||||
static_assert(std::is_enum<Enum>::value, "Flags is only usable on enumeration types.");
|
||||
Enum i;
|
||||
typedef typename std::underlying_type<Enum>::type underlying_type;
|
||||
|
||||
public:
|
||||
constexpr inline Flags(Enum f) : i(f) {}
|
||||
@@ -123,6 +124,12 @@ public:
|
||||
using u = typename std::underlying_type<Enum>::type;
|
||||
return static_cast<u>(i) == static_cast<u>(f.i);
|
||||
}
|
||||
Enum getValue() const {
|
||||
return i;
|
||||
}
|
||||
underlying_type toUnderlyingType() const {
|
||||
return static_cast<underlying_type>(i);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -610,7 +610,7 @@ inline bool BoundBox3<_Precision>::IntersectionPoint (const Vector3<_Precision>
|
||||
rc = IntersectPlaneWithLine(i, rcVct, rcVctDir, cVctRes);
|
||||
if (!cCmpBound.IsInBox(cVctRes))
|
||||
rc = false;
|
||||
if (rc == true) {
|
||||
if (rc) {
|
||||
// does intersection point lie in desired direction
|
||||
// or was found the opposing side?
|
||||
// -> scalar product of both direction vectors > 0 (angle < 90)
|
||||
@@ -773,7 +773,7 @@ inline typename BoundBox3<_Precision>::SIDE BoundBox3<_Precision>::GetSideFromRa
|
||||
Vector3<_Precision>& rcInt) const
|
||||
{
|
||||
Vector3<_Precision> cP0, cP1;
|
||||
if (IntersectWithLine(rclPt, rclDir, cP0, cP1) == false)
|
||||
if (!IntersectWithLine(rclPt, rclDir, cP0, cP1))
|
||||
return INVALID;
|
||||
|
||||
Vector3<_Precision> cOut;
|
||||
|
||||
+120
-72
@@ -14,196 +14,244 @@
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Juergen Riegel" EMail="FreeCAD@juergen-riegel.net" />
|
||||
<DeveloperDocu>This is the BoundBox export class</DeveloperDocu>
|
||||
<UserDocu>Bound box class
|
||||
A bounding box is an orthographic cube which is a way to describe outer boundaries.
|
||||
You get a bounding box from a lot of 3D types. It is often used to check if a 3D
|
||||
entity lies in the range of another object. Checking for bounding interference first
|
||||
can save a lot of computing time!
|
||||
|
||||
Constructor:
|
||||
App.BoundBox([Xmin,Ymin,Zmin,Xmax,Ymax,Zmax])
|
||||
App.BoundBox(Tuple, Tuple)
|
||||
App.BoundBox(Vector, Vector)
|
||||
App.BoundBox(BoundBox)
|
||||
</UserDocu>
|
||||
<UserDocu>Base.BoundBox class.\n
|
||||
This class represents a bounding box.
|
||||
A bounding box is a rectangular cuboid which is a way to describe outer
|
||||
boundaries and is obtained from a lot of 3D types.
|
||||
It is often used to check if a 3D entity lies in the range of another object.
|
||||
Checking for bounding interference first can save a lot of computing time!
|
||||
An invalid BoundBox is represented by inconsistent values at each direction:
|
||||
The maximum float value of the system at the minimum coordinates, and the
|
||||
opposite value at the maximum coordinates.\n
|
||||
The following constructors are supported:\n
|
||||
BoundBox()
|
||||
Empty constructor. Returns an invalid BoundBox.\n
|
||||
BoundBox(boundBox)
|
||||
Copy constructor.
|
||||
boundBox : Base.BoundBox\n
|
||||
BoundBox(xMin, yMin=0, zMin=0, xMax=0, yMax=0, zMax=0)
|
||||
Define from the minimum and maximum values at each direction.
|
||||
xMin : float\n Minimum value at x-coordinate.
|
||||
yMin : float\n Minimum value at y-coordinate.
|
||||
zMin : float\n Minimum value at z-coordinate.
|
||||
xMax : float\n Maximum value at x-coordinate.
|
||||
yMax : float\n Maximum value at y-coordinate.
|
||||
zMax : float\n Maximum value at z-coordinate.\n
|
||||
App.BoundBox(min, max)
|
||||
Define from two containers representing the minimum and maximum values of the
|
||||
coordinates in each direction.
|
||||
min : Base.Vector, tuple\n Minimum values of the coordinates.
|
||||
max : Base.Vector, tuple\n Maximum values of the coordinates.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="setVoid">
|
||||
<Documentation>
|
||||
<UserDocu>method setVoid()
|
||||
Invalidate the bounding box</UserDocu>
|
||||
<UserDocu>setVoid() -> None\n
|
||||
Invalidate the bounding box.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isValid">
|
||||
<Documentation>
|
||||
<UserDocu>method isValid()
|
||||
Checks if the bounding box is valid</UserDocu>
|
||||
<UserDocu>isValid() -> bool\n
|
||||
Checks if the bounding box is valid.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="add">
|
||||
<Documentation>
|
||||
<UserDocu>method add(BoundBox)
|
||||
Add (enlarge) the given BoundBox</UserDocu>
|
||||
<UserDocu>add(minMax) -> None
|
||||
add(x, y, z) -> None\n
|
||||
Increase the maximum values or decrease the minimum values of this BoundBox by
|
||||
replacing the current values with the given values, so the bounding box can grow
|
||||
but not shrink.\n
|
||||
minMax : Base.Vector, tuple\n Values to enlarge at each direction.
|
||||
x : float\n Value to enlarge at x-direction.
|
||||
y : float\n Value to enlarge at y-direction.
|
||||
z : float\n Value to enlarge at z-direction.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getPoint">
|
||||
<Documentation>
|
||||
<UserDocu>method getPoint(Int)
|
||||
Get the point of the given index. The index must be in the range of [0,7]
|
||||
</UserDocu>
|
||||
<UserDocu>getPoint(index) ->Base.Vector\n
|
||||
Get the point of the given index.
|
||||
The index must be in the range of [0, 7].\n
|
||||
index : int</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getEdge">
|
||||
<Documentation>
|
||||
<UserDocu>method getEdge(Int)
|
||||
Get the edge points of the given index. The index must be in the range of [0,11]
|
||||
</UserDocu>
|
||||
<UserDocu>getEdge(index) -> tuple of Base.Vector\n
|
||||
Get the edge points of the given index.
|
||||
The index must be in the range of [0, 11].\n
|
||||
index : int</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="closestPoint">
|
||||
<Documentation>
|
||||
<UserDocu>method closestPoint(Vector)
|
||||
Get the closest point of the bounding box to the given point
|
||||
</UserDocu>
|
||||
<UserDocu>closestPoint(point) -> Base.Vector
|
||||
closestPoint(x, y, z) -> Base.Vector\n
|
||||
Get the closest point of the bounding box to the given point.\n
|
||||
point : Base.Vector, tuple\n Coordinates of the given point.
|
||||
x : float\n X-coordinate of the given point.
|
||||
y : float\n Y-coordinate of the given point.
|
||||
z : float\n Z-coordinate of the given point.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="intersect">
|
||||
<Documentation>
|
||||
<UserDocu>method intersect(BoundBox|Vector Base, Vector Dir)
|
||||
Checks if the given object intersects with the BoundBox. That can be:
|
||||
- Another BoundBox
|
||||
- A line, specified by Base and Dir
|
||||
</UserDocu>
|
||||
<UserDocu>intersect(boundBox2) -> bool
|
||||
intersect(base, dir) -> bool\n
|
||||
Checks if the given object intersects with this bounding box. That can be
|
||||
another bounding box or a line specified by base and direction.\n
|
||||
boundBox2 : Base.BoundBox
|
||||
base : Base.Vector, tuple
|
||||
dir : Base.Vector, tuple</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="intersected">
|
||||
<Documentation>
|
||||
<UserDocu>method intersected(BoundBox)
|
||||
Returns the intersection of this and the given bounding box.
|
||||
</UserDocu>
|
||||
<UserDocu>intersected(boundBox2) -> Base.BoundBox\n
|
||||
Returns the intersection of this and the given bounding box.\n
|
||||
boundBox2 : Base.BoundBox</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="united">
|
||||
<Documentation>
|
||||
<UserDocu>method united(BoundBox)
|
||||
Returns the union of this and the given bounding box.
|
||||
</UserDocu>
|
||||
<UserDocu>united(boundBox2) -> Base.BoundBox\n
|
||||
Returns the union of this and the given bounding box.\n
|
||||
boundBox2 : Base.BoundBox</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="enlarge">
|
||||
<Documentation>
|
||||
<UserDocu>method enlarge(Float)
|
||||
Enlarge the BoundBox by the given value in each direction.
|
||||
A negative value shrinks the box.</UserDocu>
|
||||
<UserDocu>enlarge(variation) -> None\n
|
||||
Decrease the minimum values and increase the maximum values by the given value.
|
||||
A negative value shrinks the bounding box.\n
|
||||
variation : float</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
|
||||
<Methode Name="getIntersectionPoint">
|
||||
<Documentation>
|
||||
<UserDocu>method Vector getIntersectionPoint(Vector Base, Vector Dir, [float epsilon=0.0001])
|
||||
Calculate the intersection point of a line with the BoundBox
|
||||
The Base point must lie inside the bounding box, if not an
|
||||
exception is thrown.
|
||||
</UserDocu>
|
||||
<UserDocu>getIntersectionPoint(base, dir, epsilon=0.0001) -> Base.Vector\n
|
||||
Calculate the intersection point of a line with the bounding box.
|
||||
The base point must lie inside the bounding box, if not an exception is thrown.\n
|
||||
base : Base.Vector\n Base point of the line.
|
||||
dir : Base.Vector\n Direction of the line.
|
||||
epsilon : float\n Bounding box size tolerance.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="move">
|
||||
<Documentation>
|
||||
<UserDocu> method move(Vector)
|
||||
Move the BoundBox by the given vector
|
||||
</UserDocu>
|
||||
<UserDocu>move(displacement) -> None
|
||||
move(x, y, z) -> None\n
|
||||
Move the bounding box by the given values.\n
|
||||
displacement : Base.Vector, tuple\n Displacement at each direction.
|
||||
x : float\n Displacement at x-direction.
|
||||
y : float\n Displacement at y-direction.
|
||||
z : float\n Displacement at z-direction.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="scale">
|
||||
<Documentation>
|
||||
<UserDocu> method scale(x,y,z)
|
||||
Scale the BoundBox by the given values in x, y and z
|
||||
</UserDocu>
|
||||
<UserDocu>scale(factor) -> None
|
||||
scale(x, y, z) -> None\n
|
||||
Scale the bounding box by the given values.\n
|
||||
factor : Base.Vector, tuple\n Factor scale at each direction.
|
||||
x : float\n Scale at x-direction.
|
||||
y : float\n Scale at y-direction.
|
||||
z : float\n Scale at z-direction.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="transformed">
|
||||
<Documentation>
|
||||
<UserDocu> method transformed(Matrix)
|
||||
Return a new bounding box with the transformed corner of this bounding box
|
||||
</UserDocu>
|
||||
<UserDocu>transformed(matrix) -> Base.BoundBox\n
|
||||
Returns a new BoundBox containing the transformed rectangular cuboid
|
||||
represented by this BoundBox.\n
|
||||
matrix : Base.Matrix\n Transformation matrix.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isCutPlane">
|
||||
<Documentation>
|
||||
<UserDocu>method bool isCutPlane(Vector Base, Vector Normal)
|
||||
Check if the plane specified by Base and Normal intersects (cuts) the BoundBox</UserDocu>
|
||||
<UserDocu>isCutPlane(base, normal) -> bool\n
|
||||
Check if the plane specified by base and normal intersects (cuts) this bounding
|
||||
box.\n
|
||||
base : Base.Vector
|
||||
normal : Base.Vector</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isInside">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
method bool isInside(Vector Base|BoundBox box)
|
||||
Check if the point or bounding box is inside this bounding box
|
||||
</UserDocu>
|
||||
<UserDocu>isInside(object) -> bool
|
||||
isInside(x, y, z) -> bool\n
|
||||
Check if a point or a bounding box is inside this bounding box.\n
|
||||
object : Base.Vector, Base.BoundBox\n Object to check if it is inside this bounding box.
|
||||
x : float\n X-coordinate of the point to check.
|
||||
y : float\n Y-coordinate of the point to check.
|
||||
z : float\n Z-coordinate of the point to check.</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Center" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Center point of the bounding box</UserDocu>
|
||||
<UserDocu>Center point of the bounding box.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Center" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="XMax" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The maximum x boundary position</UserDocu>
|
||||
<UserDocu>The maximum x boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="XMax" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="YMax" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The maximum y boundary position</UserDocu>
|
||||
<UserDocu>The maximum y boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="YMax" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="ZMax" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The maximum z boundary position</UserDocu>
|
||||
<UserDocu>The maximum z boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ZMax" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="XMin" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The minimum x boundary position</UserDocu>
|
||||
<UserDocu>The minimum x boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="XMin" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="YMin" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The minimum y boundary position</UserDocu>
|
||||
<UserDocu>The minimum y boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="YMin" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="ZMin" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>The minimum z boundary position</UserDocu>
|
||||
<UserDocu>The minimum z boundary position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ZMin" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="XLength" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Length of the BoundBox in x direction</UserDocu>
|
||||
<UserDocu>Length of the bounding box in x direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="XLength" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="YLength" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Length of the BoundBox in y direction</UserDocu>
|
||||
<UserDocu>Length of the bounding box in y direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="YLength" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="ZLength" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Length of the BoundBox in z direction</UserDocu>
|
||||
<UserDocu>Length of the bounding box in z direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ZLength" Type="Float" />
|
||||
</Attribute>
|
||||
<Attribute Name="DiagonalLength" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Diagonal length of the BoundBox</UserDocu>
|
||||
<UserDocu>Diagonal length of the bounding box.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="DiagonalLength" Type="Float" />
|
||||
</Attribute>
|
||||
|
||||
+24
-25
@@ -311,23 +311,22 @@ PyObject* BoundBoxPy::getIntersectionPoint(PyObject *args)
|
||||
{
|
||||
PyObject *object,*object2;
|
||||
double epsilon=0.0001;
|
||||
if (PyArg_ParseTuple(args,"O!O!|d:Need base and direction vector",
|
||||
&(Base::VectorPy::Type), &object,&(Base::VectorPy::Type), &object2, &epsilon)) {
|
||||
Base::Vector3d point;
|
||||
bool ok = getBoundBoxPtr()->IntersectionPoint(
|
||||
*(static_cast<Base::VectorPy*>(object)->getVectorPtr()),
|
||||
*(static_cast<Base::VectorPy*>(object2)->getVectorPtr()),
|
||||
point, epsilon);
|
||||
if (ok) {
|
||||
return new VectorPy(point);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "No intersection");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!PyArg_ParseTuple(args,"O!O!|d;Need base and direction vector",
|
||||
&(Base::VectorPy::Type), &object,&(Base::VectorPy::Type), &object2, &epsilon))
|
||||
return nullptr;
|
||||
|
||||
Base::Vector3d point;
|
||||
bool ok = getBoundBoxPtr()->IntersectionPoint(
|
||||
*(static_cast<Base::VectorPy*>(object)->getVectorPtr()),
|
||||
*(static_cast<Base::VectorPy*>(object2)->getVectorPtr()),
|
||||
point, epsilon);
|
||||
if (ok) {
|
||||
return new VectorPy(point);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(Base::PyExc_FC_GeneralError, "No intersection");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* BoundBoxPy::move(PyObject *args)
|
||||
@@ -344,13 +343,13 @@ PyObject* BoundBoxPy::move(PyObject *args)
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args,"O!:Need vector to move",&PyTuple_Type, &object)) {
|
||||
if (PyArg_ParseTuple(args,"O!",&PyTuple_Type, &object)) {
|
||||
vec = getVectorFromTuple<double>(object);
|
||||
break;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args,"O!:Need vector to move",&(Base::VectorPy::Type), &object)) {
|
||||
if (PyArg_ParseTuple(args,"O!",&(Base::VectorPy::Type), &object)) {
|
||||
vec = *(static_cast<Base::VectorPy*>(object)->getVectorPtr());
|
||||
break;
|
||||
}
|
||||
@@ -382,13 +381,13 @@ PyObject* BoundBoxPy::scale(PyObject *args)
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args,"O!:Need vector to scale",&PyTuple_Type, &object)) {
|
||||
if (PyArg_ParseTuple(args,"O!",&PyTuple_Type, &object)) {
|
||||
vec = getVectorFromTuple<double>(object);
|
||||
break;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args,"O!:Need vector to scale",&(Base::VectorPy::Type), &object)) {
|
||||
if (PyArg_ParseTuple(args,"O!",&(Base::VectorPy::Type), &object)) {
|
||||
vec = *(static_cast<Base::VectorPy*>(object)->getVectorPtr());
|
||||
break;
|
||||
}
|
||||
@@ -429,14 +428,14 @@ PyObject* BoundBoxPy::isCutPlane(PyObject *args)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (PyArg_ParseTuple(args,"O!O!:Need base and normal vector of a plane",
|
||||
if (!PyArg_ParseTuple(args,"O!O!;Need base and normal vector of a plane",
|
||||
&(Base::VectorPy::Type), &object,&(Base::VectorPy::Type), &object2))
|
||||
retVal = getBoundBoxPtr()->IsCutPlane(
|
||||
*(static_cast<Base::VectorPy*>(object)->getVectorPtr()),
|
||||
*(static_cast<Base::VectorPy*>(object2)->getVectorPtr()));
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
retVal = getBoundBoxPtr()->IsCutPlane(
|
||||
*(static_cast<Base::VectorPy*>(object)->getVectorPtr()),
|
||||
*(static_cast<Base::VectorPy*>(object2)->getVectorPtr()));
|
||||
|
||||
return Py::new_reference_to(retVal);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ void Builder3D::endPoints()
|
||||
void Builder3D::addSinglePoint(float x, float y, float z,short pointSize, float color_r,float color_g,float color_b)
|
||||
{
|
||||
// addSinglePoint() not between startXXX() and endXXX() allowed
|
||||
assert( bStartEndOpen == false );
|
||||
assert(!bStartEndOpen);
|
||||
|
||||
result << "Separator { ";
|
||||
result << "Material { ";
|
||||
@@ -155,7 +155,7 @@ void Builder3D::addSinglePoint(const Base::Vector3f &vec, short pointSize, float
|
||||
void Builder3D::addText(float pos_x, float pos_y , float pos_z,const char * text, float color_r,float color_g,float color_b)
|
||||
{
|
||||
// addSinglePoint() not between startXXX() and endXXX() allowed
|
||||
assert( bStartEndOpen == false );
|
||||
assert(!bStartEndOpen);
|
||||
|
||||
result << "Separator { "
|
||||
<< "Material { diffuseColor " << color_r << " "<< color_g << " "<< color_b << "} "
|
||||
@@ -172,8 +172,8 @@ void Builder3D::addText(const Base::Vector3f &vec,const char * text, float color
|
||||
|
||||
void Builder3D::clear ()
|
||||
{
|
||||
// Under VC6 string::clear() doesn't exist, under gcc stringstream::str() returns a copy not a reference
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
// under gcc stringstream::str() returns a copy not a reference
|
||||
#if defined(_MSC_VER)
|
||||
result.str().clear();
|
||||
#endif
|
||||
result.clear();
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <frameobject.h>
|
||||
|
||||
#include "ConsoleObserver.h"
|
||||
#include "Interpreter.h"
|
||||
|
||||
|
||||
using namespace Base;
|
||||
@@ -263,6 +264,7 @@ std::stringstream &LogLevel::prefix(std::stringstream &str, const char *src, int
|
||||
}
|
||||
if (print_tag) str << '<' << tag << "> ";
|
||||
if (print_src==2) {
|
||||
PyGILStateLocker lock;
|
||||
PyFrameObject* frame = PyEval_GetFrame();
|
||||
if (frame) {
|
||||
line = PyFrame_GetLineNumber(frame);
|
||||
|
||||
@@ -14,68 +14,76 @@
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="Juergen Riegel" EMail="FreeCAD@juergen-riegel.net" />
|
||||
<DeveloperDocu>This is the CoordinateSystem export class</DeveloperDocu>
|
||||
<UserDocu></UserDocu>
|
||||
<UserDocu>Base.CoordinateSystem class.\n
|
||||
An orthonormal right-handed coordinate system in 3D space.\n
|
||||
CoordinateSystem()
|
||||
Empty constructor.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="setAxes">
|
||||
<Documentation>
|
||||
<UserDocu>setAxes(Axis or Vector z, Vector x)
|
||||
Set axis or z direction and x direction</UserDocu>
|
||||
<UserDocu>setAxes(axis, xDir) -> None\n
|
||||
Set axis or Z-direction, and X-direction.
|
||||
The X-direction is determined from the orthonormal compononent of `xDir`
|
||||
with respect to `axis` direction.\n
|
||||
axis : Base.Axis, Base.Vector
|
||||
xDir : Base.Vector</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="displacement" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>displacement(CoordinateSystem)
|
||||
Computes the placement from this to the passed coordinate system</UserDocu>
|
||||
<UserDocu>displacement(coordSystem2) -> Base.Placement\n
|
||||
Computes the placement from this to the passed coordinate system `coordSystem2`.\n
|
||||
coordSystem2 : Base.CoordinateSystem</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="transformTo">
|
||||
<Documentation>
|
||||
<UserDocu>transformTo(Vector)
|
||||
Computes the coordinates of the point in coordinates of this system
|
||||
</UserDocu>
|
||||
<UserDocu>transformTo(vector) -> Base.Vector\n
|
||||
Computes the coordinates of the point in coordinates of this coordinate system.\n
|
||||
vector : Base.Vector</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="transform">
|
||||
<Documentation>
|
||||
<UserDocu>transform(Rotation or Placement)
|
||||
Applies the rotation or placement on this coordinate system
|
||||
</UserDocu>
|
||||
<UserDocu>transform(trans) -> None\n
|
||||
Applies a transformation on this coordinate system.\n
|
||||
trans : Base.Rotation, Base.Placement</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="setPlacement">
|
||||
<Documentation>
|
||||
<UserDocu>setPlacment(Placement)
|
||||
Set placement to the coordinate system.
|
||||
</UserDocu>
|
||||
<UserDocu>setPlacment(placement) -> None\n
|
||||
Set placement to the coordinate system.\n
|
||||
placement : Base.Placement</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Axis" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Set or get axis</UserDocu>
|
||||
<UserDocu>Set or get axis.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Axis" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="XDirection" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Set or get x direction</UserDocu>
|
||||
<UserDocu>Set or get X-direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="XDirection" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="YDirection" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Set or get y direction</UserDocu>
|
||||
<UserDocu>Set or get Y-direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="YDirection" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="ZDirection" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Set or get z direction</UserDocu>
|
||||
<UserDocu>Set or get Z-direction.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ZDirection" Type="Object" />
|
||||
</Attribute>
|
||||
<Attribute Name="Position" ReadOnly="false">
|
||||
<Documentation>
|
||||
<UserDocu>Set or get position</UserDocu>
|
||||
<UserDocu>Set or get position.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Position" Type="Object" />
|
||||
</Attribute>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user