Compare commits

..

2 Commits

Author SHA1 Message Date
pre-commit-ci[bot] 4b2296936c [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2026-03-16 20:36:26 +00:00
pre-commit-ci[bot] 56530cd309 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black-pre-commit-mirror: 2892f1f81088477370d4fbc56545c05d33d2493f → fa505ab9c3e0fedafe1709fd7ac2b5f8996c670d](https://github.com/psf/black-pre-commit-mirror/compare/2892f1f81088477370d4fbc56545c05d33d2493f...fa505ab9c3e0fedafe1709fd7ac2b5f8996c670d)
- [github.com/pre-commit/mirrors-clang-format: 317810f3c6a0ad3572367dc86cb6e41863e16e08 → 88c364bab316f4b6b18f6c298133bbbf32d7cd15](https://github.com/pre-commit/mirrors-clang-format/compare/317810f3c6a0ad3572367dc86cb6e41863e16e08...88c364bab316f4b6b18f6c298133bbbf32d7cd15)
2026-03-16 20:31:17 +00:00
839 changed files with 5203 additions and 8524 deletions
+1
View File
@@ -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
+1 -1
View File
@@ -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
+14 -78
View File
@@ -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:
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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 }}
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -2
View File
@@ -19,12 +19,11 @@ debugpy = "*"
defusedxml = "*"
docutils = "*"
doxygen = "*"
eigen = ">=3.3,<5"
eigen = "*"
fmt = "*"
freetype = "*"
git = "*"
graphviz = "*"
harfbuzz = "*"
hdf5 = "*"
ifcopenshell = "*"
lark = "*"
-9
View File
@@ -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
View File
@@ -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;
+8 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*
-9
View File
@@ -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
"""
...
-9
View File
@@ -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
{
+3 -3
View File
@@ -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();
}
}
-59
View File
@@ -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
+1 -1
View File
@@ -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;
}
}
+1 -3
View File
@@ -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;
-6
View File
@@ -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
View File
@@ -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.
+2 -4
View File
@@ -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.
+2 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+3 -3
View File
@@ -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);
+17 -17
View File
@@ -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());
+9 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*/
-3
View File
@@ -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
+5 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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();
+2 -2
View File
@@ -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
View File
@@ -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();
+4 -2
View File
@@ -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());
}
}
-2
View File
@@ -101,8 +101,6 @@ void StdCmdPart::activated(int iMsg)
PartName.c_str()
);
commitCommand();
updateActive();
}
+7 -66
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
+3 -2
View File
@@ -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;
}
+18 -25
View File
@@ -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;
}
+5 -5
View File
@@ -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;
}
+4 -12
View File
@@ -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
View File
@@ -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
View File
@@ -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
-25
View File
@@ -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."""
-28
View File
@@ -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()};
+11 -11
View File
@@ -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();
}
}
}
+2 -4
View File
@@ -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())
+4 -4
View File
@@ -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);
+3 -2
View File
@@ -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;
+1 -1
View File
@@ -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();
+5 -3
View File
@@ -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);
+1 -1
View File
@@ -96,7 +96,7 @@ void NavigationAnimator::stop()
*/
bool NavigationAnimator::isAnimating() const
{
if (activeAnimation) {
if (activeAnimation != nullptr) {
return activeAnimation->state() == QAbstractAnimation::State::Running;
}
+23 -8
View File
@@ -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)
+1
View File
@@ -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(
+5 -3
View File
@@ -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
View File
@@ -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()
+15 -8
View File
@@ -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
View File
@@ -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)
+7 -5
View File
@@ -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 {
+4 -2
View File
@@ -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;
}
+4 -2
View File
@@ -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);
}
+2 -2
View File
@@ -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
+6
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+69 -83
View File
@@ -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;
};
/**
+8 -4
View File
@@ -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
+4 -2
View File
@@ -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()) {
+9 -6
View File
@@ -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