Compare commits
419 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 | |||
| 82ba9ec9d8 | |||
| f60f3d7cc5 | |||
| bef9d03312 | |||
| 1bfaa81d77 | |||
| 7586620d41 | |||
| 1cc53d911a | |||
| 7bf2050865 | |||
| b7b3187e1d | |||
| 9e0538abc8 | |||
| a64a43b9ca | |||
| 7c813a6f5a | |||
| 884baf2cb8 | |||
| 0f4ad868f7 | |||
| adf15a401d | |||
| 1de8cd5e36 | |||
| daceb8afe4 | |||
| 8dad760db4 | |||
| 1455321ace | |||
| 47d02c0618 | |||
| 53bb61da00 | |||
| dd3c12758f | |||
| 6d3f786b38 | |||
| 1eb6968265 | |||
| 388c66b41e | |||
| 928e5e0fbb | |||
| 603fc4b341 | |||
| 70b9305f2e | |||
| 8e04386c67 | |||
| cdce2f0ffd | |||
| 6a66c233f1 | |||
| 1800ef0f10 | |||
| bc81a16eb4 | |||
| 22f40741ee |
@@ -58,7 +58,7 @@ jobs:
|
||||
logdir: /tmp/log/
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
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
|
||||
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
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,11 +21,11 @@ jobs:
|
||||
build_tag: ${{ steps.get_tag.outputs.build_tag }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout Source
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
@@ -29,7 +33,7 @@ jobs:
|
||||
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:
|
||||
@@ -105,7 +112,7 @@ jobs:
|
||||
environment: weekly-build
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -118,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 }}
|
||||
@@ -128,7 +135,7 @@ jobs:
|
||||
echo 'RATTLER_CACHE_DIR=D:\rattler' >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Checkout Source
|
||||
- name: Checkout source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
@@ -142,7 +149,7 @@ jobs:
|
||||
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 }}
|
||||
@@ -150,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
|
||||
@@ -186,23 +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 }}
|
||||
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: |
|
||||
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 }}
|
||||
TARGET_PLATFORM: ${{ matrix.target }}
|
||||
MAKE_INSTALLER: "true"
|
||||
UPLOAD_RELEASE: "true"
|
||||
BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }}
|
||||
run: |
|
||||
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 run -e package create_bundle
|
||||
|
||||
## Needed if running on a self-hosted runner:
|
||||
|
||||
@@ -64,7 +64,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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4
|
||||
uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
- name: Restore Compiler Cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
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@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
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,7 +77,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
- name: Restore Compiler Cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
@@ -216,14 +216,14 @@ jobs:
|
||||
- name: Save Compiler Cache
|
||||
id: cache-save
|
||||
if: always()
|
||||
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
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: |
|
||||
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
- name: Restore compiler cache
|
||||
id: cache-restore
|
||||
if: always()
|
||||
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
|
||||
@@ -169,14 +169,14 @@ jobs:
|
||||
- name: Save Compiler Cache
|
||||
id: cache-save
|
||||
if: always()
|
||||
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
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,7 +198,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -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@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
|
||||
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
|
||||
|
||||
+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
|
||||
|
||||
|
||||
+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.
@@ -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 :
|
||||
|
||||
@@ -31,4 +31,4 @@ else
|
||||
MAIN="$HERE/usr/bin/freecad"
|
||||
fi
|
||||
|
||||
"${MAIN}" "$@"
|
||||
exec "${MAIN}" "$@"
|
||||
|
||||
@@ -76,9 +76,9 @@ if [ -d "${conda_env}/PlugIns" ]; then
|
||||
mv ${conda_env}/PlugIns ${conda_env}/..
|
||||
fi
|
||||
|
||||
if [[ "${SIGN_RELEASE}" == "true" ]]; then
|
||||
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
|
||||
|
||||
@@ -100,7 +100,7 @@ requirements:
|
||||
|
||||
host:
|
||||
- coin3d
|
||||
- eigen
|
||||
- eigen >=3.3,<5
|
||||
- fmt
|
||||
- freetype
|
||||
- hdf5
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,11 +19,12 @@ debugpy = "*"
|
||||
defusedxml = "*"
|
||||
docutils = "*"
|
||||
doxygen = "*"
|
||||
eigen = "*"
|
||||
eigen = ">=3.3,<5"
|
||||
fmt = "*"
|
||||
freetype = "*"
|
||||
git = "*"
|
||||
graphviz = "*"
|
||||
harfbuzz = "*"
|
||||
hdf5 = "*"
|
||||
ifcopenshell = "*"
|
||||
lark = "*"
|
||||
|
||||
@@ -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
|
||||
|
||||
+188
-175
@@ -34,15 +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>
|
||||
@@ -93,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>
|
||||
@@ -161,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;
|
||||
@@ -512,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 );
|
||||
@@ -558,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
|
||||
{
|
||||
@@ -957,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;
|
||||
}
|
||||
}
|
||||
@@ -1447,6 +1485,93 @@ void Application::addExportType(const char* filter, const char* moduleName)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -1734,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
|
||||
@@ -2142,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>;
|
||||
@@ -2174,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);
|
||||
}
|
||||
@@ -2490,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
|
||||
@@ -2737,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()
|
||||
@@ -3416,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;
|
||||
@@ -3611,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");
|
||||
|
||||
+79
-32
@@ -23,8 +23,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SRC_APP_APPLICATION_H_
|
||||
#define SRC_APP_APPLICATION_H_
|
||||
#pragma once
|
||||
|
||||
#include <fastsignals/signal.h>
|
||||
#include <QtCore/qtextstream.h>
|
||||
@@ -36,10 +35,12 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include <Base/Observer.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <Base/ProgressIndicator.h>
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
// forward declarations
|
||||
using PyObject = struct _object;
|
||||
@@ -129,6 +130,15 @@ public:
|
||||
App::Document* newDocument(const char* proposedName = nullptr,
|
||||
const char* proposedLabel = nullptr,
|
||||
DocumentInitFlags CreateFlags = DocumentInitFlags());
|
||||
|
||||
/**
|
||||
* @brief Closes the document and removes it from the application.
|
||||
*
|
||||
* @param[in] doc The document to close.
|
||||
* @return Returns true if the document was found and closed, false otherwise.
|
||||
*/
|
||||
bool closeDocument(const Document* doc);
|
||||
|
||||
/**
|
||||
* @brief Closes the document and removes it from the application.
|
||||
*
|
||||
@@ -195,6 +205,8 @@ public:
|
||||
*/
|
||||
App::Document* getDocument(const char *Name) const;
|
||||
|
||||
App::Document* getDocumentOrActive(const char *Name) const;
|
||||
|
||||
/// %Path matching modes for getDocumentByPath()
|
||||
enum class PathMatchMode
|
||||
{
|
||||
@@ -281,9 +293,11 @@ public:
|
||||
/**
|
||||
* @brief Setup a pending application-wide active transaction.
|
||||
*
|
||||
* Call this function to setup an application-wide transaction. All current
|
||||
* pending transactions of opening documents will be committed first.
|
||||
* However, no new transaction is created by this call. Any subsequent
|
||||
* Call this function to setup a transaction in the currently active document
|
||||
* if no document is active, a global transaction is created. If the current
|
||||
* active document already has a transaction setup it will either commit the
|
||||
* current transaction or rename it, depending on the tmpName flag of the
|
||||
* currently setup transaction. No new transaction is created by this call. Any subsequent
|
||||
* changes in any current opening document will auto create a transaction
|
||||
* with the given name and ID. If more than one document is changed, the
|
||||
* transactions will share the same ID, and will be undo/redo together.
|
||||
@@ -295,32 +309,45 @@ public:
|
||||
*
|
||||
* @return The new transaction ID.
|
||||
*/
|
||||
int setActiveTransaction(const char* name, bool persist = false);
|
||||
|
||||
/**
|
||||
* @brief Get the current active transaction name and ID.
|
||||
int setActiveTransaction(TransactionName name);
|
||||
|
||||
/// Return the current global transaction name and ID if such a global transaction is
|
||||
/// setup (uncommon)
|
||||
std::string getActiveTransaction(int *tid=nullptr) const;
|
||||
|
||||
int openGlobalTransaction(TransactionName name);
|
||||
int getGlobalTransaction() const;
|
||||
|
||||
bool transactionIsActive(int tid) const;
|
||||
std::string getTransactionName(int tid) const;
|
||||
bool transactionTmpName(int tid) const;
|
||||
Document* transactionInitiator(int tid) const;
|
||||
std::optional<TransactionDescription> transactionDescription(int tid) const;
|
||||
void setTransactionDescription(int tid, const TransactionDescription& desc);
|
||||
void setTransactionName(int tid, const TransactionName& name);
|
||||
|
||||
/** Commit/abort current active transactions
|
||||
*
|
||||
* If there is no active transaction, an empty string is returned.
|
||||
*
|
||||
* @param[out] tid If not `nullptr`, the current active transaction ID is
|
||||
* returned through this pointer.
|
||||
* @return The current active transaction name.
|
||||
*/
|
||||
const char* getActiveTransaction(int* tid = nullptr) const;
|
||||
|
||||
/**
|
||||
* @brief Commit/abort current active transactions.
|
||||
*
|
||||
* @param[in] abort: whether to abort or commit the transactions
|
||||
* @param[in] id: by default 0 meaning that the current active transaction ID is used.
|
||||
*
|
||||
* Besides calling this function directly, it will be called by
|
||||
* automatically if 1) any new transaction is created with a different ID,
|
||||
* or 2) any transaction with the current active transaction ID is either
|
||||
* committed or aborted.
|
||||
* @param[in] id: by default 0 meaning that the current global transaction ID is used.
|
||||
*
|
||||
* Bsides calling this function directly, it will be called by automatically
|
||||
* if 1) any new transaction is created with a different ID, or 2) any
|
||||
* transaction with the current active transaction ID is either committed or
|
||||
* aborted
|
||||
* returns true if it succeeded in closing the transaction
|
||||
*/
|
||||
void closeActiveTransaction(bool abort=false, int id=0);
|
||||
/// @}
|
||||
bool closeActiveTransaction(TransactionCloseMode mode = TransactionCloseMode::Commit, int id=0);
|
||||
|
||||
/// Internally call closeActiveTransaction(), but it makes the call site clearer
|
||||
bool commitTransaction(int tid);
|
||||
bool abortTransaction(int tid);
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
// NOLINTBEGIN
|
||||
// clang-format off
|
||||
@@ -595,6 +622,22 @@ public:
|
||||
*/
|
||||
void addExportType(const char* filter, const char* moduleName);
|
||||
|
||||
/**
|
||||
* @brief Register an export filetype with a translatable description
|
||||
*
|
||||
* @param[in] description A translatable string describing the file type. Must not contain the
|
||||
* list of extensions.
|
||||
* @param[in] extensions A list of supported extensions. Do not include the "*.", only the
|
||||
* extension itself. For example, "txt", not "*.txt".
|
||||
* @param[in] moduleName The name of the module handling the export.
|
||||
*/
|
||||
void addTranslatableExportType(const std::string &description,
|
||||
const std::vector<std::string> &extensions,
|
||||
const std::string &moduleName);
|
||||
|
||||
/// Intended to be called when the language is changed, this retranslates the export type.
|
||||
void retranslateExportTypes();
|
||||
|
||||
/**
|
||||
* @copydoc changeImportModule
|
||||
*/
|
||||
@@ -987,6 +1030,7 @@ private:
|
||||
std::string filter;
|
||||
std::string module;
|
||||
std::vector<std::string> types;
|
||||
bool translatable = false;
|
||||
};
|
||||
|
||||
// open ending information
|
||||
@@ -1015,10 +1059,16 @@ private:
|
||||
|
||||
friend class AutoTransaction;
|
||||
|
||||
std::string _activeTransactionName;
|
||||
int _activeTransactionID{0};
|
||||
int _activeTransactionGuard{0};
|
||||
bool _activeTransactionTmpName{false};
|
||||
std::map<int, TransactionDescription> _activeTransactionDescriptions; // Maps transaction ID to transaction name
|
||||
|
||||
int currentlyClosingID {0};
|
||||
|
||||
// This is the transaction ID for a global transaction
|
||||
// Documents will take this ID if it is non-zero
|
||||
// and generate their own otherwise
|
||||
int _globalTransactionID { 0 };
|
||||
bool _globalTransactionTmpName {false};
|
||||
std::string _globalTransactionName;
|
||||
|
||||
Base::ProgressIndicator _progressIndicator;
|
||||
|
||||
@@ -1035,6 +1085,3 @@ inline App::Application &GetApplication(){
|
||||
}
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // SRC_APP_APPLICATION_H_
|
||||
|
||||
@@ -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_
|
||||
|
||||
+185
-111
@@ -48,6 +48,7 @@ using namespace App;
|
||||
//**************************************************************************
|
||||
// Python stuff
|
||||
|
||||
// NOLINTBEGIN
|
||||
// Application methods structure
|
||||
PyMethodDef ApplicationPy::Methods[] = {
|
||||
{"ParamGet", (PyCFunction)ApplicationPy::sGetParam, METH_VARARGS, "Get parameters by path"},
|
||||
@@ -88,6 +89,12 @@ PyMethodDef ApplicationPy::Methods[] = {
|
||||
(PyCFunction)ApplicationPy::sAddExportType,
|
||||
METH_VARARGS,
|
||||
"Register filetype for export"},
|
||||
{"addTranslatableExportType",
|
||||
(PyCFunction)ApplicationPy::sAddTranslatableExportType,
|
||||
METH_VARARGS,
|
||||
"addTranslatableExportType(description:str, extensions:list[str], module_name:str)\n\n"
|
||||
"Register filetype with translatable description for export. Description should be a\n"
|
||||
"string registered with the translation system using the 'FileFormat' context."},
|
||||
{"changeExportModule",
|
||||
(PyCFunction)ApplicationPy::sChangeExportModule,
|
||||
METH_VARARGS,
|
||||
@@ -158,9 +165,6 @@ PyMethodDef ApplicationPy::Methods[] = {
|
||||
" In this case the document is kept alive.\n"
|
||||
"hidden: whether to hide document 3D view.\n"
|
||||
"temporary: whether to hide document in the tree view."},
|
||||
// {"saveDocument", (PyCFunction) ApplicationPy::sSaveDocument, METH_VARARGS,
|
||||
// "saveDocument(string) -- Save the document to a file."},
|
||||
// {"saveDocumentAs", (PyCFunction) ApplicationPy::sSaveDocumentAs, METH_VARARGS},
|
||||
{"newDocument",
|
||||
reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(ApplicationPy::sNewDocument)),
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
@@ -238,9 +242,7 @@ PyMethodDef ApplicationPy::Methods[] = {
|
||||
METH_VARARGS,
|
||||
"setActiveTransaction(name, persist=False) -- setup active transaction with the given name\n\n"
|
||||
"name: the transaction name\n"
|
||||
"persist(False): by default, if the calling code is inside any invocation of a command, it\n"
|
||||
" will be auto closed once all commands within the current stack exists. To\n"
|
||||
" disable auto closing, set persist=True\n"
|
||||
"persist(False): This parameter has no effect and is kept for compatibility reasonss"
|
||||
"Returns the transaction ID for the active transaction. An application-wide\n"
|
||||
"active transaction causes any document changes to open a transaction with\n"
|
||||
"the given name and ID."},
|
||||
@@ -268,11 +270,12 @@ PyMethodDef ApplicationPy::Methods[] = {
|
||||
"trigger a Base.FreeCADAbort exception."},
|
||||
{nullptr, nullptr, 0, nullptr} /* Sentinel */
|
||||
};
|
||||
// NOLINTEND
|
||||
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-*)
|
||||
PyObject* ApplicationPy::sLoadFile(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
const char* path;
|
||||
const char* path = "";
|
||||
const char* doc = "";
|
||||
const char* mod = "";
|
||||
if (!PyArg_ParseTuple(args, "s|ss", &path, &doc, &mod)) {
|
||||
@@ -293,9 +296,8 @@ PyObject* ApplicationPy::sLoadFile(PyObject* /*self*/, PyObject* args)
|
||||
PyErr_Format(PyExc_IOError, "Filetype %s is not supported.", ext.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
module = modules.front();
|
||||
}
|
||||
|
||||
module = modules.front();
|
||||
}
|
||||
|
||||
// path could contain characters that need escaping, such as quote signs
|
||||
@@ -340,7 +342,7 @@ PyObject* ApplicationPy::sIsRestoring(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sOpenDocument(PyObject* /*self*/, PyObject* args, PyObject* kwd)
|
||||
{
|
||||
char* Name;
|
||||
char* Name {};
|
||||
PyObject* hidden = Py_False;
|
||||
PyObject* temporary = Py_False;
|
||||
static const std::array<const char*, 4> kwlist {"name", "hidden", "temporary", nullptr};
|
||||
@@ -439,31 +441,54 @@ PyObject* ApplicationPy::sSetActiveDocument(PyObject* /*self*/, PyObject* args)
|
||||
PyObject* ApplicationPy::sCloseDocument(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* pstr = nullptr;
|
||||
if (!PyArg_ParseTuple(args, "s", &pstr)) {
|
||||
return nullptr;
|
||||
if (PyArg_ParseTuple(args, "s", &pstr)) {
|
||||
Document* doc = GetApplication().getDocument(pstr);
|
||||
if (!doc) {
|
||||
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
if (!doc->isClosable()) {
|
||||
PyErr_Format(PyExc_RuntimeError, "The document '%s' is not closable for the moment", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!GetApplication().closeDocument(pstr)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
Document* doc = GetApplication().getDocument(pstr);
|
||||
if (!doc) {
|
||||
PyErr_Format(PyExc_NameError, "Unknown document '%s'", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
if (!doc->isClosable()) {
|
||||
PyErr_Format(PyExc_RuntimeError, "The document '%s' is not closable for the moment", pstr);
|
||||
return nullptr;
|
||||
PyErr_Clear();
|
||||
PyObject* docpy {};
|
||||
if (PyArg_ParseTuple(args, "O!", &App::DocumentPy::Type, &docpy)) {
|
||||
Document* doc = static_cast<App::DocumentPy*>(docpy)->getDocumentPtr();
|
||||
if (!doc) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Invalid document");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!doc->isClosable()) {
|
||||
PyErr_Format(PyExc_RuntimeError, "The document '%s' is not closable for the moment", doc->getName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!GetApplication().closeDocument(doc)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", doc->getName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
if (!GetApplication().closeDocument(pstr)) {
|
||||
PyErr_Format(PyExc_RuntimeError, "Closing the document '%s' failed", pstr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py_Return;
|
||||
PyErr_SetString(PyExc_TypeError, "Expect str or Document");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sSaveDocument(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* pDoc;
|
||||
char* pDoc {};
|
||||
if (!PyArg_ParseTuple(args, "s", &pDoc)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -493,10 +518,9 @@ PyObject* ApplicationPy::sActiveDocument(PyObject* /*self*/, PyObject* args)
|
||||
if (doc) {
|
||||
return doc->getPyObject();
|
||||
}
|
||||
else {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sGetDocument(PyObject* /*self*/, PyObject* args)
|
||||
@@ -545,7 +569,7 @@ PyObject* ApplicationPy::sSaveParameter(PyObject* /*self*/, PyObject* args)
|
||||
PyErr_SetString(PyExc_ValueError, str.str().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
else if (!param->HasSerializer()) {
|
||||
if (!param->HasSerializer()) {
|
||||
std::stringstream str;
|
||||
str << "Parameter set cannot be serialized: " << pstr;
|
||||
PyErr_SetString(PyExc_RuntimeError, str.str().c_str());
|
||||
@@ -562,21 +586,21 @@ PyObject* ApplicationPy::sSaveParameter(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sGetConfig(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* pstr;
|
||||
char* pstr {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &pstr)) {
|
||||
return nullptr;
|
||||
}
|
||||
const std::map<std::string, std::string>& Map = GetApplication().Config();
|
||||
|
||||
std::map<std::string, std::string>::const_iterator it = Map.find(pstr);
|
||||
const std::map<std::string, std::string>& Map = Application::Config();
|
||||
|
||||
auto it = Map.find(pstr);
|
||||
if (it != Map.end()) {
|
||||
return Py_BuildValue("s", it->second.c_str());
|
||||
}
|
||||
else {
|
||||
// do not set an error because this may break existing python code
|
||||
return PyUnicode_FromString("");
|
||||
}
|
||||
|
||||
// do not set an error because this may break existing python code
|
||||
return PyUnicode_FromString("");
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sDumpConfig(PyObject* /*self*/, PyObject* args)
|
||||
@@ -586,7 +610,7 @@ PyObject* ApplicationPy::sDumpConfig(PyObject* /*self*/, PyObject* args)
|
||||
}
|
||||
|
||||
PyObject* dict = PyDict_New();
|
||||
for (const auto& It : GetApplication().Config()) {
|
||||
for (const auto& It : Application::Config()) {
|
||||
PyDict_SetItemString(dict, It.first.c_str(), PyUnicode_FromString(It.second.c_str()));
|
||||
}
|
||||
return dict;
|
||||
@@ -594,13 +618,14 @@ PyObject* ApplicationPy::sDumpConfig(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sSetConfig(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *pstr, *pstr2;
|
||||
char *pstr {};
|
||||
char *pstr2 {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss", &pstr, &pstr2)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GetApplication().Config()[pstr] = pstr2;
|
||||
Application::Config()[pstr] = pstr2;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
@@ -649,7 +674,8 @@ PyObject* ApplicationPy::sGetVersion(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sAddImportType(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *psKey, *psMod;
|
||||
char *psKey {};
|
||||
char *psMod {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss", &psKey, &psMod)) {
|
||||
return nullptr;
|
||||
@@ -662,7 +688,9 @@ PyObject* ApplicationPy::sAddImportType(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sChangeImportModule(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *key, *oldMod, *newMod;
|
||||
char *key {};
|
||||
char *oldMod {};
|
||||
char *newMod {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sss", &key, &oldMod, &newMod)) {
|
||||
return nullptr;
|
||||
@@ -690,33 +718,33 @@ PyObject* ApplicationPy::sGetImportType(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
else {
|
||||
Py::Dict dict;
|
||||
std::vector<std::string> types = GetApplication().getImportTypes();
|
||||
for (const auto& it : types) {
|
||||
std::vector<std::string> modules = GetApplication().getImportModules(it.c_str());
|
||||
if (modules.empty()) {
|
||||
dict.setItem(it.c_str(), Py::None());
|
||||
}
|
||||
else if (modules.size() == 1) {
|
||||
dict.setItem(it.c_str(), Py::String(modules.front()));
|
||||
}
|
||||
else {
|
||||
Py::List list;
|
||||
for (const auto& jt : modules) {
|
||||
list.append(Py::String(jt));
|
||||
}
|
||||
dict.setItem(it.c_str(), list);
|
||||
}
|
||||
}
|
||||
|
||||
return Py::new_reference_to(dict);
|
||||
Py::Dict dict;
|
||||
std::vector<std::string> types = GetApplication().getImportTypes();
|
||||
for (const auto& it : types) {
|
||||
std::vector<std::string> modules = GetApplication().getImportModules(it.c_str());
|
||||
if (modules.empty()) {
|
||||
dict.setItem(it.c_str(), Py::None());
|
||||
}
|
||||
else if (modules.size() == 1) {
|
||||
dict.setItem(it.c_str(), Py::String(modules.front()));
|
||||
}
|
||||
else {
|
||||
Py::List list;
|
||||
for (const auto& jt : modules) {
|
||||
list.append(Py::String(jt));
|
||||
}
|
||||
dict.setItem(it.c_str(), list);
|
||||
}
|
||||
}
|
||||
|
||||
return Py::new_reference_to(dict);
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sAddExportType(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *psKey, *psMod;
|
||||
char *psKey {};
|
||||
char *psMod {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss", &psKey, &psMod)) {
|
||||
return nullptr;
|
||||
@@ -727,9 +755,52 @@ PyObject* ApplicationPy::sAddExportType(PyObject* /*self*/, PyObject* args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sAddTranslatableExportType(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *description {};
|
||||
PyObject *pyExtensions {};
|
||||
char *moduleName {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sOs", &description, &pyExtensions, &moduleName)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!PyList_Check(pyExtensions)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Expected a list of strings as second argument");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Py_ssize_t n = PyList_Size(pyExtensions);
|
||||
|
||||
std::vector<std::string> extensions;
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
PyObject *item = PyList_GetItem(pyExtensions, i);
|
||||
|
||||
if (!PyUnicode_Check(item)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Extensions list elements must be strings");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *value = PyUnicode_AsUTF8(item);
|
||||
if (!value) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extensions.emplace_back(value);
|
||||
}
|
||||
|
||||
GetApplication().addTranslatableExportType(description, extensions, moduleName);
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sChangeExportModule(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char *key, *oldMod, *newMod;
|
||||
char *key {};
|
||||
char *oldMod {};
|
||||
char *newMod {};
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sss", &key, &oldMod, &newMod)) {
|
||||
return nullptr;
|
||||
@@ -757,28 +828,27 @@ PyObject* ApplicationPy::sGetExportType(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
return Py::new_reference_to(list);
|
||||
}
|
||||
else {
|
||||
Py::Dict dict;
|
||||
std::vector<std::string> types = GetApplication().getExportTypes();
|
||||
for (const auto& it : types) {
|
||||
std::vector<std::string> modules = GetApplication().getExportModules(it);
|
||||
if (modules.empty()) {
|
||||
dict.setItem(it.c_str(), Py::None());
|
||||
}
|
||||
else if (modules.size() == 1) {
|
||||
dict.setItem(it.c_str(), Py::String(modules.front()));
|
||||
}
|
||||
else {
|
||||
Py::List list;
|
||||
for (const auto& jt : modules) {
|
||||
list.append(Py::String(jt));
|
||||
}
|
||||
dict.setItem(it.c_str(), list);
|
||||
}
|
||||
}
|
||||
|
||||
return Py::new_reference_to(dict);
|
||||
Py::Dict dict;
|
||||
std::vector<std::string> types = GetApplication().getExportTypes();
|
||||
for (const auto& it : types) {
|
||||
std::vector<std::string> modules = GetApplication().getExportModules(it.c_str());
|
||||
if (modules.empty()) {
|
||||
dict.setItem(it.c_str(), Py::None());
|
||||
}
|
||||
else if (modules.size() == 1) {
|
||||
dict.setItem(it.c_str(), Py::String(modules.front()));
|
||||
}
|
||||
else {
|
||||
Py::List list;
|
||||
for (const auto& jt : modules) {
|
||||
list.append(Py::String(jt));
|
||||
}
|
||||
dict.setItem(it.c_str(), list);
|
||||
}
|
||||
}
|
||||
|
||||
return Py::new_reference_to(dict);
|
||||
}
|
||||
|
||||
PyObject* ApplicationPy::sGetResourcePath(PyObject* /*self*/, PyObject* args)
|
||||
@@ -889,8 +959,8 @@ PyObject* ApplicationPy::sListDocuments(PyObject* /*self*/, PyObject* args)
|
||||
PY_TRY
|
||||
{
|
||||
PyObject* pDict = PyDict_New();
|
||||
PyObject* pKey;
|
||||
Base::PyObjectBase* pValue;
|
||||
PyObject* pKey {};
|
||||
Base::PyObjectBase* pValue {};
|
||||
|
||||
std::vector<Document*> docs = GetApplication().getDocuments();
|
||||
;
|
||||
@@ -914,7 +984,7 @@ PyObject* ApplicationPy::sListDocuments(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sAddDocObserver(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
PyObject* o;
|
||||
PyObject* o {};
|
||||
if (!PyArg_ParseTuple(args, "O", &o)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -928,7 +998,7 @@ PyObject* ApplicationPy::sAddDocObserver(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sRemoveDocObserver(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
PyObject* o;
|
||||
PyObject* o {};
|
||||
if (!PyArg_ParseTuple(args, "O", &o)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -942,14 +1012,14 @@ PyObject* ApplicationPy::sRemoveDocObserver(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sSetLogLevel(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* tag;
|
||||
PyObject* pcObj;
|
||||
char* tag {};
|
||||
PyObject* pcObj {};
|
||||
if (!PyArg_ParseTuple(args, "sO", &tag, &pcObj)) {
|
||||
return nullptr;
|
||||
}
|
||||
PY_TRY
|
||||
{
|
||||
int l;
|
||||
int l {};
|
||||
if (PyUnicode_Check(pcObj)) {
|
||||
const char* pstr = PyUnicode_AsUTF8(pcObj);
|
||||
if (strcmp(pstr, "Log") == 0) {
|
||||
@@ -978,7 +1048,7 @@ PyObject* ApplicationPy::sSetLogLevel(PyObject* /*self*/, PyObject* args)
|
||||
}
|
||||
}
|
||||
else {
|
||||
l = PyLong_AsLong(pcObj);
|
||||
l = static_cast<int>(PyLong_AsLong(pcObj));
|
||||
}
|
||||
GetApplication()
|
||||
.GetParameterGroupByPath("User parameter:BaseApp/LogLevels")
|
||||
@@ -1008,7 +1078,7 @@ PyObject* ApplicationPy::sSetLogLevel(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sGetLogLevel(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* tag;
|
||||
char* tag {};
|
||||
if (!PyArg_ParseTuple(args, "s", &tag)) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1018,7 +1088,7 @@ PyObject* ApplicationPy::sGetLogLevel(PyObject* /*self*/, PyObject* args)
|
||||
int l = -1;
|
||||
if (strcmp(tag, "Default") == 0) {
|
||||
#ifdef FC_DEBUG
|
||||
l = GetApplication().GetUserParameter().GetGroup("BaseApp/LogLevels")->GetInt(tag, -1);
|
||||
l = static_cast<int>(GetApplication().GetUserParameter().GetGroup("BaseApp/LogLevels")->GetInt(tag, -1));
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(tag, "DebugDefault") == 0) {
|
||||
@@ -1071,7 +1141,7 @@ PyObject* ApplicationPy::sGetLinksTo(PyObject* /*self*/, PyObject* args)
|
||||
}
|
||||
|
||||
auto links = GetApplication().getLinksTo(obj, options, count);
|
||||
Py::Tuple ret(links.size());
|
||||
Py::Tuple ret(static_cast<int>(links.size()));
|
||||
int i = 0;
|
||||
for (auto o : links) {
|
||||
ret.setItem(i++, Py::Object(o->getPyObject(), true));
|
||||
@@ -1084,7 +1154,7 @@ PyObject* ApplicationPy::sGetLinksTo(PyObject* /*self*/, PyObject* args)
|
||||
|
||||
PyObject* ApplicationPy::sGetDependentObjects(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
PyObject* obj;
|
||||
PyObject* obj {};
|
||||
int options = 0;
|
||||
if (!PyArg_ParseTuple(args, "O|i", &obj, &options)) {
|
||||
return nullptr;
|
||||
@@ -1093,13 +1163,13 @@ PyObject* ApplicationPy::sGetDependentObjects(PyObject* /*self*/, PyObject* args
|
||||
std::vector<App::DocumentObject*> objs;
|
||||
if (PySequence_Check(obj)) {
|
||||
Py::Sequence seq(obj);
|
||||
for (Py_ssize_t i = 0; i < seq.size(); ++i) {
|
||||
if (!PyObject_TypeCheck(seq[i].ptr(), &DocumentObjectPy::Type)) {
|
||||
for (const auto& py : seq) {
|
||||
if (!PyObject_TypeCheck(py.ptr(), &DocumentObjectPy::Type)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Expect element in sequence to be of type document object");
|
||||
return nullptr;
|
||||
}
|
||||
objs.push_back(static_cast<DocumentObjectPy*>(seq[i].ptr())->getDocumentObjectPtr());
|
||||
objs.push_back(static_cast<DocumentObjectPy*>(py.ptr())->getDocumentObjectPtr());
|
||||
}
|
||||
}
|
||||
else if (!PyObject_TypeCheck(obj, &DocumentObjectPy::Type)) {
|
||||
@@ -1116,9 +1186,9 @@ PyObject* ApplicationPy::sGetDependentObjects(PyObject* /*self*/, PyObject* args
|
||||
{
|
||||
auto ret = App::Document::getDependencyList(objs, options);
|
||||
|
||||
Py::Tuple tuple(ret.size());
|
||||
Py::Tuple tuple(static_cast<int>(ret.size()));
|
||||
for (size_t i = 0; i < ret.size(); ++i) {
|
||||
tuple.setItem(i, Py::Object(ret[i]->getPyObject(), true));
|
||||
tuple.setItem(static_cast<int>(i), Py::Object(ret[i]->getPyObject(), true));
|
||||
}
|
||||
return Py::new_reference_to(tuple);
|
||||
}
|
||||
@@ -1128,15 +1198,15 @@ PyObject* ApplicationPy::sGetDependentObjects(PyObject* /*self*/, PyObject* args
|
||||
|
||||
PyObject* ApplicationPy::sSetActiveTransaction(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
PyObject* persist = Py_False;
|
||||
char* name {};
|
||||
PyObject* persist = Py_False; // Not used
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &name, &PyBool_Type, &persist)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
Py::Long ret(GetApplication().setActiveTransaction(name, Base::asBoolean(persist)));
|
||||
Py::Long ret(GetApplication().setActiveTransaction(TransactionName {.name=name, .temporary=false}));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
PY_CATCH;
|
||||
@@ -1151,8 +1221,8 @@ PyObject* ApplicationPy::sGetActiveTransaction(PyObject* /*self*/, PyObject* arg
|
||||
PY_TRY
|
||||
{
|
||||
int id = 0;
|
||||
const char* name = GetApplication().getActiveTransaction(&id);
|
||||
if (!name || id <= 0) {
|
||||
std::string name = GetApplication().getActiveTransaction(&id);
|
||||
if (name.empty() || id <= 0) {
|
||||
Py_Return;
|
||||
}
|
||||
Py::Tuple ret(2);
|
||||
@@ -1173,7 +1243,10 @@ PyObject* ApplicationPy::sCloseActiveTransaction(PyObject* /*self*/, PyObject* a
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
GetApplication().closeActiveTransaction(Base::asBoolean(abort), id);
|
||||
TransactionCloseMode mode = Base::asBoolean(abort)
|
||||
? TransactionCloseMode::Abort
|
||||
: TransactionCloseMode::Commit;
|
||||
GetApplication().closeActiveTransaction(mode, id);
|
||||
Py_Return;
|
||||
}
|
||||
PY_CATCH;
|
||||
@@ -1192,3 +1265,4 @@ PyObject* ApplicationPy::sCheckAbort(PyObject* /*self*/, PyObject* args)
|
||||
}
|
||||
PY_CATCH
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-*)
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef APP_APPLICATIONPY_H
|
||||
#define APP_APPLICATIONPY_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
@@ -48,6 +47,7 @@ public:
|
||||
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);
|
||||
@@ -63,7 +63,6 @@ public:
|
||||
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* sSaveDocumentAs (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);
|
||||
@@ -91,5 +90,3 @@ public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // APP_APPLICATIONPY_H
|
||||
|
||||
+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
|
||||
@@ -25,8 +25,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_COMPLEX_GEO_DATA_H
|
||||
#define APP_COMPLEX_GEO_DATA_H
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
@@ -749,4 +748,3 @@ protected:
|
||||
} // 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 */
|
||||
|
||||
+207
-101
@@ -35,6 +35,7 @@
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
@@ -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;
|
||||
@@ -3279,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)
|
||||
{
|
||||
@@ -3304,7 +3410,7 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
return;
|
||||
}
|
||||
|
||||
TransactionLocker tlock;
|
||||
TransactionLocker tlock(this);
|
||||
|
||||
_checkTransaction(pcObject, nullptr, __LINE__);
|
||||
|
||||
|
||||
+26
-11
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SRC_APP_DOCUMENT_H_
|
||||
#define SRC_APP_DOCUMENT_H_
|
||||
#pragma once
|
||||
|
||||
#include <CXX/Objects.hxx>
|
||||
#include <Base/Observer.h>
|
||||
@@ -36,6 +35,7 @@
|
||||
#include "PropertyLinks.h"
|
||||
#include "PropertyStandard.h"
|
||||
#include "ExportInfo.h"
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -500,6 +500,13 @@ public:
|
||||
std::vector<DocumentObject*>
|
||||
addObjects(const char* sType, const std::vector<std::string>& objectNames, bool isNew = true);
|
||||
|
||||
/**
|
||||
* @brief Remove an object from the document.
|
||||
*
|
||||
* @param[in] object The object to remove.
|
||||
*/
|
||||
void removeObject(const DocumentObject* object);
|
||||
|
||||
/**
|
||||
* @brief Remove an object from the document.
|
||||
*
|
||||
@@ -859,7 +866,19 @@ public:
|
||||
* setup a potential transaction that will only be created if there are
|
||||
* actual changes.
|
||||
*/
|
||||
void openTransaction(const char* name = nullptr);
|
||||
int openTransaction(TransactionName name, int tid = 0);
|
||||
int openTransaction(std::string name, int tid = 0);
|
||||
|
||||
// If the tid != 0, it will take the transaction id if it exists
|
||||
int setActiveTransaction(TransactionName name, int tid = 0);
|
||||
|
||||
void lockTransaction();
|
||||
void unlockTransaction();
|
||||
bool isTransactionLocked() const;
|
||||
|
||||
bool transacting() const;
|
||||
|
||||
int getBookedTransactionID() const;
|
||||
|
||||
/**
|
||||
* @brief Rename the current transaction.
|
||||
@@ -869,7 +888,7 @@ public:
|
||||
* @param[in] name The new name of the transaction.
|
||||
* @param[in] id The transaction ID to match.
|
||||
*/
|
||||
void renameTransaction(const char* name, int id) const;
|
||||
void renameTransaction(const std::string& name, int id) const;
|
||||
|
||||
/**
|
||||
* @brief Commit the Command transaction.
|
||||
@@ -1238,7 +1257,7 @@ public:
|
||||
|
||||
/// Check if there is any document restoring/importing.
|
||||
static bool isAnyRestoring();
|
||||
|
||||
|
||||
/// Register a new label.
|
||||
void registerLabel(const std ::string& newLabel);
|
||||
/// Unregister a label.
|
||||
@@ -1403,8 +1422,7 @@ protected:
|
||||
* This function creates an actual transaction regardless of Application
|
||||
* AutoTransaction setting.
|
||||
*/
|
||||
int _openTransaction(const char* name = nullptr, int id = 0);
|
||||
|
||||
int _openTransaction(std::string name = "", int id = 0);
|
||||
/**
|
||||
* @brief Commit the Command transaction.
|
||||
*
|
||||
@@ -1413,8 +1431,7 @@ protected:
|
||||
*
|
||||
* @param notify If true, notify the application to close the transaction.
|
||||
*/
|
||||
void _commitTransaction(bool notify = false);
|
||||
|
||||
bool _commitTransaction(bool notify = false);
|
||||
/**
|
||||
* @brief Abort the running transaction.
|
||||
*
|
||||
@@ -1470,5 +1487,3 @@ T* Document::addObject(const char* pObjectName, bool isNew, const char* viewType
|
||||
}
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_DOCUMENT_H_
|
||||
|
||||
@@ -447,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();
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SRC_APP_DOCUMENTOBJECT_H_
|
||||
#define SRC_APP_DOCUMENTOBJECT_H_
|
||||
#pragma once
|
||||
|
||||
#include <App/TransactionalObject.h>
|
||||
#include <App/PropertyExpressionEngine.h>
|
||||
@@ -1365,5 +1364,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_DOCUMENTOBJECT_H_
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_DOCUMENTOBJECTEXTENSION_H
|
||||
#define APP_DOCUMENTOBJECTEXTENSION_H
|
||||
#pragma once
|
||||
|
||||
#include "Extension.h"
|
||||
|
||||
@@ -144,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
|
||||
{
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SRC_APP_DYNAMICPROPERTY_H_
|
||||
#define SRC_APP_DYNAMICPROPERTY_H_
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -199,6 +198,4 @@ private:
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_DYNAMICPROPERTY_H_
|
||||
} // namespace App
|
||||
@@ -23,8 +23,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef DATA_ELEMENTMAP_H
|
||||
#define DATA_ELEMENTMAP_H
|
||||
#pragma once
|
||||
|
||||
#include "FCGlobal.h"
|
||||
|
||||
@@ -423,5 +422,3 @@ public:
|
||||
|
||||
|
||||
} // namespace Data
|
||||
|
||||
#endif // DATA_ELEMENTMAP_H
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include "ElementNamingUtils.h"
|
||||
#include <charconv>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
|
||||
@@ -123,3 +124,20 @@ const std::string Data::indexSuffix(int index, const char* label)
|
||||
name += std::to_string(index);
|
||||
return name;
|
||||
}
|
||||
|
||||
int Data::indexOfElement(std::string_view s, std::string_view prefix)
|
||||
{
|
||||
int idx = 0;
|
||||
if (prefix.empty()) {
|
||||
return idx;
|
||||
}
|
||||
if (s.starts_with(prefix)) {
|
||||
auto num = s.substr(prefix.size());
|
||||
auto [ptr, ec] = std::from_chars(num.data(), num.data() + num.size(), idx);
|
||||
|
||||
if (ec != std::errc{} || ptr != num.data() + num.size()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#ifndef ELEMENT_NAMING_UTILS_H
|
||||
#define ELEMENT_NAMING_UTILS_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include "FCGlobal.h"
|
||||
|
||||
@@ -120,7 +120,8 @@ AppExport const char *hasMappedElementName(const char *subname);
|
||||
|
||||
AppExport const std::string indexSuffix(int index, const char *label=ELEMENT_MAP_INDEX);
|
||||
|
||||
/// Given a string and a prefix, return the integer index that follows that prefix, or 0 if not found
|
||||
AppExport int indexOfElement(std::string_view s, std::string_view prefix);
|
||||
|
||||
} // namespace Data
|
||||
// clang-format on
|
||||
|
||||
#endif // ELEMENT_NAMING_UTILS_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef BASE_ENUMERATION_H
|
||||
#define BASE_ENUMERATION_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -194,5 +193,3 @@ private:
|
||||
friend class PropertyEnumeration;
|
||||
}; // class Enumeration
|
||||
} // namespace App
|
||||
|
||||
#endif // #ifndef BASE_ENUMERATION_H
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#ifndef SRC_APP_EXPORTINFO_H_
|
||||
#define SRC_APP_EXPORTINFO_H_
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
|
||||
@@ -23,5 +22,3 @@ struct ExportInfo {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+96
-81
@@ -636,25 +636,31 @@ bool isAnyEqual(const App::any &v1, const App::any &v2) {
|
||||
return !!res;
|
||||
}
|
||||
|
||||
Expression* expressionFromPy(const DocumentObject *owner, const Py::Object &value) {
|
||||
ExpressionPtr expressionFromPy(const DocumentObject* owner, const Py::Object& value)
|
||||
{
|
||||
if (value.isNone())
|
||||
return new PyObjectExpression(owner);
|
||||
return std::make_unique<PyObjectExpression>(owner);
|
||||
if(value.isString()) {
|
||||
return new StringExpression(owner,value.as_string());
|
||||
return std::make_unique<StringExpression>(owner, value.as_string());
|
||||
} else if (PyObject_TypeCheck(value.ptr(),&QuantityPy::Type)) {
|
||||
return new NumberExpression(owner,
|
||||
*static_cast<QuantityPy*>(value.ptr())->getQuantityPtr());
|
||||
return std::make_unique<NumberExpression>(
|
||||
owner,
|
||||
*static_cast<QuantityPy*>(value.ptr())->getQuantityPtr()
|
||||
);
|
||||
} else if (value.isBoolean()) {
|
||||
if(value.isTrue())
|
||||
return new ConstantExpression(owner,"True",Quantity(1.0));
|
||||
else
|
||||
return new ConstantExpression(owner,"False",Quantity(0.0));
|
||||
if (value.isTrue()) {
|
||||
return std::make_unique<ConstantExpression>(owner, "True", Quantity(1.0));
|
||||
}
|
||||
else {
|
||||
return std::make_unique<ConstantExpression>(owner, "False", Quantity(0.0));
|
||||
}
|
||||
} else {
|
||||
Quantity q;
|
||||
if(pyToQuantity(q,value))
|
||||
return new NumberExpression(owner,q);
|
||||
if (pyToQuantity(q, value)) {
|
||||
return std::make_unique<NumberExpression>(owner, q);
|
||||
}
|
||||
}
|
||||
return new PyObjectExpression(owner,value.ptr());
|
||||
return std::make_unique<PyObjectExpression>(owner, value.ptr());
|
||||
}
|
||||
|
||||
} // namespace App
|
||||
@@ -686,12 +692,7 @@ Expression::Component::Component(const Component &other)
|
||||
,e3(other.e3?other.e3->copy():nullptr)
|
||||
{}
|
||||
|
||||
Expression::Component::~Component()
|
||||
{
|
||||
delete e1;
|
||||
delete e2;
|
||||
delete e3;
|
||||
}
|
||||
Expression::Component::~Component() = default;
|
||||
|
||||
Expression::Component* Expression::Component::copy() const {
|
||||
return new Component(*this);
|
||||
@@ -881,7 +882,7 @@ int Expression::priority() const {
|
||||
return 20;
|
||||
}
|
||||
|
||||
Expression * Expression::parse(const DocumentObject *owner, const std::string &buffer)
|
||||
ExpressionPtr Expression::parse(const DocumentObject* owner, const std::string& buffer)
|
||||
{
|
||||
return ExpressionParser::parse(owner, buffer.c_str());
|
||||
}
|
||||
@@ -1024,7 +1025,7 @@ ExpressionPtr Expression::importSubNames(const std::map<std::string,std::string>
|
||||
ImportSubNamesExpressionVisitor v(subNameMap);
|
||||
auto res = copy();
|
||||
res->visit(v);
|
||||
return ExpressionPtr(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
class UpdateLabelExpressionVisitor : public ExpressionVisitor {
|
||||
@@ -1056,7 +1057,7 @@ ExpressionPtr Expression::updateLabelReference(
|
||||
UpdateLabelExpressionVisitor v(obj,ref,newLabel);
|
||||
auto expr = copy();
|
||||
expr->visit(v);
|
||||
return ExpressionPtr(expr);
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
@@ -1101,7 +1102,7 @@ ExpressionPtr Expression::replaceObject(const DocumentObject *parent,
|
||||
auto expr = copy();
|
||||
v.collect = false;
|
||||
expr->visit(v);
|
||||
return ExpressionPtr(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
App::any Expression::getValueAsAny() const {
|
||||
@@ -1135,9 +1136,10 @@ void Expression::visit(ExpressionVisitor &v) {
|
||||
v.visit(*this);
|
||||
}
|
||||
|
||||
Expression* Expression::eval() const {
|
||||
ExpressionPtr Expression::eval() const
|
||||
{
|
||||
Base::PyGILStateLocker lock;
|
||||
return expressionFromPy(owner,getPyValue());
|
||||
return expressionFromPy(owner, getPyValue());
|
||||
}
|
||||
|
||||
bool Expression::isSame(const Expression &other, bool checkComment) const {
|
||||
@@ -1175,8 +1177,9 @@ void Expression::toString(std::ostream &ss, bool persistent, bool checkPriority,
|
||||
c->toString(ss,persistent);
|
||||
}
|
||||
|
||||
Expression* Expression::copy() const {
|
||||
auto expr = _copy();
|
||||
ExpressionPtr Expression::copy() const
|
||||
{
|
||||
auto expr = std::unique_ptr<Expression>(_copy());
|
||||
copy_vector(expr->components,components);
|
||||
expr->comment = comment;
|
||||
return expr;
|
||||
@@ -1223,9 +1226,9 @@ void UnitExpression::setUnit(const Quantity &_quantity)
|
||||
}
|
||||
}
|
||||
|
||||
Expression *UnitExpression::simplify() const
|
||||
ExpressionPtr UnitExpression::simplify() const
|
||||
{
|
||||
return new NumberExpression(owner, quantity);
|
||||
return std::make_unique<NumberExpression>(owner, quantity);
|
||||
}
|
||||
|
||||
void UnitExpression::_toString(std::ostream &ss, bool,int) const
|
||||
@@ -1255,7 +1258,7 @@ NumberExpression::NumberExpression(const DocumentObject *_owner, const Quantity
|
||||
{
|
||||
}
|
||||
|
||||
Expression *NumberExpression::simplify() const
|
||||
ExpressionPtr NumberExpression::simplify() const
|
||||
{
|
||||
return copy();
|
||||
}
|
||||
@@ -1436,19 +1439,17 @@ Py::Object OperatorExpression::_getPyValue() const {
|
||||
return calc(this,op,left,right,false);
|
||||
}
|
||||
|
||||
Expression *OperatorExpression::simplify() const
|
||||
ExpressionPtr OperatorExpression::simplify() const
|
||||
{
|
||||
Expression * v1 = left->simplify();
|
||||
Expression * v2 = right->simplify();
|
||||
ExpressionPtr v1 = left->simplify();
|
||||
ExpressionPtr v2 = right->simplify();
|
||||
|
||||
// Both arguments reduced to numerics? Then evaluate and return answer
|
||||
if (freecad_cast<NumberExpression*>(v1) && freecad_cast<NumberExpression*>(v2)) {
|
||||
delete v1;
|
||||
delete v2;
|
||||
if (freecad_cast<NumberExpression*>(v1.get()) && freecad_cast<NumberExpression*>(v2.get())) {
|
||||
return eval();
|
||||
}
|
||||
else
|
||||
return new OperatorExpression(owner, v1, op, v2);
|
||||
return std::make_unique<OperatorExpression>(owner, v1.release(), op, v2.release());
|
||||
}
|
||||
|
||||
void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
|
||||
@@ -1554,7 +1555,7 @@ void OperatorExpression::_toString(std::ostream &s, bool persistent,int) const
|
||||
|
||||
Expression *OperatorExpression::_copy() const
|
||||
{
|
||||
return new OperatorExpression(owner, left->copy(), op, right->copy());
|
||||
return new OperatorExpression(owner, left->copy().release(), op, right->copy().release());
|
||||
}
|
||||
|
||||
int OperatorExpression::priority() const
|
||||
@@ -2584,18 +2585,19 @@ Py::Object FunctionExpression::_getPyValue() const {
|
||||
return evaluate(this,f,args);
|
||||
}
|
||||
|
||||
Expression *FunctionExpression::simplify() const
|
||||
ExpressionPtr FunctionExpression::simplify() const
|
||||
{
|
||||
size_t numerics = 0;
|
||||
std::vector<Expression*> simplifiedArgs;
|
||||
|
||||
// Try to simplify each argument to function
|
||||
for (auto it : args) {
|
||||
Expression * v = it->simplify();
|
||||
ExpressionPtr v = it->simplify();
|
||||
|
||||
if (freecad_cast<NumberExpression*>(v))
|
||||
if (freecad_cast<NumberExpression*>(v.get())) {
|
||||
++numerics;
|
||||
simplifiedArgs.push_back(v);
|
||||
}
|
||||
simplifiedArgs.push_back(v.release());
|
||||
}
|
||||
|
||||
if (numerics == args.size()) {
|
||||
@@ -2608,8 +2610,12 @@ Expression *FunctionExpression::simplify() const
|
||||
return eval();
|
||||
}
|
||||
else
|
||||
return new FunctionExpression(owner, f, std::string(fname),
|
||||
std::move(simplifiedArgs));
|
||||
return std::make_unique<FunctionExpression>(
|
||||
owner,
|
||||
f,
|
||||
std::string(fname),
|
||||
std::move(simplifiedArgs)
|
||||
);
|
||||
}
|
||||
|
||||
void FunctionExpression::_toString(std::ostream &ss, bool persistent,int) const
|
||||
@@ -2768,7 +2774,7 @@ Expression *FunctionExpression::_copy() const
|
||||
std::vector<Expression*> a;
|
||||
|
||||
while (i != args.end()) {
|
||||
a.push_back((*i)->copy());
|
||||
a.push_back((*i)->copy().release());
|
||||
++i;
|
||||
}
|
||||
return new FunctionExpression(owner, f, std::string(fname), std::move(a));
|
||||
@@ -2824,16 +2830,16 @@ void VariableExpression::addComponent(Component *c) {
|
||||
}
|
||||
long l1=0,l2=0,l3=1;
|
||||
if(c->e3) {
|
||||
auto n3 = freecad_cast<NumberExpression*>(c->e3);
|
||||
auto n3 = freecad_cast<NumberExpression*>(c->e3.get());
|
||||
if(!n3 || !essentiallyEqual(n3->getValue(),(double)l3))
|
||||
break;
|
||||
}
|
||||
if(c->e1) {
|
||||
auto n1 = freecad_cast<NumberExpression*>(c->e1);
|
||||
auto n1 = freecad_cast<NumberExpression*>(c->e1.get());
|
||||
if(!n1) {
|
||||
if(c->e2 || c->e3)
|
||||
break;
|
||||
auto s = freecad_cast<StringExpression*>(c->e1);
|
||||
auto s = freecad_cast<StringExpression*>(c->e1.get());
|
||||
if(!s)
|
||||
break;
|
||||
var << ObjectIdentifier::MapComponent(
|
||||
@@ -2850,7 +2856,7 @@ void VariableExpression::addComponent(Component *c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto n2 = freecad_cast<NumberExpression*>(c->e2);
|
||||
auto n2 = freecad_cast<NumberExpression*>(c->e2.get());
|
||||
if(n2 && essentiallyInteger(n2->getValue(),l2)) {
|
||||
var << ObjectIdentifier::RangeComponent(l1,l2,l3);
|
||||
return;
|
||||
@@ -2875,7 +2881,7 @@ void VariableExpression::_toString(std::ostream &ss, bool persistent,int) const
|
||||
ss << var.toString();
|
||||
}
|
||||
|
||||
Expression *VariableExpression::simplify() const
|
||||
ExpressionPtr VariableExpression::simplify() const
|
||||
{
|
||||
return copy();
|
||||
}
|
||||
@@ -3080,7 +3086,7 @@ StringExpression::~StringExpression() {
|
||||
}
|
||||
}
|
||||
|
||||
Expression *StringExpression::simplify() const
|
||||
ExpressionPtr StringExpression::simplify() const
|
||||
{
|
||||
return copy();
|
||||
}
|
||||
@@ -3128,18 +3134,26 @@ Py::Object ConditionalExpression::_getPyValue() const {
|
||||
return falseExpr->getPyValue();
|
||||
}
|
||||
|
||||
Expression *ConditionalExpression::simplify() const
|
||||
ExpressionPtr ConditionalExpression::simplify() const
|
||||
{
|
||||
std::unique_ptr<Expression> e(condition->simplify());
|
||||
ExpressionPtr e = condition->simplify();
|
||||
NumberExpression * v = freecad_cast<NumberExpression*>(e.get());
|
||||
|
||||
if (!v)
|
||||
return new ConditionalExpression(owner, condition->simplify(), trueExpr->simplify(), falseExpr->simplify());
|
||||
if (!v) {
|
||||
return std::make_unique<ConditionalExpression>(
|
||||
owner,
|
||||
condition->simplify().release(),
|
||||
trueExpr->simplify().release(),
|
||||
falseExpr->simplify().release()
|
||||
);
|
||||
}
|
||||
else {
|
||||
if (fabs(v->getValue()) >= Base::Precision::Confusion())
|
||||
if (fabs(v->getValue()) >= Base::Precision::Confusion()) {
|
||||
return trueExpr->simplify();
|
||||
else
|
||||
}
|
||||
else {
|
||||
return falseExpr->simplify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3166,7 +3180,12 @@ void ConditionalExpression::_toString(std::ostream &ss, bool persistent,int) con
|
||||
|
||||
Expression *ConditionalExpression::_copy() const
|
||||
{
|
||||
return new ConditionalExpression(owner, condition->copy(), trueExpr->copy(), falseExpr->copy());
|
||||
return new ConditionalExpression(
|
||||
owner,
|
||||
condition->copy().release(),
|
||||
trueExpr->copy().release(),
|
||||
falseExpr->copy().release()
|
||||
);
|
||||
}
|
||||
|
||||
int ConditionalExpression::priority() const
|
||||
@@ -3262,7 +3281,7 @@ Expression *RangeExpression::_copy() const
|
||||
return new RangeExpression(owner, begin, end);
|
||||
}
|
||||
|
||||
Expression *RangeExpression::simplify() const
|
||||
ExpressionPtr RangeExpression::simplify() const
|
||||
{
|
||||
return copy();
|
||||
}
|
||||
@@ -3459,7 +3478,7 @@ double num_change(char* yytext,char dez_delim,char grp_delim)
|
||||
}
|
||||
|
||||
/// The resulting expression after a successful parsing.
|
||||
static Expression* ScanResult = nullptr;
|
||||
static ExpressionPtr ScanResult = ExpressionPtr {};
|
||||
|
||||
/// The DocumentObject that will own the expression.
|
||||
static const App::DocumentObject* DocumentObject = nullptr;
|
||||
@@ -3539,7 +3558,7 @@ static void initParser(const App::DocumentObject *owner)
|
||||
|
||||
using namespace App::ExpressionParser;
|
||||
|
||||
ScanResult = nullptr;
|
||||
ScanResult.reset();
|
||||
App::ExpressionParser::DocumentObject = owner;
|
||||
labels = std::stack<std::string>();
|
||||
column = 0;
|
||||
@@ -3659,7 +3678,7 @@ std::vector<std::tuple<int, int, std::string> > tokenize(const std::string &str)
|
||||
*
|
||||
*/
|
||||
|
||||
Expression * App::ExpressionParser::parse(const App::DocumentObject *owner, const char* buffer)
|
||||
ExpressionPtr App::ExpressionParser::parse(const App::DocumentObject* owner, const char* buffer)
|
||||
{
|
||||
// parse from buffer
|
||||
ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
|
||||
@@ -3678,16 +3697,17 @@ Expression * App::ExpressionParser::parse(const App::DocumentObject *owner, cons
|
||||
throw ParserError(fmt::format("Unknown error in expression '{}'", buffer));
|
||||
}
|
||||
|
||||
if (valueExpression) {
|
||||
return ScanResult;
|
||||
}
|
||||
else {
|
||||
delete ScanResult;
|
||||
if (!valueExpression) {
|
||||
ScanResult.reset();
|
||||
throw Expression::Exception("Expression can not evaluate to a value.");
|
||||
}
|
||||
return std::exchange(ScanResult, nullptr);
|
||||
}
|
||||
|
||||
UnitExpression * ExpressionParser::parseUnit(const App::DocumentObject *owner, const char* buffer)
|
||||
std::unique_ptr<UnitExpression> ExpressionParser::parseUnit(
|
||||
const App::DocumentObject* owner,
|
||||
const char* buffer
|
||||
)
|
||||
{
|
||||
// parse from buffer
|
||||
ExpressionParser::YY_BUFFER_STATE my_string_buffer = ExpressionParser::ExpressionParser_scan_string (buffer);
|
||||
@@ -3705,10 +3725,10 @@ UnitExpression * ExpressionParser::parseUnit(const App::DocumentObject *owner, c
|
||||
throw ParserError("Unknown error in expression");
|
||||
|
||||
// Simplify expression
|
||||
Expression * simplified = ScanResult->simplify();
|
||||
ExpressionPtr simplified = ScanResult->simplify();
|
||||
|
||||
if (!unitExpression) {
|
||||
OperatorExpression * fraction = freecad_cast<OperatorExpression*>(ScanResult);
|
||||
auto* fraction = freecad_cast<OperatorExpression*>(ScanResult.get());
|
||||
|
||||
if (fraction && fraction->getOperator() == OperatorExpression::DIV) {
|
||||
NumberExpression * nom = freecad_cast<NumberExpression*>(fraction->getLeft());
|
||||
@@ -3719,21 +3739,16 @@ UnitExpression * ExpressionParser::parseUnit(const App::DocumentObject *owner, c
|
||||
unitExpression = true;
|
||||
}
|
||||
}
|
||||
delete ScanResult;
|
||||
ScanResult.reset();
|
||||
|
||||
if (unitExpression) {
|
||||
NumberExpression * num = freecad_cast<NumberExpression*>(simplified);
|
||||
|
||||
if (num) {
|
||||
simplified = new UnitExpression(num->getOwner(), num->getQuantity());
|
||||
delete num;
|
||||
}
|
||||
return freecad_cast<UnitExpression*>(simplified);
|
||||
}
|
||||
else {
|
||||
delete simplified;
|
||||
if (!unitExpression) {
|
||||
throw Expression::Exception("Expression is not a unit.");
|
||||
}
|
||||
|
||||
if (auto num = freecad_cast<NumberExpression*>(simplified.get()); num) {
|
||||
return std::make_unique<UnitExpression>(num->getOwner(), num->getQuantity());
|
||||
}
|
||||
return std::unique_ptr<UnitExpression>(freecad_cast<UnitExpression*>(simplified.release()));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXPRESSION_H
|
||||
#define EXPRESSION_H
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
@@ -332,7 +331,7 @@ public:
|
||||
*
|
||||
* @return The evaluated expression.
|
||||
*/
|
||||
Expression* eval() const;
|
||||
ExpressionPtr eval() const;
|
||||
|
||||
/**
|
||||
* @brief Convert the expression to a string.
|
||||
@@ -363,10 +362,10 @@ public:
|
||||
*
|
||||
* @return The parsed expression.
|
||||
*/
|
||||
static Expression* parse(const App::DocumentObject * owner, const std::string& buffer);
|
||||
static ExpressionPtr parse(const App::DocumentObject* owner, const std::string& buffer);
|
||||
|
||||
/// Copy an expression.
|
||||
Expression * copy() const;
|
||||
ExpressionPtr copy() const;
|
||||
|
||||
/**
|
||||
* @brief Get the operator priority.
|
||||
@@ -487,7 +486,7 @@ public:
|
||||
*
|
||||
* @return The simplified expression.
|
||||
*/
|
||||
virtual Expression * simplify() const = 0;
|
||||
virtual ExpressionPtr simplify() const = 0;
|
||||
|
||||
/// Visit the expression with a visitor.
|
||||
void visit(ExpressionVisitor & v);
|
||||
@@ -580,6 +579,4 @@ public:
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EXPRESSION_H
|
||||
}
|
||||
@@ -211,6 +211,9 @@ EXPO [eE][-+]?[0-9]+
|
||||
"h" COUNTCHARS; yylval.quantity.scaler = Quantity::Hour; yylval.quantity.unitStr = yytext; return UNIT; // hour
|
||||
|
||||
"A" COUNTCHARS; yylval.quantity.scaler = Quantity::Ampere; yylval.quantity.unitStr = yytext; return UNIT; // Ampere (internal standard electric current)
|
||||
"nA" COUNTCHARS; yylval.quantity.scaler = Quantity::NanoAmpere; yylval.quantity.unitStr = yytext; return UNIT; // nano Ampere
|
||||
"uA" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroAmpere; yylval.quantity.unitStr = yytext; return UNIT; // micro Ampere
|
||||
"\xC2\xB5""A" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroAmpere; yylval.quantity.unitStr = yytext; return UNIT; // micro Ampere
|
||||
"mA" COUNTCHARS; yylval.quantity.scaler = Quantity::MilliAmpere; yylval.quantity.unitStr = yytext; return UNIT; // milli Ampere
|
||||
"kA" COUNTCHARS; yylval.quantity.scaler = Quantity::KiloAmpere; yylval.quantity.unitStr = yytext; return UNIT; // kilo Ampere
|
||||
"MA" COUNTCHARS; yylval.quantity.scaler = Quantity::MegaAmpere; yylval.quantity.unitStr = yytext; return UNIT; // mega Ampere
|
||||
@@ -221,6 +224,9 @@ EXPO [eE][-+]?[0-9]+
|
||||
"uK" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroKelvin; yylval.quantity.unitStr = yytext; return UNIT; // micro Kelvin
|
||||
|
||||
"mol" COUNTCHARS; yylval.quantity.scaler = Quantity::Mole; yylval.quantity.unitStr = yytext; return UNIT; // Mole (internal standard amount of substance)
|
||||
"nmol" COUNTCHARS; yylval.quantity.scaler = Quantity::NanoMole; yylval.quantity.unitStr = yytext; return UNIT; // nano Mole
|
||||
"\xC2\xB5mol" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroMole; yylval.quantity.unitStr = yytext; return UNIT; // micro Mole
|
||||
"umol" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroMole; yylval.quantity.unitStr = yytext; return UNIT; // micro Mole
|
||||
"mmol" COUNTCHARS; yylval.quantity.scaler = Quantity::MilliMole; yylval.quantity.unitStr = yytext; return UNIT; // milli Mole
|
||||
|
||||
"cd" COUNTCHARS; yylval.quantity.scaler = Quantity::Candela; yylval.quantity.unitStr = yytext; return UNIT; // Candela (internal standard luminous intensity)
|
||||
@@ -269,6 +275,9 @@ EXPO [eE][-+]?[0-9]+
|
||||
"Mpsi" COUNTCHARS; yylval.quantity.scaler = Quantity::MPSI; yylval.quantity.unitStr = yytext; return UNIT; // 1000 ksi
|
||||
|
||||
"W" COUNTCHARS; yylval.quantity.scaler = Quantity::Watt; yylval.quantity.unitStr = yytext; return UNIT; // Watt (kg*m^2/s^3)
|
||||
"nW" COUNTCHARS; yylval.quantity.scaler = Quantity::NanoWatt; yylval.quantity.unitStr = yytext; return UNIT; // nano Watt
|
||||
"uW" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroWatt; yylval.quantity.unitStr = yytext; return UNIT; // micro Watt
|
||||
"\xC2\xB5W" COUNTCHARS; yylval.quantity.scaler = Quantity::MicroWatt; yylval.quantity.unitStr = yytext; return UNIT; // micro Watt
|
||||
"mW" COUNTCHARS; yylval.quantity.scaler = Quantity::MilliWatt; yylval.quantity.unitStr = yytext; return UNIT; // milli Watt
|
||||
"kW" COUNTCHARS; yylval.quantity.scaler = Quantity::KiloWatt; yylval.quantity.unitStr = yytext; return UNIT; // kilo Watt
|
||||
"VA" COUNTCHARS; yylval.quantity.scaler = Quantity::VoltAmpere; yylval.quantity.unitStr = yytext; return UNIT; // VoltAmpere (kg*m^2/s^3)
|
||||
|
||||
+6215
-6349
File diff suppressed because it is too large
Load Diff
+10
-178
@@ -70,7 +70,6 @@
|
||||
|
||||
|
||||
/* First part of user prologue. */
|
||||
#line 26 "Expression.y"
|
||||
|
||||
#define YYSTYPE App::ExpressionParser::semantic_type
|
||||
|
||||
@@ -79,7 +78,6 @@ std::stack<FunctionExpression::Function> functions; /**< Function
|
||||
#define yyparse ExpressionParser_yyparse
|
||||
#define yyerror ExpressionParser_yyerror
|
||||
|
||||
#line 80 "Expression.tab.c"
|
||||
|
||||
# ifndef YY_CAST
|
||||
# ifdef __cplusplus
|
||||
@@ -555,14 +553,14 @@ static const yytype_int8 yytranslate[] =
|
||||
/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
|
||||
static const yytype_uint8 yyrline[] =
|
||||
{
|
||||
0, 81, 81, 82, 85, 86, 89, 90, 91, 92,
|
||||
93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
|
||||
103, 104, 105, 106, 107, 108, 109, 110, 111, 114,
|
||||
115, 116, 117, 119, 120, 121, 122, 123, 124, 127,
|
||||
131, 132, 134, 135, 136, 137, 138, 139, 140, 143,
|
||||
144, 148, 149, 153, 154, 158, 163, 168, 174, 181,
|
||||
188, 195, 199, 200, 201, 202, 203, 204, 205, 206,
|
||||
210, 211, 212, 216, 217, 221, 222
|
||||
0, 83, 83, 84, 87, 88, 91, 92, 93, 94,
|
||||
95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
||||
105, 106, 107, 108, 109, 110, 111, 112, 113, 116,
|
||||
117, 118, 119, 121, 122, 123, 124, 125, 126, 129,
|
||||
133, 134, 136, 137, 138, 139, 140, 141, 142, 145,
|
||||
146, 150, 151, 155, 156, 160, 165, 170, 176, 183,
|
||||
190, 197, 201, 202, 203, 204, 205, 206, 207, 208,
|
||||
212, 213, 214, 218, 219, 223, 224
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1007,45 +1005,31 @@ yydestruct (const char *yymsg,
|
||||
switch (yykind)
|
||||
{
|
||||
case YYSYMBOL_exp: /* exp */
|
||||
#line 73 "Expression.y"
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1010 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_num: /* num */
|
||||
#line 73 "Expression.y"
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1016 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_args: /* args */
|
||||
#line 75 "Expression.y"
|
||||
{ std::vector<Expression*>::const_iterator i = ((*yyvaluep).arguments).begin(); while (i != ((*yyvaluep).arguments).end()) { delete *i; ++i; } }
|
||||
#line 1022 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_range: /* range */
|
||||
#line 73 "Expression.y"
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1028 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_unit_exp: /* unit_exp */
|
||||
#line 73 "Expression.y"
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1034 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_indexer: /* indexer */
|
||||
#line 74 "Expression.y"
|
||||
{ delete ((*yyvaluep).component); }
|
||||
#line 1040 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case YYSYMBOL_indexable: /* indexable */
|
||||
#line 73 "Expression.y"
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1046 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1313,356 +1297,243 @@ yyreduce:
|
||||
switch (yyn)
|
||||
{
|
||||
case 2: /* input: exp */
|
||||
#line 81 "Expression.y"
|
||||
{ ScanResult = (yyvsp[0].expr); valueExpression = true; }
|
||||
#line 1316 "Expression.tab.c"
|
||||
{ ScanResult = std::unique_ptr<Expression>((yyvsp[0].expr)); valueExpression = true; }
|
||||
break;
|
||||
|
||||
case 3: /* input: unit_exp */
|
||||
#line 82 "Expression.y"
|
||||
{ ScanResult = (yyvsp[0].expr); unitExpression = true; }
|
||||
#line 1322 "Expression.tab.c"
|
||||
{ ScanResult = std::unique_ptr<Expression>((yyvsp[0].expr)); unitExpression = true; }
|
||||
break;
|
||||
|
||||
case 4: /* unit_num: num unit_exp */
|
||||
#line 85 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)); }
|
||||
#line 1328 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 5: /* unit_num: num us_building_unit num us_building_unit */
|
||||
#line 86 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::UNIT, (yyvsp[-2].expr)), OperatorExpression::ADD, new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)));}
|
||||
#line 1334 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 6: /* exp: num */
|
||||
#line 89 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1340 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 7: /* exp: unit_num */
|
||||
#line 90 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1346 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 8: /* exp: STRING */
|
||||
#line 91 "Expression.y"
|
||||
{ (yyval.expr) = new StringExpression(DocumentObject, (yyvsp[0].string)); }
|
||||
#line 1352 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 9: /* exp: identifier */
|
||||
#line 92 "Expression.y"
|
||||
{ (yyval.expr) = new VariableExpression(DocumentObject, (yyvsp[0].path)); }
|
||||
#line 1358 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 10: /* exp: MINUSSIGN exp */
|
||||
#line 93 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1))); }
|
||||
#line 1364 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 11: /* exp: '+' exp */
|
||||
#line 94 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::POS, new NumberExpression(DocumentObject, Quantity(1))); }
|
||||
#line 1370 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 12: /* exp: exp '+' exp */
|
||||
#line 95 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::ADD, (yyvsp[0].expr)); }
|
||||
#line 1376 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 13: /* exp: exp MINUSSIGN exp */
|
||||
#line 96 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::SUB, (yyvsp[0].expr)); }
|
||||
#line 1382 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 14: /* exp: exp '*' exp */
|
||||
#line 97 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
|
||||
#line 1388 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 15: /* exp: exp '/' exp */
|
||||
#line 98 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1394 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 16: /* exp: exp '%' exp */
|
||||
#line 99 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MOD, (yyvsp[0].expr)); }
|
||||
#line 1400 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 17: /* exp: exp '/' unit_exp */
|
||||
#line 100 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1406 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 18: /* exp: exp '^' exp */
|
||||
#line 101 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, (yyvsp[0].expr)); }
|
||||
#line 1412 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 19: /* exp: exp EQ exp */
|
||||
#line 102 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::EQ, (yyvsp[0].expr)); }
|
||||
#line 1418 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 20: /* exp: exp NEQ exp */
|
||||
#line 103 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::NEQ, (yyvsp[0].expr)); }
|
||||
#line 1424 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 21: /* exp: exp LT exp */
|
||||
#line 104 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LT, (yyvsp[0].expr)); }
|
||||
#line 1430 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 22: /* exp: exp GT exp */
|
||||
#line 105 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GT, (yyvsp[0].expr)); }
|
||||
#line 1436 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 23: /* exp: exp GTE exp */
|
||||
#line 106 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GTE, (yyvsp[0].expr)); }
|
||||
#line 1442 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 24: /* exp: exp LTE exp */
|
||||
#line 107 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LTE, (yyvsp[0].expr)); }
|
||||
#line 1448 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 25: /* exp: indexable */
|
||||
#line 108 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1454 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 26: /* exp: FUNC args ')' */
|
||||
#line 109 "Expression.y"
|
||||
{ (yyval.expr) = new FunctionExpression(DocumentObject, (yyvsp[-2].func).first, std::move((yyvsp[-2].func).second), (yyvsp[-1].arguments));}
|
||||
#line 1460 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 27: /* exp: exp '?' exp ':' exp */
|
||||
#line 110 "Expression.y"
|
||||
{ (yyval.expr) = new ConditionalExpression(DocumentObject, (yyvsp[-4].expr), (yyvsp[-2].expr), (yyvsp[0].expr)); }
|
||||
#line 1466 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 28: /* exp: '(' exp ')' */
|
||||
#line 111 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[-1].expr); }
|
||||
#line 1472 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 29: /* num: ONE */
|
||||
#line 114 "Expression.y"
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
|
||||
#line 1478 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 30: /* num: NUM */
|
||||
#line 115 "Expression.y"
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
|
||||
#line 1484 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 31: /* num: INTEGER */
|
||||
#line 116 "Expression.y"
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))); }
|
||||
#line 1490 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 32: /* num: CONSTANT */
|
||||
#line 117 "Expression.y"
|
||||
{ (yyval.expr) = new ConstantExpression(DocumentObject, (yyvsp[0].constant).name, Quantity((yyvsp[0].constant).fvalue)); }
|
||||
#line 1496 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 33: /* args: exp */
|
||||
#line 119 "Expression.y"
|
||||
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
|
||||
#line 1502 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 34: /* args: range */
|
||||
#line 120 "Expression.y"
|
||||
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
|
||||
#line 1508 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 35: /* args: args ',' exp */
|
||||
#line 121 "Expression.y"
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1514 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 36: /* args: args ';' exp */
|
||||
#line 122 "Expression.y"
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1520 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 37: /* args: args ',' range */
|
||||
#line 123 "Expression.y"
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1526 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 38: /* args: args ';' range */
|
||||
#line 124 "Expression.y"
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1532 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 39: /* range: id_or_cell ':' id_or_cell */
|
||||
#line 127 "Expression.y"
|
||||
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
|
||||
#line 1538 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 40: /* us_building_unit: USUNIT */
|
||||
#line 131 "Expression.y"
|
||||
{ (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); }
|
||||
#line 1544 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 41: /* other_unit: UNIT */
|
||||
#line 132 "Expression.y"
|
||||
{ (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); }
|
||||
#line 1550 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 42: /* unit_exp: other_unit */
|
||||
#line 134 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1556 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 43: /* unit_exp: us_building_unit */
|
||||
#line 135 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1562 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 44: /* unit_exp: unit_exp '/' unit_exp */
|
||||
#line 136 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1568 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 45: /* unit_exp: unit_exp '*' unit_exp */
|
||||
#line 137 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
|
||||
#line 1574 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 46: /* unit_exp: unit_exp '^' integer */
|
||||
#line 138 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue)))); }
|
||||
#line 1580 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 47: /* unit_exp: unit_exp '^' MINUSSIGN integer */
|
||||
#line 139 "Expression.y"
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::POW, new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1)))); }
|
||||
#line 1586 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 48: /* unit_exp: '(' unit_exp ')' */
|
||||
#line 140 "Expression.y"
|
||||
{ (yyval.expr) = (yyvsp[-1].expr); }
|
||||
#line 1592 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 49: /* integer: INTEGER */
|
||||
#line 143 "Expression.y"
|
||||
{ (yyval.ivalue) = (yyvsp[0].ivalue); }
|
||||
#line 1598 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 50: /* integer: ONE */
|
||||
#line 144 "Expression.y"
|
||||
{ (yyval.ivalue) = (yyvsp[0].fvalue); }
|
||||
#line 1604 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 51: /* id_or_cell: IDENTIFIER */
|
||||
#line 148 "Expression.y"
|
||||
{ (yyval.string) = std::move((yyvsp[0].string)); }
|
||||
#line 1610 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 52: /* id_or_cell: CELLADDRESS */
|
||||
#line 149 "Expression.y"
|
||||
{ (yyval.string) = std::move((yyvsp[0].string)); }
|
||||
#line 1616 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 53: /* identifier: id_or_cell */
|
||||
#line 153 "Expression.y"
|
||||
{ (yyval.path) = ObjectIdentifier(DocumentObject); (yyval.path) << ObjectIdentifier::SimpleComponent((yyvsp[0].string)); }
|
||||
#line 1622 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 54: /* identifier: iden */
|
||||
#line 154 "Expression.y"
|
||||
{ (yyval.path) = std::move((yyvsp[0].path)); }
|
||||
#line 1628 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 55: /* iden: '.' STRING '.' id_or_cell */
|
||||
#line 158 "Expression.y"
|
||||
{ /* Path to property of a sub-object of the current object*/
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject,true);
|
||||
(yyval.path).setDocumentObjectName(DocumentObject,false,ObjectIdentifier::String(std::move((yyvsp[-2].string)),true),true);
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
}
|
||||
#line 1638 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 56: /* iden: '.' id_or_cell */
|
||||
#line 163 "Expression.y"
|
||||
{ /* Path to property of the current document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject,true);
|
||||
(yyval.path).setDocumentObjectName(DocumentObject);
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
}
|
||||
#line 1648 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 57: /* iden: object '.' STRING '.' id_or_cell */
|
||||
#line 168 "Expression.y"
|
||||
{ /* Path to property of a sub-object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentObjectName(std::move((yyvsp[-4].string_or_identifier)), true, ObjectIdentifier::String(std::move((yyvsp[-2].string)),true),true);
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1659 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 58: /* iden: object '.' id_or_cell */
|
||||
#line 174 "Expression.y"
|
||||
{ /* Path to property of a given document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyvsp[-2].string_or_identifier).checkImport(DocumentObject);
|
||||
@@ -1670,11 +1541,9 @@ yyreduce:
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1671 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 59: /* iden: document '#' object '.' id_or_cell */
|
||||
#line 181 "Expression.y"
|
||||
{ /* Path to property from an external document, within a named document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentName(std::move((yyvsp[-4].string_or_identifier)), true);
|
||||
@@ -1682,118 +1551,82 @@ yyreduce:
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1683 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 60: /* iden: document '#' object '.' STRING '.' id_or_cell */
|
||||
#line 189 "Expression.y"
|
||||
{ (yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentName(std::move((yyvsp[-6].string_or_identifier)), true);
|
||||
(yyval.path).setDocumentObjectName(std::move((yyvsp[-4].string_or_identifier)), true, ObjectIdentifier::String(std::move((yyvsp[-2].string)),true));
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string)));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1694 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 61: /* iden: iden '.' IDENTIFIER */
|
||||
#line 195 "Expression.y"
|
||||
{ (yyval.path)= std::move((yyvsp[-2].path)); (yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1700 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 62: /* indexer: '[' exp ']' */
|
||||
#line 199 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent((yyvsp[-1].expr)); }
|
||||
#line 1706 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 63: /* indexer: '[' exp ':' ']' */
|
||||
#line 200 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent((yyvsp[-2].expr),0,0,true); }
|
||||
#line 1712 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 64: /* indexer: '[' ':' exp ']' */
|
||||
#line 201 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent(0,(yyvsp[-1].expr)); }
|
||||
#line 1718 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 65: /* indexer: '[' ':' ':' exp ']' */
|
||||
#line 202 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent(0,0,(yyvsp[-1].expr)); }
|
||||
#line 1724 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 66: /* indexer: '[' exp ':' exp ']' */
|
||||
#line 203 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent((yyvsp[-3].expr),(yyvsp[-1].expr));}
|
||||
#line 1730 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 67: /* indexer: '[' exp ':' ':' exp ']' */
|
||||
#line 204 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent((yyvsp[-4].expr),0,(yyvsp[-1].expr)); }
|
||||
#line 1736 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 68: /* indexer: '[' ':' exp ':' exp ']' */
|
||||
#line 205 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent(0,(yyvsp[-3].expr),(yyvsp[-1].expr)); }
|
||||
#line 1742 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 69: /* indexer: '[' exp ':' exp ':' exp ']' */
|
||||
#line 206 "Expression.y"
|
||||
{ (yyval.component) = Expression::createComponent((yyvsp[-5].expr),(yyvsp[-3].expr),(yyvsp[-1].expr));}
|
||||
#line 1748 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 70: /* indexable: identifier indexer */
|
||||
#line 210 "Expression.y"
|
||||
{ (yyval.expr) = new VariableExpression(DocumentObject,(yyvsp[-1].path)); (yyval.expr)->addComponent((yyvsp[0].component)); }
|
||||
#line 1754 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 71: /* indexable: indexable indexer */
|
||||
#line 211 "Expression.y"
|
||||
{ (yyvsp[-1].expr)->addComponent(std::move((yyvsp[0].component))); (yyval.expr) = (yyvsp[-1].expr); }
|
||||
#line 1760 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 72: /* indexable: indexable '.' IDENTIFIER */
|
||||
#line 212 "Expression.y"
|
||||
{ (yyvsp[-2].expr)->addComponent(Expression::createComponent((yyvsp[0].string))); (yyval.expr) = (yyvsp[-2].expr); }
|
||||
#line 1766 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 73: /* document: STRING */
|
||||
#line 216 "Expression.y"
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), true); }
|
||||
#line 1772 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 74: /* document: IDENTIFIER */
|
||||
#line 217 "Expression.y"
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), false, true);}
|
||||
#line 1778 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 75: /* object: STRING */
|
||||
#line 221 "Expression.y"
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), true); }
|
||||
#line 1784 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
case 76: /* object: id_or_cell */
|
||||
#line 222 "Expression.y"
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String(std::move((yyvsp[0].string)), false);}
|
||||
#line 1790 "Expression.tab.c"
|
||||
break;
|
||||
|
||||
|
||||
#line 1794 "Expression.tab.c"
|
||||
|
||||
default: break;
|
||||
}
|
||||
@@ -1986,5 +1819,4 @@ yyreturnlab:
|
||||
return yyresult;
|
||||
}
|
||||
|
||||
#line 225 "Expression.y"
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
// clang-format off
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
@@ -80,8 +80,8 @@ std::stack<FunctionExpression::Function> functions; /**< Function
|
||||
%%
|
||||
|
||||
|
||||
input: exp { ScanResult = $1; valueExpression = true; }
|
||||
| unit_exp { ScanResult = $1; unitExpression = true; }
|
||||
input: exp { ScanResult = std::unique_ptr<Expression>($1); valueExpression = true; }
|
||||
| unit_exp { ScanResult = std::unique_ptr<Expression>($1); unitExpression = true; }
|
||||
;
|
||||
|
||||
unit_num: num unit_exp %prec NUM_AND_UNIT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::UNIT, $2); }
|
||||
|
||||
+16
-19
@@ -24,8 +24,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef EXPRESSION_PARSER_H
|
||||
#define EXPRESSION_PARSER_H
|
||||
#pragma once
|
||||
|
||||
#include "Expression.h"
|
||||
#include <Base/Matrix.h>
|
||||
@@ -48,9 +47,9 @@ namespace App
|
||||
struct AppExport Expression::Component
|
||||
{
|
||||
ObjectIdentifier::Component comp;
|
||||
Expression* e1;
|
||||
Expression* e2;
|
||||
Expression* e3;
|
||||
ExpressionPtr e1;
|
||||
ExpressionPtr e2;
|
||||
ExpressionPtr e3;
|
||||
|
||||
explicit Component(const std::string& n);
|
||||
Component(Expression* e1, Expression* e2, Expression* e3, bool isRange = false);
|
||||
@@ -88,7 +87,7 @@ public:
|
||||
|
||||
~UnitExpression() override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
void setUnit(const Base::Quantity& _quantity);
|
||||
|
||||
@@ -144,7 +143,7 @@ public:
|
||||
explicit NumberExpression(const App::DocumentObject* _owner = nullptr,
|
||||
const Base::Quantity& quantity = Base::Quantity());
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
/**
|
||||
* @brief Negate the stored value.
|
||||
@@ -221,7 +220,7 @@ public:
|
||||
|
||||
bool isTouched() const override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
int priority() const override;
|
||||
|
||||
@@ -274,7 +273,7 @@ public:
|
||||
|
||||
bool isTouched() const override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
int priority() const override;
|
||||
|
||||
@@ -403,7 +402,7 @@ public:
|
||||
|
||||
bool isTouched() const override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
static Py::Object
|
||||
evaluate(const Expression* owner, int type, const std::vector<Expression*>& args);
|
||||
@@ -465,7 +464,7 @@ public:
|
||||
|
||||
bool isTouched() const override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
std::string name() const
|
||||
{
|
||||
@@ -540,7 +539,7 @@ public:
|
||||
|
||||
void setPyValue(Py::Object pyobj);
|
||||
void setPyValue(PyObject* pyobj, bool owned = false);
|
||||
Expression* simplify() const override
|
||||
ExpressionPtr simplify() const override
|
||||
{
|
||||
return copy();
|
||||
}
|
||||
@@ -568,7 +567,7 @@ public:
|
||||
const std::string& _text = std::string());
|
||||
~StringExpression() override;
|
||||
|
||||
Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
virtual std::string getText() const
|
||||
{
|
||||
@@ -602,7 +601,7 @@ public:
|
||||
|
||||
bool isTouched() const override;
|
||||
|
||||
App::Expression* simplify() const override;
|
||||
ExpressionPtr simplify() const override;
|
||||
|
||||
Range getRange() const;
|
||||
|
||||
@@ -630,8 +629,8 @@ protected:
|
||||
*/
|
||||
namespace ExpressionParser
|
||||
{
|
||||
AppExport Expression* parse(const App::DocumentObject* owner, const char* buffer);
|
||||
AppExport UnitExpression* parseUnit(const App::DocumentObject* owner, const char* buffer);
|
||||
AppExport ExpressionPtr parse(const App::DocumentObject* owner, const char* buffer);
|
||||
AppExport std::unique_ptr<UnitExpression> parseUnit(const App::DocumentObject* owner, const char* buffer);
|
||||
AppExport ObjectIdentifier parsePath(const App::DocumentObject* owner, const char* buffer);
|
||||
AppExport bool isTokenAnIndentifier(const std::string& str);
|
||||
AppExport bool isTokenAConstant(const std::string& str);
|
||||
@@ -689,6 +688,4 @@ public:
|
||||
#undef YYSTYPE_ISDECLARED
|
||||
} // namespace ExpressionParser
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // EXPRESSION_PARSER_H
|
||||
} // namespace App
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXPRESSIONTOKENIZER_H
|
||||
#define EXPRESSIONTOKENIZER_H
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <FCGlobal.h>
|
||||
@@ -53,5 +52,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // EXPRESSIONTOKENIZER_H
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H
|
||||
#define RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H
|
||||
#pragma once
|
||||
|
||||
#include "Expression.h"
|
||||
|
||||
@@ -146,5 +145,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H
|
||||
|
||||
+1
-4
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SRC_APP_EXTENSION_H_
|
||||
#define SRC_APP_EXTENSION_H_
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -367,5 +366,3 @@ private:
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_EXTENSION_H_
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef SRC_APP_EXTENSIONCONTAINER_H_
|
||||
#define SRC_APP_EXTENSIONCONTAINER_H_
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -352,5 +351,3 @@ private:
|
||||
PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_)
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // SRC_APP_EXTENSIONCONTAINER_H_
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_EXTENSIONPYTHON_H
|
||||
#define APP_EXTENSIONPYTHON_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/Interpreter.h>
|
||||
#include "Extension.h"
|
||||
@@ -121,5 +120,3 @@ using ExtensionPython = ExtensionPythonT<App::Extension>;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_EXTENSIONPYTHON_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_FEATURECUSTOM_H
|
||||
#define APP_FEATURECUSTOM_H
|
||||
#pragma once
|
||||
|
||||
#include <App/PropertyContainer.h>
|
||||
|
||||
@@ -104,5 +103,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_FEATURECUSTOM_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_FEATUREPYTHON_H
|
||||
#define APP_FEATUREPYTHON_H
|
||||
#pragma once
|
||||
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/PropertyPythonObject.h>
|
||||
@@ -460,5 +459,3 @@ using FeaturePython = FeaturePythonT<DocumentObject>;
|
||||
using GeometryPython = FeaturePythonT<GeoFeature>;
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_FEATUREPYTHON_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
// clang-format off
|
||||
#ifndef APP_FEATUREPYTHONPYIMP_H
|
||||
#define APP_FEATUREPYTHONPYIMP_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Interpreter.h>
|
||||
@@ -118,5 +117,4 @@ private:
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // APP_FEATUREPYTHONPYIMP_H
|
||||
// clang-format on
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_FEATURETEST_H
|
||||
#define APP_FEATURETEST_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "PropertyGeo.h"
|
||||
@@ -222,5 +221,3 @@ public:
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_FEATURETEST_H
|
||||
|
||||
@@ -456,6 +456,8 @@ App.Units.Minute = App.Units.Quantity('min')
|
||||
App.Units.Hour = App.Units.Quantity('h')
|
||||
|
||||
App.Units.Ampere = App.Units.Quantity('A')
|
||||
App.Units.NanoAmpere = App.Units.Quantity('nA')
|
||||
App.Units.MicroAmpere = App.Units.Quantity('uA')
|
||||
App.Units.MilliAmpere = App.Units.Quantity('mA')
|
||||
App.Units.KiloAmpere = App.Units.Quantity('kA')
|
||||
App.Units.MegaAmpere = App.Units.Quantity('MA')
|
||||
@@ -464,8 +466,10 @@ App.Units.Kelvin = App.Units.Quantity('K')
|
||||
App.Units.MilliKelvin = App.Units.Quantity('mK')
|
||||
App.Units.MicroKelvin = App.Units.Quantity('uK')
|
||||
|
||||
App.Units.MilliMole = App.Units.Quantity('mmol')
|
||||
App.Units.Mole = App.Units.Quantity('mol')
|
||||
App.Units.NanoMole = App.Units.Quantity('nmol')
|
||||
App.Units.MicroMole = App.Units.Quantity('umol')
|
||||
App.Units.MilliMole = App.Units.Quantity('mmol')
|
||||
|
||||
App.Units.Candela = App.Units.Quantity('cd')
|
||||
|
||||
@@ -511,6 +515,8 @@ App.Units.KSI = App.Units.Quantity('ksi')
|
||||
App.Units.MPSI = App.Units.Quantity('Mpsi')
|
||||
|
||||
App.Units.Watt = App.Units.Quantity('W')
|
||||
App.Units.NanoWatt = App.Units.Quantity('nW')
|
||||
App.Units.MicroWatt = App.Units.Quantity('uW')
|
||||
App.Units.MilliWatt = App.Units.Quantity('mW')
|
||||
App.Units.KiloWatt = App.Units.Quantity('kW')
|
||||
App.Units.VoltAmpere = App.Units.Quantity('VA')
|
||||
|
||||
@@ -328,7 +328,7 @@ Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
Base::Placement GeoFeature::getGlobalPlacement(App::DocumentObject* targetObj,
|
||||
App::PropertyXLinkSub* prop)
|
||||
{
|
||||
if (!targetObj || !prop) {
|
||||
if (!prop) {
|
||||
return Base::Placement();
|
||||
}
|
||||
|
||||
@@ -357,3 +357,4 @@ Base::Placement GeoFeature::getGlobalPlacement(const DocumentObject* obj)
|
||||
return placementProperty->getValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_GEOFEATURE_H
|
||||
#define APP_GEOFEATURE_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "PropertyGeo.h"
|
||||
@@ -216,6 +215,3 @@ protected:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_GEOFEATURE_H
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_GeoFeatureGroup_H
|
||||
#define APP_GeoFeatureGroup_H
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include "DocumentObject.h"
|
||||
@@ -159,6 +158,3 @@ using GeoFeatureGroupExtensionPython =
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_GeoFeatureGroup_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_GROUPEXTENSION_H
|
||||
#define APP_GROUPEXTENSION_H
|
||||
#pragma once
|
||||
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/DocumentObjectExtension.h>
|
||||
@@ -195,6 +194,3 @@ public:
|
||||
using GroupExtensionPython = ExtensionPythonT<GroupExtensionPythonT<GroupExtension>>;
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_GROUPEXTENSION_H
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef App_ImagePlane_H
|
||||
#define App_ImagePlane_H
|
||||
#pragma once
|
||||
|
||||
#include <App/GeoFeature.h>
|
||||
#include <App/PropertyFile.h>
|
||||
@@ -61,6 +60,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace Image
|
||||
|
||||
|
||||
#endif // App_ImagePlane_H
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_INDEXEDNAME_H
|
||||
#define APP_INDEXEDNAME_H
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
@@ -467,5 +466,3 @@ struct ByteArrayHasher
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
#endif // APP_INDEXEDNAME_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_INVENTOROBJECT_H
|
||||
#define APP_INVENTOROBJECT_H
|
||||
#pragma once
|
||||
|
||||
#include "GeoFeature.h"
|
||||
#include "PropertyStandard.h"
|
||||
@@ -59,6 +58,3 @@ public:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_INVENTOROBJECT_H
|
||||
|
||||
+1
-4
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_LICENSE_H
|
||||
#define APP_LICENSE_H
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
@@ -80,5 +79,3 @@ int constexpr findLicense(const char* identifier)
|
||||
return -1;
|
||||
}
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_LICENSE_H
|
||||
|
||||
+1
-4
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef APP_LINK_H
|
||||
#define APP_LINK_H
|
||||
#pragma once
|
||||
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
@@ -1214,5 +1213,3 @@ public:
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // APP_LINK_H
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
* *
|
||||
**************************************************************************************************/
|
||||
|
||||
#ifndef APP_MAPPED_ELEMENT_H
|
||||
#define APP_MAPPED_ELEMENT_H
|
||||
#pragma once
|
||||
|
||||
#include "IndexedName.h"
|
||||
#include "MappedName.h"
|
||||
@@ -149,6 +148,3 @@ struct AppExport ElementNameComparator
|
||||
};
|
||||
|
||||
} // namespace Data
|
||||
|
||||
|
||||
#endif // APP_MAPPED_ELEMENT_H
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef APP_MAPPED_NAME_H
|
||||
#define APP_MAPPED_NAME_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -1246,6 +1245,3 @@ struct MappedNameRef
|
||||
|
||||
|
||||
} // namespace Data
|
||||
|
||||
|
||||
#endif // APP_MAPPED_NAME_H
|
||||
|
||||
+1
-4
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_MATERIAL_H
|
||||
#define APP_MATERIAL_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/Color.h>
|
||||
|
||||
@@ -169,5 +168,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_MATERIAL_H
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_MaterialObject_H
|
||||
#define APP_MaterialObject_H
|
||||
#pragma once
|
||||
|
||||
#include "DocumentObject.h"
|
||||
#include "FeaturePython.h"
|
||||
@@ -54,7 +53,4 @@ public:
|
||||
using MaterialObjectPython = App::FeaturePythonT<MaterialObject>;
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
#endif // APP_MaterialObject_H
|
||||
} // namespace App
|
||||
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MEASUREMANAGER_H
|
||||
#define MEASUREMANAGER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <vector>
|
||||
@@ -51,6 +50,7 @@ enum class MeasureElementType
|
||||
CIRCLE,
|
||||
ARC,
|
||||
CURVE, // Has a length but no radius or axis
|
||||
DISC,
|
||||
PLANE,
|
||||
CYLINDER,
|
||||
VOLUME,
|
||||
@@ -128,6 +128,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // MEASUREMANAGER_H
|
||||
} // namespace App
|
||||
@@ -23,8 +23,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_MERGEDOCUMENTS_H
|
||||
#define APP_MERGEDOCUMENTS_H
|
||||
#pragma once
|
||||
|
||||
#include <Base/Persistence.h>
|
||||
#include <fastsignals/signal.h>
|
||||
@@ -78,5 +77,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif // APP_MERGEDOCUMENTS_H
|
||||
|
||||
+1
-4
@@ -22,8 +22,7 @@
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef BASE_METADATAREADER_H
|
||||
#define BASE_METADATAREADER_H
|
||||
#pragma once
|
||||
|
||||
#include "FCConfig.h"
|
||||
|
||||
@@ -402,5 +401,3 @@ private:
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user