Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b2296936c | |||
| 56530cd309 |
@@ -16,6 +16,7 @@ If FREECAD_EXEC is an executable path, it is used directly.
|
||||
This script returns 0 if all GUI modules run successfully. Otherwise it returns the last non-zero
|
||||
exit code.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
logdir: /tmp/log/
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -10,10 +10,6 @@ permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: build-release-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
upload_src:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -21,11 +17,11 @@ jobs:
|
||||
build_tag: ${{ steps.get_tag.outputs.build_tag }}
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout source
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
@@ -33,7 +29,7 @@ jobs:
|
||||
fetch-tags: true
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Get tag and create release if weekly
|
||||
- name: get tag and create release if weekly
|
||||
id: get_tag
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
@@ -43,10 +39,7 @@ jobs:
|
||||
export BUILD_TAG="${{ github.event.release.tag_name }}"
|
||||
else
|
||||
export BUILD_TAG=weekly-$(date "+%Y.%m.%d")
|
||||
gh release create ${BUILD_TAG} --title "Development Build ${BUILD_TAG}" \
|
||||
-F .github/workflows/weekly-build-notes.md \
|
||||
--prerelease || \
|
||||
gh release view ${BUILD_TAG} > /dev/null # fail if it doesn't exist
|
||||
gh release create ${BUILD_TAG} --title "Development Build ${BUILD_TAG}" -F .github/workflows/weekly-build-notes.md --prerelease || true
|
||||
fi
|
||||
echo "BUILD_TAG=${BUILD_TAG}" >> "$GITHUB_ENV"
|
||||
echo "build_tag=${BUILD_TAG}" >> "$GITHUB_OUTPUT"
|
||||
@@ -112,7 +105,7 @@ jobs:
|
||||
environment: weekly-build
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -125,7 +118,7 @@ jobs:
|
||||
remove-android: 'true' # (frees ~9 GB)
|
||||
remove-cached-tools: 'true' # (frees ~8.3 GB)
|
||||
|
||||
- name: Set platform environment variables
|
||||
- name: Set Platform Environment Variables
|
||||
shell: bash -l {0}
|
||||
env:
|
||||
OPERATING_SYSTEM: ${{ runner.os }}
|
||||
@@ -135,7 +128,7 @@ jobs:
|
||||
echo 'RATTLER_CACHE_DIR=D:\rattler' >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Checkout source
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
@@ -149,7 +142,7 @@ jobs:
|
||||
cache: false
|
||||
|
||||
- name: Install the Apple certificate and provisioning profile
|
||||
id: macos_get_cert
|
||||
id: get_cert
|
||||
if: runner.os == 'macOS'
|
||||
env:
|
||||
APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }}
|
||||
@@ -157,6 +150,7 @@ jobs:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
|
||||
DEVELOPER_TEAM_ID: ${{ secrets.DEVELOPER_TEAM_ID }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
||||
run: |
|
||||
if [ -z "$BUILD_CERTIFICATE_BASE64" ]; then
|
||||
@@ -192,81 +186,23 @@ jobs:
|
||||
|
||||
xcrun notarytool store-credentials "FreeCAD" --keychain "$KEYCHAIN_PATH" --apple-id "${APPLE_ID}" --password "${APP_SPECIFIC_PASSWORD}" --team-id "${DEVELOPER_TEAM_ID}"
|
||||
|
||||
- name: Setup .NET 10 SDK
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/setup-dotnet@baa11fbfe1d6520db94683bd5c7a3818018e4309 # v5.1.0
|
||||
with:
|
||||
dotnet-version: '10.0.103'
|
||||
|
||||
- name: Install sign tool
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
# NOTE: The sign tool is ONLY available as a prerelease package, they never issue real releases.
|
||||
dotnet tool install --global --prerelease sign
|
||||
echo "$env:USERPROFILE\.dotnet\tools" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
dotnet --info
|
||||
sign --version
|
||||
|
||||
- name: Build packages
|
||||
- name: Build and Release Packages
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
|
||||
SIGN_RELEASE: ${{ steps.get_cert.outputs.has_cert }}
|
||||
TARGET_PLATFORM: ${{ matrix.target }}
|
||||
MAKE_INSTALLER: "true"
|
||||
UPLOAD_RELEASE: "true"
|
||||
BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "${{ runner.os }}" == "macOS" ]]; then
|
||||
export MACOS_DEPLOYMENT_TARGET="${{ matrix.deploy_target }}"
|
||||
fi
|
||||
python3 package/scripts/write_version_info.py ../freecad_version.txt
|
||||
cd package/rattler-build
|
||||
pixi install
|
||||
|
||||
- name: Azure login for Windows build code signing
|
||||
id: azure_login
|
||||
if: runner.os == 'Windows'
|
||||
continue-on-error: true
|
||||
uses: azure/login@a457da9ea143d694b1b9c7c869ebb04ebe844ef5 # v2.3.0
|
||||
with:
|
||||
creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
|
||||
|
||||
- name: Release packages with optional code-signing on Windows and macOS
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TARGET_PLATFORM: ${{ matrix.target }}
|
||||
MAKE_INSTALLER: "true"
|
||||
UPLOAD_RELEASE: "true"
|
||||
BUILD_TAG: ${{ needs.upload_src.outputs.build_tag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
export MACOS_SIGN_RELEASE=0
|
||||
export WINDOWS_SIGN_RELEASE=0
|
||||
|
||||
case "${RUNNER_OS}" in
|
||||
Windows)
|
||||
export WINDOWS_SIGN_RELEASE="${{ steps.azure_login.outcome }}"
|
||||
export WINDOWS_AZURE_ENDPOINT="${{ vars.AZURE_TRUSTED_SIGNING_ENDPOINT }}"
|
||||
export WINDOWS_AZURE_CERTIFICATE_PROFILE="${{ vars.AZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE }}"
|
||||
export WINDOWS_AZURE_SIGNING_ACCOUNT="${{ vars.AZURE_TRUSTED_SIGNING_ACCOUNT }}"
|
||||
|
||||
# For good measure, normalize the azure_login result to 1 or 0
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-}" == "success" ]]; then
|
||||
export WINDOWS_SIGN_RELEASE=1
|
||||
else
|
||||
export WINDOWS_SIGN_RELEASE=0
|
||||
fi
|
||||
;;
|
||||
|
||||
macOS)
|
||||
export MACOS_SIGN_RELEASE="${{ steps.macos_get_cert.outputs.has_cert }}"
|
||||
export MACOS_SIGNING_KEY_ID="${{ secrets.SIGNING_KEY_ID }}"
|
||||
export MACOS_DEPLOYMENT_TARGET="${{ matrix.deploy_target }}"
|
||||
;;
|
||||
esac
|
||||
|
||||
cd package/rattler-build
|
||||
pixi run -e package create_bundle
|
||||
|
||||
## Needed if running on a self-hosted runner:
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4
|
||||
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Harden the runner (Audit all outbound calls)
|
||||
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
|
||||
uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
cat report.md >> $GITHUB_STEP_SUMMARY
|
||||
- name: Delete used artifacts
|
||||
continue-on-error: true
|
||||
uses: geekyeggo/delete-artifact@176a747ab7e287e3ff4787bf8a148716375ca118 # v6.0.0
|
||||
uses: geekyeggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b # v5.1.0
|
||||
with:
|
||||
name: |
|
||||
${{ env.usedArtifacts }}
|
||||
|
||||
@@ -70,11 +70,11 @@ repos:
|
||||
- id: check-added-large-files
|
||||
- id: mixed-line-ending
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 2892f1f81088477370d4fbc56545c05d33d2493f # frozen: 25.11.0
|
||||
rev: fa505ab9c3e0fedafe1709fd7ac2b5f8996c670d # frozen: 26.3.1
|
||||
hooks:
|
||||
- id: black
|
||||
args: ['--line-length', '100']
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: 317810f3c6a0ad3572367dc86cb6e41863e16e08 # frozen: v21.1.5
|
||||
rev: 88c364bab316f4b6b18f6c298133bbbf32d7cd15 # frozen: v22.1.1
|
||||
hooks:
|
||||
- id: clang-format
|
||||
|
||||
@@ -76,9 +76,9 @@ if [ -d "${conda_env}/PlugIns" ]; then
|
||||
mv ${conda_env}/PlugIns ${conda_env}/..
|
||||
fi
|
||||
|
||||
if [[ "${MACOS_SIGN_RELEASE}" == "true" ]]; then
|
||||
if [[ "${SIGN_RELEASE}" == "true" ]]; then
|
||||
# create the signed dmg
|
||||
../../scripts/macos_sign_and_notarize.zsh -p "FreeCAD" -k ${MACOS_SIGNING_KEY_ID} -o "${version_name}.dmg"
|
||||
../../scripts/macos_sign_and_notarize.zsh -p "FreeCAD" -k ${SIGNING_KEY_ID} -o "${version_name}.dmg"
|
||||
else
|
||||
# Ad-hoc sign for local builds (required for QuickLook extensions to register)
|
||||
if [ -d "FreeCAD.app/Contents/PlugIns" ]; then
|
||||
|
||||
@@ -100,7 +100,7 @@ requirements:
|
||||
|
||||
host:
|
||||
- coin3d
|
||||
- eigen >=3.3,<5
|
||||
- eigen
|
||||
- fmt
|
||||
- freetype
|
||||
- hdf5
|
||||
|
||||
@@ -44,9 +44,6 @@ find ${copy_dir} -name \*arm\*.exe -delete # arm binaries that fail to extract u
|
||||
mv ${copy_dir}/bin/Lib/ssl.py .ssl-orig.py
|
||||
cp ssl-patch.py ${copy_dir}/bin/Lib/ssl.py
|
||||
|
||||
# Turn off the echo before we start actually calling "echo"
|
||||
set +x
|
||||
|
||||
echo '[Paths]' >> ${copy_dir}/bin/qt6.conf
|
||||
echo 'Prefix = ../lib/qt6' >> ${copy_dir}/bin/qt6.conf
|
||||
|
||||
@@ -70,64 +67,6 @@ sed -i '1s/.*/\nLIST OF PACKAGES:/' ${copy_dir}/packages.txt
|
||||
|
||||
mv ${copy_dir} ${version_name}
|
||||
|
||||
|
||||
# Sign the EXE, DLL, and PYD files (if we can access the Azure account for signing):
|
||||
set -euo pipefail
|
||||
SIGN_DIR="${version_name}"
|
||||
|
||||
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-0}" == "1" ]]; then
|
||||
TENANT="$(az account show --query tenantId -o tsv)"
|
||||
export AZURE_IDENTITY_DISABLE_WORKLOAD_IDENTITY=true
|
||||
export AZURE_IDENTITY_DISABLE_MANAGED_IDENTITY=true
|
||||
unset AZURE_IDENTITY_LOGGING_ENABLED
|
||||
|
||||
if az account get-access-token \
|
||||
--tenant "$TENANT" \
|
||||
--scope "https://codesigning.azure.net/.default" \
|
||||
>/dev/null 2>&1;
|
||||
then
|
||||
echo "Azure Artifact Signing access confirmed. Beginning signing process..."
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
FILES=(
|
||||
"$SIGN_DIR"/*.exe
|
||||
"$SIGN_DIR"/bin/*.exe
|
||||
"$SIGN_DIR"/bin/*.dll
|
||||
"$SIGN_DIR"/bin/*.pyd
|
||||
)
|
||||
|
||||
count=0
|
||||
total=${#FILES[@]}
|
||||
echo "Signing $total files"
|
||||
for f in "${FILES[@]}"; do
|
||||
((count+=1))
|
||||
echo "Signing [$count/$total]: $f"
|
||||
sign code artifact-signing \
|
||||
--artifact-signing-endpoint "${WINDOWS_AZURE_ENDPOINT}" \
|
||||
--artifact-signing-certificate-profile "${WINDOWS_AZURE_CERTIFICATE_PROFILE}" \
|
||||
--artifact-signing-account "${WINDOWS_AZURE_SIGNING_ACCOUNT}" \
|
||||
--timestamp-url https://timestamp.acs.microsoft.com \
|
||||
--timestamp-digest sha256 \
|
||||
"$f" >/dev/null 2>&1
|
||||
|
||||
# Output was redirected to /dev/null because Azure authentication is absurdly noisy, with constant misleading
|
||||
# "failure" messages about Managed Identity authentication failing. We don't use, or want to use, that
|
||||
# authentication, and the fact that it fails is not a problem as long as the real authentication succeeds.
|
||||
done
|
||||
|
||||
# Manually check the important one!
|
||||
signtool verify -pa "$SIGN_DIR/bin/FreeCAD.exe"
|
||||
|
||||
echo "Signing completed."
|
||||
else
|
||||
echo "Signing requested, but no Azure Artifact Signing available -- skipping signing."
|
||||
fi
|
||||
else
|
||||
echo "Not logged into Azure -- skipping signing."
|
||||
fi
|
||||
|
||||
7z a -t7z -mx9 -mmt=${NUMBER_OF_PROCESSORS} ${version_name}.7z ${version_name} -bb
|
||||
# create hash
|
||||
sha256sum ${version_name}.7z > ${version_name}.7z-SHA256.txt
|
||||
@@ -149,28 +88,6 @@ if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
-X'SetCompressor /FINAL lzma' \
|
||||
../../WindowsInstaller/FreeCAD-installer.nsi
|
||||
mv ../../WindowsInstaller/${version_name}-installer.exe .
|
||||
echo "Created installer ${version_name}-installer.exe"
|
||||
|
||||
# See if we can sign the installer exe as well:
|
||||
if [[ "${WINDOWS_SIGN_RELEASE:-0}" == "1" ]] && \
|
||||
az account get-access-token \
|
||||
--tenant "$TENANT" \
|
||||
--scope "https://codesigning.azure.net/.default" \
|
||||
>/dev/null 2>&1;
|
||||
then
|
||||
echo "Signing the installer..."
|
||||
sign code artifact-signing \
|
||||
--artifact-signing-endpoint "${WINDOWS_AZURE_ENDPOINT}" \
|
||||
--artifact-signing-certificate-profile "${WINDOWS_AZURE_CERTIFICATE_PROFILE}" \
|
||||
--artifact-signing-account "${WINDOWS_AZURE_SIGNING_ACCOUNT}" \
|
||||
--timestamp-url https://timestamp.acs.microsoft.com \
|
||||
--timestamp-digest sha256 \
|
||||
${version_name}-installer.exe >/dev/null 2>&1 \
|
||||
|| { echo "Signing the installer failed!"; exit 1; }
|
||||
else
|
||||
echo "No code signing available, leaving the installer unsigned"
|
||||
fi
|
||||
|
||||
sha256sum ${version_name}-installer.exe > ${version_name}-installer.exe-SHA256.txt
|
||||
else
|
||||
echo "Error: Failed to get NsProcess plugin. Aborting installer creation..."
|
||||
@@ -179,10 +96,8 @@ if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
fi
|
||||
|
||||
if [ "${UPLOAD_RELEASE}" == "true" ]; then
|
||||
echo "Uploading the release..."
|
||||
gh release upload --clobber ${BUILD_TAG} "${version_name}.7z" "${version_name}.7z-SHA256.txt"
|
||||
if [ "${MAKE_INSTALLER}" == "true" ]; then
|
||||
gh release upload --clobber ${BUILD_TAG} "${version_name}-installer.exe" "${version_name}-installer.exe-SHA256.txt"
|
||||
fi
|
||||
echo "Done uploading"
|
||||
fi
|
||||
|
||||
@@ -19,12 +19,11 @@ debugpy = "*"
|
||||
defusedxml = "*"
|
||||
docutils = "*"
|
||||
doxygen = "*"
|
||||
eigen = ">=3.3,<5"
|
||||
eigen = "*"
|
||||
fmt = "*"
|
||||
freetype = "*"
|
||||
git = "*"
|
||||
graphviz = "*"
|
||||
harfbuzz = "*"
|
||||
hdf5 = "*"
|
||||
ifcopenshell = "*"
|
||||
lark = "*"
|
||||
|
||||
@@ -587,15 +587,6 @@ Document* Application::getDocument(const char *Name) const
|
||||
|
||||
return pos->second;
|
||||
}
|
||||
Document* Application::getDocumentOrActive(const char *Name) const
|
||||
{
|
||||
if (!Base::Tools::isNullOrEmpty(Name)) {
|
||||
return getDocument(Name);
|
||||
}
|
||||
else {
|
||||
return getActiveDocument();
|
||||
}
|
||||
}
|
||||
|
||||
const char * Application::getDocumentName(const Document* doc) const
|
||||
{
|
||||
|
||||
+27
-52
@@ -35,12 +35,10 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include <Base/Observer.h>
|
||||
#include <Base/Parameter.h>
|
||||
#include <Base/ProgressIndicator.h>
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
// forward declarations
|
||||
using PyObject = struct _object;
|
||||
@@ -205,8 +203,6 @@ public:
|
||||
*/
|
||||
App::Document* getDocument(const char *Name) const;
|
||||
|
||||
App::Document* getDocumentOrActive(const char *Name) const;
|
||||
|
||||
/// %Path matching modes for getDocumentByPath()
|
||||
enum class PathMatchMode
|
||||
{
|
||||
@@ -293,11 +289,9 @@ public:
|
||||
/**
|
||||
* @brief Setup a pending application-wide active transaction.
|
||||
*
|
||||
* Call this function to setup a transaction in the currently active document
|
||||
* if no document is active, a global transaction is created. If the current
|
||||
* active document already has a transaction setup it will either commit the
|
||||
* current transaction or rename it, depending on the tmpName flag of the
|
||||
* currently setup transaction. No new transaction is created by this call. Any subsequent
|
||||
* Call this function to setup an application-wide transaction. All current
|
||||
* pending transactions of opening documents will be committed first.
|
||||
* However, no new transaction is created by this call. Any subsequent
|
||||
* changes in any current opening document will auto create a transaction
|
||||
* with the given name and ID. If more than one document is changed, the
|
||||
* transactions will share the same ID, and will be undo/redo together.
|
||||
@@ -309,45 +303,32 @@ public:
|
||||
*
|
||||
* @return The new transaction ID.
|
||||
*/
|
||||
int setActiveTransaction(const char* name, bool persist = false);
|
||||
|
||||
int setActiveTransaction(TransactionName name);
|
||||
|
||||
/// Return the current global transaction name and ID if such a global transaction is
|
||||
/// setup (uncommon)
|
||||
std::string getActiveTransaction(int *tid=nullptr) const;
|
||||
|
||||
int openGlobalTransaction(TransactionName name);
|
||||
int getGlobalTransaction() const;
|
||||
|
||||
bool transactionIsActive(int tid) const;
|
||||
std::string getTransactionName(int tid) const;
|
||||
bool transactionTmpName(int tid) const;
|
||||
Document* transactionInitiator(int tid) const;
|
||||
std::optional<TransactionDescription> transactionDescription(int tid) const;
|
||||
void setTransactionDescription(int tid, const TransactionDescription& desc);
|
||||
void setTransactionName(int tid, const TransactionName& name);
|
||||
|
||||
/** Commit/abort current active transactions
|
||||
/**
|
||||
* @brief Get the current active transaction name and ID.
|
||||
*
|
||||
* If there is no active transaction, an empty string is returned.
|
||||
*
|
||||
* @param[in] abort: whether to abort or commit the transactions
|
||||
* @param[in] id: by default 0 meaning that the current global transaction ID is used.
|
||||
*
|
||||
* Bsides calling this function directly, it will be called by automatically
|
||||
* if 1) any new transaction is created with a different ID, or 2) any
|
||||
* transaction with the current active transaction ID is either committed or
|
||||
* aborted
|
||||
* returns true if it succeeded in closing the transaction
|
||||
* @param[out] tid If not `nullptr`, the current active transaction ID is
|
||||
* returned through this pointer.
|
||||
* @return The current active transaction name.
|
||||
*/
|
||||
bool closeActiveTransaction(TransactionCloseMode mode = TransactionCloseMode::Commit, int id=0);
|
||||
const char* getActiveTransaction(int* tid = nullptr) const;
|
||||
|
||||
/// Internally call closeActiveTransaction(), but it makes the call site clearer
|
||||
bool commitTransaction(int tid);
|
||||
bool abortTransaction(int tid);
|
||||
|
||||
|
||||
//@}
|
||||
/**
|
||||
* @brief Commit/abort current active transactions.
|
||||
*
|
||||
* @param[in] abort: whether to abort or commit the transactions
|
||||
* @param[in] id: by default 0 meaning that the current active transaction ID is used.
|
||||
*
|
||||
* Besides calling this function directly, it will be called by
|
||||
* automatically if 1) any new transaction is created with a different ID,
|
||||
* or 2) any transaction with the current active transaction ID is either
|
||||
* committed or aborted.
|
||||
*/
|
||||
void closeActiveTransaction(bool abort=false, int id=0);
|
||||
/// @}
|
||||
|
||||
// NOLINTBEGIN
|
||||
// clang-format off
|
||||
@@ -1059,16 +1040,10 @@ private:
|
||||
|
||||
friend class AutoTransaction;
|
||||
|
||||
std::map<int, TransactionDescription> _activeTransactionDescriptions; // Maps transaction ID to transaction name
|
||||
|
||||
int currentlyClosingID {0};
|
||||
|
||||
// This is the transaction ID for a global transaction
|
||||
// Documents will take this ID if it is non-zero
|
||||
// and generate their own otherwise
|
||||
int _globalTransactionID { 0 };
|
||||
bool _globalTransactionTmpName {false};
|
||||
std::string _globalTransactionName;
|
||||
std::string _activeTransactionName;
|
||||
int _activeTransactionID{0};
|
||||
int _activeTransactionGuard{0};
|
||||
bool _activeTransactionTmpName{false};
|
||||
|
||||
Base::ProgressIndicator _progressIndicator;
|
||||
|
||||
|
||||
@@ -242,7 +242,9 @@ PyMethodDef ApplicationPy::Methods[] = {
|
||||
METH_VARARGS,
|
||||
"setActiveTransaction(name, persist=False) -- setup active transaction with the given name\n\n"
|
||||
"name: the transaction name\n"
|
||||
"persist(False): This parameter has no effect and is kept for compatibility reasonss"
|
||||
"persist(False): by default, if the calling code is inside any invocation of a command, it\n"
|
||||
" will be auto closed once all commands within the current stack exists. To\n"
|
||||
" disable auto closing, set persist=True\n"
|
||||
"Returns the transaction ID for the active transaction. An application-wide\n"
|
||||
"active transaction causes any document changes to open a transaction with\n"
|
||||
"the given name and ID."},
|
||||
@@ -1199,14 +1201,14 @@ PyObject* ApplicationPy::sGetDependentObjects(PyObject* /*self*/, PyObject* args
|
||||
PyObject* ApplicationPy::sSetActiveTransaction(PyObject* /*self*/, PyObject* args)
|
||||
{
|
||||
char* name {};
|
||||
PyObject* persist = Py_False; // Not used
|
||||
PyObject* persist = Py_False;
|
||||
if (!PyArg_ParseTuple(args, "s|O!", &name, &PyBool_Type, &persist)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
Py::Long ret(GetApplication().setActiveTransaction(TransactionName {.name=name, .temporary=false}));
|
||||
Py::Long ret(GetApplication().setActiveTransaction(name, Base::asBoolean(persist)));
|
||||
return Py::new_reference_to(ret);
|
||||
}
|
||||
PY_CATCH;
|
||||
@@ -1221,8 +1223,8 @@ PyObject* ApplicationPy::sGetActiveTransaction(PyObject* /*self*/, PyObject* arg
|
||||
PY_TRY
|
||||
{
|
||||
int id = 0;
|
||||
std::string name = GetApplication().getActiveTransaction(&id);
|
||||
if (name.empty() || id <= 0) {
|
||||
const char* name = GetApplication().getActiveTransaction(&id);
|
||||
if (!name || id <= 0) {
|
||||
Py_Return;
|
||||
}
|
||||
Py::Tuple ret(2);
|
||||
@@ -1243,10 +1245,7 @@ PyObject* ApplicationPy::sCloseActiveTransaction(PyObject* /*self*/, PyObject* a
|
||||
|
||||
PY_TRY
|
||||
{
|
||||
TransactionCloseMode mode = Base::asBoolean(abort)
|
||||
? TransactionCloseMode::Abort
|
||||
: TransactionCloseMode::Commit;
|
||||
GetApplication().closeActiveTransaction(mode, id);
|
||||
GetApplication().closeActiveTransaction(Base::asBoolean(abort), id);
|
||||
Py_Return;
|
||||
}
|
||||
PY_CATCH;
|
||||
|
||||
+175
-175
@@ -35,217 +35,204 @@ FC_LOG_LEVEL_INIT("App", true, true)
|
||||
|
||||
using namespace App;
|
||||
|
||||
AutoTransaction::AutoTransaction(int tid)
|
||||
: tid(tid)
|
||||
{
|
||||
static int _TransactionLock;
|
||||
static int _TransactionClosed;
|
||||
|
||||
}
|
||||
AutoTransaction::AutoTransaction(Document* doc, const std::string& name)
|
||||
: AutoTransaction(doc->openTransaction(name))
|
||||
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;
|
||||
}
|
||||
}
|
||||
// We use negative transaction guard to disable auto transaction from here
|
||||
// and any stack below. This is to support user setting active transaction
|
||||
// before having any existing AutoTransaction on stack, or 'persist'
|
||||
// transaction that can out live AutoTransaction.
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
--app._activeTransactionGuard;
|
||||
}
|
||||
else if (tid || app._activeTransactionGuard > 0) {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
else if (app.getActiveTransaction()) {
|
||||
FC_LOG("auto transaction disabled because of '" << app._activeTransactionName << "'");
|
||||
--app._activeTransactionGuard;
|
||||
}
|
||||
else {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
FC_TRACE("construct auto Transaction " << app._activeTransactionGuard);
|
||||
}
|
||||
|
||||
AutoTransaction::~AutoTransaction()
|
||||
{
|
||||
close(TransactionCloseMode::Commit);
|
||||
auto& app = GetApplication();
|
||||
FC_TRACE("before destruct auto Transaction " << app._activeTransactionGuard);
|
||||
if (app._activeTransactionGuard < 0) {
|
||||
++app._activeTransactionGuard;
|
||||
}
|
||||
else if (!app._activeTransactionGuard) {
|
||||
#ifdef FC_DEBUG
|
||||
FC_ERR("Transaction guard error");
|
||||
#endif
|
||||
}
|
||||
else if (--app._activeTransactionGuard == 0) {
|
||||
try {
|
||||
// We don't call close() here, because close() only closes
|
||||
// transaction that we opened during construction time. However,
|
||||
// when _activeTransactionGuard reaches zero here, we are supposed
|
||||
// to close any transaction opened.
|
||||
app.closeActiveTransaction();
|
||||
}
|
||||
catch (Base::Exception& e) {
|
||||
e.reportException();
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
FC_TRACE("destruct auto Transaction " << app._activeTransactionGuard);
|
||||
}
|
||||
|
||||
void AutoTransaction::close(TransactionCloseMode mode)
|
||||
void AutoTransaction::close(bool abort)
|
||||
{
|
||||
if (tid != NullTransaction) {
|
||||
GetApplication().closeActiveTransaction(mode, tid);
|
||||
if (tid || abort) {
|
||||
GetApplication().closeActiveTransaction(abort, abort ? 0 : tid);
|
||||
tid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Application::setActiveTransaction(TransactionName name)
|
||||
void AutoTransaction::setEnable(bool enable)
|
||||
{
|
||||
if (name.name.empty()) {
|
||||
name.name = "Command";
|
||||
auto& app = GetApplication();
|
||||
if (!app._activeTransactionGuard) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pActiveDoc != nullptr) {
|
||||
return _pActiveDoc->setActiveTransaction(name);
|
||||
if ((enable && app._activeTransactionGuard > 0)
|
||||
|| (!enable && app._activeTransactionGuard < 0)) {
|
||||
return;
|
||||
}
|
||||
return openGlobalTransaction(name);
|
||||
}
|
||||
|
||||
std::string Application::getActiveTransaction(int* id) const
|
||||
{
|
||||
if (id != nullptr) {
|
||||
*id = _globalTransactionID;
|
||||
}
|
||||
return _globalTransactionID != 0 ? getTransactionName(_globalTransactionID) : "";
|
||||
}
|
||||
int Application::openGlobalTransaction(TransactionName name)
|
||||
{
|
||||
if (name.name.empty()) {
|
||||
name.name = "Command";
|
||||
}
|
||||
|
||||
FC_WARN("Setting a global transaction with name='" << name.name);
|
||||
if (_globalTransactionID != 0 && transactionTmpName(_globalTransactionID)) {
|
||||
setTransactionName(_globalTransactionID, name);
|
||||
} else {
|
||||
FC_LOG("set global transaction '" << name.name << "'");
|
||||
|
||||
if (_globalTransactionID != 0 && !commitTransaction(_globalTransactionID)) {
|
||||
FC_WARN("could not close current global transaction");
|
||||
return _globalTransactionID;
|
||||
}
|
||||
|
||||
_globalTransactionID = Transaction::getNewID();
|
||||
setTransactionDescription(
|
||||
_globalTransactionID,
|
||||
TransactionDescription {
|
||||
.initiator = nullptr,
|
||||
.name = name
|
||||
app._activeTransactionGuard = -app._activeTransactionGuard;
|
||||
FC_TRACE("toggle auto Transaction " << app._activeTransactionGuard);
|
||||
if (!enable && app._activeTransactionTmpName) {
|
||||
bool close = true;
|
||||
for (auto& v : app.DocMap) {
|
||||
if (v.second->hasPendingTransaction()) {
|
||||
close = false;
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return _globalTransactionID;
|
||||
}
|
||||
int Application::getGlobalTransaction() const
|
||||
{
|
||||
return _globalTransactionID;
|
||||
}
|
||||
bool Application::transactionIsActive(int tid) const
|
||||
{
|
||||
return transactionDescription(tid) != std::nullopt;
|
||||
}
|
||||
std::string Application::getTransactionName(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->name.name : "";
|
||||
}
|
||||
bool Application::transactionTmpName(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->name.temporary : false;
|
||||
}
|
||||
Document* Application::transactionInitiator(int tid) const
|
||||
{
|
||||
auto desc = transactionDescription(tid);
|
||||
return desc ? desc->initiator : nullptr;
|
||||
}
|
||||
std::optional<TransactionDescription> Application::transactionDescription(int tid) const
|
||||
{
|
||||
if (tid == NullTransaction) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
if (found != _activeTransactionDescriptions.end()) {
|
||||
return std::optional<TransactionDescription>(found->second);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
void Application::setTransactionDescription(int tid, const TransactionDescription& desc)
|
||||
{
|
||||
if (tid == NullTransaction) {
|
||||
return;
|
||||
}
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
bool wasPresent = (found != _activeTransactionDescriptions.end());
|
||||
|
||||
if (wasPresent && found->second.name.temporary) {
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(desc.name.name, tid);
|
||||
}
|
||||
if (close) {
|
||||
app.closeActiveTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasPresent || found->second.name.temporary) {
|
||||
_activeTransactionDescriptions[tid] = desc;
|
||||
FC_LOG("transaction rename to '" << desc.name.name << "'");
|
||||
}
|
||||
}
|
||||
void Application::setTransactionName(int tid, const TransactionName& name)
|
||||
{
|
||||
if (tid == NullTransaction || !transactionIsActive(tid)) {
|
||||
return;
|
||||
}
|
||||
auto found = _activeTransactionDescriptions.find(tid);
|
||||
if (found == _activeTransactionDescriptions.end() || found->second.name.temporary) {
|
||||
_activeTransactionDescriptions[tid].name = name;
|
||||
FC_LOG("transaction rename to '" << name.name << "'");
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(name.name, tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::closeActiveTransaction(TransactionCloseMode mode, int id)
|
||||
int Application::setActiveTransaction(const char* name, bool persist)
|
||||
{
|
||||
bool abort = (mode == TransactionCloseMode::Abort);
|
||||
|
||||
if (!name || !name[0]) {
|
||||
name = "Command";
|
||||
}
|
||||
|
||||
if (id == NullTransaction) {
|
||||
if (_pActiveDoc != nullptr && _pActiveDoc->getBookedTransactionID() != NullTransaction) {
|
||||
id = _pActiveDoc->getBookedTransactionID();
|
||||
} else {
|
||||
id = _globalTransactionID;
|
||||
}
|
||||
}
|
||||
if (id == NullTransaction || id == currentlyClosingID) {
|
||||
return false;
|
||||
}
|
||||
currentlyClosingID = id;
|
||||
|
||||
std::vector<Document*> docsToPoke;
|
||||
for (auto& docNameAndDoc : DocMap) {
|
||||
if (docNameAndDoc.second->getBookedTransactionID() != id) {
|
||||
continue;
|
||||
}
|
||||
if(docNameAndDoc.second->isTransactionLocked() || docNameAndDoc.second->transacting()) {
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
currentlyClosingID = 0;
|
||||
return false;
|
||||
}
|
||||
if(docNameAndDoc.second->transacting()) {
|
||||
FC_LOG("pending " << (abort ? "abort" : "close") << " transaction");
|
||||
currentlyClosingID = 0;
|
||||
return false;
|
||||
}
|
||||
docsToPoke.push_back(docNameAndDoc.second);
|
||||
}
|
||||
|
||||
FC_LOG("close transaction '" << _activeTransactionDescriptions[id].name.name << "' " << abort);
|
||||
_activeTransactionDescriptions.erase(id);
|
||||
if (id == _globalTransactionID) {
|
||||
_globalTransactionID = 0;
|
||||
}
|
||||
|
||||
TransactionSignaller signaller(abort, false);
|
||||
|
||||
for (auto& doc : docsToPoke) {
|
||||
if (abort) {
|
||||
doc->_abortTransaction();
|
||||
this->signalBeforeOpenTransaction(name);
|
||||
if (_activeTransactionGuard > 0 && getActiveTransaction()) {
|
||||
if (_activeTransactionTmpName) {
|
||||
FC_LOG("transaction rename to '" << name << "'");
|
||||
for (auto& v : DocMap) {
|
||||
v.second->renameTransaction(name, _activeTransactionID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
doc->_commitTransaction();
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
currentlyClosingID = 0;
|
||||
else if (_TransactionLock) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
FC_LOG("set active transaction '" << name << "'");
|
||||
_activeTransactionID = 0;
|
||||
for (auto& v : DocMap) {
|
||||
v.second->_commitTransaction();
|
||||
}
|
||||
_activeTransactionID = Transaction::getNewID();
|
||||
}
|
||||
_activeTransactionTmpName = false;
|
||||
_activeTransactionName = name;
|
||||
if (persist) {
|
||||
AutoTransaction::setEnable(false);
|
||||
}
|
||||
return _activeTransactionID;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Application::commitTransaction(int tid)
|
||||
const char* Application::getActiveTransaction(int* id) const
|
||||
{
|
||||
return closeActiveTransaction(TransactionCloseMode::Commit, tid);
|
||||
int tid = 0;
|
||||
if (Transaction::getLastID() == _activeTransactionID) {
|
||||
tid = _activeTransactionID;
|
||||
}
|
||||
if (id) {
|
||||
*id = tid;
|
||||
}
|
||||
return tid ? _activeTransactionName.c_str() : nullptr;
|
||||
}
|
||||
bool Application::abortTransaction(int tid)
|
||||
|
||||
void Application::closeActiveTransaction(bool abort, int id)
|
||||
{
|
||||
return closeActiveTransaction(TransactionCloseMode::Abort, tid);
|
||||
if (!id) {
|
||||
id = _activeTransactionID;
|
||||
}
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_activeTransactionGuard > 0 && !abort) {
|
||||
FC_LOG("ignore close transaction");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_TransactionLock) {
|
||||
if (_TransactionClosed >= 0) {
|
||||
_TransactionLock = abort ? -1 : 1;
|
||||
}
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
if (abort) {
|
||||
v.second->_abortTransaction();
|
||||
}
|
||||
else {
|
||||
v.second->_commitTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TransactionLocker::TransactionLocker(Document* doc, bool lock)
|
||||
TransactionLocker::TransactionLocker(bool lock)
|
||||
: active(lock)
|
||||
, doc(doc)
|
||||
{
|
||||
if (lock) {
|
||||
doc->lockTransaction();
|
||||
++_TransactionLock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,9 +267,22 @@ void TransactionLocker::activate(bool enable)
|
||||
|
||||
active = enable;
|
||||
if (active) {
|
||||
doc->lockTransaction();
|
||||
++_TransactionLock;
|
||||
return;
|
||||
}
|
||||
|
||||
doc->unlockTransaction();
|
||||
if (--_TransactionLock != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_TransactionClosed) {
|
||||
bool abort = (_TransactionClosed < 0);
|
||||
_TransactionClosed = 0;
|
||||
GetApplication().closeActiveTransaction(abort);
|
||||
}
|
||||
}
|
||||
|
||||
bool TransactionLocker::isLocked()
|
||||
{
|
||||
return _TransactionLock > 0;
|
||||
}
|
||||
|
||||
+48
-22
@@ -26,15 +26,11 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <FCGlobal.h>
|
||||
#include <string>
|
||||
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Application;
|
||||
class Document;
|
||||
|
||||
/**
|
||||
* @brief A helper class to manage transactions (i.e. undo/redo).
|
||||
@@ -49,31 +45,59 @@ public:
|
||||
void* operator new(std::size_t) = delete;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
*
|
||||
* @param tid the ID of the transaction to manage
|
||||
*
|
||||
* No action is done in the constructor
|
||||
/**
|
||||
* @brief Construct an auto transaction.
|
||||
*
|
||||
* @param[in] name: optional new transaction name on construction
|
||||
* @param[in] tmpName: if true and a new transaction is setup, the name given is
|
||||
* considered as temporary, and subsequent construction of this class (or
|
||||
* calling Application::setActiveTransaction()) can override the transaction
|
||||
* name.
|
||||
*
|
||||
* The constructor increments an internal counter
|
||||
* (Application::_activeTransactionGuard). The counter prevents any new
|
||||
* active transactions being setup. It also prevents to close
|
||||
* (i.e. commits) the current active transaction until it reaches zero. It
|
||||
* does not have any effect on aborting transactions though.
|
||||
*/
|
||||
explicit AutoTransaction(int tid);
|
||||
AutoTransaction(Document* doc, const std::string& name);
|
||||
|
||||
/** Destructor
|
||||
*
|
||||
* This destructor attempts to commit the transaction it manages
|
||||
AutoTransaction(const char* name = nullptr, bool tmpName = false);
|
||||
|
||||
/**
|
||||
* @brief Destruct an auto transaction.
|
||||
*
|
||||
* This destructor decrease an internal counter
|
||||
* (Application::_activeTransactionGuard), and will commit any current
|
||||
* active transaction when the counter reaches zero.
|
||||
*/
|
||||
~AutoTransaction();
|
||||
|
||||
/**
|
||||
* @brief Close or abort the transaction.
|
||||
*
|
||||
* This function can be used to explicitly close (i.e. commit / abort) the
|
||||
* transaction,
|
||||
* This function can be used to explicitly close (i.e. commit) the
|
||||
* transaction, if the current transaction ID matches the one created inside
|
||||
* the constructor. For aborting, it will abort any current transaction.
|
||||
*
|
||||
* @param[in] abort: if true, abort the transaction; otherwise, commit it.
|
||||
*/
|
||||
void close(TransactionCloseMode mode = TransactionCloseMode::Commit);
|
||||
void close(bool abort = false);
|
||||
|
||||
/**
|
||||
* @brief Enable/Disable any AutoTransaction instance on the current stack.
|
||||
*
|
||||
* Once disabled, any empty temporary named transaction is closed. If there
|
||||
* are non-empty or non-temporary named active transaction, it will not be
|
||||
* auto closed.
|
||||
*
|
||||
* This function may be used in, for example, Gui::Document::setEdit() to
|
||||
* allow a transaction live past any command scope.
|
||||
*
|
||||
* @param[in] enable: if true, enable the AutoTransaction; otherwise, disable it.
|
||||
*/
|
||||
static void setEnable(bool enable);
|
||||
|
||||
private:
|
||||
int tid { 0 };
|
||||
int tid = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -92,7 +116,7 @@ public:
|
||||
*
|
||||
* @param[in] lock: whether to activate the lock
|
||||
*/
|
||||
TransactionLocker(Document* doc, bool lock = true);
|
||||
TransactionLocker(bool lock = true);
|
||||
|
||||
/**
|
||||
* @brief Destruct a transaction locker.
|
||||
@@ -118,7 +142,10 @@ public:
|
||||
{
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
/// Check if transaction is being locked.
|
||||
static bool isLocked();
|
||||
|
||||
friend class Application;
|
||||
|
||||
public:
|
||||
@@ -127,7 +154,6 @@ public:
|
||||
|
||||
private:
|
||||
bool active;
|
||||
Document* doc;
|
||||
};
|
||||
|
||||
} // namespace App
|
||||
+93
-191
@@ -35,7 +35,6 @@
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/bimap.hpp>
|
||||
@@ -191,7 +190,6 @@ bool Document::undo(const int id)
|
||||
mRedoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
mRedoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
d->bookedTransaction = 0;
|
||||
|
||||
mUndoMap.erase(mUndoTransactions.back()->getID());
|
||||
delete mUndoTransactions.back();
|
||||
@@ -244,7 +242,6 @@ bool Document::redo(const int id)
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
mUndoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
d->bookedTransaction = 0;
|
||||
|
||||
mRedoMap.erase(mRedoTransactions.back()->getID());
|
||||
delete mRedoTransactions.back();
|
||||
@@ -274,10 +271,10 @@ void Document::changePropertyOfObject(TransactionalObject* obj,
|
||||
}
|
||||
if ((d->iUndoMode != 0) && !isPerformingTransaction() && !d->activeUndoTransaction) {
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
if (d->bookedTransaction == NullTransaction) {
|
||||
d->bookedTransaction = GetApplication().getGlobalTransaction();
|
||||
} else {
|
||||
_openTransaction(GetApplication().getTransactionName(d->bookedTransaction), d->bookedTransaction);
|
||||
int tid = 0;
|
||||
const char* name = GetApplication().getActiveTransaction(&tid);
|
||||
if (name && tid > 0) {
|
||||
_openTransaction(name, tid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -332,92 +329,71 @@ std::vector<std::string> Document::getAvailableRedoNames() const
|
||||
return vList;
|
||||
}
|
||||
|
||||
int Document::openTransaction(TransactionName name, int tid) // NOLINT
|
||||
void Document::openTransaction(const char* name) // NOLINT
|
||||
{
|
||||
if (tid != NullTransaction && tid == d->bookedTransaction) {
|
||||
return tid; // Early exit without warning
|
||||
}
|
||||
if (isTransactionLocked()) {
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name.name << "'");
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
}
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
GetApplication().setActiveTransaction(name ? name : "<empty>");
|
||||
}
|
||||
|
||||
int Document::_openTransaction(const char* name, int id)
|
||||
{
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (name.name.empty()) {
|
||||
name.name = "<empty>";
|
||||
}
|
||||
return setActiveTransaction(name, tid);
|
||||
}
|
||||
int Document::openTransaction(std::string name, int tid)
|
||||
{
|
||||
return openTransaction(TransactionName {.name = name, .temporary = false}, tid);
|
||||
}
|
||||
|
||||
int Document::_openTransaction(std::string name, int id)
|
||||
{
|
||||
if (isTransactionLocked() && id != d->bookedTransaction) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Transaction locked, ignore new transaction '" << name << "'");
|
||||
if (d->iUndoMode != 0) {
|
||||
// Avoid recursive calls that is possible while
|
||||
// clearing the redo transactions and will cause
|
||||
// a double deletion of some transaction and thus
|
||||
// a segmentation fault
|
||||
if (d->opentransaction) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (isPerformingTransaction() || d->committing) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot open transaction while transacting");
|
||||
Base::FlagToggler<> flag(d->opentransaction);
|
||||
|
||||
if ((id != 0) && mUndoMap.find(id) != mUndoMap.end()) {
|
||||
throw Base::RuntimeError("invalid transaction id");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (d->iUndoMode == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
_commitTransaction(true);
|
||||
}
|
||||
_clearRedos();
|
||||
|
||||
// Avoid recursive calls that is possible while
|
||||
// clearing the redo transactions and will cause
|
||||
// a double deletion of some transaction and thus
|
||||
// a segmentation fault
|
||||
if (d->opentransaction) {
|
||||
return 0;
|
||||
}
|
||||
Base::FlagToggler<> flag(d->opentransaction);
|
||||
d->activeUndoTransaction = new Transaction(id);
|
||||
if (!name) {
|
||||
name = "<empty>";
|
||||
}
|
||||
d->activeUndoTransaction->Name = name;
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
id = d->activeUndoTransaction->getID();
|
||||
|
||||
if ((id != 0) && mUndoMap.find(id) != mUndoMap.end()) {
|
||||
throw Base::RuntimeError("invalid transaction id");
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
_commitTransaction(true);
|
||||
}
|
||||
_clearRedos();
|
||||
signalOpenTransaction(*this, name);
|
||||
|
||||
// When id == 0, this creates a new id
|
||||
// for instance, when there is no global transaction
|
||||
// from the application to stick to
|
||||
d->activeUndoTransaction = new Transaction(id);
|
||||
if (name.empty()) {
|
||||
name = "<empty>";
|
||||
auto& app = GetApplication();
|
||||
auto activeDoc = app.getActiveDocument();
|
||||
if (activeDoc && activeDoc != this && !activeDoc->hasPendingTransaction()) {
|
||||
std::string aname("-> ");
|
||||
aname += d->activeUndoTransaction->Name;
|
||||
FC_LOG("auto transaction " << getName() << " -> " << activeDoc->getName());
|
||||
activeDoc->_openTransaction(aname.c_str(), id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
d->activeUndoTransaction->Name = name;
|
||||
mUndoMap[d->activeUndoTransaction->getID()] = d->activeUndoTransaction;
|
||||
id = d->activeUndoTransaction->getID();
|
||||
|
||||
signalOpenTransaction(*this, name);
|
||||
|
||||
Document* transactionInitiator = GetApplication().transactionInitiator(id);
|
||||
if (transactionInitiator && transactionInitiator != this && !transactionInitiator->hasPendingTransaction()) {
|
||||
std::string aname = std::format("-> {}", d->activeUndoTransaction->Name);
|
||||
FC_LOG("auto transaction " << getName() << " -> " << transactionInitiator->getName());
|
||||
transactionInitiator->_openTransaction(aname, id);
|
||||
}
|
||||
return id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Document::renameTransaction(const std::string& name, const int id) const
|
||||
void Document::renameTransaction(const char* name, const int id) const
|
||||
{
|
||||
if (!name.empty() && d->activeUndoTransaction && d->activeUndoTransaction->getID() == id) {
|
||||
if (name && d->activeUndoTransaction && d->activeUndoTransaction->getID() == id) {
|
||||
if (boost::starts_with(d->activeUndoTransaction->Name, "-> ")) {
|
||||
d->activeUndoTransaction->Name.resize(3);
|
||||
}
|
||||
@@ -427,108 +403,48 @@ void Document::renameTransaction(const std::string& name, const int id) const
|
||||
d->activeUndoTransaction->Name += name;
|
||||
}
|
||||
}
|
||||
int Document::setActiveTransaction(TransactionName name, int tid)
|
||||
{
|
||||
// Probably a group transaction situation
|
||||
if (tid != NullTransaction) {
|
||||
if (!GetApplication().transactionIsActive(tid)) {
|
||||
FC_LOG("Could not set active transaction to inactive ID");
|
||||
return NullTransaction;
|
||||
}
|
||||
if (d->bookedTransaction != NullTransaction && d->bookedTransaction != tid && !_commitTransaction(true)) {
|
||||
FC_LOG("Could not book transaction for document");
|
||||
return NullTransaction;
|
||||
}
|
||||
d->bookedTransaction = tid;
|
||||
|
||||
if (GetApplication().transactionTmpName(d->bookedTransaction)) {
|
||||
GetApplication().setTransactionName(d->bookedTransaction, name);
|
||||
}
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
|
||||
// Rename the transaction if it had a tmp name
|
||||
if (d->bookedTransaction != NullTransaction && GetApplication().transactionTmpName(d->bookedTransaction)) {
|
||||
GetApplication().setTransactionName(d->bookedTransaction, name);
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
if (d->bookedTransaction != NullTransaction && !_commitTransaction(true)) {
|
||||
FC_LOG("Could not book transaction for document");
|
||||
return NullTransaction;
|
||||
}
|
||||
d->bookedTransaction = Transaction::getNewID();
|
||||
|
||||
GetApplication().setTransactionDescription(d->bookedTransaction, TransactionDescription {.initiator = this, .name = name});
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
|
||||
void Document::lockTransaction()
|
||||
{
|
||||
d->TransactionLock++;
|
||||
}
|
||||
void Document::unlockTransaction()
|
||||
{
|
||||
if (d->TransactionLock > 0) {
|
||||
d->TransactionLock--;
|
||||
}
|
||||
}
|
||||
bool Document::isTransactionLocked() const
|
||||
{
|
||||
return d->TransactionLock > 0;
|
||||
}
|
||||
bool Document::transacting() const
|
||||
{
|
||||
return isPerformingTransaction() || d->committing;
|
||||
}
|
||||
|
||||
void Document::_checkTransaction(DocumentObject* pcDelObj, const Property* What, int line)
|
||||
{
|
||||
// if the undo is active but no transaction open, open one!
|
||||
if (d->iUndoMode == 0 || isPerformingTransaction() || d->activeUndoTransaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
|
||||
// Priority to a transaction that has been booked
|
||||
// explicitly for this document, it there are none
|
||||
// get a sticky transaction from application
|
||||
if (!d->bookedTransaction) {
|
||||
d->bookedTransaction = GetApplication().getGlobalTransaction();
|
||||
}
|
||||
|
||||
if (d->bookedTransaction != NullTransaction) {
|
||||
std::string name = GetApplication().getTransactionName(d->bookedTransaction);
|
||||
bool ignore = false;
|
||||
if (What && What->testStatus(Property::NoModify)) {
|
||||
ignore = true;
|
||||
}
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
if (What) {
|
||||
FC_LOG((ignore ? "ignore" : "auto")
|
||||
<< " transaction (" << line << ") '" << What->getFullName());
|
||||
}
|
||||
else {
|
||||
FC_LOG((ignore ? "ignore" : "auto") << " transaction (" << line << ") '"
|
||||
<< name << "' in " << getName());
|
||||
if ((d->iUndoMode != 0) && !isPerformingTransaction()) {
|
||||
if (!d->activeUndoTransaction) {
|
||||
if (!testStatus(Restoring) || testStatus(Importing)) {
|
||||
int tid = 0;
|
||||
const char* name = GetApplication().getActiveTransaction(&tid);
|
||||
if (name && tid > 0) {
|
||||
bool ignore = false;
|
||||
if (What && What->testStatus(Property::NoModify)) {
|
||||
ignore = true;
|
||||
}
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
if (What) {
|
||||
FC_LOG((ignore ? "ignore" : "auto")
|
||||
<< " transaction (" << line << ") '" << What->getFullName());
|
||||
}
|
||||
else {
|
||||
FC_LOG((ignore ? "ignore" : "auto") << " transaction (" << line << ") '"
|
||||
<< name << "' in " << getName());
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
_openTransaction(name, tid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!ignore) {
|
||||
_openTransaction(name, d->bookedTransaction);
|
||||
if (!pcDelObj) {
|
||||
return;
|
||||
}
|
||||
// When the object is going to be deleted we have to check if it has already been added
|
||||
// to the undo transactions
|
||||
std::list<Transaction*>::iterator it;
|
||||
for (it = mUndoTransactions.begin(); it != mUndoTransactions.end(); ++it) {
|
||||
if ((*it)->hasObject(pcDelObj)) {
|
||||
_openTransaction("Delete");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!pcDelObj) {
|
||||
return;
|
||||
}
|
||||
// When the object is going to be deleted we have to check if it has already been added
|
||||
// to the undo transactions
|
||||
std::list<Transaction*>::iterator it;
|
||||
for (it = mUndoTransactions.begin(); it != mUndoTransactions.end(); ++it) {
|
||||
if ((*it)->hasObject(pcDelObj)) {
|
||||
_openTransaction("Delete");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -557,36 +473,29 @@ void Document::commitTransaction() // NOLINT
|
||||
}
|
||||
|
||||
if (d->activeUndoTransaction) {
|
||||
// This will iterate over all documents and ask them to
|
||||
// commit their transaction if their ID matches
|
||||
GetApplication().commitTransaction(d->activeUndoTransaction->getID());
|
||||
} else {
|
||||
d->bookedTransaction = 0; // Reset booked transaction even if it was not used
|
||||
GetApplication().closeActiveTransaction(false, d->activeUndoTransaction->getID());
|
||||
}
|
||||
}
|
||||
|
||||
bool Document::_commitTransaction(const bool notify)
|
||||
void Document::_commitTransaction(const bool notify)
|
||||
{
|
||||
if (isPerformingTransaction()) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Cannot commit transaction while transacting");
|
||||
}
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if (d->committing) {
|
||||
// for a recursive call return without printing a warning
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
d->bookedTransaction = 0;
|
||||
if (d->activeUndoTransaction) {
|
||||
Base::FlagToggler<> flag(d->committing);
|
||||
Application::TransactionSignaller signaller(false, true);
|
||||
const int id = d->activeUndoTransaction->getID();
|
||||
|
||||
mUndoTransactions.push_back(d->activeUndoTransaction);
|
||||
d->activeUndoTransaction = nullptr;
|
||||
|
||||
// check the stack for the limits
|
||||
if (mUndoTransactions.size() > d->UndoMaxStackSize) {
|
||||
mUndoMap.erase(mUndoTransactions.front()->getID());
|
||||
@@ -595,12 +504,11 @@ bool Document::_commitTransaction(const bool notify)
|
||||
}
|
||||
signalCommitTransaction(*this);
|
||||
|
||||
// commitTransaction() may call again _commitTransaction()
|
||||
// closeActiveTransaction() may call again _commitTransaction()
|
||||
if (notify) {
|
||||
GetApplication().commitTransaction(id);
|
||||
GetApplication().closeActiveTransaction(false, id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Document::abortTransaction() const
|
||||
@@ -612,9 +520,7 @@ void Document::abortTransaction() const
|
||||
return;
|
||||
}
|
||||
if (d->activeUndoTransaction) {
|
||||
GetApplication().abortTransaction(d->activeUndoTransaction->getID());
|
||||
} else {
|
||||
d->bookedTransaction = 0; // Reset booked transaction even if it was not used
|
||||
GetApplication().closeActiveTransaction(true, d->activeUndoTransaction->getID());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +532,6 @@ void Document::_abortTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
d->bookedTransaction = 0;
|
||||
if (d->activeUndoTransaction) {
|
||||
Base::FlagToggler<bool> flag(d->rollback);
|
||||
Application::TransactionSignaller signaller(true, true);
|
||||
@@ -670,10 +575,7 @@ int Document::getTransactionID(const bool undo, unsigned pos) const
|
||||
for (; pos != 0U; ++rit, --pos) {}
|
||||
return (*rit)->getID();
|
||||
}
|
||||
int Document::getBookedTransactionID() const
|
||||
{
|
||||
return d->bookedTransaction;
|
||||
}
|
||||
|
||||
bool Document::isTransactionEmpty() const
|
||||
{
|
||||
return !d->activeUndoTransaction;
|
||||
@@ -3410,7 +3312,7 @@ void Document::_removeObject(DocumentObject* pcObject, RemoveObjectOptions optio
|
||||
return;
|
||||
}
|
||||
|
||||
TransactionLocker tlock(this);
|
||||
TransactionLocker tlock;
|
||||
|
||||
_checkTransaction(pcObject, nullptr, __LINE__);
|
||||
|
||||
|
||||
+7
-18
@@ -35,7 +35,6 @@
|
||||
#include "PropertyLinks.h"
|
||||
#include "PropertyStandard.h"
|
||||
#include "ExportInfo.h"
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -866,19 +865,7 @@ public:
|
||||
* setup a potential transaction that will only be created if there are
|
||||
* actual changes.
|
||||
*/
|
||||
int openTransaction(TransactionName name, int tid = 0);
|
||||
int openTransaction(std::string name, int tid = 0);
|
||||
|
||||
// If the tid != 0, it will take the transaction id if it exists
|
||||
int setActiveTransaction(TransactionName name, int tid = 0);
|
||||
|
||||
void lockTransaction();
|
||||
void unlockTransaction();
|
||||
bool isTransactionLocked() const;
|
||||
|
||||
bool transacting() const;
|
||||
|
||||
int getBookedTransactionID() const;
|
||||
void openTransaction(const char* name = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Rename the current transaction.
|
||||
@@ -888,7 +875,7 @@ public:
|
||||
* @param[in] name The new name of the transaction.
|
||||
* @param[in] id The transaction ID to match.
|
||||
*/
|
||||
void renameTransaction(const std::string& name, int id) const;
|
||||
void renameTransaction(const char* name, int id) const;
|
||||
|
||||
/**
|
||||
* @brief Commit the Command transaction.
|
||||
@@ -1257,7 +1244,7 @@ public:
|
||||
|
||||
/// Check if there is any document restoring/importing.
|
||||
static bool isAnyRestoring();
|
||||
|
||||
|
||||
/// Register a new label.
|
||||
void registerLabel(const std ::string& newLabel);
|
||||
/// Unregister a label.
|
||||
@@ -1422,7 +1409,8 @@ protected:
|
||||
* This function creates an actual transaction regardless of Application
|
||||
* AutoTransaction setting.
|
||||
*/
|
||||
int _openTransaction(std::string name = "", int id = 0);
|
||||
int _openTransaction(const char* name = nullptr, int id = 0);
|
||||
|
||||
/**
|
||||
* @brief Commit the Command transaction.
|
||||
*
|
||||
@@ -1431,7 +1419,8 @@ protected:
|
||||
*
|
||||
* @param notify If true, notify the application to close the transaction.
|
||||
*/
|
||||
bool _commitTransaction(bool notify = false);
|
||||
void _commitTransaction(bool notify = false);
|
||||
|
||||
/**
|
||||
* @brief Abort the running transaction.
|
||||
*
|
||||
|
||||
@@ -447,12 +447,3 @@ class Document(PropertyContainer):
|
||||
sort: whether to topologically sort the return list
|
||||
"""
|
||||
...
|
||||
|
||||
def getBookedTransactionID(self) -> int:
|
||||
"""
|
||||
getBookedTransactionID() -> int
|
||||
|
||||
Returns the currently booked transaction id, which is the id of the current transaction OR the id
|
||||
the next transaction will stick to if no change has occured yet
|
||||
"""
|
||||
...
|
||||
@@ -1175,15 +1175,6 @@ PyObject* DocumentPy::getDependentDocuments(PyObject* args)
|
||||
}
|
||||
PY_CATCH;
|
||||
}
|
||||
PyObject* DocumentPy::getBookedTransactionID(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
int tid = getDocumentPtr()->getBookedTransactionID();
|
||||
return Py::new_reference_to(Py::Long(tid));
|
||||
}
|
||||
|
||||
|
||||
Py::Boolean DocumentPy::getRestoring() const
|
||||
{
|
||||
|
||||
@@ -1546,11 +1546,11 @@ void PropertyString::setValue(const char* newValue)
|
||||
// OnProposedLabelChange has changed the new value to what the current value is
|
||||
return;
|
||||
}
|
||||
if (!propChanges.empty() && obj->getDocument()->getBookedTransactionID() == 0) {
|
||||
if (!propChanges.empty() && !GetApplication().getActiveTransaction()) {
|
||||
commit = true;
|
||||
std::ostringstream str;
|
||||
str << "Change " << obj->getNameInDocument() << ".Label";
|
||||
obj->getDocument()->openTransaction(str.str().c_str());
|
||||
GetApplication().setActiveTransaction(str.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1563,7 +1563,7 @@ void PropertyString::setValue(const char* newValue)
|
||||
}
|
||||
|
||||
if (commit) {
|
||||
obj->getDocument()->commitTransaction();
|
||||
GetApplication().closeActiveTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2026 Théo Veilleux-Trinh <theo.veilleux.trinh@proton.me>*
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_TRANSACTIONDEFS_H_
|
||||
#define APP_TRANSACTIONDEFS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace App {
|
||||
|
||||
class Document;
|
||||
|
||||
constexpr int NullTransaction = 0;
|
||||
|
||||
struct TransactionName {
|
||||
// Name of the transaction as it will appear in the GUI
|
||||
std::string name;
|
||||
|
||||
// If true, the transaction is allowed to be renamed
|
||||
bool temporary { false };
|
||||
};
|
||||
|
||||
struct TransactionDescription {
|
||||
// Document on which the transaction was first created
|
||||
// useful for mass transaction (e.g. delete from an assembly)
|
||||
// where other documents may use the same transaction id
|
||||
Document* initiator { nullptr };
|
||||
TransactionName name;
|
||||
};
|
||||
|
||||
enum class TransactionCloseMode {
|
||||
Commit = 0,
|
||||
Abort = 1,
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -556,4 +556,4 @@ TransactionObject* TransactionFactory::createTransaction(const Base::Type& type)
|
||||
|
||||
Base::Console().log("Cannot create transaction object from %s\n", type.getName());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <Base/Factory.h>
|
||||
#include <Base/Persistence.h>
|
||||
#include <App/PropertyContainer.h>
|
||||
#include "TransactionDefs.h"
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
@@ -62,7 +61,6 @@ class AppExport Transaction: public Base::Persistence
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a transaction.
|
||||
@@ -73,7 +71,7 @@ public:
|
||||
* transactions from different document, so that they can be undone/redone
|
||||
* together.
|
||||
*/
|
||||
explicit Transaction(int id = NullTransaction);
|
||||
explicit Transaction(int id = 0);
|
||||
|
||||
~Transaction() override;
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <optional>
|
||||
|
||||
#include <boost/bimap.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
@@ -94,11 +93,6 @@ struct DocumentP
|
||||
int iUndoMode {0};
|
||||
unsigned int UndoMemSize {0};
|
||||
unsigned int UndoMaxStackSize {20};
|
||||
unsigned int TransactionLock {0};
|
||||
// Id and name that the next transaction will take
|
||||
// as soon as there is a change to the document
|
||||
int bookedTransaction { 0 };
|
||||
|
||||
std::string programVersion;
|
||||
mutable HasherMap hashers;
|
||||
std::multimap<const App::DocumentObject*, std::unique_ptr<App::DocumentObjectExecReturn>>
|
||||
|
||||
+2
-4
@@ -22,14 +22,12 @@ class ScaleType(IntEnum):
|
||||
NumberProtocol=True,
|
||||
RichCompare=True,
|
||||
)
|
||||
@class_declarations(
|
||||
"""public:
|
||||
@class_declarations("""public:
|
||||
MatrixPy(const Matrix4D & mat, PyTypeObject *T = &Type)
|
||||
:PyObjectBase(new Matrix4D(mat),T){}
|
||||
Matrix4D value() const
|
||||
{ return *(getMatrixPtr()); }
|
||||
"""
|
||||
)
|
||||
""")
|
||||
class Matrix(PyObjectBase):
|
||||
"""
|
||||
Base.Matrix class.
|
||||
|
||||
@@ -15,14 +15,12 @@ from typing import Sequence, overload
|
||||
NumberProtocol=True,
|
||||
RichCompare=True,
|
||||
)
|
||||
@class_declarations(
|
||||
"""public:
|
||||
@class_declarations("""public:
|
||||
PlacementPy(const Placement & pla, PyTypeObject *T = &Type)
|
||||
:PyObjectBase(new Placement(pla),T){}
|
||||
Placement value() const
|
||||
{ return *(getPlacementPtr()); }
|
||||
"""
|
||||
)
|
||||
""")
|
||||
class Placement(PyObjectBase):
|
||||
"""
|
||||
Base.Placement class.
|
||||
|
||||
@@ -14,14 +14,12 @@ from typing import overload, Tuple, List, Final
|
||||
NumberProtocol=True,
|
||||
RichCompare=True,
|
||||
)
|
||||
@class_declarations(
|
||||
"""public:
|
||||
@class_declarations("""public:
|
||||
RotationPy(const Rotation & mat, PyTypeObject *T = &Type)
|
||||
:PyObjectBase(new Rotation(mat),T){}
|
||||
Rotation value() const
|
||||
{ return *(getRotationPtr()); }
|
||||
"""
|
||||
)
|
||||
""")
|
||||
class Rotation(PyObjectBase):
|
||||
"""
|
||||
Base.Rotation class.
|
||||
|
||||
+2
-4
@@ -603,8 +603,7 @@ public:
|
||||
{
|
||||
}
|
||||
#endif
|
||||
~ofstream() override
|
||||
= default;
|
||||
~ofstream() override = default;
|
||||
void open(const FileInfo& fi, ios_base::openmode mode = std::ios::out | std::ios::trunc)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
@@ -638,8 +637,7 @@ public:
|
||||
{
|
||||
}
|
||||
#endif
|
||||
~ifstream() override
|
||||
= default;
|
||||
~ifstream() override = default;
|
||||
void open(const FileInfo& fi, ios_base::openmode mode = std::ios::in)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
|
||||
+2
-4
@@ -11,12 +11,10 @@ from typing import List, Final
|
||||
TwinPointer="BaseType",
|
||||
Delete=True,
|
||||
)
|
||||
@forward_declarations(
|
||||
"""
|
||||
@forward_declarations("""
|
||||
namespace Base {
|
||||
using BaseType = Type;
|
||||
}"""
|
||||
)
|
||||
}""")
|
||||
class Type(PyObjectBase):
|
||||
"""
|
||||
BaseTypePy class.
|
||||
|
||||
+2
-4
@@ -26,8 +26,7 @@ from typing import overload, Sequence
|
||||
sq_inplace_concat=False,
|
||||
sq_inplace_repeat=False,
|
||||
)
|
||||
@class_declarations(
|
||||
"""public:
|
||||
@class_declarations("""public:
|
||||
VectorPy(const Vector3d & vec, PyTypeObject *T = &Type)
|
||||
:PyObjectBase(new Vector3d(vec),T){}
|
||||
VectorPy(const Vector3f & vec, PyTypeObject *T = &Type)
|
||||
@@ -36,8 +35,7 @@ from typing import overload, Sequence
|
||||
{ return *(getVectorPtr()); }
|
||||
private:
|
||||
Py::List sequence;
|
||||
"""
|
||||
)
|
||||
""")
|
||||
class Vector(PyObjectBase):
|
||||
"""
|
||||
Base.Vector class.
|
||||
|
||||
@@ -157,7 +157,7 @@ long NavlibInterface::SetActiveCommand(std::string commandId)
|
||||
if (!std::string(command->getName()).compare(parsedData.commandName)) {
|
||||
if (parsedData.actionIndex == -1) {
|
||||
Gui::Action* pAction = command->getAction();
|
||||
if (pAction) {
|
||||
if (pAction != nullptr) {
|
||||
pAction->action()->trigger();
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ void NavlibInterface::unpackCommands(Gui::Command& command,
|
||||
TDxCategory& category,
|
||||
std::vector<TDx::CImage>& images)
|
||||
{
|
||||
if (!command.getAction())
|
||||
if (command.getAction() == nullptr)
|
||||
return;
|
||||
|
||||
QList<QAction*> pQActions;
|
||||
@@ -185,7 +185,7 @@ void NavlibInterface::unpackCommands(Gui::Command& command,
|
||||
int32_t index = -1;
|
||||
auto actionGroup = qobject_cast<Gui::ActionGroup*>(command.getAction());
|
||||
|
||||
if (actionGroup) {
|
||||
if (actionGroup != nullptr) {
|
||||
pQActions = actionGroup->actions();
|
||||
std::string subCategoryName = actionGroup->text().toStdString();
|
||||
subCategory = TDxCategory(subCategoryName, subCategoryName);
|
||||
|
||||
@@ -58,7 +58,7 @@ NavlibInterface::~NavlibInterface()
|
||||
{
|
||||
disableNavigation();
|
||||
|
||||
if (pivot.pVisibility)
|
||||
if (pivot.pVisibility != nullptr)
|
||||
pivot.pVisibility->unref();
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ long NavlibInterface::GetPointerPosition(navlib::point_t& position) const
|
||||
|
||||
if (is3DView()) {
|
||||
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
|
||||
if (!inventorViewer)
|
||||
if (inventorViewer == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
QPoint viewPoint = currentView.pView3d->mapFromGlobal(QCursor::pos());
|
||||
@@ -122,7 +122,7 @@ CameraType NavlibInterface::getCamera() const
|
||||
{
|
||||
if (is3DView()) {
|
||||
const Gui::View3DInventorViewer* inventorViewer = currentView.pView3d->getViewer();
|
||||
if (inventorViewer)
|
||||
if (inventorViewer != nullptr)
|
||||
return dynamic_cast<CameraType>(inventorViewer->getCamera());
|
||||
}
|
||||
return nullptr;
|
||||
@@ -132,18 +132,18 @@ template SoCamera* NavlibInterface::getCamera<SoCamera*>() const;
|
||||
|
||||
void NavlibInterface::onViewChanged(const Gui::MDIView* view)
|
||||
{
|
||||
if (!view)
|
||||
if (view == nullptr)
|
||||
return;
|
||||
|
||||
currentView.pView3d = dynamic_cast<const Gui::View3DInventor*>(view);
|
||||
currentView.pView2d = nullptr;
|
||||
if (currentView.pView3d) {
|
||||
if (currentView.pView3d != nullptr) {
|
||||
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
|
||||
if (!inventorViewer)
|
||||
if (inventorViewer == nullptr)
|
||||
return;
|
||||
|
||||
auto pGroup = dynamic_cast<SoGroup* const>(inventorViewer->getSceneGraph());
|
||||
if (!pGroup)
|
||||
if (pGroup == nullptr)
|
||||
return;
|
||||
|
||||
if (pGroup->findChild(pivot.pVisibility) == -1)
|
||||
@@ -198,11 +198,11 @@ void NavlibInterface::enableNavigation()
|
||||
void NavlibInterface::connectActiveTab()
|
||||
{
|
||||
auto pQMdiArea = Gui::MainWindow::getInstance()->findChild<QMdiArea*>();
|
||||
if (!pQMdiArea)
|
||||
if (pQMdiArea == nullptr)
|
||||
return;
|
||||
|
||||
auto pQTabBar = pQMdiArea->findChild<QTabBar*>();
|
||||
if (!pQTabBar)
|
||||
if (pQTabBar == nullptr)
|
||||
return;
|
||||
|
||||
pQTabBar->connect(pQTabBar, &QTabBar::currentChanged, [this, pQTabBar](int idx) {
|
||||
@@ -222,7 +222,7 @@ long NavlibInterface::GetCameraMatrix(navlib::matrix_t& matrix) const
|
||||
|
||||
if (is3DView()) {
|
||||
auto pCamera = getCamera<SoCamera*>();
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::function_not_supported);
|
||||
|
||||
SbMatrix cameraMatrix;
|
||||
@@ -268,7 +268,7 @@ long NavlibInterface::SetCameraMatrix(const navlib::matrix_t& matrix)
|
||||
|
||||
if (is3DView()) {
|
||||
auto pCamera = getCamera<SoCamera*>();
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
SbMatrix cameraMatrix(matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(0, 3),
|
||||
@@ -288,7 +288,7 @@ long NavlibInterface::SetCameraMatrix(const navlib::matrix_t& matrix)
|
||||
long NavlibInterface::GetViewFrustum(navlib::frustum_t& frustum) const
|
||||
{
|
||||
const auto pCamera = getCamera<SoPerspectiveCamera* const>();
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
const SbViewVolume viewVolume = pCamera->getViewVolume(pCamera->aspectRatio.getValue());
|
||||
@@ -327,7 +327,7 @@ long NavlibInterface::GetViewExtents(navlib::box_t& extents) const
|
||||
}
|
||||
|
||||
const auto pCamera = getCamera<SoOrthographicCamera* const>();
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
const SbViewVolume viewVolume = pCamera->getViewVolume(pCamera->aspectRatio.getValue());
|
||||
@@ -371,7 +371,7 @@ long NavlibInterface::SetViewExtents(const navlib::box_t& extents)
|
||||
|
||||
if (is3DView()) {
|
||||
auto pCamera = getCamera<SoOrthographicCamera* const>();
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
navlib::box_t oldExtents;
|
||||
@@ -399,13 +399,13 @@ long NavlibInterface::SetViewFOV(double)
|
||||
long NavlibInterface::GetIsViewPerspective(navlib::bool_t& perspective) const
|
||||
{
|
||||
auto pPerspectiveCamera = getCamera<SoPerspectiveCamera* const>();
|
||||
if (pPerspectiveCamera) {
|
||||
if (pPerspectiveCamera != nullptr) {
|
||||
perspective = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto pOrthographicCamera = getCamera<SoOrthographicCamera* const>();
|
||||
if (pOrthographicCamera || is2DView()) {
|
||||
if (pOrthographicCamera != nullptr || is2DView()) {
|
||||
perspective = false;
|
||||
return 0;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ long NavlibInterface::GetModelExtents(navlib::box_t& extents) const
|
||||
{
|
||||
if (is3DView()) {
|
||||
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
|
||||
if (!inventorViewer)
|
||||
if (inventorViewer == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
SoGetBoundingBoxAction action(inventorViewer->getSoRenderManager()->getViewportRegion());
|
||||
|
||||
@@ -71,7 +71,7 @@ long NavlibInterface::GetPivotPosition(navlib::point_t&) const
|
||||
|
||||
long NavlibInterface::SetPivotPosition(const navlib::point_t& position)
|
||||
{
|
||||
if (!pivot.pTransform)
|
||||
if (pivot.pTransform == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
pivot.pTransform->translation.setValue(position.x, position.y, position.z);
|
||||
@@ -86,7 +86,7 @@ long NavlibInterface::IsUserPivot(navlib::bool_t& userPivot) const
|
||||
|
||||
long NavlibInterface::GetPivotVisible(navlib::bool_t& visible) const
|
||||
{
|
||||
if (!pivot.pVisibility)
|
||||
if (pivot.pVisibility == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
visible = pivot.pVisibility->whichChild.getValue() == SO_SWITCH_ALL;
|
||||
@@ -96,7 +96,7 @@ long NavlibInterface::GetPivotVisible(navlib::bool_t& visible) const
|
||||
|
||||
long NavlibInterface::SetPivotVisible(bool visible)
|
||||
{
|
||||
if (!pivot.pVisibility)
|
||||
if (pivot.pVisibility == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
if (visible)
|
||||
@@ -115,11 +115,11 @@ long NavlibInterface::GetHitLookAt(navlib::point_t& position) const
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
const Gui::View3DInventorViewer* const inventorViewer = currentView.pView3d->getViewer();
|
||||
if (!inventorViewer)
|
||||
if (inventorViewer == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
SoNode* pSceneGraph = inventorViewer->getSceneGraph();
|
||||
if (!pSceneGraph)
|
||||
if (pSceneGraph == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
// Prepare the ray-picking object
|
||||
@@ -131,7 +131,7 @@ long NavlibInterface::GetHitLookAt(navlib::point_t& position) const
|
||||
// Get the camera rotation
|
||||
SoCamera* pCamera = getCamera<SoCamera*>();
|
||||
|
||||
if (!pCamera)
|
||||
if (pCamera == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
pCamera->orientation.getValue().getValue(cameraMatrix);
|
||||
@@ -177,7 +177,7 @@ long NavlibInterface::GetHitLookAt(navlib::point_t& position) const
|
||||
SoPickedPoint* pickedPoint = rayPickAction.getPickedPoint();
|
||||
|
||||
// Check if there was a hit
|
||||
if (pickedPoint) {
|
||||
if (pickedPoint != nullptr) {
|
||||
SbVec3f hitPoint = pickedPoint->getPoint();
|
||||
float distance = (origin - hitPoint).length();
|
||||
|
||||
@@ -213,7 +213,7 @@ long NavlibInterface::GetSelectionExtents(navlib::box_t& extents) const
|
||||
Gui::ViewProvider* pViewProvider =
|
||||
Gui::Application::Instance->getViewProvider(selection.pObject);
|
||||
|
||||
if (!pViewProvider)
|
||||
if (pViewProvider == nullptr)
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
|
||||
boundingBox.Add(pViewProvider->getBoundingBox(selection.SubName, true));
|
||||
@@ -254,7 +254,7 @@ long NavlibInterface::SetHitLookFrom(const navlib::point_t& eye)
|
||||
}
|
||||
else {
|
||||
auto pCamera = getCamera<SoCamera*>();
|
||||
if (!pCamera) {
|
||||
if (pCamera == nullptr) {
|
||||
return navlib::make_result_code(navlib::navlib_errc::no_data_available);
|
||||
}
|
||||
|
||||
|
||||
+13
-64
@@ -227,7 +227,7 @@ struct ApplicationP
|
||||
std::map<const App::Document*, Gui::Document*> documents;
|
||||
/// Active document
|
||||
Gui::Document* activeDocument {nullptr};
|
||||
std::vector<Gui::Document*> editDocuments;
|
||||
Gui::Document* editDocument {nullptr};
|
||||
|
||||
MacroManager* macroMngr;
|
||||
PreferencePackManager* prefPackManager;
|
||||
@@ -631,7 +631,7 @@ Application::Application(bool GUIenabled)
|
||||
PyObject* module = PyImport_AddModule("FreeCADGui");
|
||||
PyMethodDef* meth = FreeCADGui_methods;
|
||||
PyObject* dict = PyModule_GetDict(module);
|
||||
for (; meth->ml_name; meth++) {
|
||||
for (; meth->ml_name != nullptr; meth++) {
|
||||
PyObject* descr;
|
||||
descr = PyCFunction_NewEx(meth, nullptr, nullptr);
|
||||
if (!descr) {
|
||||
@@ -1285,9 +1285,6 @@ void Application::slotActiveDocument(const App::Document& Doc)
|
||||
Py::Module("FreeCADGui").setAttr(std::string("ActiveDocument"), Py::None());
|
||||
}
|
||||
}
|
||||
if (!d->activeDocument->workbench().empty()) {
|
||||
activateWorkbench(d->activeDocument->workbench().c_str());
|
||||
}
|
||||
|
||||
// Update the application to show the unit change
|
||||
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath(
|
||||
@@ -1494,65 +1491,26 @@ Gui::Document* Application::activeDocument() const
|
||||
|
||||
Gui::Document* Application::editDocument() const
|
||||
{
|
||||
if (d->editDocuments.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return d->editDocuments[0];
|
||||
return d->editDocument;
|
||||
}
|
||||
Gui::Document* Application::editDocument(const std::function<bool(Gui::Document*)>& eval)
|
||||
{
|
||||
auto found = std::ranges::find_if(d->editDocuments, eval);
|
||||
|
||||
return found == d->editDocuments.end() ? nullptr : *found;
|
||||
}
|
||||
std::vector<Gui::Document*> Application::editDocuments() const
|
||||
{
|
||||
return d->editDocuments;
|
||||
}
|
||||
bool Application::isInEdit(Gui::Document* pcDocument) const
|
||||
{
|
||||
return std::ranges::find(d->editDocuments, pcDocument) != d->editDocuments.end();
|
||||
}
|
||||
void Application::unsetEditDocument(Gui::Document* pcDocument)
|
||||
{
|
||||
if (std::erase(d->editDocuments, pcDocument) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pcDocument->_resetEdit();
|
||||
updateActions();
|
||||
}
|
||||
void Application::unsetEditDocumentIf(const std::function<bool(Gui::Document*)>& eval)
|
||||
{
|
||||
std::erase_if(d->editDocuments, [&](Gui::Document* doc) {
|
||||
if (eval(doc)) {
|
||||
doc->_resetEdit();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
updateActions();
|
||||
}
|
||||
Gui::MDIView* Application::editViewOfNode(SoNode* node) const
|
||||
{
|
||||
for (auto editDoc : d->editDocuments) {
|
||||
if (Gui::MDIView* view = editDoc->getViewOfNode(node)) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return d->editDocument ? d->editDocument->getViewOfNode(node) : nullptr;
|
||||
}
|
||||
|
||||
void Application::setEditDocument(Gui::Document* pcDocument)
|
||||
void Application::setEditDocument(Gui::Document* doc)
|
||||
{
|
||||
if (pcDocument == nullptr) {
|
||||
if (!doc) {
|
||||
d->editDocument = nullptr;
|
||||
}
|
||||
else if (doc == d->editDocument) {
|
||||
return;
|
||||
}
|
||||
if (std::ranges::find(d->editDocuments, pcDocument) != d->editDocuments.end()) {
|
||||
return;
|
||||
for (auto& v : d->documents) {
|
||||
v.second->_resetEdit();
|
||||
}
|
||||
d->editDocuments.push_back(pcDocument);
|
||||
|
||||
d->editDocument = doc;
|
||||
updateActions();
|
||||
}
|
||||
|
||||
@@ -1573,18 +1531,12 @@ void Application::setActiveDocument(Gui::Document* pcDocument)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (d->activeDocument) {
|
||||
d->activeDocument->setIsActive(false);
|
||||
}
|
||||
d->activeDocument = pcDocument;
|
||||
|
||||
std::string nameApp, nameGui;
|
||||
|
||||
// This adds just a line to the macro file but does not set the active document
|
||||
// Macro recording of this is problematic, thus it's written out as comment.
|
||||
if (pcDocument) {
|
||||
pcDocument->setIsActive(true);
|
||||
|
||||
nameApp += "App.setActiveDocument(\"";
|
||||
nameApp += pcDocument->getDocument()->getName();
|
||||
nameApp += "\")\n";
|
||||
@@ -1941,9 +1893,6 @@ bool Application::activateWorkbench(const char* name)
|
||||
}
|
||||
newWb->activated();
|
||||
}
|
||||
if (activeDocument()) {
|
||||
activeDocument()->setWorkbench(name);
|
||||
}
|
||||
}
|
||||
catch (Py::Exception&) {
|
||||
Base::PyException e; // extract the Python error text
|
||||
@@ -2841,7 +2790,7 @@ void Application::setStyle(const QString& name)
|
||||
return qobject_cast<FreeCADStyle*>(style) != nullptr;
|
||||
};
|
||||
|
||||
if (auto* current = qApp->style(); current && requiresEventFilter(current)) {
|
||||
if (auto* current = qApp->style(); current != nullptr && requiresEventFilter(current)) {
|
||||
qApp->removeEventFilter(current);
|
||||
}
|
||||
|
||||
|
||||
+2
-17
@@ -181,26 +181,11 @@ public:
|
||||
Gui::Document* activeDocument() const;
|
||||
/// Set the active document
|
||||
void setActiveDocument(Gui::Document* pcDocument);
|
||||
|
||||
/// Getter for the editing document, will be removed soon
|
||||
/// Getter for the editing document
|
||||
Gui::Document* editDocument() const;
|
||||
/// Getter for the first editing document that matches a functor
|
||||
Gui::Document* editDocument(const std::function<bool(Gui::Document*)>& eval);
|
||||
/// Getter for all currently editing documents, all pointers are guaranteed to be non-null
|
||||
std::vector<Gui::Document*> editDocuments() const;
|
||||
|
||||
// Returns true if the document is in edit (will make more sense once the edit document it is a
|
||||
// vector)
|
||||
bool isInEdit(Gui::Document* pcDocument) const;
|
||||
// Reset edit if eval returns true for a document in edit
|
||||
|
||||
Gui::MDIView* editViewOfNode(SoNode* node) const;
|
||||
/// Adds a document in edit
|
||||
/// Set editing document, which will reset editing of all other document
|
||||
void setEditDocument(Gui::Document* pcDocument);
|
||||
// After this, isInEdit(pcDocument) returns false
|
||||
void unsetEditDocument(Gui::Document* pcDocument);
|
||||
void unsetEditDocumentIf(const std::function<bool(Gui::Document*)>& eval);
|
||||
|
||||
/** Retrieves a pointer to the Gui::Document whose App::Document has the name \a name.
|
||||
* If no such document exists 0 is returned.
|
||||
*/
|
||||
|
||||
@@ -490,7 +490,6 @@ SET(Gui_UIC_SRCS
|
||||
InputVector.ui
|
||||
Placement.ui
|
||||
TaskTransform.ui
|
||||
TaskCommandLink.ui
|
||||
TextureMapping.ui
|
||||
TaskView/TaskAppearance.ui
|
||||
TaskView/TaskOrientation.ui
|
||||
@@ -579,7 +578,6 @@ SET(Dialog_CPP_SRCS
|
||||
TaskDlgRelocation.cpp
|
||||
Dialogs/DlgCheckableMessageBox.cpp
|
||||
TaskTransform.cpp
|
||||
TaskCommandLink.cpp
|
||||
Dialogs/DlgUndoRedo.cpp
|
||||
InputVector.cpp
|
||||
Placement.cpp
|
||||
@@ -622,7 +620,6 @@ SET(Dialog_HPP_SRCS
|
||||
Dialogs/DlgVersionMigrator.h
|
||||
TaskDlgRelocation.h
|
||||
TaskTransform.h
|
||||
TaskCommandLink.h
|
||||
Dialogs/DlgUndoRedo.h
|
||||
InputVector.h
|
||||
Placement.h
|
||||
|
||||
@@ -226,7 +226,7 @@ QMap<QString, CallTip> CallTipsList::extractTips(const QString& context) const
|
||||
try {
|
||||
PyErr_Clear();
|
||||
Py::Module module("__main__");
|
||||
if (!module.ptr()) {
|
||||
if (module.ptr() == nullptr) {
|
||||
return tips;
|
||||
}
|
||||
Py::Dict dict = module.getDict();
|
||||
@@ -698,9 +698,10 @@ bool CallTipsList::eventFilter(QObject* watched, QEvent* event)
|
||||
Q_EMIT itemActivated(currentItem());
|
||||
return false;
|
||||
}
|
||||
else if (ke->key() == Qt::Key_Shift || ke->key() == Qt::Key_Control
|
||||
|| ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Alt
|
||||
|| ke->key() == Qt::Key_AltGr) {
|
||||
else if (
|
||||
ke->key() == Qt::Key_Shift || ke->key() == Qt::Key_Control
|
||||
|| ke->key() == Qt::Key_Meta || ke->key() == Qt::Key_Alt || ke->key() == Qt::Key_AltGr
|
||||
) {
|
||||
// filter these meta keys to avoid to call keyboardSearch()
|
||||
return true;
|
||||
}
|
||||
|
||||
+4
-27
@@ -21,7 +21,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
|
||||
#include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||
#include <Inventor/nodes/SoClipPlane.h>
|
||||
@@ -30,8 +29,6 @@
|
||||
#include <QDockWidget>
|
||||
#include <QPointer>
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "Clipping.h"
|
||||
#include "ui_Clipping.h"
|
||||
#include "DockWindowManager.h"
|
||||
@@ -54,10 +51,6 @@ public:
|
||||
bool flipY {false};
|
||||
bool flipZ {false};
|
||||
SoTimerSensor* sensor;
|
||||
App::Document* shownOn {nullptr};
|
||||
QDockWidget* dockWidget {nullptr};
|
||||
fastsignals::scoped_connection activeDocConnection;
|
||||
|
||||
Private()
|
||||
{
|
||||
clipX = new SoClipPlane();
|
||||
@@ -106,7 +99,7 @@ public:
|
||||
|
||||
/* TRANSLATOR Gui::Dialog::Clipping */
|
||||
|
||||
Clipping::Clipping(Gui::View3DInventor* view, App::Document* showOn, QWidget* parent)
|
||||
Clipping::Clipping(Gui::View3DInventor* view, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
@@ -131,7 +124,6 @@ Clipping::Clipping(Gui::View3DInventor* view, App::Document* showOn, QWidget* pa
|
||||
d->ui.dirZ->setRange(-max, max);
|
||||
d->ui.dirZ->setSingleStep(0.1f);
|
||||
d->ui.dirZ->setValue(1.0f);
|
||||
d->shownOn = showOn;
|
||||
|
||||
d->view = view;
|
||||
View3DInventorViewer* viewer = view->getViewer();
|
||||
@@ -198,15 +190,14 @@ Clipping::Clipping(Gui::View3DInventor* view, App::Document* showOn, QWidget* pa
|
||||
}
|
||||
}
|
||||
|
||||
Clipping* Clipping::makeDockWidget(Gui::View3DInventor* view, App::Document* showOn)
|
||||
Clipping* Clipping::makeDockWidget(Gui::View3DInventor* view)
|
||||
{
|
||||
// embed this dialog into a QDockWidget
|
||||
auto clipping = new Clipping(view, showOn);
|
||||
auto clipping = new Clipping(view);
|
||||
Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance();
|
||||
QDockWidget* dw = pDockMgr->addDockWindow("Clipping", clipping, Qt::LeftDockWidgetArea);
|
||||
dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
|
||||
dw->show();
|
||||
clipping->d->dockWidget = dw;
|
||||
|
||||
return clipping;
|
||||
}
|
||||
@@ -214,7 +205,6 @@ Clipping* Clipping::makeDockWidget(Gui::View3DInventor* view, App::Document* sho
|
||||
/** Destroys the object and frees any allocated resources */
|
||||
Clipping::~Clipping()
|
||||
{
|
||||
d->activeDocConnection.disconnect();
|
||||
d->node->removeChild(d->clipX);
|
||||
d->node->removeChild(d->clipY);
|
||||
d->node->removeChild(d->clipZ);
|
||||
@@ -226,8 +216,6 @@ Clipping::~Clipping()
|
||||
void Clipping::setupConnections()
|
||||
{
|
||||
// clang-format off
|
||||
d->activeDocConnection = App::GetApplication().signalActiveDocument.connect(
|
||||
std::bind(&Clipping::onActiveDocument, this, std::placeholders::_1));
|
||||
connect(d->ui.groupBoxX, &QGroupBox::toggled,
|
||||
this, &Clipping::onGroupBoxXToggled);
|
||||
connect(d->ui.groupBoxY, &QGroupBox::toggled,
|
||||
@@ -271,18 +259,7 @@ void Clipping::reject()
|
||||
dw->deleteLater();
|
||||
}
|
||||
}
|
||||
void Clipping::onActiveDocument(const App::Document& doc)
|
||||
{
|
||||
if (!d || !d->dockWidget) {
|
||||
return;
|
||||
}
|
||||
if (&doc == d->shownOn) {
|
||||
d->dockWidget->show();
|
||||
}
|
||||
else {
|
||||
d->dockWidget->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void Clipping::onGroupBoxXToggled(bool on)
|
||||
{
|
||||
if (on) {
|
||||
|
||||
+2
-8
@@ -26,11 +26,6 @@
|
||||
#include <QDialog>
|
||||
#include <FCGlobal.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class View3DInventor;
|
||||
@@ -45,13 +40,12 @@ class GuiExport Clipping: public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Clipping* makeDockWidget(Gui::View3DInventor*, App::Document* showOn);
|
||||
Clipping(Gui::View3DInventor* view, App::Document* showOn, QWidget* parent = nullptr);
|
||||
static Clipping* makeDockWidget(Gui::View3DInventor*);
|
||||
Clipping(Gui::View3DInventor* view, QWidget* parent = nullptr);
|
||||
~Clipping() override;
|
||||
|
||||
protected:
|
||||
void setupConnections();
|
||||
void onActiveDocument(const App::Document& doc);
|
||||
void onGroupBoxXToggled(bool);
|
||||
void onGroupBoxYToggled(bool);
|
||||
void onGroupBoxZToggled(bool);
|
||||
|
||||
+24
-59
@@ -36,7 +36,7 @@
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObject.h>
|
||||
#include <App/Transactions.h>
|
||||
#include <App/AutoTransaction.h>
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Interpreter.h>
|
||||
@@ -45,7 +45,6 @@
|
||||
|
||||
#include "Command.h"
|
||||
#include "Action.h"
|
||||
#include "App/Application.h"
|
||||
#include "Application.h"
|
||||
#include "BitmapFactory.h"
|
||||
#include "Control.h"
|
||||
@@ -448,6 +447,11 @@ void Command::invoke(int i, TriggerSource trigger)
|
||||
void Command::_invoke(int id, bool disablelog)
|
||||
{
|
||||
try {
|
||||
// Because Transaction now captures ViewObject changes, auto named
|
||||
// transaction is disabled here to avoid too many unnecessary transactions.
|
||||
//
|
||||
App::AutoTransaction committer(nullptr, true);
|
||||
|
||||
// set the application module type for the macro
|
||||
getGuiApplication()->macroManager()->setModule(sAppModule);
|
||||
|
||||
@@ -459,6 +463,7 @@ void Command::_invoke(int id, bool disablelog)
|
||||
// check if it really works NOW (could be a delay between click deactivation of the button)
|
||||
if (isActive()) {
|
||||
auto manager = getGuiApplication()->macroManager();
|
||||
auto editDoc = getGuiApplication()->editDocument();
|
||||
|
||||
if (!logdisabler) {
|
||||
activated(id);
|
||||
@@ -494,10 +499,12 @@ void Command::_invoke(int id, bool disablelog)
|
||||
}
|
||||
|
||||
getMainWindow()->updateActions();
|
||||
|
||||
// If this command starts an editing, let the transaction persist
|
||||
if (!editDoc && getGuiApplication()->editDocument()) {
|
||||
committer.setEnable(false);
|
||||
}
|
||||
}
|
||||
// here we assume that the overriden activated() function
|
||||
// commited, aborted or gave the transaction id to a dialog
|
||||
currentTransactionID = App::NullTransaction; // Get ready for next invoke
|
||||
}
|
||||
catch (const Base::SystemExitException&) {
|
||||
throw;
|
||||
@@ -543,10 +550,9 @@ void Command::testActive()
|
||||
|
||||
if (!(eType & ForEdit)) { // special case for commands which are only in some edit modes active
|
||||
|
||||
App::Document* doc = getDocument();
|
||||
if ((!Gui::Control().isAllowedAlterDocument(doc) && eType & AlterDoc)
|
||||
|| (!Gui::Control().isAllowedAlterView(doc) && eType & Alter3DView)
|
||||
|| (!Gui::Control().isAllowedAlterSelection(doc) && eType & AlterSelection)) {
|
||||
if ((!Gui::Control().isAllowedAlterDocument() && eType & AlterDoc)
|
||||
|| (!Gui::Control().isAllowedAlterView() && eType & Alter3DView)
|
||||
|| (!Gui::Control().isAllowedAlterSelection() && eType & AlterSelection)) {
|
||||
_pcAction->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
@@ -675,68 +681,27 @@ QString Command::translatedGroupName() const
|
||||
* operation default is the Command name.
|
||||
* @see CommitCommand(),AbortCommand()
|
||||
*/
|
||||
int Command::openCommand(App::TransactionName name)
|
||||
void Command::openCommand(const char* sCmdName)
|
||||
{
|
||||
currentTransactionID = openActiveDocumentCommand(name);
|
||||
return currentTransactionID;
|
||||
}
|
||||
int Command::openCommand(std::string name)
|
||||
{
|
||||
return openCommand(App::TransactionName {.name = name, .temporary = false});
|
||||
}
|
||||
int Command::openActiveDocumentCommand(App::TransactionName name, int tid)
|
||||
{
|
||||
if (Gui::Document* guidoc = getGuiApplication()->activeDocument()) {
|
||||
return guidoc->getDocument()->setActiveTransaction(name, tid);
|
||||
if (!sCmdName) {
|
||||
sCmdName = "Command";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int Command::openActiveDocumentCommand(std::string name, int tid)
|
||||
{
|
||||
return openActiveDocumentCommand(App::TransactionName {.name = name, .temporary = false}, tid);
|
||||
}
|
||||
void Command::rename(const std::string& name)
|
||||
{
|
||||
App::GetApplication().setTransactionName(
|
||||
currentTransactionID,
|
||||
App::TransactionName {.name = name, .temporary = false}
|
||||
);
|
||||
App::GetApplication().setActiveTransaction(sCmdName);
|
||||
}
|
||||
|
||||
void Command::commitCommand()
|
||||
{
|
||||
commitCommand(currentTransactionID);
|
||||
currentTransactionID = App::NullTransaction;
|
||||
}
|
||||
void Command::commitCommand(int tid)
|
||||
{
|
||||
if (tid != App::NullTransaction) {
|
||||
App::GetApplication().commitTransaction(tid);
|
||||
}
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
|
||||
void Command::abortCommand()
|
||||
{
|
||||
abortCommand(currentTransactionID);
|
||||
currentTransactionID = App::NullTransaction;
|
||||
}
|
||||
void Command::abortCommand(int tid)
|
||||
{
|
||||
if (tid != App::NullTransaction) {
|
||||
App::GetApplication().abortTransaction(tid);
|
||||
}
|
||||
}
|
||||
int Command::transactionID() const
|
||||
{
|
||||
return currentTransactionID;
|
||||
}
|
||||
void Command::resetTransactionID()
|
||||
{
|
||||
currentTransactionID = App::NullTransaction;
|
||||
App::GetApplication().closeActiveTransaction(true);
|
||||
}
|
||||
|
||||
bool Command::hasPendingCommand()
|
||||
{
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
return doc && doc->getBookedTransactionID() != App::NullTransaction;
|
||||
return !!App::GetApplication().getActiveTransaction();
|
||||
}
|
||||
|
||||
bool Command::_blockCmd = false;
|
||||
|
||||
+3
-18
@@ -473,24 +473,11 @@ public:
|
||||
/** @name Helper methods for the Undo/Redo and Update handling */
|
||||
//@{
|
||||
/// Open a new Undo transaction on the active document
|
||||
int openCommand(App::TransactionName name);
|
||||
int openCommand(std::string name);
|
||||
static int openActiveDocumentCommand(App::TransactionName name, int tid = App::NullTransaction);
|
||||
static int openActiveDocumentCommand(std::string name, int tid = App::NullTransaction);
|
||||
|
||||
void rename(const std::string& name);
|
||||
|
||||
static void openCommand(const char* sName = nullptr);
|
||||
/// Commit the Undo transaction on the active document
|
||||
void commitCommand();
|
||||
static void commitCommand(int tid);
|
||||
|
||||
static void commitCommand();
|
||||
/// Abort the Undo transaction on the active document
|
||||
void abortCommand();
|
||||
static void abortCommand(int tid);
|
||||
|
||||
int transactionID() const;
|
||||
void resetTransactionID();
|
||||
|
||||
static void abortCommand();
|
||||
/// Check if an Undo transaction is open on the active document
|
||||
static bool hasPendingCommand();
|
||||
/// Updates the (active) document (propagate changes)
|
||||
@@ -728,8 +715,6 @@ protected:
|
||||
/// Indicate if the command shall log to MacroManager
|
||||
bool bCanLog;
|
||||
//@}
|
||||
|
||||
int currentTransactionID {0}; // TransactionID created in _invoke
|
||||
private:
|
||||
static int _busy;
|
||||
bool bEnabled;
|
||||
|
||||
+26
-51
@@ -710,7 +710,6 @@ StdCmdNew::StdCmdNew()
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "document-new";
|
||||
sAccel = keySequenceToAccel(QKeySequence::New);
|
||||
eType = NoTransaction;
|
||||
}
|
||||
|
||||
void StdCmdNew::activated(int iMsg)
|
||||
@@ -1447,57 +1446,41 @@ void StdCmdDelete::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
int tid = 0;
|
||||
std::set<App::Document*> docs;
|
||||
try {
|
||||
std::set<App::Document*> docs;
|
||||
std::vector<App::TransactionLocker> tlocks;
|
||||
auto manageDocCommand = [&tid, &tlocks](App::Document* doc) {
|
||||
// The tid will not be updated if non-zero
|
||||
tid = doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Delete"), tid);
|
||||
tlocks.emplace_back(doc);
|
||||
};
|
||||
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Delete"));
|
||||
if (getGuiApplication()->sendHasMsgToFocusView(getName())) {
|
||||
// no command has been opened yet so we can skip this commit
|
||||
// commitCommand();
|
||||
commitCommand();
|
||||
return;
|
||||
}
|
||||
// Ensure that the document from which we send the command
|
||||
// can undo it (e.g delete a subobject of an assembly
|
||||
// from the assembly file)
|
||||
manageDocCommand(getActiveGuiDocument()->getDocument());
|
||||
|
||||
App::TransactionLocker tlock;
|
||||
|
||||
Gui::getMainWindow()->setUpdatesEnabled(false);
|
||||
|
||||
bool deletedSelectionOfEditDocument = false;
|
||||
std::vector<Gui::Document*> editDocs = Application::Instance->editDocuments();
|
||||
for (auto& editDoc : editDocs) {
|
||||
auto vpedit = freecad_cast<ViewProviderDocumentObject*>(editDoc->getInEdit());
|
||||
|
||||
// In practice, no ViewProviderDocumentObject accepts deletion in edit - 2025-06-17
|
||||
if (vpedit && !vpedit->acceptDeletionsInEdit()) {
|
||||
for (auto& sel : Selection().getSelectionEx(editDoc->getDocument()->getName())) {
|
||||
if (sel.getObject() == vpedit->getObject()) {
|
||||
if (!sel.getSubNames().empty()) {
|
||||
deletedSelectionOfEditDocument = true;
|
||||
manageDocCommand(editDoc->getDocument());
|
||||
vpedit->onDelete(sel.getSubNames());
|
||||
docs.insert(editDoc->getDocument());
|
||||
}
|
||||
break;
|
||||
auto editDoc = Application::Instance->editDocument();
|
||||
ViewProviderDocumentObject* vpedit = nullptr;
|
||||
if (editDoc) {
|
||||
vpedit = freecad_cast<ViewProviderDocumentObject*>(editDoc->getInEdit());
|
||||
}
|
||||
if (vpedit && !vpedit->acceptDeletionsInEdit()) {
|
||||
for (auto& sel : Selection().getSelectionEx(editDoc->getDocument()->getName())) {
|
||||
if (sel.getObject() == vpedit->getObject()) {
|
||||
if (!sel.getSubNames().empty()) {
|
||||
vpedit->onDelete(sel.getSubNames());
|
||||
docs.insert(editDoc->getDocument());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deletedSelectionOfEditDocument) {
|
||||
else {
|
||||
std::set<QString> affectedLabels;
|
||||
bool more = false;
|
||||
auto sels = Selection().getSelectionEx();
|
||||
bool autoDeletion = true;
|
||||
for (auto& sel : sels) {
|
||||
auto obj = sel.getObject();
|
||||
if (!obj) {
|
||||
if (obj == nullptr) {
|
||||
Base::Console().developerWarning(
|
||||
"StdCmdDelete::activated",
|
||||
"App::DocumentObject pointer is nullptr\n"
|
||||
@@ -1565,7 +1548,6 @@ void StdCmdDelete::activated(int iMsg)
|
||||
auto obj = sel.getObject();
|
||||
Gui::ViewProvider* vp = Application::Instance->getViewProvider(obj);
|
||||
if (vp) {
|
||||
manageDocCommand(obj->getDocument());
|
||||
// ask the ViewProvider if it wants to do some clean up
|
||||
if (vp->onDelete(sel.getSubNames())) {
|
||||
docs.insert(obj->getDocument());
|
||||
@@ -1599,8 +1581,6 @@ void StdCmdDelete::activated(int iMsg)
|
||||
QString::fromLatin1(e.what())
|
||||
);
|
||||
e.reportException();
|
||||
App::GetApplication().abortTransaction(tid);
|
||||
tid = 0;
|
||||
}
|
||||
catch (...) {
|
||||
QMessageBox::critical(
|
||||
@@ -1608,11 +1588,8 @@ void StdCmdDelete::activated(int iMsg)
|
||||
QObject::tr("Delete Failed"),
|
||||
QStringLiteral("Unknown error")
|
||||
);
|
||||
App::GetApplication().abortTransaction(tid);
|
||||
tid = 0;
|
||||
}
|
||||
|
||||
App::GetApplication().commitTransaction(tid);
|
||||
commitCommand();
|
||||
Gui::getMainWindow()->setUpdatesEnabled(true);
|
||||
Gui::getMainWindow()->update();
|
||||
}
|
||||
@@ -1658,8 +1635,7 @@ void StdCmdRefresh::activated([[maybe_unused]] int iMsg)
|
||||
return;
|
||||
}
|
||||
|
||||
App::AutoTransaction trans((eType & NoTransaction) ? 0 : openActiveDocumentCommand("Recompute"));
|
||||
|
||||
App::AutoTransaction trans((eType & NoTransaction) ? nullptr : "Recompute");
|
||||
try {
|
||||
doCommand(Doc, "App.activeDocument().recompute(None,True,True)");
|
||||
}
|
||||
@@ -1762,7 +1738,7 @@ void StdCmdPlacement::activated(int iMsg)
|
||||
plm->clearSelection();
|
||||
}
|
||||
}
|
||||
Gui::Control().showDialog(plm, getDocument());
|
||||
Gui::Control().showDialog(plm);
|
||||
}
|
||||
|
||||
bool StdCmdPlacement::isActive()
|
||||
@@ -2157,10 +2133,9 @@ protected:
|
||||
return;
|
||||
}
|
||||
|
||||
int tid = App::NullTransaction;
|
||||
openCommand(QT_TRANSLATE_NOOP("Command", "Paste expressions"));
|
||||
try {
|
||||
for (auto& v : exprs) {
|
||||
tid = v.first->openTransaction(QT_TRANSLATE_NOOP("Command", "Paste expressions"), tid);
|
||||
for (auto& v2 : v.second) {
|
||||
auto& expressions = v2.second;
|
||||
auto old = v2.first->getExpressions();
|
||||
@@ -2177,13 +2152,13 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
App::GetApplication().commitTransaction(tid);
|
||||
commitCommand();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
App::GetApplication().abortTransaction(tid);
|
||||
abortCommand();
|
||||
QMessageBox::critical(
|
||||
getMainWindow(),
|
||||
QObject::tr("Failed to paste expressions"),
|
||||
QObject::tr("Failed to Paste Expressions"),
|
||||
QString::fromLatin1(e.what())
|
||||
);
|
||||
e.reportException();
|
||||
|
||||
@@ -330,7 +330,7 @@ Gui::Action* StdCmdToggleSkipRecompute::createAction()
|
||||
void StdCmdToggleSkipRecompute::activated(int iMsg)
|
||||
{
|
||||
const auto doc = this->getDocument();
|
||||
if (!doc) {
|
||||
if (doc == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ void StdCmdToggleSkipRecompute::activated(int iMsg)
|
||||
bool StdCmdToggleSkipRecompute::isActive()
|
||||
{
|
||||
const auto doc = this->getDocument();
|
||||
if (!doc) {
|
||||
if (doc == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+44
-62
@@ -34,11 +34,9 @@
|
||||
#include "Action.h"
|
||||
#include "Application.h"
|
||||
#include "Command.h"
|
||||
#include "Control.h"
|
||||
#include "Document.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Selection.h"
|
||||
#include "TaskCommandLink.h"
|
||||
#include "Tree.h"
|
||||
#include "ViewProviderDocumentObject.h"
|
||||
#include "WaitCursor.h"
|
||||
@@ -282,51 +280,6 @@ void StdCmdLinkMake::activated(int)
|
||||
return;
|
||||
}
|
||||
|
||||
auto exec = [=](std::vector<App::DocumentObject*> objs) {
|
||||
doc->openTransaction(QT_TRANSLATE_NOOP("Command", "Make link"));
|
||||
try {
|
||||
if (objs.empty()) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(
|
||||
Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s')",
|
||||
doc->getName(),
|
||||
name.c_str()
|
||||
);
|
||||
Selection().addSelection(doc->getName(), name.c_str());
|
||||
}
|
||||
else {
|
||||
for (auto obj : objs) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(
|
||||
Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s').setLink(App.getDocument("
|
||||
"'%s'"
|
||||
").%s)",
|
||||
doc->getName(),
|
||||
name.c_str(),
|
||||
obj->getDocument()->getName(),
|
||||
obj->getNameInDocument()
|
||||
);
|
||||
setLinkLabel(obj, doc->getName(), name.c_str());
|
||||
Selection().addSelection(doc->getName(), name.c_str());
|
||||
}
|
||||
}
|
||||
Selection().selStackPush();
|
||||
doc->commitTransaction();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
doc->abortTransaction();
|
||||
QMessageBox::critical(
|
||||
getMainWindow(),
|
||||
QObject::tr("Create link failed"),
|
||||
QString::fromLatin1(e.what())
|
||||
);
|
||||
e.reportException();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
std::set<App::DocumentObject*> objs;
|
||||
for (auto& sel : Selection().getCompleteSelection()) {
|
||||
if (sel.pObject && sel.pObject->isAttachedToDocument()) {
|
||||
@@ -334,13 +287,48 @@ void StdCmdLinkMake::activated(int)
|
||||
}
|
||||
}
|
||||
|
||||
if (objs.empty()) {
|
||||
Gui::Control().showDialog(new TaskCommandLinkDialog(exec));
|
||||
}
|
||||
else {
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
|
||||
Command::openCommand(QT_TRANSLATE_NOOP("Command", "Make link"));
|
||||
try {
|
||||
if (objs.empty()) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(
|
||||
Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s')",
|
||||
doc->getName(),
|
||||
name.c_str()
|
||||
);
|
||||
Selection().addSelection(doc->getName(), name.c_str());
|
||||
}
|
||||
else {
|
||||
for (auto obj : objs) {
|
||||
std::string name = doc->getUniqueObjectName("Link");
|
||||
Command::doCommand(
|
||||
Command::Doc,
|
||||
"App.getDocument('%s').addObject('App::Link','%s').setLink(App.getDocument('%s'"
|
||||
").%s)",
|
||||
doc->getName(),
|
||||
name.c_str(),
|
||||
obj->getDocument()->getName(),
|
||||
obj->getNameInDocument()
|
||||
);
|
||||
setLinkLabel(obj, doc->getName(), name.c_str());
|
||||
Selection().addSelection(doc->getName(), name.c_str());
|
||||
}
|
||||
}
|
||||
Selection().selStackPush();
|
||||
Selection().clearCompleteSelection();
|
||||
exec(std::vector<App::DocumentObject*>(objs.begin(), objs.end()));
|
||||
Command::commitCommand();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
Command::abortCommand();
|
||||
QMessageBox::critical(
|
||||
getMainWindow(),
|
||||
QObject::tr("Create link failed"),
|
||||
QString::fromLatin1(e.what())
|
||||
);
|
||||
e.reportException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +476,7 @@ static void linkConvert(bool unlink)
|
||||
|
||||
// now, do actual operation
|
||||
const char* transactionName = unlink ? "Unlink" : "Replace with link";
|
||||
int tid = 0;
|
||||
Command::openCommand(transactionName);
|
||||
try {
|
||||
std::unordered_map<App::DocumentObject*, App::DocumentObjectT> recomputeSet;
|
||||
for (auto& v : infos) {
|
||||
@@ -505,12 +493,6 @@ static void linkConvert(bool unlink)
|
||||
recomputeSet.emplace(parent, parent);
|
||||
}
|
||||
auto doc = parent->getDocument();
|
||||
|
||||
tid = doc->openTransaction(
|
||||
App::TransactionName {.name = transactionName, .temporary = false},
|
||||
tid
|
||||
);
|
||||
|
||||
App::DocumentObject* replaceObj;
|
||||
if (unlink) {
|
||||
replaceObj = obj->getLinkedObject(false);
|
||||
@@ -570,10 +552,10 @@ static void linkConvert(bool unlink)
|
||||
recomputes.front()->getDocument()->recompute(recomputes);
|
||||
}
|
||||
|
||||
App::GetApplication().commitTransaction(tid);
|
||||
Command::commitCommand();
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
App::GetApplication().abortTransaction(tid);
|
||||
Command::abortCommand();
|
||||
auto title = unlink ? QObject::tr("Unlink failed") : QObject::tr("Replace link failed");
|
||||
QMessageBox::critical(getMainWindow(), title, QString::fromLatin1(e.what()));
|
||||
e.reportException();
|
||||
|
||||
@@ -116,8 +116,10 @@ PyObject* CommandPy::listByShortcut(PyObject* args)
|
||||
matches.emplace_back(c->getName());
|
||||
}
|
||||
}
|
||||
else if (action->shortcut().toString().remove(spc).toUpper()
|
||||
== QString::fromLatin1(shortcut_to_find).remove(spc).toUpper()) {
|
||||
else if (
|
||||
action->shortcut().toString().remove(spc).toUpper()
|
||||
== QString::fromLatin1(shortcut_to_find).remove(spc).toUpper()
|
||||
) {
|
||||
matches.emplace_back(c->getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,8 +101,6 @@ void StdCmdPart::activated(int iMsg)
|
||||
PartName.c_str()
|
||||
);
|
||||
|
||||
commitCommand();
|
||||
|
||||
updateActive();
|
||||
}
|
||||
|
||||
|
||||
+7
-66
@@ -21,9 +21,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#include <Inventor/events/SoMouseButtonEvent.h>
|
||||
#include <Inventor/nodes/SoOrthographicCamera.h>
|
||||
#include <Inventor/nodes/SoPerspectiveCamera.h>
|
||||
@@ -397,7 +394,7 @@ void StdCmdFreezeViews::activated(int iMsg)
|
||||
else if (iMsg == 3) {
|
||||
// Create a new view
|
||||
auto* view3d = freecad_cast<View3DInventor*>(getGuiApplication()->activeView());
|
||||
if (!view3d) {
|
||||
if (view3d == nullptr) {
|
||||
Base::Console().developerError(
|
||||
"StdCmdFreezeViews",
|
||||
"Expected the active view to be View3DInventor\n"
|
||||
@@ -643,34 +640,7 @@ void StdCmdFreezeViews::languageChange()
|
||||
// Std_ToggleClipPlane
|
||||
//===========================================================================
|
||||
|
||||
class StdCmdToggleClipPlane: public Gui::Command
|
||||
{
|
||||
public:
|
||||
StdCmdToggleClipPlane();
|
||||
virtual ~StdCmdToggleClipPlane()
|
||||
{}
|
||||
virtual const char* className() const
|
||||
{
|
||||
return "StdCmdToggleClipPlane";
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void activated(int iMsg);
|
||||
virtual bool isActive(void);
|
||||
virtual Gui::Action* createAction(void);
|
||||
|
||||
private:
|
||||
StdCmdToggleClipPlane(const StdCmdToggleClipPlane&) = delete;
|
||||
StdCmdToggleClipPlane(StdCmdToggleClipPlane&&) = delete;
|
||||
StdCmdToggleClipPlane& operator=(const StdCmdToggleClipPlane&) = delete;
|
||||
StdCmdToggleClipPlane& operator=(StdCmdToggleClipPlane&&) = delete;
|
||||
|
||||
void garbageCollect();
|
||||
bool hasClipping(App::Document* doc) const;
|
||||
|
||||
private:
|
||||
std::vector<std::pair<App::Document*, QPointer<Gui::Dialog::Clipping>>> clippings;
|
||||
};
|
||||
DEF_STD_CMD_AC(StdCmdToggleClipPlane)
|
||||
|
||||
StdCmdToggleClipPlane::StdCmdToggleClipPlane()
|
||||
: Command("Std_ToggleClipPlane")
|
||||
@@ -693,15 +663,11 @@ Action* StdCmdToggleClipPlane::createAction()
|
||||
void StdCmdToggleClipPlane::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
App::Document* doc = getActiveDocument();
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
garbageCollect(); // remove dead pointers
|
||||
if (!hasClipping(doc)) {
|
||||
static QPointer<Gui::Dialog::Clipping> clipping = nullptr;
|
||||
if (!clipping) {
|
||||
auto view = qobject_cast<View3DInventor*>(getMainWindow()->activeWindow());
|
||||
if (view) {
|
||||
clippings.push_back(std::make_pair(doc, Gui::Dialog::Clipping::makeDockWidget(view, doc)));
|
||||
clipping = Gui::Dialog::Clipping::makeDockWidget(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -712,31 +678,6 @@ bool StdCmdToggleClipPlane::isActive()
|
||||
return view ? true : false;
|
||||
}
|
||||
|
||||
void StdCmdToggleClipPlane::garbageCollect()
|
||||
{
|
||||
// We assume the vector to be small
|
||||
std::vector<std::pair<App::Document*, QPointer<Gui::Dialog::Clipping>>> newClippings;
|
||||
newClippings.reserve(clippings.size());
|
||||
std::copy_if(
|
||||
clippings.begin(),
|
||||
clippings.end(),
|
||||
std::back_inserter(newClippings),
|
||||
[](const std::pair<App::Document*, QPointer<Gui::Dialog::Clipping>>& clipPair) -> bool {
|
||||
return clipPair.second != nullptr;
|
||||
}
|
||||
);
|
||||
clippings = newClippings;
|
||||
}
|
||||
bool StdCmdToggleClipPlane::hasClipping(App::Document* doc) const
|
||||
{
|
||||
return std::ranges::find(
|
||||
clippings,
|
||||
doc,
|
||||
&std::pair<App::Document*, QPointer<Gui::Dialog::Clipping>>::first
|
||||
)
|
||||
!= clippings.end();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// StdCmdDrawStyle
|
||||
//===========================================================================
|
||||
@@ -2698,7 +2639,7 @@ void StdCmdViewIvIssueCamPos::activated(int iMsg)
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
auto* view3d = freecad_cast<View3DInventor*>(getGuiApplication()->activeView());
|
||||
if (!view3d) {
|
||||
if (view3d == nullptr) {
|
||||
Base::Console().developerError(
|
||||
"StdCmdViewIvIssueCameraPos",
|
||||
"Expected the active view to be View3DInventor\n"
|
||||
@@ -3490,7 +3431,7 @@ StdCmdTextureMapping::StdCmdTextureMapping()
|
||||
void StdCmdTextureMapping::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
Gui::Control().showDialog(new Gui::Dialog::TaskTextureMapping, getDocument());
|
||||
Gui::Control().showDialog(new Gui::Dialog::TaskTextureMapping);
|
||||
}
|
||||
|
||||
bool StdCmdTextureMapping::isActive()
|
||||
|
||||
+51
-110
@@ -26,12 +26,10 @@
|
||||
#include <QDockWidget>
|
||||
#include <QPointer>
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <App/AutoTransaction.h>
|
||||
#include <Gui/ComboView.h>
|
||||
#include <Gui/DockWindowManager.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
#include <Gui/Document.h>
|
||||
|
||||
#include "Control.h"
|
||||
#include "BitmapFactory.h"
|
||||
@@ -47,7 +45,8 @@ using namespace std;
|
||||
ControlSingleton* ControlSingleton::_pcSingleton = nullptr;
|
||||
|
||||
ControlSingleton::ControlSingleton()
|
||||
: oldTabIndex(-1)
|
||||
: ActiveDialog(nullptr)
|
||||
, oldTabIndex(-1)
|
||||
{}
|
||||
|
||||
ControlSingleton::~ControlSingleton() = default;
|
||||
@@ -146,28 +145,14 @@ void ControlSingleton::showModelView()
|
||||
}
|
||||
}
|
||||
|
||||
void ControlSingleton::showDialog(Gui::TaskView::TaskDialog* dlg, App::Document* attachTo)
|
||||
void ControlSingleton::showDialog(Gui::TaskView::TaskDialog* dlg)
|
||||
{
|
||||
attachTo = docOrDefault(attachTo);
|
||||
if (!attachTo) {
|
||||
qWarning() << "ControlSingleton::showDialog: Cannot attach to nullptr document";
|
||||
return;
|
||||
}
|
||||
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
// should return the pointer to combo view
|
||||
if (!taskView) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only one dialog at a time, print a warning instead of raising an assert
|
||||
TaskView::TaskDialog* foundDialog = taskView->dialog(attachTo);
|
||||
if (!dlg || foundDialog == dlg) {
|
||||
if (ActiveDialog && ActiveDialog != dlg) {
|
||||
if (dlg) {
|
||||
qWarning() << "ControlSingleton::showDialog: Can't show "
|
||||
<< dlg->metaObject()->className()
|
||||
<< " since there is already an active task dialog in Document "
|
||||
<< (attachTo ? attachTo->getName() : "''");
|
||||
<< " since there is already an active task dialog";
|
||||
}
|
||||
else {
|
||||
qWarning() << "ControlSingleton::showDialog: Task dialog is null";
|
||||
@@ -175,87 +160,69 @@ void ControlSingleton::showDialog(Gui::TaskView::TaskDialog* dlg, App::Document*
|
||||
return;
|
||||
}
|
||||
|
||||
bool addedDialog = taskView->showDialog(dlg, attachTo);
|
||||
|
||||
// make sure that the combo view is shown
|
||||
if (auto dw = qobject_cast<QDockWidget*>(taskView->parentWidget())) {
|
||||
aboutToShowDialog(dw);
|
||||
dw->setVisible(true);
|
||||
dw->toggleViewAction()->setVisible(true);
|
||||
dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
|
||||
}
|
||||
|
||||
if (!addedDialog) {
|
||||
return; // dialog is already defined
|
||||
}
|
||||
|
||||
connect(dlg, &TaskView::TaskDialog::aboutToBeDestroyed, this, [this, attachTo] {
|
||||
closedDialog(attachTo);
|
||||
});
|
||||
}
|
||||
|
||||
Gui::TaskView::TaskDialog* ControlSingleton::activeDialog(App::Document* attachedTo) const
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
return nullptr;
|
||||
}
|
||||
// Since the caller sets up a modeless task panel, it indicates intention
|
||||
// for prolonged editing. So disable auto transaction in the current call
|
||||
// stack.
|
||||
// Do this before showing the dialog because its open() function is called
|
||||
// which may open a transaction but fails when auto transaction is still active.
|
||||
App::AutoTransaction::setEnable(false);
|
||||
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
|
||||
// should return the pointer to combo view
|
||||
if (taskView) {
|
||||
return taskView->dialog(attachedTo);
|
||||
taskView->showDialog(dlg);
|
||||
|
||||
// make sure that the combo view is shown
|
||||
auto dw = qobject_cast<QDockWidget*>(taskView->parentWidget());
|
||||
if (dw) {
|
||||
aboutToShowDialog(dw);
|
||||
dw->setVisible(true);
|
||||
dw->toggleViewAction()->setVisible(true);
|
||||
dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
|
||||
}
|
||||
|
||||
if (ActiveDialog == dlg) {
|
||||
return; // dialog is already defined
|
||||
}
|
||||
ActiveDialog = dlg;
|
||||
connect(dlg, &TaskView::TaskDialog::aboutToBeDestroyed, this, &ControlSingleton::closedDialog);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ControlSingleton::accept(App::Document* attachedTo)
|
||||
Gui::TaskView::TaskDialog* ControlSingleton::activeDialog() const
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
qWarning() << "ControlSingleton::accept: Cannot accept dialog of nullptr document";
|
||||
return;
|
||||
}
|
||||
return ActiveDialog;
|
||||
}
|
||||
|
||||
void ControlSingleton::accept()
|
||||
{
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
if (taskView) {
|
||||
taskView->accept(attachedTo);
|
||||
taskView->accept();
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlSingleton::reject(App::Document* attachedTo)
|
||||
void ControlSingleton::reject()
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
qWarning() << "ControlSingleton::reject: Cannot reject dialog of nullptr document";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
if (taskView) {
|
||||
taskView->reject(attachedTo);
|
||||
taskView->reject();
|
||||
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlSingleton::closeDialog(App::Document* attachedTo)
|
||||
void ControlSingleton::closeDialog()
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
qWarning() << "ControlSingleton::closeDialog: Cannot close dialog of nullptr document";
|
||||
return;
|
||||
}
|
||||
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
if (taskView) {
|
||||
taskView->removeDialog(attachedTo);
|
||||
taskView->removeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
void ControlSingleton::closedDialog(App::Document* attachedTo)
|
||||
void ControlSingleton::closedDialog()
|
||||
{
|
||||
ActiveDialog = nullptr;
|
||||
Gui::TaskView::TaskView* taskView = taskPanel();
|
||||
assert(taskView);
|
||||
|
||||
@@ -270,57 +237,31 @@ void ControlSingleton::closedDialog(App::Document* attachedTo)
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlSingleton::isAllowedAlterDocument(App::Document* attachedTo) const
|
||||
bool ControlSingleton::isAllowedAlterDocument() const
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
return true;
|
||||
}
|
||||
Gui::TaskView::TaskDialog* dlg = activeDialog(attachedTo);
|
||||
|
||||
if (dlg) {
|
||||
return dlg->isAllowedAlterDocument();
|
||||
if (ActiveDialog) {
|
||||
return ActiveDialog->isAllowedAlterDocument();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlSingleton::isAllowedAlterView(App::Document* attachedTo) const
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
return true;
|
||||
}
|
||||
Gui::TaskView::TaskDialog* dlg = activeDialog(attachedTo);
|
||||
|
||||
if (dlg) {
|
||||
return dlg->isAllowedAlterView();
|
||||
bool ControlSingleton::isAllowedAlterView() const
|
||||
{
|
||||
if (ActiveDialog) {
|
||||
return ActiveDialog->isAllowedAlterView();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlSingleton::isAllowedAlterSelection(App::Document* attachedTo) const
|
||||
bool ControlSingleton::isAllowedAlterSelection() const
|
||||
{
|
||||
attachedTo = docOrDefault(attachedTo);
|
||||
if (!attachedTo) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Gui::TaskView::TaskDialog* dlg = activeDialog(attachedTo);
|
||||
|
||||
if (dlg) {
|
||||
return dlg->isAllowedAlterSelection();
|
||||
if (ActiveDialog) {
|
||||
return ActiveDialog->isAllowedAlterSelection();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
App::Document* ControlSingleton::docOrDefault(App::Document* attachedTo)
|
||||
{
|
||||
if (!attachedTo && Application::Instance->activeDocument()) {
|
||||
attachedTo = Application::Instance->activeDocument()->getDocument();
|
||||
}
|
||||
return attachedTo;
|
||||
}
|
||||
|
||||
// -------------------------------------------
|
||||
|
||||
ControlSingleton& ControlSingleton::instance()
|
||||
|
||||
+11
-16
@@ -64,9 +64,8 @@ public:
|
||||
*/
|
||||
//@{
|
||||
/// This method starts a task dialog in the task view
|
||||
/// The dialog is relative to a specific document
|
||||
void showDialog(Gui::TaskView::TaskDialog* dlg, App::Document* attachTo = nullptr);
|
||||
Gui::TaskView::TaskDialog* activeDialog(App::Document* attachedTo = nullptr) const;
|
||||
void showDialog(Gui::TaskView::TaskDialog* dlg);
|
||||
Gui::TaskView::TaskDialog* activeDialog() const;
|
||||
// void closeDialog();
|
||||
//@}
|
||||
|
||||
@@ -82,29 +81,28 @@ public:
|
||||
If a task dialog is open then it indicates whether this task dialog allows other commands to
|
||||
modify the document while it is open. If no task dialog is open true is returned.
|
||||
*/
|
||||
bool isAllowedAlterDocument(App::Document* attachedTo = nullptr) const;
|
||||
bool isAllowedAlterDocument() const;
|
||||
/*!
|
||||
If a task dialog is open then it indicates whether this task dialog allows other commands to
|
||||
modify the 3d view while it is open. If no task dialog is open true is returned.
|
||||
*/
|
||||
bool isAllowedAlterView(App::Document* attachedTo = nullptr) const;
|
||||
bool isAllowedAlterView() const;
|
||||
/*!
|
||||
If a task dialog is open then it indicates whether this task dialog allows other commands to
|
||||
modify the selection while it is open. If no task dialog is open true is returned.
|
||||
*/
|
||||
bool isAllowedAlterSelection(App::Document* attachedTo = nullptr) const;
|
||||
bool isAllowedAlterSelection() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void accept(App::Document* attachedTo = nullptr);
|
||||
void reject(App::Document* attachedTo = nullptr);
|
||||
void closeDialog(App::Document* attachedTo = nullptr);
|
||||
|
||||
void accept();
|
||||
void reject();
|
||||
void closeDialog();
|
||||
/// raises the task view panel
|
||||
void showTaskView();
|
||||
|
||||
private:
|
||||
private Q_SLOTS:
|
||||
/// This get called by the TaskView when the Dialog is finished
|
||||
void closedDialog(App::Document* attachedTo = nullptr);
|
||||
void closedDialog();
|
||||
|
||||
private:
|
||||
struct status
|
||||
@@ -114,7 +112,7 @@ private:
|
||||
|
||||
std::stack<status> StatusStack;
|
||||
|
||||
std::map<App::Document*, Gui::TaskView::TaskDialog*> ActiveDialogs;
|
||||
Gui::TaskView::TaskDialog* ActiveDialog;
|
||||
int oldTabIndex;
|
||||
|
||||
private:
|
||||
@@ -127,9 +125,6 @@ private:
|
||||
void aboutToShowDialog(QDockWidget* widget);
|
||||
void aboutToHideDialog(QDockWidget* widget);
|
||||
|
||||
// Returns attachTo if not nullptr, otherwise return the active document
|
||||
static App::Document* docOrDefault(App::Document* attachedTo);
|
||||
|
||||
static ControlSingleton* _pcSingleton;
|
||||
};
|
||||
|
||||
|
||||
@@ -194,13 +194,14 @@ void DemoMode::onAngleSliderValueChanged(int v)
|
||||
void DemoMode::reorientCamera(SoCamera* cam, const SbRotation& rot)
|
||||
{
|
||||
// Find global coordinates of focal point.
|
||||
SbVec3f focalpoint = activeView()->getViewer()->getFocalPoint();
|
||||
SbVec3f direction;
|
||||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||||
SbVec3f focalpoint = cam->position.getValue() + cam->focalDistance.getValue() * direction;
|
||||
|
||||
// Set new orientation value by accumulating the new rotation.
|
||||
cam->orientation = rot * cam->orientation.getValue();
|
||||
|
||||
// Reposition camera so we are still pointing at the same old focal point.
|
||||
SbVec3f direction;
|
||||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||||
cam->position = focalpoint - cam->focalDistance.getValue() * direction;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ int DlgAddProperty::findLabelRow(const char* labelName, QFormLayout* layout)
|
||||
{
|
||||
for (int row = 0; row < layout->rowCount(); ++row) {
|
||||
QLayoutItem* labelItem = layout->itemAt(row, QFormLayout::LabelRole);
|
||||
if (!labelItem) {
|
||||
if (labelItem == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ void DlgAddProperty::removeExistingWidget(QFormLayout* formLayout, int labelRow)
|
||||
void DlgAddProperty::setWidgetForLabel(const char* labelName, QWidget* widget, QLayout* layout)
|
||||
{
|
||||
auto formLayout = qobject_cast<QFormLayout*>(layout);
|
||||
if (!formLayout) {
|
||||
if (formLayout == nullptr) {
|
||||
FC_ERR("Form layout not found");
|
||||
return;
|
||||
}
|
||||
@@ -403,7 +403,7 @@ void DlgAddProperty::addEditor(PropertyItem* propertyItem)
|
||||
else {
|
||||
addNormalEditor(propertyItem);
|
||||
}
|
||||
if (!editor) {
|
||||
if (editor == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -451,12 +451,12 @@ bool DlgAddProperty::isExcluded(const Base::Type& type) const
|
||||
|
||||
bool DlgAddProperty::isTypeWithEditor(PropertyItem* propertyItem) const
|
||||
{
|
||||
if (!propertyItem) {
|
||||
if (propertyItem == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
App::Property* prop = propertyItem->getFirstProperty();
|
||||
if (!prop) {
|
||||
if (prop == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -689,7 +689,7 @@ void DlgAddProperty::showStatusMessage()
|
||||
|
||||
void DlgAddProperty::removeEditor()
|
||||
{
|
||||
if (!editor) {
|
||||
if (editor == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ QVariant DlgAddProperty::getEditorData() const
|
||||
{
|
||||
if (isEnumPropertyItem()) {
|
||||
PropertyItem* child = propertyItem->child(0);
|
||||
if (!child) {
|
||||
if (child == nullptr) {
|
||||
return {};
|
||||
}
|
||||
return child->editorData(editor.get());
|
||||
@@ -726,7 +726,7 @@ void DlgAddProperty::setEditorData(const QVariant& data)
|
||||
{
|
||||
if (isEnumPropertyItem()) {
|
||||
PropertyItem* child = propertyItem->child(0);
|
||||
if (!child) {
|
||||
if (child == nullptr) {
|
||||
return;
|
||||
}
|
||||
child->setEditorData(editor.get(), data);
|
||||
@@ -741,7 +741,7 @@ void DlgAddProperty::setEditor(bool valueNeedsReset)
|
||||
if (editor && !valueNeedsReset) {
|
||||
QVariant data = getEditorData();
|
||||
addEditor(propertyItem.get());
|
||||
if (!editor) {
|
||||
if (editor == nullptr) {
|
||||
return;
|
||||
}
|
||||
setEditorData(data);
|
||||
@@ -762,15 +762,15 @@ void DlgAddProperty::setEditor(bool valueNeedsReset)
|
||||
|
||||
void DlgAddProperty::setPropertyItem(App::Property* prop, bool supportsExpressions)
|
||||
{
|
||||
if (!prop) {
|
||||
if (prop == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!propertyItem) {
|
||||
if (propertyItem == nullptr) {
|
||||
propertyItem.reset(createPropertyItem(prop));
|
||||
}
|
||||
|
||||
if (!propertyItem) {
|
||||
if (propertyItem == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -816,7 +816,7 @@ bool DlgAddProperty::clearBoundProperty()
|
||||
|
||||
bool DlgAddProperty::clear(FieldChange fieldChange)
|
||||
{
|
||||
if (!propertyItem) {
|
||||
if (propertyItem == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -890,7 +890,7 @@ void DlgAddProperty::changeEvent(QEvent* e)
|
||||
void DlgAddProperty::valueChangedEnum()
|
||||
{
|
||||
auto* propEnum = static_cast<App::PropertyEnumeration*>(propertyItem->getFirstProperty());
|
||||
if (!propEnum || propertyItem->childCount() == 0) {
|
||||
if (propEnum == nullptr || propertyItem->childCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -920,9 +920,7 @@ void DlgAddProperty::valueChanged()
|
||||
*/
|
||||
void DlgAddProperty::openTransaction()
|
||||
{
|
||||
transactionID = App::GetApplication().setActiveTransaction(
|
||||
App::TransactionName {.name = "Add property", .temporary = false}
|
||||
);
|
||||
transactionID = App::GetApplication().setActiveTransaction("Add property");
|
||||
}
|
||||
|
||||
void DlgAddProperty::critical(const QString& title, const QString& text)
|
||||
@@ -995,12 +993,7 @@ void DlgAddProperty::closeTransaction(TransactionOption option)
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == TransactionOption::Abort) {
|
||||
App::GetApplication().abortTransaction(transactionID);
|
||||
}
|
||||
else {
|
||||
App::GetApplication().commitTransaction(transactionID);
|
||||
}
|
||||
App::GetApplication().closeActiveTransaction(static_cast<bool>(option), transactionID);
|
||||
transactionID = 0;
|
||||
}
|
||||
|
||||
@@ -1026,13 +1019,13 @@ void DlgAddProperty::addDocumentation()
|
||||
std::string group = comboBoxGroup.currentText().toStdString();
|
||||
std::string doc = ui->lineEditToolTip->text().toStdString();
|
||||
|
||||
if (!propertyItem) {
|
||||
if (propertyItem == nullptr) {
|
||||
// If there is no property item, we cannot add documentation.
|
||||
return;
|
||||
}
|
||||
|
||||
App::Property* prop = propertyItem->getFirstProperty();
|
||||
if (!prop) {
|
||||
if (prop == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -697,7 +697,7 @@ static App::Document* getPreselectedDocument()
|
||||
}
|
||||
|
||||
App::Document* doc = App::GetApplication().getDocument(lastDoc.c_str());
|
||||
if (!doc) {
|
||||
if (doc == nullptr) {
|
||||
return App::GetApplication().getActiveDocument();
|
||||
}
|
||||
|
||||
@@ -728,7 +728,7 @@ int DlgExpressionInput::getVarSetIndex(const App::Document* doc) const
|
||||
void DlgExpressionInput::preselectVarSet()
|
||||
{
|
||||
const App::Document* doc = getPreselectedDocument();
|
||||
if (!doc) {
|
||||
if (doc == nullptr) {
|
||||
FC_ERR("No active document found");
|
||||
}
|
||||
ui->comboBoxVarSet->setCurrentIndex(getVarSetIndex(doc));
|
||||
@@ -763,7 +763,7 @@ static void addVarSetsVarSetComboBox(
|
||||
auto* vp = freecad_cast<Gui::ViewProviderDocumentObject*>(
|
||||
Gui::Application::Instance->getViewProvider(varSet)
|
||||
);
|
||||
if (!vp) {
|
||||
if (vp == nullptr) {
|
||||
FC_ERR("No ViewProvider found for VarSet: " << varSet->getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
@@ -889,13 +889,13 @@ void DlgExpressionInput::onVarSetSelected(int /*index*/)
|
||||
}
|
||||
|
||||
App::Document* doc = App::GetApplication().getDocument(docName.toUtf8());
|
||||
if (!doc) {
|
||||
if (doc == nullptr) {
|
||||
FC_ERR("Document not found: " << docName.toStdString());
|
||||
return;
|
||||
}
|
||||
|
||||
App::DocumentObject* varSet = doc->getObject(varSetName.toUtf8());
|
||||
if (!varSet) {
|
||||
if (varSet == nullptr) {
|
||||
FC_ERR("Variable set not found: " << varSetName.toStdString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -344,33 +344,25 @@ void DlgParameterImp::onGroupSelected(QTreeWidgetItem* item)
|
||||
// filling up Int nodes
|
||||
std::vector<std::pair<std::string, long>> mcIntMap = _hcGrp->GetIntMap();
|
||||
for (const auto& It3 : mcIntMap) {
|
||||
(
|
||||
void
|
||||
)new ParameterInt(paramValue, QString::fromUtf8(It3.first.c_str()), It3.second, _hcGrp);
|
||||
(void)new ParameterInt(paramValue, QString::fromUtf8(It3.first.c_str()), It3.second, _hcGrp);
|
||||
}
|
||||
|
||||
// filling up Float nodes
|
||||
std::vector<std::pair<std::string, double>> mcFloatMap = _hcGrp->GetFloatMap();
|
||||
for (const auto& It4 : mcFloatMap) {
|
||||
(
|
||||
void
|
||||
)new ParameterFloat(paramValue, QString::fromUtf8(It4.first.c_str()), It4.second, _hcGrp);
|
||||
(void)new ParameterFloat(paramValue, QString::fromUtf8(It4.first.c_str()), It4.second, _hcGrp);
|
||||
}
|
||||
|
||||
// filling up bool nodes
|
||||
std::vector<std::pair<std::string, bool>> mcBoolMap = _hcGrp->GetBoolMap();
|
||||
for (const auto& It5 : mcBoolMap) {
|
||||
(
|
||||
void
|
||||
)new ParameterBool(paramValue, QString::fromUtf8(It5.first.c_str()), It5.second, _hcGrp);
|
||||
(void)new ParameterBool(paramValue, QString::fromUtf8(It5.first.c_str()), It5.second, _hcGrp);
|
||||
}
|
||||
|
||||
// filling up UInt nodes
|
||||
std::vector<std::pair<std::string, unsigned long>> mcUIntMap = _hcGrp->GetUnsignedMap();
|
||||
for (const auto& It6 : mcUIntMap) {
|
||||
(
|
||||
void
|
||||
)new ParameterUInt(paramValue, QString::fromUtf8(It6.first.c_str()), It6.second, _hcGrp);
|
||||
(void)new ParameterUInt(paramValue, QString::fromUtf8(It6.first.c_str()), It6.second, _hcGrp);
|
||||
}
|
||||
paramValue->setSortingEnabled(sortingEnabled);
|
||||
}
|
||||
|
||||
+27
-61
@@ -90,7 +90,6 @@ struct DocumentP
|
||||
bool _isClosing;
|
||||
bool _isModified;
|
||||
bool _isTransacting;
|
||||
bool _isActive;
|
||||
bool _changeViewTouchDocument;
|
||||
bool _editWantsRestore;
|
||||
bool _editWantsRestorePrevious;
|
||||
@@ -102,7 +101,6 @@ struct DocumentP
|
||||
ViewProviderDocumentObject* _editViewProviderParent;
|
||||
std::string _editSubname;
|
||||
std::string _editSubElement;
|
||||
std::string _workbenchName; // Name of the workbench acting on this document
|
||||
Base::Matrix4D _editingTransform;
|
||||
View3DInventorViewer* _editingViewer;
|
||||
std::set<const App::DocumentObject*> _editObjs;
|
||||
@@ -286,8 +284,6 @@ struct DocumentP
|
||||
{
|
||||
_editingObject = sobj;
|
||||
_editMode = ModNum;
|
||||
_editViewProvider = svp; // Used to resolve start editing (find the document in edit from
|
||||
// within the viewprovider)
|
||||
_editViewProvider = svp->startEditing(ModNum);
|
||||
if (!_editViewProvider) {
|
||||
_editViewProviderParent = nullptr;
|
||||
@@ -317,7 +313,7 @@ struct DocumentP
|
||||
|
||||
void setDocumentNameOfTaskDialog(App::Document* doc)
|
||||
{
|
||||
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(_pcDocument);
|
||||
Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
|
||||
if (dlg) {
|
||||
dlg->setDocumentName(doc->getName());
|
||||
}
|
||||
@@ -436,7 +432,6 @@ Document::Document(App::Document* pcDocument, Application* app)
|
||||
d->_isClosing = false;
|
||||
d->_isModified = false;
|
||||
d->_isTransacting = false;
|
||||
d->_isActive = false;
|
||||
d->_pcAppWnd = app;
|
||||
d->_pcDocument = pcDocument;
|
||||
d->_editViewProvider = nullptr;
|
||||
@@ -695,6 +690,7 @@ bool Document::trySetEdit(Gui::ViewProvider* p, int ModNum, const char* subname)
|
||||
d->setEditingViewerIfPossible(view3d, ModNum);
|
||||
d->signalEditMode();
|
||||
|
||||
App::AutoTransaction::setEnable(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -721,7 +717,7 @@ void Document::resetEdit()
|
||||
Gui::ViewProvider* vpToRestore = d->_editViewProviderPrevious;
|
||||
bool shouldRestorePrevious = d->_editWantsRestorePrevious;
|
||||
|
||||
Application::Instance->unsetEditDocument(this);
|
||||
Application::Instance->setEditDocument(nullptr);
|
||||
|
||||
if (vpIsNotNull && vpHasChanged && shouldRestorePrevious) {
|
||||
setEdit(vpToRestore, modeToRestore);
|
||||
@@ -759,16 +755,18 @@ void Document::_resetEdit()
|
||||
|
||||
// The logic below is not necessary anymore, because this method is
|
||||
// changed into a private one, _resetEdit(). And the exposed
|
||||
// resetEdit() above calls into Application->unsetEditDocument() which
|
||||
// resetEdit() above calls into Application->setEditDocument(0) which
|
||||
// will prevent recursive calling.
|
||||
|
||||
App::GetApplication().commitTransaction(getDocument()->getBookedTransactionID());
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
d->_editViewProviderParent = nullptr;
|
||||
d->_editingViewer = nullptr;
|
||||
d->_editObjs.clear();
|
||||
d->_editingObject = nullptr;
|
||||
Application::Instance->unsetEditDocument(this);
|
||||
if (Application::Instance->editDocument() == this) {
|
||||
Application::Instance->setEditDocument(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ViewProvider* Document::getInEdit(
|
||||
@@ -801,10 +799,6 @@ ViewProvider* Document::getInEdit(
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
ViewProvider* Document::getEditViewProvider() const
|
||||
{
|
||||
return d->_editViewProvider;
|
||||
}
|
||||
|
||||
void Document::setInEdit(ViewProviderDocumentObject* parentVp, const char* subname)
|
||||
{
|
||||
@@ -1074,11 +1068,12 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
if (d->_editViewProvider == viewProvider || d->_editViewProviderParent == viewProvider) {
|
||||
_resetEdit();
|
||||
}
|
||||
else {
|
||||
Application::Instance->unsetEditDocumentIf([&viewProvider](Gui::Document* editdoc) {
|
||||
return editdoc->d->_editViewProvider == viewProvider
|
||||
|| editdoc->d->_editViewProviderParent == viewProvider;
|
||||
});
|
||||
else if (Application::Instance->editDocument()) {
|
||||
auto editDoc = Application::Instance->editDocument();
|
||||
if (editDoc->d->_editViewProvider == viewProvider
|
||||
|| editDoc->d->_editViewProviderParent == viewProvider) {
|
||||
Application::Instance->setEditDocument(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
handleChildren3D(viewProvider, true);
|
||||
@@ -1101,13 +1096,15 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj)
|
||||
|
||||
void Document::beforeDelete()
|
||||
{
|
||||
Application::Instance->unsetEditDocumentIf([this](Gui::Document* editDoc) {
|
||||
auto editDoc = Application::Instance->editDocument();
|
||||
if (editDoc) {
|
||||
auto vp = freecad_cast<ViewProviderDocumentObject*>(editDoc->d->_editViewProvider);
|
||||
auto vpp = freecad_cast<ViewProviderDocumentObject*>(editDoc->d->_editViewProviderParent);
|
||||
|
||||
return editDoc == this || (vp && vp->getDocument() == this)
|
||||
|| (vpp && vpp->getDocument() == this);
|
||||
});
|
||||
if (editDoc == this || (vp && vp->getDocument() == this)
|
||||
|| (vpp && vpp->getDocument() == this)) {
|
||||
Application::Instance->setEditDocument(nullptr);
|
||||
}
|
||||
}
|
||||
for (auto& v : d->_ViewProviderMap) {
|
||||
v.second->beforeDelete();
|
||||
}
|
||||
@@ -1254,18 +1251,6 @@ void Document::slotSkipRecompute(const App::Document& doc, const std::vector<App
|
||||
return;
|
||||
}
|
||||
App::DocumentObject* obj = nullptr;
|
||||
|
||||
if (Gui::Application::Instance->isInEdit(this)) {
|
||||
auto vp = freecad_cast<ViewProviderDocumentObject*>(getInEdit());
|
||||
if (vp) {
|
||||
obj = vp->getObject();
|
||||
}
|
||||
}
|
||||
if (objs.size() > 1 || App::GetApplication().getActiveDocument() != &doc
|
||||
|| !doc.testStatus(App::Document::AllowPartialRecompute)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto editDoc = Application::Instance->editDocument();
|
||||
if (editDoc) {
|
||||
auto vp = freecad_cast<ViewProviderDocumentObject*>(editDoc->getInEdit());
|
||||
@@ -1344,14 +1329,6 @@ bool Document::isModified() const
|
||||
{
|
||||
return d->_isModified;
|
||||
}
|
||||
void Document::setWorkbench(const std::string& name)
|
||||
{
|
||||
d->_workbenchName = name;
|
||||
}
|
||||
std::string Document::workbench() const
|
||||
{
|
||||
return d->_workbenchName;
|
||||
}
|
||||
|
||||
bool Document::isAboutToClose() const
|
||||
{
|
||||
@@ -1422,17 +1399,6 @@ App::Document* Document::getDocument() const
|
||||
{
|
||||
return d->_pcDocument;
|
||||
}
|
||||
void Document::setIsActive(bool active)
|
||||
{
|
||||
d->_isActive = active;
|
||||
if (d->_editViewProvider) {
|
||||
d->_editViewProvider->setActive(active);
|
||||
}
|
||||
}
|
||||
bool Document::isActive() const
|
||||
{
|
||||
return d->_isActive;
|
||||
}
|
||||
|
||||
static bool checkCanonicalPath(const std::map<App::Document*, bool>& docs)
|
||||
{
|
||||
@@ -1602,7 +1568,7 @@ bool Document::save()
|
||||
for (auto doc : docs) {
|
||||
// Changed 'mustExecute' status may be triggered by saving external document
|
||||
if (!dmap[doc] && doc->mustExecute()) {
|
||||
App::AutoTransaction trans(doc, "Recompute");
|
||||
App::AutoTransaction trans("Recompute");
|
||||
Command::doCommand(
|
||||
Command::Doc,
|
||||
"App.getDocument(\"%s\").recompute()",
|
||||
@@ -1745,7 +1711,7 @@ void Document::saveAll()
|
||||
try {
|
||||
// Changed 'mustExecute' status may be triggered by saving external document
|
||||
if (!dmap[doc] && doc->mustExecute()) {
|
||||
App::AutoTransaction trans(doc, "Recompute");
|
||||
App::AutoTransaction trans("Recompute");
|
||||
Command::doCommand(Command::Doc, "App.getDocument('%s').recompute()", doc->getName());
|
||||
}
|
||||
Command::doCommand(Command::Doc, "App.getDocument('%s').save()", doc->getName());
|
||||
@@ -2510,8 +2476,8 @@ bool Document::canClose(bool checkModify, bool checkLink)
|
||||
// If a task dialog is open that doesn't allow other commands to modify
|
||||
// the document it must be closed by resetting the edit mode of the
|
||||
// corresponding view provider.
|
||||
if (!Gui::Control().isAllowedAlterDocument(getDocument())) {
|
||||
std::string name = Gui::Control().activeDialog(getDocument())->getDocumentName();
|
||||
if (!Gui::Control().isAllowedAlterDocument()) {
|
||||
std::string name = Gui::Control().activeDialog()->getDocumentName();
|
||||
if (name == this->getDocument()->getName()) {
|
||||
// getInEdit() only checks if the currently active MDI view is
|
||||
// a 3D view and that it is in edit mode. However, when closing a
|
||||
@@ -2767,9 +2733,9 @@ Gui::MDIView* Document::getEditingViewOfViewProvider(Gui::ViewProvider* vp) cons
|
||||
* operation default is the command name.
|
||||
* @see CommitCommand(),AbortCommand()
|
||||
*/
|
||||
int Document::openCommand(const char* sName)
|
||||
void Document::openCommand(const char* sName)
|
||||
{
|
||||
return getDocument()->openTransaction(App::TransactionName {.name = sName, .temporary = false});
|
||||
getDocument()->openTransaction(sName);
|
||||
}
|
||||
|
||||
void Document::commitCommand()
|
||||
|
||||
+1
-12
@@ -191,21 +191,12 @@ public:
|
||||
void setModified(bool);
|
||||
bool isModified() const;
|
||||
|
||||
/// getter-setter for workbench name
|
||||
void setWorkbench(const std::string& name);
|
||||
std::string workbench() const;
|
||||
|
||||
/// Returns true if the document is about to be closed, false otherwise
|
||||
bool isAboutToClose() const;
|
||||
|
||||
/// Getter for the App Document
|
||||
App::Document* getDocument() const;
|
||||
|
||||
/// Notify the document when it becomes
|
||||
/// the active document/stops being the active document
|
||||
void setIsActive(bool active);
|
||||
bool isActive() const;
|
||||
|
||||
/** @name methods for View handling */
|
||||
//@{
|
||||
/// Getter for the active view
|
||||
@@ -296,8 +287,6 @@ public:
|
||||
int* mode = nullptr,
|
||||
std::string* subElement = nullptr
|
||||
) const;
|
||||
ViewProvider* getEditViewProvider() const; // Returns the _editViewProvider even if it is not
|
||||
// in edit at the moment
|
||||
/// set the in edit ViewProvider subname reference
|
||||
void setInEdit(ViewProviderDocumentObject* parentVp, const char* subname);
|
||||
/** Add or remove view provider from scene graphs of all views
|
||||
@@ -311,7 +300,7 @@ public:
|
||||
/** @name methods for the UNDO REDO handling */
|
||||
//@{
|
||||
/// Open a new Undo transaction on the document
|
||||
int openCommand(const char* sName = nullptr);
|
||||
void openCommand(const char* sName = nullptr);
|
||||
/// Commit the Undo transaction on the document
|
||||
void commitCommand();
|
||||
/// Abort the Undo transaction on the document
|
||||
|
||||
@@ -187,31 +187,6 @@ class Document(Persistence):
|
||||
obj : Gui.ViewProvider
|
||||
"""
|
||||
...
|
||||
|
||||
def openCommand(self, name: str) -> int:
|
||||
"""
|
||||
openCommand(name) -> int
|
||||
|
||||
Opens a named transaction for the document and returns it's
|
||||
id or 0 on failure
|
||||
"""
|
||||
...
|
||||
|
||||
def commitCommand(self) -> None:
|
||||
"""
|
||||
commitCommand() -> None
|
||||
|
||||
Commits the current transaction of the document
|
||||
"""
|
||||
...
|
||||
|
||||
def abortCommand(self) -> None:
|
||||
"""
|
||||
abortCommand() -> None
|
||||
|
||||
Aborts the current transaction of the document
|
||||
"""
|
||||
...
|
||||
ActiveObject: Any = ...
|
||||
"""The active object of the document."""
|
||||
|
||||
|
||||
@@ -577,34 +577,6 @@ Py::Long DocumentPy::getEditMode() const
|
||||
return Py::Long(mode);
|
||||
}
|
||||
|
||||
PyObject* DocumentPy::openCommand(PyObject* arg, PyObject* kwd)
|
||||
{
|
||||
const char* name = nullptr;
|
||||
if (!PyArg_ParseTuple(arg, "s", &name)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
int tid = getDocumentPtr()->openCommand(name);
|
||||
|
||||
return Py::new_reference_to(Py::Long(tid));
|
||||
}
|
||||
PyObject* DocumentPy::commitCommand(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
getDocumentPtr()->commitCommand();
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
PyObject* DocumentPy::abortCommand(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
getDocumentPtr()->abortCommand();
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
Py::Boolean DocumentPy::getTransacting() const
|
||||
{
|
||||
return {getDocumentPtr()->isPerformingTransaction()};
|
||||
|
||||
@@ -75,11 +75,11 @@ void Gui::ExpressionBinding::setExpression(std::shared_ptr<Expression> expr)
|
||||
|
||||
lastExpression = getExpression();
|
||||
|
||||
bool transaction = docObj->getDocument()->getBookedTransactionID() == 0;
|
||||
bool transaction = !App::GetApplication().getActiveTransaction();
|
||||
if (transaction) {
|
||||
std::ostringstream ss;
|
||||
ss << (expr ? "Set" : "Discard") << " expression " << docObj->Label.getValue();
|
||||
docObj->getDocument()->openTransaction(ss.str().c_str());
|
||||
App::GetApplication().setActiveTransaction(ss.str().c_str());
|
||||
}
|
||||
|
||||
docObj->ExpressionEngine.setValue(path, expr);
|
||||
@@ -89,7 +89,7 @@ void Gui::ExpressionBinding::setExpression(std::shared_ptr<Expression> expr)
|
||||
}
|
||||
|
||||
if (transaction) {
|
||||
docObj->getDocument()->commitTransaction();
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ void ExpressionBinding::bind(const App::ObjectIdentifier& _path)
|
||||
{
|
||||
const Property* prop = _path.getProperty();
|
||||
|
||||
Q_ASSERT(prop);
|
||||
Q_ASSERT(prop != nullptr);
|
||||
|
||||
path = prop->canonicalPath(_path);
|
||||
|
||||
@@ -133,7 +133,7 @@ std::shared_ptr<App::Expression> ExpressionBinding::getExpression() const
|
||||
{
|
||||
DocumentObject* docObj = path.getDocumentObject();
|
||||
|
||||
Q_ASSERT(isBound() && docObj);
|
||||
Q_ASSERT(isBound() && docObj != nullptr);
|
||||
|
||||
return docObj->getExpression(path).expression;
|
||||
}
|
||||
@@ -214,11 +214,11 @@ bool ExpressionBinding::apply(const std::string& propName)
|
||||
throw Base::RuntimeError("Document object not found.");
|
||||
}
|
||||
|
||||
bool transaction = docObj->getDocument()->getBookedTransactionID() == 0;
|
||||
bool transaction = !App::GetApplication().getActiveTransaction();
|
||||
if (transaction) {
|
||||
std::ostringstream ss;
|
||||
ss << "Set expression " << docObj->Label.getValue();
|
||||
docObj->getDocument()->openTransaction(ss.str().c_str());
|
||||
App::GetApplication().setActiveTransaction(ss.str().c_str());
|
||||
}
|
||||
Gui::Command::doCommand(
|
||||
Gui::Command::Doc,
|
||||
@@ -229,7 +229,7 @@ bool ExpressionBinding::apply(const std::string& propName)
|
||||
getEscapedExpressionString().c_str()
|
||||
);
|
||||
if (transaction) {
|
||||
docObj->getDocument()->commitTransaction();
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -242,11 +242,11 @@ bool ExpressionBinding::apply(const std::string& propName)
|
||||
}
|
||||
|
||||
if (lastExpression) {
|
||||
bool transaction = docObj->getDocument()->getBookedTransactionID() == 0;
|
||||
bool transaction = !App::GetApplication().getActiveTransaction();
|
||||
if (transaction) {
|
||||
std::ostringstream ss;
|
||||
ss << "Discard expression " << docObj->Label.getValue();
|
||||
docObj->getDocument()->openTransaction(ss.str().c_str());
|
||||
App::GetApplication().setActiveTransaction(ss.str().c_str());
|
||||
}
|
||||
Gui::Command::doCommand(
|
||||
Gui::Command::Doc,
|
||||
@@ -256,7 +256,7 @@ bool ExpressionBinding::apply(const std::string& propName)
|
||||
path.toEscapedString().c_str()
|
||||
);
|
||||
if (transaction) {
|
||||
docObj->getDocument()->commitTransaction();
|
||||
App::GetApplication().closeActiveTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,10 +430,8 @@ def GeneratePackageIcon(
|
||||
return
|
||||
absolute_filename = Path(subdirectory) / Path(relative_filename)
|
||||
if hasattr(wb_handle, "Icon") and wb_handle.Icon:
|
||||
Log(
|
||||
f"Init: Packaged workbench {workbench_metadata.Name} specified icon\
|
||||
in class {workbench_metadata.Classname}"
|
||||
)
|
||||
Log(f"Init: Packaged workbench {workbench_metadata.Name} specified icon\
|
||||
in class {workbench_metadata.Classname}")
|
||||
Log(" ... replacing with icon from package.xml data.\n")
|
||||
wb_handle.__dict__["Icon"] = str(absolute_filename.resolve())
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ public:
|
||||
void setUserSchema(int userSchema)
|
||||
{
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
if (doc) {
|
||||
if (doc != nullptr) {
|
||||
if (doc->UnitSystem.getValue() != userSchema) {
|
||||
doc->UnitSystem.setValue(userSchema);
|
||||
}
|
||||
@@ -275,7 +275,7 @@ private:
|
||||
bool ignore = hGrpu->GetBool("IgnoreProjectSchema", false);
|
||||
App::Document* doc = App::GetApplication().getActiveDocument();
|
||||
int userSchema = getWindowParameter()->GetInt("UserSchema", 0);
|
||||
if (doc && !ignore) {
|
||||
if (doc != nullptr && !ignore) {
|
||||
userSchema = doc->UnitSystem.getValue();
|
||||
}
|
||||
auto actions = menu()->actions();
|
||||
@@ -937,7 +937,7 @@ int MainWindow::confirmSave(App::Document* doc, QWidget* parent, bool addCheckbo
|
||||
const QList<QWidget*> listOfMDIs = this->windows();
|
||||
for (QWidget* widget : listOfMDIs) {
|
||||
auto mdiView = qobject_cast<MDIView*>(widget);
|
||||
if (mdiView && mdiView->getAppDocument() == doc) {
|
||||
if (mdiView != nullptr && mdiView->getAppDocument() == doc) {
|
||||
this->setActiveWindow(mdiView);
|
||||
}
|
||||
}
|
||||
@@ -974,7 +974,7 @@ bool MainWindow::closeAllDocuments(bool close)
|
||||
// moves the active document to the front
|
||||
MDIView* activeView = this->activeWindow();
|
||||
App::Document* activeDoc = (activeView ? activeView->getAppDocument() : nullptr);
|
||||
if (activeDoc) {
|
||||
if (activeDoc != nullptr) {
|
||||
for (auto it = ++docs.begin(); it != docs.end(); it++) {
|
||||
if (*it == activeDoc) {
|
||||
docs.erase(it);
|
||||
|
||||
@@ -1360,8 +1360,9 @@ void ManualAlignment::probePickedCallback(void* ud, SoEventCallback* n)
|
||||
Gui::getMainWindow()->showMessage(tr("No point was picked"));
|
||||
}
|
||||
}
|
||||
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2
|
||||
&& mbe->getState() == SoButtonEvent::UP) {
|
||||
else if (
|
||||
mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP
|
||||
) {
|
||||
ManualAlignment* self = ManualAlignment::instance();
|
||||
if (self->myAlignModel.isEmpty() || self->myFixedGroup.isEmpty()) {
|
||||
return;
|
||||
|
||||
@@ -1220,7 +1220,7 @@ bool NaviCubeImplementation::mouseReleased(short x, short y)
|
||||
// If the previous flat button animation is still active then apply the rotation to the
|
||||
// previous target orientation, otherwise apply the rotation to the current camera
|
||||
// orientation
|
||||
if (m_flatButtonAnimation
|
||||
if (m_flatButtonAnimation != nullptr
|
||||
&& m_flatButtonAnimation->state() == QAbstractAnimation::Running) {
|
||||
m_flatButtonTargetOrientation = rotation * m_flatButtonTargetOrientation;
|
||||
}
|
||||
|
||||
@@ -123,9 +123,11 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
|
||||
processed = true;
|
||||
}
|
||||
else if (press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)) {
|
||||
else if (
|
||||
press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)
|
||||
) {
|
||||
newmode = NavigationStyle::DRAGGING;
|
||||
saveCursorPosition(ev);
|
||||
this->centerTime = ev->getTime();
|
||||
|
||||
@@ -120,9 +120,11 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
|
||||
processed = true;
|
||||
}
|
||||
else if (press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)) {
|
||||
else if (
|
||||
press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)
|
||||
) {
|
||||
newmode = NavigationStyle::DRAGGING;
|
||||
saveCursorPosition(ev);
|
||||
this->centerTime = ev->getTime();
|
||||
|
||||
@@ -710,7 +710,7 @@ public:
|
||||
: my_base(ctx)
|
||||
{
|
||||
auto& ns = this->outermost_context().ns;
|
||||
ns.setRotationCenter(ns.viewer->getFocalPoint());
|
||||
ns.setRotationCenter(ns.getFocalPoint());
|
||||
ns.setViewingMode(NavigationStyle::DRAGGING);
|
||||
this->base_pos
|
||||
= static_cast<const NS::Event*>(this->triggering_event())->inventor_event->getPosition();
|
||||
|
||||
@@ -129,8 +129,9 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
setupPanningPlane(getCamera());
|
||||
this->lockrecenter = false;
|
||||
}
|
||||
else if (!press && ev->wasShiftDown()
|
||||
&& (this->currentmode != NavigationStyle::SELECTION)) {
|
||||
else if (
|
||||
!press && ev->wasShiftDown() && (this->currentmode != NavigationStyle::SELECTION)
|
||||
) {
|
||||
SbTime tmp = (ev->getTime() - this->centerTime);
|
||||
float dci = (float)QApplication::doubleClickInterval() / 1000.0f;
|
||||
// is it just a left click?
|
||||
@@ -325,9 +326,11 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
if (ev->isOfType(SoMouseWheelEvent::getClassTypeId())) {
|
||||
processed = inherited::processSoEvent(ev);
|
||||
}
|
||||
else if ((curmode == NavigationStyle::SELECTION || newmode == NavigationStyle::SELECTION
|
||||
|| viewer->isEditing())
|
||||
&& !processed) {
|
||||
else if (
|
||||
(curmode == NavigationStyle::SELECTION || newmode == NavigationStyle::SELECTION
|
||||
|| viewer->isEditing())
|
||||
&& !processed
|
||||
) {
|
||||
processed = inherited::processSoEvent(ev);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -589,7 +589,7 @@ SbBool MayaGestureNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
if (comboAfter & BUTTON1DOWN || comboAfter & BUTTON2DOWN) {
|
||||
// don't leave navigation till all buttons have been released
|
||||
if (comboAfter & BUTTON1DOWN && comboAfter & BUTTON2DOWN) {
|
||||
setRotationCenter(viewer->getFocalPoint());
|
||||
setRotationCenter(getFocalPoint());
|
||||
}
|
||||
else {
|
||||
saveCursorPosition(ev);
|
||||
|
||||
@@ -96,7 +96,7 @@ void NavigationAnimator::stop()
|
||||
*/
|
||||
bool NavigationAnimator::isAnimating() const
|
||||
{
|
||||
if (activeAnimation) {
|
||||
if (activeAnimation != nullptr) {
|
||||
return activeAnimation->state() == QAbstractAnimation::State::Running;
|
||||
}
|
||||
|
||||
|
||||
@@ -504,7 +504,7 @@ void NavigationStyle::lookAtPoint(const SbVec2s screenpos)
|
||||
void NavigationStyle::lookAtPoint(const SbVec3f& position)
|
||||
{
|
||||
this->rotationCenterFound = false;
|
||||
translateCamera(position - viewer->getFocalPoint());
|
||||
translateCamera(position - getFocalPoint());
|
||||
}
|
||||
|
||||
SoCamera* NavigationStyle::getCamera() const
|
||||
@@ -524,7 +524,7 @@ std::shared_ptr<NavigationAnimation> NavigationStyle::setCameraOrientation(
|
||||
|
||||
animator->stop();
|
||||
|
||||
const SbVec3f focalPoint = viewer->getFocalPoint();
|
||||
const SbVec3f focalPoint = getFocalPoint();
|
||||
SbVec3f translation(0, 0, 0);
|
||||
|
||||
if (moveToCenter) {
|
||||
@@ -618,7 +618,6 @@ void NavigationStyle::boxZoom(const SbBox2s& box)
|
||||
|
||||
doScale(cam, scaleFactor);
|
||||
}
|
||||
|
||||
void NavigationStyle::scale(float factor)
|
||||
{
|
||||
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
|
||||
@@ -627,7 +626,9 @@ void NavigationStyle::scale(float factor)
|
||||
}
|
||||
|
||||
// Find the current center of the screen
|
||||
SbVec3f initCenter = viewer->getFocalPoint();
|
||||
SbVec3f direction;
|
||||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||||
SbVec3f initCenter = cam->position.getValue() + cam->focalDistance.getValue() * direction;
|
||||
|
||||
// Move the camera to the origin for scaling
|
||||
cam->position = cam->position.getValue() - initCenter;
|
||||
@@ -701,7 +702,7 @@ void NavigationStyle::findBoundingSphere()
|
||||
*/
|
||||
void NavigationStyle::reorientCamera(SoCamera* camera, const SbRotation& rotation)
|
||||
{
|
||||
reorientCamera(camera, rotation, viewer->getFocalPoint());
|
||||
reorientCamera(camera, rotation, getFocalPoint());
|
||||
}
|
||||
|
||||
/** Rotate the camera by the given amount, then reposition it so the rotation center stays in the
|
||||
@@ -750,7 +751,7 @@ void NavigationStyle::reorientCamera(
|
||||
#else
|
||||
constexpr float orthographicFocalDistance = 1;
|
||||
#endif
|
||||
camera->position = viewer->getFocalPoint() - orthographicFocalDistance * direction;
|
||||
camera->position = getFocalPoint() - orthographicFocalDistance * direction;
|
||||
camera->focalDistance = orthographicFocalDistance;
|
||||
}
|
||||
|
||||
@@ -1003,7 +1004,7 @@ void NavigationStyle::doZoom(SoCamera* camera, float logfactor, const SbVec2f& p
|
||||
// Change the position of the rotation center indicator after zooming at cursor
|
||||
// Rotation mode is WindowCenter
|
||||
if (!rotationCenterMode) {
|
||||
viewer->changeRotationCenterPosition(viewer->getFocalPoint());
|
||||
viewer->changeRotationCenterPosition(getFocalPoint());
|
||||
|
||||
#if (COIN_MAJOR_VERSION * 100 + COIN_MINOR_VERSION * 10 + COIN_MICRO_VERSION < 403)
|
||||
findBoundingSphere();
|
||||
@@ -1082,6 +1083,20 @@ void NavigationStyle::setRotationCenter(const SbVec3f& cnt)
|
||||
}
|
||||
}
|
||||
|
||||
SbVec3f NavigationStyle::getFocalPoint() const
|
||||
{
|
||||
SoCamera* cam = viewer->getSoRenderManager()->getCamera();
|
||||
if (!cam) {
|
||||
return {0, 0, 0};
|
||||
}
|
||||
|
||||
// Find global coordinates of focal point.
|
||||
SbVec3f direction;
|
||||
cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
|
||||
SbVec3f focal = cam->position.getValue() + cam->focalDistance.getValue() * direction;
|
||||
return focal;
|
||||
}
|
||||
|
||||
/** Uses the sphere sheet projector to map the mouse position onto
|
||||
* a 3D point and find a rotation from this and the last calculated point.
|
||||
*/
|
||||
@@ -1281,7 +1296,7 @@ void NavigationStyle::saveCursorPosition(const SoEvent* const ev)
|
||||
|
||||
// mode is WindowCenter
|
||||
if (!this->rotationCenterMode) {
|
||||
setRotationCenter(viewer->getFocalPoint());
|
||||
setRotationCenter(getFocalPoint());
|
||||
}
|
||||
|
||||
// Option to get point on model (slow) or always on focal plane (fast)
|
||||
|
||||
@@ -166,6 +166,7 @@ public:
|
||||
void setRotationCenterMode(RotationCenterModes);
|
||||
RotationCenterModes getRotationCenterMode() const;
|
||||
void setRotationCenter(const SbVec3f& cnt);
|
||||
SbVec3f getFocalPoint() const;
|
||||
|
||||
SoCamera* getCamera() const;
|
||||
std::shared_ptr<NavigationAnimation> setCameraOrientation(
|
||||
|
||||
@@ -125,9 +125,11 @@ SbBool RevitNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
|
||||
processed = true;
|
||||
}
|
||||
else if (press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)) {
|
||||
else if (
|
||||
press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)
|
||||
) {
|
||||
newmode = NavigationStyle::DRAGGING;
|
||||
saveCursorPosition(ev);
|
||||
this->centerTime = ev->getTime();
|
||||
|
||||
@@ -123,9 +123,11 @@ SbBool SolidWorksNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
|
||||
processed = true;
|
||||
}
|
||||
else if (press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)) {
|
||||
else if (
|
||||
press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)
|
||||
) {
|
||||
newmode = NavigationStyle::DRAGGING;
|
||||
saveCursorPosition(ev);
|
||||
this->centerTime = ev->getTime();
|
||||
|
||||
@@ -122,9 +122,11 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent* const ev)
|
||||
this->seekToPoint(pos); // implicitly calls interactiveCountInc()
|
||||
processed = true;
|
||||
}
|
||||
else if (press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)) {
|
||||
else if (
|
||||
press
|
||||
&& (this->currentmode == NavigationStyle::PANNING
|
||||
|| this->currentmode == NavigationStyle::ZOOMING)
|
||||
) {
|
||||
newmode = NavigationStyle::DRAGGING;
|
||||
saveCursorPosition(ev);
|
||||
this->centerTime = ev->getTime();
|
||||
|
||||
+42
-36
@@ -183,36 +183,38 @@ inline void Gui::Notify(TNotifier&& notifier, TCaption&& caption, TMessage&& mes
|
||||
// Send also to log for developer only
|
||||
auto msg = std::string(message).append("\n"); // use untranslated message
|
||||
|
||||
if constexpr (std::is_base_of_v<
|
||||
App::DocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
if constexpr (
|
||||
std::is_base_of_v<App::DocumentObject, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console()
|
||||
.send<type, Base::IntendedRecipient::Developer, Base::ContentType::Untranslated>(
|
||||
notifier->getFullLabel(),
|
||||
msg.c_str()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console()
|
||||
.send<type, Base::IntendedRecipient::Developer, Base::ContentType::Untranslated>(
|
||||
notifier->getObject()->getFullLabel(),
|
||||
msg.c_str()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<Gui::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console()
|
||||
.send<type, Base::IntendedRecipient::Developer, Base::ContentType::Untranslated>(
|
||||
notifier->getDocument()->Label.getStrValue(),
|
||||
msg.c_str()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
App::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<App::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console()
|
||||
.send<type, Base::IntendedRecipient::Developer, Base::ContentType::Untranslated>(
|
||||
notifier->Label.getStrValue(),
|
||||
@@ -269,30 +271,32 @@ inline void Gui::Notify(TNotifier&& notifier, TCaption&& caption, TMessage&& mes
|
||||
// trailing newline is not necessary as translated messages are not shown in logs
|
||||
auto msg = QStringLiteral("%1. %2").arg(caption).arg(message); // QString
|
||||
|
||||
if constexpr (std::is_base_of_v<
|
||||
App::DocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
if constexpr (
|
||||
std::is_base_of_v<App::DocumentObject, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(notifier->getFullLabel(), msg.toUtf8());
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->getObject()->getFullLabel(),
|
||||
msg.toUtf8()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<Gui::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->getDocument()->Label.getStrValue(),
|
||||
msg.toUtf8()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
App::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<App::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->Label.getStrValue(),
|
||||
msg.toUtf8()
|
||||
@@ -307,30 +311,32 @@ inline void Gui::Notify(TNotifier&& notifier, TCaption&& caption, TMessage&& mes
|
||||
// (depending on the configuration).
|
||||
auto msg = std::string(message).append("\n");
|
||||
|
||||
if constexpr (std::is_base_of_v<
|
||||
App::DocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
if constexpr (
|
||||
std::is_base_of_v<App::DocumentObject, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(notifier->getFullLabel(), msg.c_str());
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<
|
||||
Gui::ViewProviderDocumentObject,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->getObject()->getFullLabel(),
|
||||
msg.c_str()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
Gui::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<Gui::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->getDocument()->Label.getStrValue(),
|
||||
msg.c_str()
|
||||
);
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<
|
||||
App::Document,
|
||||
std::remove_pointer_t<typename std::decay<TNotifier>::type>>) {
|
||||
else if constexpr (
|
||||
std::is_base_of_v<App::Document, std::remove_pointer_t<typename std::decay<TNotifier>::type>>
|
||||
) {
|
||||
Base::Console().send<type, recipient, content>(
|
||||
notifier->Label.getStrValue(),
|
||||
msg.c_str()
|
||||
|
||||
@@ -1807,8 +1807,10 @@ bool OverlayManager::eventFilter(QObject* o, QEvent* ev)
|
||||
if (auto titleBar = qobject_cast<OverlayTitleBar*>(OverlayTabWidget::_Dragging)) {
|
||||
titleBar->endDrag();
|
||||
}
|
||||
else if (auto splitHandle
|
||||
= qobject_cast<OverlaySplitterHandle*>(OverlayTabWidget::_Dragging)) {
|
||||
else if (
|
||||
auto splitHandle
|
||||
= qobject_cast<OverlaySplitterHandle*>(OverlayTabWidget::_Dragging)
|
||||
) {
|
||||
splitHandle->endDrag();
|
||||
}
|
||||
}
|
||||
@@ -1861,8 +1863,9 @@ bool OverlayManager::eventFilter(QObject* o, QEvent* ev)
|
||||
if (auto titleBar = qobject_cast<OverlayTitleBar*>(OverlayTabWidget::_Dragging)) {
|
||||
titleBar->endDrag();
|
||||
}
|
||||
else if (auto splitHandle
|
||||
= qobject_cast<OverlaySplitterHandle*>(OverlayTabWidget::_Dragging)) {
|
||||
else if (
|
||||
auto splitHandle = qobject_cast<OverlaySplitterHandle*>(OverlayTabWidget::_Dragging)
|
||||
) {
|
||||
splitHandle->endDrag();
|
||||
}
|
||||
}
|
||||
@@ -1909,8 +1912,10 @@ bool OverlayManager::eventFilter(QObject* o, QEvent* ev)
|
||||
// probably do not matter.
|
||||
return true;
|
||||
}
|
||||
else if (ev->type() != QEvent::MouseButtonPress && ev->type() != QEvent::MouseButtonDblClick
|
||||
&& QApplication::mouseButtons() != Qt::NoButton) {
|
||||
else if (
|
||||
ev->type() != QEvent::MouseButtonPress && ev->type() != QEvent::MouseButtonDblClick
|
||||
&& QApplication::mouseButtons() != Qt::NoButton
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1925,8 +1930,10 @@ bool OverlayManager::eventFilter(QObject* o, QEvent* ev)
|
||||
&& pos == d->_lastPos) {
|
||||
hit = 1;
|
||||
}
|
||||
else if (ev->type() == QEvent::Wheel && !d->wheelDelay.isNull()
|
||||
&& (isNear(pos, d->wheelPos) || d->wheelDelay > QTime::currentTime())) {
|
||||
else if (
|
||||
ev->type() == QEvent::Wheel && !d->wheelDelay.isNull()
|
||||
&& (isNear(pos, d->wheelPos) || d->wheelDelay > QTime::currentTime())
|
||||
) {
|
||||
d->wheelDelay = QTime::currentTime().addMSecs(
|
||||
OverlayParams::getDockOverlayWheelDelay()
|
||||
);
|
||||
|
||||
+13
-24
@@ -19,6 +19,7 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Auto code generator for overlay widgets related parameters in Preferences/View"""
|
||||
|
||||
import cog
|
||||
import inspect, sys
|
||||
from os import path
|
||||
@@ -101,12 +102,10 @@ class ParamAnimationCurve(ParamProxy):
|
||||
|
||||
def init_widget(self, param, row, group_name):
|
||||
super().init_widget(param, row, group_name)
|
||||
cog.out(
|
||||
f"""
|
||||
cog.out(f"""
|
||||
{auto_comment()}
|
||||
for (const auto &item : OverlayParams::AnimationCurveTypes)
|
||||
{param.widget_name}->addItem(item);"""
|
||||
)
|
||||
{param.widget_name}->addItem(item);""")
|
||||
cog.out(
|
||||
f"""
|
||||
{param.widget_name}->setCurrentIndex({param.namespace}::{param.class_name}::default{param.name}());"""
|
||||
@@ -295,40 +294,30 @@ Params = [
|
||||
|
||||
|
||||
def declare():
|
||||
cog.out(
|
||||
f"""
|
||||
cog.out(f"""
|
||||
{auto_comment()}
|
||||
#include <QString>
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
params_utils.declare_begin(sys.modules[__name__])
|
||||
cog.out(
|
||||
f"""
|
||||
cog.out(f"""
|
||||
{auto_comment()}
|
||||
static const std::vector<QString> AnimationCurveTypes;
|
||||
"""
|
||||
)
|
||||
""")
|
||||
params_utils.declare_end(sys.modules[__name__])
|
||||
|
||||
|
||||
def define():
|
||||
params_utils.define(sys.modules[__name__])
|
||||
cog.out(
|
||||
f"""
|
||||
cog.out(f"""
|
||||
{auto_comment()}
|
||||
const std::vector<QString> OverlayParams::AnimationCurveTypes = {{"""
|
||||
)
|
||||
const std::vector<QString> OverlayParams::AnimationCurveTypes = {{""")
|
||||
for item in AnimationCurveTypes:
|
||||
cog.out(
|
||||
f"""
|
||||
QStringLiteral("{item}"),"""
|
||||
)
|
||||
cog.out(
|
||||
f"""
|
||||
cog.out(f"""
|
||||
QStringLiteral("{item}"),""")
|
||||
cog.out(f"""
|
||||
}};
|
||||
"""
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
params_utils.init_params(Params, NameSpace, ClassName, ParamPath)
|
||||
|
||||
@@ -1244,16 +1244,16 @@ bool OverlayTabWidget::checkAutoHide() const
|
||||
}
|
||||
}
|
||||
|
||||
bool activeDocInEdit = Application::Instance->isInEdit(Application::Instance->activeDocument());
|
||||
if (autoMode == AutoMode::EditShow) {
|
||||
return !activeDocInEdit && (!Control().taskPanel() || Control().taskPanel()->isEmpty(false));
|
||||
return !Application::Instance->editDocument()
|
||||
&& (!Control().taskPanel() || Control().taskPanel()->isEmpty(false));
|
||||
}
|
||||
|
||||
if (autoMode == AutoMode::TaskShow) {
|
||||
return (!Control().taskPanel() || Control().taskPanel()->isEmpty());
|
||||
}
|
||||
|
||||
if (autoMode == AutoMode::EditHide && activeDocInEdit) {
|
||||
if (autoMode == AutoMode::EditHide && Application::Instance->editDocument()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1549,8 +1549,10 @@ void OverlayTabWidget::setOverlayMode(bool enable)
|
||||
if (!enable && isTransparent()) {
|
||||
option = OverlayOption::ShowTab;
|
||||
}
|
||||
else if (enable && !isTransparent()
|
||||
&& (autoMode == AutoMode::EditShow || autoMode == AutoMode::AutoHide)) {
|
||||
else if (
|
||||
enable && !isTransparent()
|
||||
&& (autoMode == AutoMode::EditShow || autoMode == AutoMode::AutoHide)
|
||||
) {
|
||||
option = OverlayOption::Disable;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -548,8 +548,10 @@ static void copyTemplateParameters(
|
||||
}
|
||||
}
|
||||
|
||||
static void copyTemplateParameters(/*const*/ ParameterManager& templateParameterManager,
|
||||
ParameterManager& outputParameterManager)
|
||||
static void copyTemplateParameters(
|
||||
/*const*/ ParameterManager& templateParameterManager,
|
||||
ParameterManager& outputParameterManager
|
||||
)
|
||||
{
|
||||
auto groups = templateParameterManager.GetGroups();
|
||||
for (auto& group : groups) {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
"""Auto code generator for preference page of Display/UI"""
|
||||
|
||||
import cog, sys
|
||||
from os import path
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ void DlgSettingsLightSources::resetSettingsToDefaults()
|
||||
|
||||
void DlgSettingsLightSources::zoomIn() const
|
||||
{
|
||||
if (!camera) {
|
||||
if (camera == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -360,7 +360,7 @@ void DlgSettingsLightSources::zoomIn() const
|
||||
|
||||
void DlgSettingsLightSources::zoomOut() const
|
||||
{
|
||||
if (!camera) {
|
||||
if (camera == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -585,8 +585,10 @@ void PythonConsole::keyPressEvent(QKeyEvent* e)
|
||||
|| e->matches(QKeySequence::SelectAll)) {
|
||||
PythonTextEditor::keyPressEvent(e);
|
||||
}
|
||||
else if (!e->text().isEmpty()
|
||||
&& (e->modifiers() == Qt::NoModifier || e->modifiers() == Qt::ShiftModifier)) {
|
||||
else if (
|
||||
!e->text().isEmpty()
|
||||
&& (e->modifiers() == Qt::NoModifier || e->modifiers() == Qt::ShiftModifier)
|
||||
) {
|
||||
this->moveCursor(QTextCursor::End);
|
||||
PythonTextEditor::keyPressEvent(e);
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ public:
|
||||
const auto PyW_uniqueName = QString::number(reinterpret_cast<quintptr>(pyobj));
|
||||
auto PyW_invalidator = findChild<QObject*>(PyW_uniqueName, Qt::FindDirectChildrenOnly);
|
||||
|
||||
if (!PyW_invalidator) {
|
||||
if (PyW_invalidator == nullptr) {
|
||||
PyW_invalidator = new QObject(this);
|
||||
PyW_invalidator->setObjectName(PyW_uniqueName);
|
||||
|
||||
@@ -420,7 +420,7 @@ public:
|
||||
auto destroyedFun = [pyobj]() {
|
||||
Base::PyGILStateLocker lock;
|
||||
|
||||
if (auto sbkPtr = reinterpret_cast<SbkObject*>(pyobj); sbkPtr) {
|
||||
if (auto sbkPtr = reinterpret_cast<SbkObject*>(pyobj); sbkPtr != nullptr) {
|
||||
Shiboken::Object::setValidCpp(sbkPtr, false);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -93,5 +93,10 @@ ActionGroup *ActionPanel::createGroup(const QPixmap &icon, const QString &title,
|
||||
return group;
|
||||
}
|
||||
|
||||
QSize ActionPanel::minimumSizeHint() const
|
||||
{
|
||||
return {200,150};
|
||||
}
|
||||
|
||||
} // namespace QSint
|
||||
|
||||
|
||||
@@ -89,6 +89,12 @@ public:
|
||||
*/
|
||||
void setScheme(ActionPanelScheme *scheme);
|
||||
|
||||
/**
|
||||
* @brief Returns the recommended minimum size for the panel.
|
||||
* @return The minimum size hint.
|
||||
*/
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
protected:
|
||||
/** @brief The color scheme used by the panel. */
|
||||
ActionPanelScheme *myScheme;
|
||||
|
||||
+359
-485
File diff suppressed because it is too large
Load Diff
@@ -225,7 +225,7 @@ class GuiExport SelectionObserver
|
||||
public:
|
||||
/** Constructor
|
||||
*
|
||||
* @param attach: whether to attach this observer on construction
|
||||
* @param attach: whether to attach this observer on construction
|
||||
* @param resolve: sub-object resolving mode.
|
||||
*/
|
||||
explicit SelectionObserver(bool attach = true, ResolveMode resolve = ResolveMode::OldStyleElement);
|
||||
@@ -264,7 +264,6 @@ private:
|
||||
std::string filterDocName;
|
||||
std::string filterObjName;
|
||||
ResolveMode resolve;
|
||||
const char* pDocumentScopeName {nullptr};
|
||||
bool blockedSelection;
|
||||
};
|
||||
|
||||
@@ -287,6 +286,20 @@ public:
|
||||
std::string notAllowedReason;
|
||||
};
|
||||
|
||||
/** SelectionGateFilterExternal
|
||||
* The selection gate disallows any external object
|
||||
*/
|
||||
class GuiExport SelectionGateFilterExternal: public SelectionGate
|
||||
{
|
||||
public:
|
||||
explicit SelectionGateFilterExternal(const char* docName, const char* objName = nullptr);
|
||||
bool allow(App::Document*, App::DocumentObject*, const char*) override;
|
||||
|
||||
private:
|
||||
std::string DocName;
|
||||
std::string ObjName;
|
||||
};
|
||||
|
||||
/** The Selection class
|
||||
* The selection singleton keeps track of the selection state of
|
||||
* the whole application. It gets messages from all entities which can
|
||||
@@ -369,7 +382,7 @@ public:
|
||||
/// of the active document is cleared.
|
||||
void clearSelection(const char* pDocName = nullptr, bool clearPreSelect = true);
|
||||
/// Clear the selection of all documents
|
||||
void clearCompleteSelection(const char* pDocName = nullptr, bool clearPreSelect = true);
|
||||
void clearCompleteSelection(bool clearPreSelect = true);
|
||||
/// Check if selected
|
||||
bool isSelected(
|
||||
const char* pDocName,
|
||||
@@ -384,7 +397,7 @@ public:
|
||||
ResolveMode resolve = ResolveMode::OldStyleElement
|
||||
) const;
|
||||
|
||||
std::string getSelectedElement(App::DocumentObject*, const char* pSubName) const;
|
||||
const char* getSelectedElement(App::DocumentObject*, const char* pSubName) const;
|
||||
|
||||
/// set the preselected object (mostly by the 3D view)
|
||||
int setPreselect(
|
||||
@@ -402,19 +415,10 @@ public:
|
||||
void setPreselectCoord(float x, float y, float z);
|
||||
/// returns the present preselection
|
||||
const SelectionChanges& getPreselection() const;
|
||||
/// add a SelectionGate to control what is selectable in a document's scope, by default the
|
||||
/// active document is selected
|
||||
// which is usually the intended behavior
|
||||
void addSelectionGate(
|
||||
Gui::SelectionGate* gate,
|
||||
ResolveMode resolve = ResolveMode::OldStyleElement,
|
||||
const char* pDocName = nullptr
|
||||
);
|
||||
/// remove the document's SelectionGate, by default the active document is selected, which is
|
||||
/// usually the intended behavior
|
||||
void rmvSelectionGate(const char* pDocName = nullptr);
|
||||
/// remove the document's SelectionGate (assumes valid pointer)
|
||||
void rmvSelectionGate(App::Document* doc);
|
||||
/// add a SelectionGate to control what is selectable
|
||||
void addSelectionGate(Gui::SelectionGate* gate, ResolveMode resolve = ResolveMode::OldStyleElement);
|
||||
/// remove the active SelectionGate
|
||||
void rmvSelectionGate();
|
||||
|
||||
int disableCommandLog();
|
||||
int enableCommandLog(bool silent = false);
|
||||
@@ -491,9 +495,8 @@ public:
|
||||
/** Set selection object visibility
|
||||
*
|
||||
* @param visible: see VisibleState
|
||||
* @param pDocName: name of the document that scopes the request, defaults to active document
|
||||
*/
|
||||
void setVisible(VisibleState visible, const char* pDocName = nullptr);
|
||||
void setVisible(VisibleState visible);
|
||||
|
||||
bool isClarifySelectionActive();
|
||||
void setClarifySelectionActive(bool active);
|
||||
@@ -577,7 +580,7 @@ public:
|
||||
std::vector<SelObj> getCompleteSelection(ResolveMode resolve = ResolveMode::OldStyleElement) const;
|
||||
|
||||
/// Check if there is any selection
|
||||
bool hasSelection(const char* pDocName = nullptr) const;
|
||||
bool hasSelection() const;
|
||||
|
||||
/** Check if there is any selection within a given document
|
||||
*
|
||||
@@ -591,7 +594,7 @@ public:
|
||||
* If \c resolve is false, then the match is only done with the top
|
||||
* level parent object.
|
||||
*/
|
||||
bool hasSelection(const char* doc, ResolveMode resolve) const;
|
||||
bool hasSelection(const char* doc, ResolveMode resolve = ResolveMode::OldStyleElement) const;
|
||||
|
||||
/** Check if there is any sub-element selection
|
||||
*
|
||||
@@ -608,7 +611,10 @@ public:
|
||||
bool hasPreselection() const;
|
||||
|
||||
/// Size of selected entities for all documents
|
||||
unsigned int size(const char* pDocName = nullptr) const;
|
||||
unsigned int size() const
|
||||
{
|
||||
return static_cast<unsigned int>(_SelList.size());
|
||||
}
|
||||
|
||||
/** @name Selection stack functions
|
||||
*
|
||||
@@ -617,10 +623,16 @@ public:
|
||||
*/
|
||||
//@{
|
||||
/// Return the current selection stack size
|
||||
std::size_t selStackBackSize(const char* pDocName = nullptr) const;
|
||||
std::size_t selStackBackSize() const
|
||||
{
|
||||
return _SelStackBack.size();
|
||||
}
|
||||
|
||||
/// Return the current forward selection stack size
|
||||
std::size_t selStackForwardSize(const char* pDocName = nullptr) const;
|
||||
std::size_t selStackForwardSize() const
|
||||
{
|
||||
return _SelStackForward.size();
|
||||
}
|
||||
|
||||
/** Obtain selected objects from stack
|
||||
*
|
||||
@@ -638,31 +650,28 @@ public:
|
||||
/** Go back selection history
|
||||
*
|
||||
* @param count: optional number of steps to go back
|
||||
* @param pDocName: the name of the document to index the context, defaults to active document
|
||||
*
|
||||
* This function pops the selection stack, and populate the current
|
||||
* selection with the content of the last pop'd entry
|
||||
*/
|
||||
void selStackGoBack(int count = 1, const char* pDocName = nullptr);
|
||||
void selStackGoBack(int count = 1);
|
||||
|
||||
/** Go forward selection history
|
||||
*
|
||||
* @param count: optional number of steps to go back
|
||||
* @param pDocName: the name of the document to index the context, defaults to active document
|
||||
*
|
||||
* This function pops the selection stack, and populate the current
|
||||
* selection with the content of the last pop'd entry
|
||||
*/
|
||||
void selStackGoForward(int count = 1, const char* pDocName = nullptr);
|
||||
void selStackGoForward(int count = 1);
|
||||
|
||||
/** Save the current selection on to the stack
|
||||
*
|
||||
* @param clearForward: whether to clear forward selection stack
|
||||
* @param overwrite: whether to overwrite the current top entry of the
|
||||
* stack instead of pushing a new entry.
|
||||
* @param pDocName: the name of the document to index the context, defaults to active document
|
||||
*/
|
||||
void selStackPush(bool clearForward = true, bool overwrite = false, const char* pDocName = nullptr);
|
||||
void selStackPush(bool clearForward = true, bool overwrite = false);
|
||||
//@}
|
||||
|
||||
/** @name Picked list functions
|
||||
@@ -673,11 +682,11 @@ public:
|
||||
*/
|
||||
//@{
|
||||
/// Check whether picked list is enabled
|
||||
bool needPickedList(const char* pDocName = nullptr) const;
|
||||
bool needPickedList() const;
|
||||
/// Turn on or off picked list
|
||||
void enablePickedList(bool, const char* pDocName = nullptr);
|
||||
void enablePickedList(bool);
|
||||
/// Check if there is any selection inside picked list
|
||||
bool hasPickedList(const char* pDocName = nullptr) const;
|
||||
bool hasPickedList() const;
|
||||
/// Return select objects inside picked list
|
||||
std::vector<SelectionSingleton::SelObj> getPickedList(const char* pDocName) const;
|
||||
/// Return selected object inside picked list grouped by top level parents
|
||||
@@ -699,9 +708,9 @@ public:
|
||||
GreedySelection
|
||||
};
|
||||
/// Changes the style of selection between greedy and normal.
|
||||
void setSelectionStyle(SelectionStyle selStyle, const char* pDocName = nullptr);
|
||||
void setSelectionStyle(SelectionStyle selStyle);
|
||||
/// Get the style of selection.
|
||||
SelectionStyle getSelectionStyle(const char* pDocName = nullptr);
|
||||
SelectionStyle getSelectionStyle();
|
||||
//@}
|
||||
|
||||
static SelectionSingleton& instance();
|
||||
@@ -747,20 +756,24 @@ protected:
|
||||
|
||||
/// Observer message from the App doc
|
||||
void slotDeletedObject(const App::DocumentObject&);
|
||||
void slotClosedDocument(const App::Document&);
|
||||
|
||||
/// helper to retrieve document by name
|
||||
App::Document* getDocument(const char* pDocName = nullptr) const;
|
||||
|
||||
void slotSelectionChanged(const SelectionChanges& msg);
|
||||
|
||||
SelectionChanges CurrentPreselection;
|
||||
|
||||
std::deque<SelectionChanges> NotificationQueue;
|
||||
bool Notifying = false;
|
||||
|
||||
void notify(SelectionChanges&& Chng);
|
||||
void notify(const SelectionChanges& Chng)
|
||||
{
|
||||
notify(SelectionChanges(Chng));
|
||||
}
|
||||
|
||||
struct SelectionDescription
|
||||
struct _SelObj
|
||||
{
|
||||
std::string DocName;
|
||||
std::string FeatName;
|
||||
@@ -779,26 +792,34 @@ protected:
|
||||
void log(bool remove = false, bool clearPreselect = true);
|
||||
std::string getSubString() const;
|
||||
};
|
||||
mutable std::list<_SelObj> _SelList;
|
||||
|
||||
mutable std::list<_SelObj> _PickedList;
|
||||
bool _needPickedList {false};
|
||||
|
||||
using SelStackItem = std::set<App::SubObjectT>;
|
||||
std::deque<SelStackItem> _SelStackBack;
|
||||
std::deque<SelStackItem> _SelStackForward;
|
||||
|
||||
int checkSelection(
|
||||
const char* pDocName,
|
||||
const char* pObjectName,
|
||||
const char* pSubName,
|
||||
ResolveMode resolve,
|
||||
SelectionDescription& sel,
|
||||
const std::list<SelectionDescription>* selList = nullptr
|
||||
_SelObj& sel,
|
||||
const std::list<_SelObj>* selList = nullptr
|
||||
) const;
|
||||
|
||||
std::vector<Gui::SelectionObject> getObjectList(
|
||||
const char* pDocName,
|
||||
Base::Type typeId,
|
||||
const std::list<SelectionDescription>& objs,
|
||||
std::list<_SelObj>& objs,
|
||||
ResolveMode resolve,
|
||||
bool single = false
|
||||
) const;
|
||||
|
||||
static App::DocumentObject* getObjectOfType(
|
||||
const SelectionDescription& sel,
|
||||
_SelObj& sel,
|
||||
Base::Type type,
|
||||
ResolveMode resolve,
|
||||
const char** subelement = nullptr
|
||||
@@ -810,56 +831,21 @@ protected:
|
||||
ResolveMode resolve = ResolveMode::OldStyleElement
|
||||
) const;
|
||||
|
||||
using SelStackItem = std::set<App::SubObjectT>;
|
||||
// Each document has a description context
|
||||
struct SelectionInfo
|
||||
{
|
||||
Gui::SelectionGate* gate {nullptr};
|
||||
ResolveMode resolveMode {ResolveMode::OldStyleElement};
|
||||
|
||||
std::list<SelectionDescription> selList;
|
||||
std::list<SelectionDescription> pickedList;
|
||||
bool needPickedList {false};
|
||||
|
||||
std::deque<SelStackItem> selStackBack;
|
||||
std::deque<SelStackItem> selStackForward;
|
||||
|
||||
SelectionStyle selectionStyle {SelectionStyle::NormalSelection};
|
||||
};
|
||||
struct SelectionContext
|
||||
{
|
||||
SelectionInfo* info;
|
||||
std::string docName;
|
||||
};
|
||||
struct SelectionConstContext
|
||||
{
|
||||
const SelectionInfo* info;
|
||||
std::string docName;
|
||||
};
|
||||
|
||||
// Returns a selection context or nullptr if the document is not found
|
||||
SelectionContext getSelectionContext(const char* pDocName);
|
||||
SelectionConstContext getSelectionContext(const char* pDocName) const;
|
||||
|
||||
static SelectionSingleton* _pcSingleton;
|
||||
|
||||
|
||||
std::map<App::Document*, SelectionInfo> docSelectionContext;
|
||||
|
||||
// Preselection helpers, it's a mess, needs clarifying -theo-vt
|
||||
std::string DocName;
|
||||
std::string FeatName;
|
||||
std::string SubName;
|
||||
float hx {0.0f}, hy {0.0f}, hz {0.0f};
|
||||
SelectionChanges CurrentPreselection;
|
||||
float hx, hy, hz;
|
||||
|
||||
Gui::SelectionGate* ActiveGate;
|
||||
ResolveMode gateResolve;
|
||||
|
||||
int logDisabled {0};
|
||||
bool logHasSelection {false};
|
||||
bool clarifySelectionActive {false};
|
||||
int logDisabled = 0;
|
||||
bool logHasSelection = false;
|
||||
bool clarifySelectionActive = false;
|
||||
|
||||
std::deque<SelectionChanges> NotificationQueue;
|
||||
bool Notifying {false};
|
||||
SelectionStyle selectionStyle;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -264,8 +264,10 @@ int yyi;
|
||||
# ifndef YYSTACK_ALLOC_MAXIMUM
|
||||
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
|
||||
# endif
|
||||
# if (defined __cplusplus && !defined _STDLIB_H \
|
||||
&& !((defined YYMALLOC || defined malloc) && (defined YYFREE || defined free)))
|
||||
# if ( \
|
||||
defined __cplusplus && !defined _STDLIB_H \
|
||||
&& !((defined YYMALLOC || defined malloc) && (defined YYFREE || defined free)) \
|
||||
)
|
||||
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
|
||||
# ifndef _STDLIB_H
|
||||
# define _STDLIB_H 1
|
||||
@@ -289,8 +291,10 @@ void free(void*); /* INFRINGES ON USER NAME SPACE */
|
||||
#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
|
||||
|
||||
|
||||
#if (!defined yyoverflow \
|
||||
&& (!defined __cplusplus || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
|
||||
#if ( \
|
||||
!defined yyoverflow \
|
||||
&& (!defined __cplusplus || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)) \
|
||||
)
|
||||
|
||||
/* A type that is properly aligned for any stack member. */
|
||||
union yyalloc
|
||||
|
||||
@@ -188,8 +188,10 @@ void SoFCSelection::doAction(SoAction* action)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selaction->getType() == Gui::SoSelectionElementAction::None
|
||||
|| selaction->getType() == Gui::SoSelectionElementAction::Remove) {
|
||||
else if (
|
||||
selaction->getType() == Gui::SoSelectionElementAction::None
|
||||
|| selaction->getType() == Gui::SoSelectionElementAction::Remove
|
||||
) {
|
||||
SelContextPtr ctx
|
||||
= Gui::SoFCSelectionRoot::getActionContext(action, this, selContext, false);
|
||||
if (ctx && ctx->isSelected()) {
|
||||
|
||||
@@ -1130,9 +1130,11 @@ void SoBoxSelectionRenderAction::apply(SoNode* node)
|
||||
}
|
||||
PRIVATE(this)->selectsearch->reset();
|
||||
}
|
||||
else if (selection->isHighlighted()
|
||||
&& selection->selected.getValue() == SoFCSelection::NOTSELECTED
|
||||
&& selection->style.getValue() == SoFCSelection::BOX) {
|
||||
else if (
|
||||
selection->isHighlighted()
|
||||
&& selection->selected.getValue() == SoFCSelection::NOTSELECTED
|
||||
&& selection->style.getValue() == SoFCSelection::BOX
|
||||
) {
|
||||
PRIVATE(this)->basecolor->rgb.setValue(selection->colorHighlight.getValue());
|
||||
|
||||
if (!PRIVATE(this)->selectsearch) {
|
||||
@@ -1177,9 +1179,10 @@ void SoBoxSelectionRenderAction::apply(SoPath* path)
|
||||
// because this will destroy the box immediately
|
||||
selection->touch(); // force a redraw when dehighlighting
|
||||
}
|
||||
else if (selection->isHighlighted()
|
||||
&& selection->selected.getValue() == SoFCSelection::NOTSELECTED
|
||||
&& selection->style.getValue() == SoFCSelection::BOX) {
|
||||
else if (
|
||||
selection->isHighlighted() && selection->selected.getValue() == SoFCSelection::NOTSELECTED
|
||||
&& selection->style.getValue() == SoFCSelection::BOX
|
||||
) {
|
||||
PRIVATE(this)->basecolor->rgb.setValue(selection->colorHighlight.getValue());
|
||||
|
||||
if (!PRIVATE(this)->selectsearch) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user