Merge branch 'main' into tdx-mac

This commit is contained in:
Patryk Skowroński
2024-12-10 12:39:49 +01:00
committed by GitHub
2267 changed files with 227625 additions and 153653 deletions
+4 -2
View File
@@ -1,6 +1,6 @@
name: Report a Problem
description: Have you found something that does not work well, is too hard to do or is missing altogether? Please create a Problem Report.
labels: ["Status: Needs triage"]
labels: ["Status: Needs triage","Status: Needs confirmation"]
body:
- type: checkboxes
id: existing_issue
@@ -22,7 +22,7 @@ body:
id: full_version
attributes:
label: Full version info
description: Please use the About FreeCAD dialog to copy your full version information and paste it here.
description: Please use the About FreeCAD dialog to copy your full version information and paste it here. Try reproducing the issue by restarting FreeCAD in safe mode too.
render: shell
validations:
required: true
@@ -40,6 +40,8 @@ body:
- Expressions
- FEM
- File formats
- Material
- Measurement
- Mesh
- OpenSCAD
- Part
Binary file not shown.

After

Width:  |  Height:  |  Size: 431 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

+4 -32
View File
@@ -39,17 +39,11 @@ jobs:
with:
artifactBasename: Prepare-${{ github.run_id }}
MacOS_13_Conda_Apple:
Pixi:
needs: [Prepare]
uses: ./.github/workflows/sub_buildMacOSCondaApple.yml
uses: ./.github/workflows/sub_buildPixi.yml
with:
artifactBasename: MacOS_13_Conda_Apple-${{ github.run_id }}
# MacOS_13_Conda_Intel:
# needs: [Prepare]
# uses: ./.github/workflows/sub_buildMacOSCondaIntel.yml
# with:
# artifactBasename: MacOS_13_Conda_Intel-${{ github.run_id }}
artifactBasename: Pixi-${{ github.run_id }}
Ubuntu_20-04:
needs: [Prepare]
@@ -57,31 +51,12 @@ jobs:
with:
artifactBasename: Ubuntu_20-04-${{ github.run_id }}
Ubuntu_22-04_Conda:
needs: [Prepare]
uses: ./.github/workflows/sub_buildUbuntu2204Conda.yml
with:
artifactBasename: Ubuntu_22-04_Conda-${{ github.run_id }}
Ubuntu_22-04_Conda_Qt6:
needs: [Prepare]
uses: ./.github/workflows/sub_buildUbuntu2204CondaQt6.yml
with:
artifactBasename: Ubuntu_22-04_Conda-Qt6-${{ github.run_id }}
Windows:
needs: [Prepare]
uses: ./.github/workflows/sub_buildWindows.yml
with:
artifactBasename: Windows-${{ github.run_id }}
## Disable until the following issue is resolved: https://github.com/mamba-org/mamba/issues/3292
# Windows_Conda:
# needs: [Prepare]
# uses: ./.github/workflows/sub_buildWindowsConda.yml
# with:
# artifactBasename: Windows_Conda-${{ github.run_id }}
Lint:
needs: [Prepare]
uses: ./.github/workflows/sub_lint.yml
@@ -94,12 +69,9 @@ jobs:
WrapUp:
needs: [
Prepare,
MacOS_13_Conda_Apple,
# MacOS_13_Conda_Intel,
Pixi,
Ubuntu_20-04,
Ubuntu_22-04_Conda,
Windows,
# Windows_Conda,
Lint
]
if: always()
@@ -0,0 +1,133 @@
# This workflow warns and then closes issues that have had no activity for a
# specified amount of time. You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/marketplace/actions/close-stale-issues
# https://github.com/actions/stale/blob/master/action.yml
# https://github.com/actions/stale
---
name: 'Stale Issues'
on: # yamllint disable-line rule:truthy
schedule:
- cron: '0 0 * * *' # Run at 00:00 UTC every day
workflow_dispatch:
permissions:
contents: read
issues: write # for actions/stale to close stale issues
pull-requests: write # for actions/stale to close stale pull requests
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: '🧹 Tag & close stale unconfirmed bugs'
id: stale_issues
uses: actions/[email protected]
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: -1
days-before-issue-stale: 90
days-before-issue-close: 20
days-before-pr-stale: -1
day-before-pr-close: -1
operations-per-run: 100 # max num of ops per run
stale-issue-label: 'Status: Stale'
close-issue-label: 'Status: Auto-closing'
exempt-issue-labels: 'Status: Confirmed,Priority: High,Priority: Critical,Blocker,Type: Feature,no-auto-close'
remove-stale-when-updated: true
ascending: true
stale-issue-message: |
Hi! This issue hasnt seen activity in a while. If its still relevant, please update to the latest FreeCAD weekly build [download here](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds) to see if the problem is resolved.
If the issue persists, let us know by adding a comment with any updates or details. Otherwise, well close this issue automatically in 20 days to keep our backlog tidy. Feel free to comment anytime to keep it open. Closed issues can always be reopened.
Thanks for helping improve FreeCAD!
Access additional [FreeCAD](https://freecad.org) resources:
- **Forum**: https://forum.freecad.org
- **Blog**: https://blog.freecad.org
- **Wiki**: https://wiki.freecad.org
- name: '🧹 Close stale requested feedback issues'
id: awaiting_issues
uses: actions/[email protected]
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: -1
days-before-issue-stale: 20
days-before-issue-close: 20
days-before-pr-stale: -1
day-before-pr-close: -1
operations-per-run: 30 # max num of ops per run
stale-issue-label: 'Status: Stale'
close-issue-label: 'Status: Auto-closing'
only-labels: 'Status: Needs feedback,Status: Needs test on dev version,Status: Needs steps to reproduce'
remove-stale-when-updated: true
ascending: true
stale-issue-message: |
Hi! This issue hasnt seen activity in a while despite the need for further feedback.
If its still relevant, please update to the latest FreeCAD weekly build [download here](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds) to see if the problem is resolved.
If the issue persists, let us know by adding a comment with any updates or details. Otherwise, well close this issue automatically in 20 days to keep our backlog tidy. Feel free to comment anytime to keep it open. Closed issues can always be reopened.
Thanks for helping improve FreeCAD!
Access additional [FreeCAD](https://freecad.org) resources:
- **Forum**: https://forum.freecad.org
- **Blog**: https://blog.freecad.org
- **Wiki**: https://wiki.freecad.org
- name: '🧹 Tag & close inactive issues'
id: inactive_issues
uses: actions/[email protected]
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: -1
days-before-issue-stale: 190
days-before-issue-close: 60
days-before-pr-stale: -1
day-before-pr-close: -1
operations-per-run: 30 # max num of ops per run
stale-issue-label: 'Status: Stale'
close-issue-label: 'Status: Auto-closing'
exempt-issue-labels: 'Priority: High,Priority: Critical,Blocker,Type: Feature,no-auto-close'
remove-stale-when-updated: true
ascending: true
stale-issue-message: |
Hi! This issue hasnt seen activity in a while. We automatically check each issue after 190 days without activity to keep the backlog tidy.
If its still relevant, please update to the latest FreeCAD weekly build [download here](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds) to see if the issue is already resolved.
If the issue is still relevant, let us know by adding a comment.
Otherwise, well close this issue automatically in 60 days.
Feel free to comment anytime to keep it open. Closed issues can always be reopened.
Thanks for helping improve FreeCAD!
Access additional [FreeCAD](https://freecad.org) resources:
- **Forum**: https://forum.freecad.org
- **Blog**: https://blog.freecad.org
- **Wiki**: https://wiki.freecad.org
- name: '🧹 Tag & close inactive PRs'
id: inactive_pr
uses: actions/[email protected]
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: -1
days-before-issue-stale: -1
days-before-issue-close: -1
days-before-pr-stale: 150
days-before-pr-close: 90
operations-per-run: 30 # max num of ops per run
stale-pr-label: 'Status: Stale'
close-pr-label: 'Status: Auto-closing'
exempt-pr-labels: 'Needs backport,Priority: High,Priority: Critical,no-auto-close'
remove-stale-when-updated: true
ascending: true
stale-pr-message: |
Thanks for helping improve FreeCAD!
This pull request hasnt seen activity in a while. We automatically check each PR after 160 days without activity to keep the repository tidy.
If the PR is still relevant, let us know by adding a comment.
Otherwise, well close this PR automatically in 90 days.
If you would like to keep working on this pull request, we advice to rebase it on current main branch, ask feedback from users or maintainers and engage with the community to get it forward.
@@ -1,171 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2023 0penBrain. *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD on a Conda environment on macOS.
name: Build macOS 13 (Apple Silicon)
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
testOnBuildDir:
default: false
type: boolean
required: false
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
Build:
runs-on: macos-14
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config
CCACHE_MAXSIZE: 1G
CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 1
CC: arm64-apple-darwin20.0.0-clang
CXX: arm64-apple-darwin20.0.0-clang++
builddir: ${{ github.workspace }}/build/release/
logdir: /tmp/logs/
reportdir: /tmp/report/
reportfilename: ${{ inputs.artifactBasename }}-report.md
defaults:
run:
shell: bash -l {0}
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
steps:
- name: Checking out source code
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Miniconda
env:
CONDA_VERBOSITY: 2
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: .conda/freecad
environment-file: conda/conda-env.yaml
channels: conda-forge,defaults
channel-priority: true
miniforge-version: latest
- name: Install FreeCAD dependencies
env:
CONDA_VERBOSITY: 2
run: |
./conda/setup-environment.sh
- name: Set Environment Variables
run: |
echo "CC=$CC" >> "$GITHUB_ENV"
echo "CXX=$CXX" >> "$GITHUB_ENV"
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir -p ${{ env.CCACHE_DIR }}
mkdir -p ${{ env.CCACHE_CONFIGPATH }}
mkdir -p ${{ env.builddir }}
mkdir -p ${{ env.logdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- name: Generate cache key
id: genCacheKey
uses: ./.github/workflows/actions/macos/generateCacheKey
with:
compiler: ${{ env.CXX }}
- name: Restore Compiler Cache
uses: actions/cache@v4
with:
save-always: true
path: ${{ env.CCACHE_DIR }}
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-
FC-${{ steps.genCacheKey.outputs.cacheKey }}-
- name: Print CCache statistics before build, reset stats and print config
run: |
ccache -s
ccache -z
ccache -p
- name: CMake Configure
run: |
mamba run --live-stream -p .conda/freecad cmake --preset conda-macos-release -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.conda/freecad/opt/freecad
- name: CMake Build
run: |
mamba run --live-stream -p .conda/freecad cmake --build build/release
- name: Print ccache statistics after Build
run: |
ccache -s
- name: FreeCAD CLI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on build dir"
testCommand: ${{ env.builddir }}/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: C++ tests
timeout-minutes: 1
uses: ./.github/workflows/actions/runCPPTests/runAllTests
with:
reportdir: ${{ env.reportdir }}
builddir: ${{ env.builddir }}
reportFile: ${{ env.reportdir }}${{ env.reportfilename }}
- name: CMake Install
run: |
mamba run --live-stream -p .conda/freecad cmake --install build/release
- name: FreeCAD CLI tests on install
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on install"
testCommand: ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-Logs
path: |
${{ env.logdir }}
/var/crash/*FreeCAD*
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.reportfilename }}
path: |
${{env.reportdir}}${{ env.reportfilename }}
@@ -1,171 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2023 0penBrain. *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD on a Conda environment on macOS.
name: Build macOS 13 (Intel)
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
testOnBuildDir:
default: false
type: boolean
required: false
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
Build:
runs-on: macos-13
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config
CCACHE_MAXSIZE: 1G
CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 1
CC: x86_64-apple-darwin13.4.0-clang
CXX: x86_64-apple-darwin13.4.0-clang++
builddir: ${{ github.workspace }}/build/release/
logdir: /tmp/logs/
reportdir: /tmp/report/
reportfilename: ${{ inputs.artifactBasename }}-report.md
defaults:
run:
shell: bash -l {0}
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
steps:
- name: Checking out source code
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Miniconda
env:
CONDA_VERBOSITY: 2
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: .conda/freecad
environment-file: conda/conda-env.yaml
channels: conda-forge,defaults
channel-priority: true
miniforge-version: latest
- name: Install FreeCAD dependencies
env:
CONDA_VERBOSITY: 2
run: |
./conda/setup-environment.sh
- name: Set Environment Variables
run: |
echo "CC=$CC" >> "$GITHUB_ENV"
echo "CXX=$CXX" >> "$GITHUB_ENV"
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir -p ${{ env.CCACHE_DIR }}
mkdir -p ${{ env.CCACHE_CONFIGPATH }}
mkdir -p ${{ env.builddir }}
mkdir -p ${{ env.logdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- name: Generate cache key
id: genCacheKey
uses: ./.github/workflows/actions/macos/generateCacheKey
with:
compiler: ${{ env.CXX }}
- name: Restore Compiler Cache
uses: actions/cache@v4
with:
save-always: true
path: ${{ env.CCACHE_DIR }}
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-
FC-${{ steps.genCacheKey.outputs.cacheKey }}-
- name: Print CCache statistics before build, reset stats and print config
run: |
ccache -s
ccache -z
ccache -p
- name: CMake Configure
run: |
mamba run --live-stream -p .conda/freecad cmake --preset conda-macos-release -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.conda/freecad/opt/freecad
- name: CMake Build
run: |
mamba run --live-stream -p .conda/freecad cmake --build build/release
- name: Print ccache statistics after Build
run: |
ccache -s
- name: FreeCAD CLI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on build dir"
testCommand: ${{ env.builddir }}/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: C++ tests
timeout-minutes: 1
uses: ./.github/workflows/actions/runCPPTests/runAllTests
with:
reportdir: ${{ env.reportdir }}
builddir: ${{ env.builddir }}
reportFile: ${{ env.reportdir }}${{ env.reportfilename }}
- name: CMake Install
run: |
mamba run --live-stream -p .conda/freecad cmake --install build/release
- name: FreeCAD CLI tests on install
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on install"
testCommand: ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-Logs
path: |
${{ env.logdir }}
/var/crash/*FreeCAD*
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.reportfilename }}
path: |
${{env.reportdir}}${{ env.reportfilename }}
+203
View File
@@ -0,0 +1,203 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2024 0penBrain, Lorenz Lechner and Jacob Oursland. *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD on a Conda environment on macOS.
name: Pixi Builds
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
testOnBuildDir:
default: false
type: boolean
required: false
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
build_with_pixi:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config
CCACHE_MAXSIZE: 1G
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 5
builddir: ${{ github.workspace }}/build/
cacheKey: pixi-${{ matrix.os }}
logdir: ${{ github.workspace }}/logs/
reportdir: ${{ github.workspace }}/report/
reportfilename: ${{ inputs.artifactBasename }}-${{ matrix.os }}-report.md
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
strategy:
max-parallel: 6
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Set Platform Environment Variables
shell: bash -l {0}
env:
OPERATING_SYSTEM: ${{ runner.os }}
run: |
if [[ $OPERATING_SYSTEM == 'Windows' ]]; then
echo 'CCACHE_COMPILERCHECK=%compiler%' >> "$GITHUB_ENV"
else
echo 'CCACHE_COMPILERCHECK=%compiler% -dumpfullversion -dumpversion' >> "$GITHUB_ENV"
fi
- name: Checkout
uses: actions/checkout@v2
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir -p ${{ env.builddir }}
mkdir -p ${{ env.logdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- uses: prefix-dev/[email protected]
with:
pixi-version: v0.34.0
cache: false
- name: Restore Compiler Cache
uses: actions/cache/restore@v4
with:
path: ${{ env.CCACHE_DIR }}
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-${{ env.cacheKey }}-${{ github.ref }}-
FC-${{ env.cacheKey }}-
- name: Print CCache statistics before build, reset stats and print config
run: |
pixi run ccache -s
pixi run ccache -z
pixi run ccache -p
- name: CMake Configure
run: |
pixi run configure-release
- name: CMake Build
run: |
pixi run build
- name: Print ccache statistics after Build
run: |
pixi run ccache -s
- name: FreeCAD CLI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on build dir"
testCommand: pixi run ${{ env.builddir }}/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on build dir
if: runner.os == 'Linux' && inputs.testOnBuildDir
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on build dir"
testCommand: pixi run xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: C++ tests
timeout-minutes: 10
if: runner.os != 'Windows'
uses: ./.github/workflows/actions/runCPPTests/runAllTests
with:
reportdir: ${{ env.reportdir }}
builddir: ${{ env.builddir }}
reportFile: ${{ env.reportdir }}${{ env.reportfilename }}
- name: CMake Install
run: |
pixi run install
- name: FreeCAD CLI tests on install
if: runner.os != 'Windows'
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on install"
testCommand: pixi run FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on install
# if: runner.os == 'Linux'
# currently broken on Qt6 builds
if: false
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on install"
testCommand: pixi run xvfb-run FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Save Compiler Cache
if: always()
uses: actions/cache/save@v4
with:
path: ${{ env.CCACHE_DIR }}
key: FC-${{ env.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-${{ matrix.os }}-Logs
path: |
${{ env.logdir }}
/var/crash/*FreeCAD*
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.reportfilename }}
path: |
${{env.reportdir}}${{ env.reportfilename }}
@@ -95,8 +95,6 @@ jobs:
libboost-thread-dev \
libcoin-dev \
libeigen3-dev \
libgts-bin \
libgts-dev \
libkdtree++-dev \
libmedc-dev \
libocct-data-exchange-dev \
@@ -1,200 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2023 0penBrain. *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD on a Conda environment on Linux.
name: Build Ubuntu 22.04 (Conda)
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
testOnBuildDir:
default: false
type: boolean
required: false
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
Build:
runs-on: ubuntu-22.04
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config
CCACHE_MAXSIZE: 1G
CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 1
builddir: ${{ github.workspace }}/build/release/
logdir: /tmp/logs/
reportdir: /tmp/report/
reportfilename: ${{ inputs.artifactBasename }}-report.md
defaults:
run:
shell: bash -l {0}
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
steps:
- name: Checking out source code
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Miniconda
env:
CONDA_VERBOSITY: 2
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: .conda/freecad
environment-file: conda/conda-env.yaml
channels: conda-forge,defaults
channel-priority: true
miniforge-version: latest
- name: Install FreeCAD dependencies
env:
CONDA_VERBOSITY: 2
run: |
./conda/setup-environment.sh
- name: Set Environment Variables
run: |
echo "CC=$CC" >> "$GITHUB_ENV"
echo "CXX=$CXX" >> "$GITHUB_ENV"
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir -p ${{ env.CCACHE_DIR }}
mkdir -p ${{ env.CCACHE_CONFIGPATH }}
mkdir -p ${{ env.builddir }}
mkdir -p ${{ env.logdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- name: Generate cache key
id: genCacheKey
uses: ./.github/workflows/actions/linux/generateCacheKey
with:
compiler: ${{ env.CXX }}
qt_major_version: 5
- name: Restore Compiler Cache
uses: actions/cache@v4
with:
save-always: true
path: ${{ env.CCACHE_DIR }}
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-
FC-${{ steps.genCacheKey.outputs.cacheKey }}-
- name: Print CCache statistics before build, reset stats and print config
run: |
ccache -s
ccache -z
ccache -p
- name: CMake Configure
uses: ./.github/workflows/actions/linux/configure
with:
extraParameters: --preset conda-linux-release -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.conda/freecad/opt/freecad
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Cmake.log
errorFile: ${{ env.logdir }}CmakeErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: CMake Build
uses: ./.github/workflows/actions/linux/build
with:
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Build.log
errorFile: ${{ env.logdir }}BuildErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Print ccache statistics after Build
run: |
ccache -s
- name: FreeCAD CLI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on build dir"
testCommand: ${{ env.builddir }}/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on build dir"
testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: C++ tests
timeout-minutes: 1
uses: ./.github/workflows/actions/runCPPTests/runAllTests
with:
reportdir: ${{ env.reportdir }}
builddir: ${{ env.builddir }}
reportFile: ${{ env.reportdir }}${{ env.reportfilename }}
- name: CMake Install
uses: ./.github/workflows/actions/linux/install
with:
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Install.log
errorFile: ${{ env.logdir }}InstallErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD CLI tests on install
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on install"
testCommand: ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on install
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on install"
testCommand: xvfb-run ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-Logs
path: |
${{ env.logdir }}
/var/crash/*FreeCAD*
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.reportfilename }}
path: |
${{env.reportdir}}${{ env.reportfilename }}
@@ -1,211 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# ***************************************************************************
# * *
# * Copyright (c) 2023 0penBrain. *
# * *
# * This file is part of FreeCAD. *
# * *
# * FreeCAD is free software: you can redistribute it and/or modify it *
# * under the terms of the GNU Lesser General Public License as *
# * published by the Free Software Foundation, either version 2.1 of the *
# * License, or (at your option) any later version. *
# * *
# * FreeCAD is distributed in the hope that it will be useful, but *
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
# * Lesser General Public License for more details. *
# * *
# * You should have received a copy of the GNU Lesser General Public *
# * License along with FreeCAD. If not, see *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD on a Conda environment on Linux.
name: Build Ubuntu 22.04 (Conda)
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
testOnBuildDir:
default: false
type: boolean
required: false
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
Build:
runs-on: ubuntu-22.04
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config
CCACHE_MAXSIZE: 1G
CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 1
builddir: ${{ github.workspace }}/build/release/
logdir: /tmp/logs/
reportdir: /tmp/report/
reportfilename: ${{ inputs.artifactBasename }}-report.md
defaults:
run:
shell: bash -l {0}
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
steps:
- name: Checking out source code
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Miniconda
env:
CONDA_VERBOSITY: 2
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: .conda/freecad
environment-file: conda/conda-env-qt6.yaml
channels: conda-forge,defaults
channel-priority: true
miniforge-version: latest
- name: Install FreeCAD dependencies
env:
CONDA_VERBOSITY: 2
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
libegl1 \
libgl1 \
libglx0 \
libopengl0
./conda/setup-environment-qt6.sh
- name: Set Environment Variables
run: |
echo "CC=$CC" >> "$GITHUB_ENV"
echo "CXX=$CXX" >> "$GITHUB_ENV"
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir -p ${{ env.CCACHE_DIR }}
mkdir -p ${{ env.CCACHE_CONFIGPATH }}
mkdir -p ${{ env.builddir }}
mkdir -p ${{ env.logdir }}
mkdir -p ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- name: Generate cache key
id: genCacheKey
uses: ./.github/workflows/actions/linux/generateCacheKey
with:
compiler: ${{ env.CXX }}
qt_major_version: 6
- name: Restore Compiler Cache
uses: actions/cache@v4
with:
save-always: true
path: ${{ env.CCACHE_DIR }}
key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-
FC-${{ steps.genCacheKey.outputs.cacheKey }}-
- name: Print CCache statistics before build, reset stats and print config
run: |
ccache -s
ccache -z
ccache -p
- name: CMake Configure
uses: ./.github/workflows/actions/linux/configure
with:
extraParameters: >
--preset conda-linux-release
-DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.conda/freecad/opt/freecad
-DQT_HOST_PATH=${{ github.workspace }}/.conda/freecad/
-DFREECAD_QT_VERSION=6
-DBUILD_REVERSEENGINEERING=OFF
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Cmake.log
errorFile: ${{ env.logdir }}CmakeErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: CMake Build
uses: ./.github/workflows/actions/linux/build
with:
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Build.log
errorFile: ${{ env.logdir }}BuildErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Print ccache statistics after Build
run: |
ccache -s
- name: FreeCAD CLI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on build dir"
testCommand: ${{ env.builddir }}/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on build dir
if: inputs.testOnBuildDir
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on build dir"
testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIBuild.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: C++ tests
timeout-minutes: 1
uses: ./.github/workflows/actions/runCPPTests/runAllTests
with:
reportdir: ${{ env.reportdir }}
builddir: ${{ env.builddir }}
reportFile: ${{ env.reportdir }}${{ env.reportfilename }}
- name: CMake Install
uses: ./.github/workflows/actions/linux/install
with:
builddir: ${{ env.builddir }}
logFile: ${{ env.logdir }}Install.log
errorFile: ${{ env.logdir }}InstallErrors.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD CLI tests on install
timeout-minutes: 10
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "CLI tests on install"
testCommand: ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCADCmd -t 0
logFile: ${{ env.logdir }}TestCLIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: FreeCAD GUI tests on install
timeout-minutes: 15
uses: ./.github/workflows/actions/runPythonTests
with:
testDescription: "GUI tests on install"
testCommand: xvfb-run ${{ github.workspace }}/.conda/freecad/opt/freecad/bin/FreeCAD -t 0
logFile: ${{ env.logdir }}TestGUIInstall.log
reportFile: ${{env.reportdir}}${{ env.reportfilename }}
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-Logs
path: |
${{ env.logdir }}
/var/crash/*FreeCAD*
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ env.reportfilename }}
path: |
${{env.reportdir}}${{ env.reportfilename }}
-133
View File
@@ -1,133 +0,0 @@
# ***************************************************************************
# * Copyright (c) 2023 0penBrain *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
# This is a build and test workflow for CI of FreeCAD.
# This workflow aims at building and testing FreeCAD using a Conda environment on Windows with MSVC.
name: Build Windows (Conda)
on:
workflow_call:
inputs:
artifactBasename:
type: string
required: true
allowedToFail:
default: false
type: boolean
required: false
outputs:
reportFile:
value: ${{ jobs.Build.outputs.reportFile }}
jobs:
Build:
runs-on: windows-latest
continue-on-error: ${{ inputs.allowedToFail }}
env:
CCACHE_DIR: C:/FC/cache/
CCACHE_COMPILERCHECK: "%compiler%" # default:mtime
CCACHE_MAXSIZE: 1G
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 1
CCACHE_NOHASHDIR: true
CCACHE_DIRECT: true
#CCACHE_SLOPPINESS: "pch_defines,time_macros" # Can't get PCH to work on Windows
CCACHE_LOGFILE: C:/logs/ccache.log
## Have to use C:\ because not enough space on workspace drive
builddir: C:/FC/build/
logdir: C:/logs/
reportdir: C:/report/
reportfilename: ${{ inputs.artifactBasename }}-report.md
outputs:
reportFile: ${{ steps.Init.outputs.reportFile }}
steps:
- name: Checking out source code
uses: actions/checkout@v4
with:
submodules: true
- name: Setup Miniconda
env:
CONDA_VERBOSITY: 2
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: .conda/freecad
environment-file: conda/conda-env.yaml
channels: conda-forge,defaults
channel-priority: true
miniforge-version: latest
- name: Install FreeCAD dependencies
env:
CONDA_VERBOSITY: 2
run: |
conda config --add envs_dirs $PWD/.conda
mamba-devenv --no-prune -f conda/environment.devenv.yml
- name: Make needed directories, files and initializations
id: Init
run: |
mkdir ${{ env.CCACHE_DIR }}
mkdir ${{ env.builddir }}
mkdir ${{ env.logdir }}
mkdir ${{ env.reportdir }}
echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT
- name: Restore compiler cache
uses: actions/cache@v4
with:
save-always: true
path: ${{ env.CCACHE_DIR }}
key: FC-Windows-Conda-${{ github.ref }}-${{ github.run_id }}
restore-keys: |
FC-Windows-Conda-${{ github.ref }}-
FC-Windows-Conda-
- name: Print Ccache statistics before build, reset stats and print config
run: |
ccache -s
ccache -z
ccache -p
- name: Configuring CMake
shell: cmd /C CALL {0}
run: >
conda\cmake.cmd --preset conda-windows-release -DFREECAD_USE_PCH:BOOL=OFF -DFREECAD_RELEASE_PDB:BOOL=OFF -DFREECAD_USE_CCACHE:BOOL=ON
- name: Compiling sources
shell: cmd /C CALL {0}
run: >
conda\cmake.cmd --build build\release
- name: Print Ccache statistics after build
run: |
ccache -s
- name: CMake Install
shell: cmd /C CALL {0}
run: |
conda\cmake.cmd --install build\release
- name: C++ unit tests
timeout-minutes: 1
run: |
. build\release\tests\Tests_run --gtest_output=json:${{ env.reportdir }}gtest_results.json # 2>&1 | tee -filepath ${{ env.logdir }}/unitTests.log
- name: FreeCAD CLI tests
run: |
. build\release\bin\FreeCADCmd -t 0 # 2>&1 | tee -filepath ${{ env.logdir }}/integrationTests.log
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifactBasename }}-Logs
path: |
${{ env.logdir }}
+74 -15
View File
@@ -77,7 +77,73 @@ on:
type: boolean
required: false
cpplintFilters:
default: -whitespace-*
default: >-
'
+build/deprecated,
-build/endif_comment,
+build/explicit_make_pair,
-build/forward_decl,
+build/header_guard,
+build/include,
-build/include_subdir,
-build/include_alpha,
-build/include_order,
+build/include_what_you_use,
+build/namespaces_headers,
+build/namespaces_literals,
+build/namespaces,
+build/printf_format,
+build/storage_class,
+readability/alt_tokens,
-readability/braces,
+readability/casting,
+readability/check,
+readability/constructors,
+readability/fn_size,
+readability/inheritance,
+readability/multiline_comment,
+readability/multiline_string,
+readability/namespace,
-readability/nolint,
+readability/nul,
+readability/strings,
+readability/todo,
+readability/utf8,
+runtime/arrays,
+runtime/casting,
+runtime/explicit,
+runtime/int,
+runtime/init,
+runtime/invalid_increment,
+runtime/member_string_references,
+runtime/memset,
+runtime/operator,
+runtime/printf,
+runtime/printf_format,
+runtime/references,
+runtime/string,
+runtime/threadsafe_fn,
+runtime/vlog,
-whitespace/blank_line,
-whitespace/braces,
-whitespace/comma,
-whitespace/comments,
-whitespace/empty_conditional_body,
-whitespace/empty_if_body,
-whitespace/empty_loop_body,
-whitespace/end_of_line,
-whitespace/ending_newline,
-whitespace/forcolon,
-whitespace/indent,
-whitespace/indent_namespace,
-whitespace/line_length,
-whitespace/newline,
-whitespace/operators,
-whitespace/parens,
-whitespace/semicolon,
-whitespace/tab,
-whitespace/todo
'
type: string
required: false
cpplintLineLength:
@@ -140,10 +206,6 @@ on:
default: true
type: boolean
required: false
clangTidyChecks:
default: # empty to use the .clang-tidy file
type: string
required: false
clangTidyFailSilent:
default: true # warnings or notes will never fail the CI, only errors
type: boolean
@@ -318,7 +380,7 @@ jobs:
pylintWarnings=0
pylintRefactorings=0
pylintConventions=0
pip install pylint
pip install --break-system-packages pylint
# List enabled pylint checks
pylint --list-msgs-enabled > ${{ env.logdir }}pylint-enabled-checks.log
# Run pylint on all python files
@@ -378,7 +440,7 @@ jobs:
run: |
blackReformats=0
blackFails=0
pip install black
pip install --break-system-packages black
set +e
black --check ${{ inputs.changedPythonFiles }} &> ${{ env.logdir }}black.log
exitCode=$?
@@ -429,8 +491,6 @@ jobs:
libboost-thread-dev \
libcoin-dev \
libeigen3-dev \
libgts-bin \
libgts-dev \
libkdtree++-dev \
libmedc-dev \
libocct-data-exchange-dev \
@@ -444,7 +504,7 @@ jobs:
libqt5x11extras5-dev \
libshiboken2-dev \
libspnav-dev \
libvtk7-dev \
libvtk9-dev \
libx11-dev \
libxerces-c-dev \
libyaml-cpp-dev \
@@ -452,7 +512,6 @@ jobs:
netgen \
netgen-headers \
occt-draw \
pyqt5-dev-tools \
pyside2-tools \
python3-dev \
python3-git \
@@ -516,7 +575,7 @@ jobs:
continue-on-error: ${{ inputs.cpplintFailSilent }}
run: |
cpplintErrors=0
pip install cpplint
pip install --break-system-packages cpplint
# Run cpplint
for file in ${{ inputs.changedCppFiles }}
do
@@ -581,7 +640,7 @@ jobs:
if: inputs.checkSpelling && always()
continue-on-error: ${{ inputs.codespellFailSilent }}
run: |
pip install codespell
pip install --break-system-packages codespell
wget https://raw.githubusercontent.com/codespell-project/codespell/master/codespell_lib/data/dictionary.txt
#wget https://raw.githubusercontent.com/codespell-project/codespell/master/codespell_lib/data/dictionary_rare.txt
set +e
@@ -620,10 +679,10 @@ jobs:
clangTidyNotes=0
sudo apt-get install -y --no-install-recommends clang-tidy
#TODO: check where this "clang-tidy.yaml" goes ; shall this be put in the fixes ?
clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -checks=${{ inputs.clangTidyChecks }} -p build/ --explain-config &>> ${{ env.logdir }}clang-tidy-enabled-checks.log
clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -p build/ --explain-config &>> ${{ env.logdir }}clang-tidy-enabled-checks.log
# Run clang-tidy on all cpp files
set +e
clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -checks=${{ inputs.clangTidyChecks }} -p build/ ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clang-tidy.log
clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -p build/ ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clang-tidy.log
exitCode=$?
set -e
# If clang-tidy has run successfully, write the Log to the console with the Problem Matchers
+3
View File
@@ -61,3 +61,6 @@ src/Tools/freecad.zip
tsupdate_stderr.log
tsupdate_stdout.log
files_to_translate.txt
# pixi environments
.pixi
*.egg-info
+5 -2
View File
@@ -42,6 +42,9 @@ exclude: |
src/App/ExpressionParser.tab.h|
src/App/ExpressionParser.y|
src/App/lex.ExpressionParser.c|
src/Gui/3Dconnexion/navlib|
src/Gui/QSint|
src/Gui/Quarter|
src/Mod/Import/App/SCL|
src/Mod/Import/App/SCL_output|
src/Mod/Mesh/App/TestData|
@@ -51,7 +54,7 @@ exclude: |
)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0
rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -59,7 +62,7 @@ repos:
- id: check-added-large-files
- id: mixed-line-ending
- repo: https://github.com/psf/black
rev: b965c2a5026f8ba399283ba3e01898b012853c79 # frozen: 24.8.0
rev: 1b2427a2b785cc4aac97c19bb4b9a0de063f9547 # frozen: 24.10.0
hooks:
- id: black
args: ['--line-length', '100']
+3 -1
View File
@@ -21,7 +21,9 @@ option(FREECAD_USE_CCACHE "Auto detect and use ccache during compilation" ON)
if(FREECAD_USE_CCACHE)
find_program(CCACHE_PROGRAM ccache) #This check should occur before project()
if(CCACHE_PROGRAM)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
message(STATUS "Using ccache found at: " ${CCACHE_PROGRAM})
set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
endif()
endif()
+29 -31
View File
@@ -51,14 +51,6 @@
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"Boost_NO_BOOST_CMAKE": {
"type": "BOOL",
"value": "ON"
},
"BUILD_DYNAMIC_LINK_PYTHON": {
"type": "BOOL",
"value": "ON"
},
"BUILD_FEM_NETGEN": {
"type": "BOOL",
"value": "ON"
@@ -99,9 +91,9 @@
"type": "BOOL",
"value": "ON"
},
"USE_BOOST_PYTHON": {
"type": "BOOL",
"value": "OFF"
"QT_HOST_PATH": {
"type": "PATH",
"value": "$env{CONDA_PREFIX}"
}
}
},
@@ -117,27 +109,27 @@
"cacheVariables": {
"CMAKE_INCLUDE_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/include"
"value": "$env{CONDA_PREFIX}/include"
},
"CMAKE_INSTALL_LIBDIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/lib"
"value": "$env{CONDA_PREFIX}/lib"
},
"CMAKE_INSTALL_PREFIX": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad"
"value": "$env{CONDA_PREFIX}"
},
"CMAKE_LIBRARY_PATH":{
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/lib"
"value": "$env{CONDA_PREFIX}/lib"
},
"CMAKE_PREFIX_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad"
"value": "$env{CONDA_PREFIX}"
},
"OCC_INCLUDE_DIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/include/opencascade"
"value": "$env{CONDA_PREFIX}/include/opencascade"
}
}
},
@@ -157,27 +149,27 @@
},
"CMAKE_INCLUDE_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/include"
"value": "$env{CONDA_PREFIX}/include"
},
"CMAKE_INSTALL_LIBDIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/lib"
"value": "$env{CONDA_PREFIX}/lib"
},
"CMAKE_INSTALL_PREFIX": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad"
"value": "$env{CONDA_PREFIX}"
},
"CMAKE_LIBRARY_PATH":{
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/lib"
"value": "$env{CONDA_PREFIX}/lib"
},
"CMAKE_PREFIX_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad"
"value": "$env{CONDA_PREFIX}"
},
"OCC_INCLUDE_DIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/include/opencascade"
"value": "$env{CONDA_PREFIX}/include/opencascade"
}
}
},
@@ -193,27 +185,27 @@
"cacheVariables": {
"CMAKE_INCLUDE_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library/include"
"value": "$env{CONDA_PREFIX}/Library/include"
},
"CMAKE_INSTALL_LIBDIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library/lib"
"value": "$env{CONDA_PREFIX}/Library/lib"
},
"CMAKE_INSTALL_PREFIX": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library"
"value": "$env{CONDA_PREFIX}/Library"
},
"CMAKE_LIBRARY_PATH":{
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library/lib"
"value": "$env{CONDA_PREFIX}/Library/lib"
},
"CMAKE_PREFIX_PATH": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library"
"value": "$env{CONDA_PREFIX}/Library"
},
"OCC_INCLUDE_DIR": {
"type": "FILEPATH",
"value": "${sourceDir}/.conda/freecad/Library/include/opencascade"
"value": "$env{CONDA_PREFIX}/Library/include/opencascade"
}
}
},
@@ -295,7 +287,13 @@
"inherits": [
"conda-release",
"conda-windows"
]
],
"cacheVariables": {
"FREECAD_RELEASE_PDB": {
"type": "BOOL",
"value": "OFF"
}
}
}
]
}
}
+17 -22
View File
@@ -2,7 +2,7 @@
### Your own 3D parametric modeler
[Website](https://www.freecad.org) •
[Website](https://www.freecad.org) •
[Documentation](https://wiki.freecad.org) •
[Forum](https://forum.freecad.org/) •
[Bug tracker](https://github.com/FreeCAD/FreeCAD/issues) •
@@ -12,7 +12,7 @@
[![Release](https://img.shields.io/github/release/freecad/freecad.svg)](https://github.com/freecad/freecad/releases/latest) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/freecad/localized.svg)](https://crowdin.com/project/freecad) [![Liberapay](https://img.shields.io/liberapay/receives/FreeCAD.svg?logo=liberapay)](https://liberapay.com/FreeCAD)
<img src="https://user-images.githubusercontent.com/1828501/174066870-1692005b-f8d7-43fb-a289-6d2f07f73d7f.png" width="800"/>
<img src="/.github/images/partdesign.png" width="800"/>
Overview
--------
@@ -49,27 +49,20 @@ Precompiled packages for stable releases are available for Windows, macOS and Li
On most Linux distributions, FreeCAD is also directly installable from the
software center application.
For development releases check the [weekly-builds page](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds).
For development releases visit the [weekly-builds page](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds).
Other options are described at the [wiki Download page](https://wiki.freecad.org/Download).
Other options are described on the [wiki Download page](https://wiki.freecad.org/Download).
Compiling
---------
Compiling FreeCAD requires installation of several libraries and their
development files such as OCCT (Open Cascade), Coin and Qt, listed in the
pages below. Once this is done, FreeCAD can be compiled with
CMake. On Windows, these libraries are bundled and offered by the
FreeCAD team in a convenient package. On Linux, they are usually found
in your distribution's repositories, and on macOS and other platforms,
you will usually have to compile them yourself.
The pages below contain up-to-date build instructions:
FreeCAD requires several dependencies to correctly compile for development and
production builds. The following pages contain updated build instructions for
their respective platforms:
- [Linux](https://wiki.freecad.org/Compile_on_Linux)
- [Windows](https://wiki.freecad.org/Compile_on_Windows)
- [macOS](https://wiki.freecad.org/Compile_on_MacOS)
- [Cygwin](https://wiki.freecad.org/Compile_on_Cygwin)
- [MinGW](https://wiki.freecad.org/Compile_on_MinGW)
@@ -81,12 +74,13 @@ To report an issue please:
- Consider posting to the [Forum](https://forum.freecad.org), [Discord](https://discord.com/invite/F4hdxzYZfc) channel, or [Reddit](https://www.reddit.com/r/FreeCAD) to verify the issue;
- Search the existing [issues](https://github.com/FreeCAD/FreeCAD/issues) for potential duplicates;
- Use the most updated stable or [development versions](https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds) of FreeCAD;
- Post version info from e.g. `Help > About FreeCAD > Copy to clipboard`;
- Post version info from `Help > About FreeCAD > Copy to clipboard`;
- Restart FreeCAD in safe mode `Help > Restart in safe mode` and try to reproduce the issue again. If the issue is resolved it can be fixed by deleting the FreeCAD config files.
- Start recording a macro `Macro > Macro recording...` and repeat all steps. Stop recording after the issue occurs and upload the saved macro or copy the macro code in the issue;
- Post a Step-By-Step explanation on how to recreate the issue;
- Upload an example file (FCStd as ZIP file) to demonstrate the problem;
For more detail see:
For more details see:
- [Bug Tracker](https://github.com/FreeCAD/FreeCAD/issues)
- [Reporting Issues and Requesting Features](https://github.com/FreeCAD/FreeCAD/issues/new/choose)
@@ -94,17 +88,18 @@ For more detail see:
- [Help Forum](https://forum.freecad.org/viewforum.php?f=3)
- [Developers Handbook](https://freecad.github.io/DevelopersHandbook/)
> [!NOTE]
The [FPA](https://fpa.freecad.org) offers developers the opportunity
to apply for a grant to work on projects of their choosing. Check
[jobs and funding](https://blog.freecad.org/jobs/) to know more.
Usage & Getting help
Usage & Getting Help
--------------------
The FreeCAD wiki contains documentation on
general FreeCAD usage, Python scripting, and development. These
pages might help you get started:
general FreeCAD usage, Python scripting, and development.
View these pages for more information:
- [Getting started](https://wiki.freecad.org/Getting_started)
- [Features list](https://wiki.freecad.org/Feature_list)
@@ -113,10 +108,10 @@ pages might help you get started:
- [Scripting](https://wiki.freecad.org/Power_users_hub)
- [Development](https://wiki.freecad.org/Developer_hub)
The [FreeCAD forum](https://forum.freecad.org) is also a great place
to find help and solve specific problems you might encounter when
learning to use FreeCAD.
The [FreeCAD forum](https://forum.freecad.org) is a great place
to find help and solve specific problems when learning to use FreeCAD.
---
<p>This project receives generous infrastructure support from
<a href="https://www.digitalocean.com/">
+4 -4
View File
@@ -17,13 +17,13 @@ hostage in demands for "bounties" will not be entertained. Contact the FPA at fp
## Supported Versions
FreeCAD implements security fixes to the current release series, and to the current development on the master branch.
FreeCAD implements security fixes to the current release series, and to the current development on the main branch.
| Version | Supported |
|---------| ------------------ |
| 0.22dev | :white_check_mark: |
| 0.21 | :white_check_mark: |
| < 0.21 | :x: |
| 1.1dev | :white_check_mark: |
| 1.0 | :white_check_mark: |
| < 1.0 | :x: |
## Reporting a Vulnerability
+3 -6
View File
@@ -12,7 +12,7 @@ IF ( CMAKE_PKGCONFIG_EXECUTABLE )
SET(ENV{PKG_CONFIG_PATH} "${KDL_INSTALL}/lib/pkgconfig/")
MESSAGE( "Looking for KDL in: ${KDL_INSTALL}")
PKGCONFIG( "orocos-kdl >= 0.99" KDL_FOUND KDL_INCLUDE_DIRS KDL_DEFINES KDL_LINK_DIRS KDL_LIBS )
PKGCONFIG( "orocos-kdl >= 1.4.0" KDL_FOUND KDL_INCLUDE_DIRS KDL_DEFINES KDL_LINK_DIRS KDL_LIBS )
IF( KDL_FOUND )
MESSAGE(" Includes in: ${KDL_INCLUDE_DIRS}")
@@ -22,13 +22,10 @@ IF ( CMAKE_PKGCONFIG_EXECUTABLE )
INCLUDE_DIRECTORIES( ${KDL_INCLUDE_DIRS} )
LINK_DIRECTORIES( ${KDL_LINK_DIRS})
#OROCOS_PKGCONFIG_INCPATH("${KDLTK_INCLUDE_DIRS}")
#OROCOS_PKGCONFIG_LIBS("${KDL_LIBS}")
#OROCOS_PKGCONFIG_LIBPATH("${KDL_LINK_DIRS}")
SET(ENV{PKG_CONFIG_PATH} "${KDL_INSTALL}/lib/pkgconfig/:${OROCOS_INSTALL}/lib/pkgconfig")
MESSAGE( "Looking for KDL Toolkit in: ${PKG_CONFIG_PATH}")
PKGCONFIG( "orocos-kdltk-${OROCOS_TARGET} >= 0.99" KDLTK_FOUND KDLTK_INCLUDE_DIRS KDLTK_DEFINES KDLTK_LINK_DIRS KDLTK_LIBS )
PKGCONFIG( "orocos-kdltk-${OROCOS_TARGET} >= 1.4.0" KDLTK_FOUND KDLTK_INCLUDE_DIRS KDLTK_DEFINES KDLTK_LINK_DIRS KDLTK_LIBS )
IF(KDLTK_FOUND)
INCLUDE_DIRECTORIES( ${KDLTK_INCLUDE_DIRS} )
LINK_DIRECTORIES( ${KDLTK_LINK_DIRS})
@@ -38,7 +35,7 @@ IF ( CMAKE_PKGCONFIG_EXECUTABLE )
IF(CORBA_ENABLED)
SET(ENV{PKG_CONFIG_PATH} "${KDL_INSTALL}/lib/pkgconfig/:${OROCOS_INSTALL}/lib/pkgconfig")
MESSAGE("Looking for KDL Toolkit CORBA extension in ${PKG_CONFIG_PATH}")
PKGCONFIG( "orocos-kdltk-corba-${OROCOS_TARGET} >= 0.99" KDLTKCORBA_FOUND KDLTKCORBA_INCLUDE_DIRS KDLTKCORBA_DEFINES KDLTKCORBA_LINK_DIRS KDLTKCORBA_LIBS )
PKGCONFIG( "orocos-kdltk-corba-${OROCOS_TARGET} >= 1.4.0" KDLTKCORBA_FOUND KDLTKCORBA_INCLUDE_DIRS KDLTKCORBA_DEFINES KDLTKCORBA_LINK_DIRS KDLTKCORBA_LIBS )
IF(KDLTKCORBA_FOUND)
INCLUDE_DIRECTORIES( ${KDLTKCORBA_INCLUDE_DIRS} )
LINK_DIRECTORIES( ${KDLTKCORBA_LINK_DIRS})
@@ -25,13 +25,14 @@ macro(CheckInterModuleDependencies)
REQUIRES_MODS(BUILD_IMPORT BUILD_PART)
REQUIRES_MODS(BUILD_INSPECTION BUILD_MESH BUILD_POINTS BUILD_PART)
REQUIRES_MODS(BUILD_JTREADER BUILD_MESH)
REQUIRES_MODS(BUILD_MESH_PART BUILD_PART BUILD_MESH BUILD_SMESH)
REQUIRES_MODS(BUILD_MESH_PART BUILD_PART BUILD_MESH)
REQUIRES_MODS(BUILD_FLAT_MESH BUILD_MESH_PART)
REQUIRES_MODS(BUILD_OPENSCAD BUILD_MESH_PART BUILD_DRAFT)
REQUIRES_MODS(BUILD_PART BUILD_MATERIAL)
REQUIRES_MODS(BUILD_PART_DESIGN BUILD_SKETCHER)
# REQUIRES_MODS(BUILD_CAM BUILD_PART BUILD_MESH BUILD_ROBOT)
REQUIRES_MODS(BUILD_CAM BUILD_PART BUILD_MESH)
REQUIRES_MODS(BUILD_REVERSEENGINEERING BUILD_PART BUILD_MESH)
REQUIRES_MODS(BUILD_REVERSEENGINEERING BUILD_PART BUILD_MESH BUILD_POINTS)
REQUIRES_MODS(BUILD_ROBOT BUILD_PART)
REQUIRES_MODS(BUILD_SANDBOX BUILD_PART BUILD_MESH)
REQUIRES_MODS(BUILD_SKETCHER BUILD_PART)
@@ -15,7 +15,9 @@ macro(CopyLibpackDirectories)
if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.0.0")
file(COPY ${FREECAD_LIBPACK_DIR}/plugins/tls DESTINATION ${CMAKE_BINARY_DIR}/bin)
endif()
file(COPY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR})
if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.0.0" AND FREECAD_LIBPACK_VERSION VERSION_LESS "3.1.0")
file(COPY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR})
endif()
message(STATUS "... end copying.\n=======================================\n")
endif()
@@ -40,7 +42,9 @@ macro(CopyLibpackDirectories)
file(COPY ${FREECAD_LIBPACK_DIR}/plugins/imageformats DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(COPY ${FREECAD_LIBPACK_DIR}/plugins/platforms DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(COPY ${FREECAD_LIBPACK_DIR}/plugins/styles DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(COPY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR})
if(FREECAD_LIBPACK_VERSION VERSION_LESS "3.1.0")
file(COPY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_BINARY_DIR})
endif()
file(WRITE ${CMAKE_BINARY_DIR}/bin/qt.conf "[Paths]\nPrefix=..\n")
endif()
endif()
@@ -59,7 +63,9 @@ macro(CopyLibpackDirectories)
if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.0.0")
install(DIRECTORY ${FREECAD_LIBPACK_DIR}/plugins/tls DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
endif()
install(DIRECTORY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_INSTALL_PREFIX})
if(FREECAD_LIBPACK_VERSION VERSION_LESS "3.1.0")
install(DIRECTORY ${FREECAD_LIBPACK_DIR}/resources DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()
install(DIRECTORY ${FREECAD_LIBPACK_DIR}/bin DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${FREECAD_LIBPACK_DIR}/lib DESTINATION ${CMAKE_INSTALL_PREFIX} FILES_MATCHING PATTERN "*.dll")
if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.0.0")
@@ -144,37 +144,39 @@ macro(InitializeFreeCADBuildOptions)
if(MSVC OR APPLE)
set(FREECAD_3DCONNEXION_SUPPORT "NavLib" CACHE STRING "Select version of the 3Dconnexion device integration")
set_property(CACHE FREECAD_3DCONNEXION_SUPPORT PROPERTY STRINGS "NavLib" "Raw input")
set_property(CACHE FREECAD_3DCONNEXION_SUPPORT PROPERTY STRINGS "NavLib" "Raw input" "Both")
option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
else(MSVC OR APPLE)
set(FREECAD_3DCONNEXION_SUPPORT "Raw input")
set(FREECAD_USE_3DCONNEXION_RAWINPUT ON)
set(FREECAD_USE_3DCONNEXION OFF )
endif(MSVC OR APPLE)
if(MSVC)
option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) # 3/5/2021 current LibPack uses non-C++17 FLANN
option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
elseif(APPLE AND FREECAD_3DCONNEXION_SUPPORT STREQUAL "NavLib")
option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
elseif(APPLE AND FREECAD_3DCONNEXION_SUPPORT STREQUAL "Raw input")
if(FREECAD_3DCONNEXION_SUPPORT STREQUAL "NavLib" AND FREECAD_USE_3DCONNEXION)
set(FREECAD_USE_3DCONNEXION_NAVLIB ON)
set(FREECAD_USE_3DCONNEXION OFF)
elseif(FREECAD_3DCONNEXION_SUPPORT STREQUAL "Both" AND FREECAD_USE_3DCONNEXION)
set(FREECAD_USE_3DCONNEXION_NAVLIB ON)
set(FREECAD_USE_3DCONNEXION_RAWINPUT ON)
endif()
if(APPLE AND NOT (FREECAD_3DCONNEXION_SUPPORT STREQUAL "NavLib"))
find_library(3DCONNEXIONCLIENT_FRAMEWORK 3DconnexionClient)
if(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK})
option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON)
else(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK})
option(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." OFF)
endif(IS_DIRECTORY ${3DCONNEXIONCLIENT_FRAMEWORK})
else(MSVC)
set(FREECAD_USE_3DCONNEXION OFF )
endif()
if(MSVC)
option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" ON)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF) # 3/5/2021 current LibPack uses non-C++17 FLANN
endif(MSVC)
if(NOT MSVC)
option(BUILD_FEM_NETGEN "Build the FreeCAD FEM module with the NETGEN mesher" OFF)
option(FREECAD_USE_PCL "Build the features that use PCL libs" OFF)
endif(NOT MSVC)
if(FREECAD_3DCONNEXION_SUPPORT STREQUAL "NavLib" AND FREECAD_USE_3DCONNEXION)
set(FREECAD_USE_3DCONNEXION_NAVLIB ON)
set(FREECAD_USE_3DCONNEXION OFF)
endif()
# if this is set override some options
if (FREECAD_BUILD_DEBIAN)
set(FREECAD_USE_EXTERNAL_ZIPIOS ON )
@@ -182,14 +184,16 @@ macro(InitializeFreeCADBuildOptions)
#set(FREECAD_USE_EXTERNAL_SMESH ON )
endif (FREECAD_BUILD_DEBIAN)
if(BUILD_FEM)
set(BUILD_SMESH ON )
endif()
# for Windows the minimum required cmake version is 3.4.3 to build the CAM module
if(WIN32 AND CMAKE_VERSION VERSION_LESS 3.4.3)
message(WARNING "Disable CAM, requires cmake >= 3.4.3 in order to build this module")
set(BUILD_CAM OFF )
if(BUILD_FEM OR BUILD_MESH_PART)
set(FREECAD_USE_SMESH ON)
if(FREECAD_USE_EXTERNAL_SMESH)
set(BUILD_SMESH OFF)
else()
set(BUILD_SMESH ON)
endif()
else()
set(FREECAD_USE_SMESH OFF)
set(BUILD_SMESH OFF)
endif()
# force build directory to be different to source directory
+11 -4
View File
@@ -58,6 +58,7 @@ macro(PrintFinalReport)
simple(Compiler "${CMAKE_CXX_COMPILER} (${CMAKE_CXX_COMPILER_VERSION})")
value(CMAKE_VERSION)
conditional(ccache CCACHE_PROGRAM "not enabled" ${CCACHE_PROGRAM})
simple(prefix ${CMAKE_INSTALL_PREFIX})
simple(bindir ${CMAKE_INSTALL_BINDIR})
simple(datadir ${CMAKE_INSTALL_DATADIR})
@@ -141,7 +142,7 @@ macro(PrintFinalReport)
simple(ZLIB "${ZLIB_VERSION_STRING}")
simple(OCC "${OCC_VERSION_STRING} [${OCC_LIBRARY_DIR}] [${OCC_INCLUDE_DIR}]")
simple(OCC_Libs "[${OCC_LIBRARIES}]")
if(BUILD_SMESH)
if(FREECAD_USE_SMESH)
if(FREECAD_USE_EXTERNAL_SMESH)
simple(SMESH "${SMESH_VERSION_MAJOR}.${SMESH_VERSION_MINOR}.${SMESH_VERSION_PATCH}.${SMESH_VERSION_TWEAK}")
else()
@@ -151,7 +152,7 @@ macro(PrintFinalReport)
simple(VTK ${VTK_VERSION})
endif()
else()
simple(SMESH "do not build")
simple(SMESH "not enabled")
endif()
conditional(NETGEN NETGEN_FOUND
"not enabled"
@@ -193,13 +194,19 @@ macro(PrintFinalReport)
simple(Coin3D "${COIN3D_VERSION} [${COIN3D_LIBRARIES}] [${COIN3D_INCLUDE_DIRS}]")
simple(pivy ${PIVY_VERSION})
if (WIN32)
if (FREECAD_USE_3DCONNEXION)
simple(3Dconnexion "Building 3Dconnexion support with original code")
if (FREECAD_USE_3DCONNEXION_RAWINPUT AND FREECAD_USE_3DCONNEXION_NAVLIB)
simple(3Dconnexion "Building 3Dconnexion support with raw input and NavLib")
elseif (FREECAD_USE_3DCONNEXION)
simple(3Dconnexion "Building 3Dconnexion support with raw input")
elseif(FREECAD_USE_3DCONNEXION_NAVLIB)
simple(3Dconnexion "Building 3Dconnexion support with NavLib")
else()
simple(3Dconnexion "Not building 3Dconnexion device support")
endif()
elseif(APPLE)
if (FREECAD_USE_3DCONNEXION)
simple(3Dconnexion "Building 3Dconnexion support with raw input")
endif()
else()
conditional(SPNAV SPNAV_FOUND "not found" "[${SPNAV_LIBRARY}] [${SPNAV_INCLUDE_DIR}]")
endif()
+3 -3
View File
@@ -1,8 +1,8 @@
macro(SetupSalomeSMESH)
# -------------------------------- Salome SMESH --------------------------
# Salome SMESH sources are under src/3rdParty now
if(BUILD_SMESH)
if(FREECAD_USE_SMESH)
# set the internal smesh version:
# see src/3rdParty/salomonemesh/CMakeLists.txt and commit https://github.com/FreeCAD/FreeCAD/commit/666a3e5 and https://forum.freecad.org/viewtopic.php?f=10&t=30838
set(SMESH_VERSION_MAJOR 7)
@@ -145,6 +145,6 @@ macro(SetupSalomeSMESH)
set(SMESH_FOUND TRUE)
configure_file(${CMAKE_SOURCE_DIR}/src/SMESH_Version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/SMESH_Version.h)
endif(BUILD_SMESH)
endif(FREECAD_USE_SMESH)
endmacro(SetupSalomeSMESH)
+7 -1
View File
@@ -15,11 +15,17 @@ set(SWIG_EXECUTABLE ${FREECAD_LIBPACK_DIR}/bin/swig.exe CACHE FILEPATH "Swig" FO
find_package(Qt6 REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/lib/cmake NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 Qt ${Qt6_VERSION}")
if(FREECAD_LIBPACK_VERSION VERSION_GREATER_EQUAL "3.1.0")
find_package(pybind11 REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/share/cmake/pybind11 NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 pybind11 ${pybind11_VERSION}")
set(FREECAD_USE_PYBIND11 ON)
endif()
find_package(XercesC REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/cmake NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 XercesC ${XercesC_VERSION}")
find_package(yaml-cpp REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/lib/cmake NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 yaml-cpp ${XercesC_VERSION}")
message(STATUS "Found LibPack 3 yaml-cpp ${yaml-cpp_VERSION}")
find_package(Coin REQUIRED PATHS ${FREECAD_LIBPACK_DIR}/lib/cmake NO_DEFAULT_PATH)
message(STATUS "Found LibPack 3 Coin ${Coin_VERSION}")
+1
View File
@@ -2,6 +2,7 @@ name: freecad
channels:
- conda-forge
dependencies:
- conda-forge/noarch::conda-libmamba-solver==24.7.0
- conda-devenv
- mamba
- python==3.12.*
+1
View File
@@ -2,6 +2,7 @@ name: freecad
channels:
- conda-forge
dependencies:
- conda-forge/noarch::conda-libmamba-solver==24.7.0
- conda-devenv
- mamba
- python==3.11.*
+1 -1
View File
@@ -3,6 +3,7 @@ channels:
- conda-forge
- conda-forge/label/pivy_rc
dependencies:
- conda-forge/noarch::conda-libmamba-solver==24.7.0
- libspnav # [linux]
- kernel-headers_linux-64 # [linux and x86_64]
- libdrm-cos7-x86_64 # [linux and x86_64]
@@ -91,7 +92,6 @@ dependencies:
- python==3.12.*
- pyyaml
- qt6-main
- six
- smesh
- swig
- vtk==9.2.6
+1 -1
View File
@@ -2,6 +2,7 @@ name: freecad
channels:
- conda-forge
dependencies:
- conda-forge/noarch::conda-libmamba-solver==24.7.0
- libspnav # [linux]
- kernel-headers_linux-64 # [linux and x86_64]
- libdrm-cos6-x86_64 # [linux and x86_64]
@@ -91,7 +92,6 @@ dependencies:
- python==3.11.*
- pyyaml
- qt-main
- six
- smesh
- swig
- vtk==9.2.6
+1 -1
View File
@@ -66,7 +66,7 @@
"redirectOutput": true,
"connect": {
"host": "localhost",
"port": 5678
"port": 5679
},
"pathMappings": [
{
+5 -1
View File
@@ -7,7 +7,11 @@ from freecad.utils import get_python_exe
# By default it attempts to use Freecad's PID mistaking it for python.
# https://github.com/microsoft/debugpy/issues/262
debugpy.configure(python=get_python_exe())
debugpy.listen(('localhost', 5678))
# As of Python 3.12, debugpy runs a forwarding process that listens both on the port specified here for the debugger
# to connect to, but also on an internal port for the underlying pydevd within the python process to connect to. The
# default for that internal port is 5678, so we need to not duplicate it for the external port. Also, on Linux the
# attempt to spawn the forwarding process separately fails, so we force it to be internal to our main process.
debugpy.listen(('localhost', 5679),in_process_debug_adapter=True)
# Turns out you cannot probe debugpy to see if it is up:
# https://github.com/microsoft/debugpy/issues/974
+2 -2
View File
@@ -13,8 +13,8 @@ def check_socket(host, port):
return sock.connect_ex((host, port)) == 0
def main():
# DO NOT CHECK 5678 or debugpy will break
# Check other port manually opened instead
# DO NOT CHECK the actual port 5678/5879 or debugpy will break
# Check that the other port 39999 used as a flag is manually opened instead
attempt_counter = 0
while (not check_socket('localhost', 39999)) and attempt_counter < MAX_ATTEMPTS:
time.sleep(RETRY_DELAY_S)
+12
View File
@@ -0,0 +1,12 @@
import pydevd
from multiprocessing.connection import Listener
print("CLion debugger macro running. Starting listener to get port")
listen = Listener(('localhost', 39998), backlog=1)
link = listen.accept()
port = link.recv()
link.close()
listen.close()
print("Port", port, "received, starting debugger. Check CLion to see if a breakpoint has been hit and continue")
pydevd.settrace(port=port)
print("Debugger operating, leaving macro.")
+18
View File
@@ -0,0 +1,18 @@
--- attach_pydevd.py.orig 2024-09-26 10:36:47.131066345 -0400
+++ attach_pydevd.py 2024-09-26 10:16:48.687714133 -0400
@@ -48,6 +48,15 @@
import add_code_to_python_process
show_debug_info_on_target_process = 0
+ print("attach_pydevd is trying to relay the port",setup['port'])
+ try:
+ from multiprocessing.connection import Client
+ link = Client(('localhost',39998))
+ link.send(setup['port'])
+ link.close()
+ except ConnectionError as ce:
+ pass
+
pydevd_dirname = os.path.dirname(os.path.dirname(__file__))
if sys.platform == 'win32':
Binary file not shown.
+1 -1
View File
@@ -4,10 +4,10 @@ SET(Examples_Files
draft_test_objects.FCStd
EngineBlock.FCStd
PartDesignExample.FCStd
RobotExample.FCStd
BIMExample.FCStd
FEMExample.FCStd
AssemblyExample.FCStd
ArchDetail.FCStd
)
ADD_CUSTOM_TARGET(Example_data ALL
Binary file not shown.
Binary file not shown.
+25692
View File
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
[project]
name = "FreeCAD"
version = "0.22.0"
description = "pixi instructions for FreeCAD"
authors = ["looooo <[email protected]>"]
channels = ["conda-forge/label/pivy_rc", "conda-forge"]
platforms = [ "linux-64", "linux-aarch64", "osx-64", "osx-arm64", "win-64" ]
[dependencies]
ccache = "*"
cmake = "3.28.3"
coin3d = "*"
compilers = "*"
conda-devenv = "*"
debugpy = "*"
doxygen = "*"
eigen = "*"
fmt = "*"
freetype = "*"
git = "*"
graphviz = "*"
hdf5 = "*"
libboost-devel = "*"
matplotlib = "*"
ninja = "*"
noqt5 = "*"
numpy = "*"
occt = "*"
openssl = "*"
pcl = "*"
pip = "*"
pivy = "*"
ply = "*"
pre-commit = "*"
pybind11 = "*"
pyside6 = "*"
python = "3.12"
pyyaml = "*"
qt6-main = "*"
scipy = ">=1.14.1,<2"
six = "*"
smesh = "*"
swig = "*"
vtk = "*"
xerces-c = "*"
yaml-cpp = "*"
zlib = "*"
zstd = "*"
## Linux Dependencies (x86-64)
[target.linux-64.dependencies]
kernel-headers_linux-64 = "*"
libdrm-cos6-x86_64 = "*"
libselinux-cos6-x86_64 = "*"
libsepol-cos6-x86_64 = "*"
libspnav = "*"
libx11-common-cos6-x86_64 = "*"
libx11-cos6-x86_64 = "*"
libxau-cos6-x86_64 = "*"
libxcb-cos6-x86_64 = "*"
libxdamage-cos6-x86_64 = "*"
libxext-cos6-x86_64 = "*"
libxfixes-cos6-x86_64 = "*"
libxi-cos6-x86_64 = "*"
libxi-devel-cos6-x86_64 = "*"
libxxf86vm-cos6-x86_64 = "*"
mesa-dri-drivers-cos6-x86_64 = "*"
mesa-dri1-drivers-cos6-x86_64 = "*"
mesa-libegl-cos6-x86_64 = "*"
mesa-libegl-devel-cos6-x86_64 = "*"
mesa-libgl-cos6-x86_64 = "*"
mesa-libgl-devel-cos6-x86_64 = "*"
pixman-cos6-x86_64 = "*"
sed = "*"
sysroot_linux-64 = "*"
xorg-x11-server-common-cos6-x86_64 = "*"
xorg-x11-server-xvfb-cos6-x86_64 = "*"
## Linux Dependencies (aarch64)
[target.linux-aarch64.dependencies]
kernel-headers_linux-aarch64 = "*"
libdrm-cos7-aarch64 = "*"
libglvnd-cos7-aarch64 = "*"
libglvnd-glx-cos7-aarch64 = "*"
libselinux-cos7-aarch64 = "*"
libsepol-cos7-aarch64 = "*"
libspnav = "*"
libx11-common-cos7-aarch64 = "*"
libx11-cos7-aarch64 = "*"
libxau-cos7-aarch64 = "*"
libxcb-cos7-aarch64 = "*"
libxdamage-cos7-aarch64 = "*"
libxext-cos7-aarch64 = "*"
libxfixes-cos7-aarch64 = "*"
libxi-cos7-aarch64 = "*"
libxi-devel-cos7-aarch64 = "*"
libxxf86vm-cos7-aarch64 = "*"
mesa-dri-drivers-cos7-aarch64 = "*"
mesa-khr-devel-cos7-aarch64 = "*"
mesa-libegl-cos7-aarch64 = "*"
mesa-libegl-devel-cos7-aarch64 = "*"
mesa-libgbm-cos7-aarch64 = "*"
mesa-libgl-cos7-aarch64 = "*"
mesa-libgl-devel-cos7-aarch64 = "*"
mesa-libglapi-cos7-aarch64 = "*"
pixman-cos7-aarch64 = "*"
sed = "*"
sysroot_linux-aarch64 = "*"
xorg-x11-server-common-cos7-aarch64 = "*"
xorg-x11-server-xvfb-cos7-aarch64 = "*"
## macOS Dependencies (Intel)
[target.osx-64.dependencies]
sed = "*"
## macOS Dependencies (Apple Silicon)
[target.osx-arm64.dependencies]
sed = "*"
## Qt 6 Configuration Presets
[target.linux-64.tasks]
configure = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-debug = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-release = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-release", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
[target.linux-aarch64.tasks]
configure = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on= ["initialize"]}
configure-debug = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on= ["initialize"]}
configure-release = { cmd = [ "cmake", "-B", "build", "--preset", "conda-linux-release", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on= ["initialize"]}
[target.osx-64.tasks]
configure = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-debug = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-release = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-release", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
[target.osx-arm64.tasks]
configure = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-debug = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-release = { cmd = [ "cmake", "-B", "build", "--preset", "conda-macos-release", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
[target.win-64.tasks]
configure = { cmd = [ "cmake", "-B", "build", "--preset", "conda-windows-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-debug = { cmd = [ "cmake", "-B", "build", "--preset", "conda-windows-debug", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
configure-release = { cmd = [ "cmake", "-B", "build", "--preset", "conda-windows-release", "-DFREECAD_QT_VERSION=6", "-DBUILD_REVERSEENGINEERING=OFF" ], depends-on = ["initialize"]}
## Tasks
[tasks]
initialize = { cmd = ["git", "submodule", "update", "--init", "--recursive"]}
build = { cmd = [ "cmake", "--build", "build" ] }
install = { cmd = [ "cmake", "--install", "build" ] }
test = { cmd = [ "ctest", "--test-dir", "build" ] }
freecad = "build/bin/FreeCAD"
+2 -2
View File
@@ -1,5 +1,5 @@
# Build SalomeMesh for all Platforms since heavily patched
if (BUILD_SMESH AND NOT FREECAD_USE_EXTERNAL_SMESH)
if (BUILD_SMESH)
add_subdirectory(salomesmesh)
endif()
@@ -12,4 +12,4 @@ if (BUILD_ASSEMBLY AND NOT FREECAD_USE_EXTERNAL_ONDSELSOLVER)
git submodule update --init" )
endif()
add_subdirectory(OndselSolver)
endif()
endif()
+1 -1
View File
@@ -45,7 +45,7 @@ PROPERTY_SOURCE(App::AnnotationLabel, App::DocumentObject)
AnnotationLabel::AnnotationLabel()
{
ADD_PROPERTY_TYPE(LabelText, (""), "Label",Prop_Output, "Text label of the annotation");
ADD_PROPERTY_TYPE(LabelText, (""), "Label", Prop_Output, "Text label of the annotation");
ADD_PROPERTY_TYPE(BasePosition, (Base::Vector3d()), "Label", Prop_Output, "Base position");
ADD_PROPERTY_TYPE(TextPosition, (Base::Vector3d()), "Label", Prop_Output, "Text position");
}
+8 -6
View File
@@ -32,7 +32,7 @@
namespace App
{
class AppExport Annotation : public DocumentObject
class AppExport Annotation: public DocumentObject
{
PROPERTY_HEADER_WITH_OVERRIDE(App::Annotation);
@@ -45,12 +45,13 @@ public:
App::PropertyVector Position;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override {
const char* getViewProviderName() const override
{
return "Gui::ViewProviderAnnotation";
}
};
class AppExport AnnotationLabel : public DocumentObject
class AppExport AnnotationLabel: public DocumentObject
{
PROPERTY_HEADER_WITH_OVERRIDE(App::AnnotationLabel);
@@ -64,12 +65,13 @@ public:
App::PropertyVector TextPosition;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override {
const char* getViewProviderName() const override
{
return "Gui::ViewProviderAnnotationLabel";
}
};
} //namespace App
} // namespace App
#endif // APP_ANNOTATION_H
#endif // APP_ANNOTATION_H
+52 -3
View File
@@ -35,6 +35,8 @@
# endif
# include <boost/program_options.hpp>
# include <boost/date_time/posix_time/posix_time.hpp>
# include <chrono>
# include <random>
#endif
#ifdef FC_OS_WIN32
@@ -47,6 +49,7 @@
#include <sys/sysctl.h>
#endif
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QProcessEnvironment>
@@ -104,7 +107,7 @@
#include "MaterialObject.h"
#include "MeasureManagerPy.h"
#include "Origin.h"
#include "OriginFeature.h"
#include "Datums.h"
#include "OriginGroupExtension.h"
#include "OriginGroupExtensionPy.h"
#include "SuppressibleExtension.h"
@@ -137,6 +140,8 @@
#include <App/TestScript.h>
#include <App/CMakeScript.h>
#include "SafeMode.h"
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
# pragma warning( disable : 4535 )
# if !defined(_DEBUG) && defined(HAVE_SEH)
@@ -427,6 +432,10 @@ void Application::setupPythonException(PyObject* module)
Base::PyExc_FC_PropertyError = PyErr_NewException("Base.PropertyError", PyExc_AttributeError, nullptr);
Py_INCREF(Base::PyExc_FC_PropertyError);
PyModule_AddObject(module, "PropertyError", Base::PyExc_FC_PropertyError);
Base::PyExc_FC_AbortIOException = PyErr_NewException("Base.PyExc_FC_AbortIOException", PyExc_BaseException, nullptr);
Py_INCREF(Base::PyExc_FC_AbortIOException);
PyModule_AddObject(module, "AbortIOException", Base::PyExc_FC_AbortIOException);
}
// clang-format on
@@ -1108,6 +1117,21 @@ Application::TransactionSignaller::~TransactionSignaller() {
}
}
int64_t Application::applicationPid()
{
static int64_t randomNumber = []() {
auto tp = std::chrono::high_resolution_clock::now();
auto dur = tp.time_since_epoch();
auto seed = dur.count();
std::mt19937 generator(static_cast<unsigned>(seed));
constexpr int64_t minValue {1};
constexpr int64_t maxValue {1000000};
std::uniform_int_distribution<int64_t> distribution(minValue, maxValue);
return distribution(generator);
}();
return randomNumber;
}
std::string Application::getHomePath()
{
return mConfig["AppHomePath"];
@@ -1738,6 +1762,7 @@ void Application::destruct()
Base::InterpreterSingleton::Destruct();
Base::Type::destruct();
ParameterManager::Terminate();
SafeMode::Destruct();
}
void Application::destructObserver()
@@ -2122,9 +2147,11 @@ void Application::initTypes()
App::TextDocument ::init();
App::Placement ::init();
App::PlacementPython ::init();
App::OriginFeature ::init();
App::DatumElement ::init();
App::Plane ::init();
App::Line ::init();
App::Point ::init();
App::LocalCoordinateSystem ::init();
App::Part ::init();
App::Origin ::init();
App::Link ::init();
@@ -2225,7 +2252,9 @@ void parseProgramOptions(int ac, char ** av, const string& exe, variables_map& v
("run-open,r", value<string>()->implicit_value(""),"Run a given test case (use 0 (zero) to run all tests). If no argument is provided then return list of all available tests. Keeps UI open after test(s) complete.")
("module-path,M", value< vector<string> >()->composing(),"Additional module paths")
("python-path,P", value< vector<string> >()->composing(),"Additional python paths")
("disable-addon", value< vector<string> >()->composing(),"Disable a given addon.")
("single-instance", "Allow to run a single instance of the application")
("safe-mode", "Force enable safe mode")
("pass", value< vector<string> >()->multitoken(), "Ignores the following arguments and pass them through to be used by a script")
;
@@ -2405,6 +2434,16 @@ void processProgramOptions(const variables_map& vm, std::map<std::string,std::st
Base::Interpreter().addPythonPath(It.c_str());
}
if (vm.count("disable-addon")) {
auto Addons = vm["disable-addon"].as< vector<string> >();
string temp;
for (const auto & It : Addons) {
temp += It + ";";
}
temp.erase(temp.end()-1);
mConfig["DisabledAddons"] = temp;
}
if (vm.count("input-file")) {
vector<string> files(vm["input-file"].as< vector<string> >());
int OpenFileCount=0;
@@ -2553,6 +2592,10 @@ void Application::initConfig(int argc, char ** argv)
// extract home paths
ExtractUserPath();
if (vm.count("safe-mode")) {
SafeMode::StartSafeMode();
}
# ifdef FC_DEBUG
mConfig["Debug"] = "1";
@@ -2641,6 +2684,12 @@ void Application::initConfig(int argc, char ** argv)
mConfig["BuildVersionPoint"].c_str(),
mConfig["BuildVersionSuffix"].c_str(),
mConfig["BuildRevision"].c_str());
if (SafeMode::SafeModeEnabled()) {
Base::Console().Message("FreeCAD is running in _SAFE_MODE_.\n"
"Safe mode temporarily disables your configurations and "
"addons. Restart the application to exit safe mode.\n\n");
}
}
LoadParameters();
@@ -3013,7 +3062,7 @@ void Application::LoadParameters()
}
}
#if defined(_MSC_VER) && BOOST_VERSION < 108300
#if defined(_MSC_VER) && BOOST_VERSION < 108200
// fix weird error while linking boost (all versions of VC)
// VS2010: https://forum.freecad.org/viewtopic.php?f=4&t=1886&p=12553&hilit=boost%3A%3Afilesystem%3A%3Aget#p12553
namespace boost { namespace program_options { std::string arg="arg"; } }
+6 -2
View File
@@ -78,7 +78,6 @@ class AppExport Application
{
public:
//---------------------------------------------------------------------
// exported functions go here +++++++++++++++++++++++++++++++++++++++++
//---------------------------------------------------------------------
@@ -205,6 +204,8 @@ public:
void closeActiveTransaction(bool abort=false, int id=0);
//@}
// NOLINTBEGIN
// clang-format off
/** @name Signals of the Application */
//@{
/// signal on new Document
@@ -311,7 +312,9 @@ public:
boost::signals2::signal<void (const App::ExtensionContainer&, std::string extension)> signalBeforeAddingDynamicExtension;
/// signal after the extension was added
boost::signals2::signal<void (const App::ExtensionContainer&, std::string extension)> signalAddedDynamicExtension;
//@}
//@}
// clang-format off
// NOLINTEND
/** @name methods for parameter handling */
@@ -399,6 +402,7 @@ public:
static std::map<std::string, std::string> &Config(){return mConfig;}
static int GetARGC(){return _argc;}
static char** GetARGV(){return _argv;}
static int64_t applicationPid();
//@}
/** @name Application directories */
+491 -282
View File
File diff suppressed because it is too large Load Diff
+114 -73
View File
@@ -37,12 +37,11 @@ using namespace App;
static int _TransactionLock;
static int _TransactionClosed;
AutoTransaction::AutoTransaction(const char *name, bool tmpName) {
auto &app = GetApplication();
if(name && app._activeTransactionGuard>=0) {
if(!app.getActiveTransaction()
|| (!tmpName && app._activeTransactionTmpName))
{
AutoTransaction::AutoTransaction(const char* name, bool tmpName)
{
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;
@@ -52,166 +51,206 @@ AutoTransaction::AutoTransaction(const char *name, bool tmpName) {
// 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)
if (app._activeTransactionGuard < 0) {
--app._activeTransactionGuard;
else if(tid || app._activeTransactionGuard>0)
}
else if (tid || app._activeTransactionGuard > 0) {
++app._activeTransactionGuard;
else if(app.getActiveTransaction()) {
}
else if (app.getActiveTransaction()) {
FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'");
--app._activeTransactionGuard;
} else
}
else {
++app._activeTransactionGuard;
}
FC_TRACE("construct auto Transaction " << app._activeTransactionGuard);
}
AutoTransaction::~AutoTransaction() {
auto &app = GetApplication();
AutoTransaction::~AutoTransaction()
{
auto& app = GetApplication();
FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard);
if(app._activeTransactionGuard<0)
if (app._activeTransactionGuard < 0) {
++app._activeTransactionGuard;
else if(!app._activeTransactionGuard) {
}
else if (!app._activeTransactionGuard) {
#ifdef FC_DEBUG
FC_ERR("Transaction guard error");
#endif
} else if(--app._activeTransactionGuard == 0) {
}
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) {
}
catch (Base::Exception& e) {
e.ReportException();
} catch(...)
{}
}
catch (...) {
}
}
FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard);
}
void AutoTransaction::close(bool abort) {
if(tid || abort) {
GetApplication().closeActiveTransaction(abort,abort?0:tid);
void AutoTransaction::close(bool abort)
{
if (tid || abort) {
GetApplication().closeActiveTransaction(abort, abort ? 0 : tid);
tid = 0;
}
}
void AutoTransaction::setEnable(bool enable) {
auto &app = GetApplication();
if(!app._activeTransactionGuard)
void AutoTransaction::setEnable(bool enable)
{
auto& app = GetApplication();
if (!app._activeTransactionGuard) {
return;
if((enable && app._activeTransactionGuard>0)
|| (!enable && app._activeTransactionGuard<0))
}
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) {
if (!enable && app._activeTransactionTmpName) {
bool close = true;
for(auto &v : app.DocMap) {
if(v.second->hasPendingTransaction()) {
for (auto& v : app.DocMap) {
if (v.second->hasPendingTransaction()) {
close = false;
break;
}
}
if(close)
if (close) {
app.closeActiveTransaction();
}
}
}
int Application::setActiveTransaction(const char *name, bool persist) {
if(!name || !name[0])
int Application::setActiveTransaction(const char* name, bool persist)
{
if (!name || !name[0]) {
name = "Command";
}
if(_activeTransactionGuard>0 && getActiveTransaction()) {
if(_activeTransactionTmpName) {
if (_activeTransactionGuard > 0 && getActiveTransaction()) {
if (_activeTransactionTmpName) {
FC_LOG("transaction rename to '" << name << "'");
for(auto &v : DocMap)
v.second->renameTransaction(name,_activeTransactionID);
} else {
if(persist)
for (auto& v : DocMap) {
v.second->renameTransaction(name, _activeTransactionID);
}
}
else {
if (persist) {
AutoTransaction::setEnable(false);
}
return 0;
}
} else if (_TransactionLock) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
}
else if (_TransactionLock) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
}
return 0;
} else {
}
else {
FC_LOG("set active transaction '" << name << "'");
_activeTransactionID = 0;
for(auto &v : DocMap)
for (auto& v : DocMap) {
v.second->_commitTransaction();
}
_activeTransactionID = Transaction::getNewID();
}
_activeTransactionTmpName = false;
_activeTransactionName = name;
if(persist)
if (persist) {
AutoTransaction::setEnable(false);
}
return _activeTransactionID;
}
const char *Application::getActiveTransaction(int *id) const {
const char* Application::getActiveTransaction(int* id) const
{
int tid = 0;
if(Transaction::getLastID() == _activeTransactionID)
if (Transaction::getLastID() == _activeTransactionID) {
tid = _activeTransactionID;
if (id)
}
if (id) {
*id = tid;
}
return tid ? _activeTransactionName.c_str() : nullptr;
}
void Application::closeActiveTransaction(bool abort, int id) {
if(!id) id = _activeTransactionID;
if(!id)
void Application::closeActiveTransaction(bool abort, int id)
{
if (!id) {
id = _activeTransactionID;
}
if (!id) {
return;
}
if(_activeTransactionGuard>0 && !abort) {
if (_activeTransactionGuard > 0 && !abort) {
FC_LOG("ignore close transaction");
return;
}
if(_TransactionLock) {
if(_TransactionClosed >= 0)
_TransactionLock = abort?-1:1;
FC_LOG("pending " << (abort?"abort":"close") << " transaction");
if (_TransactionLock) {
if (_TransactionClosed >= 0) {
_TransactionLock = abort ? -1 : 1;
}
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
return;
}
FC_LOG("close transaction '" << _activeTransactionName << "' " << abort);
_activeTransactionID = 0;
TransactionSignaller signaller(abort,false);
for(auto &v : DocMap) {
if(v.second->getTransactionID(true) != id)
TransactionSignaller signaller(abort, false);
for (auto& v : DocMap) {
if (v.second->getTransactionID(true) != id) {
continue;
if(abort)
}
if (abort) {
v.second->_abortTransaction();
else
}
else {
v.second->_commitTransaction();
}
}
}
////////////////////////////////////////////////////////////////////////
TransactionLocker::TransactionLocker(bool lock)
:active(lock)
: active(lock)
{
if(lock)
if (lock) {
++_TransactionLock;
}
}
TransactionLocker::~TransactionLocker()
{
if(active) {
if (active) {
try {
activate(false);
return;
} catch (Base::Exception &e) {
}
catch (Base::Exception& e) {
e.ReportException();
} catch (Py::Exception &) {
}
catch (Py::Exception&) {
Base::PyException e;
e.ReportException();
} catch (std::exception &e) {
}
catch (std::exception& e) {
FC_ERR(e.what());
} catch (...) {
}
catch (...) {
}
FC_ERR("Exception when unlocking transaction");
}
@@ -219,26 +258,28 @@ TransactionLocker::~TransactionLocker()
void TransactionLocker::activate(bool enable)
{
if(active == enable)
if (active == enable) {
return;
}
active = enable;
if(active) {
if (active) {
++_TransactionLock;
return;
}
if(--_TransactionLock != 0)
if (--_TransactionLock != 0) {
return;
}
if(_TransactionClosed) {
bool abort = (_TransactionClosed<0);
if (_TransactionClosed) {
bool abort = (_TransactionClosed < 0);
_TransactionClosed = 0;
GetApplication().closeActiveTransaction(abort);
}
}
bool TransactionLocker::isLocked() {
bool TransactionLocker::isLocked()
{
return _TransactionLock > 0;
}
+17 -12
View File
@@ -26,15 +26,17 @@
#include <cstddef>
#include <FCGlobal.h>
namespace App {
namespace App
{
class Application;
/// Helper class to manager transaction (i.e. undo/redo)
class AppExport AutoTransaction {
class AppExport AutoTransaction
{
public:
/// Private new operator to prevent heap allocation
void* operator new (std::size_t) = delete;
void* operator new(std::size_t) = delete;
public:
/** Constructor
@@ -51,7 +53,7 @@ public:
* current active transaction until it reaches zero. It does not have any
* effect on aborting transaction, though.
*/
AutoTransaction(const char *name=nullptr, bool tmpName=false);
AutoTransaction(const char* name = nullptr, bool tmpName = false);
/** Destructor
*
@@ -67,7 +69,7 @@ public:
* transaction, if the current transaction ID matches the one created inside
* the constructor. For aborting, it will abort any current transaction
*/
void close(bool abort=false);
void close(bool abort = false);
/** Enable/Disable any AutoTransaction instance in the current stack
*
@@ -90,13 +92,13 @@ private:
* The helper class is used to protect some critical transaction from being
* closed prematurely, e.g. when deleting some object.
*/
class AppExport TransactionLocker {
class AppExport TransactionLocker
{
public:
/** Constructor
* @param lock: whether to activate the lock
*/
TransactionLocker(bool lock=true);
TransactionLocker(bool lock = true);
/** Destructor
* Unlock the transaction is this locker is active
@@ -114,7 +116,10 @@ public:
void activate(bool enable);
/// Check if the locker is active
bool isActive() const {return active;}
bool isActive() const
{
return active;
}
/// Check if transaction is being locked
static bool isLocked();
@@ -123,12 +128,12 @@ public:
public:
/// Private new operator to prevent heap allocation
void* operator new (std::size_t) = delete;
void* operator new(std::size_t) = delete;
private:
bool active;
};
} // namespace App
} // namespace App
#endif // APP_AUTOTRANSACTION_H
#endif // APP_AUTOTRANSACTION_H
+10 -7
View File
@@ -63,10 +63,12 @@ Branding::Branding()
bool Branding::readFile(const QString& fn)
{
QFile file(fn);
if (!file.open(QFile::ReadOnly))
if (!file.open(QFile::ReadOnly)) {
return false;
if (!evaluateXML(&file, domDocument))
}
if (!evaluateXML(&file, domDocument)) {
return false;
}
file.close();
return true;
}
@@ -81,22 +83,22 @@ Branding::XmlConfig Branding::getUserDefines() const
while (!child.isNull()) {
std::string name = child.localName().toLatin1().constData();
std::string value = child.text().toUtf8().constData();
if (std::find(filter.begin(), filter.end(), name) != filter.end())
if (std::find(filter.begin(), filter.end(), name) != filter.end()) {
cfg[name] = value;
}
child = child.nextSiblingElement();
}
}
return cfg;
}
bool Branding::evaluateXML(QIODevice *device, QDomDocument& xmlDocument)
bool Branding::evaluateXML(QIODevice* device, QDomDocument& xmlDocument)
{
QString errorStr;
int errorLine;
int errorColumn;
if (!xmlDocument.setContent(device, true, &errorStr, &errorLine,
&errorColumn)) {
if (!xmlDocument.setContent(device, true, &errorStr, &errorLine, &errorColumn)) {
return false;
}
@@ -106,8 +108,9 @@ bool Branding::evaluateXML(QIODevice *device, QDomDocument& xmlDocument)
}
else if (root.hasAttribute(QLatin1String("version"))) {
QString attr = root.attribute(QLatin1String("version"));
if (attr != QLatin1String("1.0"))
if (attr != QLatin1String("1.0")) {
return false;
}
}
return true;
+5 -4
View File
@@ -33,7 +33,8 @@
class QIODevice;
namespace App {
namespace App
{
class Branding
{
@@ -46,10 +47,10 @@ public:
private:
QVector<std::string> filter;
bool evaluateXML(QIODevice *device, QDomDocument& xmlDocument);
bool evaluateXML(QIODevice* device, QDomDocument& xmlDocument);
QDomDocument domDocument;
};
}
} // namespace App
#endif // APP_BRANDING_H
#endif // APP_BRANDING_H
+3 -2
View File
@@ -167,7 +167,7 @@ SET(Document_CPP_SRCS
InventorObject.cpp
Placement.cpp
ProjectFile.cpp
OriginFeature.cpp
Datums.cpp
Range.cpp
Transactions.cpp
TransactionalObject.cpp
@@ -213,7 +213,7 @@ SET(Document_HPP_SRCS
InventorObject.h
Placement.h
ProjectFile.h
OriginFeature.h
Datums.h
Range.h
Transactions.h
TransactionalObject.h
@@ -288,6 +288,7 @@ SET(FreeCADApp_CPP_SRCS
Metadata.cpp
MetadataPyImp.cpp
ElementNamingUtils.cpp
SafeMode.cpp
StringHasher.cpp
StringHasherPyImp.cpp
StringIDPyImp.cpp
+1 -1
View File
@@ -31,7 +31,7 @@ using namespace App;
namespace
{
static std::list<std::function<void()>> cleanup_funcs; // NOLINT
static std::list<std::function<void()>> cleanup_funcs; // NOLINT
}
void CleanupProcess::registerCleanup(const std::function<void()>& func)
+1 -1
View File
@@ -52,6 +52,6 @@ public:
static void callCleanup();
};
}
} // namespace App
#endif // APP_CLEANUPPROCESS_H
+19 -10
View File
@@ -35,15 +35,14 @@ using namespace App;
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
Color::Color(float red, float green, float blue, float alpha)
: r(red)
, g(green)
, b(blue)
, a(alpha)
{
}
: r(red)
, g(green)
, b(blue)
, a(alpha)
{}
Color::Color(uint32_t rgba)
: Color{}
: Color {}
{
setPackedValue(rgba);
}
@@ -67,6 +66,16 @@ void Color::set(float red, float green, float blue, float alpha)
a = alpha;
}
float Color::transparency() const
{
return 1.0F - a;
}
void Color::setTransparency(float value)
{
a = 1.0F - value;
}
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
Color& Color::setPackedValue(uint32_t rgba)
{
@@ -149,7 +158,7 @@ bool Color::fromHexString(const std::string& hex)
if (hex.size() == 7) {
std::stringstream ss(hex);
unsigned int rgb;
char ch{};
char ch {};
ss >> ch >> std::hex >> rgb;
int rc = (rgb >> 16) & 0xff;
@@ -166,13 +175,13 @@ bool Color::fromHexString(const std::string& hex)
if (hex.size() == 9) {
std::stringstream ss(hex);
unsigned int rgba;
char ch{};
char ch {};
ss >> ch >> std::hex >> rgba;
int rc = (rgba >> 24) & 0xff;
int gc = (rgba >> 16) & 0xff;
int bc = (rgba >> 8) & 0xff;
int ac = rgba & 0xff;
int ac = rgba & 0xff;
r = rc / 255.0F;
g = gc / 255.0F;
+102 -27
View File
@@ -25,16 +25,65 @@
#define APP_COLOR_H
#ifdef __GNUC__
# include <cstdint>
#include <cstdint>
#endif
#include <cmath>
#include <string>
#include <FCGlobal.h>
// NOLINTBEGIN(readability-magic-numbers)
namespace App
{
template<class color_type>
struct color_traits
{
color_traits() = default;
explicit color_traits(const color_type& ct)
: ct(ct)
{}
float redF() const
{
return static_cast<float>(ct.redF());
}
float greenF() const
{
return static_cast<float>(ct.greenF());
}
float blueF() const
{
return static_cast<float>(ct.blueF());
}
float alphaF() const
{
return static_cast<float>(ct.alphaF());
}
int red() const
{
return ct.red();
}
int green() const
{
return ct.green();
}
int blue() const
{
return ct.blue();
}
int alpha() const
{
return ct.alpha();
}
static color_type makeColor(int red, int green, int blue, int alpha = 255)
{
return color_type {red, green, blue, alpha};
}
private:
color_type ct;
};
/** Color class
*/
class AppExport Color
@@ -42,9 +91,9 @@ class AppExport Color
public:
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency.
* \a A defines the alpha value.
*/
explicit Color(float R=0.0,float G=0.0, float B=0.0, float A=0.0);
explicit Color(float R = 0.0, float G = 0.0, float B = 0.0, float A = 1.0);
/**
* Does basically the same as the constructor above unless that (R,G,B,A) is
@@ -61,9 +110,11 @@ public:
bool operator!=(const Color& c) const;
/**
* Defines the color as (R,G,B,A) whereas all values are in the range [0,1].
* \a A defines the transparency, 0 means complete opaque and 1 invisible.
* \a A defines the alpha value, 1 means fully opaque and 0 transparent.
*/
void set(float R,float G, float B, float A=0.0);
void set(float R, float G, float B, float A = 1.0);
float transparency() const;
void setTransparency(float value);
Color& operator=(const Color& c) = default;
Color& operator=(Color&& c) = default;
/**
@@ -97,45 +148,68 @@ public:
*/
void setPackedARGB(uint32_t);
template <typename T>
static uint32_t asPackedRGBA(const T& color) {
return (color.red() << 24) | (color.green() << 16) | (color.blue() << 8) | color.alpha();
template<typename T>
static uint32_t asPackedRGBA(const T& color)
{
color_traits<T> ct {color};
return (ct.red() << 24) | (ct.green() << 16) | (ct.blue() << 8) | ct.alpha();
}
template <typename T>
static T fromPackedRGBA(uint32_t color) {
return T((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
template<typename T>
static T fromPackedRGBA(uint32_t color)
{
return color_traits<T>::makeColor((color >> 24) & 0xff,
(color >> 16) & 0xff,
(color >> 8) & 0xff,
(color & 0xff));
}
template <typename T>
static uint32_t asPackedRGB(const T& color) {
return (color.red() << 24) | (color.green() << 16) | (color.blue() << 8);
template<typename T>
static uint32_t asPackedRGB(const T& color)
{
color_traits<T> ct {color};
return (ct.red() << 24) | (ct.green() << 16) | (ct.blue() << 8);
}
template <typename T>
static T fromPackedRGB(uint32_t color) {
return T((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff);
template<typename T>
static T fromPackedRGB(uint32_t color)
{
return color_traits<T>::makeColor((color >> 24) & 0xff,
(color >> 16) & 0xff,
(color >> 8) & 0xff);
}
/**
* creates FC Color from template type, e.g. Qt QColor
*/
template <typename T>
void setValue(const T& q) {
set(q.redF(),q.greenF(),q.blueF());
template<typename T>
void setValue(const T& q)
{
color_traits<T> ct {q};
set(ct.redF(), ct.greenF(), ct.blueF(), ct.alphaF());
}
/**
* returns a template type e.g. Qt color equivalent to FC color
*
*/
template <typename T>
template<typename T>
inline T asValue() const
{
// clang-format off
return(T(int(std::lround(r * 255.0F)),
int(std::lround(g * 255.0F)),
int(std::lround(b * 255.0F))));
return color_traits<T>::makeColor(int(std::lround(r * 255.0F)),
int(std::lround(g * 255.0F)),
int(std::lround(b * 255.0F)),
int(std::lround(a * 255.0F)));
// clang-format on
}
/**
* creates FC Color from template type, e.g. Qt QColor
*/
template<typename T>
static Color fromValue(const T& q)
{
color_traits<T> ct {q};
return Color(ct.redF(), ct.greenF(), ct.blueF(), ct.alphaF());
}
/**
* returns color as hex color "#RRGGBB"
*
@@ -149,9 +223,10 @@ public:
bool fromHexString(const std::string& hex);
/// color values, public accessible
float r,g,b,a;
float r {}, g {}, b {}, a {};
};
} //namespace App
} // namespace App
// NOLINTEND(readability-magic-numbers)
#endif // APP_COLOR_H
#endif // APP_COLOR_H
+151 -121
View File
@@ -23,7 +23,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cstdlib>
#include <cstdlib>
#endif
#include <Base/Exception.h>
@@ -36,66 +36,66 @@ using namespace App;
ColorModelPack ColorModelPack::createRedGreenBlue()
{
ColorModelPack pack{ColorModelBlueGreenRed(),
ColorModelGreenYellowRed(),
ColorModelBlueCyanGreen(),
"Red-Yellow-Green-Cyan-Blue"};
ColorModelPack pack {ColorModelBlueGreenRed(),
ColorModelGreenYellowRed(),
ColorModelBlueCyanGreen(),
"Red-Yellow-Green-Cyan-Blue"};
return pack;
}
ColorModelPack ColorModelPack::createBlueGreenRed()
{
ColorModelPack pack{ColorModelRedGreenBlue(),
ColorModelGreenCyanBlue(),
ColorModelRedYellowGreen(),
"Blue-Cyan-Green-Yellow-Red"};
ColorModelPack pack {ColorModelRedGreenBlue(),
ColorModelGreenCyanBlue(),
ColorModelRedYellowGreen(),
"Blue-Cyan-Green-Yellow-Red"};
return pack;
}
ColorModelPack ColorModelPack::createWhiteBlack()
{
ColorModelPack pack{ColorModelBlackWhite(),
ColorModelGrayWhite(),
ColorModelBlackGray(),
"White-Black"};
ColorModelPack pack {ColorModelBlackWhite(),
ColorModelGrayWhite(),
ColorModelBlackGray(),
"White-Black"};
return pack;
}
ColorModelPack ColorModelPack::createBlackWhite()
{
ColorModelPack pack{ColorModelWhiteBlack(),
ColorModelGrayBlack(),
ColorModelWhiteGray(),
"Black-White"};
ColorModelPack pack {ColorModelWhiteBlack(),
ColorModelGrayBlack(),
ColorModelWhiteGray(),
"Black-White"};
return pack;
}
ColorModelPack ColorModelPack::createRedWhiteBlue()
{
ColorModelPack pack{ColorModelBlueWhiteRed(),
ColorModelWhiteRed(),
ColorModelBlueWhite(),
"Red-White-Blue"};
ColorModelPack pack {ColorModelBlueWhiteRed(),
ColorModelWhiteRed(),
ColorModelBlueWhite(),
"Red-White-Blue"};
return pack;
}
ColorField::ColorField ()
ColorField::ColorField()
{
set(ColorModelBlueGreenRed(), -1.0f, 1.0f, 13);
}
ColorField::ColorField (const ColorModel &rclModel, float fMin, float fMax, std::size_t usCt)
ColorField::ColorField(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt)
{
set(rclModel, fMin, fMax, usCt);
}
ColorField& ColorField::operator = (const ColorField &rclCF)
ColorField& ColorField::operator=(const ColorField& rclCF)
{
colorField = rclCF.colorField;
return *this;
}
void ColorField::set (const ColorModel &rclModel, float fMin, float fMax, std::size_t usCt)
void ColorField::set(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt)
{
auto bounds = std::minmax(fMin, fMax);
if (bounds.second <= bounds.first) {
@@ -109,34 +109,37 @@ void ColorField::set (const ColorModel &rclModel, float fMin, float fMax, std::s
rebuild();
}
void ColorField::setColorModel (const ColorModel &rclModel)
void ColorField::setColorModel(const ColorModel& rclModel)
{
colorModel = rclModel;
rebuild();
}
void ColorField::rebuild ()
void ColorField::rebuild()
{
colorField.resize(ctColors);
std::size_t usStep = std::min<std::size_t>(ctColors / (colorModel.getCountColors() - 1), ctColors - 1);
std::size_t usStep =
std::min<std::size_t>(ctColors / (colorModel.getCountColors() - 1), ctColors - 1);
std::size_t usInd1 = 0;
std::size_t usInd2 = usStep;
for (std::size_t i = 0; i < (colorModel.getCountColors() - 1); i++) {
interpolate(colorModel.colors[i], usInd1, colorModel.colors[i+1], usInd2);
interpolate(colorModel.colors[i], usInd1, colorModel.colors[i + 1], usInd2);
usInd1 = usInd2;
if ((i + 1) == (colorModel.getCountColors() - 2))
if ((i + 1) == (colorModel.getCountColors() - 2)) {
usInd2 = ctColors - 1;
else
}
else {
usInd2 += usStep;
}
}
fAscent = float(ctColors) / (fMax - fMin);
fAscent = float(ctColors) / (fMax - fMin);
fConstant = -fAscent * fMin;
}
// fuellt das Array von Farbe 1, Index 1 bis Farbe 2, Index 2
void ColorField::interpolate (Color clCol1, std::size_t usInd1, Color clCol2, std::size_t usInd2)
void ColorField::interpolate(Color clCol1, std::size_t usInd1, Color clCol2, std::size_t usInd2)
{
float fStep = 1.0f, fLen = float(usInd2 - usInd1);
@@ -161,28 +164,37 @@ ColorGradientProfile::ColorGradientProfile() = default;
bool ColorGradientProfile::isEqual(const ColorGradientProfile& cg) const
{
if (tStyle != cg.tStyle)
if (tStyle != cg.tStyle) {
return false;
if (fMin != cg.fMin)
}
if (fMin != cg.fMin) {
return false;
if (fMax != cg.fMax)
}
if (fMax != cg.fMax) {
return false;
if (!visibility.isEqual(cg.visibility))
}
if (!visibility.isEqual(cg.visibility)) {
return false;
if (tColorModel != cg.tColorModel)
}
if (tColorModel != cg.tColorModel) {
return false;
}
return true;
}
ColorGradient::ColorGradient ()
ColorGradient::ColorGradient()
{
createStandardPacks();
setColorModel();
set(-1.0f, 1.0f, 13, ColorBarStyle::ZERO_BASED, Visibility::Default);
}
ColorGradient::ColorGradient (float fMin, float fMax, std::size_t usCtColors, ColorBarStyle tS, VisibilityFlags flags)
ColorGradient::ColorGradient(float fMin,
float fMax,
std::size_t usCtColors,
ColorBarStyle tS,
VisibilityFlags flags)
{
createStandardPacks();
setColorModel();
@@ -202,8 +214,9 @@ std::vector<std::string> ColorGradient::getColorModelNames() const
{
std::vector<std::string> names;
names.reserve(modelPacks.size());
for (const auto& it : modelPacks)
for (const auto& it : modelPacks) {
names.push_back(it.description);
}
return names;
}
@@ -214,7 +227,11 @@ void ColorGradient::setProfile(const ColorGradientProfile& pro)
rebuild();
}
void ColorGradient::set (float fMin, float fMax, std::size_t usCt, ColorBarStyle tS, VisibilityFlags flags)
void ColorGradient::set(float fMin,
float fMax,
std::size_t usCt,
ColorBarStyle tS,
VisibilityFlags flags)
{
auto bounds = std::minmax(fMin, fMax);
if (bounds.second <= bounds.first) {
@@ -229,74 +246,79 @@ void ColorGradient::set (float fMin, float fMax, std::size_t usCt, ColorBarStyle
rebuild();
}
void ColorGradient::rebuild ()
void ColorGradient::rebuild()
{
switch (profile.tStyle)
{
case ColorBarStyle::FLOW:
{
colorField1.set(currentModelPack.totalModel, profile.fMin, profile.fMax, profile.ctColors);
switch (profile.tStyle) {
case ColorBarStyle::FLOW: {
colorField1.set(currentModelPack.totalModel,
profile.fMin,
profile.fMax,
profile.ctColors);
break;
}
case ColorBarStyle::ZERO_BASED:
{
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f))
{
colorField1.set(currentModelPack.bottomModel, profile.fMin, 0.0f, profile.ctColors / 2);
colorField2.set(currentModelPack.topModel, 0.0f, profile.fMax, profile.ctColors / 2);
case ColorBarStyle::ZERO_BASED: {
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
colorField1.set(currentModelPack.bottomModel,
profile.fMin,
0.0f,
profile.ctColors / 2);
colorField2.set(currentModelPack.topModel,
0.0f,
profile.fMax,
profile.ctColors / 2);
}
else if (profile.fMin >= 0.0f)
else if (profile.fMin >= 0.0f) {
colorField1.set(currentModelPack.topModel, 0.0f, profile.fMax, profile.ctColors);
else
}
else {
colorField1.set(currentModelPack.bottomModel, profile.fMin, 0.0f, profile.ctColors);
}
break;
}
}
}
std::size_t ColorGradient::getMinColors () const
std::size_t ColorGradient::getMinColors() const
{
switch (profile.tStyle)
{
case ColorBarStyle::FLOW:
return colorField1.getMinColors();
case ColorBarStyle::ZERO_BASED:
{
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f))
switch (profile.tStyle) {
case ColorBarStyle::FLOW:
return colorField1.getMinColors();
case ColorBarStyle::ZERO_BASED: {
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
return colorField1.getMinColors() + colorField2.getMinColors();
else
}
else {
return colorField1.getMinColors();
}
}
}
return 2;
}
void ColorGradient::setColorModel (std::size_t tModel)
void ColorGradient::setColorModel(std::size_t tModel)
{
profile.tColorModel = tModel;
setColorModel();
rebuild();
}
void ColorGradient::setColorModel ()
void ColorGradient::setColorModel()
{
if (profile.tColorModel < modelPacks.size())
if (profile.tColorModel < modelPacks.size()) {
currentModelPack = modelPacks[profile.tColorModel];
}
switch (profile.tStyle)
{
case ColorBarStyle::FLOW:
{
colorField1.setColorModel(currentModelPack.totalModel);
colorField2.setColorModel(currentModelPack.bottomModel);
break;
}
case ColorBarStyle::ZERO_BASED:
{
colorField1.setColorModel(currentModelPack.topModel);
colorField2.setColorModel(currentModelPack.bottomModel);
break;
}
switch (profile.tStyle) {
case ColorBarStyle::FLOW: {
colorField1.setColorModel(currentModelPack.totalModel);
colorField2.setColorModel(currentModelPack.bottomModel);
break;
}
case ColorBarStyle::ZERO_BASED: {
colorField1.setColorModel(currentModelPack.topModel);
colorField2.setColorModel(currentModelPack.bottomModel);
break;
}
}
}
@@ -317,60 +339,65 @@ ColorLegend::ColorLegend()
values.push_back(1.0f);
}
bool ColorLegend::operator == (const ColorLegend &rclCL) const
bool ColorLegend::operator==(const ColorLegend& rclCL) const
{
return (colorFields.size() == rclCL.colorFields.size()) &&
(names.size() == rclCL.names.size()) &&
(values.size() == rclCL.values.size()) &&
std::equal(colorFields.begin(), colorFields.end(), rclCL.colorFields.begin()) &&
std::equal(names.begin(), names.end(), rclCL.names.begin()) &&
std::equal(values.begin(), values.end(), rclCL.values.begin()) &&
outsideGrayed == rclCL.outsideGrayed;
return (colorFields.size() == rclCL.colorFields.size()) && (names.size() == rclCL.names.size())
&& (values.size() == rclCL.values.size())
&& std::equal(colorFields.begin(), colorFields.end(), rclCL.colorFields.begin())
&& std::equal(names.begin(), names.end(), rclCL.names.begin())
&& std::equal(values.begin(), values.end(), rclCL.values.begin())
&& outsideGrayed == rclCL.outsideGrayed;
}
float ColorLegend::getValue (std::size_t ulPos) const
float ColorLegend::getValue(std::size_t ulPos) const
{
if (ulPos < values.size())
if (ulPos < values.size()) {
return values[ulPos];
else
}
else {
return 0.0f;
}
}
bool ColorLegend::setValue (std::size_t ulPos, float fVal)
bool ColorLegend::setValue(std::size_t ulPos, float fVal)
{
if (ulPos < values.size())
{
if (ulPos < values.size()) {
values[ulPos] = fVal;
return true;
}
else
else {
return false;
}
}
Color ColorLegend::getColor (std::size_t ulPos) const
Color ColorLegend::getColor(std::size_t ulPos) const
{
if (ulPos < colorFields.size())
if (ulPos < colorFields.size()) {
return colorFields[ulPos];
else
}
else {
return Color();
}
}
// color as: 0x00rrggbb
uint32_t ColorLegend::getPackedColor (std::size_t ulPos) const
uint32_t ColorLegend::getPackedColor(std::size_t ulPos) const
{
Color clRGB = getColor(ulPos);
return clRGB.getPackedValue();
}
std::string ColorLegend::getText (std::size_t ulPos) const
std::string ColorLegend::getText(std::size_t ulPos) const
{
if (ulPos < names.size())
if (ulPos < names.size()) {
return names[ulPos];
else
}
else {
return "";
}
}
std::size_t ColorLegend::addMin (const std::string &rclName)
std::size_t ColorLegend::addMin(const std::string& rclName)
{
names.push_front(rclName);
values.push_front(values.front() - 1.0f);
@@ -385,7 +412,7 @@ std::size_t ColorLegend::addMin (const std::string &rclName)
return colorFields.size() - 1;
}
std::size_t ColorLegend::addMax (const std::string &rclName)
std::size_t ColorLegend::addMax(const std::string& rclName)
{
names.push_back(rclName);
values.push_back(values.back() + 1.0f);
@@ -400,7 +427,7 @@ std::size_t ColorLegend::addMax (const std::string &rclName)
return colorFields.size() - 1;
}
bool ColorLegend::remove (std::size_t ulPos)
bool ColorLegend::remove(std::size_t ulPos)
{
if (ulPos < colorFields.size()) {
colorFields.erase(colorFields.begin() + ulPos);
@@ -413,7 +440,7 @@ bool ColorLegend::remove (std::size_t ulPos)
return false;
}
void ColorLegend::removeFirst ()
void ColorLegend::removeFirst()
{
if (!colorFields.empty()) {
colorFields.erase(colorFields.begin());
@@ -422,33 +449,36 @@ void ColorLegend::removeFirst ()
}
}
void ColorLegend::removeLast ()
void ColorLegend::removeLast()
{
if (!colorFields.empty()) {
colorFields.erase(colorFields.end()-1);
names.erase(names.end()-1);
values.erase(values.end()-1);
colorFields.erase(colorFields.end() - 1);
names.erase(names.end() - 1);
values.erase(values.end() - 1);
}
}
void ColorLegend::resize (std::size_t ulCt)
void ColorLegend::resize(std::size_t ulCt)
{
if ((ulCt < 2) || (ulCt == colorFields.size()))
if ((ulCt < 2) || (ulCt == colorFields.size())) {
return;
}
if (ulCt > colorFields.size()) {
int k = ulCt - colorFields.size();
for (int i = 0; i < k; i++)
for (int i = 0; i < k; i++) {
addMin("new");
}
}
else {
int k = colorFields.size() - ulCt;
for (int i = 0; i < k; i++)
for (int i = 0; i < k; i++) {
removeLast();
}
}
}
bool ColorLegend::setColor (std::size_t ulPos, float ucRed, float ucGreen, float ucBlue)
bool ColorLegend::setColor(std::size_t ulPos, float ucRed, float ucGreen, float ucBlue)
{
if (ulPos < names.size()) {
colorFields[ulPos] = Color(ucRed, ucGreen, ucBlue);
@@ -459,15 +489,15 @@ bool ColorLegend::setColor (std::size_t ulPos, float ucRed, float ucGreen, float
}
// color as 0x00rrggbb
bool ColorLegend::setColor (std::size_t ulPos, unsigned long ulColor)
bool ColorLegend::setColor(std::size_t ulPos, unsigned long ulColor)
{
unsigned char ucRed = (unsigned char)((ulColor & 0x00ff0000) >> 16);
unsigned char ucRed = (unsigned char)((ulColor & 0x00ff0000) >> 16);
unsigned char ucGreen = (unsigned char)((ulColor & 0x0000ff00) >> 8);
unsigned char ucBlue = (unsigned char)(ulColor & 0x000000ff);
unsigned char ucBlue = (unsigned char)(ulColor & 0x000000ff);
return setColor(ulPos, ucRed, ucGreen, ucBlue);
}
bool ColorLegend::setText (std::size_t ulPos, const std::string &rclName)
bool ColorLegend::setText(std::size_t ulPos, const std::string& rclName)
{
if (ulPos < names.size()) {
names[ulPos] = rclName;
+267 -180
View File
@@ -36,7 +36,8 @@
namespace App
{
enum class Visibility {
enum class Visibility
{
Default,
Grayed,
Invisible
@@ -44,12 +45,13 @@ enum class Visibility {
using VisibilityFlags = Base::Flags<Visibility>;
enum class ColorBarStyle {
enum class ColorBarStyle
{
FLOW,
ZERO_BASED
};
}
} // namespace App
ENABLE_BITMASK_OPERATORS(App::Visibility)
@@ -65,8 +67,8 @@ public:
virtual Color getColor(float fVal) const = 0;
protected:
ValueFloatToRGB () = default;
virtual ~ValueFloatToRGB () = default;
ValueFloatToRGB() = default;
virtual ~ValueFloatToRGB() = default;
};
@@ -74,22 +76,26 @@ class AppExport ColorModel
{
public:
ColorModel() = default;
explicit ColorModel (std::size_t usCt) {
explicit ColorModel(std::size_t usCt)
{
colors.resize(usCt);
}
ColorModel(const ColorModel&) = default;
virtual ~ColorModel () = default;
ColorModel& operator = (const ColorModel&) = default;
std::size_t getCountColors() const {
virtual ~ColorModel() = default;
ColorModel& operator=(const ColorModel&) = default;
std::size_t getCountColors() const
{
return colors.size();
}
std::vector<Color> colors;
};
class AppExport ColorModelBlueGreenRed : public ColorModel
class AppExport ColorModelBlueGreenRed: public ColorModel
{
public:
ColorModelBlueGreenRed () : ColorModel(5) {
ColorModelBlueGreenRed()
: ColorModel(5)
{
colors[0] = Color(0, 0, 1);
colors[1] = Color(0, 1, 1);
colors[2] = Color(0, 1, 0);
@@ -98,30 +104,36 @@ public:
}
};
class AppExport ColorModelBlueCyanGreen : public ColorModel
class AppExport ColorModelBlueCyanGreen: public ColorModel
{
public:
ColorModelBlueCyanGreen () : ColorModel(3) {
ColorModelBlueCyanGreen()
: ColorModel(3)
{
colors[0] = Color(0, 0, 1);
colors[1] = Color(0, 1, 1);
colors[2] = Color(0, 1, 0);
}
};
class AppExport ColorModelGreenYellowRed : public ColorModel
class AppExport ColorModelGreenYellowRed: public ColorModel
{
public:
ColorModelGreenYellowRed () : ColorModel(3) {
ColorModelGreenYellowRed()
: ColorModel(3)
{
colors[0] = Color(0, 1, 0);
colors[1] = Color(1, 1, 0);
colors[2] = Color(1, 0, 0);
}
};
class AppExport ColorModelRedGreenBlue : public ColorModel
class AppExport ColorModelRedGreenBlue: public ColorModel
{
public:
ColorModelRedGreenBlue () : ColorModel(5) {
ColorModelRedGreenBlue()
: ColorModel(5)
{
colors[0] = Color(1, 0, 0);
colors[1] = Color(1, 1, 0);
colors[2] = Color(0, 1, 0);
@@ -130,30 +142,36 @@ public:
}
};
class AppExport ColorModelGreenCyanBlue : public ColorModel
class AppExport ColorModelGreenCyanBlue: public ColorModel
{
public:
ColorModelGreenCyanBlue () : ColorModel(3) {
ColorModelGreenCyanBlue()
: ColorModel(3)
{
colors[0] = Color(0, 1, 0);
colors[1] = Color(0, 1, 1);
colors[2] = Color(0, 0, 1);
}
};
class AppExport ColorModelRedYellowGreen : public ColorModel
class AppExport ColorModelRedYellowGreen: public ColorModel
{
public:
ColorModelRedYellowGreen () : ColorModel(3) {
ColorModelRedYellowGreen()
: ColorModel(3)
{
colors[0] = Color(1, 0, 0);
colors[1] = Color(1, 1, 0);
colors[2] = Color(0, 1, 0);
}
};
class AppExport ColorModelBlueWhiteRed : public ColorModel
class AppExport ColorModelBlueWhiteRed: public ColorModel
{
public:
ColorModelBlueWhiteRed () : ColorModel(5) {
ColorModelBlueWhiteRed()
: ColorModel(5)
{
colors[0] = Color(0, 0, 1);
colors[1] = Color(float(85.0 / 255), float(170.0 / 255), 1);
colors[2] = Color(1, 1, 1);
@@ -162,75 +180,91 @@ public:
}
};
class AppExport ColorModelBlueWhite : public ColorModel
class AppExport ColorModelBlueWhite: public ColorModel
{
public:
ColorModelBlueWhite () : ColorModel(3) {
ColorModelBlueWhite()
: ColorModel(3)
{
colors[0] = Color(0, 0, 1);
colors[1] = Color(float(85.0 / 255), float(170.0 / 255), 1);
colors[2] = Color(1, 1, 1);
}
};
class AppExport ColorModelWhiteRed : public ColorModel
class AppExport ColorModelWhiteRed: public ColorModel
{
public:
ColorModelWhiteRed () : ColorModel(3) {
ColorModelWhiteRed()
: ColorModel(3)
{
colors[0] = Color(1, 1, 1);
colors[1] = Color(1, float(85.0 / 255), 0);
colors[2] = Color(1, 0, 0);
}
};
class AppExport ColorModelBlackWhite : public ColorModel
class AppExport ColorModelBlackWhite: public ColorModel
{
public:
ColorModelBlackWhite () : ColorModel(2) {
ColorModelBlackWhite()
: ColorModel(2)
{
colors[0] = Color(0, 0, 0);
colors[1] = Color(1, 1, 1);
}
};
class AppExport ColorModelBlackGray : public ColorModel
class AppExport ColorModelBlackGray: public ColorModel
{
public:
ColorModelBlackGray () : ColorModel(2) {
ColorModelBlackGray()
: ColorModel(2)
{
colors[0] = Color(0.0f, 0.0f, 0.0f);
colors[1] = Color(0.5f, 0.5f, 0.5f);
}
};
class AppExport ColorModelGrayWhite : public ColorModel
class AppExport ColorModelGrayWhite: public ColorModel
{
public:
ColorModelGrayWhite () : ColorModel(2) {
ColorModelGrayWhite()
: ColorModel(2)
{
colors[0] = Color(0.5f, 0.5f, 0.5f);
colors[1] = Color(1.0f, 1.0f, 1.0f);
}
};
class AppExport ColorModelWhiteBlack : public ColorModel
class AppExport ColorModelWhiteBlack: public ColorModel
{
public:
ColorModelWhiteBlack () : ColorModel(2) {
ColorModelWhiteBlack()
: ColorModel(2)
{
colors[0] = Color(1, 1, 1);
colors[1] = Color(0, 0, 0);
}
};
class AppExport ColorModelWhiteGray : public ColorModel
class AppExport ColorModelWhiteGray: public ColorModel
{
public:
ColorModelWhiteGray () : ColorModel(2) {
ColorModelWhiteGray()
: ColorModel(2)
{
colors[0] = Color(1.0f, 1.0f, 1.0f);
colors[1] = Color(0.5f, 0.5f, 0.5f);
}
};
class AppExport ColorModelGrayBlack : public ColorModel
class AppExport ColorModelGrayBlack: public ColorModel
{
public:
ColorModelGrayBlack () : ColorModel(2) {
ColorModelGrayBlack()
: ColorModel(2)
{
colors[0] = Color(0.5f, 0.5f, 0.5f);
colors[1] = Color(0.0f, 0.0f, 0.0f);
}
@@ -252,48 +286,59 @@ struct AppExport ColorModelPack
class AppExport ColorField
{
public:
ColorField ();
ColorField (const ColorField &rclCF) = default;
ColorField (const ColorModel &rclModel, float fMin, float fMax, std::size_t usCt);
virtual ~ColorField () = default;
ColorField();
ColorField(const ColorField& rclCF) = default;
ColorField(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt);
virtual ~ColorField() = default;
ColorField& operator = (const ColorField &rclCF);
ColorField& operator=(const ColorField& rclCF);
std::size_t getCountColors () const {
std::size_t getCountColors() const
{
return ctColors;
}
void set (const ColorModel &rclModel, float fMin, float fMax, std::size_t usCt);
void setCountColors (std::size_t usCt) {
void set(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt);
void setCountColors(std::size_t usCt)
{
set(colorModel, fMin, fMax, usCt);
}
void setRange (float fMin, float fMax) {
void setRange(float fMin, float fMax)
{
set(colorModel, fMin, fMax, ctColors);
}
void getRange (float &rfMin, float &rfMax) {
rfMin = fMin; rfMax = fMax;
void getRange(float& rfMin, float& rfMax)
{
rfMin = fMin;
rfMax = fMax;
}
std::size_t getMinColors () const {
std::size_t getMinColors() const
{
return colorModel.getCountColors();
}
void setColorModel (const ColorModel &rclModel);
const ColorModel& getColorModel () const {
void setColorModel(const ColorModel& rclModel);
const ColorModel& getColorModel() const
{
return colorModel;
}
void setDirect (std::size_t usInd, Color clCol) {
void setDirect(std::size_t usInd, Color clCol)
{
colorField[usInd] = clCol;
}
float getMinValue () const {
float getMinValue() const
{
return fMin;
}
float getMaxValue () const {
float getMaxValue() const
{
return fMax;
}
Color getColor (std::size_t usIndex) const {
Color getColor(std::size_t usIndex) const
{
return colorField[usIndex];
}
inline Color getColor (float fVal) const;
inline std::size_t getColorIndex (float fVal) const;
inline Color getColor(float fVal) const;
inline std::size_t getColorIndex(float fVal) const;
protected:
ColorModel colorModel;
@@ -302,32 +347,34 @@ protected:
std::size_t ctColors;
std::vector<Color> colorField;
void rebuild ();
void interpolate (Color clCol1, std::size_t usPos1, Color clCol2, std::size_t usPos2);
void rebuild();
void interpolate(Color clCol1, std::size_t usPos1, Color clCol2, std::size_t usPos2);
};
inline Color ColorField::getColor (float fVal) const
inline Color ColorField::getColor(float fVal) const
{
// if the value is outside or at the border of the range
std::size_t ct = colorModel.getCountColors() - 1;
if ( fVal <= fMin )
if (fVal <= fMin) {
return colorModel.colors[0];
else if ( fVal >= fMax )
}
else if (fVal >= fMax) {
return colorModel.colors[ct];
}
// get the color field position (with 0 < t < 1)
float t = (fVal - fMin) / (fMax - fMin);
Color col(1.0f, 1.0f, 1.0f); // white as default
for (std::size_t i=0; i<ct; i++) {
float r = (float)(i+1)/(float)ct;
Color col(1.0f, 1.0f, 1.0f); // white as default
for (std::size_t i = 0; i < ct; i++) {
float r = (float)(i + 1) / (float)ct;
if (t < r) {
// calculate the exact position in the subrange
float s = t * float(ct) - float(i);
Color c1 = colorModel.colors[i];
Color c2 = colorModel.colors[i+1];
col.r = (1.0f-s) * c1.r + s * c2.r;
col.g = (1.0f-s) * c1.g + s * c2.g;
col.b = (1.0f-s) * c1.b + s * c2.b;
Color c2 = colorModel.colors[i + 1];
col.r = (1.0f - s) * c1.r + s * c2.r;
col.g = (1.0f - s) * c1.g + s * c2.g;
col.b = (1.0f - s) * c1.b + s * c2.b;
break;
}
}
@@ -335,23 +382,24 @@ inline Color ColorField::getColor (float fVal) const
return col;
}
inline std::size_t ColorField::getColorIndex (float fVal) const
inline std::size_t ColorField::getColorIndex(float fVal) const
{
return std::size_t(std::min<int>(std::max<int>(int(fConstant + fAscent * fVal), 0), int(ctColors - 1)));
return std::size_t(
std::min<int>(std::max<int>(int(fConstant + fAscent * fVal), 0), int(ctColors - 1)));
}
struct AppExport ColorGradientProfile
{
ColorBarStyle tStyle{ColorBarStyle::FLOW};
float fMin{};
float fMax{};
std::size_t ctColors{};
std::size_t tColorModel{};
VisibilityFlags visibility{Visibility::Default};
ColorBarStyle tStyle {ColorBarStyle::FLOW};
float fMin {};
float fMax {};
std::size_t ctColors {};
std::size_t tColorModel {};
VisibilityFlags visibility {Visibility::Default};
ColorGradientProfile();
ColorGradientProfile (const ColorGradientProfile &) = default;
ColorGradientProfile& operator = (const ColorGradientProfile &) = default;
ColorGradientProfile(const ColorGradientProfile&) = default;
ColorGradientProfile& operator=(const ColorGradientProfile&) = default;
bool isEqual(const ColorGradientProfile&) const;
};
@@ -359,261 +407,300 @@ struct AppExport ColorGradientProfile
class AppExport ColorGradient
{
public:
ColorGradient ();
ColorGradient (float fMin, float fMax, std::size_t usCtColors, ColorBarStyle tS, VisibilityFlags fl = Visibility::Default);
ColorGradient (const ColorGradient &) = default;
ColorGradient& operator = (const ColorGradient &) = default;
const ColorGradientProfile& getProfile() const {
ColorGradient();
ColorGradient(float fMin,
float fMax,
std::size_t usCtColors,
ColorBarStyle tS,
VisibilityFlags fl = Visibility::Default);
ColorGradient(const ColorGradient&) = default;
ColorGradient& operator=(const ColorGradient&) = default;
const ColorGradientProfile& getProfile() const
{
return profile;
}
void setProfile(const ColorGradientProfile& pro);
void set (float fMin, float fMax, std::size_t usCt, ColorBarStyle tS, VisibilityFlags fl);
void setRange (float fMin, float fMax) {
void set(float fMin, float fMax, std::size_t usCt, ColorBarStyle tS, VisibilityFlags fl);
void setRange(float fMin, float fMax)
{
set(fMin, fMax, profile.ctColors, profile.tStyle, profile.visibility);
}
void getRange (float &rfMin, float &rfMax) const {
void getRange(float& rfMin, float& rfMax) const
{
rfMin = profile.fMin;
rfMax = profile.fMax;
}
bool isOutOfRange(float fVal) const {
bool isOutOfRange(float fVal) const
{
return ((fVal < profile.fMin) || (fVal > profile.fMax));
}
std::size_t getCountColors () const {
std::size_t getCountColors() const
{
return profile.ctColors;
}
void setCountColors (std::size_t usCt) {
void setCountColors(std::size_t usCt)
{
set(profile.fMin, profile.fMax, usCt, profile.tStyle, profile.visibility);
}
void setStyle (ColorBarStyle tS) {
void setStyle(ColorBarStyle tS)
{
set(profile.fMin, profile.fMax, profile.ctColors, tS, profile.visibility);
}
std::size_t getMinColors () const;
ColorBarStyle getStyle () const {
std::size_t getMinColors() const;
ColorBarStyle getStyle() const
{
return profile.tStyle;
}
void setOutsideGrayed (bool value) {
void setOutsideGrayed(bool value)
{
profile.visibility.setFlag(Visibility::Grayed, value);
}
bool isOutsideGrayed () const {
bool isOutsideGrayed() const
{
return profile.visibility.testFlag(Visibility::Grayed);
}
void setOutsideInvisible (bool value) {
void setOutsideInvisible(bool value)
{
profile.visibility.setFlag(Visibility::Invisible, value);
}
bool isOutsideInvisible () const {
bool isOutsideInvisible() const
{
return profile.visibility.testFlag(Visibility::Invisible);
}
void setColorModel (std::size_t tModel);
std::size_t getColorModelType () const {
void setColorModel(std::size_t tModel);
std::size_t getColorModelType() const
{
return profile.tColorModel;
}
inline const ColorModel& getColorModel () const;
inline const ColorModel& getColorModel() const;
std::vector<std::string> getColorModelNames() const;
float getMinValue () const {
float getMinValue() const
{
return profile.fMin;
}
float getMaxValue () const {
float getMaxValue() const
{
return profile.fMax;
}
inline Color getColor (float fVal) const;
inline std::size_t getColorIndex (float fVal) const;
inline Color getColor(float fVal) const;
inline std::size_t getColorIndex(float fVal) const;
private:
inline Color _getColor (float fVal) const;
inline Color _getColor(float fVal) const;
protected:
void createStandardPacks();
protected:
ColorGradientProfile profile;
ColorField colorField1, colorField2;
ColorField colorField1, colorField2;
ColorModelPack currentModelPack;
std::vector<ColorModelPack> modelPacks;
void rebuild ();
void setColorModel ();
void rebuild();
void setColorModel();
};
class AppExport ColorLegend
{
public:
ColorLegend ();
ColorLegend (const ColorLegend &rclCL) = default;
virtual ~ColorLegend () = default;
ColorLegend();
ColorLegend(const ColorLegend& rclCL) = default;
virtual ~ColorLegend() = default;
ColorLegend& operator = (const ColorLegend &rclCL) = default;
bool operator == (const ColorLegend &rclCL) const;
bool operator != (const ColorLegend &rclCL) const {
ColorLegend& operator=(const ColorLegend& rclCL) = default;
bool operator==(const ColorLegend& rclCL) const;
bool operator!=(const ColorLegend& rclCL) const
{
return !(*this == rclCL);
}
void resize (std::size_t ulN);
std::size_t addMin (const std::string &rclName);
std::size_t addMax (const std::string &rclName);
bool remove (std::size_t ulPos);
void removeFirst ();
void removeLast ();
void resize(std::size_t ulN);
std::size_t addMin(const std::string& rclName);
std::size_t addMax(const std::string& rclName);
bool remove(std::size_t ulPos);
void removeFirst();
void removeLast();
Color getColor (std::size_t ulPos) const;
uint32_t getPackedColor (std::size_t ulPos) const;
bool setColor (std::size_t ulPos, float ucRed, float ucGreen, float ucBlue);
bool setColor (std::size_t ulPos, unsigned long ulColor);
float getValue (std::size_t ulPos) const;
bool setValue (std::size_t ulPos, float fVal);
std::string getText (std::size_t ulPos) const;
bool setText (std::size_t ulPos, const std::string &rclName);
std::size_t hasNumberOfFields () const {
Color getColor(std::size_t ulPos) const;
uint32_t getPackedColor(std::size_t ulPos) const;
bool setColor(std::size_t ulPos, float ucRed, float ucGreen, float ucBlue);
bool setColor(std::size_t ulPos, unsigned long ulColor);
float getValue(std::size_t ulPos) const;
bool setValue(std::size_t ulPos, float fVal);
std::string getText(std::size_t ulPos) const;
bool setText(std::size_t ulPos, const std::string& rclName);
std::size_t hasNumberOfFields() const
{
return colorFields.size();
}
void setOutsideGrayed (bool bOS) {
void setOutsideGrayed(bool bOS)
{
outsideGrayed = bOS;
}
bool isOutsideGrayed () const {
bool isOutsideGrayed() const
{
return outsideGrayed;
}
inline float getMinValue () const;
inline float getMaxValue () const;
inline float getMinValue() const;
inline float getMaxValue() const;
inline Color getColor (float fVal) const;
inline std::size_t getColorIndex (float fVal) const;
inline Color getColor(float fVal) const;
inline std::size_t getColorIndex(float fVal) const;
protected:
std::deque<Color> colorFields;
std::deque<std::string> names;
std::deque<float> values;
bool outsideGrayed{false};
bool outsideGrayed {false};
};
inline Color ColorLegend::getColor (float fVal) const
inline Color ColorLegend::getColor(float fVal) const
{
std::deque<float>::const_iterator pI;
for (pI = values.begin(); pI != values.end(); ++pI) {
if (fVal < *pI)
if (fVal < *pI) {
break;
}
}
if (outsideGrayed) {
if ((pI == values.begin()) || (pI == values.end()))
if ((pI == values.begin()) || (pI == values.end())) {
return Color(0.5f, 0.5f, 0.5f);
else
}
else {
return colorFields[pI - values.begin() - 1];
}
}
if (pI == values.begin())
if (pI == values.begin()) {
return *colorFields.begin();
else if (pI == values.end())
return *(colorFields.end()-1);
else
}
else if (pI == values.end()) {
return *(colorFields.end() - 1);
}
else {
return colorFields[pI - values.begin() - 1];
}
}
inline std::size_t ColorLegend::getColorIndex (float fVal) const
inline std::size_t ColorLegend::getColorIndex(float fVal) const
{
std::deque<float>::const_iterator pI;
for (pI = values.begin(); pI != values.end(); ++pI) {
if (fVal < *pI)
if (fVal < *pI) {
break;
}
}
if (pI == values.begin())
if (pI == values.begin()) {
return 0;
else if (pI == values.end())
}
else if (pI == values.end()) {
return (std::size_t)(colorFields.size() - 1);
else
}
else {
return pI - values.begin() - 1;
}
}
inline float ColorLegend::getMinValue () const
inline float ColorLegend::getMinValue() const
{
return values.front();
}
inline float ColorLegend::getMaxValue () const
inline float ColorLegend::getMaxValue() const
{
return values.back();
}
inline Color ColorGradient::getColor (float fVal) const
inline Color ColorGradient::getColor(float fVal) const
{
Color color = _getColor(fVal);
if (isOutsideInvisible()) {
if (isOutOfRange(fVal))
color.a = 0.8f;
if (isOutOfRange(fVal)) {
color.a = 0.2F;
}
}
return color;
}
inline Color ColorGradient::_getColor (float fVal) const
inline Color ColorGradient::_getColor(float fVal) const
{
if (isOutsideGrayed()) {
if (isOutOfRange(fVal))
if (isOutOfRange(fVal)) {
return Color(0.5f, 0.5f, 0.5f);
}
}
switch (profile.tStyle) {
case ColorBarStyle::ZERO_BASED:
{
case ColorBarStyle::ZERO_BASED: {
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
if (fVal < 0.0f)
if (fVal < 0.0f) {
return colorField1.getColor(fVal);
else
}
else {
return colorField2.getColor(fVal);
}
}
else {
return colorField1.getColor(fVal);
}
}
default:
case ColorBarStyle::FLOW:
{
default:
case ColorBarStyle::FLOW: {
return colorField1.getColor(fVal);
}
}
}
inline std::size_t ColorGradient::getColorIndex (float fVal) const
inline std::size_t ColorGradient::getColorIndex(float fVal) const
{
switch (profile.tStyle) {
case ColorBarStyle::ZERO_BASED:
{
case ColorBarStyle::ZERO_BASED: {
if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
if (fVal < 0.0f)
if (fVal < 0.0f) {
return colorField1.getColorIndex(fVal);
else
return std::size_t(colorField1.getCountColors() + colorField2.getColorIndex(fVal));
}
else {
return std::size_t(colorField1.getCountColors()
+ colorField2.getColorIndex(fVal));
}
}
else {
return colorField1.getColorIndex(fVal);
}
}
default:
case ColorBarStyle::FLOW:
{
default:
case ColorBarStyle::FLOW: {
return colorField1.getColorIndex(fVal);
}
}
}
inline const ColorModel& ColorGradient::getColorModel () const
inline const ColorModel& ColorGradient::getColorModel() const
{
if (profile.tStyle == ColorBarStyle::ZERO_BASED) {
if (profile.fMax <= 0.0f)
if (profile.fMax <= 0.0f) {
return currentModelPack.bottomModel;
else if ( profile.fMin >= 0.0f )
}
else if (profile.fMin >= 0.0f) {
return currentModelPack.topModel;
else
}
else {
return currentModelPack.totalModel;
}
}
return currentModelPack.totalModel;
}
} // namespace App
} // namespace App
#endif // APP_COLORMODEL_H
#endif // APP_COLORMODEL_H
+14 -12
View File
@@ -184,20 +184,20 @@ bool ComplexGeoData::getCenterOfGravity(Base::Vector3d& unused) const
return false;
}
const std::string &ComplexGeoData::elementMapPrefix() {
const std::string& ComplexGeoData::elementMapPrefix()
{
static std::string prefix(ELEMENT_MAP_PREFIX);
return prefix;
}
std::string ComplexGeoData::getElementMapVersion() const {
std::string ComplexGeoData::getElementMapVersion() const
{
return "4";
}
bool ComplexGeoData::checkElementMapVersion(const char * ver) const
bool ComplexGeoData::checkElementMapVersion(const char* ver) const
{
return !boost::equals(ver, "3")
&& !boost::equals(ver, "4")
&& !boost::starts_with(ver, "3.");
return !boost::equals(ver, "3") && !boost::equals(ver, "4") && !boost::starts_with(ver, "3.");
}
size_t ComplexGeoData::getElementMapSize(bool flush) const
@@ -301,8 +301,9 @@ ElementMapPtr ComplexGeoData::resetElementMap(ElementMapPtr elementMap)
_elementMap.swap(elementMap);
// We expect that if the ComplexGeoData ( TopoShape ) has a hasher, then its elementMap will
// have the same one. Make sure that happens.
if ( _elementMap && ! _elementMap->hasher )
if (_elementMap && !_elementMap->hasher) {
_elementMap->hasher = Hasher;
}
return elementMap;
}
@@ -329,7 +330,6 @@ ElementMapPtr ComplexGeoData::ensureElementMap(bool flush)
resetElementMap(std::make_shared<Data::ElementMap>());
}
return elementMap(flush);
}
void ComplexGeoData::flushElementMap() const
@@ -656,12 +656,13 @@ unsigned int ComplexGeoData::getMemSize() const
return 0;
}
std::vector<IndexedName> ComplexGeoData::getHigherElements(const char *, bool) const
std::vector<IndexedName> ComplexGeoData::getHigherElements(const char*, bool) const
{
return {};
}
void ComplexGeoData::setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements> & children)
void ComplexGeoData::setMappedChildElements(
const std::vector<Data::ElementMap::MappedChildElements>& children)
{
// DO NOT reset element map if there is one. Because we allow mixing child
// mapping and normal mapping
@@ -690,8 +691,9 @@ void ComplexGeoData::beforeSave() const
void ComplexGeoData::hashChildMaps()
{
flushElementMap();
if (_elementMap)
if (_elementMap) {
_elementMap->hashChildMaps(Tag);
}
}
bool ComplexGeoData::hasChildElementMap() const
@@ -704,7 +706,7 @@ void ComplexGeoData::dumpElementMap(std::ostream& stream) const
{
auto map = getElementMap();
std::sort(map.begin(), map.end());
for ( auto& element : map ) {
for (auto& element : map) {
stream << element.index << " : " << element.name << std::endl;
}
}
+123 -90
View File
@@ -37,7 +37,7 @@
#include "StringHasher.h"
#ifdef __GNUC__
# include <cstdint>
#include <cstdint>
#endif
@@ -45,16 +45,18 @@ namespace Base
{
class Placement;
class Rotation;
template <class _Precision> class BoundBox3;// NOLINT
template<class _Precision>
class BoundBox3; // NOLINT
using BoundBox3d = BoundBox3<double>;
}
} // namespace Base
namespace Data
{
//struct MappedChildElements;
// struct MappedChildElements;
/// Option for App::GeoFeature::searchElementCache()
enum class SearchOption {
enum class SearchOption
{
/// Whether to compare shape geometry
CheckGeometry = 1,
SingleResult = 2,
@@ -67,11 +69,11 @@ typedef Base::Flags<SearchOption> SearchOptions;
*/
class AppExport Segment: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();// NOLINT
TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT
public:
~Segment() override = default;
virtual std::string getName() const=0;
virtual std::string getName() const = 0;
};
enum ElementMapResetPolicy
@@ -84,12 +86,22 @@ enum ElementMapResetPolicy
*/
class AppExport ComplexGeoData: public Base::Persistence, public Base::Handled
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();// NOLINT
TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT
public:
struct Line {uint32_t I1; uint32_t I2;};
struct Facet {uint32_t I1; uint32_t I2; uint32_t I3;};
struct Domain {
struct Line
{
uint32_t I1;
uint32_t I2;
};
struct Facet
{
uint32_t I1;
uint32_t I2;
uint32_t I3;
};
struct Domain
{
std::vector<Base::Vector3d> points;
std::vector<Facet> facets;
};
@@ -105,26 +117,24 @@ public:
* List of different sub-element types
* its NOT a list of the sub-elements itself
*/
virtual std::vector<const char*> getElementTypes() const=0;
virtual unsigned long countSubElements(const char* Type) const=0;
virtual std::vector<const char*> getElementTypes() const = 0;
virtual unsigned long countSubElements(const char* Type) const = 0;
/// Returns a generic element type and index. The determined element type isn't
/// necessarily supported by this geometry.
static std::pair<std::string, unsigned long> getTypeAndIndex(const char* Name);
/// get the sub-element by type and number
virtual Segment* getSubElement(const char* Type, unsigned long) const=0;
virtual Segment* getSubElement(const char* Type, unsigned long) const = 0;
/// get sub-element by combined name
virtual Segment* getSubElementByName(const char* Name) const;
/** Get lines from segment */
virtual void getLinesFromSubElement(
const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Line> &lines) const;
virtual void getLinesFromSubElement(const Segment*,
std::vector<Base::Vector3d>& Points,
std::vector<Line>& lines) const;
/** Get faces from segment */
virtual void getFacesFromSubElement(
const Segment*,
std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &PointNormals,
std::vector<Facet> &faces) const;
virtual void getFacesFromSubElement(const Segment*,
std::vector<Base::Vector3d>& Points,
std::vector<Base::Vector3d>& PointNormals,
std::vector<Facet>& faces) const;
//@}
/** @name Placement control */
@@ -147,7 +157,7 @@ public:
* This method has to be handled by the child classes.
* the actual placement and matrix is not part of this class.
*/
virtual void setTransform(const Base::Matrix4D& rclTrf)=0;
virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
/** Return the current matrix
* This method has to be handled by the child classes.
* the actual placement and matrix is not part of this class.
@@ -158,7 +168,7 @@ public:
/** @name Modification */
//@{
/// Applies a transformation on the real geometric data type
virtual void transformGeometry(const Base::Matrix4D &rclMat) = 0;
virtual void transformGeometry(const Base::Matrix4D& rclMat) = 0;
//@}
/** @name Getting basic geometric entities */
@@ -166,21 +176,25 @@ public:
/// Get the standard accuracy to be used with getPoints, getLines or getFaces
virtual double getAccuracy() const;
/// Get the bound box
virtual Base::BoundBox3d getBoundBox() const=0;
virtual Base::BoundBox3d getBoundBox() const = 0;
/** Get point from line object intersection */
virtual Base::Vector3d getPointFromLineIntersection(
const Base::Vector3f& base,
const Base::Vector3f& dir) const;
virtual Base::Vector3d getPointFromLineIntersection(const Base::Vector3f& base,
const Base::Vector3f& dir) const;
/** Get points from object with given accuracy */
virtual void getPoints(std::vector<Base::Vector3d> &Points,
std::vector<Base::Vector3d> &Normals,
double Accuracy, uint16_t flags=0) const;
virtual void getPoints(std::vector<Base::Vector3d>& Points,
std::vector<Base::Vector3d>& Normals,
double Accuracy,
uint16_t flags = 0) const;
/** Get lines from object with given accuracy */
virtual void getLines(std::vector<Base::Vector3d> &Points,std::vector<Line> &lines,
double Accuracy, uint16_t flags=0) const;
virtual void getLines(std::vector<Base::Vector3d>& Points,
std::vector<Line>& lines,
double Accuracy,
uint16_t flags = 0) const;
/** Get faces from object with given accuracy */
virtual void getFaces(std::vector<Base::Vector3d> &Points,std::vector<Facet> &faces,
double Accuracy, uint16_t flags=0) const;
virtual void getFaces(std::vector<Base::Vector3d>& Points,
std::vector<Facet>& faces,
double Accuracy,
uint16_t flags = 0) const;
/** Get the center of gravity
* If this method is implemented then true is returned and the center of gravity.
* The default implementation only returns false.
@@ -188,7 +202,7 @@ public:
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
//@}
static const std::string &elementMapPrefix();
static const std::string& elementMapPrefix();
/** @name Element name mapping */
//@{
@@ -200,8 +214,7 @@ public:
*
* @return Returns an indexed name.
*/
IndexedName getIndexedName(const MappedName & name,
ElementIDRefs *sid = nullptr) const;
IndexedName getIndexedName(const MappedName& name, ElementIDRefs* sid = nullptr) const;
/** Get element mapped name
*
@@ -212,9 +225,9 @@ public:
* @param sid: optional output of and App::StringID involved forming this mapped name
* @return Returns the mapped name.
*/
MappedName getMappedName(const IndexedName & element,
MappedName getMappedName(const IndexedName& element,
bool allowUnmapped = false,
ElementIDRefs *sid = nullptr) const;
ElementIDRefs* sid = nullptr) const;
/** Return a pair of indexed name and mapped name
*
@@ -233,9 +246,8 @@ public:
* it will be treated as indexed name. Or else, it will be treated as
* mapped name.
*/
MappedElement getElementName(const char * name,
ElementIDRefs *sid = nullptr,
bool copy = false) const;
MappedElement
getElementName(const char* name, ElementIDRefs* sid = nullptr, bool copy = false) const;
/** Add a sub-element name mapping.
*
@@ -259,11 +271,13 @@ public:
const MappedName& name,
long masterTag,
const ElementIDRefs* sid = nullptr,
bool overwrite = false) {
return _elementMap -> setElementName(element, name, masterTag, sid, overwrite);
bool overwrite = false)
{
return _elementMap->setElementName(element, name, masterTag, sid, overwrite);
}
bool hasElementMap() {
bool hasElementMap()
{
return _elementMap != nullptr;
}
@@ -276,8 +290,8 @@ public:
* @return a list of mapped names of the give element along with their
* associated string ID references
*/
std::vector<std::pair<MappedName, ElementIDRefs> >
getElementMappedNames(const IndexedName & element, bool needUnmapped=false) const;
std::vector<std::pair<MappedName, ElementIDRefs>>
getElementMappedNames(const IndexedName& element, bool needUnmapped = false) const;
/// Hash the child element map postfixes to shorten element name from hierarchical maps
void hashChildMaps();
@@ -286,29 +300,31 @@ public:
bool hasChildElementMap() const;
/// Append the Tag (if and only if it is non zero) into the element map
virtual void reTagElementMap(long tag,
App::StringHasherRef hasher,
const char *postfix=nullptr) {
virtual void
reTagElementMap(long tag, App::StringHasherRef hasher, const char* postfix = nullptr)
{
(void)tag;
(void)hasher;
(void)postfix;
}
// NOTE: getElementHistory is now in ElementMap
long getElementHistory(const MappedName & name,
MappedName *original=nullptr, std::vector<MappedName> *history=nullptr) const {
if ( _elementMap != nullptr ) {
long getElementHistory(const MappedName& name,
MappedName* original = nullptr,
std::vector<MappedName>* history = nullptr) const
{
if (_elementMap != nullptr) {
return _elementMap->getElementHistory(name, Tag, original, history);
}
return 0;
};
void setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements> & children);
void setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements>& children);
std::vector<Data::ElementMap::MappedChildElements> getMappedChildElements() const;
char elementType(const Data::MappedName &) const;
char elementType(const Data::IndexedName &) const;
char elementType(const char *name) const;
char elementType(const Data::MappedName&) const;
char elementType(const Data::IndexedName&) const;
char elementType(const char* name) const;
/** Reset/swap the element map
*
@@ -322,19 +338,19 @@ public:
std::vector<MappedElement> getElementMap() const;
/// Set the entire element map
void setElementMap(const std::vector<MappedElement> &elements);
void setElementMap(const std::vector<MappedElement>& elements);
/// Get the current element map size
size_t getElementMapSize(bool flush=true) const;
size_t getElementMapSize(bool flush = true) const;
/// Return the higher level element names of the given element
virtual std::vector<IndexedName> getHigherElements(const char *name, bool silent=false) const;
virtual std::vector<IndexedName> getHigherElements(const char* name, bool silent = false) const;
/// Return the current element map version
virtual std::string getElementMapVersion() const;
/// Return true to signal element map version change
virtual bool checkElementMapVersion(const char * ver) const;
virtual bool checkElementMapVersion(const char* ver) const;
/// Check if the given sub-name only contains an element name
static bool isElementName(const char* subName)
@@ -359,15 +375,21 @@ public:
/** @name Save/restore */
//@{
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
void SaveDocFile(Base::Writer &writer) const override;
void RestoreDocFile(Base::Reader &reader) override;
unsigned int getMemSize () const override;
void setPersistenceFileName(const char *name) const;
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
void SaveDocFile(Base::Writer& writer) const override;
void RestoreDocFile(Base::Reader& reader) override;
unsigned int getMemSize() const override;
void setPersistenceFileName(const char* name) const;
virtual void beforeSave() const;
bool isRestoreFailed() const { return _restoreFailed; }
void resetRestoreFailure() const { _restoreFailed = true; }
bool isRestoreFailed() const
{
return _restoreFailed;
}
void resetRestoreFailure() const
{
_restoreFailed = true;
}
//@}
/**
@@ -382,51 +404,60 @@ public:
const std::string dumpElementMap() const;
protected:
/// from local to outside
inline Base::Vector3d transformPointToOutside(const Base::Vector3f& vec) const
{
// clang-format off
return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
// clang-format on
}
/// from local to outside
template<typename Vec>
inline std::vector<Base::Vector3d> transformPointsToOutside(const std::vector<Vec>& input) const
{
// clang-format off
std::vector<Base::Vector3d> output;
output.reserve(input.size());
Base::Matrix4D mat(getTransform());
std::transform(input.cbegin(), input.cend(), std::back_inserter(output), [&mat](const Vec& vec) {
return mat * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
});
std::transform(input.cbegin(), input.cend(), std::back_inserter(output),
[&mat](const Vec& vec) {
return mat * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
});
return output;
// clang-format on
}
inline Base::Vector3d transformVectorToOutside(const Base::Vector3f& vec) const
{
// clang-format off
Base::Matrix4D mat(getTransform());
mat.setCol(3, Base::Vector3d());
return mat * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
static_cast<double>(vec.y),
static_cast<double>(vec.z));
// clang-format on
}
template<typename Vec>
std::vector<Base::Vector3d> transformVectorsToOutside(const std::vector<Vec>& input) const
{
// clang-format off
std::vector<Base::Vector3d> output;
output.reserve(input.size());
Base::Matrix4D mat(getTransform());
mat.setCol(3, Base::Vector3d());
std::transform(input.cbegin(), input.cend(), std::back_inserter(output), [&mat](const Vec& vec) {
return mat * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
});
std::transform(input.cbegin(), input.cend(), std::back_inserter(output),
[&mat](const Vec& vec) {
return mat * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
});
return output;
// clang-format on
}
/// from local to inside
inline Base::Vector3f transformPointToInside(const Base::Vector3d& vec) const
@@ -438,23 +469,25 @@ protected:
static_cast<float>(tmp.y),
static_cast<float>(tmp.z));
}
public:
mutable long Tag{0};
mutable long Tag {0};
/// String hasher for element name shortening
mutable App::StringHasherRef Hasher;
protected:
void restoreStream(std::istream & stream, std::size_t count);
void restoreStream(std::istream& stream, std::size_t count);
void readElements(Base::XMLReader& reader, size_t count);
/// from local to outside
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
{
// clang-format off
return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
// clang-format on
}
/// from local to inside
inline Base::Vector3f transformToInside(const Base::Vector3d& vec) const
@@ -468,8 +501,8 @@ protected:
}
protected:
ElementMapPtr elementMap(bool flush=true) const;
ElementMapPtr ensureElementMap(bool flush=true);
ElementMapPtr elementMap(bool flush = true) const;
ElementMapPtr ensureElementMap(bool flush = true);
private:
ElementMapPtr _elementMap;
@@ -479,7 +512,7 @@ protected:
mutable bool _restoreFailed = false;
};
} //namespace App
} // namespace Data
ENABLE_BITMASK_OPERATORS(Data::SearchOption)
#endif
+74 -58
View File
@@ -23,7 +23,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <memory>
#include <memory>
#endif
#include "ComplexGeoData.h"
@@ -50,10 +50,11 @@ std::string ComplexGeoDataPy::representation() const
return {"<ComplexGeoData object>"};
}
PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
PyObject* ComplexGeoDataPy::getElementTypes(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
std::vector<const char*> types = getComplexGeoDataPtr()->getElementTypes();
Py::List list;
@@ -63,11 +64,12 @@ PyObject* ComplexGeoDataPy::getElementTypes(PyObject *args)
return Py::new_reference_to(list);
}
PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
PyObject* ComplexGeoDataPy::countSubElements(PyObject* args)
{
char *type;
if (!PyArg_ParseTuple(args, "s", &type))
char* type;
if (!PyArg_ParseTuple(args, "s", &type)) {
return nullptr;
}
try {
unsigned long count = getComplexGeoDataPtr()->countSubElements(type);
@@ -79,12 +81,13 @@ PyObject* ComplexGeoDataPy::countSubElements(PyObject *args)
}
}
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject* args)
{
char *type;
char* type;
unsigned long index;
if (!PyArg_ParseTuple(args, "sk", &type, &index))
if (!PyArg_ParseTuple(args, "sk", &type, &index)) {
return nullptr;
}
std::vector<Base::Vector3d> points;
std::vector<Base::Vector3d> normals;
@@ -100,27 +103,29 @@ PyObject* ComplexGeoDataPy::getFacesFromSubElement(PyObject *args)
Py::Tuple tuple(2);
Py::List vertex;
for (const auto & it : points)
for (const auto& it : points) {
vertex.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(0, vertex);
Py::List facet;
for (const auto & it : facets) {
for (const auto& it : facets) {
Py::Tuple f(3);
f.setItem(0,Py::Int(int(it.I1)));
f.setItem(1,Py::Int(int(it.I2)));
f.setItem(2,Py::Int(int(it.I3)));
f.setItem(0, Py::Int(int(it.I1)));
f.setItem(1, Py::Int(int(it.I2)));
f.setItem(2, Py::Int(int(it.I3)));
facet.append(f);
}
tuple.setItem(1, facet);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject* args)
{
char *type;
char* type;
int index;
if (!PyArg_ParseTuple(args, "si", &type, &index))
if (!PyArg_ParseTuple(args, "si", &type, &index)) {
return nullptr;
}
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
@@ -135,25 +140,27 @@ PyObject* ComplexGeoDataPy::getLinesFromSubElement(PyObject *args)
Py::Tuple tuple(2);
Py::List vertex;
for (const auto & it : points)
for (const auto& it : points) {
vertex.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(0, vertex);
Py::List line;
for (const auto & it : lines) {
for (const auto& it : lines) {
Py::Tuple l(2);
l.setItem(0,Py::Int((int)it.I1));
l.setItem(1,Py::Int((int)it.I2));
l.setItem(0, Py::Int((int)it.I1));
l.setItem(1, Py::Int((int)it.I2));
line.append(l);
}
tuple.setItem(1, line);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
PyObject* ComplexGeoDataPy::getPoints(PyObject* args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
return nullptr;
}
std::vector<Base::Vector3d> points;
std::vector<Base::Vector3d> normals;
@@ -167,24 +174,25 @@ PyObject* ComplexGeoDataPy::getPoints(PyObject *args)
Py::Tuple tuple(2);
Py::List vertex;
for (const auto & it : points) {
for (const auto& it : points) {
vertex.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(0, vertex);
Py::List normal;
for (const auto & it : normals) {
for (const auto& it : normals) {
normal.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(1, normal);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getLines(PyObject *args)
PyObject* ComplexGeoDataPy::getLines(PyObject* args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
return nullptr;
}
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Line> lines;
@@ -198,25 +206,27 @@ PyObject* ComplexGeoDataPy::getLines(PyObject *args)
Py::Tuple tuple(2);
Py::List vertex;
for (const auto & it : points)
for (const auto& it : points) {
vertex.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(0, vertex);
Py::List line;
for (const auto & it : lines) {
for (const auto& it : lines) {
Py::Tuple l(2);
l.setItem(0,Py::Int((int)it.I1));
l.setItem(1,Py::Int((int)it.I2));
l.setItem(0, Py::Int((int)it.I1));
l.setItem(1, Py::Int((int)it.I2));
line.append(l);
}
tuple.setItem(1, line);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
PyObject* ComplexGeoDataPy::getFaces(PyObject* args)
{
double accuracy = 0.05;
if (!PyArg_ParseTuple(args, "d", &accuracy))
if (!PyArg_ParseTuple(args, "d", &accuracy)) {
return nullptr;
}
std::vector<Base::Vector3d> points;
std::vector<Data::ComplexGeoData::Facet> facets;
@@ -230,26 +240,28 @@ PyObject* ComplexGeoDataPy::getFaces(PyObject *args)
Py::Tuple tuple(2);
Py::List vertex;
for (const auto & it : points)
for (const auto& it : points) {
vertex.append(Py::asObject(new Base::VectorPy(it)));
}
tuple.setItem(0, vertex);
Py::List facet;
for (const auto & it : facets) {
for (const auto& it : facets) {
Py::Tuple f(3);
f.setItem(0,Py::Int((int)it.I1));
f.setItem(1,Py::Int((int)it.I2));
f.setItem(2,Py::Int((int)it.I3));
f.setItem(0, Py::Int((int)it.I1));
f.setItem(1, Py::Int((int)it.I2));
f.setItem(2, Py::Int((int)it.I3));
facet.append(f);
}
tuple.setItem(1, facet);
return Py::new_reference_to(tuple);
}
PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
PyObject* ComplexGeoDataPy::applyTranslation(PyObject* args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type),&obj))
PyObject* obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::VectorPy::Type), &obj)) {
return nullptr;
}
try {
Base::Vector3d move = static_cast<Base::VectorPy*>(obj)->value();
@@ -262,11 +274,12 @@ PyObject* ComplexGeoDataPy::applyTranslation(PyObject *args)
}
}
PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
PyObject* ComplexGeoDataPy::applyRotation(PyObject* args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type),&obj))
PyObject* obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::RotationPy::Type), &obj)) {
return nullptr;
}
try {
Base::Rotation rot = static_cast<Base::RotationPy*>(obj)->value();
@@ -279,11 +292,12 @@ PyObject* ComplexGeoDataPy::applyRotation(PyObject *args)
}
}
PyObject* ComplexGeoDataPy::transformGeometry(PyObject *args)
PyObject* ComplexGeoDataPy::transformGeometry(PyObject* args)
{
PyObject *obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type),&obj))
PyObject* obj;
if (!PyArg_ParseTuple(args, "O!", &(Base::MatrixPy::Type), &obj)) {
return nullptr;
}
try {
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
@@ -377,17 +391,18 @@ PyObject* ComplexGeoDataPy::setElementName(PyObject* args, PyObject* kwds)
PyObject* pySid = Py_None;
PyObject* overwrite = Py_False;
const std::array<const char *,7> kwlist = {"element", "name", "postfix", "overwrite", "sid", "tag", nullptr};
const std::array<const char*, 7> kwlist =
{"element", "name", "postfix", "overwrite", "sid", "tag", nullptr};
if (!Wrapped_ParseTupleAndKeywords(args,
kwds,
"s|sssOOi",
kwlist,
&element,
&name,
&postfix,
&overwrite,
&pySid,
&tag)) {
kwds,
"s|sssOOi",
kwlist,
&element,
&name,
&postfix,
&overwrite,
&pySid,
&tag)) {
return NULL;
}
ElementIDRefs sids;
@@ -529,8 +544,9 @@ Py::Object ComplexGeoDataPy::getBoundBox() const
Py::Object ComplexGeoDataPy::getCenterOfGravity() const
{
Base::Vector3d center;
if (getComplexGeoDataPtr()->getCenterOfGravity(center))
if (getComplexGeoDataPtr()->getCenterOfGravity(center)) {
return Py::Vector(center);
}
throw Py::RuntimeError("Cannot get center of gravity");
}
+340
View File
@@ -0,0 +1,340 @@
/***************************************************************************
* Copyright (c) 2015 Stefan Tröger <[email protected]> *
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <[email protected]> *
* Copyright (c) 2024 Ondsel (PL Boyer) <[email protected]> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <string>
#endif
#include <App/Document.h>
#include <Base/Exception.h>
#include <Base/Placement.h>
#include "Datums.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace App;
PROPERTY_SOURCE(App::DatumElement, App::GeoFeature)
PROPERTY_SOURCE(App::Plane, App::DatumElement)
PROPERTY_SOURCE(App::Line, App::DatumElement)
PROPERTY_SOURCE(App::Point, App::DatumElement)
PROPERTY_SOURCE(App::LocalCoordinateSystem, App::GeoFeature)
DatumElement::DatumElement(bool hideRole)
{
ADD_PROPERTY_TYPE(Role,
(""),
0,
App::Prop_ReadOnly,
"Role of the datum in the local coordinate system.");
// The role is hidden by default. It is visible only when the datum is in a LCS
if (hideRole) {
Role.setStatus(Property::Hidden, true);
}
}
DatumElement::~DatumElement() = default;
bool DatumElement::getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const
{
Q_UNUSED(subname);
Placement.getValue().getRotation().multVec(Base::Vector3d(0., 0., 1.), direction);
return true;
}
App::LocalCoordinateSystem* DatumElement::getLCS()
{
auto inList = getInList();
for (auto* obj : inList) {
auto* lcs = dynamic_cast<App::LocalCoordinateSystem*>(obj);
if (lcs) {
return lcs;
}
}
return nullptr;
}
bool DatumElement::isOriginFeature()
{
auto lcs = getLCS();
return lcs ? lcs->isOrigin() : false;
}
// ----------------------------------------------------------------------------
LocalCoordinateSystem::LocalCoordinateSystem()
: extension(this)
{
ADD_PROPERTY_TYPE(OriginFeatures,
(nullptr),
0,
App::Prop_Hidden,
"Axis and baseplanes controlled by the LCS");
setStatus(App::NoAutoExpand, true);
extension.initExtension(this);
}
LocalCoordinateSystem::~LocalCoordinateSystem() = default;
bool LocalCoordinateSystem::getCameraAlignmentDirection(Base::Vector3d& direction,
const char* subname) const
{
Q_UNUSED(subname);
Placement.getValue().getRotation().multVec(Base::Vector3d(0., 0., 1.), direction);
return true;
}
App::DatumElement* LocalCoordinateSystem::getDatumElement(const char* role) const
{
const auto& features = OriginFeatures.getValues();
auto featIt = std::find_if(features.begin(), features.end(), [role](App::DocumentObject* obj) {
return obj->isDerivedFrom(App::DatumElement::getClassTypeId())
&& strcmp(static_cast<App::DatumElement*>(obj)->Role.getValue(), role) == 0;
});
if (featIt != features.end()) {
return static_cast<App::DatumElement*>(*featIt);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" doesn't contain feature with role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Line* LocalCoordinateSystem::getAxis(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Line::getClassTypeId())) {
return static_cast<App::Line*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Axis object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Plane* LocalCoordinateSystem::getPlane(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Plane::getClassTypeId())) {
return static_cast<App::Plane*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Plane object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
App::Point* LocalCoordinateSystem::getPoint(const char* role) const
{
App::DatumElement* feat = getDatumElement(role);
if (feat->isDerivedFrom(App::Point::getClassTypeId())) {
return static_cast<App::Point*>(feat);
}
std::stringstream err;
err << "LocalCoordinateSystem \"" << getFullName() << "\" contains bad Point object for role \""
<< role << '"';
throw Base::RuntimeError(err.str().c_str());
}
bool LocalCoordinateSystem::hasObject(const DocumentObject* obj) const
{
const auto& features = OriginFeatures.getValues();
return std::find(features.begin(), features.end(), obj) != features.end();
}
short LocalCoordinateSystem::mustExecute() const
{
if (OriginFeatures.isTouched()) {
return 1;
}
return DocumentObject::mustExecute();
}
App::DocumentObjectExecReturn* LocalCoordinateSystem::execute()
{
try { // try to find all base axis and planes in the origin
for (const char* role : AxisRoles) {
App::Line* axis = getAxis(role);
assert(axis);
(void)axis;
}
for (const char* role : PlaneRoles) {
App::Plane* plane = getPlane(role);
assert(plane);
(void)plane;
}
}
catch (const Base::Exception& ex) {
setError();
return new App::DocumentObjectExecReturn(ex.what());
}
return DocumentObject::execute();
}
const std::vector<LocalCoordinateSystem::SetupData>& LocalCoordinateSystem::getSetupData()
{
static const std::vector<SetupData> setupData = {
// clang-format off
{App::Line::getClassTypeId(), AxisRoles[0], tr("X-axis"), Base::Rotation()},
{App::Line::getClassTypeId(), AxisRoles[1], tr("Y-axis"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
{App::Line::getClassTypeId(), AxisRoles[2], tr("Z-axis"), Base::Rotation(Base::Vector3d(1,-1, 1), M_PI * 2 / 3)},
{App::Plane::getClassTypeId(), PlaneRoles[0], tr("XY-plane"), Base::Rotation()},
{App::Plane::getClassTypeId(), PlaneRoles[1], tr("XZ-plane"), Base::Rotation(1.0, 0.0, 0.0, 1.0)},
{App::Plane::getClassTypeId(), PlaneRoles[2], tr("YZ-plane"), Base::Rotation(Base::Vector3d(1, 1, 1), M_PI * 2 / 3)},
{App::Point::getClassTypeId(), PointRoles[0], tr("Origin"), Base::Rotation()}
// clang-format on
};
return setupData;
}
DatumElement* LocalCoordinateSystem::createDatum(SetupData& data)
{
App::Document* doc = getDocument();
std::string objName = doc->getUniqueObjectName(data.role);
App::DocumentObject* featureObj = doc->addObject(data.type.getName(), objName.c_str());
assert(featureObj && featureObj->isDerivedFrom(App::DatumElement::getClassTypeId()));
QByteArray byteArray = data.label.toUtf8();
featureObj->Label.setValue(byteArray.constData());
auto* feature = static_cast<App::DatumElement*>(featureObj);
feature->Placement.setValue(Base::Placement(Base::Vector3d(), data.rot));
feature->Role.setValue(data.role);
feature->Placement.setStatus(Property::Hidden, true);
return feature;
}
LocalCoordinateSystem::SetupData LocalCoordinateSystem::getData(const char* role)
{
const auto& setupData = getSetupData();
for (auto data : setupData) {
if (std::strcmp(role, data.role) == 0) {
return data;
}
}
return LocalCoordinateSystem::SetupData();
}
void LocalCoordinateSystem::setupObject()
{
std::vector<App::DocumentObject*> links;
const auto& setupData = getSetupData();
for (auto data : setupData) {
links.push_back(createDatum(data));
}
OriginFeatures.setValues(links);
}
void LocalCoordinateSystem::unsetupObject()
{
const auto& objsLnk = OriginFeatures.getValues();
// Copy to set to assert we won't call method more then one time for each object
std::set<App::DocumentObject*> objs(objsLnk.begin(), objsLnk.end());
// Remove all controlled objects
for (auto obj : objs) {
// Check that previous deletes didn't indirectly remove one of our objects
const auto& objsLnk = OriginFeatures.getValues();
if (std::find(objsLnk.begin(), objsLnk.end(), obj) != objsLnk.end()) {
if (!obj->isRemoving()) {
obj->getDocument()->removeObject(obj->getNameInDocument());
}
}
}
}
// ----------------------------------------------------------------------------
LocalCoordinateSystem::LCSExtension::LCSExtension(LocalCoordinateSystem* obj)
: obj(obj)
{
Group.setStatus(Property::Transient, true);
}
void LocalCoordinateSystem::LCSExtension::initExtension(ExtensionContainer* obj)
{
App::GroupExtension::initExtension(obj);
}
bool LocalCoordinateSystem::LCSExtension::extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject** pyobj,
Base::Matrix4D* mat,
bool,
int depth) const
{
if (!subname || subname[0] == '\0') {
return false;
}
// mapping of object name to role name
std::string name(subname);
for (int i = 0; i < 3; i++) {
if (name.rfind(LocalCoordinateSystem::AxisRoles[i], 0) == 0) {
name = LocalCoordinateSystem::AxisRoles[i];
break;
}
if (name.rfind(LocalCoordinateSystem::PlaneRoles[i], 0) == 0) {
name = LocalCoordinateSystem::PlaneRoles[i];
break;
}
}
if (name.rfind(LocalCoordinateSystem::PointRoles[0], 0) == 0) {
name = LocalCoordinateSystem::PointRoles[0];
}
try {
ret = obj->getDatumElement(name.c_str());
if (!ret) {
return false;
}
const char* dot = strchr(subname, '.');
if (dot) {
subname = dot + 1;
}
else {
subname = "";
}
ret = ret->getSubObject(subname, pyobj, mat, true, depth + 1);
return true;
}
catch (const Base::Exception& e) {
e.ReportException();
return false;
}
}
+252
View File
@@ -0,0 +1,252 @@
/***************************************************************************
* Copyright (c) 2015 Stefan Tröger <[email protected]> *
* Copyright (c) 2015 Alexander Golubev (Fat-Zer) <[email protected]> *
* Copyright (c) 2024 Ondsel (PL Boyer) <[email protected]> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef DATUMS_H
#define DATUMS_H
#include "GeoFeature.h"
#include "GeoFeatureGroupExtension.h"
#include "QCoreApplication"
namespace Base
{
class Rotation;
}
namespace App
{
class LocalCoordinateSystem;
class AppExport DatumElement: public App::GeoFeature
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
/// additional information about the feature usage (e.g. "BasePlane-XY" or "Axis-X")
PropertyString Role;
/// Constructor
DatumElement(bool hideRole = true);
~DatumElement() override;
/// Finds the origin object this plane belongs to
App::LocalCoordinateSystem* getLCS();
bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override;
/// Returns true if this DatumElement is part of a App::Origin.
bool isOriginFeature();
};
class AppExport Plane: public App::DatumElement
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
const char* getViewProviderName() const override
{
return "Gui::ViewProviderPlane";
}
};
class AppExport Line: public App::DatumElement
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
const char* getViewProviderName() const override
{
return "Gui::ViewProviderLine";
}
};
class AppExport Point: public App::DatumElement
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DatumElement);
public:
const char* getViewProviderName() const override
{
return "Gui::ViewProviderPoint";
}
};
class AppExport LocalCoordinateSystem: public App::GeoFeature
{
PROPERTY_HEADER_WITH_OVERRIDE(App::LocalCoordinateSystem);
Q_DECLARE_TR_FUNCTIONS(App::LocalCoordinateSystem)
public:
/// Constructor
LocalCoordinateSystem();
~LocalCoordinateSystem() override;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override
{
return "Gui::ViewProviderCoordinateSystem";
}
bool getCameraAlignmentDirection(Base::Vector3d& direction, const char* subname) const override;
/** @name Axis and plane access
* This functions returns casted axis and planes objects and asserts they are set correctly
* otherwise Base::Exception is thrown.
*/
///@{
// returns origin point
App::Point* getOrigin() const
{
return getPoint(PointRoles[0]);
}
// returns X axis
App::Line* getX() const
{
return getAxis(AxisRoles[0]);
}
// returns Y axis
App::Line* getY() const
{
return getAxis(AxisRoles[1]);
}
// returns Z axis
App::Line* getZ() const
{
return getAxis(AxisRoles[2]);
}
// returns XY plane
App::Plane* getXY() const
{
return getPlane(PlaneRoles[0]);
}
// returns XZ plane
App::Plane* getXZ() const
{
return getPlane(PlaneRoles[1]);
}
// returns YZ plane
App::Plane* getYZ() const
{
return getPlane(PlaneRoles[2]);
}
/// Returns all axis objects to iterate on them
std::vector<App::Line*> axes() const
{
return {getX(), getY(), getZ()};
}
/// Returns all base planes objects to iterate on them
std::vector<App::Plane*> planes() const
{
return {getXY(), getXZ(), getYZ()};
}
/// Returns all controlled objects (both planes and axis) to iterate on them
std::vector<App::DatumElement*> baseObjects() const
{
return {getX(), getY(), getZ(), getXY(), getXZ(), getYZ(), getOrigin()};
}
/// Returns an axis by it's name
App::DatumElement* getDatumElement(const char* role) const;
/// Returns an axis by it's name
App::Line* getAxis(const char* role) const;
/// Returns an axis by it's name
App::Plane* getPlane(const char* role) const;
/// Returns a point by it's name
App::Point* getPoint(const char* role) const;
///@}
/// Returns true if the given object is part of the origin
bool hasObject(const DocumentObject* obj) const;
/// Returns true on changing DatumElement set
short mustExecute() const override;
/// Axis types
static constexpr const char* AxisRoles[3] = {"X_Axis", "Y_Axis", "Z_Axis"};
/// Baseplane types
static constexpr const char* PlaneRoles[3] = {"XY_Plane", "XZ_Plane", "YZ_Plane"};
/// Points types
static constexpr const char* PointRoles[1] = {"Origin"};
virtual bool isOrigin()
{
return false;
};
// Axis links
PropertyLinkList OriginFeatures;
protected:
/// Checks integrity of the LCS
App::DocumentObjectExecReturn* execute() override;
/// Creates all corresponding Axes and Planes objects for the LCS if they aren't linked yet
void setupObject() override;
/// Removes all planes and axis if they are still linked to the document
void unsetupObject() override;
private:
struct SetupData;
void setupDatumElement(App::PropertyLink& featProp, const SetupData& data);
class LCSExtension: public GeoFeatureGroupExtension
{
LocalCoordinateSystem* obj;
public:
explicit LCSExtension(LocalCoordinateSystem* obj);
void initExtension(ExtensionContainer* obj) override;
bool extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject**,
Base::Matrix4D*,
bool,
int) const override;
};
LCSExtension extension;
struct SetupData
{
Base::Type type;
const char* role = nullptr;
QString label;
Base::Rotation rot;
};
static const std::vector<SetupData>& getSetupData();
DatumElement* createDatum(SetupData& data);
SetupData getData(const char* role);
};
} // namespace App
#endif /* end of include guard: DATUMS_H */
+1307 -895
View File
File diff suppressed because it is too large Load Diff
+183 -150
View File
@@ -37,33 +37,32 @@
#include <vector>
#include <QString>
namespace Base {
class Writer;
}
namespace App
namespace Base
{
class TransactionalObject;
class DocumentObject;
class DocumentObjectExecReturn;
class Document;
class DocumentPy; // the python document class
class Application;
class Transaction;
class StringHasher;
using StringHasherRef = Base::Reference<StringHasher>;
class Writer;
}
namespace App
{
class TransactionalObject;
class DocumentObject;
class DocumentObjectExecReturn;
class Document;
class DocumentPy;
class Application;
class Transaction;
class StringHasher;
using StringHasherRef = Base::Reference<StringHasher>;
/// The document class
class AppExport Document : public App::PropertyContainer
class AppExport Document: public App::PropertyContainer
{
PROPERTY_HEADER_WITH_OVERRIDE(App::Document);
public:
enum Status {
// clang-format off
enum Status
{
SkipRecompute = 0,
KeepTrailingDigits = 1,
Closable = 2,
@@ -72,13 +71,16 @@ public:
PartialRestore = 5,
Importing = 6,
PartialDoc = 7,
AllowPartialRecompute = 8, // allow recomputing editing object if SkipRecompute is set
TempDoc = 9, // Mark as temporary document without prompt for save
AllowPartialRecompute = 8, // allow recomputing editing object if SkipRecompute is set
TempDoc = 9, // Mark as temporary document without prompt for save
RestoreError = 10,
LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed
IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed
LinkStampChanged = 11, // Indicates during restore time if any linked document's time stamp has changed
IgnoreErrorOnRecompute = 12, // Don't report errors if the recompute failed
RecomputeOnRestore = 13, // Mark pending recompute on restore for migration purposes
};
// clang-format on
// NOLINTBEGIN
/** @name Properties */
//@{
/// holds the long name of the document (utf-8 coded)
@@ -123,67 +125,66 @@ public:
/** @name Signals of the document */
//@{
// clang-format off
/// signal before changing an doc property
boost::signals2::signal<void (const App::Document&, const App::Property&)> signalBeforeChange;
boost::signals2::signal<void(const App::Document&, const App::Property&)> signalBeforeChange;
/// signal on changed doc property
boost::signals2::signal<void (const App::Document&, const App::Property&)> signalChanged;
boost::signals2::signal<void(const App::Document&, const App::Property&)> signalChanged;
/// signal on new Object
boost::signals2::signal<void (const App::DocumentObject&)> signalNewObject;
//boost::signals2::signal<void (const App::DocumentObject&)> m_sig;
boost::signals2::signal<void(const App::DocumentObject&)> signalNewObject;
/// signal on deleted Object
boost::signals2::signal<void (const App::DocumentObject&)> signalDeletedObject;
boost::signals2::signal<void(const App::DocumentObject&)> signalDeletedObject;
/// signal before changing an Object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChangeObject;
boost::signals2::signal<void(const App::DocumentObject&, const App::Property&)> signalBeforeChangeObject;
/// signal on changed Object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChangedObject;
boost::signals2::signal<void(const App::DocumentObject&, const App::Property&)> signalChangedObject;
/// signal on manually called DocumentObject::touch()
boost::signals2::signal<void (const App::DocumentObject&)> signalTouchedObject;
boost::signals2::signal<void(const App::DocumentObject&)> signalTouchedObject;
/// signal on relabeled Object
boost::signals2::signal<void (const App::DocumentObject&)> signalRelabelObject;
boost::signals2::signal<void(const App::DocumentObject&)> signalRelabelObject;
/// signal on activated Object
boost::signals2::signal<void (const App::DocumentObject&)> signalActivatedObject;
boost::signals2::signal<void(const App::DocumentObject&)> signalActivatedObject;
/// signal on created object
boost::signals2::signal<void (const App::DocumentObject&, Transaction*)> signalTransactionAppend;
boost::signals2::signal<void(const App::DocumentObject&, Transaction*)> signalTransactionAppend;
/// signal on removed object
boost::signals2::signal<void (const App::DocumentObject&, Transaction*)> signalTransactionRemove;
boost::signals2::signal<void(const App::DocumentObject&, Transaction*)> signalTransactionRemove;
/// signal on undo
boost::signals2::signal<void (const App::Document&)> signalUndo;
boost::signals2::signal<void(const App::Document&)> signalUndo;
/// signal on redo
boost::signals2::signal<void (const App::Document&)> signalRedo;
boost::signals2::signal<void(const App::Document&)> signalRedo;
/** signal on load/save document
* this signal is given when the document gets streamed.
* you can use this hook to write additional information in
* the file (like the Gui::Document does).
*/
boost::signals2::signal<void (Base::Writer &)> signalSaveDocument;
boost::signals2::signal<void (Base::XMLReader&)> signalRestoreDocument;
boost::signals2::signal<void (const std::vector<App::DocumentObject*>&,
Base::Writer &)> signalExportObjects;
boost::signals2::signal<void (const std::vector<App::DocumentObject*>&,
Base::Writer &)> signalExportViewObjects;
boost::signals2::signal<void (const std::vector<App::DocumentObject*>&,
Base::XMLReader&)> signalImportObjects;
boost::signals2::signal<void (const std::vector<App::DocumentObject*>&, Base::Reader&,
const std::map<std::string, std::string>&)> signalImportViewObjects;
boost::signals2::signal<void (const std::vector<App::DocumentObject*>&)> signalFinishImportObjects;
//signal starting a save action to a file
boost::signals2::signal<void (const App::Document&, const std::string&)> signalStartSave;
//signal finishing a save action to a file
boost::signals2::signal<void (const App::Document&, const std::string&)> signalFinishSave;
boost::signals2::signal<void (const App::Document&)> signalBeforeRecompute;
boost::signals2::signal<void (const App::Document&, const std::vector<App::DocumentObject*>&)> signalRecomputed;
boost::signals2::signal<void (const App::DocumentObject&)> signalRecomputedObject;
//signal a new opened transaction
boost::signals2::signal<void (const App::Document&, std::string)> signalOpenTransaction;
boost::signals2::signal<void(Base::Writer&)> signalSaveDocument;
boost::signals2::signal<void(Base::XMLReader&)> signalRestoreDocument;
boost::signals2::signal<void(const std::vector<App::DocumentObject*>&, Base::Writer&)> signalExportObjects;
boost::signals2::signal<void(const std::vector<App::DocumentObject*>&, Base::Writer&)> signalExportViewObjects;
boost::signals2::signal<void(const std::vector<App::DocumentObject*>&, Base::XMLReader&)> signalImportObjects;
boost::signals2::signal<void(const std::vector<App::DocumentObject*>&, Base::Reader&,
const std::map<std::string, std::string>&)> signalImportViewObjects;
boost::signals2::signal<void(const std::vector<App::DocumentObject*>&)> signalFinishImportObjects;
// signal starting a save action to a file
boost::signals2::signal<void(const App::Document&, const std::string&)> signalStartSave;
// signal finishing a save action to a file
boost::signals2::signal<void(const App::Document&, const std::string&)> signalFinishSave;
boost::signals2::signal<void(const App::Document&)> signalBeforeRecompute;
boost::signals2::signal<void(const App::Document&, const std::vector<App::DocumentObject*>&)> signalRecomputed;
boost::signals2::signal<void(const App::DocumentObject&)> signalRecomputedObject;
// signal a new opened transaction
boost::signals2::signal<void(const App::Document&, std::string)> signalOpenTransaction;
// signal a committed transaction
boost::signals2::signal<void (const App::Document&)> signalCommitTransaction;
boost::signals2::signal<void(const App::Document&)> signalCommitTransaction;
// signal an aborted transaction
boost::signals2::signal<void (const App::Document&)> signalAbortTransaction;
boost::signals2::signal<void (const App::Document&, const std::vector<App::DocumentObject*>&)> signalSkipRecompute;
boost::signals2::signal<void (const App::DocumentObject&)> signalFinishRestoreObject;
boost::signals2::signal<void (const App::Document&,const App::Property&)> signalChangePropertyEditor;
boost::signals2::signal<void(const App::Document&)> signalAbortTransaction;
boost::signals2::signal<void(const App::Document&, const std::vector<App::DocumentObject*>&)> signalSkipRecompute;
boost::signals2::signal<void(const App::DocumentObject&)> signalFinishRestoreObject;
boost::signals2::signal<void(const App::Document&, const App::Property&)> signalChangePropertyEditor;
boost::signals2::signal<void(std::string)> signalLinkXsetValue;
// clang-format on
//@}
boost::signals2::signal<void (std::string)> signalLinkXsetValue;
// NOLINTEND
void clearDocument();
@@ -191,21 +192,23 @@ public:
/** @name File handling of the document */
//@{
/// Save the Document under a new Name
//void saveAs (const char* Name);
// void saveAs (const char* Name);
/// Save the document to the file in Property Path
bool save ();
bool save();
bool saveAs(const char* file);
bool saveCopy(const char* file) const;
/// Restore the document from the file in Property Path
void restore (const char *filename=nullptr,
bool delaySignal=false, const std::vector<std::string> &objNames={});
bool afterRestore(bool checkPartial=false);
bool afterRestore(const std::vector<App::DocumentObject *> &, bool checkPartial=false);
enum ExportStatus {
void restore(const char* filename = nullptr,
bool delaySignal = false,
const std::vector<std::string>& objNames = {});
bool afterRestore(bool checkPartial = false);
bool afterRestore(const std::vector<App::DocumentObject*>&, bool checkPartial = false);
enum ExportStatus
{
NotExporting,
Exporting,
};
ExportStatus isExporting(const App::DocumentObject *obj) const;
ExportStatus isExporting(const App::DocumentObject* obj) const;
void exportObjects(const std::vector<App::DocumentObject*>&, std::ostream&);
void exportGraphviz(std::ostream&) const;
std::vector<App::DocumentObject*> importObjects(Base::XMLReader& reader);
@@ -221,10 +224,10 @@ public:
*
* @return the list of imported objects
*/
std::vector<App::DocumentObject*> importLinks(
const std::vector<App::DocumentObject*> &objs = {});
std::vector<App::DocumentObject*>
importLinks(const std::vector<App::DocumentObject*>& objs = {});
/// Opens the document from its file name
//void open (void);
// void open (void);
/// Is the document already saved to a file?
bool isSaved() const;
/// Get the document name
@@ -240,31 +243,39 @@ public:
const char* getFileName() const;
//@}
void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
void Save(Base::Writer& writer) const override;
void Restore(Base::XMLReader& reader) override;
/// returns the complete document memory consumption, including all managed DocObjects and Undo Redo.
unsigned int getMemSize () const override;
/// returns the complete document memory consumption, including all managed DocObjects and Undo
/// Redo.
unsigned int getMemSize() const override;
/** @name Object handling */
//@{
/** Add a feature of sType with sName (ASCII) to this document and set it active.
* Unicode names are set through the Label property.
* @param sType the type of created object
* @param pObjectName if nonNULL use that name otherwise generate a new unique name based on the \a sType
* @param isNew if false don't call the \c DocumentObject::setupObject() callback (default is true)
* @param pObjectName if nonNULL use that name otherwise generate a new unique name based on the
* \a sType
* @param isNew if false don't call the \c DocumentObject::setupObject() callback (default
* is true)
* @param viewType override object's view provider name
* @param isPartial indicate if this object is meant to be partially loaded
*/
DocumentObject *addObject(const char* sType, const char* pObjectName=nullptr,
bool isNew=true, const char *viewType=nullptr, bool isPartial=false);
DocumentObject* addObject(const char* sType,
const char* pObjectName = nullptr,
bool isNew = true,
const char* viewType = nullptr,
bool isPartial = false);
/** Add an array of features of the given types and names.
* Unicode names are set through the Label property.
* @param sType The type of created object
* @param objectNames A list of object names
* @param isNew If false don't call the \c DocumentObject::setupObject() callback (default is true)
* @param isNew If false don't call the \c DocumentObject::setupObject() callback (default
* is true)
*/
std::vector<DocumentObject *>addObjects(const char* sType, const std::vector<std::string>& objectNames, bool isNew=true);
std::vector<DocumentObject*>
addObjects(const char* sType, const std::vector<std::string>& objectNames, bool isNew = true);
/// Remove a feature out of the document
void removeObject(const char* sName);
/** Add an existing feature with sName (ASCII) to this document and set it active.
@@ -274,7 +285,7 @@ public:
* \note The passed feature must not yet be added to a document, otherwise an exception
* is raised.
*/
void addObject(DocumentObject*, const char* pObjectName=nullptr);
void addObject(DocumentObject*, const char* pObjectName = nullptr);
/** Copy objects from another document to this document
@@ -288,40 +299,44 @@ public:
*
* @return Returns the list of objects copied.
*/
std::vector<DocumentObject*> copyObject(
const std::vector<DocumentObject*> &objs,
bool recursive=false, bool returnAll=false);
std::vector<DocumentObject*> copyObject(const std::vector<DocumentObject*>& objs,
bool recursive = false,
bool returnAll = false);
/** Move an object from another document to this document
* If \a recursive is true then all objects this object depends on
* are moved as well. By default \a recursive is false.
* Returns the moved object itself or 0 if the object is already part of this
* document..
*/
DocumentObject* moveObject(DocumentObject* obj, bool recursive=false);
DocumentObject* moveObject(DocumentObject* obj, bool recursive = false);
/// Returns the active Object of this document
DocumentObject *getActiveObject() const;
DocumentObject* getActiveObject() const;
/// Returns a Object of this document
DocumentObject *getObject(const char *Name) const;
DocumentObject* getObject(const char* Name) const;
/// Returns a Object of this document by its id
DocumentObject *getObjectByID(long id) const;
DocumentObject* getObjectByID(long id) const;
/// Returns true if the DocumentObject is contained in this document
bool isIn(const DocumentObject *pFeat) const;
bool isIn(const DocumentObject* pFeat) const;
/// Returns a Name of an Object or 0
const char *getObjectName(DocumentObject *pFeat) const;
const char* getObjectName(DocumentObject* pFeat) const;
/// Returns a Name of an Object or 0
std::string getUniqueObjectName(const char *Name) const;
std::string getUniqueObjectName(const char* Name) const;
/// Returns a name of the form prefix_number. d specifies the number of digits.
std::string getStandardObjectName(const char *Name, int d) const;
std::string getStandardObjectName(const char* Name, int d) const;
/// Returns a list of document's objects including the dependencies
std::vector<DocumentObject*> getDependingObjects() const;
/// Returns a list of all Objects
const std::vector<DocumentObject*> &getObjects() const;
const std::vector<DocumentObject*>& getObjects() const;
std::vector<DocumentObject*> getObjectsOfType(const Base::Type& typeId) const;
/// Returns all object with given extensions. If derived=true also all objects with extensions derived from the given one
std::vector<DocumentObject*> getObjectsWithExtension(const Base::Type& typeId, bool derived = true) const;
std::vector<DocumentObject*> findObjects(const Base::Type& typeId, const char* objname, const char* label) const;
/// Returns all object with given extensions. If derived=true also all objects with extensions
/// derived from the given one
std::vector<DocumentObject*> getObjectsWithExtension(const Base::Type& typeId,
bool derived = true) const;
std::vector<DocumentObject*>
findObjects(const Base::Type& typeId, const char* objname, const char* label) const;
/// Returns an array with the correct types already.
template<typename T> inline std::vector<T*> getObjectsOfType() const;
template<typename T>
inline std::vector<T*> getObjectsOfType() const;
int countObjectsOfType(const Base::Type& typeId) const;
/// get the number of objects in the document
int countObjects() const;
@@ -337,7 +352,7 @@ public:
/// check if there is any object must execute in this document
bool mustExecute() const;
/// returns all touched objects
std::vector<App::DocumentObject *> getTouched() const;
std::vector<App::DocumentObject*> getTouched() const;
/// set the document to be closable, this is on by default.
void setClosable(bool);
/// check whether the document can be closed
@@ -347,10 +362,12 @@ public:
* @param objs: specify a sub set of objects to recompute. If empty, then
* all object in this document is checked for recompute
*/
int recompute(const std::vector<App::DocumentObject*> &objs={},
bool force=false,bool *hasError=nullptr, int options=0);
int recompute(const std::vector<App::DocumentObject*>& objs = {},
bool force = false,
bool* hasError = nullptr,
int options = 0);
/// Recompute only one feature
bool recomputeFeature(DocumentObject* Feat,bool recursive=false);
bool recomputeFeature(DocumentObject* Feat, bool recursive = false);
/// get the text of the error of a specified object
const char* getErrorDescription(const App::DocumentObject*) const;
/// return the status bits
@@ -391,9 +408,9 @@ public:
* to setup a potential transaction which will only be created if there is
* actual changes.
*/
void openTransaction(const char* name=nullptr);
void openTransaction(const char* name = nullptr);
/// Rename the current transaction if the id matches
void renameTransaction(const char *name, int id);
void renameTransaction(const char* name, int id);
/// Commit the Command transaction. Do nothing If there is no Command transaction open.
void commitTransaction();
/// Abort the actually running transaction.
@@ -401,49 +418,51 @@ public:
/// Check if a transaction is open
bool hasPendingTransaction() const;
/// Return the undo/redo transaction ID starting from the back
int getTransactionID(bool undo, unsigned pos=0) const;
int getTransactionID(bool undo, unsigned pos = 0) const;
/// Check if a transaction is open and its list is empty.
/// If no transaction is open true is returned.
bool isTransactionEmpty() const;
/// Set the Undo limit in Byte!
void setUndoLimit(unsigned int UndoMemSize=0);
void setUndoLimit(unsigned int UndoMemSize = 0);
/// Returns the actual memory consumption of the Undo redo stuff.
unsigned int getUndoMemSize () const;
unsigned int getUndoMemSize() const;
/// Set the Undo limit as stack size
void setMaxUndoStackSize(unsigned int UndoMaxStackSize=20);
void setMaxUndoStackSize(unsigned int UndoMaxStackSize = 20); // NOLINT
/// Set the Undo limit as stack size
unsigned int getMaxUndoStackSize()const;
unsigned int getMaxUndoStackSize() const;
/// Remove all stored Undos and Redos
void clearUndos();
/// Returns the number of stored Undos. If greater than 0 Undo will be effective.
int getAvailableUndos(int id=0) const;
int getAvailableUndos(int id = 0) const;
/// Returns a list of the Undo names
std::vector<std::string> getAvailableUndoNames() const;
/// Will UNDO one step, returns False if no undo was done (Undos == 0).
bool undo(int id=0);
bool undo(int id = 0);
/// Returns the number of stored Redos. If greater than 0 Redo will be effective.
int getAvailableRedos(int id=0) const;
int getAvailableRedos(int id = 0) const;
/// Returns a list of the Redo names.
std::vector<std::string> getAvailableRedoNames() const;
/// Will REDO one step, returns False if no redo was done (Redos == 0).
bool redo(int id=0) ;
/// returns true if the document is in an Transaction phase, e.g. currently performing a redo/undo or rollback
bool redo(int id = 0);
/// returns true if the document is in an Transaction phase, e.g. currently performing a
/// redo/undo or rollback
bool isPerformingTransaction() const;
/// \internal add or remove property from a transactional object
void addOrRemovePropertyOfObject(TransactionalObject*, Property *prop, bool add);
void addOrRemovePropertyOfObject(TransactionalObject*, Property* prop, bool add);
//@}
/** @name dependency stuff */
//@{
/// write GraphViz file
void writeDependencyGraphViz(std::ostream &out);
void writeDependencyGraphViz(std::ostream& out);
/// checks if the graph is directed and has no cycles
bool checkOnCycle();
/// get a list of all objects linking to the given object
std::vector<App::DocumentObject*> getInList(const DocumentObject* me) const;
/// Option bit flags used by getDepenencyList()
enum DependencyOption {
enum DependencyOption
{
/// Return topological sorted list
DepSort = 1,
/// Do no include object linked by PropertyXLink, as it can handle external link
@@ -460,14 +479,15 @@ public:
* @param objs: input objects to query for dependency.
* @param options: See DependencyOption
*/
static std::vector<App::DocumentObject*> getDependencyList(
const std::vector<App::DocumentObject*> &objs, int options=0);
static std::vector<App::DocumentObject*>
getDependencyList(const std::vector<App::DocumentObject*>& objs, int options = 0);
std::vector<App::Document*> getDependentDocuments(bool sort=true);
static std::vector<App::Document*> getDependentDocuments(std::vector<App::Document*> docs, bool sort);
std::vector<App::Document*> getDependentDocuments(bool sort = true);
static std::vector<App::Document*> getDependentDocuments(std::vector<App::Document*> docs,
bool sort);
// set Changed
//void setChanged(DocumentObject* change);
// void setChanged(DocumentObject* change);
/// get a list of topological sorted objects (https://en.wikipedia.org/wiki/Topological_sorting)
std::vector<App::DocumentObject*> topologicalSort() const;
/// get all root objects (objects no other one reference too)
@@ -475,8 +495,8 @@ public:
/// get all tree root objects (objects that are at the root of the object tree)
std::vector<App::DocumentObject*> getRootObjectsIgnoreLinks() const;
/// get all possible paths from one object to another following the OutList
std::vector<std::list<App::DocumentObject*> > getPathsByOutList
(const App::DocumentObject* from, const App::DocumentObject* to) const;
std::vector<std::list<App::DocumentObject*>>
getPathsByOutList(const App::DocumentObject* from, const App::DocumentObject* to) const;
//@}
/** Called by a property during save to store its StringHasher
@@ -492,7 +512,7 @@ public:
* of the hasher. If the hasher has not been added before, the object must
* save the hasher by calling StringHasher::Save
*/
std::pair<bool,int> addStringHasher(const StringHasherRef & hasher) const;
std::pair<bool, int> addStringHasher(const StringHasherRef& hasher) const;
/** Called by property to restore its StringHasher
*
@@ -504,7 +524,7 @@ public:
* The caller is responsible for restoring the hasher if the caller is the first
* owner of the hasher, i.e. if addStringHasher() returns true during save.
*/
StringHasherRef getStringHasher(int index=-1) const;
StringHasherRef getStringHasher(int index = -1) const;
/** Return the links to a given object
*
@@ -515,22 +535,32 @@ public:
* @param objs: optional objects to search for, if empty, then all objects
* of this document are searched.
*/
void getLinksTo(std::set<DocumentObject*> &links,
const DocumentObject *obj, int options, int maxCount=0,
const std::vector<DocumentObject*> &objs = {}) const;
void getLinksTo(std::set<DocumentObject*>& links,
const DocumentObject* obj,
int options,
int maxCount = 0,
const std::vector<DocumentObject*>& objs = {}) const;
/// Check if there is any link to the given object
bool hasLinksTo(const DocumentObject *obj) const;
bool hasLinksTo(const DocumentObject* obj) const;
/// Called by objects during restore to ask for recompute
void addRecomputeObject(DocumentObject *obj);
void addRecomputeObject(DocumentObject* obj);
const std::string &getOldLabel() const {return oldLabel;}
const std::string& getOldLabel() const
{
return oldLabel;
}
/// Function called to signal that an object identifier has been renamed
void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths, const std::function<bool(const App::DocumentObject*)> &selector = [](const App::DocumentObject *) { return true; });
void renameObjectIdentifiers(
const std::map<App::ObjectIdentifier, App::ObjectIdentifier>& paths,
const std::function<bool(const App::DocumentObject*)>& selector =
[](const App::DocumentObject*) {
return true;
});
PyObject *getPyObject() override;
PyObject* getPyObject() override;
std::string getFullName() const override;
@@ -549,23 +579,23 @@ public:
protected:
/// Construction
explicit Document(const char *documentName = "");
explicit Document(const char* documentName = "");
void _removeObject(DocumentObject* pcObject);
void _addObject(DocumentObject* pcObject, const char* pObjectName);
/// checks if a valid transaction is open
void _checkTransaction(DocumentObject* pcDelObj, const Property *What, int line);
void _checkTransaction(DocumentObject* pcDelObj, const Property* What, int line);
void breakDependency(DocumentObject* pcObject, bool clear);
std::vector<App::DocumentObject*> readObjects(Base::XMLReader& reader);
void writeObjects(const std::vector<App::DocumentObject*>&, Base::Writer &writer) const;
void writeObjects(const std::vector<App::DocumentObject*>&, Base::Writer& writer) const;
bool saveToFile(const char* filename) const;
void onBeforeChange(const Property* prop) override;
void onChanged(const Property* prop) override;
/// callback from the Document objects before property will be changed
void onBeforeChangeProperty(const TransactionalObject *Who, const Property *What);
void onBeforeChangeProperty(const TransactionalObject* Who, const Property* What);
/// callback from the Document objects after property was changed
void onChangedProperty(const DocumentObject *Who, const Property *What);
void onChangedProperty(const DocumentObject* Who, const Property* What);
/// helper which Recompute only this feature
/// @return 0 if succeeded, 1 if failed, -1 if aborted by user.
int _recomputeFeature(DocumentObject* Feat);
@@ -573,9 +603,10 @@ protected:
/// refresh the internal dependency graph
void _rebuildDependencyList(
const std::vector<App::DocumentObject*> &objs = std::vector<App::DocumentObject*>());
const std::vector<App::DocumentObject*>& objs = std::vector<App::DocumentObject*>());
std::string getTransientDirectoryName(const std::string& uuid, const std::string& filename) const;
std::string getTransientDirectoryName(const std::string& uuid,
const std::string& filename) const;
/** Open a new command Undo/Redo, an UTF-8 name can be specified
*
@@ -587,18 +618,19 @@ protected:
* This function creates an actual transaction regardless of Application
* AutoTransaction setting.
*/
int _openTransaction(const char* name=nullptr, int id=0);
int _openTransaction(const char* name = nullptr, int id = 0);
/// Internally called by App::Application to commit the Command transaction.
void _commitTransaction(bool notify=false);
void _commitTransaction(bool notify = false);
/// Internally called by App::Application to abort the running transaction.
void _abortTransaction();
private:
// # Data Member of the document +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// # Data Member of the document
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
std::list<Transaction*> mUndoTransactions;
std::map<int,Transaction*> mUndoMap;
std::map<int, Transaction*> mUndoMap;
std::list<Transaction*> mRedoTransactions;
std::map<int,Transaction*> mRedoMap;
std::map<int, Transaction*> mRedoMap;
struct DocumentP* d;
@@ -612,12 +644,13 @@ inline std::vector<T*> Document::getObjectsOfType() const
std::vector<T*> type;
std::vector<App::DocumentObject*> obj = this->getObjectsOfType(T::getClassTypeId());
type.reserve(obj.size());
for (std::vector<App::DocumentObject*>::iterator it = obj.begin(); it != obj.end(); ++it)
type.push_back(static_cast<T*>(*it));
for (auto it : obj) {
type.push_back(static_cast<T*>(it));
}
return type;
}
} //namespace App
} // namespace App
#endif // APP_DOCUMENT_H
#endif // APP_DOCUMENT_H
+476 -344
View File
File diff suppressed because it is too large Load Diff
+216 -124
View File
@@ -46,44 +46,49 @@ class DocumentObjectGroup;
class DocumentObjectPy;
class Expression;
enum ObjectStatus {
// clang-format off
enum ObjectStatus
{
Touch = 0,
Error = 1,
New = 2,
Recompute = 3, // set when the object is currently being recomputed
Recompute = 3, // set when the object is currently being recomputed
Restore = 4,
Remove = 5,
PythonCall = 6,
Destroy = 7,
Enforce = 8,
Recompute2 = 9, // set when the object is being recomputed in the second pass
Recompute2 = 9, // set when the object is being recomputed in the second pass
PartialObject = 10,
PendingRecompute = 11, // set by Document, indicating the object is in recomputation queue
ObjImporting = 13, // Mark the object as importing
NoTouch = 14, // no touch on any property change
GeoExcluded = 15, // mark as a member but not claimed by GeoFeatureGroup
Expand = 16, // indicate the object's tree item expansion status
NoAutoExpand = 17, // disable tree item auto expand on selection for this object
PendingTransactionUpdate = 18, // mark that the object expects a call to onUndoRedoFinished() after transaction is finished.
RecomputeExtension = 19, // mark the object to recompute its extensions
TouchOnColorChange = 20, // inform view provider touch object on color change
Freeze = 21, // do not recompute ever
PendingRecompute = 11, // set by Document, indicating the object is in recomputation queue
ObjImporting = 13, // Mark the object as importing
NoTouch = 14, // no touch on any property change
GeoExcluded = 15, // mark as a member but not claimed by GeoFeatureGroup
Expand = 16, // indicate the object's tree item expansion status
NoAutoExpand = 17, // disable tree item auto expand on selection for this object
PendingTransactionUpdate = 18, // mark that the object expects a call to onUndoRedoFinished() after transaction is finished.
RecomputeExtension = 19, // mark the object to recompute its extensions
TouchOnColorChange = 20, // inform view provider touch object on color change
Freeze = 21, // do not recompute ever
};
// clang-format on
/** Return object for feature execution
*/
*/
class AppExport DocumentObjectExecReturn
{
public:
explicit DocumentObjectExecReturn(const std::string& sWhy, DocumentObject* WhichObject=nullptr)
: Why(sWhy), Which(WhichObject)
{
}
explicit DocumentObjectExecReturn(const char* sWhy, DocumentObject* WhichObject=nullptr)
explicit DocumentObjectExecReturn(const std::string& sWhy,
DocumentObject* WhichObject = nullptr)
: Why(sWhy)
, Which(WhichObject)
{}
explicit DocumentObjectExecReturn(const char* sWhy, DocumentObject* WhichObject = nullptr)
: Which(WhichObject)
{
if (sWhy)
if (sWhy) {
Why = sWhy;
}
}
std::string Why;
@@ -91,7 +96,6 @@ public:
};
/** Base class of all Classes handled in the Document
*/
class AppExport DocumentObject: public App::TransactionalObject
@@ -99,7 +103,6 @@ class AppExport DocumentObject: public App::TransactionalObject
PROPERTY_HEADER_WITH_OVERRIDE(App::DocumentObject);
public:
PropertyString Label;
PropertyString Label2;
PropertyExpressionEngine ExpressionEngine;
@@ -107,15 +110,18 @@ public:
/// Allow control visibility status in App name space
PropertyBool Visibility;
// clang-format off
/// signal before changing a property of this object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalBeforeChange;
boost::signals2::signal<void(const App::DocumentObject&, const App::Property&)> signalBeforeChange;
/// signal on changed property of this object
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalChanged;
boost::signals2::signal<void(const App::DocumentObject&, const App::Property&)> signalChanged;
/// signal on changed property of this object before document scoped signalChangedObject
boost::signals2::signal<void (const App::DocumentObject&, const App::Property&)> signalEarlyChanged;
boost::signals2::signal<void(const App::DocumentObject&, const App::Property&)> signalEarlyChanged;
// clang-format on
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName() const {
virtual const char* getViewProviderName() const
{
return "";
}
/**
@@ -127,7 +133,8 @@ public:
* If not, the view provider will be reverted to the one returned from \ref
* getViewProviderName().
*/
virtual const char *getViewProviderNameOverride() const {
virtual const char* getViewProviderNameOverride() const
{
return getViewProviderName();
}
@@ -138,11 +145,14 @@ public:
/// returns a value that uniquely identifies this DocumentObject.
const char* getDagKey() const;
/// returns the name which is set in the document for this object (not the name property!)
const char *getNameInDocument() const;
const char* getNameInDocument() const;
/// Return the object ID that is unique within its owner document
long getID() const {return _Id;}
long getID() const
{
return _Id;
}
/// returns the name that is safe to be exported to other document
std::string getExportName(bool forced=false) const;
std::string getExportName(bool forced = false) const;
/// Return the object full name of the form DocName#ObjName
std::string getFullName() const override;
/// Return the object full label in the form DocName#ObjName
@@ -150,13 +160,13 @@ public:
bool isAttachedToDocument() const override;
const char* detachFromDocument() override;
/// gets the document in which this Object is handled
App::Document *getDocument() const;
App::Document* getDocument() const;
/** Set the property touched -> changed, cause recomputation in Update()
*/
//@{
/// set this document object touched (cause recomputation on dependent features)
void touch(bool noRecompute=false);
void touch(bool noRecompute = false);
/// test if this document object is touched
bool isTouched() const;
/// Enforce this document object to be recomputed
@@ -164,32 +174,63 @@ public:
/// Test if this document object must be recomputed
bool mustRecompute() const;
/// reset this document object touched
void purgeTouched() {
void purgeTouched()
{
StatusBits.reset(ObjectStatus::Touch);
StatusBits.reset(ObjectStatus::Enforce);
setPropertyStatus(0,false);
setPropertyStatus(0, false);
}
/// set this feature to error
bool isError() const {return StatusBits.test(ObjectStatus::Error);}
bool isValid() const {return !StatusBits.test(ObjectStatus::Error);}
bool isError() const
{
return StatusBits.test(ObjectStatus::Error);
}
bool isValid() const
{
return !StatusBits.test(ObjectStatus::Error);
}
/// remove the error from the object
void purgeError(){StatusBits.reset(ObjectStatus::Error);}
void purgeError()
{
StatusBits.reset(ObjectStatus::Error);
}
/// returns true if this objects is currently recomputing
bool isRecomputing() const {return StatusBits.test(ObjectStatus::Recompute);}
bool isRecomputing() const
{
return StatusBits.test(ObjectStatus::Recompute);
}
/// returns true if this objects is currently restoring from file
bool isRestoring() const {return StatusBits.test(ObjectStatus::Restore);}
bool isRestoring() const
{
return StatusBits.test(ObjectStatus::Restore);
}
/// returns true if this objects is currently removed from the document
bool isRemoving() const {return StatusBits.test(ObjectStatus::Remove);}
bool isRemoving() const
{
return StatusBits.test(ObjectStatus::Remove);
}
/// set this document object freezed (prevent recomputation)
void freeze();
/// set this document object unfreezed (and touch it)
void unfreeze(bool noRecompute=false);
void unfreeze(bool noRecompute = false);
/// returns true if this objects is currently freezed
bool isFreezed() const {return StatusBits.test(ObjectStatus::Freeze);}
bool isFreezed() const
{
return StatusBits.test(ObjectStatus::Freeze);
}
/// return the status bits
unsigned long getStatus() const {return StatusBits.to_ulong();}
bool testStatus(ObjectStatus pos) const {return StatusBits.test(size_t(pos));}
void setStatus(ObjectStatus pos, bool on) {StatusBits.set(size_t(pos), on);}
unsigned long getStatus() const
{
return StatusBits.to_ulong();
}
bool testStatus(ObjectStatus pos) const
{
return StatusBits.test(size_t(pos));
}
void setStatus(ObjectStatus pos, bool on)
{
StatusBits.set(size_t(pos), on);
}
//@}
int isExporting() const;
@@ -205,14 +246,14 @@ public:
* @return -1 if element visibility is not supported, 0 if element is not
* found, 1 if success
*/
virtual int setElementVisible(const char *element, bool visible);
virtual int setElementVisible(const char* element, bool visible);
/** Get sub-element visibility
*
* @return -1 if element visibility is not supported or element not found, 0
* if element is invisible, or else 1
*/
virtual int isElementVisible(const char *element) const;
virtual int isElementVisible(const char* element) const;
/// return true to activate tree view group object handling and element visibility
virtual bool hasChildElement() const;
@@ -225,7 +266,8 @@ public:
*/
//@{
/// OutList options
enum OutListOption {
enum OutListOption
{
/// Do not include link from expression engine
OutListNoExpression = 1,
/// Do not hide any link (i.e. include links with LinkScopeHidden)
@@ -234,9 +276,9 @@ public:
OutListNoXLinked = 4,
};
/// returns a list of objects this object is pointing to by Links
const std::vector<App::DocumentObject*> &getOutList() const;
const std::vector<App::DocumentObject*>& getOutList() const;
std::vector<App::DocumentObject*> getOutList(int option) const;
void getOutList(int option, std::vector<App::DocumentObject*> &res) const;
void getOutList(int option, std::vector<App::DocumentObject*>& res) const;
/// returns a list of objects linked by the property
std::vector<App::DocumentObject*> getOutListOfProperty(App::Property*) const;
@@ -245,15 +287,15 @@ public:
/// clear internal out list cache
void clearOutListCache() const;
/// get all possible paths from this to another object following the OutList
std::vector<std::list<App::DocumentObject*> > getPathsByOutList(App::DocumentObject* to) const;
std::vector<std::list<App::DocumentObject*>> getPathsByOutList(App::DocumentObject* to) const;
#ifdef USE_OLD_DAG
/// get all objects link to this object
std::vector<App::DocumentObject*> getInList(void) const
#else
const std::vector<App::DocumentObject*> &getInList() const;
const std::vector<App::DocumentObject*>& getInList() const;
#endif
/// get all objects link directly or indirectly to this object
std::vector<App::DocumentObject*> getInListRecursive() const;
/// get all objects link directly or indirectly to this object
std::vector<App::DocumentObject*> getInListRecursive() const;
/** Get a set of all objects linking to this object, including possible external parent objects
*
* @param inSet [out]: a set containing all objects linking to this object.
@@ -261,9 +303,11 @@ public:
* @param inList [in, out]: optional pointer to a vector holding the output
* objects, with the furthest linking object ordered last.
*/
void getInListEx(std::set<App::DocumentObject*> &inSet,
bool recursive, std::vector<App::DocumentObject*> *inList=nullptr) const;
/** Return a set of all objects linking to this object, including possible external parent objects
void getInListEx(std::set<App::DocumentObject*>& inSet,
bool recursive,
std::vector<App::DocumentObject*>* inList = nullptr) const;
/** Return a set of all objects linking to this object, including possible external parent
* objects
* @param recursive [in]: whether to obtain recursive in list
*/
std::set<App::DocumentObject*> getInListEx(bool recursive) const;
@@ -296,9 +340,9 @@ public:
* That is, if the return is true, the link is allowed.
*/
bool testIfLinkDAGCompatible(DocumentObject* linkTo) const;
bool testIfLinkDAGCompatible(const std::vector<DocumentObject *> &linksTo) const;
bool testIfLinkDAGCompatible(App::PropertyLinkSubList &linksTo) const;
bool testIfLinkDAGCompatible(App::PropertyLinkSub &linkTo) const;
bool testIfLinkDAGCompatible(const std::vector<DocumentObject*>& linksTo) const;
bool testIfLinkDAGCompatible(App::PropertyLinkSubList& linksTo) const;
bool testIfLinkDAGCompatible(App::PropertyLinkSub& linkTo) const;
/** Return the element map version of the geometry data stored in the given property
*
@@ -309,10 +353,11 @@ public:
*
* @return Return the element map version string.
*/
virtual std::string getElementMapVersion(const App::Property *prop, bool restored=false) const;
virtual std::string getElementMapVersion(const App::Property* prop,
bool restored = false) const;
/// Return true to signal re-generation of geometry element names
virtual bool checkElementMapVersion(const App::Property *prop, const char *ver) const;
virtual bool checkElementMapVersion(const App::Property* prop, const char* ver) const;
public:
/** mustExecute
@@ -332,10 +377,10 @@ public:
*
* @param recursive: set to true to recompute any dependent objects as well
*/
bool recomputeFeature(bool recursive=false);
bool recomputeFeature(bool recursive = false);
/// get the status Message
const char *getStatusString() const;
const char* getStatusString() const;
/** Called in case of losing a link
* Get called by the document when a object got deleted a link property of this
@@ -344,7 +389,7 @@ public:
* additional or different behavior.
*/
virtual void onLostLinkToObject(DocumentObject*);
PyObject *getPyObject() override;
PyObject* getPyObject() override;
/** Get the sub element/object by name
*
@@ -374,8 +419,11 @@ public:
* then it shall return itself. If subname is invalid, then it shall return
* zero.
*/
virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj=nullptr,
Base::Matrix4D *mat=nullptr, bool transform=true, int depth=0) const;
virtual DocumentObject* getSubObject(const char* subname,
PyObject** pyObj = nullptr,
Base::Matrix4D* mat = nullptr,
bool transform = true,
int depth = 0) const;
/** Return a list of objects referenced by a given subname including this object
* @param subname: the sub name path
@@ -391,7 +439,8 @@ public:
bool flatten = false) const;
/// reason of calling getSubObjects()
enum GSReason {
enum GSReason
{
/// default, mostly for exporting shape objects
GS_DEFAULT,
/// for element selection
@@ -413,10 +462,10 @@ public:
* need special transformation. For example, sub objects of an array type
* of object.
*/
virtual std::vector<std::string> getSubObjects(int reason=0) const;
virtual std::vector<std::string> getSubObjects(int reason = 0) const;
///Obtain top parents and subnames of this object using its InList
std::vector<std::pair<App::DocumentObject*,std::string> > getParents(int depth=0) const;
/// Obtain top parents and subnames of this object using its InList
std::vector<std::pair<App::DocumentObject*, std::string>> getParents(int depth = 0) const;
/// Obtain the first parent group of this object
App::DocumentObject* getFirstParent() const;
@@ -436,20 +485,34 @@ public:
* @return Return the linked object. This function must return itself if the
* it is not a link or the link is invalid.
*/
virtual DocumentObject *getLinkedObject(bool recurse=true,
Base::Matrix4D *mat=nullptr, bool transform=false, int depth=0) const;
virtual DocumentObject* getLinkedObject(bool recurse = true,
Base::Matrix4D* mat = nullptr,
bool transform = false,
int depth = 0) const;
/* Return true to cause PropertyView to show linked object's property */
virtual bool canLinkProperties() const {return true;}
virtual bool canLinkProperties() const
{
return true;
}
/* Return whether this object is a link */
virtual bool isLink() const {return false;};
virtual bool isLink() const
{
return false;
}
/* Return whether this object is a link group */
virtual bool isLinkGroup() const {return false;};
virtual bool isLinkGroup() const
{
return false;
}
/* Return true to bypass duplicate label checking */
virtual bool allowDuplicateLabel() const {return false;}
virtual bool allowDuplicateLabel() const
{
return false;
}
/*** Called to let object itself control relabeling
*
@@ -457,38 +520,50 @@ public:
*
* This function is called before onBeforeChange()
*/
virtual void onBeforeChangeLabel(std::string &newLabel) {(void)newLabel;}
virtual void onBeforeChangeLabel(std::string& newLabel)
{
(void)newLabel;
}
friend class Document;
friend class Transaction;
friend class ObjectExecution;
static DocumentObjectExecReturn *StdReturn;
static DocumentObjectExecReturn* StdReturn;
void Save (Base::Writer &writer) const override;
void Save(Base::Writer& writer) const override;
/* Expression support */
virtual void setExpression(const ObjectIdentifier & path, std::shared_ptr<App::Expression> expr);
virtual void setExpression(const ObjectIdentifier& path, std::shared_ptr<App::Expression> expr);
void clearExpression(const ObjectIdentifier & path);
void clearExpression(const ObjectIdentifier& path);
virtual const PropertyExpressionEngine::ExpressionInfo getExpression(const ObjectIdentifier &path) const;
virtual const PropertyExpressionEngine::ExpressionInfo
getExpression(const ObjectIdentifier& path) const;
virtual void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
virtual void
renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier>& paths);
const std::string & getOldLabel() const { return oldLabel; }
const std::string& getOldLabel() const
{
return oldLabel;
}
const char *getViewProviderNameStored() const {
const char* getViewProviderNameStored() const
{
return _pcViewProviderName.c_str();
}
bool removeDynamicProperty(const char* prop) override;
App::Property* addDynamicProperty(
const char* type, const char* name=nullptr,
const char* group=nullptr, const char* doc=nullptr,
short attr=0, bool ro=false, bool hidden=false) override;
App::Property* addDynamicProperty(const char* type,
const char* name = nullptr,
const char* group = nullptr,
const char* doc = nullptr,
short attr = 0,
bool ro = false,
bool hidden = false) override;
/** Resolve the last document object referenced in the subname
*
@@ -502,9 +577,14 @@ public:
* @return Returns the last referenced document object in the subname. If no
* such object in subname, return pObject.
*/
App::DocumentObject *resolve(const char *subname, App::DocumentObject **parent=nullptr,
std::string *childName=nullptr, const char **subElement=nullptr,
PyObject **pyObj=nullptr, Base::Matrix4D *mat=nullptr, bool transform=true, int depth=0) const;
App::DocumentObject* resolve(const char* subname,
App::DocumentObject** parent = nullptr,
std::string* childName = nullptr,
const char** subElement = nullptr,
PyObject** pyObj = nullptr,
Base::Matrix4D* mat = nullptr,
bool transform = true,
int depth = 0) const;
/** Resolve a link reference that is relative to this object reference
*
@@ -550,8 +630,9 @@ public:
*
* The common parent 'Group' is removed.
*/
App::DocumentObject *resolveRelativeLink(std::string &subname,
App::DocumentObject *&link, std::string &linkSub) const;
App::DocumentObject* resolveRelativeLink(std::string& subname,
App::DocumentObject*& link,
std::string& linkSub) const;
/** Called to adjust link properties to avoid cyclic links
*
@@ -567,8 +648,8 @@ public:
* properties that can hold subnames) to avoid cyclic when added to the
* future parent.
*/
virtual bool adjustRelativeLinks(const std::set<App::DocumentObject*> &inList,
std::set<App::DocumentObject*> *visited=nullptr);
virtual bool adjustRelativeLinks(const std::set<App::DocumentObject*>& inList,
std::set<App::DocumentObject*>* visited = nullptr);
/** allow partial loading of dependent objects
*
@@ -576,9 +657,13 @@ public:
* dependent objects to be partially loaded, i.e. only create, but not
* restored. 2 means this object itself can be partially loaded.
*/
virtual int canLoadPartial() const {return 0;}
virtual int canLoadPartial() const
{
return 0;
}
virtual void onUpdateElementReference(const Property *) {}
virtual void onUpdateElementReference(const Property*)
{}
/** Allow object to redirect a subname path
*
@@ -593,34 +678,34 @@ public:
* item is selected in the tree. Document object can use this function to
* redirect the selection to some other objects.
*/
virtual bool redirectSubName(std::ostringstream &ss,
DocumentObject *topParent, DocumentObject *child) const;
virtual bool
redirectSubName(std::ostringstream& ss, DocumentObject* topParent, DocumentObject* child) const;
/** Special marker to mark the object as hidden
*
* It is used by Gui::ViewProvider::getElementColors(), but exposed here
* for convenience
*/
static const std::string &hiddenMarker();
static const std::string& hiddenMarker();
/// Check if the subname reference ends with hidden marker.
static const char *hasHiddenMarker(const char *subname);
static const char* hasHiddenMarker(const char* subname);
protected:
/// recompute only this object
virtual App::DocumentObjectExecReturn *recompute();
virtual App::DocumentObjectExecReturn* recompute();
/** get called by the document to recompute this feature
* Normally this method get called in the processing of
* Document::recompute().
* In execute() the output properties get recomputed
* with the data from linked objects and objects own
* properties.
*/
virtual App::DocumentObjectExecReturn *execute();
* Normally this method get called in the processing of
* Document::recompute().
* In execute() the output properties get recomputed
* with the data from linked objects and objects own
* properties.
*/
virtual App::DocumentObjectExecReturn* execute();
/**
* Executes the extensions of a document object.
*/
App::DocumentObjectExecReturn *executeExtensions();
App::DocumentObjectExecReturn* executeExtensions();
/** Status bits of the document object
* The first 8 bits are used for the base system the rest can be used in
@@ -638,8 +723,14 @@ protected:
*/
std::bitset<32> StatusBits;
void setError(){StatusBits.set(ObjectStatus::Error);}
void resetError(){StatusBits.reset(ObjectStatus::Error);}
void setError()
{
StatusBits.set(ObjectStatus::Error);
}
void resetError()
{
StatusBits.reset(ObjectStatus::Error);
}
void setDocument(App::Document* doc);
/// get called before the value is changed
@@ -660,39 +751,40 @@ protected:
virtual void unsetupObject();
/// get called when a property status has changed
void onPropertyStatusChanged(const Property &prop, unsigned long oldStatus) override;
void onPropertyStatusChanged(const Property& prop, unsigned long oldStatus) override;
private:
void printInvalidLinks() const;
/// python object of this class and all descendent
protected: // attributes
/// python object of this class and all descendent
protected: // attributes
Py::SmartPtr PythonObject;
/// pointer to the document this object belongs to
App::Document* _pDoc{nullptr};
App::Document* _pDoc {nullptr};
/// Old label; used for renaming expressions
std::string oldLabel;
// pointer to the document name string (for performance)
const std::string *pcNameInDocument{nullptr};
const std::string* pcNameInDocument {nullptr};
private:
// accessed by App::Document to record and restore the correct view provider type
std::string _pcViewProviderName;
// unique identifier (among a document) of this object.
long _Id{0};
long _Id {0};
private:
// Back pointer to all the fathers in a DAG of the document
// this is used by the document (via friend) to have a effective DAG handling
std::vector<App::DocumentObject*> _inList;
mutable std::vector<App::DocumentObject *> _outList;
mutable std::unordered_map<const char *, App::DocumentObject*, CStringHasher, CStringHasher> _outListMap;
mutable std::vector<App::DocumentObject*> _outList;
mutable std::unordered_map<const char*, App::DocumentObject*, CStringHasher, CStringHasher>
_outListMap;
mutable bool _outListCached = false;
};
} //namespace App
} // namespace App
#endif // APP_DOCUMENTOBJECT_H
#endif // APP_DOCUMENTOBJECT_H
+31 -23
View File
@@ -39,55 +39,60 @@ DocumentObjectExtension::DocumentObjectExtension()
DocumentObjectExtension::~DocumentObjectExtension() = default;
short int DocumentObjectExtension::extensionMustExecute() {
short int DocumentObjectExtension::extensionMustExecute()
{
return 0;
}
App::DocumentObjectExecReturn* DocumentObjectExtension::extensionExecute() {
App::DocumentObjectExecReturn* DocumentObjectExtension::extensionExecute()
{
return App::DocumentObject::StdReturn;
}
void DocumentObjectExtension::onExtendedSettingDocument() {
void DocumentObjectExtension::onExtendedSettingDocument()
{}
}
void DocumentObjectExtension::onExtendedDocumentRestored()
{}
void DocumentObjectExtension::onExtendedDocumentRestored() {
void DocumentObjectExtension::onExtendedSetupObject()
{}
}
void DocumentObjectExtension::onExtendedUnsetupObject()
{}
void DocumentObjectExtension::onExtendedSetupObject() {
PyObject* DocumentObjectExtension::getExtensionPyObject()
{
}
void DocumentObjectExtension::onExtendedUnsetupObject() {
}
PyObject* DocumentObjectExtension::getExtensionPyObject() {
if (ExtensionPythonObject.is(Py::_None())){
if (ExtensionPythonObject.is(Py::_None())) {
// ref counter is set to 1
ExtensionPythonObject = Py::Object(new DocumentObjectExtensionPy(this),true);
ExtensionPythonObject = Py::Object(new DocumentObjectExtensionPy(this), true);
}
return Py::new_reference_to(ExtensionPythonObject);
}
const DocumentObject* DocumentObjectExtension::getExtendedObject() const {
const DocumentObject* DocumentObjectExtension::getExtendedObject() const
{
assert(getExtendedContainer()->isDerivedFrom(DocumentObject::getClassTypeId()));
return static_cast<const DocumentObject*>(getExtendedContainer());
}
DocumentObject* DocumentObjectExtension::getExtendedObject() {
DocumentObject* DocumentObjectExtension::getExtendedObject()
{
assert(getExtendedContainer()->isDerivedFrom(DocumentObject::getClassTypeId()));
return static_cast<DocumentObject*>(getExtendedContainer());
}
bool DocumentObjectExtension::extensionGetSubObject(DocumentObject *&,
const char *, PyObject **, Base::Matrix4D *, bool, int) const
bool DocumentObjectExtension::extensionGetSubObject(DocumentObject*&,
const char*,
PyObject**,
Base::Matrix4D*,
bool,
int) const
{
return false;
}
@@ -97,8 +102,11 @@ bool DocumentObjectExtension::extensionGetSubObjects(std::vector<std::string>&,
return false;
}
bool DocumentObjectExtension::extensionGetLinkedObject(
DocumentObject *&, bool, Base::Matrix4D *, bool, int) const
bool DocumentObjectExtension::extensionGetLinkedObject(DocumentObject*&,
bool,
Base::Matrix4D*,
bool,
int) const
{
return false;
}
+42 -22
View File
@@ -26,10 +26,12 @@
#include "Extension.h"
namespace Base {
namespace Base
{
class Matrix4D;
}
namespace App {
namespace App
{
class DocumentObject;
class DocumentObjectExecReturn;
@@ -37,24 +39,23 @@ class DocumentObjectExecReturn;
* @brief Extension with special document object calls
*
*/
class AppExport DocumentObjectExtension : public App::Extension
class AppExport DocumentObjectExtension: public App::Extension
{
//The cass does not have properties itself, but it is important to provide the property access
//functions. see cpp file for details
// The cass does not have properties itself, but it is important to provide the property access
// functions. see cpp file for details
EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(App::DocumentObjectExtension);
public:
DocumentObjectExtension();
~DocumentObjectExtension() override;
DocumentObjectExtension ();
~DocumentObjectExtension () override;
App::DocumentObject* getExtendedObject();
App::DocumentObject* getExtendedObject();
const App::DocumentObject* getExtendedObject() const;
//override if execution is necessary
// override if execution is necessary
virtual short extensionMustExecute();
virtual App::DocumentObjectExecReturn *extensionExecute();
virtual App::DocumentObjectExecReturn* extensionExecute();
/// get called after setting the document
@@ -70,36 +71,55 @@ public:
/// returns the type name of the ViewProviderExtension which is automatically attached
/// to the viewprovider object when it is initiated
virtual const char* getViewProviderExtensionName() const {return "";}
virtual const char* getViewProviderExtensionName() const
{
return "";
}
/** Get the sub object by name
* @sa DocumentObject::getSubObject()
*
* @return Return turn if handled, the sub object is returned in \c ret
*/
virtual bool extensionGetSubObject(DocumentObject *&ret, const char *subname,
PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const;
virtual bool extensionGetSubObject(DocumentObject*& ret,
const char* subname,
PyObject** pyObj,
Base::Matrix4D* mat,
bool transform,
int depth) const;
/** Get name references of all sub objects
* @sa DocumentObject::getSubObjects()
*
* @return Return turn if handled, the sub object is returned in \c ret
*/
virtual bool extensionGetSubObjects(std::vector<std::string> &ret, int reason) const;
virtual bool extensionGetSubObjects(std::vector<std::string>& ret, int reason) const;
/** Get the linked object
* @sa DocumentObject::getLinkedObject()
*
* @return Return turn if handled, the linked object is returned in \c ret
*/
virtual bool extensionGetLinkedObject(DocumentObject *&ret, bool recursive,
Base::Matrix4D *mat, bool transform, int depth) const;
virtual bool extensionGetLinkedObject(DocumentObject*& ret,
bool recursive,
Base::Matrix4D* mat,
bool transform,
int depth) const;
virtual int extensionSetElementVisible(const char *, bool) {return -1;}
virtual int extensionIsElementVisible(const char *) {return -1;}
virtual bool extensionHasChildElement() const {return false;}
virtual int extensionSetElementVisible(const char*, bool)
{
return -1;
}
virtual int extensionIsElementVisible(const char*)
{
return -1;
}
virtual bool extensionHasChildElement() const
{
return false;
}
};
} //App
} // namespace App
#endif // APP_DOCUMENTOBJECTEXTENSION_H
#endif // APP_DOCUMENTOBJECTEXTENSION_H
+8 -8
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="ExtensionPy"
Name="DocumentObjectExtensionPy"
TwinPointer="DocumentObjectExtension"
Twin="DocumentObjectExtension"
Include="App/DocumentObjectExtension.h"
Namespace="App"
FatherInclude="App/ExtensionPy.h"
<PythonExport
Father="ExtensionPy"
Name="DocumentObjectExtensionPy"
TwinPointer="DocumentObjectExtension"
Twin="DocumentObjectExtension"
Include="App/DocumentObjectExtension.h"
Namespace="App"
FatherInclude="App/ExtensionPy.h"
FatherNamespace="App">
<Documentation>
<Author Licence="LGPL" Name="Stefan Troeger" EMail="[email protected]" />
+2 -2
View File
@@ -35,12 +35,12 @@ std::string DocumentObjectExtensionPy::representation() const
return {"<document object extension>"};
}
PyObject *DocumentObjectExtensionPy::getCustomAttributes(const char* /*attr*/) const
PyObject* DocumentObjectExtensionPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int DocumentObjectExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject * /*obj*/)
int DocumentObjectExtensionPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
+5 -2
View File
@@ -32,8 +32,11 @@ PROPERTY_SOURCE(App::DocumentObjectFileIncluded, App::DocumentObject)
DocumentObjectFileIncluded::DocumentObjectFileIncluded()
{
ADD_PROPERTY_TYPE(File,(nullptr),"",(App::PropertyType)(Prop_None),"File to include into Project File");
ADD_PROPERTY_TYPE(File,
(nullptr),
"",
(App::PropertyType)(Prop_None),
"File to include into Project File");
}
DocumentObjectFileIncluded::~DocumentObjectFileIncluded() = default;
+5 -5
View File
@@ -31,7 +31,7 @@
namespace App
{
class AppExport DocumentObjectFileIncluded : public DocumentObject
class AppExport DocumentObjectFileIncluded: public DocumentObject
{
PROPERTY_HEADER_WITH_OVERRIDE(App::DocumentObjectFileIncluded);
@@ -42,16 +42,16 @@ public:
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override {
const char* getViewProviderName() const override
{
return "Gui::ViewProviderDocumentObject";
}
/// Properties
PropertyFileIncluded File;
};
} //namespace App
} // namespace App
#endif // APP_DOCUMENTOBJECTFILEINCLUDED_H
#endif // APP_DOCUMENTOBJECTFILEINCLUDED_H
+18 -10
View File
@@ -31,19 +31,22 @@ using namespace App;
PROPERTY_SOURCE_WITH_EXTENSIONS(App::DocumentObjectGroup, App::DocumentObject)
DocumentObjectGroup::DocumentObjectGroup(): DocumentObject(), GroupExtension() {
DocumentObjectGroup::DocumentObjectGroup()
: DocumentObject()
, GroupExtension()
{
GroupExtension::initExtension(this);
_GroupTouched.setStatus(App::Property::Output,true);
_GroupTouched.setStatus(App::Property::Output, true);
}
DocumentObjectGroup::~DocumentObjectGroup() = default;
PyObject *DocumentObjectGroup::getPyObject()
PyObject* DocumentObjectGroup::getPyObject()
{
if (PythonObject.is(Py::_None())){
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new DocumentObjectGroupPy(this),true);
PythonObject = Py::Object(new DocumentObjectGroupPy(this), true);
}
return Py::new_reference_to(PythonObject);
}
@@ -51,17 +54,22 @@ PyObject *DocumentObjectGroup::getPyObject()
// Python feature ---------------------------------------------------------
namespace App {
namespace App
{
/// @cond DOXERR
PROPERTY_SOURCE_TEMPLATE(App::DocumentObjectGroupPython, App::DocumentObjectGroup)
template<> const char* App::DocumentObjectGroupPython::getViewProviderName() const {
template<>
const char* App::DocumentObjectGroupPython::getViewProviderName() const
{
return "Gui::ViewProviderDocumentObjectGroupPython";
}
template<> PyObject* App::DocumentObjectGroupPython::getPyObject() {
template<>
PyObject* App::DocumentObjectGroupPython::getPyObject()
{
if (PythonObject.is(Py::_None())) {
// ref counter is set to 1
PythonObject = Py::Object(new FeaturePythonPyT<App::DocumentObjectGroupPy>(this),true);
PythonObject = Py::Object(new FeaturePythonPyT<App::DocumentObjectGroupPy>(this), true);
}
return Py::new_reference_to(PythonObject);
}
@@ -69,4 +77,4 @@ template<> PyObject* App::DocumentObjectGroupPython::getPyObject() {
// explicit template instantiation
template class AppExport FeaturePythonT<App::DocumentObjectGroup>;
}
} // namespace App
+7 -5
View File
@@ -32,7 +32,8 @@
namespace App
{
class AppExport DocumentObjectGroup : public DocumentObject, public GroupExtension {
class AppExport DocumentObjectGroup: public DocumentObject, public GroupExtension
{
PROPERTY_HEADER_WITH_EXTENSIONS(App::DocumentObjectGroup);
@@ -42,17 +43,18 @@ public:
~DocumentObjectGroup() override;
/// returns the type name of the ViewProvider
const char* getViewProviderName() const override {
const char* getViewProviderName() const override
{
return "Gui::ViewProviderDocumentObjectGroup";
}
PyObject *getPyObject() override;
PyObject* getPyObject() override;
};
using DocumentObjectGroupPython = App::FeaturePythonT<DocumentObjectGroup>;
} //namespace App
} // namespace App
#endif // APP_DOCUMENTOBJECTGROUP_H
#endif // APP_DOCUMENTOBJECTGROUP_H
+8 -8
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="DocumentObjectPy"
Name="DocumentObjectGroupPy"
Twin="DocumentObjectGroup"
TwinPointer="DocumentObjectGroup"
Include="App/DocumentObjectGroup.h"
Namespace="App"
FatherInclude="App/DocumentObjectPy.h"
<PythonExport
Father="DocumentObjectPy"
Name="DocumentObjectGroupPy"
Twin="DocumentObjectGroup"
TwinPointer="DocumentObjectGroup"
Include="App/DocumentObjectGroup.h"
Namespace="App"
FatherInclude="App/DocumentObjectPy.h"
FatherNamespace="App">
<Documentation>
<Author Licence="LGPL" Name="Werner Mayer" EMail="[email protected]" />
+1 -2
View File
@@ -37,7 +37,7 @@ std::string DocumentObjectGroupPy::representation() const
return {"<group object>"};
}
PyObject *DocumentObjectGroupPy::getCustomAttributes(const char* /*attr*/) const
PyObject* DocumentObjectGroupPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
@@ -46,4 +46,3 @@ int DocumentObjectGroupPy::setCustomAttributes(const char* /*attr*/, PyObject* /
{
return 0;
}
+21 -14
View File
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="ExtensionContainerPy"
Name="DocumentObjectPy"
Twin="DocumentObject"
TwinPointer="DocumentObject"
Include="App/DocumentObject.h"
Namespace="App"
FatherInclude="App/ExtensionContainerPy.h"
<PythonExport
Father="ExtensionContainerPy"
Name="DocumentObjectPy"
Twin="DocumentObject"
TwinPointer="DocumentObject"
Include="App/DocumentObject.h"
Namespace="App"
FatherInclude="App/ExtensionContainerPy.h"
FatherNamespace="App">
<Documentation>
<Author Licence="LGPL" Name="Juergen Riegel" EMail="[email protected]" />
@@ -95,7 +95,7 @@ referencing subobject.
PyObject: return a python binding object for the (sub)object referenced in
each 'subname' The actual type of 'PyObject' is implementation dependent.
For Part::Feature compatible objects, this will be of type TopoShapePy and
pre-transformed by accumulated transformation matrix along the object path.
pre-transformed by accumulated transformation matrix along the object path.
DocObject: return the document object referenced in subname, if 'matrix' is
None. Or, return a tuple (object, matrix) for each 'subname' and 'matrix' is
@@ -168,15 +168,15 @@ Return -1 if element visibility is not supported or element not found, 0 if invi
</Methode>
<Methode Name="getParentGroup">
<Documentation>
<UserDocu>Returns the group the object is in or None if it is not part of a group.
Note that an object can only be in a single group, hence only a single return
<UserDocu>Returns the group the object is in or None if it is not part of a group.
Note that an object can only be in a single group, hence only a single return
value.</UserDocu>
</Documentation>
</Methode>
<Methode Name="getParentGeoFeatureGroup">
<Documentation>
<UserDocu>Returns the GeoFeatureGroup, and hence the local coordinate system, the object
is in or None if it is not part of a group. Note that an object can only be
<UserDocu>Returns the GeoFeatureGroup, and hence the local coordinate system, the object
is in or None if it is not part of a group. Note that an object can only be
in a single group, hence only a single return value.</UserDocu>
</Documentation>
</Methode>
@@ -232,6 +232,13 @@ Return tuple(obj,newElementName,oldElementName)
</UserDocu>
</Documentation>
</Methode>
<Methode Name="isAttachedToDocument" Const="true">
<Documentation>
<UserDocu>
isAttachedToDocument(): return true if the object is part of a document, false otherwise
</UserDocu>
</Documentation>
</Methode>
<Attribute Name="OutList" ReadOnly="true">
<Documentation>
<UserDocu>A list of all objects this object links to.</UserDocu>
@@ -266,7 +273,7 @@ Return tuple(obj,newElementName,oldElementName)
<Documentation>
<UserDocu>Return the internal name of this object</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
<Parameter Name="Name" Type="Object"/>
</Attribute>
<Attribute Name="Document" ReadOnly="true">
<Documentation>
+370 -217
View File
@@ -49,14 +49,14 @@ std::string DocumentObjectPy::representation() const
return str.str();
}
Py::String DocumentObjectPy::getName() const
Py::Object DocumentObjectPy::getName() const
{
DocumentObject* object = this->getDocumentObjectPtr();
const char* internal = object->getNameInDocument();
if (!internal) {
throw Py::RuntimeError(std::string("This object is currently not part of a document"));
return Py::None();
}
return {std::string(internal)};
return Py::String(internal);
}
Py::String DocumentObjectPy::getFullName() const
@@ -76,27 +76,63 @@ Py::Object DocumentObjectPy::getDocument() const
}
}
PyObject* DocumentObjectPy::addProperty(PyObject *args, PyObject *kwd)
PyObject* DocumentObjectPy::isAttachedToDocument(PyObject* args)
{
char *sType,*sName=nullptr,*sGroup=nullptr,*sDoc=nullptr;
short attr=0;
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
DocumentObject* object = this->getDocumentObjectPtr();
bool ok = object->isAttachedToDocument();
return Py::new_reference_to(Py::Boolean(ok));
}
PyObject* DocumentObjectPy::addProperty(PyObject* args, PyObject* kwd)
{
char *sType, *sName = nullptr, *sGroup = nullptr, *sDoc = nullptr;
short attr = 0;
std::string sDocStr;
PyObject *ro = Py_False, *hd = Py_False;
PyObject* enumVals = nullptr;
const std::array<const char *, 9> kwlist {"type","name","group","doc","attr","read_only","hidden","enum_vals",nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(
args, kwd, "ss|sethO!O!O", kwlist, &sType, &sName, &sGroup, "utf-8",
&sDoc, &attr, &PyBool_Type, &ro, &PyBool_Type, &hd, &enumVals))
const std::array<const char*, 9> kwlist {"type",
"name",
"group",
"doc",
"attr",
"read_only",
"hidden",
"enum_vals",
nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args,
kwd,
"ss|sethO!O!O",
kwlist,
&sType,
&sName,
&sGroup,
"utf-8",
&sDoc,
&attr,
&PyBool_Type,
&ro,
&PyBool_Type,
&hd,
&enumVals)) {
return nullptr;
}
if (sDoc) {
sDocStr = sDoc;
PyMem_Free(sDoc);
}
Property *prop = getDocumentObjectPtr()->
addDynamicProperty(sType,sName,sGroup,sDocStr.c_str(),attr,
Base::asBoolean(ro), Base::asBoolean(hd));
Property* prop = getDocumentObjectPtr()->addDynamicProperty(sType,
sName,
sGroup,
sDocStr.c_str(),
attr,
Base::asBoolean(ro),
Base::asBoolean(hd));
// enum support
auto* propEnum = dynamic_cast<App::PropertyEnumeration*>(prop);
@@ -107,26 +143,28 @@ PyObject* DocumentObjectPy::addProperty(PyObject *args, PyObject *kwd)
return Py::new_reference_to(this);
}
PyObject* DocumentObjectPy::removeProperty(PyObject *args)
PyObject* DocumentObjectPy::removeProperty(PyObject* args)
{
char *sName;
if (!PyArg_ParseTuple(args, "s", &sName))
char* sName;
if (!PyArg_ParseTuple(args, "s", &sName)) {
return nullptr;
}
bool ok = getDocumentObjectPtr()->removeDynamicProperty(sName);
return Py_BuildValue("O", (ok ? Py_True : Py_False));
}
PyObject* DocumentObjectPy::supportedProperties(PyObject *args)
PyObject* DocumentObjectPy::supportedProperties(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
std::vector<Base::Type> ary;
Base::Type::getAllDerivedFrom(App::Property::getClassTypeId(), ary);
Py::List res;
for (auto & it : ary) {
Base::BaseClass *data = static_cast<Base::BaseClass*>(it.createInstance());
for (auto& it : ary) {
Base::BaseClass* data = static_cast<Base::BaseClass*>(it.createInstance());
if (data) {
delete data;
res.append(Py::String(it.getName()));
@@ -135,19 +173,21 @@ PyObject* DocumentObjectPy::supportedProperties(PyObject *args)
return Py::new_reference_to(res);
}
PyObject* DocumentObjectPy::touch(PyObject * args)
PyObject* DocumentObjectPy::touch(PyObject* args)
{
char *propName = nullptr;
if (!PyArg_ParseTuple(args, "|s",&propName))
char* propName = nullptr;
if (!PyArg_ParseTuple(args, "|s", &propName)) {
return nullptr;
if(propName) {
if(!propName[0]) {
}
if (propName) {
if (!propName[0]) {
getDocumentObjectPtr()->touch(true);
Py_Return;
}
auto prop = getDocumentObjectPtr()->getPropertyByName(propName);
if(!prop)
if (!prop) {
throw Py::RuntimeError("Property not found");
}
prop->touch();
Py_Return;
}
@@ -156,18 +196,20 @@ PyObject* DocumentObjectPy::touch(PyObject * args)
Py_Return;
}
PyObject* DocumentObjectPy::purgeTouched(PyObject * args)
PyObject* DocumentObjectPy::purgeTouched(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
getDocumentObjectPtr()->purgeTouched();
Py_Return;
}
PyObject* DocumentObjectPy::enforceRecompute(PyObject * args)
PyObject* DocumentObjectPy::enforceRecompute(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
getDocumentObjectPtr()->enforceRecompute();
Py_Return;
}
@@ -196,13 +238,13 @@ Py::List DocumentObjectPy::getState() const
uptodate = false;
list.append(Py::String("Restore"));
}
if (object->testStatus(App::Expand)){
if (object->testStatus(App::Expand)) {
list.append(Py::String("Expanded"));
}
if (object->testStatus(App::PartialObject)){
if (object->testStatus(App::PartialObject)) {
list.append(Py::String("Partial"));
}
if (object->testStatus(App::ObjImporting)){
if (object->testStatus(App::ObjImporting)) {
list.append(Py::String("Importing"));
}
if (uptodate) {
@@ -214,7 +256,7 @@ Py::List DocumentObjectPy::getState() const
Py::Object DocumentObjectPy::getViewObject() const
{
try {
PyObject *dict = PySys_GetObject("modules");
PyObject* dict = PySys_GetObject("modules");
if (!dict) {
return Py::None();
}
@@ -226,12 +268,13 @@ Py::Object DocumentObjectPy::getViewObject() const
}
// double-check that the module doesn't have a null pointer
Py::Module module(PyImport_ImportModule("FreeCADGui"),true);
Py::Module module(PyImport_ImportModule("FreeCADGui"), true);
if (module.isNull() || !module.hasAttr("getDocument")) {
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its document methods)
// in v0.14+, the GUI module can be loaded in console mode (but doesn't have all its
// document methods)
return Py::None();
}
if(!getDocumentObjectPtr()->getDocument()) {
if (!getDocumentObjectPtr()->getDocument()) {
throw Py::RuntimeError("Object has no document");
}
const char* internalName = getDocumentObjectPtr()->getNameInDocument();
@@ -255,7 +298,7 @@ Py::Object DocumentObjectPy::getViewObject() const
return Py::None();
}
// FreeCADGui is loaded, so there must be wrong something else
throw; // re-throw
throw; // re-throw
}
}
@@ -264,8 +307,9 @@ Py::List DocumentObjectPy::getInList() const
Py::List ret;
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getInList();
for (auto It : list)
for (auto It : list) {
ret.append(Py::Object(It->getPyObject(), true));
}
return ret;
}
@@ -276,8 +320,9 @@ Py::List DocumentObjectPy::getInListRecursive() const
try {
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getInListRecursive();
for (auto It : list)
for (auto It : list) {
ret.append(Py::Object(It->getPyObject(), true));
}
}
catch (const Base::Exception& e) {
throw Py::IndexError(e.what());
@@ -290,8 +335,9 @@ Py::List DocumentObjectPy::getOutList() const
Py::List ret;
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getOutList();
for (auto It : list)
for (auto It : list) {
ret.append(Py::Object(It->getPyObject(), true));
}
return ret;
}
@@ -303,8 +349,9 @@ Py::List DocumentObjectPy::getOutListRecursive() const
std::vector<DocumentObject*> list = getDocumentObjectPtr()->getOutListRecursive();
// create the python list for the output
for (auto It : list)
for (auto It : list) {
ret.append(Py::Object(It->getPyObject(), true));
}
}
catch (const Base::Exception& e) {
throw Py::IndexError(e.what());
@@ -313,14 +360,15 @@ Py::List DocumentObjectPy::getOutListRecursive() const
return ret;
}
PyObject* DocumentObjectPy::setExpression(PyObject * args)
PyObject* DocumentObjectPy::setExpression(PyObject* args)
{
char * path = nullptr;
PyObject * expr;
char * comment = nullptr;
char* path = nullptr;
PyObject* expr;
char* comment = nullptr;
if (!PyArg_ParseTuple(args, "sO|s", &path, &expr, &comment))
if (!PyArg_ParseTuple(args, "sO|s", &path, &expr, &comment)) {
return nullptr;
}
App::ObjectIdentifier p(ObjectIdentifier::parse(getDocumentObjectPtr(), path));
@@ -329,10 +377,11 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
Py_Return;
}
else if (PyUnicode_Check(expr)) {
const char * exprStr = PyUnicode_AsUTF8(expr);
const char* exprStr = PyUnicode_AsUTF8(expr);
std::shared_ptr<Expression> shared_expr(Expression::parse(getDocumentObjectPtr(), exprStr));
if (shared_expr && comment)
if (shared_expr && comment) {
shared_expr->comment = comment;
}
getDocumentObjectPtr()->setExpression(p, shared_expr);
Py_Return;
@@ -341,22 +390,24 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
throw Py::TypeError("String or None expected.");
}
PyObject* DocumentObjectPy::clearExpression(PyObject * args)
PyObject* DocumentObjectPy::clearExpression(PyObject* args)
{
char * path = nullptr;
if (!PyArg_ParseTuple(args, "s", &path))
char* path = nullptr;
if (!PyArg_ParseTuple(args, "s", &path)) {
return nullptr;
}
App::ObjectIdentifier p(ObjectIdentifier::parse(getDocumentObjectPtr(), path));
getDocumentObjectPtr()->clearExpression(p);
Py_Return;
}
PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
PyObject* DocumentObjectPy::evalExpression(PyObject* self, PyObject* args)
{
const char *expr;
if (!PyArg_ParseTuple(args, "s", &expr))
const char* expr;
if (!PyArg_ParseTuple(args, "s", &expr)) {
return nullptr;
}
// HINT:
// The standard behaviour of Python for class methods is to always pass the class
@@ -374,19 +425,23 @@ PyObject* DocumentObjectPy::evalExpression(PyObject *self, PyObject * args)
obj = static_cast<DocumentObjectPy*>(self)->getDocumentObjectPtr();
}
PY_TRY {
PY_TRY
{
std::shared_ptr<Expression> shared_expr(Expression::parse(obj, expr));
if (shared_expr)
if (shared_expr) {
return Py::new_reference_to(shared_expr->getPyValue());
}
Py_Return;
} PY_CATCH
}
PY_CATCH
}
PyObject* DocumentObjectPy::recompute(PyObject *args)
PyObject* DocumentObjectPy::recompute(PyObject* args)
{
PyObject *recursive = Py_False;
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive))
PyObject* recursive = Py_False;
if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &recursive)) {
return nullptr;
}
try {
bool ok = getDocumentObjectPtr()->recomputeFeature(Base::asBoolean(recursive));
@@ -397,10 +452,11 @@ PyObject* DocumentObjectPy::recompute(PyObject *args)
}
}
PyObject* DocumentObjectPy::isValid(PyObject *args)
PyObject* DocumentObjectPy::isValid(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
bool ok = getDocumentObjectPtr()->isValid();
@@ -411,10 +467,11 @@ PyObject* DocumentObjectPy::isValid(PyObject *args)
}
}
PyObject* DocumentObjectPy::getStatusString(PyObject *args)
PyObject* DocumentObjectPy::getStatusString(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
Py::String text(getDocumentObjectPtr()->getStatusString());
@@ -425,9 +482,10 @@ PyObject* DocumentObjectPy::getStatusString(PyObject *args)
}
}
PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
PyObject* DocumentObjectPy::getSubObject(PyObject* args, PyObject* keywds)
{
enum class ReturnType {
enum class ReturnType
{
PyObject = 0,
DocObject = 1,
DocAndPyObject = 2,
@@ -437,19 +495,33 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
LinkAndMatrix = 6
};
PyObject *obj;
PyObject* obj;
short retType = 0;
PyObject *pyMat = nullptr;
PyObject *doTransform = Py_True;
PyObject* pyMat = nullptr;
PyObject* doTransform = Py_True;
short depth = 0;
static const std::array<const char *, 6> kwlist {"subname", "retType", "matrix", "transform", "depth", nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "O|hO!O!h", kwlist, &obj, &retType, &Base::MatrixPy::Type,
&pyMat, &PyBool_Type, &doTransform, &depth)) {
static const std::array<const char*, 6> kwlist {"subname",
"retType",
"matrix",
"transform",
"depth",
nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args,
keywds,
"O|hO!O!h",
kwlist,
&obj,
&retType,
&Base::MatrixPy::Type,
&pyMat,
&PyBool_Type,
&doTransform,
&depth)) {
return nullptr;
}
if (retType < 0 || static_cast<size_t> (retType) > kwlist.size()) {
if (retType < 0 || static_cast<size_t>(retType) > kwlist.size()) {
PyErr_SetString(PyExc_ValueError, "invalid retType, can only be integer 0~6");
return nullptr;
}
@@ -482,12 +554,15 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
bool transform = Base::asBoolean(doTransform);
struct SubInfo {
App::DocumentObject *sobj{nullptr};
struct SubInfo
{
App::DocumentObject* sobj {nullptr};
Py::Object obj;
Py::Object pyObj;
Base::Matrix4D mat;
explicit SubInfo(const Base::Matrix4D &mat) : mat(mat){}
explicit SubInfo(const Base::Matrix4D& mat)
: mat(mat)
{}
};
Base::Matrix4D mat;
@@ -495,50 +570,66 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
}
PY_TRY {
PY_TRY
{
std::vector<SubInfo> ret;
for(const auto &sub : subs) {
for (const auto& sub : subs) {
ret.emplace_back(mat);
auto &info = ret.back();
PyObject *pyObj = nullptr;
auto& info = ret.back();
PyObject* pyObj = nullptr;
info.sobj = getDocumentObjectPtr()->getSubObject(sub.c_str(),
retEnum != ReturnType::PyObject &&
retEnum != ReturnType::DocAndPyObject ? nullptr : &pyObj,
&info.mat, transform, depth);
if (pyObj)
info.sobj = getDocumentObjectPtr()->getSubObject(
sub.c_str(),
retEnum != ReturnType::PyObject && retEnum != ReturnType::DocAndPyObject ? nullptr
: &pyObj,
&info.mat,
transform,
depth);
if (pyObj) {
info.pyObj = Py::asObject(pyObj);
if (info.sobj)
}
if (info.sobj) {
info.obj = Py::asObject(info.sobj->getPyObject());
}
}
if (ret.empty())
if (ret.empty()) {
Py_Return;
}
auto getReturnValue = [retEnum, pyMat](SubInfo& ret) -> Py::Object {
if (retEnum == ReturnType::PyObject)
if (retEnum == ReturnType::PyObject) {
return ret.pyObj;
else if (retEnum == ReturnType::DocObject && !pyMat)
}
else if (retEnum == ReturnType::DocObject && !pyMat) {
return ret.obj;
else if (!ret.sobj)
}
else if (!ret.sobj) {
return Py::None();
else if (retEnum == ReturnType::Placement)
}
else if (retEnum == ReturnType::Placement) {
return Py::Placement(Base::Placement(ret.mat));
else if (retEnum == ReturnType::Matrix)
}
else if (retEnum == ReturnType::Matrix) {
return Py::Matrix(ret.mat);
else if (retEnum == ReturnType::LinkAndPlacement || retEnum == ReturnType::LinkAndMatrix) {
}
else if (retEnum == ReturnType::LinkAndPlacement
|| retEnum == ReturnType::LinkAndMatrix) {
ret.sobj->getLinkedObject(true, &ret.mat, false);
if (retEnum == ReturnType::LinkAndPlacement)
if (retEnum == ReturnType::LinkAndPlacement) {
return Py::Placement(Base::Placement(ret.mat));
else
}
else {
return Py::Matrix(ret.mat);
}
}
else {
Py::Tuple rret(retEnum == ReturnType::DocObject ? 2 : 3);
rret.setItem(0, ret.obj);
rret.setItem(1, Py::asObject(new Base::MatrixPy(ret.mat)));
if (retEnum != ReturnType::DocObject)
if (retEnum != ReturnType::DocObject) {
rret.setItem(2, ret.pyObj);
}
return rret;
}
};
@@ -548,7 +639,7 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
}
Py::Tuple tuple(ret.size());
for(size_t i=0; i<ret.size(); ++i) {
for (size_t i = 0; i < ret.size(); ++i) {
tuple.setItem(i, getReturnValue(ret[i]));
}
return Py::new_reference_to(tuple);
@@ -556,62 +647,90 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds)
PY_CATCH
}
PyObject* DocumentObjectPy::getSubObjectList(PyObject *args) {
const char *subname;
if (!PyArg_ParseTuple(args, "s", &subname))
return nullptr;
Py::List res;
PY_TRY {
for(auto o : getDocumentObjectPtr()->getSubObjectList(subname))
res.append(Py::asObject(o->getPyObject()));
return Py::new_reference_to(res);
}PY_CATCH
}
PyObject* DocumentObjectPy::getSubObjects(PyObject *args) {
int reason = 0;
if (!PyArg_ParseTuple(args, "|i", &reason))
return nullptr;
PY_TRY {
auto names = getDocumentObjectPtr()->getSubObjects(reason);
Py::Tuple pyObjs(names.size());
for(size_t i=0;i<names.size();++i)
pyObjs.setItem(i,Py::String(names[i]));
return Py::new_reference_to(pyObjs);
}PY_CATCH;
}
PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
PyObject* DocumentObjectPy::getSubObjectList(PyObject* args)
{
PyObject *recursive = Py_True;
PyObject *pyMat = Py_None;
PyObject *transform = Py_True;
short depth = 0;
static const std::array<const char *, 5> kwlist {"recursive","matrix","transform","depth", nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args, keywds, "|O!OO!h", kwlist,
&PyBool_Type, &recursive, &pyMat, &PyBool_Type, &transform, &depth)) {
const char* subname;
if (!PyArg_ParseTuple(args, "s", &subname)) {
return nullptr;
}
Py::List res;
PY_TRY
{
for (auto o : getDocumentObjectPtr()->getSubObjectList(subname)) {
res.append(Py::asObject(o->getPyObject()));
}
return Py::new_reference_to(res);
}
PY_CATCH
}
PyObject* DocumentObjectPy::getSubObjects(PyObject* args)
{
int reason = 0;
if (!PyArg_ParseTuple(args, "|i", &reason)) {
return nullptr;
}
PY_TRY {
Base::PyTypeCheck(&pyMat, &Base::MatrixPy::Type, "expect argument 'matrix' to be of type Base.Matrix");
PY_TRY
{
auto names = getDocumentObjectPtr()->getSubObjects(reason);
Py::Tuple pyObjs(names.size());
for (size_t i = 0; i < names.size(); ++i) {
pyObjs.setItem(i, Py::String(names[i]));
}
return Py::new_reference_to(pyObjs);
}
PY_CATCH;
}
PyObject* DocumentObjectPy::getLinkedObject(PyObject* args, PyObject* keywds)
{
PyObject* recursive = Py_True;
PyObject* pyMat = Py_None;
PyObject* transform = Py_True;
short depth = 0;
static const std::array<const char*, 5> kwlist {"recursive",
"matrix",
"transform",
"depth",
nullptr};
if (!Base::Wrapped_ParseTupleAndKeywords(args,
keywds,
"|O!OO!h",
kwlist,
&PyBool_Type,
&recursive,
&pyMat,
&PyBool_Type,
&transform,
&depth)) {
return nullptr;
}
PY_TRY
{
Base::PyTypeCheck(&pyMat,
&Base::MatrixPy::Type,
"expect argument 'matrix' to be of type Base.Matrix");
Base::Matrix4D _mat;
Base::Matrix4D *mat = nullptr;
Base::Matrix4D* mat = nullptr;
if (pyMat) {
_mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
mat = &_mat;
}
auto linked = getDocumentObjectPtr()->getLinkedObject(
Base::asBoolean(recursive), mat, Base::asBoolean(transform), depth);
if (!linked)
auto linked = getDocumentObjectPtr()->getLinkedObject(Base::asBoolean(recursive),
mat,
Base::asBoolean(transform),
depth);
if (!linked) {
linked = getDocumentObjectPtr();
auto pyObj = Py::Object(linked->getPyObject(),true);
}
auto pyObj = Py::Object(linked->getPyObject(), true);
if (mat) {
Py::Tuple ret(2);
ret.setItem(0,pyObj);
ret.setItem(1,Py::asObject(new Base::MatrixPy(*mat)));
ret.setItem(0, pyObj);
ret.setItem(1, Py::asObject(new Base::MatrixPy(*mat)));
return Py::new_reference_to(ret);
}
@@ -620,44 +739,56 @@ PyObject* DocumentObjectPy::getLinkedObject(PyObject *args, PyObject *keywds)
PY_CATCH;
}
PyObject* DocumentObjectPy::isElementVisible(PyObject *args)
PyObject* DocumentObjectPy::isElementVisible(PyObject* args)
{
char *element = nullptr;
if (!PyArg_ParseTuple(args, "s", &element))
char* element = nullptr;
if (!PyArg_ParseTuple(args, "s", &element)) {
return nullptr;
PY_TRY {
}
PY_TRY
{
return Py_BuildValue("h", getDocumentObjectPtr()->isElementVisible(element));
} PY_CATCH;
}
PY_CATCH;
}
PyObject* DocumentObjectPy::setElementVisible(PyObject *args)
PyObject* DocumentObjectPy::setElementVisible(PyObject* args)
{
char *element = nullptr;
PyObject *visible = Py_True;
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible))
char* element = nullptr;
PyObject* visible = Py_True;
if (!PyArg_ParseTuple(args, "s|O!", &element, &PyBool_Type, &visible)) {
return nullptr;
PY_TRY {
return Py_BuildValue("h", getDocumentObjectPtr()->setElementVisible(element, Base::asBoolean(visible)));
} PY_CATCH;
}
PY_TRY
{
return Py_BuildValue(
"h",
getDocumentObjectPtr()->setElementVisible(element, Base::asBoolean(visible)));
}
PY_CATCH;
}
PyObject* DocumentObjectPy::hasChildElement(PyObject *args)
PyObject* DocumentObjectPy::hasChildElement(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
PY_TRY {
return Py_BuildValue("O", getDocumentObjectPtr()->hasChildElement()?Py_True:Py_False);
} PY_CATCH;
}
PY_TRY
{
return Py_BuildValue("O", getDocumentObjectPtr()->hasChildElement() ? Py_True : Py_False);
}
PY_CATCH;
}
PyObject* DocumentObjectPy::getParentGroup(PyObject *args)
PyObject* DocumentObjectPy::getParentGroup(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
auto grp = GroupExtension::getGroupOfObject(getDocumentObjectPtr());
if(!grp) {
if (!grp) {
Py_INCREF(Py_None);
return Py_None;
}
@@ -668,14 +799,15 @@ PyObject* DocumentObjectPy::getParentGroup(PyObject *args)
}
}
PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
auto grp = GeoFeatureGroupExtension::getGroupOfObject(getDocumentObjectPtr());
if(!grp) {
if (!grp) {
Py_INCREF(Py_None);
return Py_None;
}
@@ -686,14 +818,15 @@ PyObject* DocumentObjectPy::getParentGeoFeatureGroup(PyObject *args)
}
}
PyObject* DocumentObjectPy::getParent(PyObject *args)
PyObject* DocumentObjectPy::getParent(PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
if (!PyArg_ParseTuple(args, "")) {
return nullptr;
}
try {
auto grp = getDocumentObjectPtr()->getFirstParent();
if(!grp) {
if (!grp) {
Py_INCREF(Py_None);
return Py_None;
}
@@ -714,15 +847,15 @@ Py::Boolean DocumentObjectPy::getMustExecute() const
}
}
PyObject* DocumentObjectPy::getPathsByOutList(PyObject *args)
PyObject* DocumentObjectPy::getPathsByOutList(PyObject* args)
{
PyObject* o;
if (!PyArg_ParseTuple(args, "O!", &DocumentObjectPy::Type, &o))
if (!PyArg_ParseTuple(args, "O!", &DocumentObjectPy::Type, &o)) {
return nullptr;
}
try {
DocumentObject* target = static_cast<DocumentObjectPy*>
(o)->getDocumentObjectPtr();
DocumentObject* target = static_cast<DocumentObjectPy*>(o)->getDocumentObjectPtr();
auto array = getDocumentObjectPtr()->getPathsByOutList(target);
Py::List list;
for (const auto& it : array) {
@@ -755,100 +888,120 @@ PyObject* DocumentObjectPy::getElementMapVersion(PyObject* args)
Py::String(getDocumentObjectPtr()->getElementMapVersion(prop, Base::asBoolean(restored))));
}
PyObject *DocumentObjectPy::getCustomAttributes(const char* ) const
PyObject* DocumentObjectPy::getCustomAttributes(const char*) const
{
return nullptr;
return nullptr;
}
//remove
int DocumentObjectPy::setCustomAttributes(const char* , PyObject *)
// remove
int DocumentObjectPy::setCustomAttributes(const char*, PyObject*)
{
return 0;
}
Py::Int DocumentObjectPy::getID() const {
Py::Int DocumentObjectPy::getID() const
{
return Py::Int(getDocumentObjectPtr()->getID());
}
Py::Boolean DocumentObjectPy::getRemoving() const {
Py::Boolean DocumentObjectPy::getRemoving() const
{
return {getDocumentObjectPtr()->testStatus(ObjectStatus::Remove)};
}
PyObject *DocumentObjectPy::resolve(PyObject *args)
PyObject* DocumentObjectPy::resolve(PyObject* args)
{
const char *subname;
if (!PyArg_ParseTuple(args, "s",&subname))
const char* subname;
if (!PyArg_ParseTuple(args, "s", &subname)) {
return nullptr;
}
PY_TRY {
PY_TRY
{
std::string elementName;
const char *subElement = nullptr;
App::DocumentObject *parent = nullptr;
auto obj = getDocumentObjectPtr()->resolve(subname,&parent,&elementName,&subElement);
const char* subElement = nullptr;
App::DocumentObject* parent = nullptr;
auto obj = getDocumentObjectPtr()->resolve(subname, &parent, &elementName, &subElement);
Py::Tuple ret(4);
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
ret.setItem(1,parent?Py::Object(parent->getPyObject(),true):Py::None());
ret.setItem(2,Py::String(elementName.c_str()));
ret.setItem(3,Py::String(subElement?subElement:""));
ret.setItem(0, obj ? Py::Object(obj->getPyObject(), true) : Py::None());
ret.setItem(1, parent ? Py::Object(parent->getPyObject(), true) : Py::None());
ret.setItem(2, Py::String(elementName.c_str()));
ret.setItem(3, Py::String(subElement ? subElement : ""));
return Py::new_reference_to(ret);
} PY_CATCH;
}
PY_CATCH;
Py_Return;
}
PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
PyObject* DocumentObjectPy::resolveSubElement(PyObject* args)
{
const char *subname;
PyObject *append = Py_False;
const char* subname;
PyObject* append = Py_False;
int type = 0;
if (!PyArg_ParseTuple(args, "s|O!i",&subname,&PyBool_Type,&append,&type))
if (!PyArg_ParseTuple(args, "s|O!i", &subname, &PyBool_Type, &append, &type)) {
return nullptr;
}
PY_TRY {
PY_TRY
{
ElementNamePair elementName;
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
Base::asBoolean(append), static_cast<GeoFeature::ElementNameType>(type));
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(),
subname,
elementName,
Base::asBoolean(append),
static_cast<GeoFeature::ElementNameType>(type));
Py::Tuple ret(3);
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
ret.setItem(1,Py::String(elementName.newName));
ret.setItem(2,Py::String(elementName.oldName));
ret.setItem(0, obj ? Py::Object(obj->getPyObject(), true) : Py::None());
ret.setItem(1, Py::String(elementName.newName));
ret.setItem(2, Py::String(elementName.oldName));
return Py::new_reference_to(ret);
} PY_CATCH;
}
PY_CATCH;
Py_Return;
}
Py::List DocumentObjectPy::getParents() const {
Py::List DocumentObjectPy::getParents() const
{
Py::List ret;
for(auto &v : getDocumentObjectPtr()->getParents())
ret.append(Py::TupleN(Py::Object(v.first->getPyObject(),true),Py::String(v.second)));
for (auto& v : getDocumentObjectPtr()->getParents()) {
ret.append(Py::TupleN(Py::Object(v.first->getPyObject(), true), Py::String(v.second)));
}
return ret;
}
PyObject *DocumentObjectPy::adjustRelativeLinks(PyObject *args) {
PyObject *pyobj;
PyObject *recursive = Py_True;
if (!PyArg_ParseTuple(args, "O!|O",&DocumentObjectPy::Type,&pyobj,&recursive))
PyObject* DocumentObjectPy::adjustRelativeLinks(PyObject* args)
{
PyObject* pyobj;
PyObject* recursive = Py_True;
if (!PyArg_ParseTuple(args, "O!|O", &DocumentObjectPy::Type, &pyobj, &recursive)) {
return nullptr;
PY_TRY {
}
PY_TRY
{
auto obj = static_cast<DocumentObjectPy*>(pyobj)->getDocumentObjectPtr();
auto inList = obj->getInListEx(true);
inList.insert(obj);
std::set<App::DocumentObject *> visited;
return Py::new_reference_to(Py::Boolean(
getDocumentObjectPtr()->adjustRelativeLinks(inList,
Base::asBoolean(recursive) ? &visited : nullptr)));
}PY_CATCH
std::set<App::DocumentObject*> visited;
return Py::new_reference_to(Py::Boolean(getDocumentObjectPtr()->adjustRelativeLinks(
inList,
Base::asBoolean(recursive) ? &visited : nullptr)));
}
PY_CATCH
}
Py::String DocumentObjectPy::getOldLabel() const {
Py::String DocumentObjectPy::getOldLabel() const
{
return {getDocumentObjectPtr()->getOldLabel()};
}
Py::Boolean DocumentObjectPy::getNoTouch() const {
Py::Boolean DocumentObjectPy::getNoTouch() const
{
return {getDocumentObjectPtr()->testStatus(ObjectStatus::NoTouch)};
}
void DocumentObjectPy::setNoTouch(Py::Boolean value) {
getDocumentObjectPtr()->setStatus(ObjectStatus::NoTouch,value.isTrue());
void DocumentObjectPy::setNoTouch(Py::Boolean value)
{
getDocumentObjectPtr()->setStatus(ObjectStatus::NoTouch, value.isTrue());
}
+247 -198
View File
@@ -57,8 +57,9 @@ DocumentT::~DocumentT() = default;
void DocumentT::operator=(const DocumentT& doc)
{
if (this == &doc)
if (this == &doc) {
return;
}
document = doc.document;
}
@@ -77,7 +78,7 @@ Document* DocumentT::getDocument() const
return GetApplication().getDocument(document.c_str());
}
const std::string &DocumentT::getDocumentName() const
const std::string& DocumentT::getDocumentName() const
{
return document;
}
@@ -93,12 +94,12 @@ std::string DocumentT::getDocumentPython() const
DocumentObjectT::DocumentObjectT() = default;
DocumentObjectT::DocumentObjectT(const DocumentObjectT &other)
DocumentObjectT::DocumentObjectT(const DocumentObjectT& other)
{
*this = other;
}
DocumentObjectT::DocumentObjectT(DocumentObjectT &&other)
DocumentObjectT::DocumentObjectT(DocumentObjectT&& other)
{
*this = std::move(other);
}
@@ -115,25 +116,29 @@ DocumentObjectT::DocumentObjectT(const Property* prop)
DocumentObjectT::DocumentObjectT(const Document* doc, const std::string& objName)
{
if (doc && doc->getName())
if (doc && doc->getName()) {
document = doc->getName();
}
object = objName;
}
DocumentObjectT::DocumentObjectT(const char *docName, const char *objName)
DocumentObjectT::DocumentObjectT(const char* docName, const char* objName)
{
if(docName)
if (docName) {
document = docName;
if(objName)
}
if (objName) {
object = objName;
}
}
DocumentObjectT::~DocumentObjectT() = default;
DocumentObjectT &DocumentObjectT::operator=(const DocumentObjectT& obj)
DocumentObjectT& DocumentObjectT::operator=(const DocumentObjectT& obj)
{
if (this == &obj)
if (this == &obj) {
return *this;
}
object = obj.object;
label = obj.label;
document = obj.document;
@@ -141,10 +146,11 @@ DocumentObjectT &DocumentObjectT::operator=(const DocumentObjectT& obj)
return *this;
}
DocumentObjectT &DocumentObjectT::operator=(DocumentObjectT&& obj)
DocumentObjectT& DocumentObjectT::operator=(DocumentObjectT&& obj)
{
if (this == &obj)
if (this == &obj) {
return *this;
}
object = std::move(obj.object);
label = std::move(obj.label);
document = std::move(obj.document);
@@ -154,12 +160,13 @@ DocumentObjectT &DocumentObjectT::operator=(DocumentObjectT&& obj)
void DocumentObjectT::operator=(const DocumentObject* obj)
{
if(!obj || !obj->isAttachedToDocument()) {
if (!obj || !obj->isAttachedToDocument()) {
object.clear();
label.clear();
document.clear();
property.clear();
} else {
}
else {
object = obj->getNameInDocument();
label = obj->Label.getValue();
document = obj->getDocument()->getName();
@@ -167,16 +174,16 @@ void DocumentObjectT::operator=(const DocumentObject* obj)
}
}
void DocumentObjectT::operator=(const Property *prop) {
if(!prop || !prop->hasName()
|| !prop->getContainer()
|| !prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
{
void DocumentObjectT::operator=(const Property* prop)
{
if (!prop || !prop->hasName() || !prop->getContainer()
|| !prop->getContainer()->isDerivedFrom(App::DocumentObject::getClassTypeId())) {
object.clear();
label.clear();
document.clear();
property.clear();
} else {
}
else {
auto obj = static_cast<App::DocumentObject*>(prop->getContainer());
object = obj->getNameInDocument();
label = obj->Label.getValue();
@@ -185,10 +192,9 @@ void DocumentObjectT::operator=(const Property *prop) {
}
}
bool DocumentObjectT::operator==(const DocumentObjectT &other) const {
return document == other.document
&& object == other.object
&& label == other.label
bool DocumentObjectT::operator==(const DocumentObjectT& other) const
{
return document == other.document && object == other.object && label == other.label
&& property == other.property;
}
@@ -219,12 +225,12 @@ DocumentObject* DocumentObjectT::getObject() const
return obj;
}
const std::string &DocumentObjectT::getObjectName() const
const std::string& DocumentObjectT::getObjectName() const
{
return object;
}
const std::string &DocumentObjectT::getObjectLabel() const
const std::string& DocumentObjectT::getObjectLabel() const
{
return label;
}
@@ -236,7 +242,8 @@ std::string DocumentObjectT::getObjectPython() const
return str.str();
}
const std::string &DocumentObjectT::getPropertyName() const {
const std::string& DocumentObjectT::getPropertyName() const
{
return property;
}
@@ -244,15 +251,18 @@ std::string DocumentObjectT::getPropertyPython() const
{
std::stringstream str;
str << getObjectPython();
if (!property.empty())
if (!property.empty()) {
str << '.' << property;
}
return str.str();
}
Property *DocumentObjectT::getProperty() const {
Property* DocumentObjectT::getProperty() const
{
auto obj = getObject();
if(obj)
if (obj) {
return obj->getPropertyByName(property.c_str());
}
return nullptr;
}
@@ -260,86 +270,95 @@ Property *DocumentObjectT::getProperty() const {
SubObjectT::SubObjectT() = default;
SubObjectT::SubObjectT(const SubObjectT &) = default;
SubObjectT::SubObjectT(const SubObjectT&) = default;
SubObjectT::SubObjectT(SubObjectT &&other)
:DocumentObjectT(std::move(other)), subname(std::move(other.subname))
SubObjectT::SubObjectT(SubObjectT&& other)
: DocumentObjectT(std::move(other))
, subname(std::move(other.subname))
{}
SubObjectT::SubObjectT(const DocumentObject* obj, const char* s)
: DocumentObjectT(obj)
, subname(s ? s : "")
{}
SubObjectT::SubObjectT(const DocumentObject* obj)
: DocumentObjectT(obj)
{}
SubObjectT::SubObjectT(const DocumentObjectT& obj, const char* s)
: DocumentObjectT(obj)
, subname(s ? s : "")
{}
SubObjectT::SubObjectT(const char* docName, const char* objName, const char* s)
: DocumentObjectT(docName, objName)
, subname(s ? s : "")
{}
bool SubObjectT::operator<(const SubObjectT& other) const
{
}
SubObjectT::SubObjectT(const DocumentObject *obj, const char *s)
:DocumentObjectT(obj),subname(s?s:"")
{
}
SubObjectT::SubObjectT(const DocumentObject *obj)
:DocumentObjectT(obj)
{
}
SubObjectT::SubObjectT(const DocumentObjectT& obj, const char *s)
:DocumentObjectT(obj),subname(s?s:"")
{
}
SubObjectT::SubObjectT(const char *docName, const char *objName, const char *s)
:DocumentObjectT(docName,objName), subname(s?s:"")
{
}
bool SubObjectT::operator<(const SubObjectT &other) const {
if(getDocumentName() < other.getDocumentName())
if (getDocumentName() < other.getDocumentName()) {
return true;
if(getDocumentName() > other.getDocumentName())
}
if (getDocumentName() > other.getDocumentName()) {
return false;
if(getObjectName() < other.getObjectName())
}
if (getObjectName() < other.getObjectName()) {
return true;
if(getObjectName() > other.getObjectName())
}
if (getObjectName() > other.getObjectName()) {
return false;
if(getSubName() < other.getSubName())
}
if (getSubName() < other.getSubName()) {
return true;
if(getSubName() > other.getSubName())
}
if (getSubName() > other.getSubName()) {
return false;
}
return getPropertyName() < other.getPropertyName();
}
SubObjectT &SubObjectT::operator=(const SubObjectT& other)
SubObjectT& SubObjectT::operator=(const SubObjectT& other)
{
if (this == &other)
if (this == &other) {
return *this;
}
static_cast<DocumentObjectT&>(*this) = other;
subname = other.subname;
return *this;
}
SubObjectT &SubObjectT::operator=(SubObjectT &&other)
SubObjectT& SubObjectT::operator=(SubObjectT&& other)
{
if (this == &other)
if (this == &other) {
return *this;
}
static_cast<DocumentObjectT&>(*this) = std::move(other);
subname = std::move(other.subname);
return *this;
}
SubObjectT &SubObjectT::operator=(const DocumentObjectT &other)
SubObjectT& SubObjectT::operator=(const DocumentObjectT& other)
{
if (this == &other)
if (this == &other) {
return *this;
}
static_cast<DocumentObjectT&>(*this) = other;
subname.clear();
return *this;
}
SubObjectT &SubObjectT::operator=(const DocumentObject *other)
SubObjectT& SubObjectT::operator=(const DocumentObject* other)
{
static_cast<DocumentObjectT&>(*this) = other;
subname.clear();
return *this;
}
bool SubObjectT::operator==(const SubObjectT &other) const {
return static_cast<const DocumentObjectT&>(*this) == other
&& subname == other.subname;
bool SubObjectT::operator==(const SubObjectT& other) const
{
return static_cast<const DocumentObjectT&>(*this) == other && subname == other.subname;
}
namespace
@@ -430,19 +449,23 @@ SubObjectT App::SubObjectT::normalized(NormalizeOptions options) const
return res;
}
void SubObjectT::setSubName(const char *s) {
subname = s?s:"";
void SubObjectT::setSubName(const char* s)
{
subname = s ? s : "";
}
const std::string &SubObjectT::getSubName() const {
const std::string& SubObjectT::getSubName() const
{
return subname;
}
std::string SubObjectT::getSubNameNoElement() const {
std::string SubObjectT::getSubNameNoElement() const
{
return Data::noElementName(subname.c_str());
}
const char *SubObjectT::getElementName() const {
const char* SubObjectT::getElementName() const
{
return Data::findElementName(subname.c_str());
}
@@ -457,90 +480,107 @@ bool SubObjectT::hasSubElement() const
return element && (element[0] != '\0');
}
std::string SubObjectT::getNewElementName() const {
std::string SubObjectT::getNewElementName() const
{
ElementNamePair element;
auto obj = getObject();
if(!obj)
if (!obj) {
return {};
GeoFeature::resolveElement(obj,subname.c_str(),element);
}
GeoFeature::resolveElement(obj, subname.c_str(), element);
return std::move(element.newName);
}
std::string SubObjectT::getOldElementName(int *index) const {
std::string SubObjectT::getOldElementName(int* index) const
{
ElementNamePair element;
auto obj = getObject();
if(!obj)
if (!obj) {
return {};
GeoFeature::resolveElement(obj,subname.c_str(),element);
if(!index)
}
GeoFeature::resolveElement(obj, subname.c_str(), element);
if (!index) {
return std::move(element.oldName);
}
std::size_t pos = element.oldName.find_first_of("0123456789");
if(pos == std::string::npos)
if (pos == std::string::npos) {
*index = -1;
}
else {
*index = std::atoi(element.oldName.c_str()+pos);
*index = std::atoi(element.oldName.c_str() + pos);
element.oldName.resize(pos);
}
return std::move(element.oldName);
}
App::DocumentObject *SubObjectT::getSubObject() const {
App::DocumentObject* SubObjectT::getSubObject() const
{
auto obj = getObject();
if(obj)
if (obj) {
return obj->getSubObject(subname.c_str());
}
return nullptr;
}
std::string SubObjectT::getSubObjectPython(bool force) const {
if(!force && subname.empty())
std::string SubObjectT::getSubObjectPython(bool force) const
{
if (!force && subname.empty()) {
return getObjectPython();
}
std::stringstream str;
str << "(" << getObjectPython() << ",u'"
<< Base::Tools::escapedUnicodeFromUtf8(subname.c_str()) << "')";
str << "(" << getObjectPython() << ",u'" << Base::Tools::escapedUnicodeFromUtf8(subname.c_str())
<< "')";
return str.str();
}
std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const {
std::vector<App::DocumentObject*> SubObjectT::getSubObjectList() const
{
auto obj = getObject();
if(obj)
if (obj) {
return obj->getSubObjectList(subname.c_str());
}
return {};
}
std::string SubObjectT::getObjectFullName(const char *docName) const
std::string SubObjectT::getObjectFullName(const char* docName) const
{
std::ostringstream ss;
if (!docName || getDocumentName() != docName) {
ss << getDocumentName();
if (auto doc = getDocument()) {
if (doc->Label.getStrValue() != getDocumentName())
if (doc->Label.getStrValue() != getDocumentName()) {
ss << "(" << doc->Label.getValue() << ")";
}
}
ss << "#";
}
ss << getObjectName();
if (!getObjectLabel().empty() && getObjectLabel() != getObjectName())
if (!getObjectLabel().empty() && getObjectLabel() != getObjectName()) {
ss << " (" << getObjectLabel() << ")";
}
return ss.str();
}
std::string SubObjectT::getSubObjectFullName(const char *docName) const
std::string SubObjectT::getSubObjectFullName(const char* docName) const
{
if (subname.empty())
if (subname.empty()) {
return getObjectFullName(docName);
}
std::ostringstream ss;
if (!docName || getDocumentName() != docName) {
ss << getDocumentName();
if (auto doc = getDocument()) {
if (doc->Label.getStrValue() != getDocumentName())
if (doc->Label.getStrValue() != getDocumentName()) {
ss << "(" << doc->Label.getValue() << ")";
}
}
ss << "#";
}
ss << getObjectName() << "." << subname;
auto sobj = getSubObject();
if (sobj && sobj->Label.getStrValue() != sobj->getNameInDocument())
if (sobj && sobj->Label.getStrValue() != sobj->getNameInDocument()) {
ss << " (" << sobj->Label.getValue() << ")";
}
return ss.str();
}
@@ -548,10 +588,9 @@ std::string SubObjectT::getSubObjectFullName(const char *docName) const
PropertyLinkT::PropertyLinkT()
: toPython("None")
{
}
{}
PropertyLinkT::PropertyLinkT(DocumentObject *obj)
PropertyLinkT::PropertyLinkT(DocumentObject* obj)
: PropertyLinkT()
{
if (obj) {
@@ -563,15 +602,16 @@ PropertyLinkT::PropertyLinkT(DocumentObject *obj)
}
}
PropertyLinkT::PropertyLinkT(DocumentObject *obj, const std::vector<std::string>& subNames)
PropertyLinkT::PropertyLinkT(DocumentObject* obj, const std::vector<std::string>& subNames)
: PropertyLinkT()
{
if (obj) {
std::ostringstream str;
DocumentObjectT objT(obj);
str << "(" << objT.getObjectPython() << ",[";
for(const auto& it : subNames)
for (const auto& it : subNames) {
str << "'" << it << "',";
}
str << "])";
toPython = str.str();
@@ -585,8 +625,9 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs)
std::stringstream str;
str << "[";
for (std::size_t i = 0; i < objs.size(); i++) {
if (i > 0)
if (i > 0) {
str << ", ";
}
App::DocumentObject* obj = objs[i];
if (obj) {
@@ -602,17 +643,20 @@ PropertyLinkT::PropertyLinkT(const std::vector<DocumentObject*>& objs)
}
}
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()) {
std::stringstream str;
str << "[";
for (std::size_t i = 0; i < subNames.size(); i++) {
if (i>0)
if (i > 0) {
str << ",(";
else
}
else {
str << "(";
}
App::DocumentObject* obj = objs[i];
if (obj) {
@@ -639,22 +683,28 @@ std::string PropertyLinkT::getPropertyPython() const
// -----------------------------------------------------------------------------
class DocumentWeakPtrT::Private {
class DocumentWeakPtrT::Private
{
public:
explicit Private(App::Document* doc) : _document(doc) {
explicit Private(App::Document* doc)
: _document(doc)
{
if (doc) {
//NOLINTBEGIN
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
(&Private::deletedDocument, this, sp::_1));
//NOLINTEND
// NOLINTBEGIN
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
std::bind(&Private::deletedDocument, this, sp::_1));
// NOLINTEND
}
}
void deletedDocument(const App::Document& doc) {
if (_document == &doc)
void deletedDocument(const App::Document& doc)
{
if (_document == &doc) {
reset();
}
}
void reset() {
void reset()
{
connectApplicationDeletedDocument.disconnect();
_document = nullptr;
}
@@ -665,9 +715,8 @@ public:
};
DocumentWeakPtrT::DocumentWeakPtrT(App::Document* doc) noexcept
: d(new Private(doc))
{
}
: d(new Private(doc))
{}
DocumentWeakPtrT::~DocumentWeakPtrT() = default;
@@ -693,56 +742,65 @@ App::Document* DocumentWeakPtrT::operator->() const noexcept
// -----------------------------------------------------------------------------
class DocumentObjectWeakPtrT::Private {
class DocumentObjectWeakPtrT::Private
{
public:
explicit Private(App::DocumentObject* obj) : object(obj) {
explicit Private(App::DocumentObject* obj)
: object(obj)
{
set(obj);
}
void deletedDocument(const App::Document& doc) {
void deletedDocument(const App::Document& doc)
{
// When deleting document then there is no way to undo it
if (object && object->getDocument() == &doc) {
reset();
}
}
void createdObject(const App::DocumentObject& obj) noexcept {
void createdObject(const App::DocumentObject& obj) noexcept
{
// When undoing the removal
if (object == &obj) {
indocument = true;
}
}
void deletedObject(const App::DocumentObject& obj) noexcept {
void deletedObject(const App::DocumentObject& obj) noexcept
{
if (object == &obj) {
indocument = false;
}
}
void reset() {
void reset()
{
connectApplicationDeletedDocument.disconnect();
connectDocumentCreatedObject.disconnect();
connectDocumentDeletedObject.disconnect();
object = nullptr;
indocument = false;
}
void set(App::DocumentObject* obj) {
void set(App::DocumentObject* obj)
{
object = obj;
if (obj) {
//NOLINTBEGIN
// NOLINTBEGIN
indocument = true;
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
(&Private::deletedDocument, this, sp::_1));
connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
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));
//NOLINTEND
connectDocumentCreatedObject =
doc->signalNewObject.connect(std::bind(&Private::createdObject, this, sp::_1));
connectDocumentDeletedObject =
doc->signalDeletedObject.connect(std::bind(&Private::deletedObject, this, sp::_1));
// NOLINTEND
}
}
App::DocumentObject* get() const noexcept {
App::DocumentObject* get() const noexcept
{
return indocument ? object : nullptr;
}
App::DocumentObject* object;
bool indocument{false};
bool indocument {false};
using Connection = boost::signals2::scoped_connection;
Connection connectApplicationDeletedDocument;
Connection connectDocumentCreatedObject;
@@ -750,9 +808,8 @@ public:
};
DocumentObjectWeakPtrT::DocumentObjectWeakPtrT(App::DocumentObject* obj)
: d(new Private(obj))
{
}
: d(new Private(obj))
{}
DocumentObjectWeakPtrT::~DocumentObjectWeakPtrT() = default;
@@ -771,7 +828,7 @@ bool DocumentObjectWeakPtrT::expired() const noexcept
return !d->indocument;
}
DocumentObjectWeakPtrT& DocumentObjectWeakPtrT::operator= (App::DocumentObject* p)
DocumentObjectWeakPtrT& DocumentObjectWeakPtrT::operator=(App::DocumentObject* p)
{
d->reset();
d->set(p);
@@ -788,31 +845,33 @@ App::DocumentObject* DocumentObjectWeakPtrT::operator->() const noexcept
return d->get();
}
bool DocumentObjectWeakPtrT::operator== (const DocumentObjectWeakPtrT& p) const noexcept
bool DocumentObjectWeakPtrT::operator==(const DocumentObjectWeakPtrT& p) const noexcept
{
return d->get() == p.d->get();
}
bool DocumentObjectWeakPtrT::operator!= (const DocumentObjectWeakPtrT& p) const noexcept
bool DocumentObjectWeakPtrT::operator!=(const DocumentObjectWeakPtrT& p) const noexcept
{
return d->get() != p.d->get();
}
// -----------------------------------------------------------------------------
DocumentObserver::DocumentObserver() : _document(nullptr)
DocumentObserver::DocumentObserver()
: _document(nullptr)
{
//NOLINTBEGIN
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(std::bind
(&DocumentObserver::slotCreatedDocument, this, sp::_1));
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(std::bind
(&DocumentObserver::slotDeletedDocument, this, sp::_1));
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(std::bind
(&DocumentObserver::slotActivateDocument, this, sp::_1));
//NOLINTEND
// NOLINTBEGIN
this->connectApplicationCreatedDocument = App::GetApplication().signalNewDocument.connect(
std::bind(&DocumentObserver::slotCreatedDocument, this, sp::_1));
this->connectApplicationDeletedDocument = App::GetApplication().signalDeleteDocument.connect(
std::bind(&DocumentObserver::slotDeletedDocument, this, sp::_1));
this->connectApplicationActivateDocument = App::GetApplication().signalActiveDocument.connect(
std::bind(&DocumentObserver::slotActivateDocument, this, sp::_1));
// NOLINTEND
}
DocumentObserver::DocumentObserver(Document* doc) : DocumentObserver()
DocumentObserver::DocumentObserver(Document* doc)
: DocumentObserver()
{
// Connect to application and given document
attachDocument(doc);
@@ -838,18 +897,18 @@ void DocumentObserver::attachDocument(Document* doc)
detachDocument();
_document = doc;
//NOLINTBEGIN
this->connectDocumentCreatedObject = _document->signalNewObject.connect(std::bind
(&DocumentObserver::slotCreatedObject, this, sp::_1));
this->connectDocumentDeletedObject = _document->signalDeletedObject.connect(std::bind
(&DocumentObserver::slotDeletedObject, this, sp::_1));
this->connectDocumentChangedObject = _document->signalChangedObject.connect(std::bind
(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2));
this->connectDocumentRecomputedObject = _document->signalRecomputedObject.connect(std::bind
(&DocumentObserver::slotRecomputedObject, this, sp::_1));
this->connectDocumentRecomputed = _document->signalRecomputed.connect(std::bind
(&DocumentObserver::slotRecomputedDocument, this, sp::_1));
//NOLINTEND
// NOLINTBEGIN
this->connectDocumentCreatedObject = _document->signalNewObject.connect(
std::bind(&DocumentObserver::slotCreatedObject, this, sp::_1));
this->connectDocumentDeletedObject = _document->signalDeletedObject.connect(
std::bind(&DocumentObserver::slotDeletedObject, this, sp::_1));
this->connectDocumentChangedObject = _document->signalChangedObject.connect(
std::bind(&DocumentObserver::slotChangedObject, this, sp::_1, sp::_2));
this->connectDocumentRecomputedObject = _document->signalRecomputedObject.connect(
std::bind(&DocumentObserver::slotRecomputedObject, this, sp::_1));
this->connectDocumentRecomputed = _document->signalRecomputed.connect(
std::bind(&DocumentObserver::slotRecomputedDocument, this, sp::_1));
// NOLINTEND
}
}
@@ -866,36 +925,29 @@ void DocumentObserver::detachDocument()
}
void DocumentObserver::slotCreatedDocument(const App::Document& /*Doc*/)
{
}
{}
void DocumentObserver::slotDeletedDocument(const App::Document& /*Doc*/)
{
}
{}
void DocumentObserver::slotActivateDocument(const App::Document& /*Doc*/)
{
}
{}
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*/)
{
}
{}
void DocumentObserver::slotRecomputedDocument(const Document& /*doc*/)
{
}
{}
// -----------------------------------------------------------------------------
@@ -925,8 +977,7 @@ void DocumentObjectObserver::removeFromObservation(App::DocumentObject* obj)
}
void DocumentObjectObserver::slotCreatedDocument(const App::Document&)
{
}
{}
void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
{
@@ -938,24 +989,22 @@ void DocumentObjectObserver::slotDeletedDocument(const App::Document& Doc)
}
void DocumentObjectObserver::slotCreatedObject(const App::DocumentObject&)
{
}
{}
void DocumentObjectObserver::slotDeletedObject(const App::DocumentObject& Obj)
{
std::set<App::DocumentObject*>::iterator it = _objects.find
(const_cast<App::DocumentObject*>(&Obj));
if (it != _objects.end())
std::set<App::DocumentObject*>::iterator it =
_objects.find(const_cast<App::DocumentObject*>(&Obj));
if (it != _objects.end()) {
_objects.erase(it);
if (_objects.empty())
}
if (_objects.empty()) {
cancelObservation();
}
}
void DocumentObjectObserver::slotChangedObject(const App::DocumentObject&,
const App::Property&)
{
}
void DocumentObjectObserver::slotChangedObject(const App::DocumentObject&, const App::Property&)
{}
void DocumentObjectObserver::cancelObservation()
{
}
{}
+75 -62
View File
@@ -51,7 +51,7 @@ public:
/*! Constructor */
DocumentT();
/*! Constructor */
DocumentT(Document*); // explicit bombs
DocumentT(Document*); // explicit bombs
/*! Constructor */
explicit DocumentT(const std::string&);
/*! Constructor */
@@ -65,18 +65,20 @@ public:
/*! Assignment operator */
void operator=(const std::string&);
bool operator==(const DocumentT &other) const {
bool operator==(const DocumentT& other) const
{
return document == other.document;
}
bool operator<(const DocumentT &other) const {
bool operator<(const DocumentT& other) const
{
return document < other.document;
}
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
Document* getDocument() const;
/*! Get the name of the document. */
const std::string &getDocumentName() const;
const std::string& getDocumentName() const;
/*! Get the document as Python command. */
std::string getDocumentPython() const;
@@ -85,9 +87,9 @@ private:
};
/**
* The DocumentObjectT class is a helper class to store the names of a document object and its document.
* This can be useful when you cannot rely on that the document or the object still exists when you have to
* access it.
* The DocumentObjectT class is a helper class to store the names of a document object and its
* document. This can be useful when you cannot rely on that the document or the object still exists
* when you have to access it.
*
* @author Werner Mayer
*/
@@ -97,23 +99,23 @@ public:
/*! Constructor */
DocumentObjectT();
/*! Constructor */
DocumentObjectT(const DocumentObjectT &);
DocumentObjectT(const DocumentObjectT&);
/*! Constructor */
DocumentObjectT(DocumentObjectT &&);
DocumentObjectT(DocumentObjectT&&);
/*! Constructor */
explicit DocumentObjectT(const DocumentObject*);
/*! Constructor */
DocumentObjectT(const Document*, const std::string& objName);
/*! Constructor */
DocumentObjectT(const char *docName, const char *objName);
DocumentObjectT(const char* docName, const char* objName);
/*! Constructor */
explicit DocumentObjectT(const Property*);
/*! Destructor */
~DocumentObjectT();
/*! Assignment operator */
DocumentObjectT &operator=(const DocumentObjectT&);
DocumentObjectT& operator=(const DocumentObjectT&);
/*! Assignment operator */
DocumentObjectT &operator=(DocumentObjectT &&);
DocumentObjectT& operator=(DocumentObjectT&&);
/*! Assignment operator */
void operator=(const DocumentObject*);
/*! Assignment operator */
@@ -124,7 +126,7 @@ public:
/*! Get a pointer to the document or 0 if it doesn't exist any more. */
Document* getDocument() const;
/*! Get the name of the document. */
const std::string &getDocumentName() const;
const std::string& getDocumentName() const;
/*! Get the document as Python command. */
std::string getDocumentPython() const;
/*! Get a pointer to the document object or 0 if it doesn't exist any more. */
@@ -132,16 +134,17 @@ public:
/*! Get a pointer to the property or 0 if it doesn't exist any more. */
Property* getProperty() const;
/*! Get the name of the document object. */
const std::string &getObjectName() const;
const std::string& getObjectName() const;
/*! Get the label of the document object. */
const std::string &getObjectLabel() const;
const std::string& getObjectLabel() const;
/*! Get the name of the property. */
const std::string &getPropertyName() const;
const std::string& getPropertyName() const;
/*! Get the document object as Python command. */
std::string getObjectPython() const;
/*! Get the property as Python command. */
std::string getPropertyPython() const;
/*! Get a pointer to the document or 0 if it doesn't exist any more or the type doesn't match. */
/*! Get a pointer to the document or 0 if it doesn't exist any more or the type doesn't match.
*/
template<typename T>
inline T* getObjectAs() const
{
@@ -160,72 +163,73 @@ private:
std::string property;
};
class AppExport SubObjectT : public DocumentObjectT
class AppExport SubObjectT: public DocumentObjectT
{
public:
/*! Constructor */
SubObjectT();
/*! Constructor */
SubObjectT(const SubObjectT &);
SubObjectT(const SubObjectT&);
/*! Constructor */
SubObjectT(SubObjectT &&);
SubObjectT(SubObjectT&&);
/*! Constructor */
SubObjectT(const DocumentObjectT & obj, const char *subname);
SubObjectT(const DocumentObjectT& obj, const char* subname);
/*! Constructor */
SubObjectT(const DocumentObject*, const char *subname);
SubObjectT(const DocumentObject*, const char* subname);
/*! Constructor */
SubObjectT(const DocumentObject*);// explicit bombs
SubObjectT(const DocumentObject*); // explicit bombs
/*! Constructor */
SubObjectT(const char *docName, const char *objName, const char *subname);
SubObjectT(const char* docName, const char* objName, const char* subname);
/*! Assignment operator */
SubObjectT &operator=(const SubObjectT&);
SubObjectT& operator=(const SubObjectT&);
/*! Assignment operator */
SubObjectT &operator=(SubObjectT &&);
SubObjectT& operator=(SubObjectT&&);
/*! Assignment operator */
SubObjectT &operator=(const DocumentObjectT&);
SubObjectT& operator=(const DocumentObjectT&);
/*! Assignment operator */
SubObjectT &operator=(const App::DocumentObject*);
SubObjectT& operator=(const App::DocumentObject*);
/*! Equality operator */
bool operator==(const SubObjectT&) const;
/// Set the subname path to the sub-object
void setSubName(const char *subname);
void setSubName(const char* subname);
/// Set the subname path to the sub-object
void setSubName(const std::string &subname) {
void setSubName(const std::string& subname)
{
setSubName(subname.c_str());
}
/// Return the subname path
const std::string &getSubName() const;
const std::string& getSubName() const;
/** Return docname#objname (label)
* @param docName: optional document name. The document prefix will only be printed
* if it is different then the given 'doc'.
*/
std::string getObjectFullName(const char *docName=nullptr) const;
std::string getObjectFullName(const char* docName = nullptr) const;
/** Return docname#objname.subname (label)
* @param doc: optional document name. The document prefix will only be printed
* if it is different then the given 'doc'.
*/
std::string getSubObjectFullName(const char *docName=nullptr) const;
std::string getSubObjectFullName(const char* docName = nullptr) const;
/// Return the subname path without sub-element
std::string getSubNameNoElement() const;
/// Return the sub-element (Face, Edge, etc) of the subname path
const char *getElementName() const;
const char* getElementName() const;
/// Check if there is any sub object reference
bool hasSubObject() const;
@@ -239,17 +243,17 @@ public:
/** Return the old style sub-element name
* @param index: if given, then return the element type, and extract the index
*/
std::string getOldElementName(int *index=nullptr) const;
std::string getOldElementName(int* index = nullptr) const;
/// Return the sub-object
DocumentObject *getSubObject() const;
DocumentObject* getSubObject() const;
/// Return all objects along the subname path
std::vector<DocumentObject *> getSubObjectList() const;
std::vector<DocumentObject*> getSubObjectList() const;
bool operator<(const SubObjectT &other) const;
bool operator<(const SubObjectT& other) const;
std::string getSubObjectPython(bool force=true) const;
std::string getSubObjectPython(bool force = true) const;
/// Options used by normalize()
enum class NormalizeOption : uint8_t
@@ -299,16 +303,17 @@ public:
PropertyLinkT();
/*! Constructor */
explicit PropertyLinkT(DocumentObject *obj);
explicit PropertyLinkT(DocumentObject* obj);
/*! Constructor */
PropertyLinkT(DocumentObject *obj, const std::vector<std::string>& subNames);
PropertyLinkT(DocumentObject* obj, const std::vector<std::string>& subNames);
/*! Constructor */
explicit PropertyLinkT(const std::vector<DocumentObject*>& objs);
/*! Constructor */
PropertyLinkT(const std::vector<DocumentObject*>& objs, const std::vector<std::string>& subNames);
PropertyLinkT(const std::vector<DocumentObject*>& objs,
const std::vector<std::string>& subNames);
/*! Get the property as Python command. */
std::string getPropertyPython() const;
@@ -379,7 +384,7 @@ public:
* \brief operator =
* Assignment operator
*/
DocumentObjectWeakPtrT& operator= (App::DocumentObject* p);
DocumentObjectWeakPtrT& operator=(App::DocumentObject* p);
/*!
* \brief operator *
* \return pointer to the document object
@@ -394,12 +399,12 @@ public:
* \brief operator ==
* \return true if both objects are equal, false otherwise
*/
bool operator== (const DocumentObjectWeakPtrT& p) const noexcept;
bool operator==(const DocumentObjectWeakPtrT& p) const noexcept;
/*!
* \brief operator !=
* \return true if both objects are inequal, false otherwise
*/
bool operator!= (const DocumentObjectWeakPtrT& p) const noexcept;
bool operator!=(const DocumentObjectWeakPtrT& p) const noexcept;
/*! Get a pointer to the object or 0 if it doesn't exist any more or the type doesn't match. */
template<typename T>
inline T* get() const noexcept
@@ -423,33 +428,37 @@ private:
/**
* @brief The WeakPtrT class
*/
template <class T>
template<class T>
class WeakPtrT
{
public:
explicit WeakPtrT(T* t) : ptr(t) {
}
explicit WeakPtrT(T* t)
: ptr(t)
{}
~WeakPtrT() = default;
/*!
* \brief reset
* Releases the reference to the managed object. After the call *this manages no object.
*/
void reset() {
void reset()
{
ptr.reset();
}
/*!
* \brief expired
* \return true if the managed object has already been deleted, false otherwise.
*/
bool expired() const {
bool expired() const
{
return ptr.expired();
}
/*!
* \brief operator =
* Assignment operator
*/
WeakPtrT<T>& operator= (T* p) {
WeakPtrT<T>& operator=(T* p)
{
ptr = p;
return *this;
}
@@ -457,28 +466,32 @@ public:
* \brief operator ->
* \return pointer to the document object
*/
T* operator*() const {
T* operator*() const
{
return ptr.get<T>();
}
/*!
* \brief operator ->
* \return pointer to the document object
*/
T* operator->() const {
T* operator->() const
{
return ptr.get<T>();
}
/*!
* \brief operator ==
* \return true if both objects are equal, false otherwise
*/
bool operator== (const WeakPtrT<T>& p) const {
bool operator==(const WeakPtrT<T>& p) const
{
return ptr == p.ptr;
}
/*!
* \brief operator !=
* \return true if both objects are inequal, false otherwise
*/
bool operator!= (const WeakPtrT<T>& p) const {
bool operator!=(const WeakPtrT<T>& p) const
{
return ptr != p.ptr;
}
/*! Get a pointer to the object or 0 if it doesn't exist any more. */
@@ -561,7 +574,7 @@ private:
*
* @author Werner Mayer
*/
class AppExport DocumentObjectObserver : public DocumentObserver
class AppExport DocumentObjectObserver: public DocumentObserver
{
public:
@@ -587,18 +600,18 @@ private:
void slotDeletedObject(const App::DocumentObject& Obj) override;
/** The property of an observed object has changed */
void slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop) override;
/** This method gets called when all observed objects are deleted or the whole document is deleted.
* This method can be re-implemented to perform an extra step like closing a dialog that observes
* a document.
*/
/** This method gets called when all observed objects are deleted or the whole document is
* deleted. This method can be re-implemented to perform an extra step like closing a dialog
* that observes a document.
*/
virtual void cancelObservation();
private:
std::set<App::DocumentObject*> _objects;
};
} //namespace App
} // namespace App
ENABLE_BITMASK_OPERATORS(App::SubObjectT::NormalizeOption)
#endif // APP_DOCUMENTOBSERVER_H
#endif // APP_DOCUMENTOBSERVER_H
+101 -92
View File
@@ -46,9 +46,10 @@ void DocumentObserverPython::addObserver(const Py::Object& obj)
void DocumentObserverPython::removeObserver(const Py::Object& obj)
{
DocumentObserverPython* obs=nullptr;
for (std::vector<DocumentObserverPython*>::iterator it =
_instances.begin(); it != _instances.end(); ++it) {
DocumentObserverPython* obs = nullptr;
for (std::vector<DocumentObserverPython*>::iterator it = _instances.begin();
it != _instances.end();
++it) {
if ((*it)->inst == obj) {
obs = *it;
_instances.erase(it);
@@ -59,33 +60,34 @@ void DocumentObserverPython::removeObserver(const Py::Object& obj)
delete obs;
}
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj)
DocumentObserverPython::DocumentObserverPython(const Py::Object& obj)
: inst(obj)
{
#define FC_PY_ELEMENT_ARG0(_name1, _name2) do {\
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
if (!py##_name1.py.isNone())\
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
std::bind(&DocumentObserverPython::slot##_name1, this));\
}\
while(0);
#define FC_PY_ELEMENT_ARG0(_name1, _name2) \
do { \
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
if (!py##_name1.py.isNone()) \
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
std::bind(&DocumentObserverPython::slot##_name1, this)); \
} while (0);
#define FC_PY_ELEMENT_ARG1(_name1, _name2) do {\
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
if (!py##_name1.py.isNone())\
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1));\
}\
while(0);
#define FC_PY_ELEMENT_ARG1(_name1, _name2) \
do { \
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
if (!py##_name1.py.isNone()) \
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1)); \
} while (0);
//NOLINTBEGIN
#define FC_PY_ELEMENT_ARG2(_name1, _name2) do {\
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py);\
if (!py##_name1.py.isNone())\
py##_name1.slot = App::GetApplication().signal##_name2.connect(\
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2));\
}\
while(0);
// NOLINTBEGIN
#define FC_PY_ELEMENT_ARG2(_name1, _name2) \
do { \
FC_PY_GetCallable(obj.ptr(), "slot" #_name1, py##_name1.py); \
if (!py##_name1.py.isNone()) \
py##_name1.slot = App::GetApplication().signal##_name2.connect( \
std::bind(&DocumentObserverPython::slot##_name1, this, sp::_1, sp::_2)); \
} while (0);
FC_PY_ELEMENT_ARG1(CreatedDocument, NewDocument)
FC_PY_ELEMENT_ARG1(DeletedDocument, DeleteDocument)
@@ -116,7 +118,7 @@ DocumentObserverPython::DocumentObserverPython(const Py::Object& obj) : inst(obj
FC_PY_ELEMENT_ARG2(ChangePropertyEditor, ChangePropertyEditor)
FC_PY_ELEMENT_ARG2(BeforeAddingDynamicExtension, BeforeAddingDynamicExtension)
FC_PY_ELEMENT_ARG2(AddedDynamicExtension, AddedDynamicExtension)
//NOLINTEND
// NOLINTEND
}
DocumentObserverPython::~DocumentObserverPython() = default;
@@ -127,10 +129,10 @@ void DocumentObserverPython::slotCreatedDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyCreatedDocument.ptr(),args.ptr());
Base::pyCall(pyCreatedDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -141,10 +143,10 @@ void DocumentObserverPython::slotDeletedDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyDeletedDocument.ptr(),args.ptr());
Base::pyCall(pyDeletedDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -155,10 +157,10 @@ void DocumentObserverPython::slotRelabelDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyRelabelDocument.ptr(),args.ptr());
Base::pyCall(pyRelabelDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -169,10 +171,10 @@ void DocumentObserverPython::slotActivateDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyActivateDocument.ptr(),args.ptr());
Base::pyCall(pyActivateDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -183,10 +185,10 @@ void DocumentObserverPython::slotUndoDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyUndoDocument.ptr(),args.ptr());
Base::pyCall(pyUndoDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -198,10 +200,10 @@ void DocumentObserverPython::slotRedoDocument(const App::Document& Doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(Doc).getPyObject()));
Base::pyCall(pyRedoDocument.ptr(),args.ptr());
Base::pyCall(pyRedoDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -213,7 +215,7 @@ void DocumentObserverPython::slotUndo()
Base::pyCall(pyUndo.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -225,7 +227,7 @@ void DocumentObserverPython::slotRedo()
Base::pyCall(pyRedo.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -236,10 +238,10 @@ void DocumentObserverPython::slotBeforeCloseTransaction(bool abort)
try {
Py::Tuple args(1);
args.setItem(0, Py::Boolean(abort));
Base::pyCall(pyBeforeCloseTransaction.ptr(),args.ptr());
Base::pyCall(pyBeforeCloseTransaction.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -250,15 +252,16 @@ void DocumentObserverPython::slotCloseTransaction(bool abort)
try {
Py::Tuple args(1);
args.setItem(0, Py::Boolean(abort));
Base::pyCall(pyCloseTransaction.ptr(),args.ptr());
Base::pyCall(pyCloseTransaction.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc, const App::Property& Prop)
void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
const App::Property& Prop)
{
Base::PyGILStateLocker lock;
try {
@@ -269,16 +272,17 @@ void DocumentObserverPython::slotBeforeChangeDocument(const App::Document& Doc,
const char* prop_name = Doc.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyBeforeChangeDocument.ptr(),args.ptr());
Base::pyCall(pyBeforeChangeDocument.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const App::Property& Prop)
void DocumentObserverPython::slotChangedDocument(const App::Document& Doc,
const App::Property& Prop)
{
Base::PyGILStateLocker lock;
try {
@@ -289,11 +293,11 @@ void DocumentObserverPython::slotChangedDocument(const App::Document& Doc, const
const char* prop_name = Doc.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangedDocument.ptr(),args.ptr());
Base::pyCall(pyChangedDocument.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -304,10 +308,10 @@ void DocumentObserverPython::slotCreatedObject(const App::DocumentObject& Obj)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyCreatedObject.ptr(),args.ptr());
Base::pyCall(pyCreatedObject.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -318,16 +322,16 @@ void DocumentObserverPython::slotDeletedObject(const App::DocumentObject& Obj)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyDeletedObject.ptr(),args.ptr());
Base::pyCall(pyDeletedObject.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& Obj,
const App::Property& Prop)
const App::Property& Prop)
{
Base::PyGILStateLocker lock;
try {
@@ -338,11 +342,11 @@ void DocumentObserverPython::slotBeforeChangeObject(const App::DocumentObject& O
const char* prop_name = Obj.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyBeforeChangeObject.ptr(),args.ptr());
Base::pyCall(pyBeforeChangeObject.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -359,11 +363,11 @@ void DocumentObserverPython::slotChangedObject(const App::DocumentObject& Obj,
const char* prop_name = Obj.getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangedObject.ptr(),args.ptr());
Base::pyCall(pyChangedObject.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -374,10 +378,10 @@ void DocumentObserverPython::slotRecomputedObject(const App::DocumentObject& Obj
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::DocumentObject&>(Obj).getPyObject()));
Base::pyCall(pyRecomputedObject.ptr(),args.ptr());
Base::pyCall(pyRecomputedObject.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -388,10 +392,10 @@ void DocumentObserverPython::slotRecomputedDocument(const App::Document& doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyRecomputedDocument.ptr(),args.ptr());
Base::pyCall(pyRecomputedDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -402,10 +406,10 @@ void DocumentObserverPython::slotBeforeRecomputeDocument(const App::Document& do
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyBeforeRecomputeDocument.ptr(),args.ptr());
Base::pyCall(pyBeforeRecomputeDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -417,10 +421,10 @@ void DocumentObserverPython::slotOpenTransaction(const App::Document& doc, std::
Py::Tuple args(2);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(str));
Base::pyCall(pyOpenTransaction.ptr(),args.ptr());
Base::pyCall(pyOpenTransaction.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -431,10 +435,10 @@ void DocumentObserverPython::slotCommitTransaction(const App::Document& doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyCommitTransaction.ptr(),args.ptr());
Base::pyCall(pyCommitTransaction.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -445,10 +449,10 @@ void DocumentObserverPython::slotAbortTransaction(const App::Document& doc)
try {
Py::Tuple args(1);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
Base::pyCall(pyAbortTransaction.ptr(),args.ptr());
Base::pyCall(pyAbortTransaction.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -465,11 +469,11 @@ void DocumentObserverPython::slotAppendDynamicProperty(const App::Property& Prop
const char* prop_name = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyAppendDynamicProperty.ptr(),args.ptr());
Base::pyCall(pyAppendDynamicProperty.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
@@ -486,16 +490,17 @@ void DocumentObserverPython::slotRemoveDynamicProperty(const App::Property& Prop
const char* prop_name = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyRemoveDynamicProperty.ptr(),args.ptr());
Base::pyCall(pyRemoveDynamicProperty.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, const App::Property& Prop)
void DocumentObserverPython::slotChangePropertyEditor(const App::Document&,
const App::Property& Prop)
{
Base::PyGILStateLocker lock;
try {
@@ -507,72 +512,76 @@ void DocumentObserverPython::slotChangePropertyEditor(const App::Document &, con
const char* prop_name = container->getPropertyName(&Prop);
if (prop_name) {
args.setItem(1, Py::String(prop_name));
Base::pyCall(pyChangePropertyEditor.ptr(),args.ptr());
Base::pyCall(pyChangePropertyEditor.ptr(), args.ptr());
}
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc, const std::string& file)
void DocumentObserverPython::slotStartSaveDocument(const App::Document& doc,
const std::string& file)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(file));
Base::pyCall(pyStartSaveDocument.ptr(),args.ptr());
Base::pyCall(pyStartSaveDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc, const std::string& file)
void DocumentObserverPython::slotFinishSaveDocument(const App::Document& doc,
const std::string& file)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::asObject(const_cast<App::Document&>(doc).getPyObject()));
args.setItem(1, Py::String(file));
Base::pyCall(pyFinishSaveDocument.ptr(),args.ptr());
Base::pyCall(pyFinishSaveDocument.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotBeforeAddingDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
void DocumentObserverPython::slotBeforeAddingDynamicExtension(
const App::ExtensionContainer& extcont,
std::string extension)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(),args.ptr());
Base::pyCall(pyBeforeAddingDynamicExtension.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont, std::string extension)
void DocumentObserverPython::slotAddedDynamicExtension(const App::ExtensionContainer& extcont,
std::string extension)
{
Base::PyGILStateLocker lock;
try {
Py::Tuple args(2);
args.setItem(0, Py::asObject(const_cast<App::ExtensionContainer&>(extcont).getPyObject()));
args.setItem(1, Py::String(extension));
Base::pyCall(pyAddedDynamicExtension.ptr(),args.ptr());
Base::pyCall(pyAddedDynamicExtension.ptr(), args.ptr());
}
catch (Py::Exception&) {
Base::PyException e; // extract the Python error text
Base::PyException e; // extract the Python error text
e.ReportException();
}
}
+11 -9
View File
@@ -106,7 +106,7 @@ private:
/** Called when an object gets a dynamic property removed*/
void slotRemoveDynamicProperty(const App::Property& Prop);
/** Called when an object property gets a new editor relevant status like hidden or read only*/
void slotChangePropertyEditor(const App::Document &Doc, const App::Property& Prop);
void slotChangePropertyEditor(const App::Document& Doc, const App::Property& Prop);
/** Called when a document is about to be saved*/
void slotStartSaveDocument(const App::Document&, const std::string&);
/** Called when an document has been saved*/
@@ -121,12 +121,14 @@ private:
Py::Object inst;
static std::vector<DocumentObserverPython*> _instances;
using Connection = struct PythonObject {
boost::signals2::scoped_connection slot;
Py::Object py;
PyObject* ptr() {
return py.ptr();
}
using Connection = struct PythonObject
{
boost::signals2::scoped_connection slot;
Py::Object py;
PyObject* ptr()
{
return py.ptr();
}
};
Connection pyCreatedDocument;
@@ -160,6 +162,6 @@ private:
Connection pyAddedDynamicExtension;
};
} //namespace App
} // namespace App
#endif // APP_DOCUMENTOBSERVERPYTHON_H
#endif // APP_DOCUMENTOBSERVERPYTHON_H
+12
View File
@@ -56,6 +56,18 @@ For a temporary document it returns its transient directory.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="getUniqueObjectName">
<Documentation>
<UserDocu>getUniqueObjectName(objName) -> objName
Return the same name, or the name made unique, for Example Box -> Box002 if there are conflicting name
already in the document.
ObjName : str
Object name.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="mergeProject">
<Documentation>
<UserDocu>Merges this document with another project file</UserDocu>
+358 -205
View File
File diff suppressed because it is too large Load Diff
+152 -95
View File
@@ -33,7 +33,7 @@
#include "PropertyContainer.h"
FC_LOG_LEVEL_INIT("Property",true,true)
FC_LOG_LEVEL_INIT("Property", true, true)
using namespace App;
@@ -46,65 +46,75 @@ DynamicProperty::~DynamicProperty()
clear();
}
void DynamicProperty::clear() {
auto &index = props.get<0>();
for(auto &v : index)
void DynamicProperty::clear()
{
auto& index = props.get<0>();
for (auto& v : index) {
delete v.property;
}
index.clear();
}
void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
void DynamicProperty::getPropertyList(std::vector<Property*>& List) const
{
for (auto &v : props.get<0>())
for (auto& v : props.get<0>()) {
List.push_back(v.property);
}
}
void DynamicProperty::getPropertyNamedList(std::vector<std::pair<const char*, Property*> > &List) const
void DynamicProperty::getPropertyNamedList(
std::vector<std::pair<const char*, Property*>>& List) const
{
for (auto &v : props.get<0>())
List.emplace_back(v.getName(),v.property);
for (auto& v : props.get<0>()) {
List.emplace_back(v.getName(), v.property);
}
}
void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
void DynamicProperty::getPropertyMap(std::map<std::string, Property*>& Map) const
{
for (auto &v : props.get<0>())
for (auto& v : props.get<0>()) {
Map[v.name] = v.property;
}
}
Property *DynamicProperty::getDynamicPropertyByName(const char* name) const
Property* DynamicProperty::getDynamicPropertyByName(const char* name) const
{
auto &index = props.get<0>();
auto& index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
if (it != index.end()) {
return it->property;
}
return nullptr;
}
std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
{
std::vector<std::string> names;
auto &index = props.get<0>();
auto& index = props.get<0>();
names.reserve(index.size());
for(auto &v : index)
for (auto& v : index) {
names.push_back(v.name);
}
return names;
}
short DynamicProperty::getPropertyType(const Property* prop) const
{
return prop?prop->getType():0;
return prop ? prop->getType() : 0;
}
short DynamicProperty::getPropertyType(const char *name) const
short DynamicProperty::getPropertyType(const char* name) const
{
auto &index = props.get<0>();
auto& index = props.get<0>();
auto it = index.find(name);
if (it != index.end()) {
short attr = it->attr;
if (it->hidden)
if (it->hidden) {
attr |= Prop_Hidden;
if (it->readonly)
}
if (it->readonly) {
attr |= Prop_ReadOnly;
}
return attr;
}
return 0;
@@ -112,92 +122,113 @@ short DynamicProperty::getPropertyType(const char *name) const
const char* DynamicProperty::getPropertyGroup(const Property* prop) const
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it!=index.end())
if (it != index.end()) {
return it->group.c_str();
}
return nullptr;
}
const char* DynamicProperty::getPropertyGroup(const char *name) const
const char* DynamicProperty::getPropertyGroup(const char* name) const
{
auto &index = props.get<0>();
auto& index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
if (it != index.end()) {
return it->group.c_str();
}
return nullptr;
}
const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it!=index.end())
if (it != index.end()) {
return it->doc.c_str();
}
return nullptr;
}
const char* DynamicProperty::getPropertyDocumentation(const char *name) const
const char* DynamicProperty::getPropertyDocumentation(const char* name) const
{
auto &index = props.get<0>();
auto& index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
if (it != index.end()) {
return it->doc.c_str();
}
return nullptr;
}
Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type,
const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden)
Property* DynamicProperty::addDynamicProperty(PropertyContainer& pc,
const char* type,
const char* name,
const char* group,
const char* doc,
short attr,
bool ro,
bool hidden)
{
if(!type)
if (!type) {
type = "<null>";
}
std::string _name;
static ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Document");
if(hGrp->GetBool("AutoNameDynamicProperty",false)) {
if(!name || !name[0])
static ParameterGrp::handle hGrp =
GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
if (hGrp->GetBool("AutoNameDynamicProperty", false)) {
if (!name || !name[0]) {
name = type;
_name = getUniquePropertyName(pc,name);
if(_name != name) {
FC_WARN(pc.getFullName() << " rename dynamic property from '"
<< name << "' to '" << _name << "'");
}
_name = getUniquePropertyName(pc, name);
if (_name != name) {
FC_WARN(pc.getFullName()
<< " rename dynamic property from '" << name << "' to '" << _name << "'");
}
name = _name.c_str();
} else if(!name)
name = "<null>"; // setting a bad name to trigger exception
}
else if (!name) {
name = "<null>"; // setting a bad name to trigger exception
}
auto prop = pc.getPropertyByName(name);
if(prop && prop->getContainer()==&pc)
FC_THROWM(Base::NameError, "Property " << pc.getFullName() << '.' << name << " already exists");
if (prop && prop->getContainer() == &pc) {
FC_THROWM(Base::NameError,
"Property " << pc.getFullName() << '.' << name << " already exists");
}
if(Base::Tools::getIdentifier(name) != name)
if (Base::Tools::getIdentifier(name) != name) {
FC_THROWM(Base::NameError, "Invalid property name '" << name << "'");
}
Base::Type propType = Base::Type::getTypeIfDerivedFrom(type, App::Property::getClassTypeId(), true);
Base::Type propType =
Base::Type::getTypeIfDerivedFrom(type, App::Property::getClassTypeId(), true);
if (propType.isBad()) {
FC_THROWM(Base::TypeError, "Invalid type "
<< type << " for property " << pc.getFullName() << '.' << name);
FC_THROWM(Base::TypeError,
"Invalid type " << type << " for property " << pc.getFullName() << '.' << name);
}
void* propInstance = propType.createInstance();
if (!propInstance) {
FC_THROWM(Base::RuntimeError, "Failed to create property "
<< pc.getFullName() << '.' << name << " of type " << type);
FC_THROWM(Base::RuntimeError,
"Failed to create property " << pc.getFullName() << '.' << name << " of type "
<< type);
}
Property* pcProperty = static_cast<Property*>(propInstance);
auto res = props.get<0>().emplace(pcProperty,name, nullptr, group, doc, attr, ro, hidden);
auto res = props.get<0>().emplace(pcProperty, name, nullptr, group, doc, attr, ro, hidden);
pcProperty->setContainer(&pc);
pcProperty->myName = res.first->name.c_str();
if(ro)
if (ro) {
attr |= Prop_ReadOnly;
if(hidden)
}
if (hidden) {
attr |= Prop_Hidden;
}
pcProperty->syncType(attr);
pcProperty->StatusBits.set((size_t)Property::PropDynamic);
@@ -207,21 +238,29 @@ Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char*
return pcProperty;
}
bool DynamicProperty::addProperty(Property *prop)
bool DynamicProperty::addProperty(Property* prop)
{
if(!prop || !prop->hasName())
if (!prop || !prop->hasName()) {
return false;
auto &index = props.get<0>();
if(index.count(prop->getName()))
}
auto& index = props.get<0>();
if (index.count(prop->getName())) {
return false;
index.emplace(prop,std::string(),prop->getName(),
prop->getGroup(),prop->getDocumentation(),prop->getType(),false,false);
}
index.emplace(prop,
std::string(),
prop->getName(),
prop->getGroup(),
prop->getDocumentation(),
prop->getType(),
false,
false);
return true;
}
bool DynamicProperty::removeProperty(const Property *prop)
bool DynamicProperty::removeProperty(const Property* prop)
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if (it != index.end()) {
index.erase(it);
@@ -232,14 +271,16 @@ bool DynamicProperty::removeProperty(const Property *prop)
bool DynamicProperty::removeDynamicProperty(const char* name)
{
auto &index = props.get<0>();
auto& index = props.get<0>();
auto it = index.find(name);
if (it != index.end()) {
if(it->property->testStatus(Property::LockDynamic))
if (it->property->testStatus(Property::LockDynamic)) {
throw Base::RuntimeError("property is locked");
else if(!it->property->testStatus(Property::PropDynamic))
}
else if (!it->property->testStatus(Property::PropDynamic)) {
throw Base::RuntimeError("property is not dynamic");
Property *prop = it->property;
}
Property* prop = it->property;
GetApplication().signalRemoveDynamicProperty(*prop);
// Handle possible recursive calls of removeDynamicProperty
@@ -255,12 +296,12 @@ bool DynamicProperty::removeDynamicProperty(const char* name)
return false;
}
std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const char *Name) const
std::string DynamicProperty::getUniquePropertyName(PropertyContainer& pc, const char* Name) const
{
std::string CleanName = Base::Tools::getIdentifier(Name);
// name in use?
std::map<std::string,Property*> objectProps;
std::map<std::string, Property*> objectProps;
pc.getPropertyMap(objectProps);
auto pos = objectProps.find(CleanName);
@@ -271,38 +312,42 @@ std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const
else {
std::vector<std::string> names;
names.reserve(objectProps.size());
for (pos = objectProps.begin();pos != objectProps.end();++pos) {
for (pos = objectProps.begin(); pos != objectProps.end(); ++pos) {
names.push_back(pos->first);
}
return Base::Tools::getUniqueName(CleanName, names);
}
}
void DynamicProperty::save(const Property *prop, Base::Writer &writer) const
void DynamicProperty::save(const Property* prop, Base::Writer& writer) const
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end()) {
auto &data = *it;
if (it != index.end()) {
auto& data = *it;
writer.Stream() << "\" group=\"" << Base::Persistence::encodeAttribute(data.group)
<< "\" doc=\"" << Base::Persistence::encodeAttribute(data.doc)
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly
<< "\" hide=\"" << data.hidden;
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly << "\" hide=\""
<< data.hidden;
}
}
Property *DynamicProperty::restore(PropertyContainer &pc,
const char *PropName, const char *TypeName, Base::XMLReader &reader)
Property* DynamicProperty::restore(PropertyContainer& pc,
const char* PropName,
const char* TypeName,
Base::XMLReader& reader)
{
if (!reader.hasAttribute("group"))
if (!reader.hasAttribute("group")) {
return nullptr;
}
short attribute = 0;
bool readonly = false, hidden = false;
const char *group=nullptr, *doc=nullptr, *attr=nullptr, *ro=nullptr, *hide=nullptr;
const char *group = nullptr, *doc = nullptr, *attr = nullptr, *ro = nullptr, *hide = nullptr;
group = reader.getAttribute("group");
if (reader.hasAttribute("doc"))
if (reader.hasAttribute("doc")) {
doc = reader.getAttribute("doc");
}
if (reader.hasAttribute("attr")) {
attr = reader.getAttribute("attr");
if (attr) {
@@ -312,42 +357,54 @@ Property *DynamicProperty::restore(PropertyContainer &pc,
}
if (reader.hasAttribute("ro")) {
ro = reader.getAttribute("ro");
if (ro) readonly = (ro[0]-48) != 0;
if (ro) {
readonly = (ro[0] - 48) != 0;
}
}
if (reader.hasAttribute("hide")) {
hide = reader.getAttribute("hide");
if (hide) hidden = (hide[0]-48) != 0;
if (hide) {
hidden = (hide[0] - 48) != 0;
}
}
return addDynamicProperty(pc,TypeName, PropName, group, doc, attribute, readonly, hidden);
return addDynamicProperty(pc, TypeName, PropName, group, doc, attribute, readonly, hidden);
}
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property *prop) const
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property* prop) const
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end())
if (it != index.end()) {
return *it;
}
return {};
}
bool DynamicProperty::changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
auto &index = props.get<1>();
bool DynamicProperty::changeDynamicProperty(const Property* prop,
const char* group,
const char* doc)
{
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if (it == index.end())
if (it == index.end()) {
return false;
if(group)
}
if (group) {
it->group = group;
if(doc)
}
if (doc) {
it->doc = doc;
}
return true;
}
const char *DynamicProperty::getPropertyName(const Property *prop) const
const char* DynamicProperty::getPropertyName(const Property* prop) const
{
auto &index = props.get<1>();
auto& index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end())
if (it != index.end()) {
return it->getName();
}
return nullptr;
}
+80 -49
View File
@@ -33,13 +33,15 @@
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <FCGlobal.h>
namespace Base {
namespace Base
{
class Writer;
class XMLReader;
class XMLWriter;
}
} // namespace Base
namespace App
{
@@ -48,15 +50,24 @@ class PropertyContainer;
namespace bmi = boost::multi_index;
struct CStringHasher {
inline std::size_t operator()(const char *s) const {
if(!s) return 0;
return boost::hash_range(s,s+std::strlen(s));
struct CStringHasher
{
inline std::size_t operator()(const char* s) const
{
if (!s) {
return 0;
}
return boost::hash_range(s, s + std::strlen(s));
}
inline bool operator()(const char *a, const char *b) const {
if(!a) return !b;
if(!b) return false;
return std::strcmp(a,b)==0;
inline bool operator()(const char* a, const char* b) const
{
if (!a) {
return !b;
}
if (!b) {
return false;
}
return std::strcmp(a, b) == 0;
}
};
@@ -73,13 +84,13 @@ public:
/** @name Access properties */
//@{
/// Get all properties of the class (including parent)
void getPropertyList(std::vector<Property*> &List) const;
void getPropertyList(std::vector<Property*>& List) const;
/// get all properties with their names
void getPropertyNamedList(std::vector<std::pair<const char*,Property*> > &List) const;
void getPropertyNamedList(std::vector<std::pair<const char*, Property*>>& List) const;
/// Get all properties of the class (including parent)
void getPropertyMap(std::map<std::string,Property*> &Map) const;
void getPropertyMap(std::map<std::string, Property*>& Map) const;
/// Find a dynamic property by its name
Property *getDynamicPropertyByName(const char* name) const;
Property* getDynamicPropertyByName(const char* name) const;
/*!
Add a dynamic property of the type @a type and with the name @a name.
@a Group gives the grouping name which appears in the property editor and
@@ -97,22 +108,28 @@ public:
addDynamicProperty(..., ..., "Base","blah", Prop_None, true, true);
@endcode
*/
Property* addDynamicProperty(PropertyContainer &pc, const char* type, const char* name=nullptr, const char* group=nullptr,
const char* doc=nullptr, short attr=0, bool ro=false, bool hidden=false);
Property* addDynamicProperty(PropertyContainer& pc,
const char* type,
const char* name = nullptr,
const char* group = nullptr,
const char* doc = nullptr,
short attr = 0,
bool ro = false,
bool hidden = false);
/** Add a pre-existing property
*
* The property is not treated as dynamic, and will not trigger signal.
*
* @return Return false if there is a property exist with the same name.
*/
bool addProperty(Property *prop);
bool addProperty(Property* prop);
/*!
Removes a dynamic property by name. Returns true if the property is part of the container, otherwise
false is returned.
Removes a dynamic property by name. Returns true if the property is part of the container,
otherwise false is returned.
*/
bool removeDynamicProperty(const char* name);
/// Remove pre-existing property, which will not be deleted.
bool removeProperty(const Property *prop);
bool removeProperty(const Property* prop);
/// Get a list of all dynamic properties.
std::vector<std::string> getDynamicPropertyNames() const;
/// Get the name of a property
@@ -124,72 +141,86 @@ public:
/// Get the attributes of a property
short getPropertyType(const Property* prop) const;
/// Get the attributes of a named property
short getPropertyType(const char *name) const;
short getPropertyType(const char* name) const;
/// Get the group name of a property
const char* getPropertyGroup(const Property* prop) const;
/// Get the group name of a named property
const char* getPropertyGroup(const char *name) const;
const char* getPropertyGroup(const char* name) const;
/// Get the documentation of a property
const char* getPropertyDocumentation(const Property* prop) const;
/// Get the documentation of a named property
const char* getPropertyDocumentation(const char *name) const;
const char* getPropertyDocumentation(const char* name) const;
//@}
/// Remove all properties
void clear();
/// Get property count
size_t size() const { return props.size(); }
size_t size() const
{
return props.size();
}
void save(const Property *prop, Base::Writer &writer) const;
void save(const Property* prop, Base::Writer& writer) const;
Property *restore(PropertyContainer &pc,
const char *PropName, const char *TypeName, Base::XMLReader &reader);
Property* restore(PropertyContainer& pc,
const char* PropName,
const char* TypeName,
Base::XMLReader& reader);
struct PropData {
struct PropData
{
Property* property;
std::string name;
const char *pName;
const char* pName;
mutable std::string group;
mutable std::string doc;
short attr;
bool readonly;
bool hidden;
PropData(Property *prop=nullptr, std::string &&n=std::string(), const char *pn=nullptr,
const char *g=nullptr, const char *d=nullptr, short a=0, bool ro=false, bool h=false)
:property(prop),name(std::move(n)),pName(pn)
,group(g?g:""),doc(d?d:""),attr(a),readonly(ro),hidden(h)
PropData(Property* prop = nullptr,
std::string&& n = std::string(),
const char* pn = nullptr,
const char* g = nullptr,
const char* d = nullptr,
short a = 0,
bool ro = false,
bool h = false)
: property(prop)
, name(std::move(n))
, pName(pn)
, group(g ? g : "")
, doc(d ? d : "")
, attr(a)
, readonly(ro)
, hidden(h)
{}
const char *getName() const {
return pName?pName:name.c_str();
const char* getName() const
{
return pName ? pName : name.c_str();
}
};
PropData getDynamicPropertyData(const Property* prop) const;
bool changeDynamicProperty(const Property *prop, const char *group, const char *doc);
bool changeDynamicProperty(const Property* prop, const char* group, const char* doc);
private:
std::string getUniquePropertyName(PropertyContainer &pc, const char *Name) const;
std::string getUniquePropertyName(PropertyContainer& pc, const char* Name) const;
private:
bmi::multi_index_container<
PropData,
bmi::indexed_by<
bmi::hashed_unique<
bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
CStringHasher,
CStringHasher
>,
bmi::hashed_unique<
bmi::member<PropData, Property*, &PropData::property>
>
>
> props;
bmi::hashed_unique<bmi::const_mem_fun<PropData, const char*, &PropData::getName>,
CStringHasher,
CStringHasher>,
bmi::hashed_unique<bmi::member<PropData, Property*, &PropData::property>>>>
props;
};
} // namespace App
} // namespace App
#endif // APP_DYNAMICPROPERTY_H
#endif // APP_DYNAMICPROPERTY_H
+99 -66
View File
@@ -18,7 +18,7 @@
#include <boost/algorithm/string/split.hpp>
FC_LOG_LEVEL_INIT("ElementMap", true, 2);// NOLINT
FC_LOG_LEVEL_INIT("ElementMap", true, 2); // NOLINT
namespace Data
{
@@ -104,7 +104,8 @@ void ElementMap::beforeSave(const ::App::StringHasherRef& hasherRef) const
}
}
void ElementMap::save(std::ostream& stream, int index,
void ElementMap::save(std::ostream& stream,
int index,
const std::map<const ElementMap*, int>& childMapSet,
const std::map<QByteArray, int>& postfixMap) const
{
@@ -121,7 +122,7 @@ void ElementMap::save(std::ostream& stream, int index,
if (child.elementMap) {
auto it = childMapSet.find(child.elementMap.get());
if (it == childMapSet.end() || it->second == 0) {
FC_ERR("Invalid child element map");// NOLINT
FC_ERR("Invalid child element map"); // NOLINT
}
else {
mapIndex = it->second;
@@ -240,7 +241,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
int count = 0;
std::string tmp;
if (!(stream >> id >> tmp >> count) || tmp != "PostfixCount") {
FC_THROWM(Base::RuntimeError, msg);// NOLINT
FC_THROWM(Base::RuntimeError, msg); // NOLINT
}
auto& map = _idToElementMap[id];
@@ -258,7 +259,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
std::vector<ElementMapPtr> childMaps;
count = 0;
if (!(stream >> tmp >> count) || tmp != "MapCount" || count == 0) {
FC_THROWM(Base::RuntimeError, msg);// NOLINT
FC_THROWM(Base::RuntimeError, msg); // NOLINT
}
childMaps.reserve(count - 1);
for (int i = 0; i < count - 1; ++i) {
@@ -269,7 +270,8 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
return restore(hasherRef, stream, childMaps, postfixes);
}
ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream& stream,
ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef,
std::istream& stream,
std::vector<ElementMapPtr>& childMaps,
const std::vector<std::string>& postfixes)
{
@@ -281,14 +283,14 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
int typeCount = 0;
unsigned id = 0;
if (!(stream >> tmp >> index >> id >> typeCount) || tmp != "ElementMap") {
FC_THROWM(Base::RuntimeError, msg);// NOLINT
FC_THROWM(Base::RuntimeError, msg); // NOLINT
}
auto& map = _idToElementMap[id];
if (map) {
while (tmp != "EndMap") {
if (!std::getline(stream, tmp)) {
FC_THROWM(Base::RuntimeError, "unexpected end of child element map");// NOLINT
FC_THROWM(Base::RuntimeError, "unexpected end of child element map"); // NOLINT
}
}
return map;
@@ -303,12 +305,12 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
for (int i = 0; i < typeCount; ++i) {
int outerCount = 0;
if (!(stream >> tmp)) {
FC_THROWM(Base::RuntimeError, "missing element type");// NOLINT
FC_THROWM(Base::RuntimeError, "missing element type"); // NOLINT
}
IndexedName idx(tmp.c_str(), 1);
if (!(stream >> tmp >> outerCount) || tmp != "ChildCount") {
FC_THROWM(Base::RuntimeError, "missing element child count");// NOLINT
FC_THROWM(Base::RuntimeError, "missing element child count"); // NOLINT
}
auto& indices = this->indexedNames[idx.getType()];
@@ -319,16 +321,16 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
long tag = 0;
int mapIndex = 0;
if (!(stream >> cIndex >> offset >> count >> tag >> mapIndex >> tmp)) {
FC_THROWM(Base::RuntimeError, "Invalid element child");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element child"); // NOLINT
}
if (cIndex < 0) {
FC_THROWM(Base::RuntimeError, "Invalid element child index");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element child index"); // NOLINT
}
if (offset < 0) {
FC_THROWM(Base::RuntimeError, "Invalid element child offset");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element child offset"); // NOLINT
}
if (mapIndex >= index || mapIndex < 0 || mapIndex > (int)childMaps.size()) {
FC_THROWM(Base::RuntimeError, "Invalid element child map index");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element child map index"); // NOLINT
}
auto& child = indices.children[cIndex + offset + count];
child.indexedName = IndexedName::fromConst(idx.getType(), cIndex);
@@ -346,7 +348,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
this->childElementSize += child.count;
if (!(stream >> tmp)) {
FC_THROWM(Base::RuntimeError, "Invalid element child string id");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element child string id"); // NOLINT
}
tokens.clear();
@@ -371,7 +373,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
}
if (!(stream >> tmp >> outerCount) || tmp != "NameCount") {
FC_THROWM(Base::RuntimeError, "missing element name outerCount");// NOLINT
FC_THROWM(Base::RuntimeError, "missing element name outerCount"); // NOLINT
}
boost::io::ios_flags_saver ifs(stream);
@@ -384,7 +386,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
int innerCount = 0;
while (true) {
if (!(stream >> tmp)) {
FC_THROWM(Base::RuntimeError, "Failed to read element name");// NOLINT
FC_THROWM(Base::RuntimeError, "Failed to read element name"); // NOLINT
}
if (tmp == "0") {
break;
@@ -396,7 +398,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
tokens.clear();
boost::split(tokens, tmp, boost::is_any_of("."));
if (tokens.size() < 2) {
FC_THROWM(Base::RuntimeError, "Invalid element entry");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element entry"); // NOLINT
}
int offset = 1;
@@ -406,12 +408,12 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
switch (tokens[0][0]) {
case ':': {
if (tokens.size() < 3) {
FC_THROWM(Base::RuntimeError, "Invalid element entry");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element entry"); // NOLINT
}
++offset;
long elementNameIndex = strtol(tokens[0].c_str() + 1, nullptr, hexBase);
if (elementNameIndex <= 0 || elementNameIndex > (int)postfixes.size()) {
FC_THROWM(Base::RuntimeError, "Invalid element name index");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element name index"); // NOLINT
}
long elementIndex = strtol(tokens[1].c_str(), nullptr, hexBase);
ref->name = MappedName(
@@ -427,7 +429,7 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
ref->name = MappedName(tokens[0].c_str() + 1);
break;
default:
FC_THROWM(Base::RuntimeError, "Invalid element name marker");// NOLINT
FC_THROWM(Base::RuntimeError, "Invalid element name marker"); // NOLINT
}
if (tokens[offset] != "0") {
@@ -473,31 +475,34 @@ ElementMapPtr ElementMap::restore(::App::StringHasherRef hasherRef, std::istream
}
}
if (hasherWarn) {
FC_WARN(hasherWarn);// NOLINT
FC_WARN(hasherWarn); // NOLINT
}
if (hasherIDWarn) {
FC_WARN(hasherIDWarn);// NOLINT
FC_WARN(hasherIDWarn); // NOLINT
}
if (postfixWarn) {
FC_WARN(postfixWarn);// NOLINT
FC_WARN(postfixWarn); // NOLINT
}
if (childSIDWarn) {
FC_WARN(childSIDWarn);// NOLINT
FC_WARN(childSIDWarn); // NOLINT
}
if (!(stream >> tmp) || tmp != "EndMap") {
FC_THROWM(Base::RuntimeError, "unexpected end of child element map");// NOLINT
FC_THROWM(Base::RuntimeError, "unexpected end of child element map"); // NOLINT
}
return shared_from_this();
}
MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const ElementIDRefs& sids,
bool overwrite, IndexedName* existing)
MappedName ElementMap::addName(MappedName& name,
const IndexedName& idx,
const ElementIDRefs& sids,
bool overwrite,
IndexedName* existing)
{
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
if (name.find("#") >= 0 && name.findTagInElementName() < 0) {
FC_ERR("missing tag postfix " << name);// NOLINT
FC_ERR("missing tag postfix " << name); // NOLINT
}
}
while (true) {
@@ -505,14 +510,14 @@ MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const E
erase(idx);
}
auto ret = mappedNames.insert(std::make_pair(name, idx));
if (ret.second) { // element just inserted did not exist yet in the map
ret.first->first.compact();// FIXME see MappedName.cpp
if (ret.second) { // element just inserted did not exist yet in the map
ret.first->first.compact(); // FIXME see MappedName.cpp
mappedRef(idx).append(ret.first->first, sids);
FC_TRACE(idx << " -> " << name);// NOLINT
FC_TRACE(idx << " -> " << name); // NOLINT
return ret.first->first;
}
if (ret.first->second == idx) {
FC_TRACE("duplicate " << idx << " -> " << name);// NOLINT
FC_TRACE("duplicate " << idx << " -> " << name); // NOLINT
return ret.first->first;
}
if (!overwrite) {
@@ -526,7 +531,8 @@ MappedName ElementMap::addName(MappedName& name, const IndexedName& idx, const E
};
}
void ElementMap::addPostfix(const QByteArray& postfix, std::map<QByteArray, int>& postfixMap,
void ElementMap::addPostfix(const QByteArray& postfix,
std::map<QByteArray, int>& postfixMap,
std::vector<QByteArray>& postfixes)
{
if (postfix.isEmpty()) {
@@ -539,8 +545,11 @@ void ElementMap::addPostfix(const QByteArray& postfix, std::map<QByteArray, int>
}
}
MappedName ElementMap::setElementName(const IndexedName& element, const MappedName& name,
long masterTag, const ElementIDRefs* sid, bool overwrite)
MappedName ElementMap::setElementName(const IndexedName& element,
const MappedName& name,
long masterTag,
const ElementIDRefs* sid,
bool overwrite)
{
if (!element) {
throw Base::ValueError("Invalid input");
@@ -553,13 +562,13 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
for (int i = 0, count = name.size(); i < count; ++i) {
char check = name[i];
if (check == '.' || (std::isspace((int)check) != 0)) {
FC_THROWM(Base::RuntimeError, "Illegal character in mapped name: " << name);// NOLINT
FC_THROWM(Base::RuntimeError, "Illegal character in mapped name: " << name); // NOLINT
}
}
for (const char* readChar = element.getType(); *readChar != 0; ++readChar) {
char check = *readChar;
if (check == '.' || (std::isspace((int)check) != 0)) {
FC_THROWM(Base::RuntimeError,// NOLINT
FC_THROWM(Base::RuntimeError, // NOLINT
"Illegal character in element name: " << element);
}
}
@@ -586,7 +595,7 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
}
const int maxAttempts {100};
if (++i == maxAttempts) {
FC_ERR("unresolved duplicate element mapping '"// NOLINT
FC_ERR("unresolved duplicate element mapping '" // NOLINT
<< name << ' ' << element << '/' << existing);
return name;
}
@@ -602,9 +611,14 @@ MappedName ElementMap::setElementName(const IndexedName& element, const MappedNa
}
// try to hash element name while preserving the source tag
void ElementMap::encodeElementName(char element_type, MappedName& name, std::ostringstream& ss,
ElementIDRefs* sids, long masterTag, const char* postfix,
long tag, bool forceTag) const
void ElementMap::encodeElementName(char element_type,
MappedName& name,
std::ostringstream& ss,
ElementIDRefs* sids,
long masterTag,
const char* postfix,
long tag,
bool forceTag) const
{
if (postfix && (postfix[0] != 0)) {
if (!boost::starts_with(postfix, ELEMENT_MAP_PREFIX)) {
@@ -715,26 +729,30 @@ MappedName ElementMap::dehashElementName(const MappedName& name) const
auto sid = this->hasher->getID(id);
if (!sid) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_TRACE)) {
FC_WARN("failed to find hash id " << id);// NOLINT
FC_WARN("failed to find hash id " << id); // NOLINT
}
else {
FC_LOG("failed to find hash id " << id);// NOLINT
FC_LOG("failed to find hash id " << id); // NOLINT
}
return name;
}
if (sid.isHashed()) {
FC_LOG("cannot de-hash id " << id);// NOLINT
FC_LOG("cannot de-hash id " << id); // NOLINT
return name;
}
MappedName ret(sid);
// sid.toString());// FIXME .toString() was missing in original function. is this correct?
FC_TRACE("de-hash " << name << " -> " << ret);// NOLINT
// sid.toString());// FIXME .toString() was missing in original function. is this
// correct?
FC_TRACE("de-hash " << name << " -> " << ret); // NOLINT
return ret;
}
MappedName ElementMap::renameDuplicateElement(int index, const IndexedName& element,
const IndexedName& element2, const MappedName& name,
ElementIDRefs& sids, long masterTag) const
MappedName ElementMap::renameDuplicateElement(int index,
const IndexedName& element,
const IndexedName& element2,
const MappedName& name,
ElementIDRefs& sids,
long masterTag) const
{
int idx {0};
#ifdef FC_DEBUG
@@ -751,7 +769,7 @@ MappedName ElementMap::renameDuplicateElement(int index, const IndexedName& elem
MappedName renamed(name);
encodeElementName(element.getType()[0], renamed, ss, &sids, masterTag);
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
FC_WARN("duplicate element mapping '"// NOLINT
FC_WARN("duplicate element mapping '" // NOLINT
<< name << " -> " << renamed << ' ' << element << '/' << element2);
}
return renamed;
@@ -1008,13 +1026,20 @@ void ElementMap::hashChildMaps(long masterTag)
.findTagInElementName(&tag, &len, nullptr, nullptr, false, false);
// TODO: What is this 10?
if (pos > 10) {
MappedName postfix = hashElementName(
MappedName::fromRawData(child.postfix.constData(), pos), child.sids);
MappedName postfix =
hashElementName(MappedName::fromRawData(child.postfix.constData(), pos),
child.sids);
ss.str("");
ss << MAPPED_CHILD_ELEMENTS_PREFIX << postfix;
MappedName tmp;
encodeElementName(
child.indexedName[0], tmp, ss, nullptr, masterTag, nullptr, child.tag, true);
encodeElementName(child.indexedName[0],
tmp,
ss,
nullptr,
masterTag,
nullptr,
child.tag,
true);
this->childElements.remove(child.postfix);
child.postfix = tmp.toBytes();
this->childElements[child.postfix].childMap = &child;
@@ -1152,7 +1177,7 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
for (auto& child : expansion.empty() ? children : expansion) {
if (!child.indexedName || (child.count == 0)) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
FC_ERR("invalid mapped child element");// NOLINT
FC_ERR("invalid mapped child element"); // NOLINT
}
continue;
}
@@ -1195,15 +1220,20 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
if (!name) {
if ((child.tag == 0) || child.tag == masterTag) {
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
FC_WARN("unmapped element");// NOLINT
FC_WARN("unmapped element"); // NOLINT
}
continue;
}
name = MappedName(childIdx);
}
ss.str("");
encodeElementName(
idx[0], name, ss, &sids, masterTag, child.postfix.constData(), child.tag);
encodeElementName(idx[0],
name,
ss,
&sids,
masterTag,
child.postfix.constData(),
child.tag);
setElementName(idx, name, masterTag, &sids);
}
continue;
@@ -1231,19 +1261,20 @@ void ElementMap::addChildElements(long masterTag, const std::vector<MappedChildE
entry = &childElements[tmp.toBytes()];
if (entry->childMap) {
FC_ERR("duplicate mapped child element");// NOLINT
FC_ERR("duplicate mapped child element"); // NOLINT
continue;
}
}
auto& indices = this->indexedNames[child.indexedName.getType()];
auto res = indices.children.emplace(
child.indexedName.getIndex() + child.offset + child.count, child);
auto res =
indices.children.emplace(child.indexedName.getIndex() + child.offset + child.count,
child);
if (!res.second) {
if (!entry->childMap) {
this->childElements.remove(tmp.toBytes());
}
FC_ERR("duplicate mapped child element");// NOLINT
FC_ERR("duplicate mapped child element"); // NOLINT
continue;
}
@@ -1293,7 +1324,9 @@ std::vector<MappedElement> ElementMap::getAll() const
return ret;
}
long ElementMap::getElementHistory(const MappedName& name, long masterTag, MappedName* original,
long ElementMap::getElementHistory(const MappedName& name,
long masterTag,
MappedName* original,
std::vector<MappedName>* history) const
{
long tag = 0;
@@ -1321,7 +1354,7 @@ long ElementMap::getElementHistory(const MappedName& name, long masterTag, Mappe
while (true) {
if ((len == 0) || len > pos) {
FC_WARN("invalid name length " << name);// NOLINT
FC_WARN("invalid name length " << name); // NOLINT
return 0;
}
bool deHashed = false;
@@ -1440,4 +1473,4 @@ void ElementMap::traceElement(const MappedName& name, long masterTag, TraceCallb
}
}// Namespace Data
} // Namespace Data
+44 -32
View File
@@ -46,17 +46,17 @@ class ElementMap;
using ElementMapPtr = std::shared_ptr<ElementMap>;
/** Element trace callback
*
* The callback has the following call signature
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
*
* @param name: the current element name.
* @param offset: the offset skipping the encoded element name for the next iteration.
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
* of the previous step in the shape history.
* @param tag: the tag of the current shape element.
*
* @sa traceElement()
*
* The callback has the following call signature
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
*
* @param name: the current element name.
* @param offset: the offset skipping the encoded element name for the next iteration.
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
* of the previous step in the shape history.
* @param tag: the tag of the current shape element.
*
* @sa traceElement()
*/
typedef std::function<bool(const MappedName&, int, long, long)> TraceCallback;
@@ -68,13 +68,14 @@ typedef std::function<bool(const MappedName&, int, long, long)> TraceCallback;
* possibly a recursive elementmap
* `mappedNames` maps a MappedName to a specific IndexedName.
*/
class AppExport ElementMap: public std::enable_shared_from_this<ElementMap> //TODO can remove shared_from_this?
class AppExport ElementMap
: public std::enable_shared_from_this<ElementMap> // TODO can remove shared_from_this?
{
public:
/** Default constructor: hooks internal functions to \c signalSaveDocument and
* \c signalStartRestoreDocument. This is related to the save and restore process
* of the map.
*/
*/
ElementMap();
/** Ensures that naming is properly assigned. It then marks as "used" all the StringID
@@ -82,14 +83,14 @@ public:
* as a parameter. Finally do this recursively for all childEelementMaps as well.
*
* @param hasherRef where all the StringID needed to build the map are stored.
*/
*/
// FIXME this should be made part of \c save, to achieve symmetry with the restore method
void beforeSave(const ::App::StringHasherRef& hasherRef) const;
/** Serialize this map. Calls \c collectChildMaps to get \c childMapSet and
* \c postfixMap, then calls the other (private) save function with those parameters.
* @param stream: serialized stream
*/
*/
void save(std::ostream& stream) const;
/** Deserialize and restore this map. This function restores \c childMaps and
@@ -97,7 +98,7 @@ public:
* parameters.
* @param hasherRef: where all the StringIDs are stored
* @param stream: stream to deserialize
*/
*/
ElementMapPtr restore(::App::StringHasherRef hasherRef, std::istream& stream);
@@ -196,9 +197,10 @@ public:
std::vector<MappedElement> getAll() const;
long getElementHistory(const MappedName & name,
long getElementHistory(const MappedName& name,
long masterTag,
MappedName *original=nullptr, std::vector<MappedName> *history=nullptr) const;
MappedName* original = nullptr,
std::vector<MappedName>* history = nullptr) const;
/** Iterate through the history of the give element name with a given callback
*
@@ -214,8 +216,10 @@ private:
* @param stream: serialized stream
* @param childMapSet: where all child element maps are stored
* @param postfixMap. where all postfixes are stored
*/
void save(std::ostream& stream, int index, const std::map<const ElementMap*, int>& childMapSet,
*/
void save(std::ostream& stream,
int index,
const std::map<const ElementMap*, int>& childMapSet,
const std::map<QByteArray, int>& postfixMap) const;
/** Deserialize and restore this map.
@@ -223,8 +227,9 @@ private:
* @param stream: stream to deserialize
* @param childMaps: where all child element maps are stored
* @param postfixes. where all postfixes are stored
*/
ElementMapPtr restore(::App::StringHasherRef hasherRef, std::istream& stream,
*/
ElementMapPtr restore(::App::StringHasherRef hasherRef,
std::istream& stream,
std::vector<ElementMapPtr>& childMaps,
const std::vector<std::string>& postfixes);
@@ -237,20 +242,27 @@ private:
* associated with another indexedName, set \c existing to that indexedname
* @return the name just added, or an empty name if it wasn't added.
*/
MappedName addName(MappedName& name, const IndexedName& idx, const ElementIDRefs& sids,
bool overwrite, IndexedName* existing);
MappedName addName(MappedName& name,
const IndexedName& idx,
const ElementIDRefs& sids,
bool overwrite,
IndexedName* existing);
/** Utility function that adds \c postfix to \c postfixMap, and to \c postfixes
* if it was not present in the map.
*/
static void addPostfix(const QByteArray& postfix, std::map<QByteArray, int>& postfixMap,
*/
static void addPostfix(const QByteArray& postfix,
std::map<QByteArray, int>& postfixMap,
std::vector<QByteArray>& postfixes);
/* Note: the original proc passed `ComplexGeoData& master` for getting the `Tag`,
* now it just passes `long masterTag`.*/
MappedName renameDuplicateElement(int index, const IndexedName& element,
const IndexedName& element2, const MappedName& name,
ElementIDRefs& sids, long masterTag) const;
MappedName renameDuplicateElement(int index,
const IndexedName& element,
const IndexedName& element2,
const MappedName& name,
ElementIDRefs& sids,
long masterTag) const;
/** Convenience method to hash the main element name
*
@@ -263,7 +275,7 @@ private:
/// Reverse hashElementName()
MappedName dehashElementName(const MappedName& name) const;
//FIXME duplicate code? as in copy/paste
// FIXME duplicate code? as in copy/paste
const MappedNameRef* findMappedRef(const IndexedName& idx) const;
MappedNameRef* findMappedRef(const IndexedName& idx);
@@ -313,6 +325,6 @@ public:
};
}// namespace Data
} // namespace Data
#endif// DATA_ELEMENTMAP_H
#endif // DATA_ELEMENTMAP_H
+65 -42
View File
@@ -4,96 +4,119 @@
#include <boost/algorithm/string/predicate.hpp>
const char *Data::isMappedElement(const char *name) {
if(name && boost::starts_with(name, ELEMENT_MAP_PREFIX))
const char* Data::isMappedElement(const char* name)
{
if (name && boost::starts_with(name, ELEMENT_MAP_PREFIX)) {
return name + ELEMENT_MAP_PREFIX_SIZE;
}
return nullptr;
}
std::string Data::newElementName(const char *name) {
if(!name)
std::string Data::newElementName(const char* name)
{
if (!name) {
return {};
const char *dot = strrchr(name,'.');
if(!dot || dot==name)
}
const char* dot = strrchr(name, '.');
if (!dot || dot == name) {
return name;
const char *c = dot-1;
for(;c!=name;--c) {
if(*c == '.') {
}
const char* c = dot - 1;
for (; c != name; --c) {
if (*c == '.') {
++c;
break;
}
}
if(isMappedElement(c))
return std::string(name,dot-name);
if (isMappedElement(c)) {
return std::string(name, dot - name);
}
return name;
}
std::string Data::oldElementName(const char *name) {
if(!name)
std::string Data::oldElementName(const char* name)
{
if (!name) {
return {};
const char *dot = strrchr(name,'.');
if(!dot || dot==name)
}
const char* dot = strrchr(name, '.');
if (!dot || dot == name) {
return name;
const char *c = dot-1;
for(;c!=name;--c) {
if(*c == '.') {
}
const char* c = dot - 1;
for (; c != name; --c) {
if (*c == '.') {
++c;
break;
}
}
if(isMappedElement(c))
return std::string(name,c-name)+(dot+1);
if (isMappedElement(c)) {
return std::string(name, c - name) + (dot + 1);
}
return name;
}
std::string Data::noElementName(const char *name) {
if(!name)
std::string Data::noElementName(const char* name)
{
if (!name) {
return {};
}
auto element = findElementName(name);
if(element)
return std::string(name,element-name);
if (element) {
return std::string(name, element - name);
}
return name;
}
const char *Data::findElementName(const char *subname) {
const char* Data::findElementName(const char* subname)
{
// skip leading dots
while(subname && subname[0] == '.')
while (subname && subname[0] == '.') {
++subname;
if(!subname || !subname[0] || isMappedElement(subname))
}
if (!subname || !subname[0] || isMappedElement(subname)) {
return subname;
const char *dot = strrchr(subname,'.');
if(!dot)
}
const char* dot = strrchr(subname, '.');
if (!dot) {
return subname;
const char *element = dot+1;
if(dot==subname || isMappedElement(element))
}
const char* element = dot + 1;
if (dot == subname || isMappedElement(element)) {
return element;
for(--dot;dot!=subname;--dot) {
if(*dot == '.') {
}
for (--dot; dot != subname; --dot) {
if (*dot == '.') {
++dot;
break;
}
}
if(isMappedElement(dot))
if (isMappedElement(dot)) {
return dot;
}
return element;
}
bool Data::hasMissingElement(const char *subname) {
if(!subname)
bool Data::hasMissingElement(const char* subname)
{
if (!subname) {
return false;
auto dot = strrchr(subname,'.');
if(dot)
subname = dot+1;
}
auto dot = strrchr(subname, '.');
if (dot) {
subname = dot + 1;
}
return boost::starts_with(subname, MISSING_PREFIX);
}
const char *Data::hasMappedElementName(const char *subname) {
const char* Data::hasMappedElementName(const char* subname)
{
return isMappedElement(findElementName(subname));
}
const std::string Data::indexSuffix(int index, const char *label)
const std::string Data::indexSuffix(int index, const char* label)
{
if ( index < 2 ) { // Don't add a suffix for item #1, begin appending at 2
if (index < 2) { // Don't add a suffix for item #1, begin appending at 2
return {""};
}
std::string name(label);
+6 -6
View File
@@ -18,10 +18,10 @@ struct ElementNamePair
ElementNamePair() = default;
ElementNamePair(std::string newNameStr, std::string oldNameStr) :
newName(std::move(newNameStr)), oldName(std::move(oldNameStr))
{
}
ElementNamePair(std::string newNameStr, std::string oldNameStr)
: newName(std::move(newNameStr))
, oldName(std::move(oldNameStr))
{}
bool operator==(const ElementNamePair& other) const
{
@@ -34,7 +34,7 @@ struct ElementNamePair
}
};
}
} // namespace App
// clang-format off
namespace Data
@@ -101,4 +101,4 @@ AppExport const std::string indexSuffix(int index, const char *label=ELEMENT_MAP
} // namespace Data
// clang-format on
#endif // ELEMENT_NAMING_UTILS_H
#endif // ELEMENT_NAMING_UTILS_H
+71 -46
View File
@@ -22,8 +22,8 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <cassert>
# include <cstring>
#include <cassert>
#include <cstring>
#endif
#include <Base/Exception.h>
@@ -32,17 +32,23 @@
using namespace App;
namespace {
struct StringCopy : public Enumeration::Object {
explicit StringCopy(const char* str) : d(str) {
}
const char* data() const override {
namespace
{
struct StringCopy: public Enumeration::Object
{
explicit StringCopy(const char* str)
: d(str)
{}
const char* data() const override
{
return d.data();
}
bool isEqual(const char* str) const override {
bool isEqual(const char* str) const override
{
return d == str;
}
bool isCustom() const override {
bool isCustom() const override
{
return true;
}
@@ -50,43 +56,47 @@ private:
std::string d;
};
struct StringView : public Enumeration::Object {
explicit StringView(const char* str) : d(str) {
}
const char* data() const override {
struct StringView: public Enumeration::Object
{
explicit StringView(const char* str)
: d(str)
{}
const char* data() const override
{
return d.data();
}
bool isEqual(const char* str) const override {
bool isEqual(const char* str) const override
{
return d == str;
}
bool isCustom() const override {
bool isCustom() const override
{
return false;
}
private:
std::string_view d;
};
}
} // namespace
Enumeration::Enumeration()
: _index(0)
{
}
{}
Enumeration::Enumeration(const Enumeration &other)
Enumeration::Enumeration(const Enumeration& other)
{
enumArray = other.enumArray;
_index = other._index;
}
Enumeration::Enumeration(const char *valStr)
Enumeration::Enumeration(const char* valStr)
: _index(0)
{
enumArray.push_back(std::make_shared<StringCopy>(valStr));
setValue(valStr);
}
Enumeration::Enumeration(const char **list, const char *valStr)
Enumeration::Enumeration(const char** list, const char* valStr)
: _index(0)
{
while (list && *list) {
@@ -101,14 +111,15 @@ Enumeration::~Enumeration()
enumArray.clear();
}
void Enumeration::setEnums(const char **plEnums)
void Enumeration::setEnums(const char** plEnums)
{
std::string oldValue;
bool preserve = (isValid() && plEnums != nullptr);
if (preserve) {
const char* str = getCStr();
if (str)
if (str) {
oldValue = str;
}
}
enumArray.clear();
@@ -118,14 +129,15 @@ void Enumeration::setEnums(const char **plEnums)
}
// set _index
if (_index < 0)
if (_index < 0) {
_index = 0;
}
if (preserve) {
setValue(oldValue);
}
}
void Enumeration::setEnums(const std::vector<std::string> &values)
void Enumeration::setEnums(const std::vector<std::string>& values)
{
if (values.empty()) {
setEnums(nullptr);
@@ -136,24 +148,26 @@ void Enumeration::setEnums(const std::vector<std::string> &values)
bool preserve = isValid();
if (preserve) {
const char* str = getCStr();
if (str)
if (str) {
oldValue = str;
}
}
enumArray.clear();
for (const auto & it : values) {
for (const auto& it : values) {
enumArray.push_back(std::make_shared<StringCopy>(it.c_str()));
}
// set _index
if (_index < 0)
if (_index < 0) {
_index = 0;
}
if (preserve) {
setValue(oldValue);
}
}
void Enumeration::setValue(const char *value)
void Enumeration::setValue(const char* value)
{
_index = 0;
for (std::size_t i = 0; i < enumArray.size(); i++) {
@@ -168,41 +182,45 @@ void Enumeration::setValue(long value, bool checkRange)
{
if (value >= 0 && value < countItems()) {
_index = value;
} else {
}
else {
if (checkRange) {
throw Base::ValueError("Out of range");
} else {
}
else {
_index = value;
}
}
}
bool Enumeration::isValue(const char *value) const
bool Enumeration::isValue(const char* value) const
{
int i = getInt();
if (i == -1) {
return false;
} else {
}
else {
return enumArray[i]->isEqual(value);
}
}
bool Enumeration::contains(const char *value) const
bool Enumeration::contains(const char* value) const
{
if (!isValid()) {
return false;
}
for (const auto& it : enumArray) {
if (it->isEqual(value))
if (it->isEqual(value)) {
return true;
}
}
return false;
}
const char * Enumeration::getCStr() const
const char* Enumeration::getCStr() const
{
if (!isValid() || _index < 0 || _index >= countItems()) {
return nullptr;
@@ -223,8 +241,9 @@ int Enumeration::getInt() const
std::vector<std::string> Enumeration::getEnumVector() const
{
std::vector<std::string> list;
for (const auto& it : enumArray)
for (const auto& it : enumArray) {
list.emplace_back(it->data());
}
return list;
}
@@ -241,24 +260,27 @@ bool Enumeration::isValid() const
int Enumeration::maxValue() const
{
int num = -1;
if (!enumArray.empty())
if (!enumArray.empty()) {
num = static_cast<int>(enumArray.size()) - 1;
}
return num;
}
bool Enumeration::isCustom() const
{
for (const auto& it : enumArray) {
if (it->isCustom())
if (it->isCustom()) {
return true;
}
}
return false;
}
Enumeration & Enumeration::operator=(const Enumeration &other)
Enumeration& Enumeration::operator=(const Enumeration& other)
{
if (this == &other)
if (this == &other) {
return *this;
}
enumArray = other.enumArray;
_index = other._index;
@@ -266,23 +288,26 @@ Enumeration & Enumeration::operator=(const Enumeration &other)
return *this;
}
bool Enumeration::operator==(const Enumeration &other) const
bool Enumeration::operator==(const Enumeration& other) const
{
if (_index != other._index || enumArray.size() != other.enumArray.size()) {
return false;
}
for (size_t i = 0; i < enumArray.size(); ++i) {
if (enumArray[i]->data() == other.enumArray[i]->data())
if (enumArray[i]->data() == other.enumArray[i]->data()) {
continue;
if (!enumArray[i]->data() || !other.enumArray[i]->data())
}
if (!enumArray[i]->data() || !other.enumArray[i]->data()) {
return false;
if (!enumArray[i]->isEqual(other.enumArray[i]->data()))
}
if (!enumArray[i]->isEqual(other.enumArray[i]->data())) {
return false;
}
}
return true;
}
bool Enumeration::operator==(const char *other) const
bool Enumeration::operator==(const char* other) const
{
if (!getCStr()) {
return false;
+134 -130
View File
@@ -31,162 +31,166 @@
namespace App
{
/// A bidirectional string-integer mapping
/*!
* This is mainly intended for two purposes: working around the difficulty
* in C++ of sharing enumerations between different source files,
* namespaces, etc. and as the data type stored by App::PropertyEnumeration
*
* Internally, Enumeration maintains
* -# Either a const pointer to an array of C-style strings, or a vector
* of C++ std::strings
* -# An integer index into that array/vector representing the string
* representing the instance's value.
*
* If built with FC_DEBUG defined, some boundaries of passed in pointers
* will be checked. Otherwise, the caller has the responsibility of
* checking the limits of given indices.
*
* \todo Implement lazy copy
*/
class AppExport Enumeration
/// A bidirectional string-integer mapping
/*!
* This is mainly intended for two purposes: working around the difficulty
* in C++ of sharing enumerations between different source files,
* namespaces, etc. and as the data type stored by App::PropertyEnumeration
*
* Internally, Enumeration maintains
* -# Either a const pointer to an array of C-style strings, or a vector
* of C++ std::strings
* -# An integer index into that array/vector representing the string
* representing the instance's value.
*
* If built with FC_DEBUG defined, some boundaries of passed in pointers
* will be checked. Otherwise, the caller has the responsibility of
* checking the limits of given indices.
*
* \todo Implement lazy copy
*/
class AppExport Enumeration
{
public:
class Object
{
public:
class Object {
public:
virtual ~Object() = default;
virtual const char* data() const = 0;
virtual bool isEqual(const char*) const = 0;
virtual bool isCustom() const = 0;
};
virtual ~Object() = default;
virtual const char* data() const = 0;
virtual bool isEqual(const char*) const = 0;
virtual bool isCustom() const = 0;
};
public:
/// Constructs an empty Enumeration object
Enumeration();
public:
/// Constructs an empty Enumeration object
Enumeration();
/// Standard copy constructor
Enumeration(const Enumeration& other);
/// Standard copy constructor
Enumeration(const Enumeration& other);
/// Constructs an Enumeration with a single element
explicit Enumeration(const char *valStr);
/// Constructs an Enumeration with a single element
explicit Enumeration(const char* valStr);
/// Constructs an Enumeration using val within list
Enumeration(const char **list, const char *valStr);
/// Constructs an Enumeration using val within list
Enumeration(const char** list, const char* valStr);
/// Standard destructor
~Enumeration();
/// Standard destructor
~Enumeration();
/** Sets the enumeration string list
* The list is a NULL terminated array of pointers to const
* char* strings.
* \code
* const char enums[] = {"Black","White","Other",NULL}
* \endcode
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*
* Enumeration does not take ownership of the passed object
*/
void setEnums(const char **plEnums);
/** Sets the enumeration string list
* The list is a NULL terminated array of pointers to const
* char* strings.
* \code
* const char enums[] = {"Black","White","Other",NULL}
* \endcode
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*
* Enumeration does not take ownership of the passed object
*/
void setEnums(const char** plEnums);
/// Set all enum values as vector of strings
/*!
* This method causes the Enumeration to dynamically allocate
* it's own array of C Strings, which will be deleted by the
* destructor or subsequent calls to setEnums(). So, it is
* important to make sure the Enumeration stays in scope as
* long as values returned by getCStr are in use.
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*/
void setEnums(const std::vector<std::string> &values);
/// Set all enum values as vector of strings
/*!
* This method causes the Enumeration to dynamically allocate
* it's own array of C Strings, which will be deleted by the
* destructor or subsequent calls to setEnums(). So, it is
* important to make sure the Enumeration stays in scope as
* long as values returned by getCStr are in use.
*
* If Enumeration was already valid, will attempt to preserve
* the string-representation value of the Enumeration
*/
void setEnums(const std::vector<std::string>& values);
/// Set the enum using a C string
void setValue(const char *value);
/// Set the enum using a C string
void setValue(const char* value);
/// Overload of setValue(const char *value)
void setValue(const std::string &value) {setValue(value.c_str());}
/// Overload of setValue(const char *value)
void setValue(const std::string& value)
{
setValue(value.c_str());
}
/// Set the enum using a long
/*!
* if checkRange is set to true, throws Base::ValueError when
* values are set out of range
*
* Checks for boundaries via assert()
*/
void setValue(long value, bool checkRange = false);
/// Set the enum using a long
/*!
* if checkRange is set to true, throws Base::ValueError when
* values are set out of range
*
* Checks for boundaries via assert()
*/
void setValue(long value, bool checkRange = false);
/// Checks if the property is set to a certain string value
bool isValue(const char *value) const;
/// Checks if the property is set to a certain string value
bool isValue(const char* value) const;
/// Checks if a string is included in the enumeration
bool contains(const char *value) const;
/// Checks if a string is included in the enumeration
bool contains(const char* value) const;
/// Return the value as C string
/*!
* Returns NULL if the enumeration is invalid.
*/
const char * getCStr() const;
/// Return the value as C string
/*!
* Returns NULL if the enumeration is invalid.
*/
const char* getCStr() const;
/// Return value as integer
/*!
* Returns -1 if the Enumeration isn't valid
*/
int getInt() const;
/// Return value as integer
/*!
* Returns -1 if the Enumeration isn't valid
*/
int getInt() const;
/// get all possible enum values as vector of strings
std::vector<std::string> getEnumVector() const;
/// get all possible enum values as vector of strings
std::vector<std::string> getEnumVector() const;
/// returns true if the enum list is non-empty, false otherwise
bool hasEnums() const;
/// returns true if the enum list is non-empty, false otherwise
bool hasEnums() const;
/// Returns true if the instance is in a usable state
bool isValid() const;
/// Returns true if the instance is in a usable state
bool isValid() const;
/// Returns the highest usable integer value for this enum
/*!
* Returns -1 if the enumeration is not valid according to isValid()
*/
int maxValue() const;
/// Returns the highest usable integer value for this enum
/*!
* Returns -1 if the enumeration is not valid according to isValid()
*/
int maxValue() const;
/// Returns true if any of the items is a user-defined string
bool isCustom() const;
/// Returns true if any of the items is a user-defined string
bool isCustom() const;
/// Assignment operator
Enumeration & operator=(const Enumeration &other);
/// Assignment operator
Enumeration& operator=(const Enumeration& other);
/// true iff our string representation matches other's
/*!
* Returns false if either Enumeration is not valid.
*/
bool operator==(const Enumeration &other) const;
/// true iff our string representation matches other's
/*!
* Returns false if either Enumeration is not valid.
*/
bool operator==(const Enumeration& other) const;
/// true iff our string representation matches other
/*!
* Returns false if Enumeration is not valid.
*/
bool operator==(const char *other) const;
protected:
/// true iff our string representation matches other
/*!
* Returns false if Enumeration is not valid.
*/
bool operator==(const char* other) const;
/// Number of items
int countItems() const;
protected:
/// Number of items
int countItems() const;
private:
/// Handle to C Strings of possible enumeration values
using ObjectPtr = std::shared_ptr<Object>;
std::vector<ObjectPtr> enumArray;
private:
/// Handle to C Strings of possible enumeration values
using ObjectPtr = std::shared_ptr<Object>;
std::vector<ObjectPtr> enumArray;
/// Integer value of the enumeration
/*!
* This serves as an index into enumArray to get the string
* representation.
*/
int _index;
/// Integer value of the enumeration
/*!
* This serves as an index into enumArray to get the string
* representation.
*/
int _index;
friend class PropertyEnumeration;
}; // class Enumeration
} // namespace App
friend class PropertyEnumeration;
}; // class Enumeration
} // namespace App
#endif // #ifndef BASE_ENUMERATION_H
#endif // #ifndef BASE_ENUMERATION_H
+7
View File
@@ -3855,6 +3855,13 @@ bool ExpressionParser::isTokenAnIndentifier(const std::string & str)
return (status == 0 && (token == IDENTIFIER || token == CELLADDRESS));
}
bool ExpressionParser::isTokenAConstant(const std::string & str)
{
int token{}, status{};
std::tie(token, status) = getTokenAndStatus(str);
return (status == 0 && token == CONSTANT);
}
bool ExpressionParser::isTokenAUnit(const std::string & str)
{
int token{}, status{};

Some files were not shown because too many files have changed in this diff Show More