Compare commits
655 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99bc33af60 | |||
| 8718bc28fe | |||
| 7886ebae10 | |||
| f22887868f | |||
| 2e7c16fccd | |||
| b29db79928 | |||
| 8a369481d6 | |||
| 603ec56151 | |||
| 12cced51f1 | |||
| 439c50c5c4 | |||
| 87a3bcf9db | |||
| 8910345149 | |||
| af4e54a6b7 | |||
| 90a0132533 | |||
| fe425c3f57 | |||
| 8098d72bb2 | |||
| ebde1e3d9a | |||
| d9b4006aa1 | |||
| 0b78b5ade8 | |||
| 4750f06058 | |||
| 0cb8f7e240 | |||
| 49d7d77274 | |||
| d443d5b065 | |||
| 013a1d5f3a | |||
| 180c39709a | |||
| 601bcd5e3d | |||
| dcb380e1ca | |||
| cfe641fb7d | |||
| d384c9d8cb | |||
| 3620b68b21 | |||
| 20e70f84e1 | |||
| e28b1ce1ad | |||
| c8efc26982 | |||
| 9abe7b4af1 | |||
| 27f077c62b | |||
| eabd052c17 | |||
| 706b01f607 | |||
| 8a2f665430 | |||
| 9fe630e0c3 | |||
| 91f015b132 | |||
| ad630cbb9c | |||
| 51ac15b375 | |||
| db1469f219 | |||
| 1665dec4e4 | |||
| 99e414efab | |||
| 7cb3815fb1 | |||
| 5c6bf5461d | |||
| 3076ce66be | |||
| d59471b6bd | |||
| 4ba5504e7a | |||
| 7db3f901fd | |||
| f4665aa7b5 | |||
| 6d8b98d471 | |||
| 03f506c5a5 | |||
| d90c88f0fc | |||
| df8c6b5db9 | |||
| 5455306a4a | |||
| d1476c819c | |||
| 88a74cfa3a | |||
| 5e818e961c | |||
| fdef6c35e7 | |||
| 4ac848aab0 | |||
| e1fdc27e7c | |||
| 0caccde398 | |||
| 244dffcfb7 | |||
| 5328e74e3d | |||
| 3c48b4a950 | |||
| a78c31be69 | |||
| c2495411b7 | |||
| 1a8e2fb333 | |||
| 73c3c78474 | |||
| 509c881ea0 | |||
| d690dcb1d3 | |||
| 493829b376 | |||
| 0819d776d7 | |||
| 79aca8950f | |||
| 8efe9964e7 | |||
| eda87a7efe | |||
| e1815f10ff | |||
| 7d39a9d59a | |||
| baa47bd606 | |||
| 51b37da53e | |||
| 8ce3c4a1cc | |||
| 037ce3bffd | |||
| b9306c6f63 | |||
| 7b2b972efa | |||
| 6d66721582 | |||
| 448235cd2b | |||
| a729bb4bc1 | |||
| 03fc08d02e | |||
| e44c1ce75a | |||
| 4083c7c616 | |||
| 76a84f63ab | |||
| 065315d7a4 | |||
| 6206ed2c51 | |||
| 451072f0d7 | |||
| 0b232ac1ff | |||
| 737cab44f2 | |||
| a06be5de68 | |||
| 0ea238f90c | |||
| 5ae85148cc | |||
| 1182be91bc | |||
| cd5876dc54 | |||
| ca4660167e | |||
| a0c97a102e | |||
| 90c83636cb | |||
| e561950ff8 | |||
| e7e5e39e7b | |||
| d842e4151c | |||
| 320bd61156 | |||
| fed11359d9 | |||
| fdf0013dcb | |||
| bf98221885 | |||
| d214306d1b | |||
| a0af0d2b85 | |||
| ee27de857a | |||
| 4afbadec04 | |||
| cdd9d685fe | |||
| a34bad7da4 | |||
| e20b42e484 | |||
| 79923c16f3 | |||
| 004927e16e | |||
| e8d9f30c10 | |||
| f06dfa5af8 | |||
| dc1e96c46a | |||
| 96afba8351 | |||
| 72b9a91337 | |||
| c468a622e6 | |||
| edde9fb18e | |||
| 5754c66a55 | |||
| 146ed0d704 | |||
| e807d2d421 | |||
| 0e83500531 | |||
| 143c1737af | |||
| f7939beee0 | |||
| c6aeec9146 | |||
| 9e065cdb7f | |||
| b55dd47120 | |||
| 11dd9d8870 | |||
| 88940fb375 | |||
| aa5feb3df0 | |||
| dee9d5a498 | |||
| 8c18208c97 | |||
| d68b0c087e | |||
| 35b77bc069 | |||
| 0702616895 | |||
| f36aeef878 | |||
| 5e7bbe15e3 | |||
| 687c75e5bc | |||
| 36dd4b983c | |||
| cee71e1fb1 | |||
| baed171ec5 | |||
| ecb188fe4c | |||
| 1027be1efa | |||
| d2b84db105 | |||
| c263d8f51c | |||
| 0f0d2c849f | |||
| 025d4a9f5c | |||
| 8140957413 | |||
| 6ad2206595 | |||
| dff7fc6ca8 | |||
| 1671ecb902 | |||
| 8a17ca36a4 | |||
| b8929f279f | |||
| 07540ad3ba | |||
| c387a4b5c9 | |||
| 21ef29bb82 | |||
| 8cb06956d0 | |||
| 17651fbfa4 | |||
| 87651cdd4c | |||
| d34969f7d6 | |||
| 60ebafd0b3 | |||
| 15dd009f13 | |||
| dbb6cbe335 | |||
| 2dcb495a67 | |||
| a102c8a359 | |||
| 8fda540e1a | |||
| bbd1266398 | |||
| 087522528b | |||
| 18cf24e1d9 | |||
| f0a70d5468 | |||
| 26357db694 | |||
| 83d14b785e | |||
| bc0d94d7a7 | |||
| 840122a358 | |||
| a18f77f3b8 | |||
| eb522b52dc | |||
| 04e0518051 | |||
| dac4062d54 | |||
| 949c5421cf | |||
| 912fd47b5f | |||
| b098f3ad44 | |||
| f65dda922f | |||
| 4c6eed1e63 | |||
| 6238fe1081 | |||
| b20a6acc26 | |||
| c6b99363d6 | |||
| 26435d03fd | |||
| 3c56c164ee | |||
| 6ea74652c9 | |||
| 2db12d8a66 | |||
| 637463ac35 | |||
| e516eae53b | |||
| e12d8fd01e | |||
| e1644a7310 | |||
| 3ae8d45506 | |||
| 2777999d03 | |||
| 64a4cee116 | |||
| fe25d8d0f7 | |||
| be1ec84709 | |||
| ffab288f4e | |||
| 2fb271ff28 | |||
| 617db3a2d4 | |||
| 2d6e49cb7f | |||
| 7d454121de | |||
| ba404c03ef | |||
| 8faaa60a0a | |||
| 7e7045577f | |||
| 93e537f3b3 | |||
| da584c2c84 | |||
| d6479d055d | |||
| 1f848b4d78 | |||
| b78b0a7d60 | |||
| d321a330ee | |||
| 6a4697c74d | |||
| f329584eb5 | |||
| 6a76d22d76 | |||
| 6c85e4a6a2 | |||
| d9dc07c890 | |||
| 5199c47c2d | |||
| aade9e1eed | |||
| 07cc653e66 | |||
| 3a05cb2756 | |||
| 230b64f2f5 | |||
| 1e982cae1f | |||
| 1ed0e153dc | |||
| 263bfe9948 | |||
| 61418544a5 | |||
| df1a1ab981 | |||
| 6dfe193428 | |||
| ec4dcde60c | |||
| df3809e66b | |||
| 8653d94287 | |||
| 93f76a8991 | |||
| 34d03ebee6 | |||
| 512cf349f9 | |||
| 2eb4dc7c73 | |||
| be5e657a61 | |||
| 821596140d | |||
| 0c66d18c21 | |||
| 9ac1b960a6 | |||
| 68b3d8d6e4 | |||
| 88787b11d1 | |||
| 8caa218950 | |||
| 61d17a6122 | |||
| d588e89d1d | |||
| 92ebf00cc4 | |||
| b37da5b3cc | |||
| 3d60531390 | |||
| ac576bc05e | |||
| 07e94dfaae | |||
| b4325de672 | |||
| b9b8d4023f | |||
| eb0d7ba6a5 | |||
| eaf76e4d0a | |||
| b8f98e2842 | |||
| 2b98e80313 | |||
| 659780c31b | |||
| 7be33f496e | |||
| 51cff10dcc | |||
| c9517011d2 | |||
| 7deca678ca | |||
| 8a011392bc | |||
| 0872d45827 | |||
| e292f96feb | |||
| 46dd3badbd | |||
| 8694ccf754 | |||
| 4878248572 | |||
| 2ee49e0647 | |||
| ca575acf1e | |||
| 046be9efc5 | |||
| a1acc9cf38 | |||
| bfb0e203da | |||
| f319a57252 | |||
| e1b9cbf48a | |||
| d60deb6fb6 | |||
| 7cb5c2663d | |||
| 5e0695d150 | |||
| 0df693e204 | |||
| b6c8e68eda | |||
| a17bb6bf10 | |||
| e62d68a49e | |||
| 1a8840bff9 | |||
| 4a773d2f6a | |||
| 9972df7c1d | |||
| 97cf569756 | |||
| 6620e149a5 | |||
| f2063c055f | |||
| ad50c6eb64 | |||
| 657a34b48a | |||
| d5397516b5 | |||
| 4895bea741 | |||
| 9abcdad176 | |||
| e643328599 | |||
| 9c9bf18478 | |||
| c1ca8a79c9 | |||
| 34ae16cd01 | |||
| 6d9201c828 | |||
| ab2f655245 | |||
| 650b15dd76 | |||
| ab5ef99344 | |||
| 0a4f6ec7c4 | |||
| 2e7261eec3 | |||
| e89d849bb7 | |||
| 3c860396d8 | |||
| acb14726b6 | |||
| 0b44a3f6c8 | |||
| 26a1e452c0 | |||
| 4deb889057 | |||
| 59370eeb23 | |||
| 92894ea3a8 | |||
| f153960396 | |||
| e591fe0901 | |||
| 88e7c60414 | |||
| 1c0ac9a269 | |||
| 194ec0820c | |||
| ab1b3246d4 | |||
| 27b74f3ba3 | |||
| 1396309093 | |||
| cd19a3cee5 | |||
| 7923614124 | |||
| f238a5f4e5 | |||
| 26c2d7a77c | |||
| 05ef4153f5 | |||
| 7a392c4d99 | |||
| 0eb01c636c | |||
| af5c40d8e8 | |||
| e4b6e5ab43 | |||
| 322da60cb2 | |||
| 99d142af38 | |||
| 23df715e24 | |||
| 159059fc7d | |||
| d4c28786df | |||
| ca9e1ecdf3 | |||
| 3a241c5515 | |||
| 144f1843fa | |||
| 92a23ca21b | |||
| a57ea57dba | |||
| 0fce2611ad | |||
| cc626f88b1 | |||
| 954a1239f3 | |||
| 1e51d10de8 | |||
| e116b5ae34 | |||
| 7001255e90 | |||
| b36991b239 | |||
| d3496b0458 | |||
| 23f046075a | |||
| 359e1033ec | |||
| c9518817c6 | |||
| 2fda119f74 | |||
| 1d6b2a4cca | |||
| 69b1b19024 | |||
| e3857b11a1 | |||
| 6a4b6af094 | |||
| 088b384216 | |||
| 3f83c820d5 | |||
| 49652e3c60 | |||
| f8e5a92b98 | |||
| 6f8e9f1a9e | |||
| b026958f80 | |||
| d90b6ebd0d | |||
| 0327534ffe | |||
| b4e690d9cb | |||
| ba24ab8a49 | |||
| b0e11e286b | |||
| 94c722d285 | |||
| ddb54cce65 | |||
| 0339458869 | |||
| 85e0038515 | |||
| f67088a970 | |||
| 99016e37ed | |||
| be6af47f29 | |||
| c29868cd48 | |||
| 45f65f643d | |||
| aa4a71b55b | |||
| 2d3b0a2ded | |||
| 3bad5dabde | |||
| bd07c8a214 | |||
| 99f4776fda | |||
| c788a88d6a | |||
| 6f0b1fca3d | |||
| 9fad0ed223 | |||
| fca58d99ed | |||
| 468269b9a6 | |||
| 289411f51c | |||
| f83aaf0e59 | |||
| f1d79d9ab4 | |||
| bc3c0dc19a | |||
| 8567dce28a | |||
| 72a024aaeb | |||
| e0cd49e670 | |||
| 17d5bca2ec | |||
| 82ba9ec9d8 | |||
| d05db60465 | |||
| bb5afb911a | |||
| ec9ead0db9 | |||
| 94a4017432 | |||
| 5f89fd4e98 | |||
| 7b4770c3f2 | |||
| f991407900 | |||
| 47855a018b | |||
| f60f3d7cc5 | |||
| bef9d03312 | |||
| 37600b85a0 | |||
| ce38741a52 | |||
| 62700a5f12 | |||
| 562cac277c | |||
| fae6cda1d7 | |||
| 45598fa319 | |||
| cbdb615141 | |||
| 3fecf957cb | |||
| 0cacc9bd34 | |||
| 9cbef0c5ce | |||
| 4938a6f75b | |||
| 885b8cf1de | |||
| 1bfaa81d77 | |||
| 7586620d41 | |||
| 5d81f8ac16 | |||
| ba030237b7 | |||
| f1366e8a75 | |||
| e595cc49f2 | |||
| 9289e27230 | |||
| a8757f7947 | |||
| 9e042ff480 | |||
| 6d73f9173c | |||
| 36ddfdc7b9 | |||
| 1752fd59f9 | |||
| d94269f85f | |||
| bb977afe55 | |||
| 3f17f2f01f | |||
| 7912f84136 | |||
| db5fff6ccc | |||
| 6abb2b447f | |||
| ba174bdad5 | |||
| ea27d96374 | |||
| 1fcbe6095c | |||
| 379179ce2b | |||
| 076c5916b5 | |||
| 3d14203fa4 | |||
| ec18d4e250 | |||
| ecbe21ca03 | |||
| 54c0c2f83c | |||
| 47aa61bd94 | |||
| 2cd45b07f7 | |||
| 0eaf14373f | |||
| ff377e031f | |||
| 3d0df45cd4 | |||
| be3acac53a | |||
| 1412cad2ec | |||
| bf51a00dfd | |||
| 1046c3682a | |||
| 4497ce0146 | |||
| 353459f1fe | |||
| 72b1076788 | |||
| 6a1da227cd | |||
| 6e34b79da4 | |||
| e38c831970 | |||
| 3f84746a5c | |||
| 94b147fcad | |||
| c4317f88f8 | |||
| c8c764e215 | |||
| e5d0e5316d | |||
| 1cc53d911a | |||
| 7bf2050865 | |||
| b7b3187e1d | |||
| 9e0538abc8 | |||
| a64a43b9ca | |||
| 7c813a6f5a | |||
| 884baf2cb8 | |||
| 8d3c786656 | |||
| 0f4ad868f7 | |||
| 3237a21580 | |||
| a79a22185d | |||
| 5f952812c3 | |||
| 0f23770ad7 | |||
| 9dbf5ae94b | |||
| fa97300ec6 | |||
| 8af563804c | |||
| 0d4d884a59 | |||
| f2a392c8f1 | |||
| 0745d40f86 | |||
| 105543bf17 | |||
| 5b27deb4f0 | |||
| f008c80030 | |||
| b441a3b6c1 | |||
| f36c9a8580 | |||
| 184c977677 | |||
| adf15a401d | |||
| 1de8cd5e36 | |||
| daceb8afe4 | |||
| 8dad760db4 | |||
| 1455321ace | |||
| 47d02c0618 | |||
| 61de0ffa8f | |||
| 53bb61da00 | |||
| dd3c12758f | |||
| dfdabbfc87 | |||
| 2db8942fa9 | |||
| 71e4b4f564 | |||
| 6a349de3e3 | |||
| cc665f1070 | |||
| 626c510177 | |||
| 24f0c8e2c3 | |||
| 4768f20d89 | |||
| 13909dbb00 | |||
| ed2471e835 | |||
| afd998541d | |||
| 74e1d71c65 | |||
| 1d11f05560 | |||
| 45a8650b7d | |||
| cda2b8cbdb | |||
| 4f116d8de3 | |||
| c97f6e5b3f | |||
| 2c3d9e2bb7 | |||
| 2c2cdbfe7f | |||
| 6c9ad95a70 | |||
| 41e3cdb9a5 | |||
| 27587b9cd2 | |||
| 77e5645af0 | |||
| 9440749423 | |||
| 6f60022a35 | |||
| 8a6872e69d | |||
| ed6c0c8111 | |||
| 0b5a0a6abb | |||
| 6d3f786b38 | |||
| 1eb6968265 | |||
| 6ada8e2cef | |||
| f3b4aa6b8c | |||
| eb42b77285 | |||
| 8657d0a377 | |||
| c07d248bc3 | |||
| dafed93c63 | |||
| e7bcb2c15e | |||
| f9ab227459 | |||
| e6808b6f2e | |||
| 79632dd3c6 | |||
| a4a1ef7294 | |||
| 8f2a3a4d7d | |||
| 21a597a85e | |||
| 1c90c1ec44 | |||
| 30ea676367 | |||
| ed104dd2c1 | |||
| a3486b4dd2 | |||
| 212e4f07af | |||
| 92dbaad9db | |||
| 388c66b41e | |||
| 125ff0dcea | |||
| ca923d089f | |||
| 7ad0b16d02 | |||
| 36c0eaf44b | |||
| 0b7da82433 | |||
| 3d7cc53317 | |||
| 1818911c5f | |||
| ce3fdd6e4b | |||
| c98d077d91 | |||
| bf83b9bfde | |||
| 2a103cf08e | |||
| 1d51b8e5e5 | |||
| befd4a23ee | |||
| ee538f707f | |||
| f113e775a1 | |||
| 063f03c764 | |||
| bbd0ba7626 | |||
| af4a989dc1 | |||
| 964e7387e3 | |||
| cd8fd9ace5 | |||
| fb4721bcb2 | |||
| 2dcc351532 | |||
| c497a583ca | |||
| 0a585dc3bb | |||
| 49c80ebe5c | |||
| 44fd6754d8 | |||
| 0831f7e392 | |||
| 1886bcda00 | |||
| 60b0221402 | |||
| 8062fadbd4 | |||
| 93ee3a3475 | |||
| dace71205f | |||
| 56e687d9cc | |||
| 3fba587044 | |||
| 2799aa2700 | |||
| 2c25b65b92 | |||
| b182ebdfd6 | |||
| b47bb64398 | |||
| 0f2bdf280f | |||
| 00c3422c1f | |||
| ad6c6bc8fd | |||
| 32ee950210 | |||
| 32e47bdda6 | |||
| c2504d2639 | |||
| 4f7b473a4a | |||
| 63dba7bb64 | |||
| a00db89f57 | |||
| c74ac37488 | |||
| 836c0c0d2e | |||
| a0847c22c7 | |||
| 96e4071e2d | |||
| 63e0c0ff49 | |||
| 4dda92e599 | |||
| d3d6459484 | |||
| 9eed3a8d77 | |||
| 5f0d6b4aef | |||
| d77e77f9f4 | |||
| 2c221883c1 | |||
| 2de933793d | |||
| b0a9c6ea4b | |||
| 104089179c | |||
| 928e5e0fbb | |||
| 603fc4b341 | |||
| 70b9305f2e | |||
| 8e04386c67 | |||
| cdce2f0ffd | |||
| b8f09bd758 | |||
| 29066c1a53 | |||
| 6a66c233f1 | |||
| ea58456534 | |||
| bef6aafa73 | |||
| 3fca5d99ee | |||
| fd014445fb | |||
| 5d4495785b | |||
| 1800ef0f10 | |||
| 3a553dc4f9 | |||
| 30858e0f2b | |||
| 0537bd6c36 | |||
| 171a14f542 | |||
| 88c2e9122e | |||
| 817c8e9dd3 | |||
| 8f110b59e7 | |||
| 6afb6f7071 | |||
| 250b3790dd | |||
| fac384d677 | |||
| 401400cbcd | |||
| 16592cae48 | |||
| 393434026a | |||
| d4a115df06 | |||
| df85b59de9 | |||
| bd3a7c1368 | |||
| c093fd484c | |||
| 788fe423e8 | |||
| d0b1191b2d | |||
| bc81a16eb4 | |||
| 193a789354 | |||
| 96f8b3a43b | |||
| 22f40741ee | |||
| e01063b3c4 |
@@ -58,7 +58,7 @@ jobs:
|
||||
logdir: /tmp/log/
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
done
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ github.job }}-Logs
|
||||
path: |
|
||||
|
||||
@@ -68,6 +68,12 @@ runs:
|
||||
testCommand: ${{ inputs.builddir }}/tests/Gui_tests_run --gtest_output=json:${{ inputs.reportdir }}gui_gtest_results.json
|
||||
testLogFile: ${{ inputs.reportdir }}gui_gtest_test_log.txt
|
||||
testName: Gui
|
||||
- name: C++ Qt tests
|
||||
id: qttests
|
||||
uses: ./.github/workflows/actions/runCPPTests/runQtTests
|
||||
with:
|
||||
builddir: ${{ inputs.builddir }}
|
||||
testLogFile: ${{ inputs.reportdir }}qt_ctest_log.txt
|
||||
- name: C++ Material tests
|
||||
id: material
|
||||
uses: ./.github/workflows/actions/runCPPTests/runSingleTest
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
name: runQtTests
|
||||
description: "Run all QtTest-based C++ tests (those labelled 'Qt' in CTest), generate log and report"
|
||||
|
||||
inputs:
|
||||
builddir:
|
||||
description: "Build directory containing CTestTestfile.cmake"
|
||||
required: true
|
||||
testLogFile:
|
||||
description: "Path for the command-line output of the tests"
|
||||
required: true
|
||||
outputs:
|
||||
reportText:
|
||||
description: "Report text"
|
||||
value: ${{ steps.report.outputs.reportText }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run Qt tests via CTest
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
BUILD_DIR: ${{ inputs.builddir }}
|
||||
TEST_LOG_FILE: ${{ inputs.testLogFile }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
ctest --test-dir "$BUILD_DIR" -L Qt --output-on-failure | tee -a "$TEST_LOG_FILE"
|
||||
- name: Parse test results
|
||||
if: always()
|
||||
id: report
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
TEST_LOG_FILE: ${{ inputs.testLogFile }}
|
||||
run: |
|
||||
result=$(grep -E "(Test #|tests passed|tests failed|Total Test time)" "$TEST_LOG_FILE" || true)
|
||||
if grep -qE "[1-9][0-9]* tests failed" "$TEST_LOG_FILE"
|
||||
then
|
||||
reportText="<details><summary>:fire: QtTest C++ tests failed</summary>\n"
|
||||
else
|
||||
reportText="<details><summary>:heavy_check_mark: QtTest C++ tests succeeded</summary>\n"
|
||||
fi
|
||||
reportText+="\n"
|
||||
reportText+="Results\n"
|
||||
reportText+="\n"
|
||||
reportText+='```\n'
|
||||
reportText+="$result\n"
|
||||
reportText+='```\n'
|
||||
reportText+="</details>\n"
|
||||
reportText+="\n"
|
||||
echo "reportText<<EOD" >> $GITHUB_OUTPUT
|
||||
echo -e "$reportText" >> $GITHUB_OUTPUT
|
||||
echo "EOD" >> $GITHUB_OUTPUT
|
||||
echo -e "$reportText"
|
||||
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# SPDX-FileNotice: Part of the FreeCAD project.
|
||||
|
||||
name: runSingleQtTest
|
||||
description: "Run a single QtTest-based C++ test executable, generate log and report"
|
||||
|
||||
inputs:
|
||||
testCommand:
|
||||
description: "Test executable path"
|
||||
required: true
|
||||
testLogFile:
|
||||
description: "Path for the command-line output of the tests"
|
||||
required: true
|
||||
testName:
|
||||
description: "A descriptive name for the test suite"
|
||||
required: true
|
||||
outputs:
|
||||
reportText:
|
||||
description: "Report text"
|
||||
value: ${{ steps.report.outputs.reportText }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run QtTest tests
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
QT_QPA_PLATFORM: offscreen
|
||||
TEST_COMMAND: ${{ inputs.testCommand }}
|
||||
TEST_LOG_FILE: ${{ inputs.testLogFile }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
$TEST_COMMAND | tee -a "$TEST_LOG_FILE"
|
||||
- name: Parse test results
|
||||
if: always()
|
||||
id: report
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
TEST_LOG_FILE: ${{ inputs.testLogFile }}
|
||||
TEST_NAME: ${{ inputs.testName }}
|
||||
run: |
|
||||
# This bonkers sed regex is to try to find the start and end of the QtTest output block, which is not really
|
||||
# designed to be machine-readable. Why did they have to choose asterisks?!?!
|
||||
result=$(sed -n '/^\*\*\*\*\*\*\*\*\* Start/,/^\*\*\*\*\*\*\*\*\* Finished/p' "$TEST_LOG_FILE" || true)
|
||||
if grep -qE "^FAIL!" "$TEST_LOG_FILE"
|
||||
then
|
||||
reportText="<details><summary>:fire: QtTest C++ test suite '${TEST_NAME}' failed</summary>\n"
|
||||
else
|
||||
reportText="<details><summary>:heavy_check_mark: QtTest C++ test suite '${TEST_NAME}' succeeded</summary>\n"
|
||||
fi
|
||||
reportText+="\n"
|
||||
reportText+="Results\n"
|
||||
reportText+="\n"
|
||||
reportText+='```\n'
|
||||
reportText+="$result\n"
|
||||
reportText+='```\n'
|
||||
reportText+="</details>\n"
|
||||
reportText+="\n"
|
||||
echo "reportText<<EOD" >> $GITHUB_OUTPUT
|
||||
echo -e "$reportText" >> $GITHUB_OUTPUT
|
||||
echo "EOD" >> $GITHUB_OUTPUT
|
||||
echo -e "$reportText"
|
||||
@@ -21,13 +21,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: '🧹 Tag & close stale unconfirmed bugs'
|
||||
id: stale_issues
|
||||
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
|
||||
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-issue-stale: 90
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
- name: '🧹 Close stale requested feedback issues'
|
||||
id: awaiting_issues
|
||||
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
|
||||
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-issue-stale: 20
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: '🧹 Tag & close inactive issues'
|
||||
id: inactive_issues
|
||||
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
|
||||
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-issue-stale: 190
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
|
||||
- name: '🧹 Tag & close inactive PRs'
|
||||
id: inactive_pr
|
||||
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
|
||||
uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-issue-stale: -1
|
||||
|
||||
@@ -28,12 +28,12 @@ jobs:
|
||||
)
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
token: ${{ secrets.GH_TOKEN_FOR_CI_RUNNERS }}
|
||||
|
||||
- name: Create backport pull requests
|
||||
uses: korthout/backport-action@d07416681cab29bf2661702f925f020aaa962997 # v3.4.1
|
||||
uses: korthout/backport-action@01619ebc9a6e3f6820274221b9956b3e7365000a # v4.1.0
|
||||
with:
|
||||
# Inputs documented here: https://github.com/korthout/backport-action?tab=readme-ov-file#inputs
|
||||
github_token: ${{ secrets.GH_TOKEN_FOR_CI_RUNNERS }}
|
||||
|
||||
@@ -10,6 +10,10 @@ permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: build-release-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
upload_src:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -17,19 +21,19 @@ jobs:
|
||||
build_tag: ${{ steps.get_tag.outputs.build_tag }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 2
|
||||
fetch-tags: true
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: get tag and create release if weekly
|
||||
- name: Get tag and create release if weekly
|
||||
id: get_tag
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
@@ -39,14 +43,17 @@ jobs:
|
||||
export BUILD_TAG="${{ github.event.release.tag_name }}"
|
||||
else
|
||||
export BUILD_TAG=weekly-$(date "+%Y.%m.%d")
|
||||
gh release create ${BUILD_TAG} --title "Development Build ${BUILD_TAG}" -F .github/workflows/weekly-build-notes.md --prerelease || true
|
||||
gh release create ${BUILD_TAG} --title "Development Build ${BUILD_TAG}" \
|
||||
-F .github/workflows/weekly-build-notes.md \
|
||||
--prerelease || \
|
||||
gh release view ${BUILD_TAG} > /dev/null # fail if it doesn't exist
|
||||
fi
|
||||
echo "BUILD_TAG=${BUILD_TAG}" >> "$GITHUB_ENV"
|
||||
echo "build_tag=${BUILD_TAG}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Trigger notes updater workflow (only for weekly)
|
||||
if: startsWith(steps.get_tag.outputs.build_tag, 'weekly-')
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
WEEKLY_TAG: ${{ steps.get_tag.outputs.build_tag }}
|
||||
with:
|
||||
@@ -95,8 +102,9 @@ jobs:
|
||||
include:
|
||||
- { target: linux-64, os: ubuntu-22.04 }
|
||||
- { target: linux-arm64, os: ubuntu-22.04-arm }
|
||||
- { target: osx-64, os: macos-15-intel }
|
||||
- { target: osx-arm64, os: macos-latest }
|
||||
- { target: osx-64, os: macos-15-intel, deploy_target: "10.13" }
|
||||
- { target: osx-arm64, os: macos-latest, deploy_target: "11.0" }
|
||||
- { target: osx-arm64, os: macos-latest, deploy_target: "15.0" }
|
||||
- { target: win-64, os: windows-latest }
|
||||
fail-fast: false
|
||||
|
||||
@@ -104,7 +112,7 @@ jobs:
|
||||
environment: weekly-build
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -117,7 +125,7 @@ jobs:
|
||||
remove-android: 'true' # (frees ~9 GB)
|
||||
remove-cached-tools: 'true' # (frees ~8.3 GB)
|
||||
|
||||
- name: Set Platform Environment Variables
|
||||
- name: Set platform environment variables
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
OPERATING_SYSTEM: ${{ runner.os }}
|
||||
@@ -127,21 +135,21 @@ jobs:
|
||||
echo 'RATTLER_CACHE_DIR=D:\rattler' >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 2
|
||||
fetch-tags: true
|
||||
submodules: 'recursive'
|
||||
|
||||
- uses: prefix-dev/setup-pixi@82d477f15f3a381dbcc8adc1206ce643fe110fb7 # v0.9.3
|
||||
- uses: prefix-dev/setup-pixi@a0af7a228712d6121d37aba47adf55c1332c9c2e # v0.9.4
|
||||
with:
|
||||
pixi-version: v0.59.0
|
||||
cache: false
|
||||
|
||||
- name: Install the Apple certificate and provisioning profile
|
||||
id: get_cert
|
||||
id: macos_get_cert
|
||||
if: runner.os == 'macOS'
|
||||
env:
|
||||
APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }}
|
||||
@@ -149,7 +157,6 @@ jobs:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
|
||||
DEVELOPER_TEAM_ID: ${{ secrets.DEVELOPER_TEAM_ID }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
||||
run: |
|
||||
if [ -z "$BUILD_CERTIFICATE_BASE64" ]; then
|
||||
@@ -185,20 +192,81 @@ jobs:
|
||||
|
||||
xcrun notarytool store-credentials "FreeCAD" --keychain "$KEYCHAIN_PATH" --apple-id "${APPLE_ID}" --password "${APP_SPECIFIC_PASSWORD}" --team-id "${DEVELOPER_TEAM_ID}"
|
||||
|
||||
- name: Build and Release Packages
|
||||
- name: Setup .NET 10 SDK
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
|
||||
with:
|
||||
dotnet-version: '10.0.103'
|
||||
|
||||
- name: Install sign tool
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
# NOTE: The sign tool is ONLY available as a prerelease package, they never issue real releases.
|
||||
dotnet tool install --global --prerelease sign
|
||||
echo "$env:USERPROFILE\.dotnet\tools" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
dotnet --info
|
||||
sign --version
|
||||
|
||||
- name: Build packages
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TARGET_PLATFORM: ${{ matrix.target }}
|
||||
BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "${{ runner.os }}" == "macOS" ]]; then
|
||||
export MACOS_DEPLOYMENT_TARGET="${{ matrix.deploy_target }}"
|
||||
fi
|
||||
python3 package/scripts/write_version_info.py ../freecad_version.txt
|
||||
cd package/rattler-build
|
||||
pixi install
|
||||
|
||||
- name: Azure login for Windows build code signing
|
||||
id: azure_login
|
||||
if: runner.os == 'Windows'
|
||||
continue-on-error: true
|
||||
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
|
||||
with:
|
||||
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
|
||||
|
||||
- name: Release packages with optional code-signing on Windows and macOS
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
|
||||
SIGN_RELEASE: ${{ steps.get_cert.outputs.has_cert }}
|
||||
TARGET_PLATFORM: ${{ matrix.target }}
|
||||
MAKE_INSTALLER: "true"
|
||||
UPLOAD_RELEASE: "true"
|
||||
BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }}
|
||||
run: |
|
||||
python3 package/scripts/write_version_info.py ../freecad_version.txt
|
||||
set -euo pipefail
|
||||
|
||||
export MACOS_SIGN_RELEASE=0
|
||||
export WINDOWS_SIGN_RELEASE=0
|
||||
|
||||
case "${RUNNER_OS}" in
|
||||
Windows)
|
||||
export WINDOWS_SIGN_RELEASE="${{ steps.azure_login.outcome }}"
|
||||
export WINDOWS_AZURE_ENDPOINT="${{ vars.AZURE_TRUSTED_SIGNING_ENDPOINT }}"
|
||||
export WINDOWS_AZURE_CERTIFICATE_PROFILE="${{ vars.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}"
|
||||
export WINDOWS_AZURE_SIGNING_ACCOUNT="${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT }}"
|
||||
|
||||
# For good measure, normalize the azure_login result to 1 or 0
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-}" == "success" ]]; then
|
||||
export WINDOWS_SIGN_RELEASE=1
|
||||
else
|
||||
export WINDOWS_SIGN_RELEASE=0
|
||||
fi
|
||||
;;
|
||||
|
||||
macOS)
|
||||
export MACOS_SIGN_RELEASE="${{ steps.macos_get_cert.outputs.has_cert }}"
|
||||
export MACOS_SIGNING_KEY_ID="${{ secrets.SIGNING_KEY_ID }}"
|
||||
export MACOS_DEPLOYMENT_TARGET="${{ matrix.deploy_target }}"
|
||||
;;
|
||||
esac
|
||||
|
||||
cd package/rattler-build
|
||||
pixi install
|
||||
pixi run -e package create_bundle
|
||||
|
||||
## Needed if running on a self-hosted runner:
|
||||
|
||||
@@ -64,12 +64,12 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
submodules: recursive
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
remove-docker-images: 'true' # (frees ~3.2 GB)
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
submodules: recursive
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
sarif_file: sarif-results/cpp.sarif
|
||||
|
||||
- name: Upload loc as a Build Artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7.0.0
|
||||
with:
|
||||
name: sarif-results
|
||||
path: sarif-results
|
||||
|
||||
@@ -17,11 +17,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4
|
||||
uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
copr_url = https://copr.fedorainfracloud.org
|
||||
" > ~/.config/copr
|
||||
- name: checkout sources
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 500
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GH_TOKEN_FOR_CROWDIN_SYNC }}
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
arch: "linux_gcc_64"
|
||||
|
||||
- name: Setup Python & dependencies
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Install Python packages
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
git push origin update-crowdin-translations --force
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
|
||||
with:
|
||||
branch: update-crowdin-translations
|
||||
title: "Update translations from Crowdin"
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
echo "last_month=$first_day..$last_day" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Run issue-metrics tool
|
||||
uses: github/issue-metrics@67526e7bd8100b870f10b1c120780a8375777b43 # v3.25.5
|
||||
uses: github/issue-metrics@6a35322ff89cee3e1a594d282c27eb34bffa9174 # v4.1.1
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SEARCH_QUERY: 'repo:FreeCAD/FreeCAD is:issue created:${{ env.last_month }}'
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: releases/FreeCAD-1-1
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
arch: "linux_gcc_64"
|
||||
|
||||
- name: Setup Python & dependencies
|
||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Install Python packages
|
||||
|
||||
@@ -36,12 +36,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Add GCC Problem Matcher
|
||||
if: runner.os == 'Linux'
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
mkdir -p ${{ env.reportdir }}
|
||||
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: prefix-dev/setup-pixi@82d477f15f3a381dbcc8adc1206ce643fe110fb7 # v0.9.3
|
||||
- uses: prefix-dev/setup-pixi@a0af7a228712d6121d37aba47adf55c1332c9c2e # v0.9.4
|
||||
with:
|
||||
pixi-version: v0.59.0
|
||||
cache: false
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
- name: Restore Compiler Cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
@@ -209,14 +209,14 @@ jobs:
|
||||
- name: Save Compiler Cache
|
||||
id: cache-save
|
||||
if: always()
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifactBasename }}-${{ matrix.os }}-Logs
|
||||
path: |
|
||||
@@ -225,7 +225,7 @@ jobs:
|
||||
|
||||
- name: Upload report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ env.reportfilename }}
|
||||
path: |
|
||||
|
||||
@@ -77,12 +77,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checking out source code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
- name: Restore Compiler Cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
ccache -p
|
||||
|
||||
- name: Install cmake
|
||||
uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be # v2.0.2
|
||||
uses: jwlawson/actions-setup-cmake@3a6cbe35ba64df7ca70c51365c4aff65db9a9037 # v2.1.1
|
||||
with:
|
||||
cmake-version: '3.31.6'
|
||||
|
||||
@@ -216,14 +216,14 @@ jobs:
|
||||
- name: Save Compiler Cache
|
||||
id: cache-save
|
||||
if: always()
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifactBasename }}-Logs
|
||||
path: |
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
|
||||
- name: Upload report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ env.reportfilename }}
|
||||
path: |
|
||||
|
||||
@@ -24,15 +24,27 @@
|
||||
|
||||
name: Build Windows
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
artifactBasename:
|
||||
description: "Base name for artifact"
|
||||
required: false
|
||||
type: string
|
||||
default: "FreeCAD"
|
||||
allowedToFail:
|
||||
description: "whether a failed build is allowed"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
workflow_call:
|
||||
inputs:
|
||||
artifactBasename:
|
||||
type: string
|
||||
required: true
|
||||
type: string
|
||||
allowedToFail:
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
required: false
|
||||
outputs:
|
||||
reportFile:
|
||||
value: ${{ jobs.Build.outputs.reportFile }}
|
||||
@@ -66,12 +78,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checking out source code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -99,7 +111,7 @@ jobs:
|
||||
- name: Restore compiler cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
@@ -114,7 +126,7 @@ jobs:
|
||||
. $env:ccachebindir\ccache -p
|
||||
|
||||
- name: Install cmake
|
||||
uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be # v2.0.2
|
||||
uses: jwlawson/actions-setup-cmake@3a6cbe35ba64df7ca70c51365c4aff65db9a9037 # v2.1.1
|
||||
with:
|
||||
cmake-version: '3.31.6'
|
||||
|
||||
@@ -157,14 +169,14 @@ jobs:
|
||||
- name: Save Compiler Cache
|
||||
id: cache-save
|
||||
if: always()
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifactBasename }}-Logs
|
||||
path: |
|
||||
|
||||
@@ -198,12 +198,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -355,7 +355,7 @@ jobs:
|
||||
|
||||
- name: Upload logs and fixes
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifactBasename }}-Logs
|
||||
path: |
|
||||
@@ -364,7 +364,7 @@ jobs:
|
||||
|
||||
- name: Upload report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ env.reportfilename }}
|
||||
path: |
|
||||
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
touch ${{ env.logdir }}changedFiles.lst ${{ env.logdir }}changedCppFiles.lst ${{ env.logdir }}changedPythonFiles.lst
|
||||
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
|
||||
- name: Check out code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Determine base and head SHA in case of PR
|
||||
@@ -180,14 +180,14 @@ jobs:
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ inputs.artifactBasename }}-Logs
|
||||
path: |
|
||||
${{ env.logdir }}
|
||||
- name: Upload report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: ${{ env.reportfilename }}
|
||||
path: |
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2 # v2.13.3
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p ${{ env.artifactsDownloadDir }}
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
path: ${{ env.artifactsDownloadDir }}
|
||||
- name: Save input data to file
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
cat report.md >> $GITHUB_STEP_SUMMARY
|
||||
- name: Delete used artifacts
|
||||
continue-on-error: true
|
||||
uses: geekyeggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b # v5.1.0
|
||||
uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0
|
||||
with:
|
||||
name: |
|
||||
${{ env.usedArtifacts }}
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Inject compare link into weekly release notes
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
# Pass manual inputs via env for convenience
|
||||
CURRENT_TAG: ${{ github.event.inputs.current_tag }}
|
||||
|
||||
+29
-28
@@ -1,59 +1,60 @@
|
||||
# file types to ignore
|
||||
.*
|
||||
!/.packit.yaml
|
||||
!*.gitattributes
|
||||
!*.gitignore
|
||||
!/.clang-format
|
||||
!/.clang-tidy
|
||||
!/.git-blame-ignore-revs
|
||||
!/.gitattributes
|
||||
!/.github/
|
||||
!/.gitignore
|
||||
!/.gitmodules
|
||||
!/.packit.yaml
|
||||
!/.pre-commit-config.yaml
|
||||
!/.pylintrc
|
||||
!/.github/
|
||||
!/contrib/.vscode/
|
||||
!*.gitattributes
|
||||
!*.gitignore
|
||||
*.clangd
|
||||
*.DS_Store
|
||||
*.pyc
|
||||
*.obj
|
||||
*.lib
|
||||
*.pch
|
||||
*.vcproj
|
||||
*.kdev4
|
||||
*.exp
|
||||
*.dep
|
||||
*.exp
|
||||
*.kdev4
|
||||
*.lib
|
||||
*.manifest
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.output
|
||||
*.pch
|
||||
*.pyc
|
||||
*.vcproj
|
||||
# Ignore .db files created by Qt Designer when editing .ui files
|
||||
*.db
|
||||
qrc_*.cpp
|
||||
BuildLog.htm
|
||||
cmake_install.cmake
|
||||
*~
|
||||
CMakeFiles/
|
||||
*qrc.depends
|
||||
ui_*.h
|
||||
moc_*.cpp
|
||||
Makefile
|
||||
*~
|
||||
BuildLog.htm
|
||||
CMakeCache.txt
|
||||
CMakeFiles/
|
||||
CMakeLists.txt.user
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
config.h
|
||||
install_manifest.txt
|
||||
/bin/
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
/.vscode/
|
||||
/ALL_BUILD.dir/
|
||||
/doc/
|
||||
/lib/
|
||||
/Mod/
|
||||
/ZERO_CHECK.dir/
|
||||
/build/
|
||||
/bin/
|
||||
/build-*/
|
||||
/build/
|
||||
/cmake-build*/
|
||||
/src/Tools/offlinedoc/localwiki/
|
||||
/src/Tools/offlinedoc/*.txt
|
||||
/conda/environment.yml
|
||||
/.vscode/
|
||||
/doc/
|
||||
/lib/
|
||||
/src/Tools/offlinedoc/*.txt
|
||||
/src/Tools/offlinedoc/localwiki/
|
||||
OpenSCAD_rc.py
|
||||
tags
|
||||
/CMakeUserPresets.json
|
||||
@@ -63,10 +64,10 @@ compile_commands.json
|
||||
*.sublime-workspace
|
||||
|
||||
# crowdin file
|
||||
files_to_translate.txt
|
||||
src/Tools/freecad.zip
|
||||
tsupdate_stderr.log
|
||||
tsupdate_stdout.log
|
||||
files_to_translate.txt
|
||||
# pixi environments
|
||||
.pixi
|
||||
*.egg-info
|
||||
.pixi
|
||||
|
||||
@@ -46,6 +46,7 @@ exclude: |
|
||||
src/App/ExpressionParser.tab.h|
|
||||
src/App/ExpressionParser.y|
|
||||
src/App/lex.ExpressionParser.c|
|
||||
src/Doc/ThirdPartyLibraries.html.cmake|
|
||||
src/Gui/3Dconnexion/navlib|
|
||||
src/Gui/QSint|
|
||||
src/Gui/Quarter|
|
||||
|
||||
@@ -398,7 +398,7 @@ indent-after-paren=4
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
max-line-length=120
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=1000
|
||||
|
||||
+5
-2
@@ -95,8 +95,11 @@ if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER OR FREECAD_LIB
|
||||
endif(BUILD_GUI)
|
||||
SetupSalomeSMESH()
|
||||
if (BUILD_FEM_NETGEN)
|
||||
find_package(NETGEN)
|
||||
endif(BUILD_FEM_NETGEN)
|
||||
set(NETGEN_DEFINITIONS -DNO_PARALLEL_THREADS -DOCCGEOMETRY)
|
||||
if (NOT FREECAD_USE_EXTERNAL_SMESH)
|
||||
find_package(NETGEN REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
# not needed at the moment
|
||||
#find_package(OpenCV REQUIRED)
|
||||
SetupSwig()
|
||||
|
||||
+3
-1
@@ -62,7 +62,9 @@ The FreeCAD Contribution Process is expressed here with the following specific g
|
||||
1. the PR description MUST contain proper attribution as the first line, for example: "This is work of XYZ cherry-picked from <link>";
|
||||
2. all commits MUST have proper authorship, i.e. be authored by the original author and committed by the author of the PR;
|
||||
3. if changes to cherry-picked commits are necessary they SHOULD be done as follow-up commits. If it is not possible to do so, then the modified commits MUST contain a `Co-Authored-By` trailer in their commit message.
|
||||
14. A “Valid PR” is one which satisfies the above requirements.
|
||||
14. Contributions must meet existing quality standards. Raw AI output is not accepted under any circumstances. AI may be used only as an assistive tool; in all cases, the resulting content must be reviewed, validated, and justifiable by the contributor. The contributor should be able to explain design and code decisions, answer reviewers’ questions, and ensure that AI use does not waste reviewers’ time during review. That being said, the use of AI is not recommended under any circumstances or in any manner.
|
||||
15. The contributor provides reasonable assurance that the contribution does not infringe third-party copyrights or license terms.
|
||||
16. A “Valid PR” is one which satisfies the above requirements.
|
||||
|
||||
## 6. Process
|
||||
|
||||
|
||||
@@ -56,14 +56,8 @@ Other options are described on the [wiki Download page](https://wiki.freecad.org
|
||||
Compiling
|
||||
---------
|
||||
|
||||
FreeCAD requires several dependencies to correctly compile for development and
|
||||
production builds. The following pages contain updated build instructions for
|
||||
their respective platforms:
|
||||
|
||||
- [Linux](https://wiki.freecad.org/Compile_on_Linux)
|
||||
- [Windows](https://wiki.freecad.org/Compile_on_Windows)
|
||||
- [macOS](https://wiki.freecad.org/Compile_on_MacOS)
|
||||
- [MinGW](https://wiki.freecad.org/Compile_on_MinGW)
|
||||
See the [Developers Handbook – Getting Started](https://freecad.github.io/DevelopersHandbook/gettingstarted/)
|
||||
for build instructions.
|
||||
|
||||
|
||||
Reporting Issues
|
||||
|
||||
@@ -13,19 +13,15 @@
|
||||
# See also: http://git.salome-platform.org/gitweb/?p=NETGENPLUGIN_SRC.git;a=summary
|
||||
|
||||
|
||||
find_package(Netgen CONFIG)
|
||||
find_package(Netgen CONFIG QUIET)
|
||||
IF (Netgen_FOUND)
|
||||
set(NGLIB_INCLUDE_DIR ${NETGEN_INCLUDE_DIRS})
|
||||
set(NGLIB_LIBRARIES nglib)
|
||||
set(NETGEN_DEFINITIONS -DNO_PARALLEL_THREADS -DOCCGEOMETRY)
|
||||
# for external smesh only the following two variables are needed:
|
||||
set(NETGEN_FOUND True)
|
||||
set(NETGEN_INCLUDE_DIRS ${NETGEN_INCLUDE_DIRS})
|
||||
|
||||
ELSE ()
|
||||
|
||||
SET(NETGEN_DEFINITIONS -DNO_PARALLEL_THREADS -DOCCGEOMETRY)
|
||||
|
||||
IF (WIN32)
|
||||
FIND_PATH(NGLIB_INCLUDE_DIR NAMES nglib.h PATHS ${NETGEN_INCLUDEDIR})
|
||||
SET(NETGEN_LIBS nglib mesh occ interface)
|
||||
@@ -147,3 +143,8 @@ IF (Netgen_FOUND)
|
||||
MESSAGE(STATUS "Found NETGEN version ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}, calculated: ${NETGEN_VERSION_C}")
|
||||
LIST(APPEND NETGEN_DEFINITIONS -DNETGEN_VERSION=${NETGEN_VERSION_C})
|
||||
ENDIF ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(NETGEN
|
||||
REQUIRED_VARS NGLIB_INCLUDE_DIR NGLIB_LIBRARIES NETGEN_INCLUDE_DIRS
|
||||
VERSION_VAR NETGEN_VERSION)
|
||||
|
||||
+41
-9
@@ -1,7 +1,11 @@
|
||||
# The Qt for Python project officially recommends using pip to install PySide, so we expect to find PySide in the
|
||||
# site-packages directory. The library will be called "PySide6.abi3.*", and there will be an "include" directory inside
|
||||
# the site-packages/PySide6. Over time some distros may provide custom versions, so we also support using a more normal
|
||||
# cMake find_package() call
|
||||
# The Qt for Python project officially recommends using pip to install PySide,
|
||||
# so we expect to find PySide in the site-packages directory.
|
||||
# The library will be called "PySide6.abi3.*", and there will
|
||||
# be an "include" directory inside the site-packages/PySide6.
|
||||
# Over time some distros may provide custom versions, so we also support
|
||||
# using a more normal cMake find_package() call
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package(PySide6 CONFIG QUIET)
|
||||
|
||||
@@ -9,12 +13,40 @@ if(NOT PySide6_FOUND)
|
||||
find_pip_package(PySide6)
|
||||
endif()
|
||||
|
||||
if(NOT PySide6_INCLUDE_DIRS AND TARGET PySide6::pyside6)
|
||||
get_property(PySide6_INCLUDE_DIRS TARGET PySide6::pyside6 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
if(PySide6_FOUND)
|
||||
# verify PySide6 version matches Qt6 version (major.minor)
|
||||
if(PySide6_VERSION AND Qt6_VERSION)
|
||||
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" _qt6_major_minor "${Qt6_VERSION}")
|
||||
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" _pyside6_major_minor "${PySide6_VERSION}")
|
||||
|
||||
# Also provide the old-style variables so we don't have to update everything yet
|
||||
if (PySide6_FOUND)
|
||||
message(STATUS "Qt version: ${Qt6_VERSION}")
|
||||
message(STATUS "PySide version: ${PySide6_VERSION}")
|
||||
|
||||
if(NOT _qt6_major_minor STREQUAL _pyside6_major_minor)
|
||||
message(FATAL_ERROR
|
||||
" --------------------------------------------------------
|
||||
Qt/PySide version mismatch!
|
||||
cmake found Qt: ${Qt6_VERSION}
|
||||
cmake found PySide: ${PySide6_VERSION}
|
||||
major.minor versions of Qt and PySide must match to avoid errors.
|
||||
Ensure CMAKE_PREFIX_PATH points to matching Qt and PySide6 installations.
|
||||
--------------------------------------------------------"
|
||||
)
|
||||
endif()
|
||||
|
||||
message(STATUS "PySide/Qt version check passed (${_pyside6_major_minor})")
|
||||
endif()
|
||||
|
||||
if(NOT PySide6_INCLUDE_DIRS AND TARGET PySide6::pyside6)
|
||||
get_property(PySide6_INCLUDE_DIRS TARGET PySide6::pyside6 PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(PySide6
|
||||
REQUIRED_VARS PySide6_INCLUDE_DIRS
|
||||
VERSION_VAR PySide6_VERSION
|
||||
)
|
||||
|
||||
# Also provide the old-style variables so we don't have to update everything yet
|
||||
set(PYSIDE_INCLUDE_DIR ${PySide6_INCLUDE_DIRS})
|
||||
set(PYSIDE_LIBRARY ${PySide6_LIBRARIES})
|
||||
set(PYSIDE_FOUND TRUE)
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
# PYSIDE_RCC_EXECUTABLE - Location of PYSIDE6RCC executable
|
||||
# PYSIDE_TOOLS_FOUND - PYSIDE6 utilities found.
|
||||
|
||||
if (TARGET Qt6::uic)
|
||||
if(TARGET Qt6::uic)
|
||||
get_target_property(PYSIDE6_UIC_EXECUTABLE Qt6::uic LOCATION)
|
||||
set(UICOPTIONS "--generator=python")
|
||||
endif()
|
||||
if (TARGET Qt6::rcc)
|
||||
if(TARGET Qt6::rcc)
|
||||
get_target_property(PYSIDE6_RCC_EXECUTABLE Qt6::rcc LOCATION)
|
||||
set(RCCOPTIONS "--generator=python" "--compress-algo=zlib" "--compress=1")
|
||||
endif()
|
||||
@@ -18,15 +18,15 @@ set(PySideTools_VERSION 6)
|
||||
|
||||
if(PYSIDE_RCC_EXECUTABLE AND PYSIDE_UIC_EXECUTABLE)
|
||||
set(PYSIDE_TOOLS_FOUND TRUE)
|
||||
if (NOT PYSIDE6Tools_FIND_QUIETLY)
|
||||
if(NOT PYSIDE6Tools_FIND_QUIETLY)
|
||||
message(STATUS "Found PYSIDE6 tools: ${PYSIDE_UIC_EXECUTABLE}, ${PYSIDE_RCC_EXECUTABLE}")
|
||||
endif ()
|
||||
endif()
|
||||
else()
|
||||
if(PYSIDE6Tools_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "PYSIDE6 tools could not be found, but are required.")
|
||||
else()
|
||||
if (NOT PYSIDE6Tools_FIND_QUIETLY)
|
||||
if(NOT PYSIDE6Tools_FIND_QUIETLY)
|
||||
message(STATUS "PYSIDE6 tools: not found.")
|
||||
endif ()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -10,14 +10,14 @@ if(NOT Shiboken6_FOUND)
|
||||
endif()
|
||||
if(NOT Shiboken6_INCLUDE_DIR)
|
||||
find_pip_package(Shiboken6)
|
||||
if (Shiboken6_FOUND)
|
||||
if(Shiboken6_FOUND)
|
||||
set(SHIBOKEN_LIBRARY ${Shiboken6_LIBRARIES})
|
||||
set(SHIBOKEN_MAJOR_VERSION 6)
|
||||
set(SHIBOKEN_FOUND ON)
|
||||
endif()
|
||||
# The include directory we actually want is part of shiboken6-generator
|
||||
find_pip_package(shiboken6_generator)
|
||||
if (shiboken6_generator_FOUND)
|
||||
if(shiboken6_generator_FOUND)
|
||||
set(SHIBOKEN_INCLUDE_DIR ${shiboken6_generator_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -7,6 +7,22 @@ macro(SetupFreetype)
|
||||
message("===============================================================\n"
|
||||
"FreeType2 not found. Part module will lack of makeWireString().\n"
|
||||
"===============================================================\n")
|
||||
else()
|
||||
# find_package(harfbuzz CONFIG) fails on windows
|
||||
# lets do it the complicated way instead.
|
||||
find_path(HARFBUZZ_INCLUDE_DIR hb.h PATH_SUFFIXES harfbuzz)
|
||||
find_library(HARFBUZZ_LIBRARY NAMES harfbuzz)
|
||||
if(HARFBUZZ_INCLUDE_DIR AND HARFBUZZ_LIBRARY)
|
||||
if(NOT TARGET harfbuzz::harfbuzz)
|
||||
add_library(harfbuzz::harfbuzz UNKNOWN IMPORTED)
|
||||
set_target_properties(harfbuzz::harfbuzz PROPERTIES
|
||||
IMPORTED_LOCATION "${HARFBUZZ_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${HARFBUZZ_INCLUDE_DIR}"
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "HarfBuzz not found")
|
||||
endif()
|
||||
endif(NOT FREETYPE_FOUND)
|
||||
endif(FREECAD_USE_FREETYPE)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ macro(SetupShibokenAndPyside)
|
||||
if(DEFINED MACPORTS_PREFIX)
|
||||
find_package(Shiboken REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
|
||||
find_package(PySide REQUIRED HINTS "${PYTHON_LIBRARY_DIR}/cmake")
|
||||
endif(DEFINED MACPORTS_PREFIX)
|
||||
endif()
|
||||
|
||||
if(FREECAD_QT_MAJOR_VERSION EQUAL 5)
|
||||
set(SHIBOKEN_MAJOR_VERSION 2)
|
||||
@@ -21,16 +21,16 @@ macro(SetupShibokenAndPyside)
|
||||
# Shiboken2Config.cmake may explicitly set CMAKE_BUILD_TYPE to Release which causes
|
||||
# CMake to fail to create Makefiles for a debug build.
|
||||
# So as a workaround we save and restore the value after checking for Shiboken2.
|
||||
set (SAVE_BUILD_TYPE ${CMAKE_BUILD_TYPE})
|
||||
set(SAVE_BUILD_TYPE ${CMAKE_BUILD_TYPE})
|
||||
find_package(Shiboken${SHIBOKEN_MAJOR_VERSION} QUIET)
|
||||
set (CMAKE_BUILD_TYPE ${SAVE_BUILD_TYPE})
|
||||
if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
|
||||
set(CMAKE_BUILD_TYPE ${SAVE_BUILD_TYPE})
|
||||
if(Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
|
||||
# Shiboken config file was found but it may use the wrong Python version
|
||||
# Try to get the matching config suffix and repeat finding the package
|
||||
set(SHIBOKEN_PATTERN .cpython-${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
|
||||
|
||||
file(GLOB SHIBOKEN_CONFIG "${Shiboken${SHIBOKEN_MAJOR_VERSION}_DIR}/Shiboken${SHIBOKEN_MAJOR_VERSION}Config${SHIBOKEN_PATTERN}*.cmake")
|
||||
if (SHIBOKEN_CONFIG)
|
||||
if(SHIBOKEN_CONFIG)
|
||||
get_filename_component(SHIBOKEN_CONFIG_SUFFIX ${SHIBOKEN_CONFIG} NAME)
|
||||
string(SUBSTRING ${SHIBOKEN_CONFIG_SUFFIX} 15 -1 SHIBOKEN_CONFIG_SUFFIX)
|
||||
string(REPLACE ".cmake" "" PYTHON_CONFIG_SUFFIX ${SHIBOKEN_CONFIG_SUFFIX})
|
||||
@@ -47,11 +47,11 @@ macro(SetupShibokenAndPyside)
|
||||
# to dance to be compatible with the old (<5.12) and the new versions (>=5.12)
|
||||
if(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken)
|
||||
get_property(SHIBOKEN_INCLUDE_DIR TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif(NOT SHIBOKEN_INCLUDE_DIR AND TARGET Shiboken${SHIBOKEN_MAJOR_VERSION}::libshiboken)
|
||||
endif()
|
||||
|
||||
if(NOT SHIBOKEN_INCLUDE_DIR)
|
||||
find_pip_package(Shiboken${SHIBOKEN_MAJOR_VERSION})
|
||||
if (Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
|
||||
if(Shiboken${SHIBOKEN_MAJOR_VERSION}_FOUND)
|
||||
set(SHIBOKEN_INCLUDE_DIR ${Shiboken${SHIBOKEN_MAJOR_VERSION}_INCLUDE_DIRS})
|
||||
set(SHIBOKEN_LIBRARY ${Shiboken${SHIBOKEN_MAJOR_VERSION}_LIBRARIES})
|
||||
endif()
|
||||
@@ -63,11 +63,11 @@ macro(SetupShibokenAndPyside)
|
||||
# Our internal FindPySide6.cmake file already provides these for PySide6
|
||||
if(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION})
|
||||
get_property(PYSIDE_INCLUDE_DIR TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION} PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif(NOT PYSIDE_INCLUDE_DIR AND TARGET PySide${PYSIDE_MAJOR_VERSION}::pyside${PYSIDE_MAJOR_VERSION})
|
||||
endif()
|
||||
|
||||
if(NOT PYSIDE_INCLUDE_DIR)
|
||||
find_pip_package(PySide${PYSIDE_MAJOR_VERSION})
|
||||
if (PySide${PYSIDE_MAJOR_VERSION}_FOUND)
|
||||
if(PySide${PYSIDE_MAJOR_VERSION}_FOUND)
|
||||
set(PYSIDE_INCLUDE_DIR ${PySide${PYSIDE_MAJOR_VERSION}_INCLUDE_DIRS})
|
||||
set(PYSIDE_LIBRARY ${PySide${PYSIDE_MAJOR_VERSION}_LIBRARIES})
|
||||
endif()
|
||||
@@ -175,22 +175,22 @@ macro(SetupShibokenAndPyside)
|
||||
message(STATUS "PySide ${PySide_VERSION} Python module found at ${PRINT_OUTPUT}.\n")
|
||||
endif()
|
||||
|
||||
endmacro(SetupShibokenAndPyside)
|
||||
endmacro()
|
||||
|
||||
|
||||
MACRO(PYSIDE_WRAP_RC outfiles)
|
||||
if (NOT PYSIDE_RCC_EXECUTABLE)
|
||||
macro(PYSIDE_WRAP_RC outfiles)
|
||||
if(NOT PYSIDE_RCC_EXECUTABLE)
|
||||
message(FATAL_ERROR "Qt rcc is required for generating ${ARGN}")
|
||||
endif()
|
||||
FOREACH(it ${ARGN})
|
||||
GET_FILENAME_COMPONENT(outfile ${it} NAME_WE)
|
||||
GET_FILENAME_COMPONENT(infile ${it} ABSOLUTE)
|
||||
SET(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py")
|
||||
foreach(it ${ARGN})
|
||||
get_filename_component(outfile ${it} NAME_WE)
|
||||
get_filename_component(infile ${it} ABSOLUTE)
|
||||
set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}_rc.py")
|
||||
#ADD_CUSTOM_TARGET(${it} ALL
|
||||
# DEPENDS ${outfile}
|
||||
#)
|
||||
if(WIN32 OR APPLE)
|
||||
ADD_CUSTOM_COMMAND(OUTPUT ${outfile}
|
||||
add_custom_command(OUTPUT ${outfile}
|
||||
COMMAND ${PYSIDE_RCC_EXECUTABLE} ${RCCOPTIONS} ${infile} -o ${outfile}
|
||||
MAIN_DEPENDENCY ${infile}
|
||||
)
|
||||
@@ -198,7 +198,7 @@ MACRO(PYSIDE_WRAP_RC outfiles)
|
||||
# Especially on Open Build Service we don't want changing date like
|
||||
# pyside-rcc generates in comments at beginning, which is why
|
||||
# we follow the tool command with in-place sed.
|
||||
ADD_CUSTOM_COMMAND(OUTPUT "${outfile}"
|
||||
add_custom_command(OUTPUT "${outfile}"
|
||||
COMMAND "${PYSIDE_RCC_EXECUTABLE}" ${RCCOPTIONS} "${infile}" ${PY_ATTRIBUTE} -o "${outfile}"
|
||||
# The line below sometimes catches unwanted lines too - but there is no date in the file
|
||||
# anymore with Qt5 RCC, so commenting it out for now...
|
||||
@@ -207,5 +207,5 @@ MACRO(PYSIDE_WRAP_RC outfiles)
|
||||
)
|
||||
endif()
|
||||
list(APPEND ${outfiles} ${outfile})
|
||||
ENDFOREACH(it)
|
||||
ENDMACRO (PYSIDE_WRAP_RC)
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
Binary file not shown.
@@ -64,7 +64,8 @@ ${LangFileString} SecUnPreferencesDescription 'Deletes FreeCAD$\'s configuration
|
||||
$AppSuff\$\r$\n\
|
||||
${APP_DIR_USERDATA}$\")$\r$\n\
|
||||
for you or for all users (if you are admin).'
|
||||
${LangFileString} DialogUnPreferences 'You chose to delete the FreeCADs user configuration.$\r$\n\
|
||||
This will also delete all installed FreeCAD addons.$\r$\n\
|
||||
Do you agree with this?'
|
||||
${LangFileString} DialogUnPreferences 'You chose to delete the FreeCAD user configuration.$\r$\n\
|
||||
This will also delete all installed FreeCAD addons, and will affect the$\r$\n\
|
||||
preferences for all versions of FreeCAD.$\r$\n\
|
||||
Are you sure you want to proceed?'
|
||||
${LangFileString} SecUnProgramFilesDescription "Uninstall FreeCAD and all of its components."
|
||||
|
||||
@@ -57,8 +57,6 @@
|
||||
test: xvfb-run /usr/bin/FreeCAD -t TestPartGui
|
||||
/TestPartDesignGui :
|
||||
test: xvfb-run /usr/bin/FreeCAD -t TestPartDesignGui
|
||||
/TestSketcherGui :
|
||||
test: xvfb-run /usr/bin/FreeCAD -t TestSketcherGui
|
||||
/TestTechDrawGui :
|
||||
test: xvfb-run /usr/bin/FreeCAD -t TestTechDrawGui
|
||||
/Workbench :
|
||||
|
||||
@@ -8,7 +8,9 @@ if [[ ${HOST} =~ .*darwin.* ]]; then
|
||||
# add hacks for osx here!
|
||||
echo "adding hacks for osx"
|
||||
|
||||
# install space-mouse
|
||||
# Install 3DConnexion (SpaceMouse) driver
|
||||
# Note: For local builds, comment out the following lines if you encounter issues
|
||||
# installing the driver or don't need SpaceMouse support
|
||||
/usr/bin/curl -o /tmp/3dFW.dmg -L 'https://download.3dconnexion.com/drivers/mac/10-7-0_B564CC6A-6E81-42b0-82EC-418EA823B81A/3DxWareMac_v10-7-0_r3411.dmg'
|
||||
hdiutil attach -readonly /tmp/3dFW.dmg
|
||||
sudo installer -package /Volumes/3Dconnexion\ Software/Install\ 3Dconnexion\ software.pkg -target /
|
||||
@@ -17,6 +19,31 @@ if [[ ${HOST} =~ .*darwin.* ]]; then
|
||||
CMAKE_PLATFORM_FLAGS+=(-D3DCONNEXIONCLIENT_FRAMEWORK:FILEPATH="/Library/Frameworks/3DconnexionClient.framework")
|
||||
|
||||
CXXFLAGS="${CXXFLAGS} -D_LIBCPP_DISABLE_AVAILABILITY"
|
||||
|
||||
# Use MACOS_DEPLOYMENT_TARGET from environment, default to 11.0 for backwards compat.
|
||||
# Note that CI sets this per target: 10.13 (Intel), 11.0 (ARM legacy), 15.0 (ARM modern)
|
||||
# - macOS 10.13+ Intel: legacy QuickLook generator (.qlgenerator)
|
||||
# - macOS 11-14 ARM: legacy QuickLook generator (.qlgenerator)
|
||||
# - macOS 15+ ARM: modern QuickLook App Extensions (.appex)
|
||||
DEPLOY_TARGET="${MACOS_DEPLOYMENT_TARGET:-11.0}"
|
||||
CMAKE_PLATFORM_FLAGS+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOY_TARGET})
|
||||
|
||||
# Patch Qt6's FindWrapOpenGL.cmake to not link AGL on macOS 10.15+
|
||||
# AGL framework was removed in macOS 10.15 Catalina and Qt6's cmake
|
||||
# unconditionally tries to link it on Apple platforms, causing build failures.
|
||||
# Only apply this patch for deployment targets >= 10.15.
|
||||
# See: https://github.com/conda-forge/qt-main-feedstock/issues/240
|
||||
DEPLOY_MAJOR=$(echo "$DEPLOY_TARGET" | cut -d. -f1)
|
||||
DEPLOY_MINOR=$(echo "$DEPLOY_TARGET" | cut -d. -f2)
|
||||
if [[ "$DEPLOY_MAJOR" -gt 10 ]] || [[ "$DEPLOY_MAJOR" -eq 10 && "$DEPLOY_MINOR" -ge 15 ]]; then
|
||||
FIND_WRAP_OPENGL="$PREFIX/lib/cmake/Qt6/FindWrapOpenGL.cmake"
|
||||
if [[ -f "$FIND_WRAP_OPENGL" ]]; then
|
||||
echo "Patching Qt6 FindWrapOpenGL.cmake to remove AGL linkage (not available on macOS 10.15+)..."
|
||||
sed -i.bak \
|
||||
-e '/find_library(WrapOpenGL_AGL/,/target_link_libraries.*__opengl_agl_fw_path/d' \
|
||||
"$FIND_WRAP_OPENGL"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
unset CMAKE_GENERATOR
|
||||
@@ -24,6 +51,7 @@ unset CMAKE_GENERATOR_PLATFORM
|
||||
|
||||
cmake \
|
||||
${CMAKE_ARGS} \
|
||||
${CMAKE_PLATFORM_FLAGS[@]} \
|
||||
--preset ${CMAKE_PRESET} \
|
||||
-D CMAKE_IGNORE_PREFIX_PATH="/opt/homebrew;/usr/local/homebrew" \
|
||||
-D CMAKE_INCLUDE_PATH:FILEPATH="$PREFIX/include" \
|
||||
|
||||
@@ -31,4 +31,4 @@ else
|
||||
MAIN="$HERE/usr/bin/freecad"
|
||||
fi
|
||||
|
||||
"${MAIN}" "$@"
|
||||
exec "${MAIN}" "$@"
|
||||
|
||||
@@ -48,7 +48,11 @@ mkdir -p FreeCAD.app/Contents/MacOS
|
||||
cp build/FreeCAD FreeCAD.app/Contents/MacOS/FreeCAD
|
||||
|
||||
python_version=$(${conda_env}/bin/python -c 'import platform; print("py" + platform.python_version_tuple()[0] + platform.python_version_tuple()[1])')
|
||||
version_name="FreeCAD_${BUILD_TAG}-macOS-$(uname -m)-${python_version}"
|
||||
|
||||
# Add deployment target suffix to artifact name (e.g., "-macOS11" or "-macOS15")
|
||||
deploy_target="${MACOS_DEPLOYMENT_TARGET:-11.0}"
|
||||
deploy_suffix="-macOS${deploy_target%%.*}"
|
||||
version_name="FreeCAD_${BUILD_TAG}-macOS-$(uname -m)${deploy_suffix}-${python_version}"
|
||||
application_menu_name="FreeCAD_${BUILD_TAG}"
|
||||
|
||||
echo -e "\################"
|
||||
@@ -62,14 +66,37 @@ sed -i "s/APPLICATION_MENU_NAME/${application_menu_name}/" ${conda_env}/../Info.
|
||||
pixi list -e default > FreeCAD.app/Contents/packages.txt
|
||||
sed -i '1s/.*/\nLIST OF PACKAGES:/' FreeCAD.app/Contents/packages.txt
|
||||
|
||||
# copy the plugin into its final location
|
||||
cp -a ${conda_env}/Library ${conda_env}/..
|
||||
rm -rf ${conda_env}/Library
|
||||
# move plugins into their final location (Library only exists for macOS < 15.0 builds)
|
||||
if [ -d "${conda_env}/Library" ]; then
|
||||
mv ${conda_env}/Library ${conda_env}/..
|
||||
fi
|
||||
|
||||
if [[ "${SIGN_RELEASE}" == "true" ]]; then
|
||||
# move App Extensions (PlugIns) to the correct location for macOS registration
|
||||
if [ -d "${conda_env}/PlugIns" ]; then
|
||||
mv ${conda_env}/PlugIns ${conda_env}/..
|
||||
fi
|
||||
|
||||
if [[ "${MACOS_SIGN_RELEASE}" == "true" ]]; then
|
||||
# create the signed dmg
|
||||
../../scripts/macos_sign_and_notarize.zsh -p "FreeCAD" -k ${SIGNING_KEY_ID} -o "${version_name}.dmg"
|
||||
../../scripts/macos_sign_and_notarize.zsh -p "FreeCAD" -k ${MACOS_SIGNING_KEY_ID} -o "${version_name}.dmg"
|
||||
else
|
||||
# Ad-hoc sign for local builds (required for QuickLook extensions to register)
|
||||
if [ -d "FreeCAD.app/Contents/PlugIns" ]; then
|
||||
echo "Ad-hoc signing App Extensions with entitlements..."
|
||||
codesign --force --sign - \
|
||||
--entitlements ../../../src/MacAppBundle/QuickLook/modern/ThumbnailExtension.entitlements \
|
||||
FreeCAD.app/Contents/PlugIns/FreeCADThumbnailExtension.appex
|
||||
codesign --force --sign - \
|
||||
--entitlements ../../../src/MacAppBundle/QuickLook/modern/PreviewExtension.entitlements \
|
||||
FreeCAD.app/Contents/PlugIns/FreeCADPreviewExtension.appex
|
||||
fi
|
||||
echo "Ad-hoc signing app bundle..."
|
||||
codesign --force --sign - FreeCAD.app/Contents/packages.txt
|
||||
if [ -f "FreeCAD.app/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" ]; then
|
||||
codesign --force --sign - FreeCAD.app/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd
|
||||
fi
|
||||
codesign --force --sign - FreeCAD.app
|
||||
|
||||
# create the dmg
|
||||
dmgbuild -s dmg_settings.py "FreeCAD" "${version_name}.dmg"
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(freecad-launcher LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||
# Use MACOS_DEPLOYMENT_TARGET from environment if set, otherwise keep original default
|
||||
if(DEFINED ENV{MACOS_DEPLOYMENT_TARGET})
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "$ENV{MACOS_DEPLOYMENT_TARGET}" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||
else()
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum OS X deployment version" FORCE)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_executable(FreeCAD FreeCAD.cpp)
|
||||
|
||||
+5647
-5226
File diff suppressed because it is too large
Load Diff
@@ -28,10 +28,12 @@ create_bundle = 'bash -c "cd $(bash scripts/get_os.bash) && bash create_bundle.s
|
||||
## Linux (x86-64)
|
||||
[feature.package.target.linux-64.dependencies]
|
||||
coreutils = "*"
|
||||
xcb-util-cursor = "==0.1.5" ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
|
||||
## Linux (aarch64)
|
||||
[feature.package.target.linux-aarch64.dependencies]
|
||||
coreutils = "*"
|
||||
xcb-util-cursor = "==0.1.5" ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
|
||||
## macOS (Intel)
|
||||
[feature.package.target.osx-64.dependencies]
|
||||
|
||||
@@ -22,7 +22,7 @@ requirements:
|
||||
- noqt5
|
||||
- python>=3.11,<3.12
|
||||
- qt6-main>=6.8,<6.9
|
||||
- swig
|
||||
- swig>=4.3,<4.4
|
||||
|
||||
- if: linux and x86_64
|
||||
then:
|
||||
@@ -52,6 +52,7 @@ requirements:
|
||||
- pixman-cos7-x86_64
|
||||
- sed
|
||||
- sysroot_linux-64
|
||||
- xcb-util-cursor==0.1.5 ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
- xorg-x11-server-common-cos7-x86_64
|
||||
- xorg-x11-server-xvfb-cos7-x86_64
|
||||
- xorg-xproto
|
||||
@@ -84,6 +85,7 @@ requirements:
|
||||
- pixman-cos7-aarch64
|
||||
- sed
|
||||
- sysroot_linux-aarch64
|
||||
- xcb-util-cursor==0.1.5 ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
- xorg-x11-server-common-cos7-aarch64
|
||||
- xorg-x11-server-xvfb-cos7-aarch64
|
||||
- xorg-xproto
|
||||
@@ -98,7 +100,7 @@ requirements:
|
||||
|
||||
host:
|
||||
- coin3d
|
||||
- eigen
|
||||
- eigen >=3.3,<5
|
||||
- fmt
|
||||
- freetype
|
||||
- hdf5
|
||||
@@ -176,3 +178,5 @@ requirements:
|
||||
- if: linux
|
||||
then:
|
||||
- libspnav
|
||||
- qt6-wayland
|
||||
- xcb-util-cursor==0.1.5 ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
|
||||
@@ -44,6 +44,9 @@ find ${copy_dir} -name \*arm\*.exe -delete # arm binaries that fail to extract u
|
||||
mv ${copy_dir}/bin/Lib/ssl.py .ssl-orig.py
|
||||
cp ssl-patch.py ${copy_dir}/bin/Lib/ssl.py
|
||||
|
||||
# Turn off the echo before we start actually calling "echo"
|
||||
set +x
|
||||
|
||||
echo '[Paths]' >> ${copy_dir}/bin/qt6.conf
|
||||
echo 'Prefix = ../lib/qt6' >> ${copy_dir}/bin/qt6.conf
|
||||
|
||||
@@ -67,6 +70,64 @@ sed -i '1s/.*/\nLIST OF PACKAGES:/' ${copy_dir}/packages.txt
|
||||
|
||||
mv ${copy_dir} ${version_name}
|
||||
|
||||
|
||||
# Sign the EXE, DLL, and PYD files (if we can access the Azure account for signing):
|
||||
set -euo pipefail
|
||||
SIGN_DIR="${version_name}"
|
||||
|
||||
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-0}" == "1" ]]; then
|
||||
TENANT="$(az account show --query tenantId -o tsv)"
|
||||
export AZURE_IDENTITY_DISABLE_WORKLOAD_IDENTITY=true
|
||||
export AZURE_IDENTITY_DISABLE_MANAGED_IDENTITY=true
|
||||
unset AZURE_IDENTITY_LOGGING_ENABLED
|
||||
|
||||
if az account get-access-token \
|
||||
--tenant "$TENANT" \
|
||||
--scope "https://codesigning.azure.net/.default" \
|
||||
>/dev/null 2>&1;
|
||||
then
|
||||
echo "Azure Artifact Signing access confirmed. Beginning signing process..."
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
FILES=(
|
||||
"$SIGN_DIR"/*.exe
|
||||
"$SIGN_DIR"/bin/*.exe
|
||||
"$SIGN_DIR"/bin/*.dll
|
||||
"$SIGN_DIR"/bin/*.pyd
|
||||
)
|
||||
|
||||
count=0
|
||||
total=${#FILES[@]}
|
||||
echo "Signing $total files"
|
||||
for f in "${FILES[@]}"; do
|
||||
((count+=1))
|
||||
echo "Signing [$count/$total]: $f"
|
||||
sign code artifact-signing \
|
||||
--artifact-signing-endpoint "${WINDOWS_AZURE_ENDPOINT}" \
|
||||
--artifact-signing-certificate-profile "${WINDOWS_AZURE_CERTIFICATE_PROFILE}" \
|
||||
--artifact-signing-account "${WINDOWS_AZURE_SIGNING_ACCOUNT}" \
|
||||
--timestamp-url https://timestamp.acs.microsoft.com \
|
||||
--timestamp-digest sha256 \
|
||||
"$f" >/dev/null 2>&1
|
||||
|
||||
# Output was redirected to /dev/null because Azure authentication is absurdly noisy, with constant misleading
|
||||
# "failure" messages about Managed Identity authentication failing. We don't use, or want to use, that
|
||||
# authentication, and the fact that it fails is not a problem as long as the real authentication succeeds.
|
||||
done
|
||||
|
||||
# Manually check the important one!
|
||||
signtool verify -pa "$SIGN_DIR/bin/FreeCAD.exe"
|
||||
|
||||
echo "Signing completed."
|
||||
else
|
||||
echo "Signing requested, but no Azure Artifact Signing available -- skipping signing."
|
||||
fi
|
||||
else
|
||||
echo "Not logged into Azure -- skipping signing."
|
||||
fi
|
||||
|
||||
7z a -t7z -mx9 -mmt=${NUMBER_OF_PROCESSORS} ${version_name}.7z ${version_name} -bb
|
||||
# create hash
|
||||
sha256sum ${version_name}.7z > ${version_name}.7z-SHA256.txt
|
||||
@@ -88,6 +149,28 @@ if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
-X'SetCompressor /FINAL lzma' \
|
||||
../../WindowsInstaller/FreeCAD-installer.nsi
|
||||
mv ../../WindowsInstaller/${version_name}-installer.exe .
|
||||
echo "Created installer ${version_name}-installer.exe"
|
||||
|
||||
# See if we can sign the installer exe as well:
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-0}" == "1" ]] && \
|
||||
az account get-access-token \
|
||||
--tenant "$TENANT" \
|
||||
--scope "https://codesigning.azure.net/.default" \
|
||||
>/dev/null 2>&1;
|
||||
then
|
||||
echo "Signing the installer..."
|
||||
sign code artifact-signing \
|
||||
--artifact-signing-endpoint "${WINDOWS_AZURE_ENDPOINT}" \
|
||||
--artifact-signing-certificate-profile "${WINDOWS_AZURE_CERTIFICATE_PROFILE}" \
|
||||
--artifact-signing-account "${WINDOWS_AZURE_SIGNING_ACCOUNT}" \
|
||||
--timestamp-url https://timestamp.acs.microsoft.com \
|
||||
--timestamp-digest sha256 \
|
||||
${version_name}-installer.exe >/dev/null 2>&1 \
|
||||
|| { echo "Signing the installer failed!"; exit 1; }
|
||||
else
|
||||
echo "No code signing available, leaving the installer unsigned"
|
||||
fi
|
||||
|
||||
sha256sum ${version_name}-installer.exe > ${version_name}-installer.exe-SHA256.txt
|
||||
else
|
||||
echo "Error: Failed to get NsProcess plugin. Aborting installer creation..."
|
||||
@@ -96,8 +179,10 @@ if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
fi
|
||||
|
||||
if [ "${UPLOAD_RELEASE}" == "true" ]; then
|
||||
echo "Uploading the release..."
|
||||
gh release upload --clobber ${BUILD_TAG} "${version_name}.7z" "${version_name}.7z-SHA256.txt"
|
||||
if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
gh release upload --clobber ${BUILD_TAG} "${version_name}-installer.exe" "${version_name}-installer.exe-SHA256.txt"
|
||||
fi
|
||||
echo "Done uploading"
|
||||
fi
|
||||
|
||||
@@ -123,7 +123,11 @@ done
|
||||
|
||||
# Two additional files that must be signed that aren't caught by the above searches:
|
||||
run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/packages.txt"
|
||||
run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd"
|
||||
|
||||
# Sign legacy QuickLook generator if present (not built for macOS 15.0+)
|
||||
if [ -f "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd" ]; then
|
||||
run_codesign "${CONTAINING_FOLDER}/${APP_NAME}/Contents/Library/QuickLook/QuicklookFCStd.qlgenerator/Contents/MacOS/QuicklookFCStd"
|
||||
fi
|
||||
|
||||
# Sign new Swift QuickLook extensions (macOS 15.0+) with their specific entitlements
|
||||
# These must be signed before the app itself to avoid overriding the extension signatures
|
||||
|
||||
@@ -19,11 +19,12 @@ debugpy = "*"
|
||||
defusedxml = "*"
|
||||
docutils = "*"
|
||||
doxygen = "*"
|
||||
eigen = "*"
|
||||
eigen = ">=3.3,<5"
|
||||
fmt = "*"
|
||||
freetype = "*"
|
||||
git = "*"
|
||||
graphviz = "*"
|
||||
harfbuzz = "*"
|
||||
hdf5 = "*"
|
||||
ifcopenshell = "*"
|
||||
lark = "*"
|
||||
@@ -92,9 +93,10 @@ mesa-libgl-cos7-x86_64 = "*"
|
||||
mesa-libgl-devel-cos7-x86_64 = "*"
|
||||
mold = "*"
|
||||
pixman-cos7-x86_64 = "*"
|
||||
qt6-wayland = "*"
|
||||
qt6-wayland = ">=6.8,<6.9"
|
||||
sed = "*"
|
||||
sysroot_linux-64 = "*"
|
||||
xcb-util-cursor = "==0.1.5" ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
xorg-x11-server-common-cos7-x86_64 = "*"
|
||||
xorg-x11-server-xvfb-cos7-x86_64 = "*"
|
||||
xorg-xproto = "*"
|
||||
@@ -131,9 +133,10 @@ mesa-libgl-devel-cos7-aarch64 = "*"
|
||||
mesa-libglapi-cos7-aarch64 = "*"
|
||||
mold = "*"
|
||||
pixman-cos7-aarch64 = "*"
|
||||
qt6-wayland = "*"
|
||||
qt6-wayland = ">=6.8,<6.9"
|
||||
sed = "*"
|
||||
sysroot_linux-aarch64 = "*"
|
||||
xcb-util-cursor = "==0.1.5" ## hack to address https://github.com/FreeCAD/FreeCAD/issues/26726
|
||||
xorg-x11-server-common-cos7-aarch64 = "*"
|
||||
xorg-x11-server-xvfb-cos7-aarch64 = "*"
|
||||
xorg-xproto = "*"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
project(FastSignals)
|
||||
|
||||
|
||||
+5
-4
@@ -92,12 +92,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Checkout Test Data
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: 'asmaloney/libE57Format-test-data'
|
||||
path: libE57Format-test-data
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
- name: Install Dependencies (macOS)
|
||||
if: matrix.platform == 'macos'
|
||||
run: |
|
||||
brew install ccache ninja xerces-c
|
||||
brew install ccache xerces-c
|
||||
|
||||
- name: Install Dependencies (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
@@ -118,13 +118,14 @@ jobs:
|
||||
if: matrix.platform == 'windows'
|
||||
uses: conda-incubator/setup-miniconda@v3
|
||||
with:
|
||||
channels: conda-forge
|
||||
channels: conda-forge,defaults
|
||||
|
||||
- name: Install More Dependencies (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
shell: bash -el {0}
|
||||
run: |
|
||||
conda install conda-forge::xerces-c
|
||||
echo "CMAKE_PREFIX_PATH=${CONDA_PREFIX}/Library" >> "$GITHUB_ENV"
|
||||
choco upgrade ccache ninja
|
||||
ccache --version | head -n 1
|
||||
echo "ninja $(ninja --version)"
|
||||
|
||||
+12
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 3.3.0 - (in progress)
|
||||
## [3.3.0](https://github.com/asmaloney/libE57Format/releases/tag/v3.3.0) - 2025-10-24
|
||||
|
||||
### Added
|
||||
|
||||
@@ -14,10 +14,20 @@ All notable changes to this project will be documented in this file. The format
|
||||
|
||||
### Fixed
|
||||
|
||||
- {cmake} Added missing include for GNUInstallDirs ([#315](https://github.com/asmaloney/libE57Format/pull/315)) (Thanks Adrian!)
|
||||
- Fix clang 17 warnings about `@throw` documentation. ([#327](https://github.com/asmaloney/libE57Format/pull/327))
|
||||
|
||||
- Fix MSVC C++17 deprecation of `codecvt_utf8_utf16`; replaced with `MultiByteToWideChar` if compiling with C++ >= 17. ([#326](https://github.com/asmaloney/libE57Format/pull/326)) (Thanks Christophe!)
|
||||
|
||||
- {ci} Fix some CI warnings and update actions. ([#328](https://github.com/asmaloney/libE57Format/pull/328))
|
||||
|
||||
- {ci} Fix GitHub CI for Windows. ([#325](https://github.com/asmaloney/libE57Format/pull/325)) (Thanks Christophe!)
|
||||
|
||||
- {cmake} Add missing include for GNUInstallDirs ([#315](https://github.com/asmaloney/libE57Format/pull/315)) (Thanks Adrian!)
|
||||
|
||||
If you built without testing on, the cmake files were not installed to the correct location.
|
||||
|
||||
- {standard conformance} Don't try to fill in intensity limits when using the simple API. They are for the limits that the sensor can produce, not the limits of the data (8.4.19).
|
||||
|
||||
## [3.2.0](https://github.com/asmaloney/libE57Format/releases/tag/v3.2.0) - 2024-06-27
|
||||
|
||||
### Added
|
||||
|
||||
+6
-6
@@ -36,12 +36,12 @@ set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/"
|
||||
message( STATUS "Using CMake ${CMAKE_VERSION}" )
|
||||
|
||||
project( E57Format
|
||||
DESCRIPTION
|
||||
"E57Format is a library to read and write E57 files"
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
3.2.0
|
||||
DESCRIPTION
|
||||
"E57Format is a library to read and write E57 files"
|
||||
LANGUAGES
|
||||
CXX
|
||||
VERSION
|
||||
3.3.0
|
||||
)
|
||||
|
||||
string( TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPERCASE )
|
||||
|
||||
Vendored
+1
@@ -106,6 +106,7 @@ This _Simple API_ has evolved since this original port to fix some problems and
|
||||
These projects use hard forks of libE57Format:
|
||||
|
||||
- [FreeCAD](https://github.com/FreeCAD/FreeCAD)
|
||||
- [MicMac](https://github.com/micmacIGN/micmac)
|
||||
- [PDAL](https://github.com/PDAL/PDAL)
|
||||
|
||||
There are also many commercial products using libE57Format. If any of them would like to sponsor the project and be listed here, please <a href="mailto:asmaloney@gmail.com?subject=libE57Format Sponsorship">contact Andy</a>.
|
||||
|
||||
+2
-2
@@ -634,8 +634,8 @@ namespace e57
|
||||
|
||||
@param [in] data3D Completed header which indicates the fields we are using
|
||||
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorInvalidNodeType
|
||||
@throw ::ErrorValueOutOfBounds (n/c)
|
||||
@throw ::ErrorInvalidNodeType (n/c)
|
||||
*/
|
||||
explicit Data3DPointsData_t( e57::Data3D &data3D );
|
||||
|
||||
|
||||
+19
-19
@@ -126,10 +126,10 @@ is an error to attempt to attach the BlobNode to a different ImageFile.
|
||||
must be true).
|
||||
@pre byteCount >= 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state (n/c)
|
||||
|
||||
@see Node, BlobNode::read, BlobNode::write
|
||||
*/
|
||||
@@ -200,7 +200,7 @@ bool BlobNode::isAttached() const
|
||||
|
||||
@return The declared size of the blob when it was created.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::read, BlobNode::write
|
||||
@@ -233,11 +233,11 @@ zero or more times.
|
||||
@pre 0 <= count
|
||||
@pre (@a start + @a count) < byteCount()
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorSeekFailed (n/c)
|
||||
@throw ::ErrorReadFailed (n/c)
|
||||
@throw ::ErrorBadChecksum (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::byteCount, BlobNode::write
|
||||
@@ -276,14 +276,14 @@ destImageFile().isWritable()).
|
||||
@pre 0 <= count
|
||||
@pre (@a start + @a count) < byteCount()
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorNodeUnattached (n/c)
|
||||
@throw ::ErrorSeekFailed (n/c)
|
||||
@throw ::ErrorReadFailed (n/c)
|
||||
@throw ::ErrorWriteFailed (n/c)
|
||||
@throw ::ErrorBadChecksum (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see BlobNode::byteCount, BlobNode::read
|
||||
@@ -340,7 +340,7 @@ The handle @a n must be for an underlying BlobNode, otherwise an exception is th
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), BlobNode::operator Node()
|
||||
*/
|
||||
|
||||
+27
-3
@@ -32,8 +32,13 @@
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#if defined( _MSC_VER )
|
||||
#include <codecvt>
|
||||
#include <codecvt> // codecvt_utf8_utf16 is deprecated in C++17, removed in C++226
|
||||
#include <io.h>
|
||||
#define NOMINMAX // prevents <windows.h> to #define min and max. Sigh ...
|
||||
// clang-format off: <windows.h> MUST be included before <stringapiset.h>
|
||||
#include <windows.h>
|
||||
#include <stringapiset.h> // Use WIN32 API to replace codecvt_utf8_utf16
|
||||
// clang-format on
|
||||
#elif defined( __GNUC__ )
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
@@ -233,12 +238,31 @@ CheckedFile::CheckedFile( const char *input, uint64_t size, ReadChecksumPolicy p
|
||||
int CheckedFile::open64( const ustring &fileName, int flags, int mode )
|
||||
{
|
||||
#if defined( _MSC_VER )
|
||||
// Ref: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/sopen-s-wsopen-s
|
||||
|
||||
// Handle UTF-8 file names - Windows requires conversion to UTF-16
|
||||
// Handle UTF-8 file names - Windows requires conversion to UTF-16
|
||||
#if ( ( defined( _MSVC_LANG ) && _MSVC_LANG >= 201703L ) || __cplusplus >= 201703L )
|
||||
// Ref:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar
|
||||
std::wstring widePath;
|
||||
int sizeUtf16 = ::MultiByteToWideChar( CP_UTF8, 0, fileName.c_str(), -1, NULL, 0 );
|
||||
if ( sizeUtf16 > 0 )
|
||||
{
|
||||
widePath.resize( sizeUtf16 + 1 );
|
||||
sizeUtf16 =
|
||||
::MultiByteToWideChar( CP_UTF8, 0, fileName.c_str(), -1, &widePath[0], sizeUtf16 );
|
||||
}
|
||||
if ( sizeUtf16 <= 0 )
|
||||
{
|
||||
throw E57_EXCEPTION2( ErrorOpenFailed,
|
||||
"Error in converting file name to UTF16. fileName=" + fileName );
|
||||
}
|
||||
#else
|
||||
// Until C++17
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
std::wstring widePath = converter.from_bytes( fileName );
|
||||
#endif
|
||||
|
||||
// Ref: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/sopen-s-wsopen-s
|
||||
int handle;
|
||||
errno_t err = _wsopen_s( &handle, widePath.c_str(), flags, _SH_DENYNO, mode );
|
||||
if ( err != 0 )
|
||||
|
||||
+29
-29
@@ -197,12 +197,12 @@ prototype.isRoot())
|
||||
@post prototype.isAttached()
|
||||
@post codecs.isAttached()
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorBadPrototype
|
||||
@throw ::ErrorBadCodecs
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorBadPrototype (n/c)
|
||||
@throw ::ErrorBadCodecs (n/c)
|
||||
@throw ::ErrorAlreadyHasParent (n/c)
|
||||
@throw ::ErrorDifferentDestImageFile (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see SourceDestBuffer, Node, CompressedVectorNode::reader, CompressedVectorNode::writer
|
||||
@@ -275,7 +275,7 @@ any writes completed.
|
||||
|
||||
@return Current number of records in CompressedVectorNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader, CompressedVectorNode::writer
|
||||
@@ -293,7 +293,7 @@ int64_t CompressedVectorNode::childCount() const
|
||||
|
||||
@return A smart Node handle referencing the root of the prototype tree.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::CompressedVectorNode, SourceDestBuffer, CompressedVectorNode::reader,
|
||||
@@ -313,7 +313,7 @@ CompressedVectorNode.
|
||||
|
||||
@return A smart VectorNode handle referencing the root of the codecs tree.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::CompressedVectorNode, SourceDestBuffer, CompressedVectorNode::reader,
|
||||
@@ -372,7 +372,7 @@ designs that need to avoid the exception, use Node::type() to determine the actu
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), CompressedVectorNode::operator, Node()
|
||||
*/
|
||||
@@ -422,17 +422,17 @@ CompressedVectorNode cannot be set twice).
|
||||
|
||||
@return A smart CompressedVectorWriter handle referencing the underlying iterator object.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorSetTwice
|
||||
@throw ::ErrorTooManyWriters
|
||||
@throw ::ErrorTooManyReaders
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorSetTwice (n/c)
|
||||
@throw ::ErrorTooManyWriters (n/c)
|
||||
@throw ::ErrorTooManyReaders (n/c)
|
||||
@throw ::ErrorNodeUnattached (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorBufferSizeMismatch (n/c)
|
||||
@throw ::ErrorBufferDuplicatePathName (n/c)
|
||||
@throw ::ErrorNoBufferForElement (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter, SourceDestBuffer, CompressedVectorNode::CompressedVectorNode,
|
||||
@@ -461,14 +461,14 @@ prototype. It is not an error to create a CompressedVectorReader for an empty Co
|
||||
|
||||
@return A smart CompressedVectorReader handle referencing the underlying iterator object.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorTooManyWriters
|
||||
@throw ::ErrorNodeUnattached
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorBadCVHeader
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorTooManyWriters (n/c)
|
||||
@throw ::ErrorNodeUnattached (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorBufferSizeMismatch (n/c)
|
||||
@throw ::ErrorBufferDuplicatePathName (n/c)
|
||||
@throw ::ErrorBadCVHeader (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader, SourceDestBuffer, CompressedVectorNode::CompressedVectorNode,
|
||||
|
||||
+27
-37
@@ -162,29 +162,19 @@ destroyed.
|
||||
|
||||
@return The number of records read.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorConversionRequired This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorExpectingUString This CompressedVectorReader
|
||||
in undocumented state
|
||||
@throw ::ErrorBadCVPacket This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorSeekFailed This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorReader, associated
|
||||
ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorReaderNotOpen (n/c)
|
||||
@throw ::ErrorConversionRequired This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorReal64TooLarge This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorExpectingNumeric This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorExpectingUString This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorBadCVPacket This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorSeekFailed This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorBadChecksum This CompressedVectorReader, associated ImageFile in undocumented state
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::read(std::vector<SourceDestBuffer>&),
|
||||
CompressedVectorNode::reader, SourceDestBuffer,
|
||||
@@ -230,11 +220,11 @@ detect that a memory buffer been destroyed.
|
||||
|
||||
@return The number of records read.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorImageFileNotOpen nc
|
||||
@throw ::ErrorReaderNotOpen (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorBufferSizeMismatch (n/c)
|
||||
@throw ::ErrorBufferDuplicatePathName (n/c)
|
||||
@throw ::ErrorConversionRequired This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@throw ::ErrorScaledValueNotRepresentable This CompressedVectorReader in undocumented state
|
||||
@@ -269,13 +259,13 @@ childCount() (i.e. to one record past end of CompressedVectorNode).
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorReader must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorReaderNotOpen
|
||||
@throw ::ErrorBadCVPacket
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorReaderNotOpen (n/c)
|
||||
@throw ::ErrorBadCVPacket (n/c)
|
||||
@throw ::ErrorSeekFailed (n/c)
|
||||
@throw ::ErrorReadFailed (n/c)
|
||||
@throw ::ErrorBadChecksum (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader
|
||||
@@ -308,7 +298,7 @@ void CompressedVectorReader::close()
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::close, CompressedVectorNode::reader
|
||||
@@ -328,7 +318,7 @@ It is not an error if this CompressedVectorReader is closed.
|
||||
|
||||
@return A smart CompressedVectorNode handle referencing the underlying object being read from.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorReader::close, CompressedVectorNode::reader
|
||||
|
||||
+17
-17
@@ -152,13 +152,13 @@ all writes to the CompressedVectorNode will be lost (it will have zero children)
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorWriter must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorWriterNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorWriterNotOpen (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorNoBufferForElement (n/c)
|
||||
@throw ::ErrorBufferSizeMismatch (n/c)
|
||||
@throw ::ErrorBufferDuplicatePathName (n/c)
|
||||
@throw ::ErrorConversionRequired This CompressedVectorWriter in undocumented state, associated
|
||||
CompressedVectorNode modified but consistent, associated ImageFile modified but consistent.
|
||||
@throw ::ErrorValueOutOfBounds This CompressedVectorWriter in undocumented state, associated
|
||||
@@ -218,13 +218,13 @@ is invoked, all writes to the CompressedVectorNode will be lost (it will have ze
|
||||
@pre The associated ImageFile must be open.
|
||||
@pre This CompressedVectorWriter must be open (i.e isOpen())
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorWriterNotOpen
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorNoBufferForElement
|
||||
@throw ::ErrorBufferSizeMismatch
|
||||
@throw ::ErrorBufferDuplicatePathName
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorWriterNotOpen (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorNoBufferForElement (n/c)
|
||||
@throw ::ErrorBufferSizeMismatch (n/c)
|
||||
@throw ::ErrorBufferDuplicatePathName (n/c)
|
||||
@throw ::ErrorConversionRequired This CompressedVectorWriter in undocumented state, associated
|
||||
ImageFile modified but consistent.
|
||||
@throw ::ErrorValueOutOfBounds This CompressedVectorWriter in undocumented state, associated
|
||||
@@ -269,7 +269,7 @@ writes to the CompressedVectorNode will be lost (it will have zero children).
|
||||
@pre The associated ImageFile must be open.
|
||||
@post This CompressedVectorWriter is closed (i.e !isOpen())
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorSeekFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorReadFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@throw ::ErrorWriteFailed This CompressedVectorWriter, associated ImageFile in undocumented state
|
||||
@@ -288,7 +288,7 @@ void CompressedVectorWriter::close()
|
||||
|
||||
@pre The associated ImageFile must be open.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorWriter::close, CompressedVectorNode::writer
|
||||
@@ -305,7 +305,7 @@ bool CompressedVectorWriter::isOpen()
|
||||
|
||||
@return A smart CompressedVectorNode handle referencing the underlying object being written to.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::writer
|
||||
|
||||
+9
-9
@@ -141,10 +141,10 @@ if 0 is within bounds, or a @a value = @a minimum if 0 is not within bounds.
|
||||
be true).
|
||||
@pre minimum <= value <= maximum
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorValueOutOfBounds (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatPrecision, FloatNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
@@ -222,7 +222,7 @@ is ::PrecisionDouble, the double precision value is returned as a double.
|
||||
|
||||
@return The IEEE floating point value stored, represented as a double.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::minimum, FloatNode::maximum
|
||||
@@ -241,7 +241,7 @@ double FloatNode::value() const
|
||||
@return The declared precision of the floating point number, either ::PrecisionSingle or
|
||||
::PrecisionDouble.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatPrecision
|
||||
@@ -263,7 +263,7 @@ precision is ::PrecisionDouble, the double precision minimum is returned as a do
|
||||
|
||||
@return The declared minimum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::maximum, FloatNode::value
|
||||
@@ -285,7 +285,7 @@ precision is ::PrecisionDouble, the double precision maximum is returned as a do
|
||||
|
||||
@return The declared maximum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see FloatNode::minimum, FloatNode::value
|
||||
@@ -340,7 +340,7 @@ The handle @a n must be for an underlying FloatNode, otherwise an exception is t
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), FloatNode::operator Node()
|
||||
*/
|
||||
|
||||
+38
-38
@@ -265,19 +265,19 @@ read-only). There is no API support for appending data onto an existing E57 data
|
||||
|
||||
@post Resulting ImageFile is in @c open state if constructor succeeds (no exception thrown).
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorOpenFailed
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorBadFileSignature
|
||||
@throw ::ErrorUnknownFileVersion
|
||||
@throw ::ErrorBadFileLength
|
||||
@throw ::ErrorXMLParserInit
|
||||
@throw ::ErrorXMLParser
|
||||
@throw ::ErrorBadXMLFormat
|
||||
@throw ::ErrorBadConfiguration
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorOpenFailed (n/c)
|
||||
@throw ::ErrorSeekFailed (n/c)
|
||||
@throw ::ErrorReadFailed (n/c)
|
||||
@throw ::ErrorWriteFailed (n/c)
|
||||
@throw ::ErrorBadChecksum (n/c)
|
||||
@throw ::ErrorBadFileSignature (n/c)
|
||||
@throw ::ErrorUnknownFileVersion (n/c)
|
||||
@throw ::ErrorBadFileLength (n/c)
|
||||
@throw ::ErrorXMLParserInit (n/c)
|
||||
@throw ::ErrorXMLParser (n/c)
|
||||
@throw ::ErrorBadXMLFormat (n/c)
|
||||
@throw ::ErrorBadConfiguration (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode, ScaledIntegerNode, FloatNode, StringNode, BlobNode, StructureNode, VectorNode,
|
||||
@@ -307,7 +307,7 @@ is empty in a newly created write mode ImageFile.
|
||||
|
||||
@return A smart StructureNode handle referencing the underlying object.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode.
|
||||
@@ -339,11 +339,11 @@ It is not an error if ImageFile is already closed.
|
||||
|
||||
@post ImageFile is in @c closed state.
|
||||
|
||||
@throw ::ErrorSeekFailed
|
||||
@throw ::ErrorReadFailed
|
||||
@throw ::ErrorWriteFailed
|
||||
@throw ::ErrorCloseFailed
|
||||
@throw ::ErrorBadChecksum
|
||||
@throw ::ErrorSeekFailed (n/c)
|
||||
@throw ::ErrorReadFailed (n/c)
|
||||
@throw ::ErrorWriteFailed (n/c)
|
||||
@throw ::ErrorCloseFailed (n/c)
|
||||
@throw ::ErrorBadChecksum (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::cancel, ImageFile::isOpen
|
||||
@@ -432,7 +432,7 @@ CompressedVectorWriter objects are created by the CompressedVectorNode::writer f
|
||||
|
||||
@return The current number of open CompressedVectorWriter objects writing to ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::writer, CompressedVectorWriter
|
||||
@@ -454,7 +454,7 @@ CompressedVectorReader objects are created by the CompressedVectorNode::reader f
|
||||
|
||||
@return The current number of open CompressedVectorReader objects reading from ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see CompressedVectorNode::reader, CompressedVectorReader
|
||||
@@ -496,11 +496,11 @@ See the class discussion at bottom of ImageFile page for more details about name
|
||||
@pre prefix != ""
|
||||
@pre uri != ""
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorDuplicateNamespacePrefix
|
||||
@throw ::ErrorDuplicateNamespaceURI
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorDuplicateNamespacePrefix (n/c)
|
||||
@throw ::ErrorDuplicateNamespaceURI (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsLookupPrefix, ImageFile::extensionsLookupUri
|
||||
@@ -524,8 +524,8 @@ an error if @a prefix contains an illegal character combination for E57 namespac
|
||||
|
||||
@return true if prefix is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsLookupUri
|
||||
@@ -554,8 +554,8 @@ namespace prefixes. It is not an error if @a prefix is well-formed, but not defi
|
||||
|
||||
@return true if prefix is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@@ -584,8 +584,8 @@ function just returns false).
|
||||
|
||||
@return true if URI is declared in the ImageFile.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsLookupPrefix
|
||||
@@ -606,7 +606,7 @@ The default E57 namespace does not count as an extension.
|
||||
|
||||
@return The number of E57 extensions defined in the ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsPrefix, ImageFile::extensionsUri
|
||||
@@ -632,8 +632,8 @@ counted as an extension.
|
||||
|
||||
@return The E57 extension prefix at the given index.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsUri
|
||||
@@ -659,8 +659,8 @@ as an extension.
|
||||
|
||||
@return The E57 extension URI at the given index.
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::extensionsCount, ImageFile::extensionsPrefix
|
||||
@@ -704,7 +704,7 @@ prefixed form, the prefix does not have to be declared in the ImageFile.
|
||||
|
||||
@post No visible state is modified.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::isElementNameExtended
|
||||
|
||||
+8
-8
@@ -134,10 +134,10 @@ ignored). If the IntegerNode is to be used in a prototype, it is recommended to
|
||||
be true).
|
||||
@pre minimum <= value <= maximum
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorValueOutOfBounds (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
@@ -211,7 +211,7 @@ bool IntegerNode::isAttached() const
|
||||
|
||||
@return integer value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::minimum, IntegerNode::maximum
|
||||
@@ -229,7 +229,7 @@ int64_t IntegerNode::value() const
|
||||
|
||||
@return The declared minimum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value
|
||||
@@ -247,7 +247,7 @@ int64_t IntegerNode::minimum() const
|
||||
|
||||
@return The declared maximum that the value may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see IntegerNode::value
|
||||
@@ -303,7 +303,7 @@ The handle @a n must be for an underlying IntegerNode, otherwise an exception is
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), IntegerNode::operator Node()
|
||||
*/
|
||||
|
||||
+5
-5
@@ -372,7 +372,7 @@ relationship (see Node::isAttached and CompressedVectorNode::CompressedVectorNod
|
||||
|
||||
@return true if this node is a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::parent, Node::isAttached, CompressedVectorNode::CompressedVectorNode
|
||||
@@ -407,7 +407,7 @@ infinite recursion.
|
||||
|
||||
@return A smart Node handle referencing the parent node or this node if is a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::isRoot, Node::isAttached, CompressedVectorNode::CompressedVectorNode, Node::elementName
|
||||
@@ -441,7 +441,7 @@ root node has the empty string ("") as its elementName.
|
||||
|
||||
@return The absolute path name of the node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::elementName, Node::parent, Node::isRoot
|
||||
@@ -473,7 +473,7 @@ by the position of the child.
|
||||
|
||||
@return The element name of the node, or "" if a root node.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::pathName, Node::parent, Node::isRoot
|
||||
@@ -524,7 +524,7 @@ eventually attached to the ImageFile.
|
||||
@return @c true if node is child of (or in codecs or prototype of a child CompressedVectorNode of)
|
||||
the root node of an ImageFile.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node::destImageFile, ImageFile::root
|
||||
|
||||
+17
-17
@@ -139,10 +139,10 @@ be true).
|
||||
@pre minimum <= rawValue <= maximum
|
||||
@pre scale != 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorValueOutOfBounds (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::rawValue, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
@@ -201,10 +201,10 @@ be true).
|
||||
@pre scaledMinimum <= scaledValue <= scaledMaximum
|
||||
@pre scale != 0
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorValueOutOfBounds
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorValueOutOfBounds (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
@@ -280,7 +280,7 @@ bool ScaledIntegerNode::isAttached() const
|
||||
|
||||
@return The raw unscaled integer value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue, ScaledIntegerNode::minimum, ScaledIntegerNode::maximum
|
||||
@@ -298,7 +298,7 @@ int64_t ScaledIntegerNode::rawValue() const
|
||||
|
||||
@return The scaled value (rawValue*scale + offset) calculated from the rawValue stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::rawValue
|
||||
@@ -316,7 +316,7 @@ double ScaledIntegerNode::scaledValue() const
|
||||
|
||||
@return The declared minimum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::maximum, ScaledIntegerNode::rawValue
|
||||
@@ -334,7 +334,7 @@ int64_t ScaledIntegerNode::minimum() const
|
||||
|
||||
@return The declared minimum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledMaximum, ScaledIntegerNode::scaledValue
|
||||
@@ -352,7 +352,7 @@ double ScaledIntegerNode::scaledMinimum() const
|
||||
|
||||
@return The declared maximum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::minimum, ScaledIntegerNode::rawValue
|
||||
@@ -370,7 +370,7 @@ int64_t ScaledIntegerNode::maximum() const
|
||||
|
||||
@return The declared maximum that the rawValue may take.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledMinimum, ScaledIntegerNode::scaledValue
|
||||
@@ -388,7 +388,7 @@ double ScaledIntegerNode::scaledMaximum() const // Added by SC
|
||||
|
||||
@return The scaling factor used to compute scaledValue from rawValue.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue
|
||||
@@ -406,7 +406,7 @@ double ScaledIntegerNode::scale() const
|
||||
|
||||
@return The offset used to compute scaledValue from rawValue.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ScaledIntegerNode::scaledValue
|
||||
@@ -463,7 +463,7 @@ designs that need to avoid the exception, use Node::type() to determine the actu
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), ScaledIntegerNode::operator, Node()
|
||||
*/
|
||||
|
||||
+9
-9
@@ -149,10 +149,10 @@ transfer with a CompressedVectorNode.
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
@pre The stride must be >= sizeof(*b)
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorBadBuffer
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorBadBuffer (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::reader, ImageFile::writer,
|
||||
@@ -287,10 +287,10 @@ destroyed).
|
||||
@pre b.size() must be > 0.
|
||||
@pre The @a destImageFile must be open (i.e. destImageFile.isOpen() must be true).
|
||||
|
||||
@throw ::ErrorBadAPIArgument
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorBadBuffer
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadAPIArgument (n/c)
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorBadBuffer (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see SourceDestBuffer::doConversion for discussion on representations compatible with string
|
||||
@@ -397,7 +397,7 @@ CompressedVectorReader or CompressedVectorWriter is created).
|
||||
|
||||
@return true if conversions will be performed to match the memory type of buffer.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
*/
|
||||
bool SourceDestBuffer::doConversion() const
|
||||
|
||||
+4
-4
@@ -103,8 +103,8 @@ If the StringNode is to be used in a CompressedVectorNode prototype, it is recom
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StringNode::value, Node, CompressedVectorNode, CompressedVectorNode::prototype
|
||||
@@ -177,7 +177,7 @@ bool StringNode::isAttached() const
|
||||
|
||||
@return The Unicode character string value stored.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
*/
|
||||
ustring StringNode::value() const
|
||||
@@ -232,7 +232,7 @@ The handle @a n must be for an underlying StringNode, otherwise an exception is
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), StringNode::operator Node()
|
||||
*/
|
||||
|
||||
+18
-18
@@ -127,7 +127,7 @@ to attach the StructureNode to a different ImageFile.
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node
|
||||
@@ -199,7 +199,7 @@ bool StructureNode::isAttached() const
|
||||
|
||||
@return Number of child nodes contained by this StructureNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::get(int64_t) const,
|
||||
@@ -225,8 +225,8 @@ is not attached to an ImageFile, the @a pathName origin root will not the root n
|
||||
|
||||
@return true if pathName is currently defined.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ImageFile::root, VectorNode::isDefined
|
||||
@@ -251,8 +251,8 @@ the StructureNode. The order of children may change if more children are added t
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorChildIndexOutOfBounds
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorChildIndexOutOfBounds (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::childCount,
|
||||
@@ -278,9 +278,9 @@ an ImageFile.
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::get(int64_t) const
|
||||
@@ -321,14 +321,14 @@ destImageFile().isWritable()).
|
||||
destImageFile() == n.destImageFile()).
|
||||
@post The @a pathName will be defined (i.e. isDefined(pathName)).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorSetTwice
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorHomogeneousViolation
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorSetTwice (n/c)
|
||||
@throw ::ErrorAlreadyHasParent (n/c)
|
||||
@throw ::ErrorDifferentDestImageFile (n/c)
|
||||
@throw ::ErrorHomogeneousViolation (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::append
|
||||
@@ -386,7 +386,7 @@ designs that need to avoid the exception, use Node::type() to determine the actu
|
||||
before downcasting. This function must be explicitly called (c++ compiler cannot insert it
|
||||
automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), StructureNode::operator Node()
|
||||
*/
|
||||
|
||||
+16
-16
@@ -146,7 +146,7 @@ unconstrained.
|
||||
@pre The @a destImageFile must have been opened in write mode (i.e. destImageFile.isWritable() must
|
||||
be true).
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see Node, VectorNode::allowHeteroChildren, ::ErrorHomogeneousViolation
|
||||
@@ -223,7 +223,7 @@ changed.
|
||||
|
||||
@return True if child elements can be different types.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see ::ErrorHomogeneousViolation
|
||||
@@ -241,7 +241,7 @@ bool VectorNode::allowHeteroChildren() const
|
||||
|
||||
@return Number of child elements in this VectorNode.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::get(int64_t), VectorNode::append, StructureNode::childCount
|
||||
@@ -268,8 +268,8 @@ The element names of child elements of VectorNodes are numbers, encoded as strin
|
||||
|
||||
@return true if pathName is currently defined.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see StructureNode::isDefined
|
||||
@@ -290,8 +290,8 @@ bool VectorNode::isDefined( const ustring &pathName ) const
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorChildIndexOutOfBounds
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorChildIndexOutOfBounds (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::append, StructureNode::get(int64_t) const
|
||||
@@ -319,9 +319,9 @@ The element names of child elements of VectorNodes are numbers, encoded as strin
|
||||
|
||||
@return A smart Node handle referencing the child node.
|
||||
|
||||
@throw ::ErrorBadPathName
|
||||
@throw ::ErrorPathUndefined
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorBadPathName (n/c)
|
||||
@throw ::ErrorPathUndefined (n/c)
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::append, StructureNode::get(int64_t) const
|
||||
@@ -352,11 +352,11 @@ The VectorNode must not be a descendent of a homogeneous VectorNode with more th
|
||||
destImageFile().isWritable()).
|
||||
@post the childCount is incremented.
|
||||
|
||||
@throw ::ErrorImageFileNotOpen
|
||||
@throw ::ErrorHomogeneousViolation
|
||||
@throw ::ErrorFileReadOnly
|
||||
@throw ::ErrorAlreadyHasParent
|
||||
@throw ::ErrorDifferentDestImageFile
|
||||
@throw ::ErrorImageFileNotOpen (n/c)
|
||||
@throw ::ErrorHomogeneousViolation (n/c)
|
||||
@throw ::ErrorFileReadOnly (n/c)
|
||||
@throw ::ErrorAlreadyHasParent (n/c)
|
||||
@throw ::ErrorDifferentDestImageFile (n/c)
|
||||
@throw ::ErrorInternal All objects in undocumented state
|
||||
|
||||
@see VectorNode::childCount, VectorNode::get(int64_t), StructureNode::set
|
||||
@@ -413,7 +413,7 @@ The handle @a n must be for an underlying VectorNode, otherwise an exception is
|
||||
that need to avoid the exception, use Node::type() to determine the actual type of the @a n before
|
||||
downcasting. This function must be explicitly called (c++ compiler cannot insert it automatically).
|
||||
|
||||
@throw ::ErrorBadNodeDowncast
|
||||
@throw ::ErrorBadNodeDowncast (n/c)
|
||||
|
||||
@see Node::type(), VectorNode::operator Node()
|
||||
*/
|
||||
|
||||
@@ -126,7 +126,11 @@ namespace netgen {
|
||||
#endif
|
||||
//extern void OCCSetLocalMeshSize(OCCGeometry & geom, Mesh & mesh);
|
||||
DLL_HEADER extern MeshingParameters mparam;
|
||||
DLL_HEADER extern volatile multithreadt multithread;
|
||||
#if NETGEN_VERSION >= NETGEN_VERSION_STRING(6,2,2601)
|
||||
using ngcore::multithread;
|
||||
#else
|
||||
DLL_HEADER extern volatile multithreadt multithread;
|
||||
#endif
|
||||
DLL_HEADER extern bool merge_solids;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,11 @@ namespace netgen {
|
||||
DLL_HEADER extern int OCCGenerateMesh (OCCGeometry&, Mesh*&, int, int, char*);
|
||||
#endif
|
||||
DLL_HEADER extern MeshingParameters mparam;
|
||||
DLL_HEADER extern volatile multithreadt multithread;
|
||||
#if NETGEN_VERSION >= NETGEN_VERSION_STRING(6,2,2601)
|
||||
using ngcore::multithread;
|
||||
#else
|
||||
DLL_HEADER extern volatile multithreadt multithread;
|
||||
#endif
|
||||
}
|
||||
using namespace nglib;
|
||||
using namespace std;
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_ANNOTATION_H
|
||||
#define APP_ANNOTATION_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "PropertyGeo.h"
|
||||
@@ -74,6 +73,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_ANNOTATION_H
|
||||
|
||||
+262
-261
@@ -34,14 +34,18 @@
|
||||
# define WINVER 0x502 // needed for SetDllDirectory
|
||||
# include <Windows.h>
|
||||
# endif
|
||||
|
||||
# include <boost/algorithm/string.hpp>
|
||||
# include <boost/program_options.hpp>
|
||||
# include <boost/date_time/posix_time/posix_time.hpp>
|
||||
# include <boost/scope_exit.hpp>
|
||||
# include <chrono>
|
||||
# include <optional>
|
||||
# include <random>
|
||||
# include <memory>
|
||||
# include <utility>
|
||||
# include <set>
|
||||
# include <string>
|
||||
# include <list>
|
||||
# include <algorithm>
|
||||
# include <iostream>
|
||||
@@ -92,6 +96,7 @@
|
||||
#include <Base/ProgressIndicatorPy.h>
|
||||
#include <Base/RotationPy.h>
|
||||
#include <Base/UniqueNameManager.h>
|
||||
#include <Base/SystemHandler.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Translate.h>
|
||||
#include <Base/Type.h>
|
||||
@@ -104,6 +109,7 @@
|
||||
#include "Application.h"
|
||||
#include "ApplicationDirectories.h"
|
||||
#include "ApplicationDirectoriesPy.h"
|
||||
#include "ApplicationPy.h"
|
||||
#include "CleanupProcess.h"
|
||||
#include "ComplexGeoData.h"
|
||||
#include "Services.h"
|
||||
@@ -159,18 +165,38 @@
|
||||
|
||||
#include "SafeMode.h"
|
||||
|
||||
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
|
||||
# pragma warning( disable : 4535 )
|
||||
# if !defined(_DEBUG) && defined(HAVE_SEH)
|
||||
# define FC_SE_TRANSLATOR
|
||||
# endif
|
||||
|
||||
# include <new.h>
|
||||
# include <eh.h> // VC exception handling
|
||||
#else // Ansi C/C++ new handler
|
||||
# include <new>
|
||||
#ifdef FC_OS_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
std::optional<std::string> getenvUTF8(const char* name) {
|
||||
#ifdef FC_OS_WIN32
|
||||
int wideLength = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
|
||||
std::wstring wideName(wideLength ? wideLength - 1 : 0, L'\0');
|
||||
if (wideLength) {
|
||||
MultiByteToWideChar(CP_UTF8, 0, name, -1, wideName.data(), wideLength);
|
||||
}
|
||||
|
||||
DWORD needed = GetEnvironmentVariableW(wideName.c_str(), nullptr, 0);
|
||||
if (needed == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::wstring wideValue(needed, L'\0');
|
||||
DWORD written = GetEnvironmentVariableW(wideName.c_str(), wideValue.data(), needed);
|
||||
if (written == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
wideValue.resize(written);
|
||||
return Base::Tools::wstringToString(wideValue);
|
||||
#else
|
||||
if (const char* v = std::getenv(name)) {
|
||||
return std::string(v);
|
||||
}
|
||||
return std::nullopt;
|
||||
#endif
|
||||
}
|
||||
|
||||
FC_LOG_LEVEL_INIT("App", true, true)
|
||||
|
||||
using namespace App;
|
||||
@@ -275,7 +301,7 @@ void Application::setupPythonTypes()
|
||||
Base::PyGILStateLocker lock;
|
||||
PyObject* modules = PyImport_GetModuleDict();
|
||||
|
||||
ApplicationMethods = Application::Methods;
|
||||
ApplicationMethods = ApplicationPy::Methods;
|
||||
PyObject* pAppModule = PyImport_ImportModule ("FreeCAD");
|
||||
if (!pAppModule) {
|
||||
PyErr_Clear();
|
||||
@@ -425,14 +451,6 @@ void Application::setupPythonException(PyObject* module)
|
||||
//**************************************************************************
|
||||
// Interface
|
||||
|
||||
/// get called by the document when the name is changing
|
||||
void Application::renameDocument(const char *OldName, const char *NewName)
|
||||
{
|
||||
(void)OldName;
|
||||
(void)NewName;
|
||||
throw Base::RuntimeError("Renaming document internal name is no longer allowed!");
|
||||
}
|
||||
|
||||
Document* Application::newDocument(const char * proposedName, const char * proposedLabel, DocumentInitFlags CreateFlags)
|
||||
{
|
||||
bool isUsingDefaultName = Base::Tools::isNullOrEmpty(proposedName);
|
||||
@@ -518,6 +536,11 @@ Document* Application::newDocument(const char * proposedName, const char * propo
|
||||
return doc;
|
||||
}
|
||||
|
||||
bool Application::closeDocument(const Document* doc)
|
||||
{
|
||||
return closeDocument(doc->getName());
|
||||
}
|
||||
|
||||
bool Application::closeDocument(const char* name)
|
||||
{
|
||||
const auto pos = DocMap.find( name );
|
||||
@@ -564,6 +587,15 @@ Document* Application::getDocument(const char *Name) const
|
||||
|
||||
return pos->second;
|
||||
}
|
||||
Document* Application::getDocumentOrActive(const char *Name) const
|
||||
{
|
||||
if (!Base::Tools::isNullOrEmpty(Name)) {
|
||||
return getDocument(Name);
|
||||
}
|
||||
else {
|
||||
return getActiveDocument();
|
||||
}
|
||||
}
|
||||
|
||||
const char * Application::getDocumentName(const Document* doc) const
|
||||
{
|
||||
@@ -932,7 +964,7 @@ Document* Application::openDocumentPrivate(const char * FileName,
|
||||
if (!File.exists()) {
|
||||
std::stringstream str;
|
||||
str << "File '" << FileName << "' does not exist!";
|
||||
throw Base::FileSystemError(str.str().c_str());
|
||||
throw Base::FileSystemError(str.str());
|
||||
}
|
||||
|
||||
// Before creating a new document we check whether the document is already open
|
||||
@@ -963,7 +995,7 @@ Document* Application::openDocumentPrivate(const char * FileName,
|
||||
// add it to _pendingDocsReopen to delay reloading.
|
||||
for(auto obj2 : doc->getObjects())
|
||||
objNames.emplace_back(obj2->getNameInDocument());
|
||||
_pendingDocMap[doc->FileName.getValue()] = std::move(objNames);
|
||||
_pendingDocMap[doc->FileName.getValue()] = objNames;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1308,11 +1340,11 @@ Base::Reference<ParameterGrp> Application::GetParameterGroupByPath(const char*
|
||||
return It->second->GetGroup(cName.c_str());
|
||||
}
|
||||
|
||||
void Application::addImportType(const char* Type, const char* ModuleName)
|
||||
void Application::addImportType(const char* filter, const char* moduleName)
|
||||
{
|
||||
FileTypeItem item;
|
||||
item.filter = Type;
|
||||
item.module = ModuleName;
|
||||
item.filter = filter;
|
||||
item.module = moduleName;
|
||||
|
||||
// Extract each filetype from 'Type' literal
|
||||
std::string::size_type pos = item.filter.find("*.");
|
||||
@@ -1325,8 +1357,8 @@ void Application::addImportType(const char* Type, const char* ModuleName)
|
||||
}
|
||||
|
||||
// Due to branding stuff replace "FreeCAD" with the branded application name
|
||||
if (strncmp(Type, "FreeCAD", 7) == 0) {
|
||||
std::string AppName = Config()["ExeName"];
|
||||
if (strncmp(filter, "FreeCAD", 7) == 0) {
|
||||
std::string AppName = getExecutableName();
|
||||
AppName += item.filter.substr(7);
|
||||
item.filter = std::move(AppName);
|
||||
// put to the front of the array
|
||||
@@ -1337,28 +1369,25 @@ void Application::addImportType(const char* Type, const char* ModuleName)
|
||||
}
|
||||
}
|
||||
|
||||
void Application::changeImportModule(const char* Type, const char* OldModuleName, const char* NewModuleName)
|
||||
void Application::changeImportModule(const char* filter, const char* oldModuleName, const char* newModuleName)
|
||||
{
|
||||
for (auto& it : _mImportTypes) {
|
||||
if (it.filter == Type && it.module == OldModuleName) {
|
||||
it.module = NewModuleName;
|
||||
if (it.filter == filter && it.module == oldModuleName) {
|
||||
it.module = newModuleName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Application::getImportModules(const char* Type) const
|
||||
std::vector<std::string> Application::getImportModules(const std::string& extension) const
|
||||
{
|
||||
std::vector<std::string> modules;
|
||||
for (const auto & it : _mImportTypes) {
|
||||
const std::vector<std::string>& types = it.types;
|
||||
for (const auto & jt : types) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Type,jt.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Type,jt.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(extension, jt)) {
|
||||
modules.push_back(it.module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1377,16 +1406,13 @@ std::vector<std::string> Application::getImportModules() const
|
||||
return modules;
|
||||
}
|
||||
|
||||
std::vector<std::string> Application::getImportTypes(const char* Module) const
|
||||
std::vector<std::string> Application::getImportTypes(const std::string& Module) const
|
||||
{
|
||||
std::vector<std::string> types;
|
||||
for (const auto & it : _mImportTypes) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Module,it.module.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Module,it.module.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(Module, it.module)) {
|
||||
types.insert(types.end(), it.types.begin(), it.types.end());
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
@@ -1405,18 +1431,15 @@ std::vector<std::string> Application::getImportTypes() const
|
||||
return types;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> Application::getImportFilters(const char* Type) const
|
||||
std::map<std::string, std::string> Application::getImportFilters(const std::string& extension) const
|
||||
{
|
||||
std::map<std::string, std::string> moduleFilter;
|
||||
for (const auto & it : _mImportTypes) {
|
||||
const std::vector<std::string>& types = it.types;
|
||||
for (const auto & jt : types) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Type,jt.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Type,jt.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(extension, jt)) {
|
||||
moduleFilter[it.filter] = it.module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1433,11 +1456,11 @@ std::map<std::string, std::string> Application::getImportFilters() const
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Application::addExportType(const char* Type, const char* ModuleName)
|
||||
void Application::addExportType(const char* filter, const char* moduleName)
|
||||
{
|
||||
FileTypeItem item;
|
||||
item.filter = Type;
|
||||
item.module = ModuleName;
|
||||
item.filter = filter;
|
||||
item.module = moduleName;
|
||||
|
||||
// Extract each filetype from 'Type' literal
|
||||
std::string::size_type pos = item.filter.find("*.");
|
||||
@@ -1450,8 +1473,8 @@ void Application::addExportType(const char* Type, const char* ModuleName)
|
||||
}
|
||||
|
||||
// Due to branding stuff replace "FreeCAD" with the branded application name
|
||||
if (strncmp(Type, "FreeCAD", 7) == 0) {
|
||||
std::string AppName = Config()["ExeName"];
|
||||
if (strncmp(filter, "FreeCAD", 7) == 0) {
|
||||
std::string AppName = getExecutableName();
|
||||
AppName += item.filter.substr(7);
|
||||
item.filter = std::move(AppName);
|
||||
// put to the front of the array
|
||||
@@ -1462,28 +1485,112 @@ void Application::addExportType(const char* Type, const char* ModuleName)
|
||||
}
|
||||
}
|
||||
|
||||
void Application::changeExportModule(const char* Type, const char* OldModuleName, const char* NewModuleName)
|
||||
namespace {
|
||||
// To enable changing languages while the program is running, cache the translatable export type
|
||||
// entries so that their addition can be "replayed" when the language changes (after removing
|
||||
// the originals).
|
||||
|
||||
struct TranslatableTypeCacheEntry {
|
||||
std::string description;
|
||||
const std::vector<std::string> extensions;
|
||||
std::string moduleName;
|
||||
};
|
||||
|
||||
class TranslatableTypeCache {
|
||||
public:
|
||||
TranslatableTypeCache() = default;
|
||||
void addCacheEntry(TranslatableTypeCacheEntry entry) {
|
||||
_cache.push_back(std::move(entry));
|
||||
}
|
||||
std::vector<TranslatableTypeCacheEntry> getCache() const {
|
||||
return _cache;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
_cache.clear();
|
||||
}
|
||||
private:
|
||||
std::vector<TranslatableTypeCacheEntry> _cache;
|
||||
};
|
||||
|
||||
TranslatableTypeCache translatableExportTypeCache;
|
||||
|
||||
// Given a description string and a list of extensions, construct a type string that Qt's file
|
||||
// dialogs will recognize
|
||||
void appendTypeString(std::string &description, const std::vector<std::string> &extensions) {
|
||||
description = fmt::format("{} (*.{})", description, fmt::join(extensions, " *."));
|
||||
}
|
||||
}
|
||||
|
||||
void Application::addTranslatableExportType(const std::string &description,
|
||||
const std::vector<std::string> &extensions,
|
||||
const std::string &moduleName)
|
||||
{
|
||||
assert(!extensions.empty()); // Programming error, there must be extensions
|
||||
|
||||
// Branding: replace "FreeCAD" in a file type description with the branded application name
|
||||
auto replaceFreeCAD =
|
||||
[](std::string& s)
|
||||
{
|
||||
constexpr std::string_view freecad = "FreeCAD";
|
||||
if (auto pos = s.find(freecad); pos != std::string::npos) {
|
||||
s.replace(pos, freecad.size(), getExecutableName());
|
||||
return true; // Contained the app name
|
||||
}
|
||||
return false; // Did NOT contain the app name
|
||||
};
|
||||
|
||||
translatableExportTypeCache.addCacheEntry({description, extensions, moduleName});
|
||||
auto translatedDescription = QCoreApplication::translate("FileFormat", description.c_str()).toStdString();
|
||||
bool containsAppName = replaceFreeCAD(translatedDescription); // Run *AFTER* translation
|
||||
appendTypeString(translatedDescription, extensions);
|
||||
|
||||
FileTypeItem item;
|
||||
item.filter = translatedDescription;
|
||||
item.module = moduleName;
|
||||
item.types = extensions;
|
||||
item.translatable = true;
|
||||
|
||||
if (containsAppName) {
|
||||
// put to the front of the array
|
||||
_mExportTypes.insert(_mExportTypes.begin(),std::move(item));
|
||||
}
|
||||
else {
|
||||
_mExportTypes.push_back(std::move(item));
|
||||
}
|
||||
}
|
||||
|
||||
void Application::retranslateExportTypes()
|
||||
{
|
||||
auto cache = translatableExportTypeCache.getCache();
|
||||
translatableExportTypeCache.clear();
|
||||
std::erase_if(_mExportTypes, [](const FileTypeItem& item) {
|
||||
return item.translatable;
|
||||
});
|
||||
for (const auto &cacheEntry : translatableExportTypeCache.getCache()) {
|
||||
addTranslatableExportType(cacheEntry.description, cacheEntry.extensions, cacheEntry.moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::changeExportModule(const char* filter, const char* oldModuleName, const char* newModuleName)
|
||||
{
|
||||
for (auto& it : _mExportTypes) {
|
||||
if (it.filter == Type && it.module == OldModuleName) {
|
||||
it.module = NewModuleName;
|
||||
if (it.filter == filter && it.module == oldModuleName) {
|
||||
it.module = newModuleName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> Application::getExportModules(const char* Type) const
|
||||
std::vector<std::string> Application::getExportModules(const std::string& extension) const
|
||||
{
|
||||
std::vector<std::string> modules;
|
||||
for (const auto & it : _mExportTypes) {
|
||||
const std::vector<std::string>& types = it.types;
|
||||
for (const auto & jt : types) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Type,jt.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Type,jt.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(extension, jt)) {
|
||||
modules.push_back(it.module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1502,16 +1609,13 @@ std::vector<std::string> Application::getExportModules() const
|
||||
return modules;
|
||||
}
|
||||
|
||||
std::vector<std::string> Application::getExportTypes(const char* Module) const
|
||||
std::vector<std::string> Application::getExportTypes(const std::string& Module) const
|
||||
{
|
||||
std::vector<std::string> types;
|
||||
for (const auto & it : _mExportTypes) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Module,it.module.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Module,it.module.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(Module, it.module)) {
|
||||
types.insert(types.end(), it.types.begin(), it.types.end());
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
@@ -1530,18 +1634,15 @@ std::vector<std::string> Application::getExportTypes() const
|
||||
return types;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> Application::getExportFilters(const char* Type) const
|
||||
std::map<std::string, std::string> Application::getExportFilters(const std::string& extension) const
|
||||
{
|
||||
std::map<std::string, std::string> moduleFilter;
|
||||
for (const auto & it : _mExportTypes) {
|
||||
const std::vector<std::string>& types = it.types;
|
||||
for (const auto & jt : types) {
|
||||
#ifdef __GNUC__
|
||||
if (strcasecmp(Type,jt.c_str()) == 0)
|
||||
#else
|
||||
if (_stricmp(Type,jt.c_str()) == 0)
|
||||
#endif
|
||||
if (boost::iequals(extension, jt)) {
|
||||
moduleFilter[it.filter] = it.module;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1758,175 +1859,59 @@ void Application::destructObserver()
|
||||
}
|
||||
}
|
||||
|
||||
/** freecadNewHandler()
|
||||
* prints an error message and throws an exception
|
||||
*/
|
||||
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
|
||||
int __cdecl freecadNewHandler(size_t size )
|
||||
namespace
|
||||
{
|
||||
// throw an exception
|
||||
throw Base::MemoryException();
|
||||
return 0;
|
||||
}
|
||||
#else // Ansi C/C++ new handler
|
||||
static void freecadNewHandler ()
|
||||
void initExceptions()
|
||||
{
|
||||
// throw an exception
|
||||
throw Base::MemoryException();
|
||||
// register exception producer types
|
||||
// NOLINTBEGIN
|
||||
new Base::ExceptionProducer<Base::AbortException>;
|
||||
new Base::ExceptionProducer<Base::XMLBaseException>;
|
||||
new Base::ExceptionProducer<Base::XMLParseException>;
|
||||
new Base::ExceptionProducer<Base::XMLAttributeError>;
|
||||
new Base::ExceptionProducer<Base::FileException>;
|
||||
new Base::ExceptionProducer<Base::FileSystemError>;
|
||||
new Base::ExceptionProducer<Base::BadFormatError>;
|
||||
new Base::ExceptionProducer<Base::MemoryException>;
|
||||
new Base::ExceptionProducer<Base::AccessViolation>;
|
||||
new Base::ExceptionProducer<Base::AbnormalProgramTermination>;
|
||||
new Base::ExceptionProducer<Base::UnknownProgramOption>;
|
||||
new Base::ExceptionProducer<Base::ProgramInformation>;
|
||||
new Base::ExceptionProducer<Base::TypeError>;
|
||||
new Base::ExceptionProducer<Base::ValueError>;
|
||||
new Base::ExceptionProducer<Base::IndexError>;
|
||||
new Base::ExceptionProducer<Base::NameError>;
|
||||
new Base::ExceptionProducer<Base::ImportError>;
|
||||
new Base::ExceptionProducer<Base::AttributeError>;
|
||||
new Base::ExceptionProducer<Base::RuntimeError>;
|
||||
new Base::ExceptionProducer<Base::BadGraphError>;
|
||||
new Base::ExceptionProducer<Base::NotImplementedError>;
|
||||
new Base::ExceptionProducer<Base::ZeroDivisionError>;
|
||||
new Base::ExceptionProducer<Base::ReferenceError>;
|
||||
new Base::ExceptionProducer<Base::ExpressionError>;
|
||||
new Base::ExceptionProducer<Base::ParserError>;
|
||||
new Base::ExceptionProducer<Base::UnicodeError>;
|
||||
new Base::ExceptionProducer<Base::OverflowError>;
|
||||
new Base::ExceptionProducer<Base::UnderflowError>;
|
||||
new Base::ExceptionProducer<Base::UnitsMismatchError>;
|
||||
new Base::ExceptionProducer<Base::CADKernelError>;
|
||||
new Base::ExceptionProducer<Base::RestoreError>;
|
||||
new Base::ExceptionProducer<Base::PropertyError>;
|
||||
// NOLINTEND
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FC_OS_LINUX)
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
// This function produces a stack backtrace with demangled function & method names.
|
||||
void printBacktrace(size_t skip=0)
|
||||
{
|
||||
#if defined HAVE_BACKTRACE_SYMBOLS
|
||||
void *callstack[128];
|
||||
size_t nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
|
||||
size_t nFrames = backtrace(callstack, nMaxFrames);
|
||||
char **symbols = backtrace_symbols(callstack, nFrames);
|
||||
|
||||
for (size_t i = skip; i < nFrames; i++) {
|
||||
char *demangled = nullptr;
|
||||
int status = -1;
|
||||
Dl_info info;
|
||||
if (dladdr(callstack[i], &info) && info.dli_sname && info.dli_fname) {
|
||||
if (info.dli_sname[0] == '_') {
|
||||
demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
if (status == 0) {
|
||||
void* offset = (void*)((char*)callstack[i] - (char*)info.dli_saddr);
|
||||
str << "#" << (i-skip) << " " << callstack[i] << " in " << demangled << " from " << info.dli_fname << "+" << offset << '\n';
|
||||
free(demangled);
|
||||
}
|
||||
else {
|
||||
str << "#" << (i-skip) << " " << symbols[i] << '\n';
|
||||
}
|
||||
|
||||
// cannot directly print to cerr when using --write-log
|
||||
std::cerr << str.str();
|
||||
}
|
||||
|
||||
free(symbols);
|
||||
#else //HAVE_BACKTRACE_SYMBOLS
|
||||
(void)skip;
|
||||
std::cerr << "Cannot print the stacktrace because the C runtime library doesn't provide backtrace or backtrace_symbols\n";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void segmentation_fault_handler(int sig)
|
||||
{
|
||||
#if defined(FC_OS_LINUX)
|
||||
(void)sig;
|
||||
std::cerr << "Program received signal SIGSEGV, Segmentation fault.\n";
|
||||
printBacktrace(2);
|
||||
#if defined(FC_DEBUG)
|
||||
abort();
|
||||
#else
|
||||
_exit(1);
|
||||
#endif
|
||||
#else
|
||||
switch (sig) {
|
||||
case SIGSEGV:
|
||||
std::cerr << "Illegal storage access..." << '\n';
|
||||
#if !defined(_DEBUG)
|
||||
throw Base::AccessViolation("Illegal storage access! Please save your work under a new file name and restart the application!");
|
||||
#endif
|
||||
break;
|
||||
case SIGABRT:
|
||||
std::cerr << "Abnormal program termination..." << '\n';
|
||||
#if !defined(_DEBUG)
|
||||
throw Base::AbnormalProgramTermination("Break signal occurred");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown error occurred..." << '\n';
|
||||
break;
|
||||
}
|
||||
#endif // FC_OS_LINUX
|
||||
}
|
||||
|
||||
void unhandled_exception_handler()
|
||||
{
|
||||
std::cerr << "Terminating..." << '\n';
|
||||
}
|
||||
|
||||
void unexpection_error_handler()
|
||||
{
|
||||
std::cerr << "Unexpected error occurred..." << '\n';
|
||||
// try to throw an exception and give the user chance to save their work
|
||||
#if !defined(_DEBUG)
|
||||
throw Base::AbnormalProgramTermination("Unexpected error occurred! Please save your work under a new file name and restart the application!");
|
||||
#else
|
||||
terminate();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(FC_SE_TRANSLATOR) // Microsoft compiler
|
||||
void my_se_translator_filter(unsigned int code, EXCEPTION_POINTERS* pExp)
|
||||
{
|
||||
Q_UNUSED(pExp)
|
||||
switch (code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
throw Base::AccessViolation();
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
Base::Console().error("SEH exception (%u): Division by zero\n", code);
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << "SEH exception of type: " << code;
|
||||
// general C++ SEH exception for things we don't need to handle separately....
|
||||
throw Base::RuntimeError(str.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::init(int argc, char ** argv)
|
||||
{
|
||||
try {
|
||||
// install our own new handler
|
||||
#ifdef _MSC_VER // Microsoft compiler
|
||||
_set_new_handler ( freecadNewHandler ); // Setup new handler
|
||||
_set_new_mode( 1 ); // Re-route malloc failures to new handler !
|
||||
#else // Ansi compiler
|
||||
std::set_new_handler (freecadNewHandler); // ANSI new handler
|
||||
#endif
|
||||
// if an unexpected crash occurs we can install a handler function to
|
||||
// write some additional information
|
||||
#if defined (_MSC_VER) // Microsoft compiler
|
||||
std::signal(SIGSEGV,segmentation_fault_handler);
|
||||
std::signal(SIGABRT,segmentation_fault_handler);
|
||||
std::set_terminate(unhandled_exception_handler);
|
||||
::set_unexpected(unexpection_error_handler);
|
||||
#elif defined(FC_OS_LINUX)
|
||||
std::signal(SIGSEGV,segmentation_fault_handler);
|
||||
#endif
|
||||
#if defined(FC_SE_TRANSLATOR)
|
||||
_set_se_translator(my_se_translator_filter);
|
||||
#endif
|
||||
Base::SystemHandler::installNewHandler();
|
||||
Base::SystemHandler::installSegfaultHandler();
|
||||
|
||||
initTypes();
|
||||
|
||||
initConfig(argc,argv);
|
||||
initApplication();
|
||||
initExceptions();
|
||||
}
|
||||
catch (...) {
|
||||
// force the log to flush
|
||||
@@ -2166,6 +2151,7 @@ void Application::initTypes()
|
||||
(DocumentObject::getClassTypeId());
|
||||
|
||||
// register exception producer types
|
||||
// NOLINTBEGIN
|
||||
new Base::ExceptionProducer<Base::AbortException>;
|
||||
new Base::ExceptionProducer<Base::XMLBaseException>;
|
||||
new Base::ExceptionProducer<Base::XMLParseException>;
|
||||
@@ -2198,6 +2184,7 @@ void Application::initTypes()
|
||||
new Base::ExceptionProducer<Base::CADKernelError>;
|
||||
new Base::ExceptionProducer<Base::RestoreError>;
|
||||
new Base::ExceptionProducer<Base::PropertyError>;
|
||||
// NOLINTEND
|
||||
|
||||
Base::registerServiceImplementation<CenterOfMassProvider>(new NullCenterOfMass);
|
||||
}
|
||||
@@ -2514,7 +2501,9 @@ void processProgramOptions(const boost::program_options::variables_map& vm, std:
|
||||
void Application::initConfig(int argc, char ** argv)
|
||||
{
|
||||
// find the home path....
|
||||
mConfig["AppHomePath"] = ApplicationDirectories::findHomePath(argv[0]).string();
|
||||
mConfig["AppHomePath"] = Base::FileInfo::pathToString(
|
||||
ApplicationDirectories::findHomePath(argv[0])
|
||||
);
|
||||
|
||||
// Version of the application extracted from SubWCRef into src/Build/Version.h
|
||||
// We only set these keys if not yet defined. Therefore it suffices to search
|
||||
@@ -2600,7 +2589,7 @@ void Application::initConfig(int argc, char ** argv)
|
||||
|
||||
auto moduleName = "FreeCAD";
|
||||
PyImport_AddModule(moduleName);
|
||||
ApplicationMethods = Application::Methods;
|
||||
ApplicationMethods = ApplicationPy::Methods;
|
||||
PyObject *pyModule = init_freecad_module();
|
||||
PyDict_SetItemString(sysModules, moduleName, pyModule);
|
||||
Py_DECREF(pyModule);
|
||||
@@ -2761,9 +2750,9 @@ void Application::initConfig(int argc, char ** argv)
|
||||
|
||||
void Application::SaveEnv(const char* s)
|
||||
{
|
||||
const char *c = getenv(s);
|
||||
if (c)
|
||||
mConfig[s] = c;
|
||||
if (auto c = getenvUTF8(s)) {
|
||||
mConfig[s] = c.value();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::initApplication()
|
||||
@@ -2828,7 +2817,18 @@ std::list<std::string> Application::processFiles(const std::list<std::string>& f
|
||||
std::list<std::string> processed;
|
||||
Base::Console().log("Init: Processing command line files\n");
|
||||
for (const auto & it : files) {
|
||||
|
||||
Base::FileInfo file(it);
|
||||
// Can we safely remove the isSymlink check and directly query the canonical
|
||||
// path for every string? The reason for avoiding it currently is that
|
||||
// getCannonicalPath will log an error if the file doesn't exist
|
||||
if (file.isSymlink()) {
|
||||
if (auto cannonicalPath = file.getCannonicalPath()) {
|
||||
file = Base::FileInfo(*cannonicalPath);
|
||||
} else {
|
||||
Base::Console().error("Failed to process symlink file: %s\n", file.filePath());
|
||||
}
|
||||
}
|
||||
|
||||
Base::Console().log("Init: Processing file: %s\n",file.filePath().c_str());
|
||||
|
||||
@@ -2855,8 +2855,7 @@ std::list<std::string> Application::processFiles(const std::list<std::string>& f
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string ext = file.extension();
|
||||
std::vector<std::string> mods = GetApplication().getImportModules(ext.c_str());
|
||||
std::vector<std::string> mods = GetApplication().getImportModules(file.extension());
|
||||
if (!mods.empty()) {
|
||||
std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(file.filePath().c_str());
|
||||
escapedstr = Base::Tools::escapeEncodeFilename(escapedstr);
|
||||
@@ -2889,7 +2888,6 @@ std::list<std::string> Application::processFiles(const std::list<std::string>& f
|
||||
|
||||
void Application::processCmdLineFiles()
|
||||
{
|
||||
// process files passed to command line
|
||||
const std::list<std::string> files = getCmdLineFiles();
|
||||
const std::list<std::string> processed = processFiles(files);
|
||||
|
||||
@@ -2914,9 +2912,8 @@ void Application::processCmdLineFiles()
|
||||
output = Base::Tools::escapeEncodeFilename(output);
|
||||
|
||||
const Base::FileInfo fi(output);
|
||||
const std::string ext = fi.extension();
|
||||
try {
|
||||
const std::vector<std::string> mods = GetApplication().getExportModules(ext.c_str());
|
||||
const std::vector<std::string> mods = GetApplication().getExportModules(fi.extension());
|
||||
if (!mods.empty()) {
|
||||
Base::Interpreter().loadModule(mods.front().c_str());
|
||||
Base::Interpreter().runStringArg("import %s",mods.front().c_str());
|
||||
@@ -3432,9 +3429,9 @@ std::string Application::FindHomePath(const char* sCall)
|
||||
}
|
||||
|
||||
// should be an absolute path now
|
||||
std::string::size_type pos = absPath.find_last_of("/");
|
||||
std::string::size_type pos = absPath.find_last_of('/');
|
||||
homePath.assign(absPath,0,pos);
|
||||
pos = homePath.find_last_of("/");
|
||||
pos = homePath.find_last_of('/');
|
||||
homePath.assign(homePath,0,pos+1);
|
||||
|
||||
return homePath;
|
||||
@@ -3584,14 +3581,18 @@ void Application::addModuleInfo(QTextStream& str, const QString& modPath, bool&
|
||||
firstMod = false;
|
||||
str << "Installed mods: \n";
|
||||
}
|
||||
str << " * " << (mod.isDir() ? QDir(modPath).dirName() : mod.fileName());
|
||||
QString addonName = mod.isDir() ? QDir(modPath).dirName() : mod.fileName();
|
||||
QString versionString;
|
||||
try {
|
||||
auto metadataFile =
|
||||
std::filesystem::path(mod.absoluteFilePath().toStdString()) / "package.xml";
|
||||
if (std::filesystem::exists(metadataFile)) {
|
||||
App::Metadata metadata(metadataFile);
|
||||
if (!metadata.name().empty()) {
|
||||
addonName = QString::fromStdString(metadata.name());
|
||||
}
|
||||
if (metadata.version() != App::Meta::Version()) {
|
||||
str << QLatin1String(" ") + QString::fromStdString(metadata.version().str());
|
||||
versionString = QString::fromStdString(" " + metadata.version().str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3600,6 +3601,7 @@ void Application::addModuleInfo(QTextStream& str, const QString& modPath, bool&
|
||||
QChar::fromLatin1(' '));
|
||||
str << " (Malformed metadata: " << what << ")";
|
||||
}
|
||||
str << " * " << addonName << versionString;
|
||||
QFileInfo disablingFile(mod.absoluteFilePath(), QStringLiteral("ADDON_DISABLED"));
|
||||
if (disablingFile.exists()) {
|
||||
str << " (Disabled)";
|
||||
@@ -3622,7 +3624,7 @@ void Application::getVerboseCommonInfo(QTextStream& str, const std::map<std::str
|
||||
const QString deskSess =
|
||||
QProcessEnvironment::systemEnvironment().value(QStringLiteral("DESKTOP_SESSION"),
|
||||
QString());
|
||||
|
||||
|
||||
const QString major = getValueOrEmpty(mConfig, "BuildVersionMajor");
|
||||
const QString minor = getValueOrEmpty(mConfig, "BuildVersionMinor");
|
||||
const QString point = getValueOrEmpty(mConfig, "BuildVersionPoint");
|
||||
@@ -3711,24 +3713,23 @@ void Application::getVerboseCommonInfo(QTextStream& str, const std::map<std::str
|
||||
#endif
|
||||
str << "xerces-c " << fcXercescVersion << ", ";
|
||||
|
||||
const char* cmd = "import ifcopenshell\n"
|
||||
"version = ifcopenshell.version";
|
||||
PyObject * ifcopenshellVer = nullptr;
|
||||
|
||||
try {
|
||||
ifcopenshellVer = Base::Interpreter().getValue(cmd, "version");
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
Base::Console().log("%s (safe to ignore, unless using the BIM workbench and IFC).\n", e.what());
|
||||
}
|
||||
|
||||
if (ifcopenshellVer) {
|
||||
const char* ifcopenshellVerAsStr = PyUnicode_AsUTF8(ifcopenshellVer);
|
||||
|
||||
if (ifcopenshellVerAsStr) {
|
||||
str << "IfcOpenShell " << ifcopenshellVerAsStr << ", ";
|
||||
Base::PyGILStateLocker lock;
|
||||
Py::Module module(PyImport_ImportModule("ifcopenshell"), true);
|
||||
if (!module.isNull() && module.hasAttr("version")) {
|
||||
Py::String version(module.getAttr("version"));
|
||||
auto ver_str = static_cast<std::string>(version);
|
||||
str << "IfcOpenShell " << ver_str.c_str() << ", ";
|
||||
}
|
||||
Py_DECREF(ifcopenshellVer);
|
||||
else {
|
||||
Base::Console().log("Module 'ifcopenshell' not found (safe to ignore, unless using "
|
||||
"the BIM workbench and IFC).\n");
|
||||
}
|
||||
}
|
||||
catch (const Py::Exception&) {
|
||||
Base::PyGILStateLocker lock;
|
||||
Base::PyException e;
|
||||
Base::Console().log("%s\n", e.what());
|
||||
}
|
||||
|
||||
#if defined(HAVE_OCC_VERSION)
|
||||
|
||||
+758
-367
File diff suppressed because it is too large
Load Diff
@@ -80,12 +80,16 @@ const fs::path& ApplicationDirectories::getTempPath() const {
|
||||
return this->_temp;
|
||||
}
|
||||
|
||||
fs::path ApplicationDirectories::getTempFileName(const std::string & filename) const {
|
||||
fs::path ApplicationDirectories::getTempFileName(const std::string & filename) const
|
||||
{
|
||||
auto tempPath = Base::FileInfo::pathToString(getTempPath());
|
||||
if (filename.empty()) {
|
||||
return Base::FileInfo::getTempFileName(nullptr, tempPath.c_str());
|
||||
return Base::FileInfo::stringToPath(Base::FileInfo::getTempFileName(nullptr, tempPath.c_str())
|
||||
);
|
||||
}
|
||||
return Base::FileInfo::getTempFileName(filename.c_str(), tempPath.c_str());
|
||||
return Base::FileInfo::stringToPath(
|
||||
Base::FileInfo::getTempFileName(filename.c_str(), tempPath.c_str())
|
||||
);
|
||||
}
|
||||
|
||||
const fs::path& ApplicationDirectories::getUserCachePath() const
|
||||
@@ -138,7 +142,10 @@ fs::path ApplicationDirectories::findPath(const fs::path& stdHome, const fs::pat
|
||||
// If a custom user home path is given, then don't modify it
|
||||
if (customHome.empty()) {
|
||||
for (const auto& it : subdirs) {
|
||||
appData = appData / it;
|
||||
if (!it.empty()) {
|
||||
// Refuse to add an empty directory path component
|
||||
appData = appData / it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +186,7 @@ void ApplicationDirectories::configurePaths(std::map<std::string,std::string>& m
|
||||
bool keepDeprecatedPaths = mConfig.contains("KeepDeprecatedPaths");
|
||||
|
||||
// std paths
|
||||
_home = fs::path(mConfig.at("AppHomePath"));
|
||||
_home = Base::FileInfo::stringToPath(mConfig.at("AppHomePath"));
|
||||
mConfig["BinPath"] = mConfig.at("AppHomePath") + "bin" + PATHSEP;
|
||||
mConfig["DocPath"] = mConfig.at("AppHomePath") + "doc" + PATHSEP;
|
||||
|
||||
@@ -295,7 +302,7 @@ void ApplicationDirectories::configureResourceDirectory(const std::map<std::stri
|
||||
_resource = Base::FileInfo::stringToPath(mConfig.at("AppHomePath")) / path;
|
||||
}
|
||||
#else
|
||||
_resource = fs::path(mConfig.at("AppHomePath"));
|
||||
_resource = Base::FileInfo::stringToPath(mConfig.at("AppHomePath"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
* *
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef SRC_APP_APPLICATIONDIRECTORIES_H_
|
||||
#define SRC_APP_APPLICATIONDIRECTORIES_H_
|
||||
#pragma once
|
||||
|
||||
#include "FCConfig.h"
|
||||
#include "FCGlobal.h"
|
||||
@@ -257,5 +256,3 @@ namespace App {
|
||||
};
|
||||
|
||||
} // App
|
||||
|
||||
#endif //SRC_APP_APPLICATIONDIRECTORIES_H_
|
||||
|
||||
+272
-197
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
|
||||
* *
|
||||
* This file is part of FreeCAD. *
|
||||
* *
|
||||
* FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as *
|
||||
* published by the Free Software Foundation, either version 2.1 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* FreeCAD 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with FreeCAD. If not, see *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
/** The ApplicationPy class
|
||||
* This is the Python wrapper class of Application.
|
||||
* @author Jürgen Riegel, Werner Mayer
|
||||
*/
|
||||
class AppExport ApplicationPy
|
||||
{
|
||||
public:
|
||||
// clang-format off
|
||||
// static python wrapper of the exported functions
|
||||
static PyObject* sGetParam (PyObject *self, PyObject *args);
|
||||
static PyObject* sSaveParameter (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetVersion (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetConfig (PyObject *self, PyObject *args);
|
||||
static PyObject* sSetConfig (PyObject *self, PyObject *args);
|
||||
static PyObject* sDumpConfig (PyObject *self, PyObject *args);
|
||||
static PyObject* sAddImportType (PyObject *self, PyObject *args);
|
||||
static PyObject* sChangeImportModule (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetImportType (PyObject *self, PyObject *args);
|
||||
static PyObject* sAddExportType (PyObject *self, PyObject *args);
|
||||
static PyObject* sAddTranslatableExportType (PyObject *self, PyObject *args);
|
||||
static PyObject* sChangeExportModule (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetExportType (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetResourcePath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetLibraryPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetTempPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetUserCachePath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetUserConfigPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetUserAppDataPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetUserMacroPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetHelpPath (PyObject *self, PyObject *args);
|
||||
static PyObject* sGetHomePath (PyObject *self, PyObject *args);
|
||||
|
||||
static PyObject* sLoadFile (PyObject *self,PyObject *args);
|
||||
static PyObject* sOpenDocument (PyObject *self,PyObject *args, PyObject *kwd);
|
||||
static PyObject* sSaveDocument (PyObject *self,PyObject *args);
|
||||
static PyObject* sNewDocument (PyObject *self,PyObject *args, PyObject *kwd);
|
||||
static PyObject* sCloseDocument (PyObject *self,PyObject *args);
|
||||
static PyObject* sActiveDocument (PyObject *self,PyObject *args);
|
||||
static PyObject* sSetActiveDocument (PyObject *self,PyObject *args);
|
||||
static PyObject* sGetDocument (PyObject *self,PyObject *args);
|
||||
static PyObject* sListDocuments (PyObject *self,PyObject *args);
|
||||
static PyObject* sAddDocObserver (PyObject *self,PyObject *args);
|
||||
static PyObject* sRemoveDocObserver (PyObject *self,PyObject *args);
|
||||
static PyObject *sIsRestoring (PyObject *self,PyObject *args);
|
||||
|
||||
static PyObject *sSetLogLevel (PyObject *self,PyObject *args);
|
||||
static PyObject *sGetLogLevel (PyObject *self,PyObject *args);
|
||||
|
||||
static PyObject *sCheckLinkDepth (PyObject *self,PyObject *args);
|
||||
static PyObject *sGetLinksTo (PyObject *self,PyObject *args);
|
||||
|
||||
static PyObject *sGetDependentObjects (PyObject *self,PyObject *args);
|
||||
|
||||
static PyObject *sSetActiveTransaction (PyObject *self,PyObject *args);
|
||||
static PyObject *sGetActiveTransaction (PyObject *self,PyObject *args);
|
||||
static PyObject *sCloseActiveTransaction (PyObject *self,PyObject *args);
|
||||
static PyObject *sCheckAbort (PyObject *self,PyObject *args);
|
||||
static PyMethodDef Methods[];
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
}
|
||||
+167
-167
@@ -35,204 +35,217 @@ FC_LOG_LEVEL_INIT("App", true, true)
|
||||
|
||||
using namespace App;
|
||||
|
||||
static int _TransactionLock;
|
||||
static int _TransactionClosed;
|
||||
|
||||
AutoTransaction::AutoTransaction(const char* name, bool tmpName)
|
||||
AutoTransaction::AutoTransaction(int tid)
|
||||
: tid(tid)
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
if (name && app._activeTransactionGuard >= 0) {
|
||||
if (!app.getActiveTransaction() || (!tmpName && app._activeTransactionTmpName)) {
|
||||
FC_LOG("auto transaction '" << name << "', " << tmpName);
|
||||
tid = app.setActiveTransaction(name);
|
||||
app._activeTransactionTmpName = tmpName;
|
||||
}
|
||||
}
|
||||
// We use negative transaction guard to disable auto transaction from here
|
||||
// and any stack below. This is to support user setting active transaction
|
||||
// before having any existing AutoTransaction on stack, or 'persist'
|
||||
// transaction that can out live AutoTransaction.
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
--app._activeTransactionGuard;
|
||||
}
|
||||
else if (tid || app._activeTransactionGuard > 0) {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
else if (app.getActiveTransaction()) {
|
||||
FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'");
|
||||
--app._activeTransactionGuard;
|
||||
}
|
||||
else {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
FC_TRACE("construct auto Transaction " << app._activeTransactionGuard);
|
||||
|
||||
}
|
||||
AutoTransaction::AutoTransaction(Document* doc, const std::string& name)
|
||||
: AutoTransaction(doc->openTransaction(name))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AutoTransaction::~AutoTransaction()
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard);
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
else if (!app._activeTransactionGuard) {
|
||||
#ifdef FC_DEBUG
|
||||
FC_ERR("Transaction guard error");
|
||||
#endif
|
||||
}
|
||||
else if (--app._activeTransactionGuard == 0) {
|
||||
try {
|
||||
// We don't call close() here, because close() only closes
|
||||
// transaction that we opened during construction time. However,
|
||||
// when _activeTransactionGuard reaches zero here, we are supposed
|
||||
// to close any transaction opened.
|
||||
app.closeActiveTransaction();
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
e.reportException();
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard);
|
||||
close(TransactionCloseMode::Commit);
|
||||
}
|
||||
|
||||
void AutoTransaction::close(bool abort)
|
||||
void AutoTransaction::close(TransactionCloseMode mode)
|
||||
{
|
||||
if (tid || abort) {
|
||||
GetApplication().closeActiveTransaction(abort, abort ? 0 : tid);
|
||||
if (tid != NullTransaction) {
|
||||
GetApplication().closeActiveTransaction(mode, tid);
|
||||
tid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AutoTransaction::setEnable(bool enable)
|
||||
int Application::setActiveTransaction(TransactionName name)
|
||||
{
|
||||
auto& app = GetApplication();
|
||||
if (!app._activeTransactionGuard) {
|
||||
return;
|
||||
if (name.name.empty()) {
|
||||
name.name = "Command";
|
||||
}
|
||||
if ((enable && app._activeTransactionGuard > 0)
|
||||
|| (!enable && app._activeTransactionGuard < 0)) {
|
||||
return;
|
||||
}
|
||||
app._activeTransactionGuard = -app._activeTransactionGuard;
|
||||
FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard);
|
||||
if (!enable && app._activeTransactionTmpName) {
|
||||
bool close = true;
|
||||
for (auto& v : app.DocMap) {
|
||||
if (v.second->hasPendingTransaction()) {
|
||||
close = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (close) {
|
||||
app.closeActiveTransaction();
|
||||
}
|
||||
|
||||
if (_pActiveDoc != nullptr) {
|
||||
return _pActiveDoc->setActiveTransaction(name);
|
||||
}
|
||||
return openGlobalTransaction(name);
|
||||
}
|
||||
|
||||
int Application::setActiveTransaction(const char* name, bool persist)
|
||||
std::string Application::getActiveTransaction(int* id) const
|
||||
{
|
||||
if (id != nullptr) {
|
||||
*id = _globalTransactionID;
|
||||
}
|
||||
return _globalTransactionID != 0 ? getTransactionName(_globalTransactionID) : "";
|
||||
}
|
||||
int Application::openGlobalTransaction(TransactionName name)
|
||||
{
|
||||
if (name.name.empty()) {
|
||||
name.name = "Command";
|
||||
}
|
||||
|
||||
if (!name || !name[0]) {
|
||||
name = "Command";
|
||||
}
|
||||
|
||||
this->signalBeforeOpenTransaction(name);
|
||||
if (_activeTransactionGuard > 0 && getActiveTransaction()) {
|
||||
if (_activeTransactionTmpName) {
|
||||
FC_LOG("transaction rename to '" << name << "'");
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(name, _activeTransactionID);
|
||||
FC_WARN("Setting a global transaction with name='" << name.name);
|
||||
if (_globalTransactionID != 0 && transactionTmpName(_globalTransactionID)) {
|
||||
setTransactionName(_globalTransactionID, name);
|
||||
} else {
|
||||
FC_LOG("set global transaction '" << name.name << "'");
|
||||
|
||||
if (_globalTransactionID != 0 && !commitTransaction(_globalTransactionID)) {
|
||||
FC_WARN("could not close current global transaction");
|
||||
return _globalTransactionID;
|
||||
}
|
||||
|
||||
_globalTransactionID = Transaction::getNewID();
|
||||
setTransactionDescription(
|
||||
_globalTransactionID,
|
||||
TransactionDescription {
|
||||
.initiator = nullptr,
|
||||
.name = name
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (_TransactionLock) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
|
||||
}
|
||||
return 0;
|
||||
|
||||
return _globalTransactionID;
|
||||
}
|
||||
int Application::getGlobalTransaction() const
|
||||
{
|
||||
return _globalTransactionID;
|
||||
}
|
||||
bool Application::transactionIsActive(int tid) const
|
||||
{
|
||||
return transactionDescription(tid) != std::nullopt;
|
||||
}
|
||||
std::string Application::getTransactionName(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->name.name : "";
|
||||
}
|
||||
bool Application::transactionTmpName(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->name.temporary : false;
|
||||
}
|
||||
Document* Application::transactionInitiator(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->initiator : nullptr;
|
||||
}
|
||||
std::optional<TransactionDescription> Application::transactionDescription(int tid) const
|
||||
{
|
||||
if (tid == NullTransaction) {
|
||||
return std::nullopt;
|
||||
}
|
||||
else {
|
||||
FC_LOG("set active transaction '" << name << "'");
|
||||
_activeTransactionID = 0;
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
if (found != _activeTransactionDescriptions.end()) {
|
||||
return std::optional<TransactionDescription>(found->second);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
void Application::setTransactionDescription(int tid, const TransactionDescription& desc)
|
||||
{
|
||||
if (tid == NullTransaction) {
|
||||
return;
|
||||
}
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
bool wasPresent = (found != _activeTransactionDescriptions.end());
|
||||
|
||||
if (wasPresent && found->second.name.temporary) {
|
||||
for (auto& v : DocMap) {
|
||||
v.second->_commitTransaction();
|
||||
v.second->renameTransaction(desc.name.name, tid);
|
||||
}
|
||||
_activeTransactionID = Transaction::getNewID();
|
||||
}
|
||||
_activeTransactionTmpName = false;
|
||||
_activeTransactionName = name;
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
|
||||
if (!wasPresent || found->second.name.temporary) {
|
||||
_activeTransactionDescriptions[tid] = desc;
|
||||
FC_LOG("transaction rename to '" << desc.name.name << "'");
|
||||
}
|
||||
return _activeTransactionID;
|
||||
}
|
||||
void Application::setTransactionName(int tid, const TransactionName& name)
|
||||
{
|
||||
if (tid == NullTransaction || !transactionIsActive(tid)) {
|
||||
return;
|
||||
}
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
if (found == _activeTransactionDescriptions.end() || found->second.name.temporary) {
|
||||
_activeTransactionDescriptions[tid].name = name;
|
||||
FC_LOG("transaction rename to '" << name.name << "'");
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(name.name, tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* Application::getActiveTransaction(int* id) const
|
||||
bool Application::closeActiveTransaction(TransactionCloseMode mode, int id)
|
||||
{
|
||||
int tid = 0;
|
||||
if (Transaction::getLastID() == _activeTransactionID) {
|
||||
tid = _activeTransactionID;
|
||||
}
|
||||
if (id) {
|
||||
*id = tid;
|
||||
}
|
||||
return tid ? _activeTransactionName.c_str() : nullptr;
|
||||
}
|
||||
|
||||
void Application::closeActiveTransaction(bool abort, int id)
|
||||
{
|
||||
if (!id) {
|
||||
id = _activeTransactionID;
|
||||
}
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_activeTransactionGuard > 0 && !abort) {
|
||||
FC_LOG("ignore close transaction");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_TransactionLock) {
|
||||
if (_TransactionClosed >= 0) {
|
||||
_TransactionLock = abort ? -1 : 1;
|
||||
bool abort = (mode == TransactionCloseMode::Abort);
|
||||
|
||||
if (id == NullTransaction) {
|
||||
if (_pActiveDoc != nullptr && _pActiveDoc->getBookedTransactionID() != NullTransaction) {
|
||||
id = _pActiveDoc->getBookedTransactionID();
|
||||
} else {
|
||||
id = _globalTransactionID;
|
||||
}
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
return;
|
||||
}
|
||||
if (id == NullTransaction || id == currentlyClosingID) {
|
||||
return false;
|
||||
}
|
||||
currentlyClosingID = id;
|
||||
|
||||
FC_LOG("close transaction '" << _activeTransactionName << "' " << abort);
|
||||
_activeTransactionID = 0;
|
||||
|
||||
TransactionSignaller signaller(abort, false);
|
||||
for (auto& v : DocMap) {
|
||||
if (v.second->getTransactionID(true) != id) {
|
||||
std::vector<Document*> docsToPoke;
|
||||
for (auto& docNameAndDoc : DocMap) {
|
||||
if (docNameAndDoc.second->getBookedTransactionID() != id) {
|
||||
continue;
|
||||
}
|
||||
if(docNameAndDoc.second->isTransactionLocked() || docNameAndDoc.second->transacting()) {
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
currentlyClosingID = 0;
|
||||
return false;
|
||||
}
|
||||
if(docNameAndDoc.second->transacting()) {
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
currentlyClosingID = 0;
|
||||
return false;
|
||||
}
|
||||
docsToPoke.push_back(docNameAndDoc.second);
|
||||
}
|
||||
|
||||
FC_LOG("close transaction '" << _activeTransactionDescriptions[id].name.name << "' " << abort);
|
||||
_activeTransactionDescriptions.erase(id);
|
||||
if (id == _globalTransactionID) {
|
||||
_globalTransactionID = 0;
|
||||
}
|
||||
|
||||
TransactionSignaller signaller(abort, false);
|
||||
|
||||
for (auto& doc : docsToPoke) {
|
||||
if (abort) {
|
||||
v.second->_abortTransaction();
|
||||
doc->_abortTransaction();
|
||||
}
|
||||
else {
|
||||
v.second->_commitTransaction();
|
||||
doc->_commitTransaction();
|
||||
}
|
||||
}
|
||||
currentlyClosingID = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Application::commitTransaction(int tid)
|
||||
{
|
||||
return closeActiveTransaction(TransactionCloseMode::Commit, tid);
|
||||
}
|
||||
bool Application::abortTransaction(int tid)
|
||||
{
|
||||
return closeActiveTransaction(TransactionCloseMode::Abort, tid);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TransactionLocker::TransactionLocker(bool lock)
|
||||
TransactionLocker::TransactionLocker(Document* doc, bool lock)
|
||||
: active(lock)
|
||||
, doc(doc)
|
||||
{
|
||||
if (lock) {
|
||||
++_TransactionLock;
|
||||
doc->lockTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,22 +280,9 @@ void TransactionLocker::activate(bool enable)
|
||||
|
||||
active = enable;
|
||||
if (active) {
|
||||
++_TransactionLock;
|
||||
doc->lockTransaction();
|
||||
return;
|
||||
}
|
||||
|
||||
if (--_TransactionLock != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_TransactionClosed) {
|
||||
bool abort = (_TransactionClosed < 0);
|
||||
_TransactionClosed = 0;
|
||||
GetApplication().closeActiveTransaction(abort);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransactionLocker::isLocked()
|
||||
{
|
||||
return _TransactionLock > 0;
|
||||
doc->unlockTransaction();
|
||||
}
|
||||
|
||||
+24
-53
@@ -22,16 +22,19 @@
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef APP_AUTOTRANSACTION_H
|
||||
#define APP_AUTOTRANSACTION_H
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <FCGlobal.h>
|
||||
#include <string>
|
||||
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Application;
|
||||
class Document;
|
||||
|
||||
/**
|
||||
* @brief A helper class to manage transactions (i.e. undo/redo).
|
||||
@@ -46,59 +49,31 @@ public:
|
||||
void* operator new(std::size_t) = delete;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct an auto transaction.
|
||||
*
|
||||
* @param[in] name: optional new transaction name on construction
|
||||
* @param[in] tmpName: if true and a new transaction is setup, the name given is
|
||||
* considered as temporary, and subsequent construction of this class (or
|
||||
* calling Application::setActiveTransaction()) can override the transaction
|
||||
* name.
|
||||
*
|
||||
* The constructor increments an internal counter
|
||||
* (Application::_activeTransactionGuard). The counter prevents any new
|
||||
* active transactions being setup. It also prevents to close
|
||||
* (i.e. commits) the current active transaction until it reaches zero. It
|
||||
* does not have any effect on aborting transactions though.
|
||||
/** Constructor
|
||||
*
|
||||
* @param tid the ID of the transaction to manage
|
||||
*
|
||||
* No action is done in the constructor
|
||||
*/
|
||||
AutoTransaction(const char* name = nullptr, bool tmpName = false);
|
||||
|
||||
/**
|
||||
* @brief Destruct an auto transaction.
|
||||
*
|
||||
* This destructor decrease an internal counter
|
||||
* (Application::_activeTransactionGuard), and will commit any current
|
||||
* active transaction when the counter reaches zero.
|
||||
explicit AutoTransaction(int tid);
|
||||
AutoTransaction(Document* doc, const std::string& name);
|
||||
|
||||
/** Destructor
|
||||
*
|
||||
* This destructor attempts to commit the transaction it manages
|
||||
*/
|
||||
~AutoTransaction();
|
||||
|
||||
/**
|
||||
* @brief Close or abort the transaction.
|
||||
*
|
||||
* This function can be used to explicitly close (i.e. commit) the
|
||||
* transaction, if the current transaction ID matches the one created inside
|
||||
* the constructor. For aborting, it will abort any current transaction.
|
||||
*
|
||||
* @param[in] abort: if true, abort the transaction; otherwise, commit it.
|
||||
* This function can be used to explicitly close (i.e. commit / abort) the
|
||||
* transaction,
|
||||
*/
|
||||
void close(bool abort = false);
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable any AutoTransaction instance on the current stack.
|
||||
*
|
||||
* Once disabled, any empty temporary named transaction is closed. If there
|
||||
* are non-empty or non-temporary named active transaction, it will not be
|
||||
* auto closed.
|
||||
*
|
||||
* This function may be used in, for example, Gui::Document::setEdit() to
|
||||
* allow a transaction live past any command scope.
|
||||
*
|
||||
* @param[in] enable: if true, enable the AutoTransaction; otherwise, disable it.
|
||||
*/
|
||||
static void setEnable(bool enable);
|
||||
void close(TransactionCloseMode mode = TransactionCloseMode::Commit);
|
||||
|
||||
private:
|
||||
int tid = 0;
|
||||
int tid { 0 };
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +92,7 @@ public:
|
||||
*
|
||||
* @param[in] lock: whether to activate the lock
|
||||
*/
|
||||
TransactionLocker(bool lock = true);
|
||||
TransactionLocker(Document* doc, bool lock = true);
|
||||
|
||||
/**
|
||||
* @brief Destruct a transaction locker.
|
||||
@@ -143,10 +118,7 @@ public:
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
/// Check if transaction is being locked.
|
||||
static bool isLocked();
|
||||
|
||||
|
||||
friend class Application;
|
||||
|
||||
public:
|
||||
@@ -155,8 +127,7 @@ public:
|
||||
|
||||
private:
|
||||
bool active;
|
||||
Document* doc;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_AUTOTRANSACTION_H
|
||||
} // namespace App
|
||||
+1
-4
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_BRANDING_H
|
||||
#define APP_BRANDING_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QDomDocument>
|
||||
@@ -54,5 +53,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_BRANDING_H
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef APP_CLEANUPPROCESS_H
|
||||
#define APP_CLEANUPPROCESS_H
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <FCGlobal.h>
|
||||
@@ -52,6 +51,4 @@ public:
|
||||
static void callCleanup();
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_CLEANUPPROCESS_H
|
||||
} // namespace App
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_COLORMODEL_H
|
||||
#define APP_COLORMODEL_H
|
||||
#pragma once
|
||||
|
||||
#include "Material.h"
|
||||
#include <Base/Bitmask.h>
|
||||
@@ -702,6 +701,4 @@ inline const ColorModel& ColorGradient::getColorModel() const
|
||||
return currentModelPack.totalModel;
|
||||
}
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_COLORMODEL_H
|
||||
} // namespace App
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include <boost/iostreams/device/array.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
|
||||
using namespace Data;
|
||||
|
||||
+385
-157
@@ -25,8 +25,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_COMPLEX_GEO_DATA_H
|
||||
#define APP_COMPLEX_GEO_DATA_H
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
@@ -57,18 +56,21 @@ namespace Data
|
||||
{
|
||||
|
||||
// struct MappedChildElements;
|
||||
|
||||
/// Option for App::GeoFeature::searchElementCache()
|
||||
enum class SearchOption
|
||||
{
|
||||
/// Whether to compare shape geometry
|
||||
CheckGeometry = 1,
|
||||
SingleResult = 2,
|
||||
CheckGeometry = 1, ///< Whether to compare shape geometry
|
||||
SingleResult = 2, ///< Stop at first found result
|
||||
};
|
||||
|
||||
typedef Base::Flags<SearchOption> SearchOptions;
|
||||
|
||||
/** Segments
|
||||
* Sub-element type of the ComplexGeoData type
|
||||
* It is used to split an object in further sub-parts.
|
||||
/**
|
||||
* @brief A class for segments.
|
||||
*
|
||||
* A segment is a sub-element type of the ComplexGeoData type. It is used to
|
||||
* split an object in further sub-parts.
|
||||
*/
|
||||
class AppExport Segment: public Base::BaseClass
|
||||
{
|
||||
@@ -76,200 +78,356 @@ class AppExport Segment: public Base::BaseClass
|
||||
|
||||
public:
|
||||
~Segment() override = default;
|
||||
|
||||
/// Get the name of the segment.
|
||||
virtual std::string getName() const = 0;
|
||||
};
|
||||
|
||||
enum ElementMapResetPolicy
|
||||
{
|
||||
AllowNoMap,
|
||||
ForceEmptyMap
|
||||
};
|
||||
|
||||
/** ComplexGeoData Object
|
||||
/**
|
||||
* @brief A class for complex geometric data.
|
||||
* @ingroup ElementMapping
|
||||
*/
|
||||
class AppExport ComplexGeoData: public Base::Persistence, public Base::Handled
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief A line as a facet boundary in a 3D mesh.
|
||||
*
|
||||
* The line is represented by two point indices.
|
||||
*/
|
||||
struct Line
|
||||
{
|
||||
uint32_t I1;
|
||||
uint32_t I2;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A triangular facet in a 3D mesh.
|
||||
*
|
||||
* The facet is represented by three point indices.
|
||||
*/
|
||||
struct Facet
|
||||
{
|
||||
uint32_t I1;
|
||||
uint32_t I2;
|
||||
uint32_t I3;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A domain in a 3D mesh.
|
||||
*
|
||||
* A domain consists of a list of points and a list of facets where the
|
||||
* indices of a facet index into the points list.
|
||||
*/
|
||||
struct Domain
|
||||
{
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Facet> facets;
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
ComplexGeoData();
|
||||
/// Destructor
|
||||
~ComplexGeoData() override = default;
|
||||
|
||||
/** @name Sub-element management */
|
||||
//@{
|
||||
/** Sub type list
|
||||
* List of different sub-element types
|
||||
* its NOT a list of the sub-elements itself
|
||||
/**
|
||||
* @name Sub-element management
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get a list of sub-element types.
|
||||
*
|
||||
* This list does not contain the sub-elements themselves.
|
||||
*/
|
||||
virtual std::vector<const char*> getElementTypes() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the number of sub-elements of a given type.
|
||||
*
|
||||
* @param[in] Type The type of sub-element.
|
||||
* @return The number of sub-elements of the given type.
|
||||
*/
|
||||
virtual unsigned long countSubElements(const char* Type) const = 0;
|
||||
/// Returns a generic element type and index. The determined element type isn't
|
||||
/// necessarily supported by this geometry.
|
||||
|
||||
/**
|
||||
* @brief Get the type and index from a combined name.
|
||||
*
|
||||
* An example is "Edge12", which would return the type "Edge" and the
|
||||
* index 12.
|
||||
*
|
||||
* @param[in] Name The combined name of the sub-element.
|
||||
* @returns A pair of a generic element type and index.
|
||||
*
|
||||
* @note The determined element type isn't necessarily supported by this
|
||||
* geometry.
|
||||
*/
|
||||
static std::pair<std::string, unsigned long> getTypeAndIndex(const char* Name);
|
||||
/// get the sub-element by type and number
|
||||
|
||||
/// Get the sub-element by type and number.
|
||||
virtual Segment* getSubElement(const char* Type, unsigned long) const = 0;
|
||||
/// get sub-element by combined name
|
||||
|
||||
/// Get sub-element by combined name
|
||||
virtual Segment* getSubElementByName(const char* Name) const;
|
||||
/** Get lines from segment */
|
||||
virtual void getLinesFromSubElement(const Segment*,
|
||||
|
||||
/**
|
||||
* @brief Get the lines from a segment.
|
||||
*
|
||||
* @param[in] segment The segment to get the lines from.
|
||||
*
|
||||
* @param[in,out] Points The list of points used by the lines.
|
||||
* @param[in,out] lines The list of lines retrieved from the segment.
|
||||
*/
|
||||
virtual void getLinesFromSubElement(const Segment* segment,
|
||||
std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Line>& lines) const;
|
||||
/** Get faces from segment */
|
||||
virtual void getFacesFromSubElement(const Segment*,
|
||||
|
||||
/**
|
||||
* @brief Get the faces from a segment.
|
||||
*
|
||||
* @param[in] segment The segment to get the faces from.
|
||||
* @param[in,out] Points The list of points used by the faces.
|
||||
* @param[in,out] PointNormals The list of point normals used by the faces.
|
||||
* @param[in,out] faces The list of faces retrieved from the segment.
|
||||
*/
|
||||
virtual void getFacesFromSubElement(const Segment* segment,
|
||||
std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Base::Vector3d>& PointNormals,
|
||||
std::vector<Facet>& faces) const;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Placement control */
|
||||
//@{
|
||||
/** Applies an additional transformation to the current transformation. */
|
||||
/**
|
||||
* @name Placement control
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// Apply an additional transformation to the current transformation.
|
||||
void applyTransform(const Base::Matrix4D& rclTrf);
|
||||
/** Applies an additional translation to the current transformation. */
|
||||
|
||||
/// Apply an additional translation to the current transformation.
|
||||
void applyTranslation(const Base::Vector3d&);
|
||||
/** Applies an additional rotation to the current transformation. */
|
||||
|
||||
/// Applies an additional rotation to the current transformation.
|
||||
void applyRotation(const Base::Rotation&);
|
||||
/** Override the current transformation with a placement
|
||||
* using the setTransform() method.
|
||||
|
||||
/**
|
||||
* @brief Override the current transformation with a placement.
|
||||
*
|
||||
* Override the current transformation with a placement using the
|
||||
* setTransform() method.
|
||||
*
|
||||
* @param[in] rclPlacement The new placement to set.
|
||||
*/
|
||||
void setPlacement(const Base::Placement& rclPlacement);
|
||||
/** Return the current transformation as placement using
|
||||
* getTransform().
|
||||
|
||||
/**
|
||||
* @brief Get the current transformation as placement.
|
||||
*
|
||||
* @return The current transformation as placement using getTransform().
|
||||
*/
|
||||
Base::Placement getPlacement() const;
|
||||
/** Override the current transformation with the new one.
|
||||
* This method has to be handled by the child classes.
|
||||
* the actual placement and matrix is not part of this class.
|
||||
|
||||
/**
|
||||
* @brief Override the current transformation.
|
||||
*
|
||||
* Override the current transformation with the new one. This method has
|
||||
* to be handled by the child classes. the actual placement and matrix is
|
||||
* not part of this class.
|
||||
*
|
||||
* @param[in] rclTrf The new transformation matrix to set.
|
||||
*/
|
||||
|
||||
virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
|
||||
/** Return the current matrix
|
||||
* This method has to be handled by the child classes.
|
||||
* the actual placement and matrix is not part of this class.
|
||||
|
||||
/**
|
||||
* @brief Get the current transformation matrix.
|
||||
*
|
||||
* This method has to be handled by the child classes. The actual
|
||||
* placement and matrix is not part of this class.
|
||||
*/
|
||||
virtual Base::Matrix4D getTransform() const = 0;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Modification */
|
||||
//@{
|
||||
/// Applies a transformation on the real geometric data type
|
||||
/**
|
||||
*@name Modification
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Applies a transformation on the real geometric data type.
|
||||
*
|
||||
* @param[in] rclMat The transformation matrix to apply.
|
||||
*/
|
||||
virtual void transformGeometry(const Base::Matrix4D& rclMat) = 0;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Getting basic geometric entities */
|
||||
//@{
|
||||
/// Get the standard accuracy to be used with getPoints, getLines or getFaces
|
||||
/**
|
||||
* @name Getting basic geometric entities
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the standard accuracy for meshing.
|
||||
*
|
||||
* Get the standard accuracy to be used with getPoints(), getLines() or
|
||||
* getFaces().
|
||||
*
|
||||
* @return The standard accuracy.
|
||||
*/
|
||||
virtual double getAccuracy() const;
|
||||
|
||||
/// Get the bound box
|
||||
virtual Base::BoundBox3d getBoundBox() const = 0;
|
||||
/** Get point from line object intersection */
|
||||
|
||||
/**
|
||||
* @brief Get point from line object intersection.
|
||||
*
|
||||
* @param[in] base The base point of the line.
|
||||
* @param[in] dir The direction of the line.
|
||||
*
|
||||
* @return The intersection point.
|
||||
*/
|
||||
virtual Base::Vector3d getPointFromLineIntersection(const Base::Vector3f& base,
|
||||
const Base::Vector3f& dir) const;
|
||||
/** Get points from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get points from object with given accuracy.
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] Normals The list of normals associated with faces
|
||||
* retrieved from the object. If there are no faces, then this list will
|
||||
* be empty.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the points.
|
||||
* @param[in] flags Additional flags for point retrieval.
|
||||
*/
|
||||
virtual void getPoints(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Base::Vector3d>& Normals,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get lines from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get lines from object with given accuracy
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] lines The list of lines retrieved from the object.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the lines.
|
||||
* @param[in] flags Additional flags for line retrieval.
|
||||
*/
|
||||
virtual void getLines(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Line>& lines,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get faces from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get faces from object with given accuracy.
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] faces The list of faces retrieved from the object.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the faces.
|
||||
* @param[in] flags Additional flags for face retrieval.
|
||||
*/
|
||||
virtual void getFaces(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Facet>& faces,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get the center of gravity
|
||||
* If this method is implemented then true is returned and the center of gravity.
|
||||
* The default implementation only returns false.
|
||||
|
||||
/**
|
||||
* @brief Get the center of gravity.
|
||||
*
|
||||
* @param[out] center The center of gravity.
|
||||
*
|
||||
* @return True if this method is implemented. The default implementation returns false.
|
||||
*/
|
||||
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
|
||||
virtual std::optional<Base::Vector3d> centerOfGravity() const;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @brief Get the center of gravity.
|
||||
*
|
||||
* @return The center of gravity if available.
|
||||
*/
|
||||
virtual std::optional<Base::Vector3d> centerOfGravity() const;
|
||||
/// @}
|
||||
|
||||
/// Get the element map prefix.
|
||||
static const std::string& elementMapPrefix();
|
||||
|
||||
/** @name Element name mapping */
|
||||
//@{
|
||||
|
||||
/** Get element indexed name
|
||||
/**
|
||||
* @name Element name mapping
|
||||
*
|
||||
* @param name: the input name
|
||||
* @param sid: optional output of and App::StringID involved forming this mapped name
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the element's indexed name.
|
||||
*
|
||||
* @param[in] name The mapped name.
|
||||
*
|
||||
* @param[out] 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
|
||||
/**
|
||||
* @brief Get the element's 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.
|
||||
* @param[in] element The indexed name name of the element.
|
||||
* @param[in] allowUnmapped If the queried element is not mapped, then
|
||||
* return an empty name if @p allowUnmapped is false, or else, return the
|
||||
* indexed name.
|
||||
* @param sid Optional output of and App::StringID involved forming this
|
||||
* mapped name.
|
||||
*
|
||||
* @return 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 any App::StringID involved in 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.
|
||||
/**
|
||||
* @brief Get a pair of an 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
|
||||
* mapped one, performs a lookup, and returns 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
|
||||
* it will be treated as indexed name. Otherwise, it will be treated as a
|
||||
* mapped name.
|
||||
*
|
||||
* @param[in] name The input name.
|
||||
* @param[out] sid Optional output of any App::StringID involved in forming
|
||||
* this mapped name.
|
||||
* @param[in] 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 The MappedElement that contains both the indexed and mapped
|
||||
* name.
|
||||
*/
|
||||
MappedElement
|
||||
getElementName(const char* name, ElementIDRefs* sid = nullptr, bool copy = 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.
|
||||
/**
|
||||
* @brief Add a sub-element name mapping.
|
||||
*
|
||||
* An element can have multiple mapped names. However, a name can only be
|
||||
* mapped to one element
|
||||
*
|
||||
* Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,
|
||||
* now you must pass in `long masterTag` explicitly.
|
||||
* @param[in] element The original @c Type + @c Index element name.
|
||||
* @param[in] name The mapped sub-element name. It may or may not start
|
||||
* with elementMapPrefix().
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] 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[in] overwrite If true, it will overwrite existing names.
|
||||
*
|
||||
* @return The stored mapped element name.
|
||||
*
|
||||
* @note The original function was in the context of ComplexGeoData, which
|
||||
* provided `Tag` access, now you must pass in `long masterTag` explicitly.
|
||||
*/
|
||||
MappedName setElementName(const IndexedName& element,
|
||||
const MappedName& name,
|
||||
@@ -280,30 +438,42 @@ public:
|
||||
return _elementMap->setElementName(element, name, masterTag, sid, overwrite);
|
||||
}
|
||||
|
||||
/// Check if there is an element map.
|
||||
bool hasElementMap() const
|
||||
{
|
||||
return _elementMap != nullptr;
|
||||
}
|
||||
|
||||
/** Get mapped element names
|
||||
/**
|
||||
* @brief 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
|
||||
* @param[in] element The original element name with @c Type + @c Index.
|
||||
* @param[in] 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
|
||||
* @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;
|
||||
|
||||
/// Hash the child element map postfixes to shorten element name from hierarchical maps
|
||||
/**
|
||||
* @brief Hash the child element map postfixes.
|
||||
*
|
||||
* The hashing is done to shorten element names from hierarchical maps.
|
||||
*/
|
||||
void hashChildMaps();
|
||||
|
||||
/// Check if there is child element map
|
||||
/// Check if there is child element map.
|
||||
bool hasChildElementMap() const;
|
||||
|
||||
/// Append the Tag (if and only if it is non zero) into the element map
|
||||
/**
|
||||
* @brief Append the Tag (if and only if it is non zero) into the element map.
|
||||
*
|
||||
* @param[in] tag The master tag to append.
|
||||
* @param[in] hasher The string hasher to use.
|
||||
* @param[in] postfix An optional postfix to append after the tag.
|
||||
*/
|
||||
virtual void
|
||||
reTagElementMap(long tag, App::StringHasherRef hasher, const char* postfix = nullptr)
|
||||
{
|
||||
@@ -312,7 +482,17 @@ public:
|
||||
(void)postfix;
|
||||
}
|
||||
|
||||
// NOTE: getElementHistory is now in ElementMap
|
||||
/**
|
||||
* @brief Get the history of an element name.
|
||||
*
|
||||
* @param[in] name The mapped element name to query.
|
||||
* @param[out] original Optional output parameter to store the original
|
||||
* element name.
|
||||
* @param[out] history Optional output parameter to store the history of
|
||||
* element names.
|
||||
*
|
||||
* @note This function is now in ElementMap.
|
||||
*/
|
||||
long getElementHistory(const MappedName& name,
|
||||
MappedName* original = nullptr,
|
||||
std::vector<MappedName>* history = nullptr) const
|
||||
@@ -323,49 +503,68 @@ public:
|
||||
return 0;
|
||||
};
|
||||
|
||||
/// Set the mapped child elements.
|
||||
void setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements>& children);
|
||||
|
||||
/// Get the mapped child elements.
|
||||
std::vector<Data::ElementMap::MappedChildElements> getMappedChildElements() const;
|
||||
|
||||
/// Get the element type from a mapped name.
|
||||
char elementType(const Data::MappedName&) const;
|
||||
|
||||
/// Get the element type from an indexed name.
|
||||
char elementType(const Data::IndexedName&) const;
|
||||
|
||||
/// Get the element type from a raw name.
|
||||
char elementType(const char* name) const;
|
||||
|
||||
/** Reset/swap the element map
|
||||
/**
|
||||
* @brief Reset/swap the element map.
|
||||
*
|
||||
* @param elementMap: optional new element map
|
||||
* @param[in] elementMap: optional new element map.
|
||||
*
|
||||
* @return Returns the existing element map.
|
||||
* @return The existing element map.
|
||||
*/
|
||||
virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap = ElementMapPtr());
|
||||
|
||||
/// Get the entire element map
|
||||
/// Get the entire element map.
|
||||
std::vector<MappedElement> getElementMap() const;
|
||||
|
||||
/// Set the entire element map
|
||||
/// Set the entire element map.
|
||||
void setElementMap(const std::vector<MappedElement>& elements);
|
||||
|
||||
/// Get the current element map size
|
||||
/// Get the current element map size.
|
||||
size_t getElementMapSize(bool flush = true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
/**
|
||||
* @brief Get the higher level element names of the given element.
|
||||
*
|
||||
* @param name: the input element name.
|
||||
* @param silent: if true, suppress throwing exceptions.
|
||||
*/
|
||||
virtual std::vector<IndexedName> getHigherElements(const char* name, bool silent = false) const;
|
||||
|
||||
/// Return the current element map version
|
||||
/// Get the current element map version.
|
||||
virtual std::string getElementMapVersion() const;
|
||||
|
||||
/// Return true to signal element map version change
|
||||
/// Check the element map version.
|
||||
virtual bool checkElementMapVersion(const char* ver) const;
|
||||
|
||||
/// Check if the given sub-name only contains an element name
|
||||
/// Check if the given sub-name only contains an element name.
|
||||
static bool isElementName(const char* subName)
|
||||
{
|
||||
return (subName != nullptr) && (*subName != 0) && findElementName(subName) == subName;
|
||||
}
|
||||
|
||||
/** Iterate through the history of the give element name with a given callback
|
||||
/**
|
||||
* @brief Iterate through the history given an element name.
|
||||
*
|
||||
* Iterate through the history of the given element name with a given
|
||||
* callback.
|
||||
*
|
||||
* @param[in] name: the input element name
|
||||
* @param[in] cb: trace callback function.
|
||||
*
|
||||
* @param name: the input element name
|
||||
* @param cb: trace callback with call signature.
|
||||
* @sa TraceCallback
|
||||
*/
|
||||
void traceElement(const MappedName& name, TraceCallback cb) const
|
||||
@@ -373,42 +572,62 @@ public:
|
||||
_elementMap->traceElement(name, Tag, std::move(cb));
|
||||
}
|
||||
|
||||
/** Flush an internal buffering for element mapping */
|
||||
/// Flush internal buffers for element mapping.
|
||||
virtual void flushElementMap() const;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Save/restore
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @name Save/restore */
|
||||
//@{
|
||||
void Save(Base::Writer& writer) const override;
|
||||
void Restore(Base::XMLReader& reader) override;
|
||||
void SaveDocFile(Base::Writer& writer) const override;
|
||||
void RestoreDocFile(Base::Reader& reader) override;
|
||||
unsigned int getMemSize() const override;
|
||||
|
||||
/// Set the filename for persistence.
|
||||
void setPersistenceFileName(const char* name) const;
|
||||
|
||||
/// Called before saving.
|
||||
virtual void beforeSave() const;
|
||||
|
||||
/// Check if restore has failed.
|
||||
bool isRestoreFailed() const
|
||||
{
|
||||
return _restoreFailed;
|
||||
}
|
||||
|
||||
/// Reset the restore failure flag.
|
||||
void resetRestoreFailure() const
|
||||
{
|
||||
_restoreFailed = true;
|
||||
}
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* Debugging method to dump an entire element map in human readable form to a stream
|
||||
* @param stream
|
||||
* @brief Dump the entire element map.
|
||||
*
|
||||
* Debugging method to dump an entire element map in human readable form to a stream.
|
||||
*
|
||||
* @param[in,out] stream The output stream.
|
||||
*/
|
||||
void dumpElementMap(std::ostream& stream) const;
|
||||
|
||||
/**
|
||||
* Debugging method to dump an entire element map in human readable form into a string
|
||||
* @return The string
|
||||
* @brief Dump the entire element map to a string.
|
||||
*
|
||||
* Debugging method to dump an entire element map in human readable form
|
||||
* into a string.
|
||||
*
|
||||
* @return The string with the element map.
|
||||
*/
|
||||
const std::string dumpElementMap() const;
|
||||
|
||||
protected:
|
||||
/// from local to outside
|
||||
/// Transform the point from local to outside.
|
||||
inline Base::Vector3d transformPointToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
@@ -417,7 +636,8 @@ protected:
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to outside
|
||||
|
||||
/// Transform the points from local to outside.
|
||||
template<typename Vec>
|
||||
inline std::vector<Base::Vector3d> transformPointsToOutside(const std::vector<Vec>& input) const
|
||||
{
|
||||
@@ -435,6 +655,8 @@ protected:
|
||||
return output;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Transform the vector from local to outside.
|
||||
inline Base::Vector3d transformVectorToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
@@ -445,6 +667,8 @@ protected:
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Transform the vectors from local to outside.
|
||||
template<typename Vec>
|
||||
std::vector<Base::Vector3d> transformVectorsToOutside(const std::vector<Vec>& input) const
|
||||
{
|
||||
@@ -463,7 +687,8 @@ protected:
|
||||
return output;
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to inside
|
||||
|
||||
/// Transform the point from local to inside.
|
||||
inline Base::Vector3f transformPointToInside(const Base::Vector3d& vec) const
|
||||
{
|
||||
Base::Matrix4D tmpM(getTransform());
|
||||
@@ -475,48 +700,51 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The master tag.
|
||||
*
|
||||
* The master tag is used to identify the shape to its owner document
|
||||
* object. It should be unique within the document. A tag of zero meanss
|
||||
* that automatic element mapping is disabled.
|
||||
*/
|
||||
mutable long Tag {0};
|
||||
|
||||
/// String hasher for element name shortening
|
||||
mutable App::StringHasherRef Hasher;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Restore the element map from a stream.
|
||||
*
|
||||
* @param[in,out] stream The input stream.
|
||||
* @param[in] count The number of items to restore.
|
||||
*/
|
||||
void restoreStream(std::istream& stream, std::size_t count);
|
||||
|
||||
/**
|
||||
* @brief Read the elements from an XML reader.
|
||||
*
|
||||
* @param[in,out] reader The XML reader.
|
||||
* @param[in] count The number of elements to read.
|
||||
*/
|
||||
void readElements(Base::XMLReader& reader, size_t count);
|
||||
|
||||
/// from local to outside
|
||||
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
|
||||
static_cast<double>(vec.y),
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to inside
|
||||
inline Base::Vector3f transformToInside(const Base::Vector3d& vec) const
|
||||
{
|
||||
Base::Matrix4D tmpM(getTransform());
|
||||
tmpM.inverse();
|
||||
Base::Vector3d tmp = tmpM * vec;
|
||||
return Base::Vector3f(static_cast<float>(tmp.x),
|
||||
static_cast<float>(tmp.y),
|
||||
static_cast<float>(tmp.z));
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Get the element map.
|
||||
ElementMapPtr elementMap(bool flush = true) const;
|
||||
/// Ensure there is an element map.
|
||||
ElementMapPtr ensureElementMap(bool flush = true);
|
||||
|
||||
private:
|
||||
ElementMapPtr _elementMap;
|
||||
|
||||
protected:
|
||||
/// The persistence file name.
|
||||
mutable std::string _persistenceName;
|
||||
/// Flag to indicate restore failure.
|
||||
mutable bool _restoreFailed = false;
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(Data::SearchOption)
|
||||
#endif
|
||||
|
||||
+1
-4
@@ -23,8 +23,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef DATUMS_H
|
||||
#define DATUMS_H
|
||||
#pragma once
|
||||
|
||||
#include "GeoFeature.h"
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
@@ -254,5 +253,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif /* end of include guard: DATUMS_H */
|
||||
|
||||
+359
-209
@@ -35,10 +35,12 @@
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/graph/strong_components.hpp>
|
||||
#include <boost/graph/topological_sort.hpp>
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <random>
|
||||
@@ -93,7 +95,6 @@ using Base::Console;
|
||||
using Base::streq;
|
||||
using Base::Writer;
|
||||
using namespace App;
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace zipios;
|
||||
|
||||
@@ -190,6 +191,7 @@ bool Document::undo(const int id)
|
||||
mRedoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
mRedoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
d->bookedTransaction = 0;
|
||||
|
||||
mUndoMap.erase(mUndoTransactions.back()->getID());
|
||||
delete mUndoTransactions.back();
|
||||
@@ -242,6 +244,7 @@ bool Document::redo(const int id)
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
mUndoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
d->bookedTransaction = 0;
|
||||
|
||||
mRedoMap.erase(mRedoTransactions.back()->getID());
|
||||
delete mRedoTransactions.back();
|
||||
@@ -271,10 +274,10 @@ void Document::changePropertyOfObject(TransactionalObject* obj,
|
||||
}
|
||||
if ((d->iUndoMode != 0) && !isPerformingTransaction() && !d->activeUndoTransaction) {
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
int tid = 0;
|
||||
const char* name = GetApplication().getActiveTransaction(&tid);
|
||||
if (name && tid > 0) {
|
||||
_openTransaction(name, tid);
|
||||
if (d->bookedTransaction == NullTransaction) {
|
||||
d->bookedTransaction = GetApplication().getGlobalTransaction();
|
||||
} else {
|
||||
_openTransaction(GetApplication().getTransactionName(d->bookedTransaction), d->bookedTransaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,71 +332,92 @@ std::vector<std::string> Document::getAvailableRedoNames() const
|
||||
return vList;
|
||||
}
|
||||
|
||||
void Document::openTransaction(const char* name) // NOLINT
|
||||
int Document::openTransaction(TransactionName name, int tid) // NOLINT
|
||||
{
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
}
|
||||
return;
|
||||
if (tid != NullTransaction && tid == d->bookedTransaction) {
|
||||
return tid; // Early exit without warning
|
||||
}
|
||||
if (isTransactionLocked()) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name.name << "'");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
GetApplication().setActiveTransaction(name ? name : "<empty>");
|
||||
}
|
||||
|
||||
int Document::_openTransaction(const char* name, int id)
|
||||
{
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->iUndoMode != 0) {
|
||||
// Avoid recursive calls that is possible while
|
||||
// clearing the redo transactions and will cause
|
||||
// a double deletion of some transaction and thus
|
||||
// a segmentation fault
|
||||
if (d->opentransaction) {
|
||||
return 0;
|
||||
}
|
||||
Base::FlagToggler<> flag(d->opentransaction);
|
||||
|
||||
if ((id != 0) && mUndoMap.find(id) != mUndoMap.end()) {
|
||||
throw Base::RuntimeError("invalid transaction id");
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
_commitTransaction(true);
|
||||
}
|
||||
_clearRedos();
|
||||
|
||||
d->activeUndoTransaction = new Transaction(id);
|
||||
if (!name) {
|
||||
name = "<empty>";
|
||||
}
|
||||
d->activeUndoTransaction->Name = name;
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
id = d->activeUndoTransaction->getID();
|
||||
|
||||
signalOpenTransaction(*this, name);
|
||||
|
||||
auto& app = GetApplication();
|
||||
auto activeDoc = app.getActiveDocument();
|
||||
if (activeDoc && activeDoc != this && !activeDoc->hasPendingTransaction()) {
|
||||
std::string aname("-> ");
|
||||
aname += d->activeUndoTransaction->Name;
|
||||
FC_LOG("auto transaction " << getName() << " -> " << activeDoc->getName());
|
||||
activeDoc->_openTransaction(aname.c_str(), id);
|
||||
}
|
||||
return id;
|
||||
if (name.name.empty()) {
|
||||
name.name = "<empty>";
|
||||
}
|
||||
return 0;
|
||||
return setActiveTransaction(name, tid);
|
||||
}
|
||||
int Document::openTransaction(std::string name, int tid)
|
||||
{
|
||||
return openTransaction(TransactionName {.name = name, .temporary = false}, tid);
|
||||
}
|
||||
|
||||
void Document::renameTransaction(const char* name, const int id) const
|
||||
int Document::_openTransaction(std::string name, int id)
|
||||
{
|
||||
if (name && d->activeUndoTransaction && d->activeUndoTransaction->getID() == id) {
|
||||
if (isTransactionLocked() && id != d->bookedTransaction) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
|
||||
}
|
||||
}
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (d->iUndoMode == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Avoid recursive calls that is possible while
|
||||
// clearing the redo transactions and will cause
|
||||
// a double deletion of some transaction and thus
|
||||
// a segmentation fault
|
||||
if (d->opentransaction) {
|
||||
return 0;
|
||||
}
|
||||
Base::FlagToggler<> flag(d->opentransaction);
|
||||
|
||||
if ((id != 0) && mUndoMap.find(id) != mUndoMap.end()) {
|
||||
throw Base::RuntimeError("invalid transaction id");
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
_commitTransaction(true);
|
||||
}
|
||||
_clearRedos();
|
||||
|
||||
// When id == 0, this creates a new id
|
||||
// for instance, when there is no global transaction
|
||||
// from the application to stick to
|
||||
d->activeUndoTransaction = new Transaction(id);
|
||||
if (name.empty()) {
|
||||
name = "<empty>";
|
||||
}
|
||||
d->activeUndoTransaction->Name = name;
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
id = d->activeUndoTransaction->getID();
|
||||
|
||||
signalOpenTransaction(*this, name);
|
||||
|
||||
Document* transactionInitiator = GetApplication().transactionInitiator(id);
|
||||
if (transactionInitiator && transactionInitiator != this && !transactionInitiator->hasPendingTransaction()) {
|
||||
std::string aname = std::format("-> {}", d->activeUndoTransaction->Name);
|
||||
FC_LOG("auto transaction " << getName() << " -> " << transactionInitiator->getName());
|
||||
transactionInitiator->_openTransaction(aname, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void Document::renameTransaction(const std::string& name, const int id) const
|
||||
{
|
||||
if (!name.empty() && d->activeUndoTransaction && d->activeUndoTransaction->getID() == id) {
|
||||
if (boost::starts_with(d->activeUndoTransaction->Name, "-> ")) {
|
||||
d->activeUndoTransaction->Name.resize(3);
|
||||
}
|
||||
@@ -403,48 +427,108 @@ void Document::renameTransaction(const char* name, const int id) const
|
||||
d->activeUndoTransaction->Name += name;
|
||||
}
|
||||
}
|
||||
int Document::setActiveTransaction(TransactionName name, int tid)
|
||||
{
|
||||
// Probably a group transaction situation
|
||||
if (tid != NullTransaction) {
|
||||
if (!GetApplication().transactionIsActive(tid)) {
|
||||
FC_LOG("Could not set active transaction to inactive ID");
|
||||
return NullTransaction;
|
||||
}
|
||||
if (d->bookedTransaction != NullTransaction && d->bookedTransaction != tid && !_commitTransaction(true)) {
|
||||
FC_LOG("Could not book transaction for document");
|
||||
return NullTransaction;
|
||||
}
|
||||
d->bookedTransaction = tid;
|
||||
|
||||
if (GetApplication().transactionTmpName(d->bookedTransaction)) {
|
||||
GetApplication().setTransactionName(d->bookedTransaction, name);
|
||||
}
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
|
||||
// Rename the transaction if it had a tmp name
|
||||
if (d->bookedTransaction != NullTransaction && GetApplication().transactionTmpName(d->bookedTransaction)) {
|
||||
GetApplication().setTransactionName(d->bookedTransaction, name);
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
if (d->bookedTransaction != NullTransaction && !_commitTransaction(true)) {
|
||||
FC_LOG("Could not book transaction for document");
|
||||
return NullTransaction;
|
||||
}
|
||||
d->bookedTransaction = Transaction::getNewID();
|
||||
|
||||
GetApplication().setTransactionDescription(d->bookedTransaction, TransactionDescription {.initiator = this, .name = name});
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
|
||||
void Document::lockTransaction()
|
||||
{
|
||||
d->TransactionLock++;
|
||||
}
|
||||
void Document::unlockTransaction()
|
||||
{
|
||||
if (d->TransactionLock > 0) {
|
||||
d->TransactionLock--;
|
||||
}
|
||||
}
|
||||
bool Document::isTransactionLocked() const
|
||||
{
|
||||
return d->TransactionLock > 0;
|
||||
}
|
||||
bool Document::transacting() const
|
||||
{
|
||||
return isPerformingTransaction() || d->committing;
|
||||
}
|
||||
|
||||
void Document::_checkTransaction(DocumentObject* pcDelObj, const Property* What, int line)
|
||||
{
|
||||
// if the undo is active but no transaction open, open one!
|
||||
if ((d->iUndoMode != 0) && !isPerformingTransaction()) {
|
||||
if (!d->activeUndoTransaction) {
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
int tid = 0;
|
||||
const char* name = GetApplication().getActiveTransaction(&tid);
|
||||
if (name && tid > 0) {
|
||||
bool ignore = false;
|
||||
if (What && What->testStatus(Property::NoModify)) {
|
||||
ignore = true;
|
||||
}
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
if (What) {
|
||||
FC_LOG((ignore ? "ignore" : "auto")
|
||||
<< " transaction (" << line << ") '" << What->getFullName());
|
||||
}
|
||||
else {
|
||||
FC_LOG((ignore ? "ignore" : "auto") << " transaction (" << line << ") '"
|
||||
<< name << "' in " << getName());
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
_openTransaction(name, tid);
|
||||
}
|
||||
return;
|
||||
if (d->iUndoMode == 0 || isPerformingTransaction() || d->activeUndoTransaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
|
||||
// Priority to a transaction that has been booked
|
||||
// explicitly for this document, it there are none
|
||||
// get a sticky transaction from application
|
||||
if (!d->bookedTransaction) {
|
||||
d->bookedTransaction = GetApplication().getGlobalTransaction();
|
||||
}
|
||||
|
||||
if (d->bookedTransaction != NullTransaction) {
|
||||
std::string name = GetApplication().getTransactionName(d->bookedTransaction);
|
||||
bool ignore = false;
|
||||
if (What && What->testStatus(Property::NoModify)) {
|
||||
ignore = true;
|
||||
}
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
if (What) {
|
||||
FC_LOG((ignore ? "ignore" : "auto")
|
||||
<< " transaction (" << line << ") '" << What->getFullName());
|
||||
}
|
||||
else {
|
||||
FC_LOG((ignore ? "ignore" : "auto") << " transaction (" << line << ") '"
|
||||
<< name << "' in " << getName());
|
||||
}
|
||||
}
|
||||
if (!pcDelObj) {
|
||||
return;
|
||||
}
|
||||
// When the object is going to be deleted we have to check if it has already been added
|
||||
// to the undo transactions
|
||||
std::list<Transaction*>::iterator it;
|
||||
for (it = mUndoTransactions.begin(); it != mUndoTransactions.end(); ++it) {
|
||||
if ((*it)->hasObject(pcDelObj)) {
|
||||
_openTransaction("Delete");
|
||||
break;
|
||||
}
|
||||
if (!ignore) {
|
||||
_openTransaction(name, d->bookedTransaction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!pcDelObj) {
|
||||
return;
|
||||
}
|
||||
// When the object is going to be deleted we have to check if it has already been added
|
||||
// to the undo transactions
|
||||
std::list<Transaction*>::iterator it;
|
||||
for (it = mUndoTransactions.begin(); it != mUndoTransactions.end(); ++it) {
|
||||
if ((*it)->hasObject(pcDelObj)) {
|
||||
_openTransaction("Delete");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,29 +557,36 @@ void Document::commitTransaction() // NOLINT
|
||||
}
|
||||
|
||||
if (d->activeUndoTransaction) {
|
||||
GetApplication().closeActiveTransaction(false, d->activeUndoTransaction->getID());
|
||||
// This will iterate over all documents and ask them to
|
||||
// commit their transaction if their ID matches
|
||||
GetApplication().commitTransaction(d->activeUndoTransaction->getID());
|
||||
} else {
|
||||
d->bookedTransaction = 0; // Reset booked transaction even if it was not used
|
||||
}
|
||||
}
|
||||
|
||||
void Document::_commitTransaction(const bool notify)
|
||||
bool Document::_commitTransaction(const bool notify)
|
||||
{
|
||||
if (isPerformingTransaction()) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot commit transaction while transacting");
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (d->committing) {
|
||||
// for a recursive call return without printing a warning
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
d->bookedTransaction = 0;
|
||||
if (d->activeUndoTransaction) {
|
||||
Base::FlagToggler<> flag(d->committing);
|
||||
Application::TransactionSignaller signaller(false, true);
|
||||
const int id = d->activeUndoTransaction->getID();
|
||||
|
||||
mUndoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
|
||||
// check the stack for the limits
|
||||
if (mUndoTransactions.size() > d->UndoMaxStackSize) {
|
||||
mUndoMap.erase(mUndoTransactions.front()->getID());
|
||||
@@ -504,11 +595,12 @@ void Document::_commitTransaction(const bool notify)
|
||||
}
|
||||
signalCommitTransaction(*this);
|
||||
|
||||
// closeActiveTransaction() may call again _commitTransaction()
|
||||
// commitTransaction() may call again _commitTransaction()
|
||||
if (notify) {
|
||||
GetApplication().closeActiveTransaction(false, id);
|
||||
GetApplication().commitTransaction(id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Document::abortTransaction() const
|
||||
@@ -520,7 +612,9 @@ void Document::abortTransaction() const
|
||||
return;
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
GetApplication().closeActiveTransaction(true, d->activeUndoTransaction->getID());
|
||||
GetApplication().abortTransaction(d->activeUndoTransaction->getID());
|
||||
} else {
|
||||
d->bookedTransaction = 0; // Reset booked transaction even if it was not used
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +626,7 @@ void Document::_abortTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
d->bookedTransaction = 0;
|
||||
if (d->activeUndoTransaction) {
|
||||
Base::FlagToggler<bool> flag(d->rollback);
|
||||
Application::TransactionSignaller signaller(true, true);
|
||||
@@ -575,7 +670,10 @@ int Document::getTransactionID(const bool undo, unsigned pos) const
|
||||
for (; pos != 0U; ++rit, --pos) {}
|
||||
return (*rit)->getID();
|
||||
}
|
||||
|
||||
int Document::getBookedTransactionID() const
|
||||
{
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
bool Document::isTransactionEmpty() const
|
||||
{
|
||||
return !d->activeUndoTransaction;
|
||||
@@ -996,7 +1094,14 @@ void Document::Save(Base::Writer& writer) const
|
||||
|
||||
writer.incInd();
|
||||
|
||||
// NOTE: This differs from LS3 Code. Persisting this table
|
||||
// forces the assertion in Writer.addFile(...): assert(!isForceXML()); to be removed
|
||||
// see: https://github.com/FreeCAD/FreeCAD/issues/27489
|
||||
//
|
||||
// Original code in LS3:
|
||||
// d->Hasher->setPersistenceFileName(0);
|
||||
d->Hasher->setPersistenceFileName("StringHasher.Table");
|
||||
|
||||
for (const auto o : d->objectArray) {
|
||||
o->beforeSave();
|
||||
}
|
||||
@@ -1251,96 +1356,133 @@ constexpr auto fcAttrDepObjName {"Name"};
|
||||
constexpr auto fcAttrDepAllowPartial {"AllowPartial"};
|
||||
constexpr auto fcElementObjectDep {"Dep"};
|
||||
|
||||
void Document::writeObjects(const std::vector<DocumentObject*>& obj,
|
||||
Base::Writer& writer) const
|
||||
void Document::writeObjectDeps(const std::vector<DocumentObject*>& objs,
|
||||
Base::Writer& writer) const
|
||||
{
|
||||
// writing the features types
|
||||
writer.incInd(); // indentation for 'Objects count'
|
||||
writer.Stream() << writer.ind() << "<Objects Count=\"" << obj.size();
|
||||
if (isExporting(nullptr) == 0U) {
|
||||
writer.Stream() << "\" " << fcAttrDependencies << "=\"1";
|
||||
}
|
||||
writer.Stream() << "\">" << '\n';
|
||||
for (auto o : objs) {
|
||||
// clang-format off
|
||||
const auto& outList = o->getOutList(DocumentObject::OutListNoHidden |
|
||||
DocumentObject::OutListNoXLinked);
|
||||
// clang-format on
|
||||
|
||||
writer.incInd(); // indentation for 'Object type'
|
||||
|
||||
if (isExporting(nullptr) == 0U) {
|
||||
for (const auto o : obj) {
|
||||
const auto& outList =
|
||||
o->getOutList(DocumentObject::OutListNoHidden | DocumentObject::OutListNoXLinked);
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<" << fcElementObjectDeps << " " << fcAttrDepObjName << "=\""
|
||||
<< o->getNameInDocument() << "\" " << fcAttrDepCount << "=\""
|
||||
<< outList.size();
|
||||
if (outList.empty()) {
|
||||
writer.Stream() << "\"/>" << '\n';
|
||||
continue;
|
||||
}
|
||||
const int partial = o->canLoadPartial();
|
||||
if (partial > 0) {
|
||||
writer.Stream() << "\" " << fcAttrDepAllowPartial << "=\"" << partial;
|
||||
}
|
||||
writer.Stream() << "\">" << '\n';
|
||||
writer.incInd();
|
||||
for (const auto dep : outList) {
|
||||
const auto name = dep ? dep->getNameInDocument() : "";
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<" << fcElementObjectDep << " " << fcAttrDepObjName << "=\""
|
||||
<< (name ? name : "") << "\"/>" << '\n';
|
||||
}
|
||||
writer.decInd();
|
||||
writer.Stream() << writer.ind() << "</" << fcElementObjectDeps << ">" << '\n';
|
||||
auto objName = o->getNameInDocument();
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<" << fcElementObjectDeps
|
||||
<< " " << fcAttrDepObjName << "=\""
|
||||
<< (objName ? objName : "") << "\" "
|
||||
<< fcAttrDepCount << "=\""
|
||||
<< outList.size();
|
||||
if (outList.empty()) {
|
||||
writer.Stream() << "\"/>\n";
|
||||
continue;
|
||||
}
|
||||
int partial = o->canLoadPartial();
|
||||
if (partial > 0) {
|
||||
writer.Stream() << "\" " << fcAttrDepAllowPartial << "=\"" << partial;
|
||||
}
|
||||
writer.Stream() << "\">\n";
|
||||
writer.incInd();
|
||||
for (auto dep : outList) {
|
||||
auto depName = dep ? dep->getNameInDocument() : "";
|
||||
writer.Stream() << writer.ind()
|
||||
<< "<" << fcElementObjectDep
|
||||
<< " " << fcAttrDepObjName << "=\""
|
||||
<< (depName ? depName : "") << "\"/>\n";
|
||||
}
|
||||
writer.decInd();
|
||||
writer.Stream() << writer.ind() << "</" << fcElementObjectDeps << ">\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DocumentObject*>::const_iterator it;
|
||||
for (it = obj.begin(); it != obj.end(); ++it) {
|
||||
void Document::writeObjectType(const std::vector<DocumentObject*>& objs,
|
||||
Base::Writer& writer) const
|
||||
{
|
||||
for (auto it : objs) {
|
||||
writer.Stream() << writer.ind() << "<Object "
|
||||
<< "type=\"" << (*it)->getTypeId().getName() << "\" "
|
||||
<< "name=\"" << (*it)->getExportName() << "\" "
|
||||
<< "id=\"" << (*it)->getID() << "\" ";
|
||||
<< "type=\"" << it->getTypeId().getName() << "\" "
|
||||
<< "name=\"" << it->getExportName() << "\" "
|
||||
<< "id=\"" << it->getID() << "\" ";
|
||||
|
||||
// Only write out custom view provider types
|
||||
std::string viewType = (*it)->getViewProviderNameStored();
|
||||
if (viewType != (*it)->getViewProviderName()) {
|
||||
std::string viewType = it->getViewProviderNameStored();
|
||||
if (viewType != it->getViewProviderName()) {
|
||||
writer.Stream() << "ViewType=\"" << viewType << "\" ";
|
||||
}
|
||||
|
||||
// See DocumentObjectPy::getState
|
||||
if ((*it)->testStatus(ObjectStatus::Touch)) {
|
||||
if (it->testStatus(ObjectStatus::Touch)) {
|
||||
writer.Stream() << "Touched=\"1\" ";
|
||||
}
|
||||
if ((*it)->testStatus(ObjectStatus::Error)) {
|
||||
if (it->testStatus(ObjectStatus::Error)) {
|
||||
writer.Stream() << "Invalid=\"1\" ";
|
||||
const auto desc = getErrorDescription(*it);
|
||||
auto desc = getErrorDescription(it);
|
||||
if (desc) {
|
||||
writer.Stream() << "Error=\"" << Property::encodeAttribute(desc) << "\" ";
|
||||
}
|
||||
}
|
||||
writer.Stream() << "/>" << '\n';
|
||||
if (it->isFreezed()) {
|
||||
writer.Stream() << "Freeze=\"1\" ";
|
||||
}
|
||||
writer.Stream() << "/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
writer.decInd(); // indentation for 'Object type'
|
||||
writer.Stream() << writer.ind() << "</Objects>" << '\n';
|
||||
|
||||
void Document::writeObjectData(const std::vector<DocumentObject*>& objs,
|
||||
Base::Writer& writer) const
|
||||
{
|
||||
// writing the features itself
|
||||
writer.Stream() << writer.ind() << "<ObjectData Count=\"" << obj.size() << "\">" << '\n';
|
||||
writer.Stream() << writer.ind() << "<ObjectData Count=\"" << objs.size() << "\">\n";
|
||||
|
||||
writer.incInd(); // indentation for 'Object name'
|
||||
for (it = obj.begin(); it != obj.end(); ++it) {
|
||||
writer.Stream() << writer.ind() << "<Object name=\"" << (*it)->getExportName() << "\"";
|
||||
if ((*it)->hasExtensions()) {
|
||||
for (auto it : objs) {
|
||||
writer.Stream() << writer.ind() << "<Object name=\"" << it->getExportName() << "\"";
|
||||
if (it->hasExtensions()) {
|
||||
writer.Stream() << " Extensions=\"True\"";
|
||||
}
|
||||
|
||||
writer.Stream() << ">" << '\n';
|
||||
(*it)->Save(writer);
|
||||
writer.Stream() << writer.ind() << "</Object>" << '\n';
|
||||
writer.Stream() << ">\n";
|
||||
it->Save(writer);
|
||||
writer.Stream() << writer.ind() << "</Object>\n";
|
||||
}
|
||||
writer.decInd(); // indentation for 'Object name'
|
||||
|
||||
writer.Stream() << writer.ind() << "</ObjectData>\n";
|
||||
}
|
||||
|
||||
void Document::writeObjects(const std::vector<DocumentObject*>& objs,
|
||||
Base::Writer& writer) const
|
||||
{
|
||||
std::ostream& str = writer.Stream();
|
||||
|
||||
// writing the features types
|
||||
writer.incInd(); // indentation for 'Objects count'
|
||||
str << writer.ind() << "<Objects Count=\"" << objs.size();
|
||||
if (!isExporting(nullptr)) {
|
||||
str << "\" " << fcAttrDependencies << "=\"1";
|
||||
}
|
||||
str << "\">\n";
|
||||
|
||||
writer.incInd(); // indentation for 'Object type'
|
||||
|
||||
if (!isExporting(nullptr)) {
|
||||
writeObjectDeps(objs, writer);
|
||||
}
|
||||
|
||||
writer.decInd(); // indentation for 'Object name'
|
||||
writer.Stream() << writer.ind() << "</ObjectData>" << '\n';
|
||||
writeObjectType(objs, writer);
|
||||
|
||||
writer.decInd(); // indentation for 'Object type'
|
||||
str << writer.ind() << "</Objects>\n";
|
||||
|
||||
writeObjectData(objs, writer);
|
||||
writer.decInd(); // indentation for 'Objects count'
|
||||
|
||||
// check for errors
|
||||
if (writer.hasFailed()) {
|
||||
std::cerr << "Output stream is in error state. As a result the "
|
||||
"Document.xml file may be incomplete.\n";
|
||||
// reset the error flags to try to safe the data files
|
||||
writer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
struct DepInfo
|
||||
@@ -1514,6 +1656,11 @@ std::vector<DocumentObject*> Document::readObjects(Base::XMLReader& reader)
|
||||
d->addRecomputeLog(reader.getAttribute<const char*>("Error"), obj);
|
||||
}
|
||||
}
|
||||
if (reader.hasAttribute("Freeze")) {
|
||||
if (reader.getAttribute<long>("Freeze") != 0) {
|
||||
obj->freeze();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
@@ -2036,11 +2183,11 @@ bool Document::afterRestore(const std::vector<DocumentObject*>& objArray, bool c
|
||||
return false;
|
||||
}
|
||||
|
||||
// some link type property cannot restore link information until other
|
||||
// objects has been restored. For example, PropertyExpressionEngine and
|
||||
// PropertySheet with expression containing label reference. So we add the
|
||||
// Property::afterRestore() interface to let them sort it out. Note, this
|
||||
// API is not called in object dedpenency order, because the order
|
||||
// Some link type properties cannot restore link information until other
|
||||
// objects have been restored. For example, PropertyExpressionEngine and
|
||||
// PropertySheet with expressions containing a label reference. So we add
|
||||
// the Property::afterRestore() interface to let them sort it out. Note,
|
||||
// this API is not called in object dependency order, because the order
|
||||
// information is not ready yet.
|
||||
std::map<DocumentObject*, std::vector<Property*>> propMap;
|
||||
for (auto obj : objArray) {
|
||||
@@ -2228,7 +2375,7 @@ vector<DocumentObject*> Document::getTouched() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void Document::setClosable(const bool c) // NOLINT
|
||||
void Document::setClosable(bool c) // NOLINT
|
||||
{
|
||||
setStatus(Document::Closable, c);
|
||||
}
|
||||
@@ -2508,7 +2655,7 @@ std::vector<Document*> Document::getDependentDocuments(const bool sort)
|
||||
}
|
||||
|
||||
std::vector<Document*> Document::getDependentDocuments(std::vector<Document*> docs,
|
||||
const bool sort)
|
||||
const bool sort)
|
||||
{
|
||||
DependencyList depList;
|
||||
std::map<Document*, Vertex> docMap;
|
||||
@@ -2572,11 +2719,6 @@ std::vector<Document*> Document::getDependentDocuments(std::vector<Document*> do
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Document::_rebuildDependencyList(const std::vector<DocumentObject*>& objs)
|
||||
{
|
||||
(void)objs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Signal that object identifiers, typically a property or document object has been renamed.
|
||||
*
|
||||
@@ -2821,10 +2963,10 @@ int Document::recompute(const std::vector<DocumentObject*>& objs,
|
||||
std::vector<DocumentObject*>
|
||||
DocumentP::partialTopologicalSort(const std::vector<DocumentObject*>& objects)
|
||||
{
|
||||
vector<DocumentObject*> ret;
|
||||
std::vector<DocumentObject*> ret;
|
||||
ret.reserve(objects.size());
|
||||
// pairs of input and output degree
|
||||
map<DocumentObject*, std::pair<int, int>> countMap;
|
||||
std::map<DocumentObject*, std::pair<int, int>> countMap;
|
||||
|
||||
for (auto objectIt : objects) {
|
||||
// we need inlist with unique entries
|
||||
@@ -2850,7 +2992,7 @@ DocumentP::partialTopologicalSort(const std::vector<DocumentObject*>& objects)
|
||||
// try input degree
|
||||
auto degInIt = find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](pair<DocumentObject*, pair<int, int>> vertex) -> bool {
|
||||
[](std::pair<DocumentObject*, std::pair<int, int>> vertex) -> bool {
|
||||
return vertex.second.first == 0;
|
||||
});
|
||||
|
||||
@@ -2885,11 +3027,11 @@ DocumentP::partialTopologicalSort(const std::vector<DocumentObject*>& objects)
|
||||
while (removeVertex) {
|
||||
removeVertex = false;
|
||||
|
||||
auto degOutIt = find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](pair<DocumentObject*, pair<int, int>> vertex) -> bool {
|
||||
return vertex.second.second == 0;
|
||||
});
|
||||
auto degOutIt = std::find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](std::pair<DocumentObject*, std::pair<int, int>> vertex) -> bool {
|
||||
return vertex.second.second == 0;
|
||||
});
|
||||
|
||||
if (degOutIt != countMap.end()) {
|
||||
removeVertex = true;
|
||||
@@ -2928,9 +3070,9 @@ DocumentP::topologicalSort(const std::vector<DocumentObject*>& objects) const
|
||||
{
|
||||
// topological sort algorithm described here:
|
||||
// https://de.wikipedia.org/wiki/Topologische_Sortierung#Algorithmus_f.C3.BCr_das_Topologische_Sortieren
|
||||
vector<DocumentObject*> ret;
|
||||
std::vector<DocumentObject*> ret;
|
||||
ret.reserve(objects.size());
|
||||
map<DocumentObject*, int> countMap;
|
||||
std::map<DocumentObject*, int> countMap;
|
||||
|
||||
for (auto objectIt : objects) {
|
||||
// We now support externally linked objects
|
||||
@@ -2946,14 +3088,14 @@ DocumentP::topologicalSort(const std::vector<DocumentObject*>& objects) const
|
||||
countMap[objectIt] = in.size();
|
||||
}
|
||||
|
||||
auto rootObjeIt = find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](pair<DocumentObject*, int> count) -> bool {
|
||||
return count.second == 0;
|
||||
});
|
||||
auto rootObjeIt = std::find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](std::pair<DocumentObject*, int> count) -> bool {
|
||||
return count.second == 0;
|
||||
});
|
||||
|
||||
if (rootObjeIt == countMap.end()) {
|
||||
cerr << "Document::topologicalSort: cyclic dependency detected (no root object)" << '\n';
|
||||
std::cerr << "Document::topologicalSort: cyclic dependency detected (no root object)" << '\n';
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2975,7 +3117,7 @@ DocumentP::topologicalSort(const std::vector<DocumentObject*>& objects) const
|
||||
|
||||
rootObjeIt = find_if(countMap.begin(),
|
||||
countMap.end(),
|
||||
[](pair<DocumentObject*, int> count) -> bool {
|
||||
[](std::pair<DocumentObject*, int> count) -> bool {
|
||||
return count.second == 0;
|
||||
});
|
||||
}
|
||||
@@ -3098,7 +3240,7 @@ DocumentObject* Document::addObject(const char* sType,
|
||||
AddObjectOption::SetNewStatus
|
||||
| (isPartial ? AddObjectOption::SetPartialStatus : AddObjectOption::UnsetPartialStatus)
|
||||
| (isNew ? AddObjectOption::DoSetup : AddObjectOption::None)
|
||||
| AddObjectOption::ActivateObject,
|
||||
| AddObjectOption::ActivateObject,
|
||||
viewType);
|
||||
|
||||
// return the Object
|
||||
@@ -3144,15 +3286,15 @@ Document::addObjects(const char* sType, const std::vector<std::string>& objectNa
|
||||
return objects;
|
||||
}
|
||||
|
||||
void Document::addObject(DocumentObject* pcObject, const char* pObjectName)
|
||||
void Document::addObject(DocumentObject* obj, const char* name)
|
||||
{
|
||||
if (pcObject->getDocument()) {
|
||||
if (obj->getDocument()) {
|
||||
throw Base::RuntimeError("Document object is already added to a document");
|
||||
}
|
||||
|
||||
pcObject->setDocument(this);
|
||||
obj->setDocument(this);
|
||||
|
||||
_addObject(pcObject, pObjectName, AddObjectOption::SetNewStatus | AddObjectOption::ActivateObject);
|
||||
_addObject(obj, name, AddObjectOption::SetNewStatus | AddObjectOption::ActivateObject);
|
||||
}
|
||||
|
||||
void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, AddObjectOptions options, const char* viewType)
|
||||
@@ -3165,7 +3307,7 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, Add
|
||||
else {
|
||||
ObjectName = getUniqueObjectName(pcObject->getTypeId().getName());
|
||||
}
|
||||
|
||||
|
||||
// insert in the name map
|
||||
d->objectMap[ObjectName] = pcObject;
|
||||
d->objectNameManager.addExactName(ObjectName);
|
||||
@@ -3181,7 +3323,7 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, Add
|
||||
}
|
||||
d->objectIdMap[pcObject->_Id] = pcObject;
|
||||
d->objectArray.push_back(pcObject);
|
||||
|
||||
|
||||
// do no transactions if we do a rollback!
|
||||
if (!d->rollback) {
|
||||
// Undo stuff
|
||||
@@ -3200,9 +3342,9 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, Add
|
||||
if (!isPerformingTransaction() && options.testFlag(AddObjectOption::DoSetup)) {
|
||||
pcObject->setupObject();
|
||||
}
|
||||
|
||||
|
||||
if (options.testFlag(AddObjectOption::SetNewStatus)) {
|
||||
pcObject->setStatus(ObjectStatus::New, true);
|
||||
pcObject->setStatus(ObjectStatus::New, true);
|
||||
}
|
||||
if (options.testFlag(AddObjectOption::SetPartialStatus) || options.testFlag(AddObjectOption::UnsetPartialStatus)) {
|
||||
pcObject->setStatus(ObjectStatus::PartialObject, options.testFlag(AddObjectOption::SetPartialStatus));
|
||||
@@ -3214,15 +3356,15 @@ void Document::_addObject(DocumentObject* pcObject, const char* pObjectName, Add
|
||||
pcObject->_pcViewProviderName = viewType ? viewType : "";
|
||||
|
||||
signalNewObject(*pcObject);
|
||||
|
||||
|
||||
// do no transactions if we do a rollback!
|
||||
if (!d->rollback && d->activeUndoTransaction) {
|
||||
signalTransactionAppend(*pcObject, d->activeUndoTransaction);
|
||||
}
|
||||
|
||||
|
||||
if (options.testFlag(AddObjectOption::ActivateObject)) {
|
||||
d->activeObject = pcObject;
|
||||
signalActivatedObject(*pcObject);
|
||||
signalActivatedObject(*pcObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3235,6 +3377,14 @@ bool Document::containsObject(const DocumentObject* pcObject) const
|
||||
return found != d->objectIdMap.end() && found->second == pcObject;
|
||||
}
|
||||
|
||||
/// Remove an object out of the document
|
||||
void Document::removeObject(const DocumentObject* object)
|
||||
{
|
||||
if (object->getDocument() == this) {
|
||||
removeObject(object->getNameInDocument());
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an object out of the document
|
||||
void Document::removeObject(const char* sName)
|
||||
{
|
||||
@@ -3259,8 +3409,8 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
FC_ERR("Cannot delete " << pcObject->getFullName() << " while recomputing");
|
||||
return;
|
||||
}
|
||||
|
||||
TransactionLocker tlock;
|
||||
|
||||
TransactionLocker tlock(this);
|
||||
|
||||
_checkTransaction(pcObject, nullptr, __LINE__);
|
||||
|
||||
@@ -3269,7 +3419,7 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
FC_ERR("Internal error, could not find " << pcObject->getFullName() << " to remove");
|
||||
}
|
||||
|
||||
if (options.testFlag(RemoveObjectOption::PreserveChildrenVisibility)
|
||||
if (options.testFlag(RemoveObjectOption::PreserveChildrenVisibility)
|
||||
&& !d->rollback && d->activeUndoTransaction && pcObject->hasChildElement()) {
|
||||
// Preserve link group sub object global visibilities. Normally those
|
||||
// claimed object should be hidden in global coordinate space. However,
|
||||
@@ -3277,7 +3427,7 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
// children, which may now in the global space. When the parent is
|
||||
// undeleted, having its children shown in both the local and global
|
||||
// coordinate space is very confusing. Hence, we preserve the visibility
|
||||
// here
|
||||
// here
|
||||
for (auto& sub : pcObject->getSubObjects()) {
|
||||
if (sub.empty()) {
|
||||
continue;
|
||||
@@ -3324,7 +3474,7 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
}
|
||||
|
||||
std::unique_ptr<DocumentObject> tobedestroyed;
|
||||
if ((options.testFlag(RemoveObjectOption::MayDestroyOutOfTransaction) && !d->rollback && !d->activeUndoTransaction)
|
||||
if ((options.testFlag(RemoveObjectOption::MayDestroyOutOfTransaction) && !d->rollback && !d->activeUndoTransaction)
|
||||
|| (options.testFlag(RemoveObjectOption::DestroyOnRollback) && d->rollback)) {
|
||||
// if not saved in undo -> delete object later
|
||||
std::unique_ptr<DocumentObject> delobj(pos->second);
|
||||
@@ -3340,13 +3490,13 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// In case the object gets deleted the pointer must be nullified
|
||||
if (tobedestroyed) {
|
||||
tobedestroyed->pcNameInDocument = nullptr;
|
||||
}
|
||||
|
||||
// Erase last to avoid invalidating pcObject->pcNameInDocument
|
||||
// Erase last to avoid invalidating pcObject->pcNameInDocument
|
||||
// when it is still needed in Transaction::addObjectNew
|
||||
d->objectMap.erase(pos);
|
||||
}
|
||||
|
||||
+1051
-318
File diff suppressed because it is too large
Load Diff
@@ -198,6 +198,7 @@ class Document(PropertyContainer):
|
||||
|
||||
Args:
|
||||
type: the type of the document object to create.
|
||||
Call method supportedTypes() to get a list of possible values.
|
||||
name: the optional name of the new object.
|
||||
objProxy: the Python binding object to attach to the new document object.
|
||||
viewProxy: the Python binding object to attach the view provider of this object.
|
||||
@@ -446,3 +447,12 @@ class Document(PropertyContainer):
|
||||
sort: whether to topologically sort the return list
|
||||
"""
|
||||
...
|
||||
|
||||
def getBookedTransactionID(self) -> int:
|
||||
"""
|
||||
getBookedTransactionID() -> int
|
||||
|
||||
Returns the currently booked transaction id, which is the id of the current transaction OR the id
|
||||
the next transaction will stick to if no change has occured yet
|
||||
"""
|
||||
...
|
||||
@@ -140,12 +140,10 @@ void DocumentObject::printInvalidLinks() const
|
||||
scopenames.pop_back();
|
||||
}
|
||||
|
||||
Base::Console().warning("%s: Link(s) to object(s) '%s' go out of the allowed scope '%s'. "
|
||||
"Instead, the linked object(s) reside within '%s'.\n",
|
||||
Base::Console().warning("%s: %s links are out of scope. Out of scope links to: %s\n",
|
||||
getTypeId().getName(),
|
||||
objnames.c_str(),
|
||||
getNameInDocument(),
|
||||
scopenames.c_str());
|
||||
objnames.c_str());
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
e.reportException();
|
||||
@@ -206,13 +204,6 @@ bool DocumentObject::recomputeFeature(bool recursive)
|
||||
return isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object touched.
|
||||
* Touching a document object does not mean to recompute it, it only means that
|
||||
* other document objects that link it (i.e. its InList) will be recomputed.
|
||||
* If it should be forced to recompute a document object then use
|
||||
* \ref enforceRecompute() instead.
|
||||
*/
|
||||
void DocumentObject::touch(bool noRecompute)
|
||||
{
|
||||
if (!noRecompute) {
|
||||
@@ -224,10 +215,6 @@ void DocumentObject::touch(bool noRecompute)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object freezed.
|
||||
* A freezed document object does not recompute ever.
|
||||
*/
|
||||
void DocumentObject::freeze()
|
||||
{
|
||||
StatusBits.set(ObjectStatus::Freeze);
|
||||
@@ -250,10 +237,6 @@ void DocumentObject::freeze()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set this document object unfreezed.
|
||||
* A freezed document object does not recompute ever.
|
||||
*/
|
||||
void DocumentObject::unfreeze(bool noRecompute)
|
||||
{
|
||||
StatusBits.reset(ObjectStatus::Freeze);
|
||||
@@ -271,31 +254,16 @@ void DocumentObject::unfreeze(bool noRecompute)
|
||||
touch(noRecompute);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the document object is touched or not.
|
||||
* @return true if document object is touched, false if not.
|
||||
*/
|
||||
bool DocumentObject::isTouched() const
|
||||
{
|
||||
return ExpressionEngine.isTouched() || StatusBits.test(ObjectStatus::Touch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enforces this document object to be recomputed.
|
||||
* This can be useful to recompute the feature without
|
||||
* having to change one of its input properties.
|
||||
*/
|
||||
void DocumentObject::enforceRecompute()
|
||||
{
|
||||
touch(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether the document object must be recomputed or not.
|
||||
* This means that the 'Enforce' flag is set or that \ref mustExecute()
|
||||
* returns a value > 0.
|
||||
* @return true if document object must be recomputed, false if not.
|
||||
*/
|
||||
bool DocumentObject::mustRecompute() const
|
||||
{
|
||||
if (StatusBits.test(ObjectStatus::Freeze)) {
|
||||
@@ -646,7 +614,7 @@ bool DocumentObject::isInOutListRecursive(DocumentObject* linkTo) const
|
||||
}
|
||||
|
||||
std::vector<std::list<App::DocumentObject*>>
|
||||
DocumentObject::getPathsByOutList(App::DocumentObject* to) const
|
||||
DocumentObject::getPathsByOutList(const App::DocumentObject* to) const
|
||||
{
|
||||
return _pDoc->getPathsByOutList(this, to);
|
||||
}
|
||||
@@ -1200,43 +1168,22 @@ DocumentObject* DocumentObject::getLinkedObject(bool recursive,
|
||||
|
||||
void DocumentObject::Save(Base::Writer& writer) const
|
||||
{
|
||||
if (this->isFreezed()) {
|
||||
throw Base::AbortException("At least one object is frozen, unable to save.");
|
||||
}
|
||||
|
||||
if (this->isAttachedToDocument()){
|
||||
if (this->isAttachedToDocument()) {
|
||||
writer.ObjectName = this->getNameInDocument();
|
||||
}
|
||||
App::ExtensionContainer::Save(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associate the expression \expr with the object identifier \a path in this document object.
|
||||
* @param path Target object identifier for the result of the expression
|
||||
* @param expr Expression tree
|
||||
*/
|
||||
|
||||
void DocumentObject::setExpression(const ObjectIdentifier& path, std::shared_ptr<Expression> expr)
|
||||
{
|
||||
ExpressionEngine.setValue(path, std::move(expr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear the expression of the object identifier \a path in this document object.
|
||||
* @param path Target object identifier
|
||||
*/
|
||||
|
||||
void DocumentObject::clearExpression(const ObjectIdentifier& path)
|
||||
{
|
||||
setExpression(path, std::shared_ptr<Expression>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get expression information associated with \a path.
|
||||
* @param path Object identifier
|
||||
* @return Expression info, containing expression and optional comment.
|
||||
*/
|
||||
|
||||
const PropertyExpressionEngine::ExpressionInfo
|
||||
DocumentObject::getExpression(const ObjectIdentifier& path) const
|
||||
{
|
||||
@@ -1250,13 +1197,6 @@ DocumentObject::getExpression(const ObjectIdentifier& path) const
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Invoke ExpressionEngine's renameObjectIdentifier, to possibly rewrite expressions using
|
||||
* the \a paths map with current and new identifiers.
|
||||
*
|
||||
* @param paths
|
||||
*/
|
||||
|
||||
void DocumentObject::renameObjectIdentifiers(
|
||||
const std::map<ObjectIdentifier, ObjectIdentifier>& paths)
|
||||
{
|
||||
|
||||
+847
-306
File diff suppressed because it is too large
Load Diff
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBJECTEXTENSION_H
|
||||
#define APP_DOCUMENTOBJECTEXTENSION_H
|
||||
#pragma once
|
||||
|
||||
#include "Extension.h"
|
||||
|
||||
@@ -97,10 +96,31 @@ public:
|
||||
*/
|
||||
virtual bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const;
|
||||
|
||||
/** Get the linked object
|
||||
* @sa DocumentObject::getLinkedObject()
|
||||
/**
|
||||
* @brief Get the linked object of this extension.
|
||||
*
|
||||
* @return Return turn if handled, the linked object is returned in \c ret
|
||||
* This method returns the linked object of this document object. If there
|
||||
* is no linked object, it will return the container object of the
|
||||
* extension.
|
||||
*
|
||||
* @param[out] ret The linked object is returned in this parameter.
|
||||
*
|
||||
* @param[in] recurse If true, it will recursively resolve the link until it
|
||||
* reaches the final linked object.
|
||||
*
|
||||
* @param mat[in,out] If non-null, it is used as the current transformation
|
||||
* matrix on input. On output it is used as the accumulated transformation
|
||||
* up until the final linked object.
|
||||
*
|
||||
* @param[in] transform If false, then it will not accumulate the object's own
|
||||
* placement into @p mat, which lets you override the object's placement.
|
||||
*
|
||||
* @param[in] depth This parameter indicates the level on which we are
|
||||
* resolving the link.
|
||||
*
|
||||
* @return Returns true if the linked object is successfully retrieved and
|
||||
* returned in @p ret. If the linked object is not found or is invalid, it
|
||||
* returns false.
|
||||
*/
|
||||
virtual bool extensionGetLinkedObject(DocumentObject*& ret,
|
||||
bool recursive,
|
||||
@@ -123,5 +143,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTEXTENSION_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBJECTFILEINCLUDED_H
|
||||
#define APP_DOCUMENTOBJECTFILEINCLUDED_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "PropertyFile.h"
|
||||
@@ -54,6 +53,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTFILEINCLUDED_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBJECTGROUP_H
|
||||
#define APP_DOCUMENTOBJECTGROUP_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "FeaturePython.h"
|
||||
@@ -57,6 +56,3 @@ using DocumentObjectGroupPython = App::FeaturePythonT<DocumentObjectGroup>;
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_DOCUMENTOBJECTGROUP_H
|
||||
|
||||
+104
-54
@@ -38,38 +38,49 @@ namespace sp = std::placeholders;
|
||||
DocumentT::DocumentT() = default;
|
||||
|
||||
DocumentT::DocumentT(Document* doc)
|
||||
{
|
||||
document = doc->getName();
|
||||
}
|
||||
: document {doc->getName()}
|
||||
{}
|
||||
|
||||
DocumentT::DocumentT(const std::string& name)
|
||||
{
|
||||
document = name;
|
||||
}
|
||||
DocumentT::DocumentT(std::string name)
|
||||
: document {std::move(name)}
|
||||
{}
|
||||
|
||||
DocumentT::DocumentT(const DocumentT& doc)
|
||||
{
|
||||
document = doc.document;
|
||||
}
|
||||
: document {doc.document}
|
||||
{}
|
||||
|
||||
DocumentT::DocumentT(DocumentT&& doc) noexcept
|
||||
: document {std::move(doc.document)}
|
||||
{}
|
||||
|
||||
DocumentT::~DocumentT() = default;
|
||||
|
||||
void DocumentT::operator=(const DocumentT& doc)
|
||||
DocumentT& DocumentT::operator=(const DocumentT& doc)
|
||||
{
|
||||
if (this == &doc) {
|
||||
return;
|
||||
if (this != &doc) {
|
||||
document = doc.document;
|
||||
}
|
||||
document = doc.document;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DocumentT::operator=(const Document* doc)
|
||||
DocumentT& DocumentT::operator=(DocumentT&& doc) noexcept
|
||||
{
|
||||
if (this != &doc) {
|
||||
document = std::move(doc.document);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DocumentT& DocumentT::operator=(const Document* doc)
|
||||
{
|
||||
document = doc->getName();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DocumentT::operator=(const std::string& name)
|
||||
DocumentT& DocumentT::operator=(const std::string& name)
|
||||
{
|
||||
document = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Document* DocumentT::getDocument() const
|
||||
@@ -98,7 +109,7 @@ DocumentObjectT::DocumentObjectT(const DocumentObjectT& other)
|
||||
*this = other;
|
||||
}
|
||||
|
||||
DocumentObjectT::DocumentObjectT(DocumentObjectT&& other)
|
||||
DocumentObjectT::DocumentObjectT(DocumentObjectT&& other) noexcept
|
||||
{
|
||||
*this = std::move(other);
|
||||
}
|
||||
@@ -145,7 +156,7 @@ DocumentObjectT& DocumentObjectT::operator=(const DocumentObjectT& obj)
|
||||
return *this;
|
||||
}
|
||||
|
||||
DocumentObjectT& DocumentObjectT::operator=(DocumentObjectT&& obj)
|
||||
DocumentObjectT& DocumentObjectT::operator=(DocumentObjectT&& obj) noexcept
|
||||
{
|
||||
if (this == &obj) {
|
||||
return *this;
|
||||
@@ -157,7 +168,7 @@ DocumentObjectT& DocumentObjectT::operator=(DocumentObjectT&& obj)
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DocumentObjectT::operator=(const DocumentObject* obj)
|
||||
DocumentObjectT& DocumentObjectT::operator=(const DocumentObject* obj)
|
||||
{
|
||||
if (!obj || !obj->isAttachedToDocument()) {
|
||||
object.clear();
|
||||
@@ -171,9 +182,11 @@ void DocumentObjectT::operator=(const DocumentObject* obj)
|
||||
document = obj->getDocument()->getName();
|
||||
property.clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DocumentObjectT::operator=(const Property* prop)
|
||||
DocumentObjectT& DocumentObjectT::operator=(const Property* prop)
|
||||
{
|
||||
if (!prop || !prop->hasName() || !prop->getContainer()
|
||||
|| !prop->getContainer()->isDerivedFrom<App::DocumentObject>()) {
|
||||
@@ -182,13 +195,14 @@ void DocumentObjectT::operator=(const Property* prop)
|
||||
document.clear();
|
||||
property.clear();
|
||||
}
|
||||
else {
|
||||
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
|
||||
else if (auto obj = freecad_cast<App::DocumentObject*>(prop->getContainer())) {
|
||||
object = obj->getNameInDocument();
|
||||
label = obj->Label.getValue();
|
||||
document = obj->getDocument()->getName();
|
||||
property = prop->getName();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool DocumentObjectT::operator==(const DocumentObjectT& other) const
|
||||
@@ -217,8 +231,7 @@ std::string DocumentObjectT::getDocumentPython() const
|
||||
DocumentObject* DocumentObjectT::getObject() const
|
||||
{
|
||||
DocumentObject* obj = nullptr;
|
||||
Document* doc = getDocument();
|
||||
if (doc) {
|
||||
if (auto doc = getDocument()) {
|
||||
obj = doc->getObject(object.c_str());
|
||||
}
|
||||
return obj;
|
||||
@@ -229,6 +242,20 @@ const std::string& DocumentObjectT::getObjectName() const
|
||||
return object;
|
||||
}
|
||||
|
||||
const char* DocumentObjectT::getNameInDocument() const
|
||||
{
|
||||
return object.c_str();
|
||||
}
|
||||
|
||||
bool DocumentObjectT::isAttachedToDocument() const
|
||||
{
|
||||
if (auto obj = getObject()) {
|
||||
return obj->isAttachedToDocument();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& DocumentObjectT::getObjectLabel() const
|
||||
{
|
||||
return label;
|
||||
@@ -258,9 +285,13 @@ std::string DocumentObjectT::getPropertyPython() const
|
||||
|
||||
Property* DocumentObjectT::getProperty() const
|
||||
{
|
||||
auto obj = getObject();
|
||||
if (obj) {
|
||||
return obj->getPropertyByName(property.c_str());
|
||||
return getPropertyByName(property.c_str());
|
||||
}
|
||||
|
||||
Property* DocumentObjectT::getPropertyByName(const char* name) const
|
||||
{
|
||||
if (auto obj = getObject()) {
|
||||
return obj->getPropertyByName(name);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -271,7 +302,7 @@ SubObjectT::SubObjectT() = default;
|
||||
|
||||
SubObjectT::SubObjectT(const SubObjectT&) = default;
|
||||
|
||||
SubObjectT::SubObjectT(SubObjectT&& other)
|
||||
SubObjectT::SubObjectT(SubObjectT&& other) noexcept
|
||||
: DocumentObjectT(std::move(other))
|
||||
, subname(std::move(other.subname))
|
||||
{}
|
||||
@@ -295,6 +326,8 @@ SubObjectT::SubObjectT(const char* docName, const char* objName, const char* s)
|
||||
, subname(s ? s : "")
|
||||
{}
|
||||
|
||||
SubObjectT::~SubObjectT() = default;
|
||||
|
||||
bool SubObjectT::operator<(const SubObjectT& other) const
|
||||
{
|
||||
if (getDocumentName() < other.getDocumentName()) {
|
||||
@@ -323,18 +356,18 @@ SubObjectT& SubObjectT::operator=(const SubObjectT& other)
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
static_cast<DocumentObjectT&>(*this) = other;
|
||||
static_cast<DocumentObjectT&>(*this) = other; // NOLINT
|
||||
subname = other.subname;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubObjectT& SubObjectT::operator=(SubObjectT&& other)
|
||||
SubObjectT& SubObjectT::operator=(SubObjectT&& other) noexcept
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
static_cast<DocumentObjectT&>(*this) = std::move(other);
|
||||
subname = std::move(other.subname);
|
||||
static_cast<DocumentObjectT&>(*this) = std::move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -639,11 +672,14 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs)
|
||||
}
|
||||
|
||||
str << "]";
|
||||
toPython = str.str();
|
||||
}
|
||||
}
|
||||
|
||||
PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs,
|
||||
const std::vector<std::string>& subNames)
|
||||
PropertyLinkT::PropertyLinkT(
|
||||
const std::vector<DocumentObject*>& objs,
|
||||
const std::vector<std::string>& subNames
|
||||
)
|
||||
: PropertyLinkT()
|
||||
{
|
||||
if (!objs.empty() && objs.size() == subNames.size()) {
|
||||
@@ -672,6 +708,7 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs,
|
||||
}
|
||||
|
||||
str << "]";
|
||||
toPython = str.str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,7 +728,8 @@ public:
|
||||
if (doc) {
|
||||
// NOLINTBEGIN
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&Private::deletedDocument, this, sp::_1));
|
||||
std::bind(&Private::deletedDocument, this, sp::_1)
|
||||
);
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
@@ -784,12 +822,15 @@ public:
|
||||
// NOLINTBEGIN
|
||||
indocument = true;
|
||||
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&Private::deletedDocument, this, sp::_1));
|
||||
std::bind(&Private::deletedDocument, this, sp::_1)
|
||||
);
|
||||
App::Document* doc = obj->getDocument();
|
||||
connectDocumentCreatedObject =
|
||||
doc->signalNewObject.connect(std::bind(&Private::createdObject, this, sp::_1));
|
||||
connectDocumentDeletedObject =
|
||||
doc->signalDeletedObject.connect(std::bind(&Private::deletedObject, this, sp::_1));
|
||||
connectDocumentCreatedObject = doc->signalNewObject.connect(
|
||||
std::bind(&Private::createdObject, this, sp::_1)
|
||||
);
|
||||
connectDocumentDeletedObject = doc->signalDeletedObject.connect(
|
||||
std::bind(&Private::deletedObject, this, sp::_1)
|
||||
);
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
@@ -864,11 +905,14 @@ DocumentObserver::DocumentObserver()
|
||||
{
|
||||
// NOLINTBEGIN
|
||||
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(
|
||||
std::bind(&DocumentObserver::slotCreatedDocument, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotCreatedDocument, this, sp::_1)
|
||||
);
|
||||
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
|
||||
std::bind(&DocumentObserver::slotDeletedDocument, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotDeletedDocument, this, sp::_1)
|
||||
);
|
||||
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(
|
||||
std::bind(&DocumentObserver::slotActivateDocument, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotActivateDocument, this, sp::_1)
|
||||
);
|
||||
// NOLINTEND
|
||||
}
|
||||
|
||||
@@ -901,15 +945,20 @@ void DocumentObserver::attachDocument(Document* doc)
|
||||
|
||||
// NOLINTBEGIN
|
||||
this->connectDocumentCreatedObject = _document->signalNewObject.connect(
|
||||
std::bind(&DocumentObserver::slotCreatedObject, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotCreatedObject, this, sp::_1)
|
||||
);
|
||||
this->connectDocumentDeletedObject = _document->signalDeletedObject.connect(
|
||||
std::bind(&DocumentObserver::slotDeletedObject, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotDeletedObject, this, sp::_1)
|
||||
);
|
||||
this->connectDocumentChangedObject = _document->signalChangedObject.connect(
|
||||
std::bind(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2));
|
||||
std::bind(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2)
|
||||
);
|
||||
this->connectDocumentRecomputedObject = _document->signalRecomputedObject.connect(
|
||||
std::bind(&DocumentObserver::slotRecomputedObject, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotRecomputedObject, this, sp::_1)
|
||||
);
|
||||
this->connectDocumentRecomputed = _document->signalRecomputed.connect(
|
||||
std::bind(&DocumentObserver::slotRecomputedDocument, this, sp::_1));
|
||||
std::bind(&DocumentObserver::slotRecomputedDocument, this, sp::_1)
|
||||
);
|
||||
// NOLINTEND
|
||||
}
|
||||
}
|
||||
@@ -941,8 +990,7 @@ void DocumentObserver::slotCreatedObject(const App::DocumentObject& /*Obj*/)
|
||||
void DocumentObserver::slotDeletedObject(const App::DocumentObject& /*Obj*/)
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotChangedObject(const App::DocumentObject& /*Obj*/,
|
||||
const App::Property& /*Prop*/)
|
||||
void DocumentObserver::slotChangedObject(const App::DocumentObject& /*Obj*/, const App::Property& /*Prop*/)
|
||||
{}
|
||||
|
||||
void DocumentObserver::slotRecomputedObject(const DocumentObject& /*Obj*/)
|
||||
@@ -978,7 +1026,7 @@ void DocumentObjectObserver::removeFromObservation(App::DocumentObject* obj)
|
||||
_objects.erase(obj);
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotCreatedDocument(const App::Document&)
|
||||
void DocumentObjectObserver::slotCreatedDocument([[maybe_unused]] const App::Document& doc)
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
|
||||
@@ -990,13 +1038,12 @@ void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotCreatedObject(const App::DocumentObject&)
|
||||
void DocumentObjectObserver::slotCreatedObject([[maybe_unused]] const App::DocumentObject& obj)
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
{
|
||||
std::set<App::DocumentObject*>::iterator it =
|
||||
_objects.find(const_cast<App::DocumentObject*>(&Obj));
|
||||
auto it = _objects.find(const_cast<App::DocumentObject*>(&Obj));
|
||||
if (it != _objects.end()) {
|
||||
_objects.erase(it);
|
||||
}
|
||||
@@ -1005,7 +1052,10 @@ void DocumentObjectObserver::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObjectObserver::slotChangedObject(const App::DocumentObject&, const App::Property&)
|
||||
void DocumentObjectObserver::slotChangedObject(
|
||||
[[maybe_unused]] const App::DocumentObject& obj,
|
||||
[[maybe_unused]] const App::Property& prop
|
||||
)
|
||||
{}
|
||||
|
||||
void DocumentObjectObserver::cancelObservation()
|
||||
|
||||
+42
-16
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBSERVER_H
|
||||
#define APP_DOCUMENTOBSERVER_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Bitmask.h>
|
||||
@@ -56,17 +55,21 @@ public:
|
||||
/*! Constructor */
|
||||
DocumentT(Document*); // explicit bombs
|
||||
/*! Constructor */
|
||||
explicit DocumentT(const std::string&);
|
||||
explicit DocumentT(std::string);
|
||||
/*! Constructor */
|
||||
DocumentT(const DocumentT&);
|
||||
/*! Move constructor */
|
||||
DocumentT(DocumentT&&) noexcept;
|
||||
/*! Destructor */
|
||||
~DocumentT();
|
||||
/*! Assignment operator */
|
||||
void operator=(const DocumentT&);
|
||||
DocumentT& operator=(const DocumentT&);
|
||||
/*! Move assignment operator */
|
||||
DocumentT& operator=(DocumentT&&) noexcept;
|
||||
/*! Assignment operator */
|
||||
void operator=(const Document*);
|
||||
DocumentT& operator=(const Document*);
|
||||
/*! Assignment operator */
|
||||
void operator=(const std::string&);
|
||||
DocumentT& operator=(const std::string&);
|
||||
|
||||
bool operator==(const DocumentT& other) const
|
||||
{
|
||||
@@ -78,6 +81,11 @@ public:
|
||||
return document < other.document;
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return getDocument() != nullptr;
|
||||
}
|
||||
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
|
||||
Document* getDocument() const;
|
||||
/*! Get the name of the document. */
|
||||
@@ -104,7 +112,7 @@ public:
|
||||
/*! Constructor */
|
||||
DocumentObjectT(const DocumentObjectT&);
|
||||
/*! Constructor */
|
||||
DocumentObjectT(DocumentObjectT&&);
|
||||
DocumentObjectT(DocumentObjectT&&) noexcept;
|
||||
/*! Constructor */
|
||||
explicit DocumentObjectT(const DocumentObject*);
|
||||
/*! Constructor */
|
||||
@@ -118,14 +126,24 @@ public:
|
||||
/*! Assignment operator */
|
||||
DocumentObjectT& operator=(const DocumentObjectT&);
|
||||
/*! Assignment operator */
|
||||
DocumentObjectT& operator=(DocumentObjectT&&);
|
||||
DocumentObjectT& operator=(DocumentObjectT&&) noexcept;
|
||||
/*! Assignment operator */
|
||||
void operator=(const DocumentObject*);
|
||||
DocumentObjectT& operator=(const DocumentObject*);
|
||||
/*! Assignment operator */
|
||||
void operator=(const Property*);
|
||||
DocumentObjectT& operator=(const Property*);
|
||||
/*! Equality operator */
|
||||
bool operator==(const DocumentObjectT&) const;
|
||||
|
||||
bool operator<(const DocumentObjectT& other) const
|
||||
{
|
||||
return object < other.object;
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return getObject() != nullptr;
|
||||
}
|
||||
|
||||
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
|
||||
Document* getDocument() const;
|
||||
/*! Get the name of the document. */
|
||||
@@ -136,8 +154,13 @@ public:
|
||||
DocumentObject* getObject() const;
|
||||
/*! Get a pointer to the property or 0 if it doesn't exist any more. */
|
||||
Property* getProperty() const;
|
||||
/*! Get a pointer to the property by name or 0 if it doesn't exist any more. */
|
||||
Property* getPropertyByName(const char* name) const;
|
||||
/*! Get the name of the document object. */
|
||||
const std::string& getObjectName() const;
|
||||
/*! Get the name of the document object. */
|
||||
const char* getNameInDocument() const;
|
||||
bool isAttachedToDocument() const;
|
||||
/*! Get the label of the document object. */
|
||||
const std::string& getObjectLabel() const;
|
||||
/*! Get the name of the property. */
|
||||
@@ -172,11 +195,14 @@ public:
|
||||
/*! Constructor */
|
||||
SubObjectT();
|
||||
|
||||
/*! Destructor */
|
||||
~SubObjectT();
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const SubObjectT&);
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(SubObjectT&&);
|
||||
SubObjectT(SubObjectT&&) noexcept;
|
||||
|
||||
/*! Constructor */
|
||||
SubObjectT(const DocumentObjectT& obj, const char* subname);
|
||||
@@ -194,7 +220,7 @@ public:
|
||||
SubObjectT& operator=(const SubObjectT&);
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT& operator=(SubObjectT&&);
|
||||
SubObjectT& operator=(SubObjectT&&) noexcept;
|
||||
|
||||
/*! Assignment operator */
|
||||
SubObjectT& operator=(const DocumentObjectT&);
|
||||
@@ -357,7 +383,9 @@ public:
|
||||
|
||||
// disable
|
||||
DocumentWeakPtrT(const DocumentWeakPtrT&) = delete;
|
||||
DocumentWeakPtrT(DocumentWeakPtrT&&) = delete;
|
||||
DocumentWeakPtrT& operator=(const DocumentWeakPtrT&) = delete;
|
||||
DocumentWeakPtrT& operator=(DocumentWeakPtrT&&) = delete;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
@@ -425,8 +453,6 @@ public:
|
||||
|
||||
private:
|
||||
App::DocumentObject* _get() const noexcept;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
std::unique_ptr<Private> d;
|
||||
};
|
||||
@@ -508,7 +534,9 @@ public:
|
||||
|
||||
// disable
|
||||
WeakPtrT(const WeakPtrT&) = delete;
|
||||
WeakPtrT(WeakPtrT&&) = delete;
|
||||
WeakPtrT& operator=(const WeakPtrT&) = delete;
|
||||
WeakPtrT& operator=(WeakPtrT&&) = delete;
|
||||
|
||||
private:
|
||||
DocumentObjectWeakPtrT ptr;
|
||||
@@ -628,5 +656,3 @@ struct std::hash<App::DocumentObjectWeakPtrT>
|
||||
};
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(App::SubObjectT::NormalizeOption)
|
||||
|
||||
#endif // APP_DOCUMENTOBSERVER_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBSERVERPYTHON_H
|
||||
#define APP_DOCUMENTOBSERVERPYTHON_H
|
||||
#pragma once
|
||||
|
||||
#include <FCGlobal.h>
|
||||
#include <fastsignals/signal.h>
|
||||
@@ -165,5 +164,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_DOCUMENTOBSERVERPYTHON_H
|
||||
|
||||
+38
-11
@@ -411,22 +411,40 @@ PyObject* DocumentPy::addObject(PyObject* args, PyObject* kwd)
|
||||
|
||||
PyObject* DocumentPy::removeObject(PyObject* args)
|
||||
{
|
||||
char* sName;
|
||||
if (!PyArg_ParseTuple(args, "s", &sName)) {
|
||||
return nullptr;
|
||||
}
|
||||
char* sName {};
|
||||
if (PyArg_ParseTuple(args, "s", &sName)) {
|
||||
DocumentObject* object = getDocumentPtr()->getObject(sName);
|
||||
if (object) {
|
||||
getDocumentPtr()->removeObject(sName);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
|
||||
DocumentObject* pcFtr = getDocumentPtr()->getObject(sName);
|
||||
if (pcFtr) {
|
||||
getDocumentPtr()->removeObject(sName);
|
||||
Py_Return;
|
||||
}
|
||||
else {
|
||||
std::stringstream str;
|
||||
str << "No document object found with name '" << sName << "'" << std::ends;
|
||||
throw Py::ValueError(str.str());
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
PyObject* objpy {};
|
||||
if (PyArg_ParseTuple(args, "O!", &App::DocumentObjectPy::Type, &objpy)) {
|
||||
DocumentObject* object = static_cast<App::DocumentObjectPy*>(objpy)->getDocumentObjectPtr();
|
||||
if (!object) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Invalid document object");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (object->getDocument() == getDocumentPtr()) {
|
||||
getDocumentPtr()->removeObject(object);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << "Document object is not part of this document";
|
||||
throw Py::ValueError(str.str());
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_TypeError, "Expect str or DocumentObject");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* DocumentPy::copyObject(PyObject* args, PyObject* kwd)
|
||||
@@ -1157,6 +1175,15 @@ PyObject* DocumentPy::getDependentDocuments(PyObject* args)
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
PyObject* DocumentPy::getBookedTransactionID(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
int tid = getDocumentPtr()->getBookedTransactionID();
|
||||
return Py::new_reference_to(Py::Long(tid));
|
||||
}
|
||||
|
||||
|
||||
Py::Boolean DocumentPy::getRestoring() const
|
||||
{
|
||||
|
||||
+65
-23
@@ -26,6 +26,12 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/UniqueNameManager.h>
|
||||
@@ -42,8 +48,38 @@ FC_LOG_LEVEL_INIT("Property", true, true)
|
||||
|
||||
using namespace App;
|
||||
|
||||
std::size_t CStringHasher::operator()(const char* s) const {
|
||||
if (!s) {
|
||||
return 0;
|
||||
}
|
||||
return boost::hash_range(s, s + std::strlen(s));
|
||||
}
|
||||
|
||||
DynamicProperty::DynamicProperty() = default;
|
||||
bool CStringHasher::operator()(const char* a, const char* b) const {
|
||||
if (!a) {
|
||||
return !b;
|
||||
}
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
namespace bmi = boost::multi_index;
|
||||
|
||||
struct DynamicProperty::Impl {
|
||||
bmi::multi_index_container<
|
||||
PropData,
|
||||
bmi::indexed_by<
|
||||
bmi::hashed_unique<bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
|
||||
CStringHasher,
|
||||
CStringHasher>,
|
||||
bmi::hashed_unique<bmi::member<PropData, Property*, &PropData::property>>>>
|
||||
props;
|
||||
};
|
||||
|
||||
|
||||
DynamicProperty::DynamicProperty(): impl(std::make_unique<Impl>()) {};
|
||||
|
||||
DynamicProperty::~DynamicProperty()
|
||||
{
|
||||
@@ -52,7 +88,7 @@ DynamicProperty::~DynamicProperty()
|
||||
|
||||
void DynamicProperty::clear()
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
for (auto& v : index) {
|
||||
delete v.property;
|
||||
}
|
||||
@@ -61,7 +97,7 @@ void DynamicProperty::clear()
|
||||
|
||||
void DynamicProperty::getPropertyList(std::vector<Property*>& List) const
|
||||
{
|
||||
for (auto& v : props.get<0>()) {
|
||||
for (auto& v : impl->props.get<0>()) {
|
||||
List.push_back(v.property);
|
||||
}
|
||||
}
|
||||
@@ -69,27 +105,27 @@ void DynamicProperty::getPropertyList(std::vector<Property*>& List) const
|
||||
void DynamicProperty::getPropertyNamedList(
|
||||
std::vector<std::pair<const char*, Property*>>& List) const
|
||||
{
|
||||
for (auto& v : props.get<0>()) {
|
||||
for (auto& v : impl->props.get<0>()) {
|
||||
List.emplace_back(v.getName(), v.property);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicProperty::visitProperties(const std::function<void(Property*)>& visitor) const {
|
||||
for (auto& v : props.get<0>()) {
|
||||
for (auto& v : impl->props.get<0>()) {
|
||||
visitor(v.property);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicProperty::getPropertyMap(std::map<std::string,Property*>& Map) const
|
||||
{
|
||||
for (auto& v : props.get<0>()) {
|
||||
for (auto& v : impl->props.get<0>()) {
|
||||
Map[v.name] = v.property;
|
||||
}
|
||||
}
|
||||
|
||||
Property* DynamicProperty::getDynamicPropertyByName(const char* name) const
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
return it->property;
|
||||
@@ -100,7 +136,7 @@ Property* DynamicProperty::getDynamicPropertyByName(const char* name) const
|
||||
std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
names.reserve(index.size());
|
||||
for (auto& v : index) {
|
||||
names.push_back(v.name);
|
||||
@@ -115,7 +151,7 @@ short DynamicProperty::getPropertyType(const Property* prop) const
|
||||
|
||||
short DynamicProperty::getPropertyType(const char* name) const
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
short attr = it->attr;
|
||||
@@ -132,7 +168,7 @@ short DynamicProperty::getPropertyType(const char* name) const
|
||||
|
||||
const char* DynamicProperty::getPropertyGroup(const Property* prop) const
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
return it->group.c_str();
|
||||
@@ -142,7 +178,7 @@ const char* DynamicProperty::getPropertyGroup(const Property* prop) const
|
||||
|
||||
const char* DynamicProperty::getPropertyGroup(const char* name) const
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
return it->group.c_str();
|
||||
@@ -152,7 +188,7 @@ const char* DynamicProperty::getPropertyGroup(const char* name) const
|
||||
|
||||
const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
return it->doc.c_str();
|
||||
@@ -160,9 +196,15 @@ const char* DynamicProperty::getPropertyDocumentation(const Property* prop) cons
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
size_t DynamicProperty::size() const
|
||||
{
|
||||
return impl->props.size();
|
||||
}
|
||||
|
||||
const char* DynamicProperty::getPropertyDocumentation(const char* name) const
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
return it->doc.c_str();
|
||||
@@ -228,7 +270,7 @@ Property* DynamicProperty::addDynamicProperty(PropertyContainer& pc,
|
||||
|
||||
Property* pcProperty = static_cast<Property*>(propInstance);
|
||||
|
||||
auto res = props.get<0>().emplace(pcProperty, name, nullptr, group, doc, attr, ro, hidden);
|
||||
auto res = impl->props.get<0>().emplace(pcProperty, name, nullptr, group, doc, attr, ro, hidden);
|
||||
|
||||
pcProperty->setContainer(&pc);
|
||||
pcProperty->myName = res.first->name.c_str();
|
||||
@@ -253,7 +295,7 @@ bool DynamicProperty::addProperty(Property* prop)
|
||||
if (!prop || !prop->hasName()) {
|
||||
return false;
|
||||
}
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
#if BOOST_VERSION < 107500
|
||||
if (index.count(prop->getName())) {
|
||||
return false;
|
||||
@@ -276,7 +318,7 @@ bool DynamicProperty::addProperty(Property* prop)
|
||||
|
||||
bool DynamicProperty::removeProperty(const Property* prop)
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
index.erase(it);
|
||||
@@ -287,7 +329,7 @@ bool DynamicProperty::removeProperty(const Property* prop)
|
||||
|
||||
bool DynamicProperty::removeDynamicProperty(const char* name)
|
||||
{
|
||||
auto& index = props.get<0>();
|
||||
auto& index = impl->props.get<0>();
|
||||
auto it = index.find(name);
|
||||
if (it != index.end()) {
|
||||
if (it->property->testStatus(Property::LockDynamic)) {
|
||||
@@ -333,7 +375,7 @@ std::string DynamicProperty::getUniquePropertyName(const PropertyContainer& pc,
|
||||
|
||||
void DynamicProperty::save(const Property* prop, Base::Writer& writer) const
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
auto& data = *it;
|
||||
@@ -385,7 +427,7 @@ Property* DynamicProperty::restore(PropertyContainer& pc,
|
||||
|
||||
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property* prop) const
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
return *it;
|
||||
@@ -397,7 +439,7 @@ bool DynamicProperty::changeDynamicProperty(const Property* prop,
|
||||
const char* group,
|
||||
const char* doc)
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it == index.end()) {
|
||||
return false;
|
||||
@@ -414,7 +456,7 @@ bool DynamicProperty::changeDynamicProperty(const Property* prop,
|
||||
bool DynamicProperty::renameDynamicProperty(Property* prop,
|
||||
const char* newName)
|
||||
{
|
||||
auto& propIndex = props.get<1>();
|
||||
auto& propIndex = impl->props.get<1>();
|
||||
auto propIt = propIndex.find(prop);
|
||||
if (propIt == propIndex.end()) {
|
||||
return false;
|
||||
@@ -436,7 +478,7 @@ bool DynamicProperty::renameDynamicProperty(Property* prop,
|
||||
}
|
||||
|
||||
std::string oldName{data.getName()};
|
||||
auto& nameIndex = props.get<0>();
|
||||
auto& nameIndex = impl->props.get<0>();
|
||||
auto nameIt = nameIndex.find(data.getName());
|
||||
if (nameIt == nameIndex.end()) {
|
||||
// This should never happen
|
||||
@@ -458,7 +500,7 @@ bool DynamicProperty::renameDynamicProperty(Property* prop,
|
||||
|
||||
const char* DynamicProperty::getPropertyName(const Property* prop) const
|
||||
{
|
||||
auto& index = props.get<1>();
|
||||
auto& index = impl->props.get<1>();
|
||||
auto it = index.find(const_cast<Property*>(prop));
|
||||
if (it != index.end()) {
|
||||
return it->getName();
|
||||
|
||||
+10
-42
@@ -23,19 +23,15 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SRC_APP_DYNAMICPROPERTY_H_
|
||||
#define SRC_APP_DYNAMICPROPERTY_H_
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
#include <FCGlobal.h>
|
||||
|
||||
|
||||
@@ -51,27 +47,10 @@ namespace App
|
||||
class Property;
|
||||
class PropertyContainer;
|
||||
|
||||
namespace bmi = boost::multi_index;
|
||||
|
||||
struct CStringHasher
|
||||
struct AppExport CStringHasher
|
||||
{
|
||||
inline std::size_t operator()(const char* s) const
|
||||
{
|
||||
if (!s) {
|
||||
return 0;
|
||||
}
|
||||
return boost::hash_range(s, s + std::strlen(s));
|
||||
}
|
||||
inline bool operator()(const char* a, const char* b) const
|
||||
{
|
||||
if (!a) {
|
||||
return !b;
|
||||
}
|
||||
if (!b) {
|
||||
return false;
|
||||
}
|
||||
return std::strcmp(a, b) == 0;
|
||||
}
|
||||
std::size_t operator()(const char* s) const;
|
||||
bool operator()(const char* a, const char* b) const;
|
||||
};
|
||||
|
||||
/** This class implements an interface to add properties at run-time to an object
|
||||
@@ -161,10 +140,7 @@ public:
|
||||
void clear();
|
||||
|
||||
/// Get property count
|
||||
size_t size() const
|
||||
{
|
||||
return props.size();
|
||||
}
|
||||
size_t size() const;
|
||||
|
||||
void save(const Property* prop, Base::Writer& writer) const;
|
||||
|
||||
@@ -218,16 +194,8 @@ private:
|
||||
std::string getUniquePropertyName(const PropertyContainer& pc, const char* Name) const;
|
||||
|
||||
private:
|
||||
bmi::multi_index_container<
|
||||
PropData,
|
||||
bmi::indexed_by<
|
||||
bmi::hashed_unique<bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
|
||||
CStringHasher,
|
||||
CStringHasher>,
|
||||
bmi::hashed_unique<bmi::member<PropData, Property*, &PropData::property>>>>
|
||||
props;
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_DYNAMICPROPERTY_H_
|
||||
} // namespace App
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user