Compare commits

...

4 Commits

Author SHA1 Message Date
Roman Telezhynskyi 45decf0b1f Lupdate. 2024-03-12 16:51:53 +02:00
Roman Telezhynskyi 33a5939c18 Automatic crash reports. 2024-03-12 16:39:44 +02:00
Roman Telezhynskyi fb15284483 Sonarcloud warnings. 2024-03-02 15:24:09 +02:00
Roman Telezhynskyi 3548f2b71c Install missing dependency. 2024-03-01 16:10:49 +02:00
118 changed files with 9653 additions and 6406 deletions

View File

@ -125,10 +125,12 @@ linux_qt5_qbs_task_template: &LINUX_QT5_QBS_TASK_TEMPLATE
appimage_task_template: &APPIMAGE_TASK_TEMPLATE appimage_task_template: &APPIMAGE_TASK_TEMPLATE
pip_cache: pip_cache:
folder: ${PIP_CACHE_DIR} folder: ${PIP_CACHE_DIR}
conan_cache:
folder: "~/.conan/data"
install_script: install_script:
- bash -c "$PACKAGE_MANAGER_INSTALL qt515base qt515svg qt515tools qt515xmlpatterns qt515translations qt515doc qt515imageformats poppler-utils git xvfb ccache build-essential libgl1-mesa-dev libicu-dev python3-pip" - bash -c "$PACKAGE_MANAGER_INSTALL qt515base qt515svg qt515tools qt515xmlpatterns qt515translations qt515doc qt515imageformats poppler-utils git xvfb ccache build-essential libgl1-mesa-dev libicu-dev python3-pip"
- python3 --version - python3 --version
- pip3 install --user --upgrade pip dropbox 'urllib3<2.0' - pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' conan==1.63.0
build_script: build_script:
- uname -a - uname -a
- mkdir -pm 0700 $XDG_RUNTIME_DIR - mkdir -pm 0700 $XDG_RUNTIME_DIR
@ -143,12 +145,25 @@ appimage_task_template: &APPIMAGE_TASK_TEMPLATE
- ${COMPILER} --version - ${COMPILER} --version
- qmake --version - qmake --version
- qbs --version - qbs --version
- conan profile new valentina
- conan profile update settings.build_type=Release valentina
- conan profile update settings.os=Linux valentina
- conan profile update settings.compiler=gcc valentina
- conan profile update settings.compiler.cppstd=17 valentina
- conan profile update settings.compiler.libcxx=libstdc++11 valentina
- conan profile update settings.compiler.version=9 valentina
- qbs setup-toolchains /usr/bin/${COMPILER} ${COMPILER} - qbs setup-toolchains /usr/bin/${COMPILER} ${COMPILER}
- qbs setup-qt /opt/qt515/bin/qmake qt5 - qbs setup-qt /opt/qt515/bin/qmake qt5
- qbs config defaultProfile qt5 - qbs config defaultProfile qt5
- qbs config profiles.qt5.baseProfile ${COMPILER} - qbs config profiles.qt5.baseProfile ${COMPILER}
- qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build --jobs $(nproc) profile:qt5 config:release modules.buildconfig.enableCcache:${ENABLE_CCACHE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/AppDir modules.buildconfig.enableAppImage:true modules.buildconfig.enableRPath:false - conan install . -s os=Linux --build=missing -o with_crash_reporting=True -pr valentina -g virtualrunenv
- qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build --jobs $(nproc) profile:qt5 config:release modules.buildconfig.enableCcache:${ENABLE_CCACHE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/AppDir modules.buildconfig.enableAppImage:true modules.buildconfig.enableRPath:false project.conanWithCrashReporting:true project.enableConan:true
- qbs -p autotest-runner -d build profile:qt5 config:release - qbs -p autotest-runner -d build profile:qt5 config:release
- export CRASH_QT_VERSION=$(/opt/qt515/bin/qmake -query QT_VERSION | awk -F. '{print $1 "_" $2}')
- export CRASH_SHORT_SHA=$(git log --pretty=format:%h -n 1)
- source activate_run.sh
- python3 scripts/symupload.py $CIRRUS_WORKING_DIR/build/AppDir $VALENTINA_VERSION $CRASH_SHORT_SHA $CRASH_QT_VERSION --clean
- source deactivate_run.sh
- appimage-builder --recipe dist/AppImage/AppImageBuilder.yml --appdir $CIRRUS_WORKING_DIR/build/AppDir --skip-test - appimage-builder --recipe dist/AppImage/AppImageBuilder.yml --appdir $CIRRUS_WORKING_DIR/build/AppDir --skip-test
- ccache -s - ccache -s
deploy_script: deploy_script:
@ -228,6 +243,7 @@ linux_task:
QT_VERSION: Qt6 QT_VERSION: Qt6
ARCH: x86_64 ARCH: x86_64
TARGET_PLATFORM: "Linux" TARGET_PLATFORM: "Linux"
VALENTINA_VERSION: 0_7_52
container: container:
cpu: 4 cpu: 4
memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container memory: 8G # Set to 8GB to avoid OOM. https://cirrus-ci.org/guide/linux/#linux-container
@ -350,16 +366,11 @@ macos_task_template: &MACOS_TASK_TEMPLATE
- chmod -R 755 /opt/homebrew/opt/poppler/* - chmod -R 755 /opt/homebrew/opt/poppler/*
- chmod -R 755 /opt/homebrew/opt/xerces-c/* - chmod -R 755 /opt/homebrew/opt/xerces-c/*
- python3 --version - python3 --version
- pip3 install --user --upgrade pip dropbox 'urllib3<2.0' - pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' conan==1.63.0
- ccache --set-config sloppiness=pch_defines,time_macros max_size="$CCACHE_SIZE" - ccache --set-config sloppiness=pch_defines,time_macros max_size="$CCACHE_SIZE"
- qmake --version - qmake --version
- which qmake - which qmake
- qbs --version - qbs --version
# Patch Qbs. Remove after Qbs 2.2.1+.
- curl https://gist.githubusercontent.com/dismine/43f3c51e05f3317c5d4fe16cd3c4b6d8/raw/2d297bcb53c2c022f740509923adf1eb1796afe2/qbs-pkg-config-probe.patch --output $HOME/qbs-pkg-config-probe.patch --silent
- patch -N -d $(brew --prefix qbs)/ -p1 < $HOME/qbs-pkg-config-probe.patch || true
- rm -f $(brew --prefix qbs)/share/qbs/imports/qbs/Probes/qbs-pkg-config-probe.js.rej
- rm $HOME/qbs-pkg-config-probe.patch
build_script: build_script:
- echo $PATH - echo $PATH
- export PATH="${HOME}/.local/bin:`python3 -m site --user-base`/bin:$PATH" - export PATH="${HOME}/.local/bin:`python3 -m site --user-base`/bin:$PATH"
@ -373,12 +384,26 @@ macos_task_template: &MACOS_TASK_TEMPLATE
- unzip ${HOME}/macdeployqt-main.zip -d ${HOME} - unzip ${HOME}/macdeployqt-main.zip -d ${HOME}
- cmake ${HOME}/macdeployqt-main -GNinja -S ${HOME}/macdeployqt-main -B ${HOME}/macdeployqt-build-dir -DCMAKE_INSTALL_PREFIX=${HOME}/macdeployqt-install-dir -DCMAKE_BUILD_TYPE=Release - cmake ${HOME}/macdeployqt-main -GNinja -S ${HOME}/macdeployqt-main -B ${HOME}/macdeployqt-build-dir -DCMAKE_INSTALL_PREFIX=${HOME}/macdeployqt-install-dir -DCMAKE_BUILD_TYPE=Release
- cmake --build ${HOME}/macdeployqt-build-dir --target install - cmake --build ${HOME}/macdeployqt-build-dir --target install
- conan profile new valentina
- conan profile update settings.build_type=Release valentina
- conan profile update settings.os=Macos valentina
- conan profile update settings.os.Macos.sdk_version=${MACOS_DEPLOYMENT_TARGET} valentina
- conan profile update settings.compiler=clang valentina
- conan profile update settings.compiler.cppstd=17 valentina
- conan profile update settings.compiler.libcxx=libstdc++11 valentina
- conan profile update settings.compiler.version=14 valentina
- qbs setup-toolchains --detect - qbs setup-toolchains --detect
- qbs config --list profiles - qbs config --list profiles
- qbs setup-qt /opt/homebrew/opt/qt6/bin/qmake qt6 - qbs setup-qt /opt/homebrew/opt/qt6/bin/qmake qt6
- qbs config defaultProfile qt6 - qbs config defaultProfile qt6
- qbs config profiles.qt6.baseProfile clang - qbs config profiles.qt6.baseProfile clang
- conan install . -s os=Macos --build=missing -o with_crash_reporting=True -pr valentina -g virtualrunenv
- qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:${ENABLE_CCACHE} moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:${ENABLE_CCACHE} moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir
- export CRASH_QT_VERSION=$(/opt/homebrew/opt/qt6/bin/qmake -query QT_VERSION | awk -F. '{print $1 "_" $2}')
- export CRASH_SHORT_SHA=$(git log --pretty=format:%h -n 1)
- source activate_run.sh
- python3 scripts/symupload.py $CIRRUS_WORKING_DIR/build/install-root $VALENTINA_VERSION $CRASH_SHORT_SHA $CRASH_QT_VERSION --clean
- source deactivate_run.sh
- qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:${ENABLE_CCACHE} moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - qbs build -f valentina.qbs -d $CIRRUS_WORKING_DIR/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:$CIRRUS_WORKING_DIR/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:${ENABLE_CCACHE} moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir
# Store the notarization credentials so that we can prevent a UI password dialog # Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI # from blocking the CI
@ -412,6 +437,7 @@ macos_task:
TARGET_PLATFORM: "macOS_12.4+" TARGET_PLATFORM: "macOS_12.4+"
MACOS_DEPLOYMENT_TARGET: 12.0 MACOS_DEPLOYMENT_TARGET: 12.0
ENABLE_CCACHE: true ENABLE_CCACHE: true
VALENTINA_VERSION: 0_7_52
matrix: matrix:
- name: 'macOS Monterey 12 [signle bundle, no tests]' - name: 'macOS Monterey 12 [signle bundle, no tests]'
env: env:

13
.gitignore vendored
View File

@ -73,7 +73,6 @@ cov-int/
*.la *.la
*.a *.a
*.lib *.lib
*.lo
# Executables # Executables
*.exe *.exe
@ -117,7 +116,6 @@ Makefile*
*.xcodeproj *.xcodeproj
# OSX specific # OSX specific
.DS_Store
.AppleDouble .AppleDouble
.LSOverride .LSOverride
@ -173,3 +171,14 @@ __pycache__
# Sonar Cloud # Sonar Cloud
.scannerwork .scannerwork
bw-output bw-output
# Conan
/activate_run.ps1
/activate_run.sh
/conanbuildinfo.txt
/conaninfo.txt
/deactivate_run.ps1
/deactivate_run.sh
/environment_run.ps1.env
/environment_run.sh.env
/graph_info.json

View File

@ -64,6 +64,7 @@
- Fold line. - Fold line.
- Minimal Qt version increased to Qt 5.15. Minimal C++ standard to C++17. - Minimal Qt version increased to Qt 5.15. Minimal C++ standard to C++17.
- Updated Windows installer. - Updated Windows installer.
- Automatic crash reports.
# Valentina 0.7.52 September 12, 2022 # Valentina 0.7.52 September 12, 2022
- Fix crash when default locale is ru. - Fix crash when default locale is ru.

View File

@ -40,6 +40,7 @@ environment:
ACCESS_TOKEN: ACCESS_TOKEN:
secure: RUhnEHqaR8KhalOMWwZZOoO342Ja50QV4KpEWdm9g3pG+jG7i6aJqUmeKF1l5VN6dzksk1u+yN6pOLnU8oGcaVQ6v+1dpKK1oZvF0tyHhNE= secure: RUhnEHqaR8KhalOMWwZZOoO342Ja50QV4KpEWdm9g3pG+jG7i6aJqUmeKF1l5VN6dzksk1u+yN6pOLnU8oGcaVQ6v+1dpKK1oZvF0tyHhNE=
APPVEYOR_SAVE_CACHE_ON_ERROR: "true" APPVEYOR_SAVE_CACHE_ON_ERROR: "true"
VALENTINA_VERSION: 0_7_52
matrix: matrix:
- job_name: Windows_Qt_6_5_(MSVC_x64) - job_name: Windows_Qt_6_5_(MSVC_x64)
@ -398,15 +399,26 @@ for:
build_script: build_script:
- conan profile list - conan profile list
- conan install . -s os=Windows --build=missing -pr valentina - conan install . -s os=Windows --build=missing -o with_crash_reporting=True -o with_xerces=True -pr valentina -g virtualrunenv
- qbs build -f valentina.qbs -d %APPVEYOR_BUILD_FOLDER%\build --jobs %NUMBER_OF_PROCESSORS% config:release qbs.installRoot:%APPVEYOR_BUILD_FOLDER%\build\install-root\valentina profile:qt6 project.enableConan:true modules.buildconfig.enableCcache:false project.conanProfiles:valentina modules.buildconfig.enablePCH:%ENABLE_PCH% modules.windeployqt.windeployqtProgramBinPath:%WINDEPLOYQT_BIN_PATH% modules.windeployqt.compilerRuntime:%WINDEPLOYQT_COMPILER_RUNTIME% modules.windeployqt.noCompilerRuntime:%WINDEPLOYQT_NO_COMPILER_RUNTIME% - qbs build -f valentina.qbs -d %APPVEYOR_BUILD_FOLDER%\build --jobs %NUMBER_OF_PROCESSORS% config:release qbs.installRoot:%APPVEYOR_BUILD_FOLDER%\build\install-root\valentina profile:qt6 project.enableConan:true project.conanWithCrashReporting:true project.conanWithXerces:true modules.buildconfig.enableCcache:false project.conanProfiles:valentina modules.buildconfig.enablePCH:%ENABLE_PCH% modules.windeployqt.windeployqtProgramBinPath:%WINDEPLOYQT_BIN_PATH% modules.windeployqt.compilerRuntime:%WINDEPLOYQT_COMPILER_RUNTIME% modules.windeployqt.noCompilerRuntime:%WINDEPLOYQT_NO_COMPILER_RUNTIME%
test_script: test_script:
- path - path
- if "%RUN_TESTS%" == "true" (qbs -p autotest-runner -d %APPVEYOR_BUILD_FOLDER%\build profile:qt6 config:release) - if "%RUN_TESTS%" == "true" (qbs -p autotest-runner -d %APPVEYOR_BUILD_FOLDER%\build profile:qt6 config:release)
deploy_script: deploy_script:
- if "%DEPLOY%" == "true" (qbs build -f valentina.qbs -d %APPVEYOR_BUILD_FOLDER%\build -p ValentinaSetup --jobs %NUMBER_OF_PROCESSORS% config:release qbs.installRoot:%APPVEYOR_BUILD_FOLDER%\build\install-root\valentina profile:qt6 project.enableConan:true modules.buildconfig.enableCcache:false project.conanProfiles:valentina modules.buildconfig.enablePCH:%ENABLE_PCH% modules.windeployqt.windeployqtProgramBinPath:%WINDEPLOYQT_BIN_PATH% modules.windeployqt.compilerRuntime:%WINDEPLOYQT_COMPILER_RUNTIME% modules.windeployqt.noCompilerRuntime:%WINDEPLOYQT_NO_COMPILER_RUNTIME%) - ps: |
if ($env:DEPLOY -eq "true") {
$qmakeOutput = %QTDIR%\bin\%QMAKE% -query QT_VERSION
$majorMinorVersion = $qmakeOutput -replace '\D+(\d+)\.(\d+).*', '$1_$2'
$env:CRASH_QT_VERSION = $majorMinorVersion
$env:CRASH_SHORT_SHA = git log --pretty=format:%h -n 1
}
- ps: activate_run.ps1
- if "%DEPLOY%" == "true" (python3 scripts/symupload.py %APPVEYOR_BUILD_FOLDER%\build\install-root\valentina $VALENTINA_VERSION $CRASH_SHORT_SHA $CRASH_QT_VERSION --clean)
- ps: deactivate_run.ps1
- if "%DEPLOY%" == "true" (qbs build -f valentina.qbs -d %APPVEYOR_BUILD_FOLDER%\build -p ValentinaSetup --jobs %NUMBER_OF_PROCESSORS% config:release qbs.installRoot:%APPVEYOR_BUILD_FOLDER%\build\install-root\valentina profile:qt6 project.enableConan:true project.conanWithCrashReporting:true project.conanWithXerces:true modules.buildconfig.enableCcache:false project.conanProfiles:valentina modules.buildconfig.enablePCH:%ENABLE_PCH% modules.windeployqt.windeployqtProgramBinPath:%WINDEPLOYQT_BIN_PATH% modules.windeployqt.compilerRuntime:%WINDEPLOYQT_COMPILER_RUNTIME% modules.windeployqt.noCompilerRuntime:%WINDEPLOYQT_NO_COMPILER_RUNTIME%)
- ps: scripts/appveyor-deploy.ps1 - ps: scripts/appveyor-deploy.ps1
on_finish: on_finish:
@ -537,7 +549,7 @@ for:
secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs= secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs=
cache: cache:
#- /Users/appveyor/.conan/data -> conanfile.py - /Users/appveyor/.conan/data -> conanfile.py
- $HOME/brew_cache_dir - $HOME/brew_cache_dir
init: init:
@ -643,7 +655,7 @@ for:
fi fi
- sudo python3 -m pip install --upgrade pip - sudo python3 -m pip install --upgrade pip
- pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' - pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' conan==1.63.0
- export QTDIR=`$(brew --prefix qt6)` - export QTDIR=`$(brew --prefix qt6)`
- export PATH="$PATH:`python3 -m site --user-base`/bin:$QTDIR/bin" - export PATH="$PATH:`python3 -m site --user-base`/bin:$QTDIR/bin"
- echo $PATH - echo $PATH
@ -663,13 +675,28 @@ for:
build_script: build_script:
- pwd - pwd
- git describe --always HEAD
- conan profile new valentina
- conan profile update settings.build_type=Release valentina
- conan profile update settings.os=Macos valentina
- conan profile update settings.os.Macos.sdk_version=${MACOS_DEPLOYMENT_TARGET} valentina
- conan profile update settings.compiler=clang valentina
- conan profile update settings.compiler.cppstd=17 valentina
- conan profile update settings.compiler.libcxx=libstdc++11 valentina
- conan profile update settings.compiler.version=15 valentina
- qbs setup-toolchains --detect - qbs setup-toolchains --detect
- qbs config --list profiles - qbs config --list profiles
- qbs setup-qt $(brew --prefix qt6)/bin/qmake qt6 - qbs setup-qt $(brew --prefix qt6)/bin/qmake qt6
- qbs config defaultProfile qt6 - qbs config defaultProfile qt6
- qbs config profiles.qt6.baseProfile clang - qbs config profiles.qt6.baseProfile clang
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - conan install . -s os=Macos --build=missing -o with_crash_reporting=True -pr valentina -g virtualrunenv
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir project.enableConan:true project.conanWithCrashReporting:true
- export CRASH_QT_VERSION=$($QTDIR/bin/qmake -query QT_VERSION | awk -F. '{print $1 "_" $2}')
- export CRASH_SHORT_SHA=$(git log --pretty=format:%h -n 1)
- source activate_run.sh
- python3 scripts/symupload.py ${APPVEYOR_BUILD_FOLDER}/build/install-root $VALENTINA_VERSION $CRASH_SHORT_SHA $CRASH_QT_VERSION --clean
- source deactivate_run.sh
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt6 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true moduleProviders.qbspkgconfig.extraPaths:$(brew --prefix xerces-c)/lib/pkgconfig,$(brew --prefix qt6)/lib/pkgconfig,$(brew --prefix openssl@1.1)/lib/pkgconfig "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:$(brew --prefix qt6)/lib,$(brew --prefix poppler)/lib modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir project.enableConan:true project.conanWithCrashReporting:true
# Store the notarization credentials so that we can prevent a UI password dialog # Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI # from blocking the CI
- echo "Create keychain profile" - echo "Create keychain profile"
@ -720,7 +747,7 @@ for:
secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs= secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs=
cache: cache:
#- /Users/appveyor/.conan/data -> conanfile.py - /Users/appveyor/.conan/data -> conanfile.py
- $HOME/brew_cache_dir - $HOME/brew_cache_dir
init: init:
@ -827,7 +854,7 @@ for:
fi fi
- sudo python3 -m pip install --upgrade pip - sudo python3 -m pip install --upgrade pip
- pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' - pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' conan==1.63.0
- export PATH="`brew --prefix qbs`/bin:$PATH" - export PATH="`brew --prefix qbs`/bin:$PATH"
- echo $PATH - echo $PATH
- clang --version - clang --version
@ -846,13 +873,27 @@ for:
build_script: build_script:
- pwd - pwd
- conan profile new valentina
- conan profile update settings.build_type=Release valentina
- conan profile update settings.os=Macos valentina
- conan profile update settings.os.Macos.sdk_version=${MACOS_DEPLOYMENT_TARGET} valentina
- conan profile update settings.compiler=clang valentina
- conan profile update settings.compiler.cppstd=17 valentina
- conan profile update settings.compiler.libcxx=libstdc++11 valentina
- conan profile update settings.compiler.version=14 valentina
- qbs setup-toolchains --detect - qbs setup-toolchains --detect
- qbs config --list profiles - qbs config --list profiles
- qbs setup-qt ${QTDIR}/bin/qmake qt5 - qbs setup-qt ${QTDIR}/bin/qmake qt5
- qbs config defaultProfile qt5 - qbs config defaultProfile qt5
- qbs config profiles.qt5.baseProfile clang - qbs config profiles.qt5.baseProfile clang
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt5 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:${QTDIR}/lib modules.macdeployqt.pluginspath:${QTDIR}/plugins modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - conan install . -s os=Macos --build=missing -o with_crash_reporting=True -pr valentina -g virtualrunenv
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt5 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:${QTDIR}/lib modules.macdeployqt.pluginspath:${QTDIR}/plugins modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir - qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt5 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:${QTDIR}/lib modules.macdeployqt.pluginspath:${QTDIR}/plugins modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir project.enableConan:true project.conanWithCrashReporting:true
- export CRASH_QT_VERSION=$($QTDIR/bin/qmake -query QT_VERSION | awk -F. '{print $1 "_" $2}')
- export CRASH_SHORT_SHA=$(git log --pretty=format:%h -n 1)
- source activate_run.sh
- python3 scripts/symupload.py ${APPVEYOR_BUILD_FOLDER}/build/install-root $VALENTINA_VERSION $CRASH_SHORT_SHA $CRASH_QT_VERSION --clean
- source deactivate_run.sh
- qbs build -f valentina.qbs -d ${APPVEYOR_BUILD_FOLDER}/build -p 'Valentina DMG' --force-probe-execution --jobs $(nproc) config:release modules.buildconfig.enableUnitTests:false modules.buildconfig.enableMultiBundle:${MULTI_BUNDLE} qbs.installRoot:${APPVEYOR_BUILD_FOLDER}/build/install-root profile:qt5 project.minimumMacosVersion:${MACOS_DEPLOYMENT_TARGET} modules.buildconfig.enableCcache:true "modules.buildconfig.signingIdentity:$MACOS_CERTIFICATE_NAME" modules.macdeployqt.libpath:${QTDIR}/lib modules.macdeployqt.pluginspath:${QTDIR}/plugins modules.macdeployqt.macdeployqtProgramBinPath:${HOME}/macdeployqt-install-dir project.enableConan:true project.conanWithCrashReporting:true
# Store the notarization credentials so that we can prevent a UI password dialog # Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI # from blocking the CI
- echo "Create keychain profile" - echo "Create keychain profile"

View File

@ -4,8 +4,16 @@ from conan import ConanFile
class Recipe(ConanFile): class Recipe(ConanFile):
settings = "os" settings = "os"
requires = "xerces-c/[~3.2]" requires = "xerces-c/[~3.2]", "crashpad/cci.20220219", "breakpad/cci.20210521"
default_options = {"xerces-c/*:shared": True} options = {
"with_xerces": [True, False],
"with_crash_reporting": [True, False]
}
default_options = {
"xerces-c/*:shared": True,
"with_xerces": False,
"with_crash_reporting": False
}
def configure(self): def configure(self):
if self.settings.os == "Linux": if self.settings.os == "Linux":
@ -13,3 +21,11 @@ class Recipe(ConanFile):
if self.settings.os == "Macos" and "MACOS_DEPLOYMENT_TARGET" in os.environ: if self.settings.os == "Macos" and "MACOS_DEPLOYMENT_TARGET" in os.environ:
self.settings.os.version = os.environ["MACOS_DEPLOYMENT_TARGET"] self.settings.os.version = os.environ["MACOS_DEPLOYMENT_TARGET"]
def requirements(self):
if not self.options.with_xerces:
del self.requires["xerces-c"]
if not self.options.with_crash_reporting:
del self.requires["crashpad/cci.20220219"]
del self.requires["breakpad/cci.20210521"]

View File

@ -44,4 +44,9 @@ VLib {
install: true install: true
installDir: buildconfig.installLibraryPath installDir: buildconfig.installLibraryPath
} }
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
qbs.debugInformation: true
}
} }

View File

@ -33,6 +33,11 @@ VApp {
cpp.dynamicLibraries: ["icudata", "icui18n", "icuuc"] cpp.dynamicLibraries: ["icudata", "icui18n", "icuuc"]
} }
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
qbs.debugInformation: true
}
Group { Group {
name: "Translations" name: "Translations"
condition: product.primaryApp || (qbs.targetOS.contains("macos") && (!bundle.isBundle || (bundle.isBundle && buildconfig.enableMultiBundle))) condition: product.primaryApp || (qbs.targetOS.contains("macos") && (!bundle.isBundle || (bundle.isBundle && buildconfig.enableMultiBundle)))

View File

@ -2,6 +2,8 @@ import qbs.File
import qbs.FileInfo import qbs.FileInfo
import qbs.TextFile import qbs.TextFile
import "utils.js" as Utils
ModuleProvider { ModuleProvider {
relativeSearchPaths: { relativeSearchPaths: {
var conanPackageDir = FileInfo.cleanPath(FileInfo.joinPaths(outputBaseDir, "../../..", "genconan")); var conanPackageDir = FileInfo.cleanPath(FileInfo.joinPaths(outputBaseDir, "../../..", "genconan"));
@ -25,8 +27,6 @@ ModuleProvider {
file.close(); file.close();
console.info(JSON.stringify(fileContent));
var deps = fileContent.dependencies; var deps = fileContent.dependencies;
for(i in deps){ for(i in deps){
@ -48,11 +48,11 @@ ModuleProvider {
// module name can be invalid for Javascrip. Search for alternative names for cmake. // module name can be invalid for Javascrip. Search for alternative names for cmake.
var moduleName = deps[i].name; var moduleName = deps[i].name;
if (deps[i].hasOwnProperty("names")) if (!Utils.isValidAttributeName(moduleName) && deps[i].hasOwnProperty("names"))
{ {
if (deps[i].names.hasOwnProperty("cmake_find_package")) if (deps[i].names.hasOwnProperty("cmake_find_package"))
moduleName = deps[i].names.cmake_find_package; moduleName = deps[i].names.cmake_find_package;
else if (deps.names.hasOwnProperty("cmake_find_package_multi")) else if (deps[i].names.hasOwnProperty("cmake_find_package_multi"))
moduleName = deps[i].names.cmake_find_package_multi; moduleName = deps[i].names.cmake_find_package_multi;
} }
@ -63,15 +63,18 @@ ModuleProvider {
var moduleFile = new TextFile(FileInfo.joinPaths(moduleDir, moduleName + ".qbs"), TextFile.WriteOnly); var moduleFile = new TextFile(FileInfo.joinPaths(moduleDir, moduleName + ".qbs"), TextFile.WriteOnly);
var shared = false; var shared = false;
if (fileContent.options[deps[i].name].hasOwnProperty("shared")) if (fileContent.options.hasOwnProperty(deps[i].name) && fileContent.options[deps[i].name].hasOwnProperty("shared"))
{ {
shared = (fileContent.options[deps[i].name].shared === 'True'); shared = (fileContent.options[deps[i].name].shared === 'True');
} }
var cppLibraries = shared ? "\tcpp.dynamicLibraries: " : "\tcpp.staticLibraries: "; var cppLibraries = shared ? "\tcpp.dynamicLibraries: " : "\tcpp.staticLibraries: ";
var cppLibrariesTag = shared ? "dynamiclibrary" : "staticlibrary";
var cppLibrarySuffix = shared ? "cpp.dynamicLibrarySuffix" : "cpp.staticLibrarySuffix";
moduleFile.write("import qbs\n" + moduleFile.write("import qbs\n" +
"Module {\n" + "Module {\n" +
"\tDepends { name: \"cpp\" }\n\n" +
"\tproperty bool installBin: false\n" + "\tproperty bool installBin: false\n" +
"\tproperty bool installLib: false\n" + "\tproperty bool installLib: false\n" +
"\tproperty bool installRes: false\n" + "\tproperty bool installRes: false\n" +
@ -81,10 +84,9 @@ ModuleProvider {
"\tproperty string resInstallDir: \"res\"\n" + "\tproperty string resInstallDir: \"res\"\n" +
"\tproperty string includeInstallDir: \"include\"\n" + "\tproperty string includeInstallDir: \"include\"\n" +
"\tproperty stringList binFilePatterns: [\"**/*\"]\n" + "\tproperty stringList binFilePatterns: [\"**/*\"]\n" +
"\tproperty stringList libFilePatterns: [\"**/*\"]\n" + "\tproperty stringList libFilePatterns: [\"**/*\" + " + cppLibrarySuffix + "]\n" +
"\tproperty stringList resFilePatterns: [\"**/*\"]\n" + "\tproperty stringList resFilePatterns: [\"**/*\"]\n" +
"\tproperty stringList includeFilePatterns: [\"**/*\"]\n\n" + "\tproperty stringList includeFilePatterns: [\"**/*\"]\n\n" +
"\tDepends { name: \"cpp\" }\n\n" +
"\tcpp.includePaths: " + JSON.stringify(deps[i].include_paths) + "\n" + "\tcpp.includePaths: " + JSON.stringify(deps[i].include_paths) + "\n" +
"\tcpp.systemIncludePaths: " + JSON.stringify(deps[i].include_paths) + "\n" + "\tcpp.systemIncludePaths: " + JSON.stringify(deps[i].include_paths) + "\n" +
"\tcpp.libraryPaths: " + JSON.stringify(deps[i].lib_paths) + "\n" + "\tcpp.libraryPaths: " + JSON.stringify(deps[i].lib_paths) + "\n" +
@ -94,9 +96,9 @@ ModuleProvider {
function writeGroups(file, moduleName, prefix, pathList, install) { function writeGroups(file, moduleName, prefix, pathList, install) {
for(j in pathList) { for(j in pathList) {
file.write("\tGroup {\n" + file.write("\tGroup {\n" +
"\t\tname: \"" + prefix + (j > 0 ? j : "") + "\"\n" + "\t\tname: \"" + prefix + (j > 0 ? j : "") + "\"\n" +
"\t\tprefix: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "/\"\n" + "\t\tprefix: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "/\"\n" +
"\t\tfilesAreTargets: true\n"); "\t\tfilesAreTargets: true\n");
if (install) if (install)
file.write("\t\tqbs.install: product.conan." + moduleName + ".install" + (prefix.charAt(0).toUpperCase() + prefix.substring(1)) + "\n" + file.write("\t\tqbs.install: product.conan." + moduleName + ".install" + (prefix.charAt(0).toUpperCase() + prefix.substring(1)) + "\n" +
@ -104,15 +106,19 @@ ModuleProvider {
"\t\tqbs.installDir: product.conan." + moduleName + "." + prefix + "InstallDir\n" + "\t\tqbs.installDir: product.conan." + moduleName + "." + prefix + "InstallDir\n" +
"\t\tqbs.installSourceBase: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "\"\n"); "\t\tqbs.installSourceBase: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "\"\n");
file.write("\t\tfiles: product.conan." + moduleName + "." + prefix + "FilePatterns\n" + file.write("\t\tfiles: product.conan." + moduleName + "." + prefix + "FilePatterns\n");
"\t}\n");
if (prefix === "lib")
file.write("\t\tfileTags: [\"" + cppLibrariesTag + "\"]\n");
file.write("\t}\n");
} }
} }
writeGroups(moduleFile, moduleName, "bin", deps[i].bin_paths, true); writeGroups(moduleFile, moduleName, "bin", deps[i].bin_paths, true);
writeGroups(moduleFile, moduleName, "lib", deps[i].lib_paths, shared); writeGroups(moduleFile, moduleName, "lib", deps[i].lib_paths, shared);
writeGroups(moduleFile, moduleName, "res", deps[i].res_paths, true); writeGroups(moduleFile, moduleName, "res", deps[i].res_paths, true);
writeGroups(moduleFile, moduleName, "include", deps[i].include_paths, shared); writeGroups(moduleFile, moduleName, "include", Utils.filterUniqueRootPaths(deps[i].include_paths), shared);
moduleFile.writeLine("}"); moduleFile.writeLine("}");
moduleFile.close(); moduleFile.close();

View File

@ -0,0 +1,65 @@
var FileInfo = require("qbs.FileInfo");
function isValidAttributeName(name) {
// Check if the name starts with a letter, underscore, or dollar sign
if (!/^[a-zA-Z_$]/.test(name.charAt(0))) {
return false;
}
// Check for subsequent characters: letters, digits, underscores, or dollar signs
for (var i = 1; i < name.length; i++) {
if (!/^[0-9a-zA-Z_$]/.test(name.charAt(i))) {
return false;
}
}
// Check if the name is a reserved word
const reservedWords = [
'abstract', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const',
'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'export', 'extends',
'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import',
'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package',
'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized',
'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield'
];
if (reservedWords.includes(name)) {
return false;
}
// If all checks passed, the name is valid
return true;
}
function filterUniqueRootPaths(paths) {
if (paths.length < 2) {
return paths;
}
// Always compare canonocal paths
const canonicalPaths = paths.map(function(folder) {
return FileInfo.cleanPath(folder);
});
const isChildOf = function(child, parent) {
if (child === parent) return false;
var parentTokens = parent.split('/').filter(function(i) {
return i.length;
});
var childTokens = child.split('/').filter(function(i) {
return i.length;
});
return parentTokens.every(function(t, i) {
return childTokens[i] === t;
});
}
return canonicalPaths.filter(function(folder) {
return !canonicalPaths.some(function(otherFolder) {
return folder !== otherFolder && isChildOf(folder, otherFolder);
});
});
}

View File

@ -48,6 +48,18 @@ Module {
return project.enableConan; return project.enableConan;
} }
readonly property bool conanXercesEnabled : project.conanWithXerces
readonly property bool conanCrashReportingEnabled : {
if (qbs.targetOS.contains("windows")) {
if (qbs.toolchain.contains("msvc")) {
return project.conanWithCrashReporting;
} else {
return false;
}
} else {
return project.conanWithCrashReporting;
}
}
readonly property bool enableCodeSigning: project.enableSigning readonly property bool enableCodeSigning: project.enableSigning
@ -140,6 +152,9 @@ Module {
if (enableMultiBundle) if (enableMultiBundle)
defines.push('MULTI_BUNDLE'); defines.push('MULTI_BUNDLE');
if (useConanPackages && conanCrashReportingEnabled)
defines.push('CRASH_REPORTING');
return defines; return defines;
} }
@ -827,39 +842,6 @@ Module {
} }
} }
if (Utilities.versionCompare(qbs.version, "1.22") < 0)
{
var qtLibs = [
"QtCore",
"QtSvg",
"QtXml",
"QtPrintSupport",
"QtXmlPatterns",
"QtWidgets",
"QtGui",
"QtNetwork",
"QtTest",
"QtConcurrent"
];
if (!qbs.targetOS.contains("macos"))
{
paths.push(Qt.core.incPath);
for (var i = 0; i < qtLibs.length; i++) {
paths.push(FileInfo.joinPaths(Qt.core.incPath, qtLibs[i]));
}
} else {
for (var i = 0; i < qtLibs.length; i++) {
paths.push(FileInfo.joinPaths(Qt.core.incPath,
qtLibs[i] + ".framework/Versions/" + Qt.core.versionMajor +
"/Headers"));
paths.push(FileInfo.joinPaths(Qt.core.incPath, qtLibs[i] + ".framework/Headers"));
}
}
}
return paths; return paths;
} }
} }

View File

@ -7,11 +7,14 @@ import qbs.Utilities
Module { Module {
property string type: typeProbe.type property string type: typeProbe.type
property string repoDir: project.sourceDirectory property string repoDir: project.sourceDirectory
// TODO: If minimal qbs version is 1.23 replace with FileInfo.executableSuffix()
readonly property string executableSuffix: project.qbs.targetOS.contains("windows") ? ".exe" : ""
property string toolFilePath: { property string toolFilePath: {
if (type === "git") if (type === "git")
return "git"; return "git" + executableSuffix;
if (type === "svn") if (type === "svn")
return "svn"; return "svn" + executableSuffix;
} }
property string headerFileName: "vcs-repo-state.h" property string headerFileName: "vcs-repo-state.h"
@ -101,13 +104,14 @@ Module {
// 3. latest commit is gSHA // 3. latest commit is gSHA
proc.exec(tool, ["describe", "--always", "HEAD"], true); proc.exec(tool, ["describe", "--always", "HEAD"], true);
repoState = proc.readStdOut().trim(); repoState = proc.readStdOut().trim();
if (repoState) if (repoState) {
found = true; found = true;
const tagSections = repoState.split("-"); const tagSections = repoState.split("-");
repoStateTag = tagSections[0]; repoStateTag = tagSections[0];
repoStateDistance = tagSections[1]; repoStateDistance = tagSections[1];
repoStateRevision = tagSections[2]; repoStateRevision = tagSections[2];
}
} finally { } finally {
proc.close(); proc.close();
} }

View File

@ -1,23 +0,0 @@
#!/bin/sh
# This script helps run cppcheck with the same keys we have on codeship.com (except for key --platform=unix32).
# Please, run this script from folder <root_folder>/scripts.
# Because we use the last available cppcheck version usually we build it manually.
CPPCHECK="../../../../cppcheck-2.8/cppcheck"
$CPPCHECK \
-j4 -f -q \
-UDRW_DBG \
-U__INTEL_COMPILER_UPDATE \
--template '{file}:{line}:{message}:{id}' \
--inline-suppr \
--platform=unix64 \
--std=c++17 \
--enable=all \
--library=qt \
--library=std \
--library=posix \
--inconclusive \
--suppress=*:*/vdxf/libdxfrw/intern/make_unique.h \
--inconclusive \
--suppress=*:*/qmuparser/make_unique.h \
../src

View File

@ -1,75 +0,0 @@
rem script helps create installer
rem find target architecture
IF "%PROCESSOR_ARCHITECTURE%"=="x86" (set ARCHITECTURE=32BIT) else (set ARCHITECTURE=64BIT)
rem Path to Inno Setup according to architecture
if %ARCHITECTURE%==32BIT set nsis_path="C:/Program Files/Inno Setup 5/iscc.exe"
if %ARCHITECTURE%==64BIT set nsis_path="C:/Program Files (x86)/Inno Setup 5/iscc.exe"
if not exist %nsis_path% (
echo Coudn't find Inno Setup. Package will not be created.
)
:CONTINUE
rem detect windows version
ver | find "6.1" > nul
IF ERRORLEVEL = 1 GOTO PREPARE
IF ERRORLEVEL = 0 GOTO WIN7
:WIN7
chcp 65001
:PREPARE
cd ..
cd
rem force qmake create new qm files
del /Q share\translations\*.qm
IF exist build (
echo Build exists. Clearing.
rd /s /q build\package
del /s /q /f build\Makefile
del /s /q /f build\*.exe
del /s /q /f build\*.dll
del /q /f build\src\app\tape\obj\dialogabouttape.o
del /q /f build\src\app\valentina\obj\dialogaboutapp.o
)
mkdir build && echo build created
cd build
cd
qmake -r CONFIG+=noTests ..\Valentina.pro
IF ERRORLEVEL 1 GOTO ERRORQMAKE1
IF ERRORLEVEL 0 GOTO MAKE
:MAKE
mingw32-make -j%NUMBER_OF_PROCESSORS%
IF ERRORLEVEL 1 GOTO ERRORMAKE
IF ERRORLEVEL 0 GOTO MAKEINSTALL
:MAKEINSTALL
mingw32-make install
IF ERRORLEVEL 1 GOTO ERRORMAKEINSTALL
IF ERRORLEVEL 0 GOTO ONEXIT
:ERRORMAKEINSTALL
echo Failed to create installer!
@pause
exit /b 1
:ERRORMAKE
echo Failed to build project!
@pause
exit /b 1
:ERRORQMAKE2
echo Failed to make the second run qmake!
@pause
exit /b 1
:ERRORQMAKE1
echo Failed to make the first run qmake!
@pause
exit /b 1
:ONEXIT
echo Done!
@pause

View File

@ -1,27 +0,0 @@
#!/bin/sh
# Use the script to sign your app bundle on Mac OS X.
# Requirement Mac OS El Capitan or later.
# An app bundle must be in the same folder.
# Name of your certificate in look "Developer ID Application: <yourID>"
# Be sure that you use Developer ID certificate!
CERTIFICATE="Developer ID Application: <yourID>"
BUNDLE=Valentina.app
# all must be signed
#s ign all *.dylib
find $BUNDLE -name *.dylib | xargs -I $ codesign -f -v -v -vvvv --deep --strict -s "$CERTIFICATE" $
# sign Qt frameworks
find $BUNDLE -name Qt* -type f | xargs -I $ codesign -f -v -v -vvvv --deep --strict -s "$CERTIFICATE" $
# sign all binaries
find $BUNDLE -path */MacOS/* -type f | xargs -I $ codesign -f -v -v -vvvv --deep --strict -s "$CERTIFICATE" $
# sign the app bundle
codesign -f -v -v -vvvv --deep --strict -s "$CERTIFICATE" ./$BUNDLE
#verify in the end
codesign -v -vvvv ./$BUNDLE
spctl -a -t exec -vv ./$BUNDLE

158
scripts/symupload.py Normal file
View File

@ -0,0 +1,158 @@
import argparse
import os
import subprocess
import sys
import glob
import zipfile
database = "valentina"
def debug_extension():
platform = sys.platform
if platform == "darwin":
debug_ext = ".dSYM"
elif platform == "win32":
debug_ext = ".pdb"
elif platform == "linux":
debug_ext = ".debug"
else:
print(f"Unsupported platform {platform}")
return "uknown"
return debug_ext
def check_binary(binary):
# Check if binary file exists
if not os.path.exists(binary):
# If binary file doesn't exist, it may be part of a framework
framework_binary = os.path.basename(binary.replace(".framework", ""))
for root, dirs, files in os.walk(binary):
for file in files:
if file == framework_binary:
return os.path.join(root, file)
return binary
def zip_sym(sym_file):
zip_sym_file = sym_file + ".zip"
with zipfile.ZipFile(zip_sym_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
zipf.write(sym_file, os.path.basename(sym_file))
return zip_sym_file
def generate_sym_files(install_root):
sym_files = []
platform = sys.platform
debug_ext = debug_extension()
debug_files = glob.glob(os.path.join(install_root, "**", "*" + debug_ext), recursive=True)
for debug_file in debug_files:
print(f"Generating symbols for: {os.path.basename(debug_file)}")
if platform == "win32":
# For Windows, return the executable file
sym_file = os.path.splitext(debug_file)[0] + ".exe"
else:
sym_file = os.path.splitext(debug_file)[0] + ".sym"
if platform == "darwin":
binary = check_binary(os.path.splitext(debug_file)[0])
dump_syms_cmd = ["dump_syms", "-g", debug_file, binary]
elif platform == "linux":
dump_syms_cmd = ["dump_syms", debug_file]
with open(sym_file, "w") as f:
subprocess.run(dump_syms_cmd, check=True, stdout=f)
if platform == "linux":
# When symbols are dumped from a debug file Crashpad creates an incorrect module name.
sed_cmd = ["sed", "-i", "1s/.debug//", sym_file]
subprocess.run(sed_cmd, check=True)
sym_files.append((debug_file, zip_sym(sym_file)))
return sym_files
def generate_version_string(val_version, commit_hash, qt_version):
# Determine the platform
platform = sys.platform
if platform == "win32":
platform_str = "windows"
elif platform == "darwin":
platform_str = "macos"
elif platform == "linux":
platform_str = "linux"
else:
platform_str = "unknown"
# Generate the version string
version_string = f"{val_version}-{commit_hash}-Qt_{qt_version}-{platform_str}"
return version_string
def get_app_name(sym_file):
# Get the base name of the symbol file without extension
base_name = os.path.splitext(os.path.basename(sym_file))[0].lower()
# Determine the platform
platform = sys.platform
if platform == "linux":
if base_name.startswith("lib"):
base_name = base_name[3:]
return base_name.split(".so")[0]
elif platform == "darwin":
if base_name.endswith(".framework"):
return base_name.split(".framework")[0]
return base_name
def upload_symbols(install_root, val_version, commit_hash, qt_version, clean=False):
# Platform-specific commands for generating and uploading symbol files
platform = sys.platform
sym_files = generate_sym_files(install_root)
app_version = generate_version_string(val_version, commit_hash, qt_version)
print(f"Uploading symbols for version {app_version}")
for _, sym_file in sym_files:
app_name = get_app_name(sym_file)
print(f"Uploading symbols for application {app_name}")
if platform == "linux":
upload_cmd = ["sym_upload", sym_file, f"https://{database}.bugsplat.com/post/bp/symbol/breakpadsymbols.php?appName={app_name}&appVer={app_version}"]
elif platform == "darwin":
upload_cmd = ["symupload", sym_file, f"https://{database}.bugsplat.com/post/bp/symbol/breakpadsymbols.php?appName={app_name}&appVer={app_version}"]
elif platform == "win32":
upload_cmd = ["symupload.exe", "--product", app_name, sym_file, f"https://{database}.bugsplat.com/post/bp/symbol/breakpadsymbols.php?appName={app_name}&appVer={app_version}"]
try:
subprocess.run(upload_cmd, check=True)
print(f"Symbol file '{sym_file}' uploaded successfully.")
except subprocess.CalledProcessError as e:
print(f"Error: {e}")
# Cleanup if requested
if clean:
debug_ext = debug_extension()
for debug_file, sym_file in sym_files:
os.remove(sym_file)
print(f"Symbol file '{sym_file}' removed.")
os.remove(debug_file)
print(f"Debug file '{debug_file}' removed.")
if __name__ == "__main__":
# Command-line usage: python symupload.py /path/to/install_root/folder 0_7_52 abcdef123456 6_6 --clean
# - First argument: Path to the install root folder
# - Second argument: Valentina version
# - Third argument: Commit git hash
# - Fourth argument: Qt version
# - Optional argument: --clean (Clean up after upload)
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Upload symbols to BugSplat.")
parser.add_argument("install_root", type=str, help="Path to the installation folder")
parser.add_argument("val_version", type=str, help="Valentina version")
parser.add_argument("hash", type=str, help="Commit git hash")
parser.add_argument("qt_version", type=str, help="Qt version")
parser.add_argument("--clean", action="store_true", help="Clean up after upload")
args = parser.parse_args()
# Call install_package function with provided arguments
upload_symbols(args.install_root, args.val_version, args.hash, args.qt_version, args.clean)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -117,6 +117,21 @@ PuzzlePreferencesConfigurationPage::PuzzlePreferencesConfigurationPage(QWidget *
// Tab Privacy // Tab Privacy
ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic()); ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic());
#if !defined(CRASH_REPORTING)
ui->groupBoxCrashReports->setDisabled(true);
#endif
ui->checkBoxSendCrashReports->setChecked(settings->IsSendCrashReport());
connect(ui->checkBoxSendCrashReports, &QCheckBox::stateChanged, this,
[this]() { m_sendCrashReportsChanged = true; });
QRegularExpression const rx(QStringLiteral("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"),
QRegularExpression::CaseInsensitiveOption);
ui->lineEditCrashUserEmail->setValidator(new QRegularExpressionValidator(rx, this));
ui->lineEditCrashUserEmail->setText(settings->GetCrashEmail());
connect(ui->lineEditCrashUserEmail, &QLineEdit::editingFinished, this,
[this]() { m_crashUserEmailChanged = true; });
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -229,6 +244,22 @@ auto PuzzlePreferencesConfigurationPage::Apply() -> QStringList
settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked()); settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked());
VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked()); VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked());
#if defined(CRASH_REPORTING)
if (m_sendCrashReportsChanged)
{
settings->SeSendCrashReport(ui->checkBoxSendCrashReports->isChecked());
m_sendCrashReportsChanged = false;
preferences.append(tr("send crash report"));
}
if (m_crashUserEmailChanged)
{
settings->SetCrashEmail(ui->lineEditCrashUserEmail->text());
m_crashUserEmailChanged = false;
preferences.append(tr("user email in case of crash"));
}
#endif
return preferences; return preferences;
} }

View File

@ -57,6 +57,8 @@ private:
Q_DISABLE_COPY_MOVE(PuzzlePreferencesConfigurationPage) // NOLINT Q_DISABLE_COPY_MOVE(PuzzlePreferencesConfigurationPage) // NOLINT
std::unique_ptr<Ui::PuzzlePreferencesConfigurationPage> ui; std::unique_ptr<Ui::PuzzlePreferencesConfigurationPage> ui;
bool m_langChanged{false}; bool m_langChanged{false};
bool m_sendCrashReportsChanged{false};
bool m_crashUserEmailChanged{false};
QList<QStringList> m_transientShortcuts{}; QList<QStringList> m_transientShortcuts{};
void SetThemeModeComboBox(); void SetThemeModeComboBox();

View File

@ -522,22 +522,75 @@ This option will take an affect after restart.</string>
<attribute name="title"> <attribute name="title">
<string>Privacy</string> <string>Privacy</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_14">
<item> <item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics"> <widget class="QGroupBox" name="groupBox_12">
<property name="text"> <property name="title">
<string>Send usage statistics</string> <string>Usage statistic</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label"> <widget class="QGroupBox" name="groupBoxCrashReports">
<property name="text"> <property name="title">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string> <string>Crash reports</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QCheckBox" name="checkBoxSendCrashReports">
<property name="text">
<string>Send automatic crash reports</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditCrashUserEmail">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Reporting crash reports will help us make Valentina more reliable. All information is treated as confidential and is only used to improve future versions of this program. Please activate sending automatic crash reports and fill your email address (optional). If provided, we may contact you with additional information about the crash.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -35,6 +35,11 @@
#include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/PlatformUtils.hpp>
#endif #endif
#ifdef CRASH_REPORTING
#include "../vmisc/crashhandler/crashhandler.h"
#include "version.h"
#endif
// Fix bug in Qt. Deprecation warning in QMessageBox::critical. // Fix bug in Qt. Deprecation warning in QMessageBox::critical.
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
#undef QT_REQUIRE_VERSION #undef QT_REQUIRE_VERSION
@ -81,6 +86,10 @@ auto main(int argc, char *argv[]) -> int
Q_INIT_RESOURCE(win_light_theme); // NOLINT Q_INIT_RESOURCE(win_light_theme); // NOLINT
Q_INIT_RESOURCE(win_dark_theme); // NOLINT Q_INIT_RESOURCE(win_dark_theme); // NOLINT
#ifdef CRASH_REPORTING
InitializeCrashpad(QStringLiteral(VER_PRODUCTNAME_STR).toLower());
#endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
VAbstractApplication::WinAttachConsole(); VAbstractApplication::WinAttachConsole();
#endif #endif

View File

@ -36,11 +36,17 @@ VToolApp {
type: base.concat("install_root_svg_fonts") type: base.concat("install_root_svg_fonts")
Properties { Properties {
condition: buildconfig.useConanPackages && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle condition: buildconfig.useConanPackages && buildconfig.conanXercesEnabled && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle
conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath
conan.XercesC.installLib: true conan.XercesC.installLib: true
} }
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle
conan.crashpad.installBin: true
conan.crashpad.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath
}
files: [ files: [
"main.cpp", "main.cpp",
"vpapplication.cpp", "vpapplication.cpp",

View File

@ -4701,15 +4701,20 @@ void VPMainWindow::AskDefaultSettings()
} }
} }
if (settings->IsAskCollectStatistic()) if (settings->IsAskCollectStatistic() || settings->IsAskSendCrashReport())
{ {
DialogAskCollectStatistic dialog(this); DialogAskCollectStatistic dialog(this);
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
settings->SetCollectStatistic(dialog.CollectStatistic()); settings->SetCollectStatistic(dialog.CollectStatistic());
#if defined(CRASH_REPORTING)
settings->SeSendCrashReport(dialog.SendCrashReport());
settings->SetCrashEmail(dialog.UserEmail());
#endif
} }
settings->SetAskCollectStatistic(false); settings->SetAskCollectStatistic(false);
settings->SetAskSendCrashReport(false);
} }
if (settings->IsCollectStatistic()) if (settings->IsCollectStatistic())

View File

@ -115,6 +115,21 @@ TapePreferencesConfigurationPage::TapePreferencesConfigurationPage(QWidget *pare
// Tab Privacy // Tab Privacy
ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic()); ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic());
#if !defined(CRASH_REPORTING)
ui->groupBoxCrashReports->setDisabled(true);
#endif
ui->checkBoxSendCrashReports->setChecked(settings->IsSendCrashReport());
connect(ui->checkBoxSendCrashReports, &QCheckBox::stateChanged, this,
[this]() { m_sendCrashReportsChanged = true; });
QRegularExpression const rx(QStringLiteral("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"),
QRegularExpression::CaseInsensitiveOption);
ui->lineEditCrashUserEmail->setValidator(new QRegularExpressionValidator(rx, this));
ui->lineEditCrashUserEmail->setText(settings->GetCrashEmail());
connect(ui->lineEditCrashUserEmail, &QLineEdit::editingFinished, this,
[this]() { m_crashUserEmailChanged = true; });
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -202,6 +217,22 @@ auto TapePreferencesConfigurationPage::Apply() -> QStringList
settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked()); settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked());
VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked()); VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked());
#if defined(CRASH_REPORTING)
if (m_sendCrashReportsChanged)
{
settings->SeSendCrashReport(ui->checkBoxSendCrashReports->isChecked());
m_sendCrashReportsChanged = false;
preferences.append(tr("send crash report"));
}
if (m_crashUserEmailChanged)
{
settings->SetCrashEmail(ui->lineEditCrashUserEmail->text());
m_crashUserEmailChanged = false;
preferences.append(tr("user email in case of crash"));
}
#endif
return preferences; return preferences;
} }

View File

@ -61,6 +61,8 @@ private:
std::unique_ptr<Ui::TapePreferencesConfigurationPage> ui; std::unique_ptr<Ui::TapePreferencesConfigurationPage> ui;
bool m_langChanged; bool m_langChanged;
bool m_systemChanged; bool m_systemChanged;
bool m_sendCrashReportsChanged{false};
bool m_crashUserEmailChanged{false};
QList<QStringList> m_transientShortcuts{}; QList<QStringList> m_transientShortcuts{};
void RetranslateUi(); void RetranslateUi();

View File

@ -312,20 +312,73 @@
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_7"> <layout class="QVBoxLayout" name="verticalLayout_7">
<item> <item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics"> <widget class="QGroupBox" name="groupBox_10">
<property name="text"> <property name="title">
<string>Send usage statistics</string> <string>Usage statistic</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label"> <widget class="QGroupBox" name="groupBoxCrashReports">
<property name="text"> <property name="title">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string> <string>Crash reports</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QCheckBox" name="checkBoxSendCrashReports">
<property name="text">
<string>Send automatic crash reports</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditCrashUserEmail">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Reporting crash reports will help us make Valentina more reliable. All information is treated as confidential and is only used to improve future versions of this program. Please activate sending automatic crash reports and fill your email address (optional). If provided, we may contact you with additional information about the crash.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -35,6 +35,11 @@
#include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/PlatformUtils.hpp>
#endif #endif
#ifdef CRASH_REPORTING
#include "../vmisc/crashhandler/crashhandler.h"
#include "version.h"
#endif
// Fix bug in Qt. Deprecation warning in QMessageBox::critical. // Fix bug in Qt. Deprecation warning in QMessageBox::critical.
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
#undef QT_REQUIRE_VERSION #undef QT_REQUIRE_VERSION
@ -79,6 +84,10 @@ auto main(int argc, char *argv[]) -> int
Q_INIT_RESOURCE(win_light_theme); // NOLINT Q_INIT_RESOURCE(win_light_theme); // NOLINT
Q_INIT_RESOURCE(win_dark_theme); // NOLINT Q_INIT_RESOURCE(win_dark_theme); // NOLINT
#ifdef CRASH_REPORTING
InitializeCrashpad(QStringLiteral(VER_PRODUCTNAME_STR).toLower());
#endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
VAbstractApplication::WinAttachConsole(); VAbstractApplication::WinAttachConsole();
#endif #endif

View File

@ -18,12 +18,14 @@ VToolApp {
Depends { Depends {
name: "xerces-c"; name: "xerces-c";
condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && !buildconfig.useConanPackages condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 &&
(!buildconfig.useConanPackages || (buildconfig.useConanPackages && !buildconfig.conanXercesEnabled))
} }
Depends { Depends {
name: "conan.XercesC"; name: "conan.XercesC";
condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && buildconfig.useConanPackages condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && buildconfig.useConanPackages &&
buildconfig.conanXercesEnabled
} }
// Explicitly link to libcrypto and libssl to avoid error: Failed to load libssl/libcrypto. // Explicitly link to libcrypto and libssl to avoid error: Failed to load libssl/libcrypto.
@ -45,11 +47,17 @@ VToolApp {
multibundle.targetApps: ["Valentina"] multibundle.targetApps: ["Valentina"]
Properties { Properties {
condition: buildconfig.useConanPackages && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle condition: buildconfig.useConanPackages && buildconfig.conanXercesEnabled && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle
conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath
conan.XercesC.installLib: true conan.XercesC.installLib: true
} }
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled && qbs.targetOS.contains("macos") && buildconfig.enableMultiBundle
conan.crashpad.installBin: true
conan.crashpad.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath
}
files: [ files: [
"main.cpp", "main.cpp",
"tkmmainwindow.cpp", "tkmmainwindow.cpp",

View File

@ -1513,15 +1513,20 @@ void TKMMainWindow::AskDefaultSettings()
} }
} }
if (settings->IsAskCollectStatistic()) if (settings->IsAskCollectStatistic() || settings->IsAskSendCrashReport())
{ {
DialogAskCollectStatistic dialog(this); DialogAskCollectStatistic dialog(this);
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
settings->SetCollectStatistic(dialog.CollectStatistic()); settings->SetCollectStatistic(dialog.CollectStatistic());
#if defined(CRASH_REPORTING)
settings->SeSendCrashReport(dialog.SendCrashReport());
settings->SetCrashEmail(dialog.UserEmail());
#endif
} }
settings->SetAskCollectStatistic(false); settings->SetAskCollectStatistic(false);
settings->SetAskSendCrashReport(false);
} }
if (settings->IsCollectStatistic()) if (settings->IsCollectStatistic())

View File

@ -47,7 +47,7 @@ class VPatternImage;
class QCompleter; class QCompleter;
class QxtCsvModel; class QxtCsvModel;
class TKMMainWindow : public VAbstractMainWindow class TKMMainWindow final : public VAbstractMainWindow
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -68,7 +68,7 @@ protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto eventFilter(QObject *object, QEvent *event) -> bool override; auto eventFilter(QObject *object, QEvent *event) -> bool override;
void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) final; void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) override;
auto RecentFileList() const -> QStringList override; auto RecentFileList() const -> QStringList override;
private slots: private slots:

View File

@ -2777,15 +2777,20 @@ void TMainWindow::AskDefaultSettings()
} }
} }
if (settings->IsAskCollectStatistic()) if (settings->IsAskCollectStatistic() || settings->IsAskSendCrashReport())
{ {
DialogAskCollectStatistic dialog(this); DialogAskCollectStatistic dialog(this);
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
settings->SetCollectStatistic(dialog.CollectStatistic()); settings->SetCollectStatistic(dialog.CollectStatistic());
#if defined(CRASH_REPORTING)
settings->SeSendCrashReport(dialog.SendCrashReport());
settings->SetCrashEmail(dialog.UserEmail());
#endif
} }
settings->SetAskCollectStatistic(false); settings->SetAskCollectStatistic(false);
settings->SetAskSendCrashReport(false);
} }
if (settings->IsCollectStatistic()) if (settings->IsCollectStatistic())

View File

@ -52,7 +52,7 @@ class QAbstractButton;
class QUuid; class QUuid;
class VKnownMeasurements; class VKnownMeasurements;
class TMainWindow : public VAbstractMainWindow class TMainWindow final : public VAbstractMainWindow
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -80,7 +80,7 @@ protected:
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto eventFilter(QObject *object, QEvent *event) -> bool override; auto eventFilter(QObject *object, QEvent *event) -> bool override;
void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) final; void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) override;
auto RecentFileList() const -> QStringList override; auto RecentFileList() const -> QStringList override;
private slots: private slots:
@ -295,7 +295,7 @@ private:
void SetCurrentDimensionValues(); void SetCurrentDimensionValues();
auto DimensionRestrictedValues(int index, const MeasurementDimension_p &dimension) -> QVector<double>; auto DimensionRestrictedValues(int index, const MeasurementDimension_p &dimension) -> QVector<double>;
auto OrderedMeasurements() const -> QMap<int, QSharedPointer<VMeasurement>>; auto OrderedMeasurements() const -> QMap<int, QSharedPointer<VMeasurement>>;
void InitIcons(); void InitIcons();

View File

@ -29,9 +29,11 @@
#ifndef VERSION_H #ifndef VERSION_H
#define VERSION_H #define VERSION_H
#define VER_INTERNALNAME_STR "Tape" // NOLINT(cppcoreguidelines-macro-usage) #include "../../libs/vmisc/projectversion.h"
#define VER_ORIGINALFILENAME_STR "tape.exe" // NOLINT(cppcoreguidelines-macro-usage)
#define VER_PRODUCTNAME_STR "Tape" // NOLINT(cppcoreguidelines-macro-usage) #define VER_INTERNALNAME_STR "Tape" // NOLINT(cppcoreguidelines-macro-usage)
#define VER_FILEDESCRIPTION_STR "Valentina's measurements editor." // NOLINT(cppcoreguidelines-macro-usage) #define VER_ORIGINALFILENAME_STR "tape.exe" // NOLINT(cppcoreguidelines-macro-usage)
#define VER_PRODUCTNAME_STR "Tape" // NOLINT(cppcoreguidelines-macro-usage)
#define VER_FILEDESCRIPTION_STR "Valentina's measurements editor." // NOLINT(cppcoreguidelines-macro-usage)
#endif // VERSION_H #endif // VERSION_H

View File

@ -92,8 +92,6 @@ Q_LOGGING_CATEGORY(vApp, "v.application") // NOLINT
QT_WARNING_POP QT_WARNING_POP
Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3;
namespace namespace
{ {
auto AppFilePath(const QString &appName) -> QString auto AppFilePath(const QString &appName) -> QString
@ -537,38 +535,13 @@ auto VApplication::PuzzleFilePath() -> QString
return AppFilePath(appName); return AppFilePath(appName);
} }
//---------------------------------------------------------------------------------------------------------------------
auto VApplication::LogDirPath() -> QString
{
#if defined(Q_OS_WIN) || defined(Q_OS_OSX)
const QString logDirPath =
QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(), QStandardPaths::LocateDirectory) +
"Valentina";
#else
const QString logDirPath =
QStandardPaths::locate(QStandardPaths::ConfigLocation, QString(), QStandardPaths::LocateDirectory) +
QCoreApplication::organizationName();
#endif
return logDirPath;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto VApplication::LogPath() -> QString auto VApplication::LogPath() -> QString
{ {
// Keep in sync with VCrashPaths::GetAttachmentPath
return QStringLiteral("%1/valentina-pid%2.log").arg(LogDirPath()).arg(applicationPid()); return QStringLiteral("%1/valentina-pid%2.log").arg(LogDirPath()).arg(applicationPid());
} }
//---------------------------------------------------------------------------------------------------------------------
auto VApplication::CreateLogDir() -> bool
{
QDir const logDir(LogDirPath());
if (not logDir.exists())
{
return logDir.mkpath(QChar('.')); // Create directory for log if need
}
return true;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VApplication::BeginLogging() void VApplication::BeginLogging()
{ {
@ -594,58 +567,6 @@ void VApplication::BeginLogging()
} }
} }
//---------------------------------------------------------------------------------------------------------------------
void VApplication::ClearOldLogs()
{
const QString workingDirectory = QDir::currentPath(); // Save the app working directory
const QString logDirPath = LogDirPath();
QDir logsDir(logDirPath);
if (!logsDir.exists())
{
return;
}
logsDir.setNameFilters(QStringList(QStringLiteral("*.log")));
QDir::setCurrent(logDirPath);
// Restore working directory
auto restore = qScopeGuard([workingDirectory] { QDir::setCurrent(workingDirectory); });
const QStringList allFiles = logsDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
if (allFiles.isEmpty())
{
qCDebug(vApp, "There are no old logs.");
return;
}
qCDebug(vApp, "Clearing old logs");
for (const auto &fn : allFiles)
{
QFileInfo const info(fn);
const QDateTime created = info.birthTime();
if (created.daysTo(QDateTime::currentDateTime()) >= DAYS_TO_KEEP_LOGS)
{
VLockGuard<QFile> const tmp(info.absoluteFilePath(), [&fn]() { return new QFile(fn); });
if (tmp.GetProtected() != nullptr)
{
if (tmp.GetProtected()->remove())
{
qCDebug(vApp, "Deleted %s", qUtf8Printable(info.absoluteFilePath()));
}
else
{
qCDebug(vApp, "Could not delete %s", qUtf8Printable(info.absoluteFilePath()));
}
}
else
{
qCDebug(vApp, "Failed to lock %s", qUtf8Printable(info.absoluteFilePath()));
}
}
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
void VApplication::InitOptions() void VApplication::InitOptions()
{ {

View File

@ -101,11 +101,8 @@ private:
VKnownMeasurementsDatabase *m_knownMeasurementsDatabase{nullptr}; VKnownMeasurementsDatabase *m_knownMeasurementsDatabase{nullptr};
QFileSystemWatcher *m_knownMeasurementsDatabaseWatcher{nullptr}; QFileSystemWatcher *m_knownMeasurementsDatabaseWatcher{nullptr};
static auto LogDirPath() -> QString;
static auto LogPath() -> QString; static auto LogPath() -> QString;
static auto CreateLogDir() -> bool;
void BeginLogging(); void BeginLogging();
static void ClearOldLogs();
}; };
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -176,6 +176,21 @@ PreferencesConfigurationPage::PreferencesConfigurationPage(QWidget *parent)
// Tab Privacy // Tab Privacy
ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic()); ui->checkBoxSendUsageStatistics->setChecked(settings->IsCollectStatistic());
#if !defined(CRASH_REPORTING)
ui->groupBoxCrashReports->setDisabled(true);
#endif
ui->checkBoxSendCrashReports->setChecked(settings->IsSendCrashReport());
connect(ui->checkBoxSendCrashReports, &QCheckBox::stateChanged, this,
[this]() { m_sendCrashReportsChanged = true; });
QRegularExpression const rx(QStringLiteral("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"),
QRegularExpression::CaseInsensitiveOption);
ui->lineEditCrashUserEmail->setValidator(new QRegularExpressionValidator(rx, this));
ui->lineEditCrashUserEmail->setText(settings->GetCrashEmail());
connect(ui->lineEditCrashUserEmail, &QLineEdit::editingFinished, this,
[this]() { m_crashUserEmailChanged = true; });
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -306,6 +321,22 @@ auto PreferencesConfigurationPage::Apply() -> QStringList
settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked()); settings->SetCollectStatistic(ui->checkBoxSendUsageStatistics->isChecked());
VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked()); VGAnalytics::Instance()->Enable(ui->checkBoxSendUsageStatistics->isChecked());
#if defined(CRASH_REPORTING)
if (m_sendCrashReportsChanged)
{
settings->SeSendCrashReport(ui->checkBoxSendCrashReports->isChecked());
m_sendCrashReportsChanged = false;
preferences.append(tr("send crash report"));
}
if (m_crashUserEmailChanged)
{
settings->SetCrashEmail(ui->lineEditCrashUserEmail->text());
m_crashUserEmailChanged = false;
preferences.append(tr("user email in case of crash"));
}
#endif
return preferences; return preferences;
} }

View File

@ -60,6 +60,8 @@ private:
bool m_pieceLabelLangChanged{false}; bool m_pieceLabelLangChanged{false};
bool m_unitChanged{false}; bool m_unitChanged{false};
bool m_labelLangChanged{false}; bool m_labelLangChanged{false};
bool m_sendCrashReportsChanged{false};
bool m_crashUserEmailChanged{false};
QList<QStringList> m_transientShortcuts{}; QList<QStringList> m_transientShortcuts{};
void SetLabelComboBox(const QStringList &list); void SetLabelComboBox(const QStringList &list);

View File

@ -661,22 +661,75 @@
<attribute name="title"> <attribute name="title">
<string>Privacy</string> <string>Privacy</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout_9"> <layout class="QVBoxLayout" name="verticalLayout_11">
<item> <item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics"> <widget class="QGroupBox" name="groupBox_10">
<property name="text"> <property name="title">
<string>Send usage statistics</string> <string>Usage statistic</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_15"> <widget class="QGroupBox" name="groupBoxCrashReports">
<property name="text"> <property name="title">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string> <string>Crash reports</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QCheckBox" name="checkBoxSendCrashReports">
<property name="text">
<string>Send automatic crash reports</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditCrashUserEmail">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Reporting crash reports will help us make Valentina more reliable. All information is treated as confidential and is only used to improve future versions of this program. Please activate sending automatic crash reports and fill your email address (optional). If provided, we may contact you with additional information about the crash.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -39,6 +39,11 @@
#include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/PlatformUtils.hpp>
#endif #endif
#ifdef CRASH_REPORTING
#include "../vmisc/crashhandler/crashhandler.h"
#include "version.h"
#endif
// Fix bug in Qt. Deprecation warning in QMessageBox::critical. // Fix bug in Qt. Deprecation warning in QMessageBox::critical.
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
#undef QT_REQUIRE_VERSION #undef QT_REQUIRE_VERSION
@ -69,7 +74,6 @@
#endif #endif
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto main(int argc, char *argv[]) -> int auto main(int argc, char *argv[]) -> int
{ {
Q_INIT_RESOURCE(cursor); // NOLINT Q_INIT_RESOURCE(cursor); // NOLINT
@ -88,6 +92,10 @@ auto main(int argc, char *argv[]) -> int
Q_INIT_RESOURCE(win_light_theme); // NOLINT Q_INIT_RESOURCE(win_light_theme); // NOLINT
Q_INIT_RESOURCE(win_dark_theme); // NOLINT Q_INIT_RESOURCE(win_dark_theme); // NOLINT
#ifdef CRASH_REPORTING
InitializeCrashpad(QStringLiteral(VER_PRODUCTNAME_STR).toLower());
#endif
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
VAbstractApplication::WinAttachConsole(); VAbstractApplication::WinAttachConsole();
#endif #endif

View File

@ -4930,15 +4930,20 @@ void MainWindow::AskDefaultSettings()
} }
} }
if (settings->IsAskCollectStatistic()) if (settings->IsAskCollectStatistic() || settings->IsAskSendCrashReport())
{ {
DialogAskCollectStatistic dialog(this); DialogAskCollectStatistic dialog(this);
if (dialog.exec() == QDialog::Accepted) if (dialog.exec() == QDialog::Accepted)
{ {
settings->SetCollectStatistic(dialog.CollectStatistic()); settings->SetCollectStatistic(dialog.CollectStatistic());
#if defined(CRASH_REPORTING)
settings->SeSendCrashReport(dialog.SendCrashReport());
settings->SetCrashEmail(dialog.UserEmail());
#endif
} }
settings->SetAskCollectStatistic(false); settings->SetAskCollectStatistic(false);
settings->SetAskSendCrashReport(false);
} }
if (settings->IsCollectStatistic()) if (settings->IsCollectStatistic())

View File

@ -64,7 +64,7 @@ class VWidgetBackgroundImages;
/** /**
* @brief The MainWindow class main windows. * @brief The MainWindow class main windows.
*/ */
class MainWindow : public MainWindowsNoGUI class MainWindow final : public MainWindowsNoGUI
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -120,7 +120,7 @@ protected:
void customEvent(QEvent *event) override; void customEvent(QEvent *event) override;
void CleanLayout() override; void CleanLayout() override;
void PrepareSceneList(PreviewQuatilty quality) override; void PrepareSceneList(PreviewQuatilty quality) override;
void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) final; void ExportToCSVData(const QString &fileName, bool withHeader, int mib, const QChar &separator) override;
void ToolBarStyle(QToolBar *bar) const override; void ToolBarStyle(QToolBar *bar) const override;
private slots: private slots:
void ScaleChanged(qreal scale); void ScaleChanged(qreal scale);

View File

@ -51,7 +51,7 @@ VToolApp {
type: base.concat("install_root_svg_fonts") type: base.concat("install_root_svg_fonts")
Properties { Properties {
condition: buildconfig.useConanPackages && (qbs.targetOS.contains("windows") || qbs.targetOS.contains("macos")) condition: buildconfig.useConanPackages && buildconfig.conanXercesEnabled && (qbs.targetOS.contains("windows") || qbs.targetOS.contains("macos"))
conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath conan.XercesC.libInstallDir: qbs.installPrefix + "/" + buildconfig.installLibraryPath
conan.XercesC.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath conan.XercesC.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath
conan.XercesC.installLib: { conan.XercesC.installLib: {
@ -66,6 +66,12 @@ VToolApp {
} }
} }
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
conan.crashpad.installBin: true
conan.crashpad.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath
}
files: [ files: [
"main.cpp", "main.cpp",
"mainwindow.cpp", "mainwindow.cpp",

View File

@ -11,12 +11,14 @@ VLib {
Depends { Depends {
name: "xerces-c" name: "xerces-c"
condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && !buildconfig.useConanPackages condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 &&
(!buildconfig.useConanPackages || (buildconfig.useConanPackages && !buildconfig.conanXercesEnabled))
} }
Depends { Depends {
name: "conan.XercesC" name: "conan.XercesC"
condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && buildconfig.useConanPackages condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && buildconfig.useConanPackages &&
buildconfig.conanXercesEnabled
} }
name: "IFCLib" name: "IFCLib"
@ -102,8 +104,11 @@ VLib {
Depends { name: "cpp" } Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["core", "xml"] } Depends { name: "Qt"; submodules: ["core", "xml"] }
Depends { name: "VMiscLib" } Depends { name: "VMiscLib" }
Depends { name: "xerces-c"; condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && !buildconfig.useConanPackages } Depends { name: "xerces-c"; condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 &&
Depends { name: "conan.XercesC"; condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 && buildconfig.useConanPackages } (!buildconfig.useConanPackages ||
(buildconfig.useConanPackages && !buildconfig.conanXercesEnabled)) }
Depends { name: "conan.XercesC"; condition: Utilities.versionCompare(Qt.core.version, "6") >= 0 &&
buildconfig.useConanPackages && buildconfig.conanXercesEnabled }
cpp.includePaths: [exportingProduct.sourceDirectory] cpp.includePaths: [exportingProduct.sourceDirectory]
} }
} }

View File

@ -0,0 +1,251 @@
/************************************************************************
**
** @file crashhandler.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 4 3, 2024
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2024 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "crashhandler.h"
#if defined(Q_OS_WIN)
#define NOMINMAX
#include <windows.h>
#endif
#if defined(Q_OS_MAC)
#include <mach-o/dyld.h>
#endif
#if defined(Q_OS_LINUX)
#include <QDir>
#include <QMap>
#include <unistd.h>
#define MIN(x, y) (((x) < (y)) ? (x) : (y)) // NOLINT
#endif
#include <client/crash_report_database.h>
#include <client/crashpad_client.h>
#include <client/settings.h>
#include "vcrashpaths.h"
#include "../projectversion.h"
#include "../vcommonsettings.h"
#if defined(APPIMAGE) && defined(Q_OS_LINUX)
#include "../appimage.h"
#endif
#include <vcsRepoState.h>
using namespace base;
using namespace crashpad;
namespace
{
//---------------------------------------------------------------------------------------------------------------------
Q_REQUIRED_RESULT auto AppSettings(const QString &appName) -> VCommonSettings *
{
return new VCommonSettings(QSettings::IniFormat, QSettings::UserScope, QStringLiteral(VER_COMPANYNAME_STR),
appName);
}
//---------------------------------------------------------------------------------------------------------------------
auto AppCrashVersion() -> QString
{
QString const version = QStringLiteral("%1_%2_%3").arg(MAJOR_VERSION).arg(MINOR_VERSION).arg(DEBUG_VERSION);
QString const qtVersion = QStringLiteral("Qt_%1_%2").arg(QT_VERSION_MAJOR).arg(QT_VERSION_MINOR);
#if defined(Q_OS_MACOS)
QString const platform = QStringLiteral("macos");
#elif defined(Q_OS_WIN)
QString const platform = QStringLiteral("windows");
#elif defined(Q_OS_LINUX)
QString const platform = QStringLiteral("linux");
#else
QString const platform = QStringLiteral("unknown");
#endif
return QStringLiteral("%1-%2-%3-%4").arg(version, VCS_REPO_STATE_REVISION, qtVersion, platform);
}
//---------------------------------------------------------------------------------------------------------------------
auto GetExecutableDir() -> QString
{
#if defined(Q_OS_MAC)
unsigned int bufferSize = 512;
std::vector<char> buffer(bufferSize + 1);
if (_NSGetExecutablePath(&buffer[0], &bufferSize))
{
buffer.resize(bufferSize);
_NSGetExecutablePath(&buffer[0], &bufferSize);
}
char *lastForwardSlash = strrchr(&buffer[0], '/');
if (lastForwardSlash == nullptr)
{
return nullptr;
}
*lastForwardSlash = 0;
return &buffer[0];
#elif defined(Q_OS_WINDOWS)
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
DWORD retVal = GetModuleFileNameW(hModule, path, MAX_PATH);
if (retVal == 0)
{
return nullptr;
}
wchar_t *lastBackslash = wcsrchr(path, '\\');
if (lastBackslash == nullptr)
{
return nullptr;
}
*lastBackslash = 0;
return QString::fromWCharArray(path);
#elif defined(Q_OS_LINUX)
char pBuf[FILENAME_MAX];
int len = sizeof(pBuf);
int bytes = MIN(static_cast<int>(readlink("/proc/self/exe", pBuf, static_cast<size_t>(len))), len - 1);
if (bytes >= 0)
{
pBuf[bytes] = '\0';
}
char *lastForwardSlash = strrchr(&pBuf[0], '/');
if (lastForwardSlash == nullptr)
{
return nullptr;
}
*lastForwardSlash = '\0';
return QString::fromStdString(pBuf);
#else
#error GetExecutableDir not implemented on this platform
#endif
}
} // namespace
//---------------------------------------------------------------------------------------------------------------------
auto InitializeCrashpad(const QString &appName) -> bool
{
QScopedPointer<VCommonSettings> const appSettings(AppSettings(appName));
if (!appSettings->IsSendCrashReport())
{
return true;
}
// Get directory where the exe lives so we can pass a full path to handler, reportsDir and metricsDir
#if defined(APPIMAGE) && defined(Q_OS_LINUX)
QString const exeDir = AppImageRoot(GetExecutableDir(), QString(BINDIR));
#else
QString const exeDir = GetExecutableDir();
#endif
// Helper class for cross-platform file systems
VCrashPaths crashpadPaths(exeDir);
auto MakeDir = [](const QString &path)
{
QDir const directory(path);
if (not directory.exists())
{
directory.mkpath(QChar('.'));
}
};
// Directory where reports will be saved. Important! Must be writable or crashpad_handler will crash.
QString const reportsPath = VCrashPaths::GetReportsPath();
MakeDir(reportsPath);
FilePath const reportsDir(VCrashPaths::GetPlatformString(reportsPath));
// Initialize crashpad database
std::unique_ptr<CrashReportDatabase> database = CrashReportDatabase::Initialize(reportsDir);
if (database == nullptr)
{
return false;
}
// Enable automated crash uploads
Settings *settings = database->GetSettings();
if (settings == nullptr)
{
return false;
}
settings->SetUploadsEnabled(true);
// Attachments to be uploaded alongside the crash - default bundle size limit is 20MB
std::vector<FilePath> attachments;
FilePath const attachment(VCrashPaths::GetPlatformString(VCrashPaths::GetAttachmentPath(appName)));
#if defined(Q_OS_WINDOWS) || defined(Q_OS_LINUX)
// Crashpad hasn't implemented attachments on OS X yet
attachments.push_back(attachment);
#endif
// Ensure that crashpad_handler is shipped with your application
FilePath const handler(VCrashPaths::GetPlatformString(crashpadPaths.GetHandlerPath()));
// Directory where metrics will be saved. Important! Must be writable or crashpad_handler will crash.
QString const metricsPath = VCrashPaths::GetMetricsPath();
MakeDir(metricsPath);
FilePath const metricsDir(VCrashPaths::GetPlatformString(metricsPath));
QString const dbName = QStringLiteral("valentina");
// Configure url with your BugSplat database
QString const url = QStringLiteral("https://%1.bugsplat.com/post/bp/crash/crashpad.php").arg(dbName);
// Metadata that will be posted to BugSplat
QMap<std::string, std::string> annotations;
annotations["format"] = "minidump"; // Required: Crashpad setting to save crash as a minidump
annotations["database"] = dbName.toStdString(); // Required: BugSplat database
annotations["product"] = appName.toStdString(); // Required: BugSplat appName
annotations["version"] = AppCrashVersion().toStdString(); // Required: BugSplat appVersion
QString clientID = appSettings->GetClientID();
if (clientID.isEmpty())
{
clientID = QUuid::createUuid().toString();
appSettings->SetClientID(clientID);
}
annotations["key"] = clientID.toStdString(); // Optional: BugSplat key field
QString const userEmail = appSettings->GetCrashEmail();
if (!userEmail.isEmpty())
{
annotations["user"] = userEmail.toStdString(); // Optional: BugSplat user email
}
// Disable crashpad rate limiting so that all crashes have dmp files
std::vector<std::string> arguments;
arguments.emplace_back("--no-rate-limit");
// Start crash handler
auto *client = new CrashpadClient();
return client->StartHandler(handler, reportsDir, metricsDir, url.toStdString(), annotations.toStdMap(), arguments,
true, true, attachments);
}

View File

@ -0,0 +1,35 @@
/************************************************************************
**
** @file crashhandler.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 4 3, 2024
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2024 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef CRASHHANDLER_H
#define CRASHHANDLER_H
#include <QString>
auto InitializeCrashpad(const QString &appName) -> bool;
#endif // CRASHHANDLER_H

View File

@ -0,0 +1,91 @@
/************************************************************************
**
** @file vcrashpaths.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 4 3, 2024
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2024 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include <QCoreApplication>
#include <QDir>
#include <QStandardPaths>
#include <utility>
#include "../projectversion.h"
#include "vcrashpaths.h"
//---------------------------------------------------------------------------------------------------------------------
VCrashPaths::VCrashPaths(QString exeDir)
: m_exeDir(std::move(exeDir))
{
}
//---------------------------------------------------------------------------------------------------------------------
auto VCrashPaths::GetAttachmentPath(const QString &appName) -> QString
{
const QString logDirPath =
QStandardPaths::locate(QStandardPaths::ConfigLocation, QString(), QStandardPaths::LocateDirectory) +
QStringLiteral(VER_COMPANYNAME_STR);
return QStringLiteral("%1/%2-pid%3.log").arg(logDirPath, appName.toLower()).arg(QCoreApplication::applicationPid());
}
//---------------------------------------------------------------------------------------------------------------------
auto VCrashPaths::GetHandlerPath() -> QString
{
#if defined(Q_OS_WINDOWS)
const QString handler = QStringLiteral("crashpad_handler.exe");
#elif defined(Q_OS_MAC) || defined(Q_OS_LINUX)
const QString handler = QStringLiteral("crashpad_handler");
#else
#error GetHandlerPath not implemented on this platform
#endif
return m_exeDir + QDir::separator() + handler;
}
//---------------------------------------------------------------------------------------------------------------------
auto VCrashPaths::GetReportsPath() -> QString
{
return QStandardPaths::locate(QStandardPaths::AppConfigLocation, QString(), QStandardPaths::LocateDirectory) +
QStringList{VER_COMPANYNAME_STR, "User Data", "Crashpad", "Reports"}.join(QDir::separator());
}
//---------------------------------------------------------------------------------------------------------------------
auto VCrashPaths::GetMetricsPath() -> QString
{
return QStandardPaths::locate(QStandardPaths::AppConfigLocation, QString(), QStandardPaths::LocateDirectory) +
QStringList{VER_COMPANYNAME_STR, "User Data", "Crashpad", "Metrics"}.join(QDir::separator());
}
//---------------------------------------------------------------------------------------------------------------------
#if defined(Q_OS_UNIX)
auto VCrashPaths::GetPlatformString(const QString &string) -> std::string
{
return string.toStdString();
}
#elif defined(Q_OS_WINDOWS)
auto VCrashPaths::GetPlatformString(const QString &string) -> std::wstring
{
return string.toStdWString();
}
#else
#error GetPlatformString not implemented on this platform
#endif

View File

@ -0,0 +1,56 @@
/************************************************************************
**
** @file vcrashpaths.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 4 3, 2024
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2024 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Valentina 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VCRASHPATHS_H
#define VCRASHPATHS_H
#include <QString>
class VCrashPaths
{
public:
explicit VCrashPaths(QString exeDir);
auto GetHandlerPath() -> QString;
static auto GetAttachmentPath(const QString &appName) -> QString;
static auto GetReportsPath() -> QString;
static auto GetMetricsPath() -> QString;
#if defined(Q_OS_UNIX)
static auto GetPlatformString(const QString &string) -> std::string;
#elif defined(Q_OS_WINDOWS)
static auto GetPlatformString(QString string) -> std::wstring;
#else
#error GetPlatformString not implemented on this platform
#endif
private:
QString m_exeDir;
};
#endif // VCRASHPATHS_H

View File

@ -28,12 +28,28 @@
#include "dialogaskcollectstatistic.h" #include "dialogaskcollectstatistic.h"
#include "ui_dialogaskcollectstatistic.h" #include "ui_dialogaskcollectstatistic.h"
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include "../vabstractapplication.h"
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
DialogAskCollectStatistic::DialogAskCollectStatistic(QWidget *parent) DialogAskCollectStatistic::DialogAskCollectStatistic(QWidget *parent)
: QDialog(parent), : QDialog(parent),
ui(new Ui::DialogAskCollectStatistic) ui(new Ui::DialogAskCollectStatistic)
{ {
ui->setupUi(this); ui->setupUi(this);
#if !defined(CRASH_REPORTING)
ui->groupBoxCrashReports->setDisabled(true);
#endif
VCommonSettings *settings = VAbstractApplication::VApp()->Settings();
QRegularExpression const rx(QStringLiteral("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"),
QRegularExpression::CaseInsensitiveOption);
ui->lineEditCrashUserEmail->setValidator(new QRegularExpressionValidator(rx, this));
ui->lineEditCrashUserEmail->setText(settings->GetCrashEmail());
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
@ -43,7 +59,19 @@ DialogAskCollectStatistic::~DialogAskCollectStatistic()
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto DialogAskCollectStatistic::CollectStatistic() -> bool auto DialogAskCollectStatistic::CollectStatistic() const -> bool
{ {
return ui->checkBoxSendUsageStatistics->isChecked(); return ui->checkBoxSendUsageStatistics->isChecked();
} }
//---------------------------------------------------------------------------------------------------------------------
auto DialogAskCollectStatistic::SendCrashReport() const -> bool
{
return ui->checkBoxSendCrashReports->isChecked();
}
//---------------------------------------------------------------------------------------------------------------------
auto DialogAskCollectStatistic::UserEmail() const -> QString
{
return ui->lineEditCrashUserEmail->text();
}

View File

@ -44,7 +44,9 @@ public:
explicit DialogAskCollectStatistic(QWidget *parent = nullptr); explicit DialogAskCollectStatistic(QWidget *parent = nullptr);
~DialogAskCollectStatistic() override; ~DialogAskCollectStatistic() override;
auto CollectStatistic() -> bool; auto CollectStatistic() const -> bool;
auto SendCrashReport() const -> bool;
auto UserEmail() const -> QString;
private: private:
Q_DISABLE_COPY_MOVE(DialogAskCollectStatistic) // NOLINT Q_DISABLE_COPY_MOVE(DialogAskCollectStatistic) // NOLINT

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>376</width> <width>593</width>
<height>183</height> <height>406</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -19,23 +19,79 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics"> <widget class="QGroupBox" name="groupBox_12">
<property name="text"> <property name="title">
<string>Send usage statistics</string> <string>Usage statistic</string>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="text">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label"> <widget class="QGroupBox" name="groupBoxCrashReports">
<property name="text"> <property name="title">
<string>Please help to improve Valentina's quality by automatically sending usage statistics. Sent data contains &lt;span style=&quot; font-weight:700;&quot;&gt;no potentially sensitive information&lt;/span&gt; like user names, email addresses, file contents or file paths.</string> <string>Crash reports</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QCheckBox" name="checkBoxSendCrashReports">
<property name="text">
<string>Send automatic crash reports</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Email:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditCrashUserEmail">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Reporting crash reports will help us make Valentina more reliable. All information is treated as confidential and is only used to improve future versions of this program. Please activate sending automatic crash reports and fill your email address (optional). If provided, we may contact you with additional information about the crash.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -58,7 +58,7 @@ constexpr inline auto AppVersion() -> unsigned
#define VER_PRODUCTVERSION VER_FILEVERSION #define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR #define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#define VER_COMPANYNAME_STR "ValentinaTeam" #define VER_COMPANYNAME_STR "Valentina"
// #define VER_FILEDESCRIPTION_STR "Patternmaking program." // Defined in program // #define VER_FILEDESCRIPTION_STR "Patternmaking program." // Defined in program
// #define VER_INTERNALNAME_STR "Valentina" // Defined in program // #define VER_INTERNALNAME_STR "Valentina" // Defined in program
#define VER_LEGALCOPYRIGHT_STR "Copyright © 2014-2022 Valentina Team" #define VER_LEGALCOPYRIGHT_STR "Copyright © 2014-2022 Valentina Team"

View File

@ -30,6 +30,7 @@
#include "compatibility.h" #include "compatibility.h"
#include "svgfont/vsvgfontdatabase.h" #include "svgfont/vsvgfontdatabase.h"
#include "vlockguard.h"
#include "vtranslator.h" #include "vtranslator.h"
#include "QtConcurrent/qtconcurrentrun.h" #include "QtConcurrent/qtconcurrentrun.h"
@ -67,6 +68,8 @@ using namespace Qt::Literals::StringLiterals;
namespace namespace
{ {
Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3;
auto FilterLocales(const QStringList &locales) -> QStringList auto FilterLocales(const QStringList &locales) -> QStringList
{ {
QStringList filtered; QStringList filtered;
@ -625,3 +628,75 @@ void VAbstractApplication::InitHighDpiScaling(int argc, char *argv[])
Q_UNUSED(argv); Q_UNUSED(argv);
#endif #endif
} }
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractApplication::LogDirPath() -> QString
{
const QString logDirPath =
QStandardPaths::locate(QStandardPaths::ConfigLocation, QString(), QStandardPaths::LocateDirectory) +
QCoreApplication::organizationName();
return logDirPath;
}
//---------------------------------------------------------------------------------------------------------------------
auto VAbstractApplication::CreateLogDir() -> bool
{
QDir const logDir(LogDirPath());
if (not logDir.exists())
{
return logDir.mkpath(QChar('.')); // Create directory for log if need
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
void VAbstractApplication::ClearOldLogs()
{
const QString workingDirectory = QDir::currentPath(); // Save the app working directory
const QString logDirPath = LogDirPath();
QDir logsDir(logDirPath);
if (!logsDir.exists())
{
return;
}
logsDir.setNameFilters(QStringList(QStringLiteral("*.log")));
QDir::setCurrent(logDirPath);
// Restore working directory
auto restore = qScopeGuard([workingDirectory] { QDir::setCurrent(workingDirectory); });
const QStringList allFiles = logsDir.entryList(QDir::NoDotAndDotDot | QDir::Files);
if (allFiles.isEmpty())
{
qDebug("There are no old logs.");
return;
}
qDebug("Clearing old logs");
for (const auto &fn : allFiles)
{
QFileInfo const info(fn);
const QDateTime created = info.birthTime();
if (created.daysTo(QDateTime::currentDateTime()) >= DAYS_TO_KEEP_LOGS)
{
VLockGuard<QFile> const tmp(info.absoluteFilePath(), [&fn]() { return new QFile(fn); });
if (tmp.GetProtected() != nullptr)
{
if (tmp.GetProtected()->remove())
{
qDebug("Deleted %s", qUtf8Printable(info.absoluteFilePath()));
}
else
{
qDebug("Could not delete %s", qUtf8Printable(info.absoluteFilePath()));
}
}
else
{
qDebug("Failed to lock %s", qUtf8Printable(info.absoluteFilePath()));
}
}
}
}

View File

@ -123,6 +123,10 @@ public:
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, hicpp-avoid-c-arrays, modernize-avoid-c-arrays) // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, hicpp-avoid-c-arrays, modernize-avoid-c-arrays)
static void InitHighDpiScaling(int argc, char *argv[]); static void InitHighDpiScaling(int argc, char *argv[]);
static auto LogDirPath() -> QString;
static auto CreateLogDir() -> bool;
static void ClearOldLogs();
protected: protected:
QUndoStack *undoStack; QUndoStack *undoStack;

View File

@ -131,6 +131,13 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingConfigurationInteractiveTools, (
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingConfigurationDontUseNativeDialog, Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingConfigurationDontUseNativeDialog,
("configuration/dontUseNativeDialog"_L1)) ("configuration/dontUseNativeDialog"_L1))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingsConfigurationCrashEmail, ("configuration/crashEmail"_L1)) // NOLINT
// NOLINTNEXTLINE
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingsConfigurationSendCrashReport, ("configuration/sendCrashReport"_L1))
// NOLINTNEXTLINE
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingsConfigurationAskSendCrashReport,
("configuration/askSendCrashReport"_L1))
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternUndo, ("pattern/undo"_L1)) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternUndo, ("pattern/undo"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternForbidFlipping, ("pattern/forbidFlipping"_L1)) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternForbidFlipping, ("pattern/forbidFlipping"_L1)) // NOLINT
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternForceFlipping, ("pattern/forceFlipping"_L1)) // NOLINT Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternForceFlipping, ("pattern/forceFlipping"_L1)) // NOLINT
@ -1698,3 +1705,48 @@ void VCommonSettings::SetActionShortcuts(const QString &name, const QStringList
settings.setValue(name, shortcuts); settings.setValue(name, shortcuts);
settings.sync(); settings.sync();
} }
//---------------------------------------------------------------------------------------------------------------------
auto VCommonSettings::GetCrashEmail() const -> QString
{
QSettings const settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
return settings.value(*settingsConfigurationCrashEmail, QString()).toString();
}
//---------------------------------------------------------------------------------------------------------------------
void VCommonSettings::SetCrashEmail(const QString &value)
{
QSettings settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
settings.setValue(*settingsConfigurationCrashEmail, value);
settings.sync();
}
//---------------------------------------------------------------------------------------------------------------------
auto VCommonSettings::IsSendCrashReport() const -> bool
{
QSettings const settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
return settings.value(*settingsConfigurationSendCrashReport, 1).toBool();
}
//---------------------------------------------------------------------------------------------------------------------
void VCommonSettings::SeSendCrashReport(bool value)
{
QSettings settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
settings.setValue(*settingsConfigurationSendCrashReport, value);
settings.sync();
}
//---------------------------------------------------------------------------------------------------------------------
auto VCommonSettings::IsAskSendCrashReport() const -> bool
{
QSettings const settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
return settings.value(*settingsConfigurationAskSendCrashReport, 1).toBool();
}
//---------------------------------------------------------------------------------------------------------------------
void VCommonSettings::SetAskSendCrashReport(bool value)
{
QSettings settings(this->format(), this->scope(), this->organizationName(), *commonIniFilename);
settings.setValue(*settingsConfigurationAskSendCrashReport, value);
settings.sync();
}

View File

@ -349,6 +349,15 @@ public:
auto GetActionShortcuts(const QString &name, const QStringList &defaultShortcuts) -> QStringList; auto GetActionShortcuts(const QString &name, const QStringList &defaultShortcuts) -> QStringList;
void SetActionShortcuts(const QString &name, const QStringList &shortcuts); void SetActionShortcuts(const QString &name, const QStringList &shortcuts);
auto GetCrashEmail() const -> QString;
void SetCrashEmail(const QString &value);
auto IsSendCrashReport() const -> bool;
void SeSendCrashReport(bool value);
auto IsAskSendCrashReport() const -> bool;
void SetAskSendCrashReport(bool value);
signals: signals:
void SVGFontsPathChanged(const QString &oldPath, const QString &newPath); void SVGFontsPathChanged(const QString &oldPath, const QString &newPath);
void KnownMeasurementsPathChanged(const QString &oldPath, const QString &newPath); void KnownMeasurementsPathChanged(const QString &oldPath, const QString &newPath);

View File

@ -2,6 +2,12 @@ import qbs.Utilities
VLib { VLib {
Depends { name: "Qt"; submodules: ["core", "printsupport", "gui", "widgets"] } Depends { name: "Qt"; submodules: ["core", "printsupport", "gui", "widgets"] }
Depends { name: "buildconfig" }
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
name: "VMiscLib" name: "VMiscLib"
files: { files: {
@ -178,9 +184,25 @@ VLib {
condition: qbs.targetOS.contains("macos") condition: qbs.targetOS.contains("macos")
} }
Group {
name: "crashhandler"
prefix: "crashhandler/"
files: [
"crashhandler.h",
"crashhandler.cpp",
"vcrashpaths.cpp",
"vcrashpaths.h",
]
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
Export { Export {
Depends { name: "cpp" } Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["printsupport", "widgets"] } Depends { name: "Qt"; submodules: ["printsupport", "widgets"] }
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
cpp.includePaths: [exportingProduct.sourceDirectory] cpp.includePaths: [exportingProduct.sourceDirectory]
} }
} }

View File

@ -152,7 +152,7 @@ auto PassmarkAngle(const VPiecePassmarkData &passmarkData, qreal angle) -> qreal
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
auto PassmarkWidth(const VPiecePassmarkData &passmarkData, qreal width) -> qreal auto PassmarkWidth(const VPiecePassmarkData &passmarkData, qreal width) -> qreal
{ {
auto ValidateWidth = [passmarkData](qreal width) auto ValidateWidth = [&passmarkData](qreal width)
{ {
if (qAbs(width) <= accuracyPointOnLine) if (qAbs(width) <= accuracyPointOnLine)
{ {

View File

@ -1,6 +1,7 @@
VDynamicLib { VDynamicLib {
Depends { name: "Qt"; submodules: ["gui", "widgets"] } Depends { name: "Qt"; submodules: ["gui", "widgets"] }
Depends { name: "VMiscLib" } Depends { name: "VMiscLib" }
Depends { name: "IFCLib" }
Depends { name: "multibundle"; } Depends { name: "multibundle"; }
name: "VPropertyExplorerLib" name: "VPropertyExplorerLib"

View File

@ -105,7 +105,7 @@ signals:
void DialogApplied(); void DialogApplied();
protected: protected:
virtual auto IsValid() const -> bool final; virtual auto IsValid() const -> bool;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void showEvent(QShowEvent *event) override; void showEvent(QShowEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;

View File

@ -96,7 +96,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogAlongLine) // NOLINT Q_DISABLE_COPY_MOVE(DialogAlongLine) // NOLINT

View File

@ -103,7 +103,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ValidateAlias(); void ValidateAlias();

View File

@ -99,7 +99,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ValidateAlias(); void ValidateAlias();

View File

@ -98,7 +98,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogBisector) // NOLINT Q_DISABLE_COPY_MOVE(DialogBisector) // NOLINT

View File

@ -44,12 +44,13 @@ namespace Ui
class DialogCubicBezier; class DialogCubicBezier;
} }
class DialogCubicBezier : public DialogTool class DialogCubicBezier final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
explicit DialogCubicBezier(const VContainer *data, VAbstractPattern *doc, quint32 toolId, QWidget *parent = nullptr); explicit DialogCubicBezier(const VContainer *data, VAbstractPattern *doc, quint32 toolId,
QWidget *parent = nullptr);
~DialogCubicBezier() override; ~DialogCubicBezier() override;
auto GetSpline() const -> VCubicBezier; auto GetSpline() const -> VCubicBezier;
@ -68,7 +69,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ValidateAlias(); void ValidateAlias();

View File

@ -45,7 +45,7 @@ namespace Ui
class DialogCubicBezierPath; class DialogCubicBezierPath;
} }
class DialogCubicBezierPath : public DialogTool class DialogCubicBezierPath final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -67,7 +67,7 @@ public slots:
protected: protected:
void ShowVisualization() override; void ShowVisualization() override;
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void PointChanged(int row); void PointChanged(int row);

View File

@ -93,7 +93,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ValidateAlias(); void ValidateAlias();

View File

@ -92,7 +92,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ArcChanged(); void ArcChanged();

View File

@ -90,7 +90,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void SplineChanged(); void SplineChanged();

View File

@ -90,7 +90,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void SplinePathChanged(); void SplinePathChanged();

View File

@ -42,7 +42,7 @@ namespace Ui
class DialogEllipticalArc; class DialogEllipticalArc;
} }
class DialogEllipticalArc : public DialogTool class DialogEllipticalArc final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -110,7 +110,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void ValidateAlias(); void ValidateAlias();

View File

@ -45,7 +45,7 @@ class DialogEndLine;
/** /**
* @brief The DialogEndLine class dialog for ToolEndLine. Help create point and edit option. * @brief The DialogEndLine class dialog for ToolEndLine. Help create point and edit option.
*/ */
class DialogEndLine : public DialogTool class DialogEndLine final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -97,7 +97,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogEndLine) // NOLINT Q_DISABLE_COPY_MOVE(DialogEndLine) // NOLINT

View File

@ -46,12 +46,13 @@ namespace Ui
class DialogFlippingByAxis; class DialogFlippingByAxis;
} }
class DialogFlippingByAxis : public DialogTool class DialogFlippingByAxis final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
explicit DialogFlippingByAxis(const VContainer *data, VAbstractPattern *doc, quint32 toolId, QWidget *parent = nullptr); explicit DialogFlippingByAxis(const VContainer *data, VAbstractPattern *doc, quint32 toolId,
QWidget *parent = nullptr);
~DialogFlippingByAxis() override; ~DialogFlippingByAxis() override;
auto GetOriginPointId() const -> quint32; auto GetOriginPointId() const -> quint32;
@ -99,7 +100,7 @@ protected:
/** @brief SaveData Put dialog data in local variables */ /** @brief SaveData Put dialog data in local variables */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void PointChanged(); void PointChanged();

View File

@ -46,12 +46,13 @@ namespace Ui
class DialogFlippingByLine; class DialogFlippingByLine;
} }
class DialogFlippingByLine : public DialogTool class DialogFlippingByLine final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
explicit DialogFlippingByLine(const VContainer *data, VAbstractPattern *doc, quint32 toolId, QWidget *parent = nullptr); explicit DialogFlippingByLine(const VContainer *data, VAbstractPattern *doc, quint32 toolId,
QWidget *parent = nullptr);
~DialogFlippingByLine() override; ~DialogFlippingByLine() override;
auto GetFirstLinePointId() const -> quint32; auto GetFirstLinePointId() const -> quint32;
@ -99,7 +100,7 @@ protected:
/** @brief SaveData Put dialog data in local variables */ /** @brief SaveData Put dialog data in local variables */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void PointChanged(); void PointChanged();

View File

@ -42,7 +42,7 @@ namespace Ui
class DialogGroup; class DialogGroup;
} }
class DialogGroup : public DialogTool class DialogGroup final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -66,7 +66,7 @@ public slots:
void SelectedObject(bool selected, quint32 object, quint32 tool) override; void SelectedObject(bool selected, quint32 object, quint32 tool) override;
protected: protected:
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private slots: private slots:
void NameChanged(); void NameChanged();

View File

@ -84,7 +84,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogHeight) // NOLINT Q_DISABLE_COPY_MOVE(DialogHeight) // NOLINT

View File

@ -45,7 +45,7 @@ class DialogLine;
/** /**
* @brief The DialogLine class dialog for ToolLine. Help create line and edit option. * @brief The DialogLine class dialog for ToolLine. Help create line and edit option.
*/ */
class DialogLine : public DialogTool class DialogLine final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -78,7 +78,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogLine) // NOLINT Q_DISABLE_COPY_MOVE(DialogLine) // NOLINT

View File

@ -45,7 +45,7 @@ class DialogLineIntersect;
/** /**
* @brief The DialogLineIntersect class dialog for ToolLineIntersect. Help create point and edit option. * @brief The DialogLineIntersect class dialog for ToolLineIntersect. Help create point and edit option.
*/ */
class DialogLineIntersect : public DialogTool class DialogLineIntersect final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -82,7 +82,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogLineIntersect) // NOLINT Q_DISABLE_COPY_MOVE(DialogLineIntersect) // NOLINT

View File

@ -42,7 +42,7 @@ namespace Ui
class DialogLineIntersectAxis; class DialogLineIntersectAxis;
} }
class DialogLineIntersectAxis : public DialogTool class DialogLineIntersectAxis final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -91,7 +91,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogLineIntersectAxis) // NOLINT Q_DISABLE_COPY_MOVE(DialogLineIntersectAxis) // NOLINT

View File

@ -45,7 +45,7 @@ namespace Ui
class DialogMove; class DialogMove;
} }
class DialogMove : public DialogTool class DialogMove final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -115,7 +115,7 @@ protected:
/** @brief SaveData Put dialog data in local variables */ /** @brief SaveData Put dialog data in local variables */
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogMove) // NOLINT Q_DISABLE_COPY_MOVE(DialogMove) // NOLINT

View File

@ -45,7 +45,7 @@ class DialogNormal;
/** /**
* @brief The DialogNormal class dialog for ToolNormal. Help create point and edit option. * @brief The DialogNormal class dialog for ToolNormal. Help create point and edit option.
*/ */
class DialogNormal : public DialogTool class DialogNormal final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -97,7 +97,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogNormal) // NOLINT Q_DISABLE_COPY_MOVE(DialogNormal) // NOLINT

View File

@ -43,7 +43,7 @@ namespace Ui
class DialogPointFromArcAndTangent; class DialogPointFromArcAndTangent;
} }
class DialogPointFromArcAndTangent : public DialogTool class DialogPointFromArcAndTangent final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -76,7 +76,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointFromArcAndTangent) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointFromArcAndTangent) // NOLINT

View File

@ -43,12 +43,13 @@ namespace Ui
class DialogPointFromCircleAndTangent; class DialogPointFromCircleAndTangent;
} }
class DialogPointFromCircleAndTangent : public DialogTool class DialogPointFromCircleAndTangent final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
DialogPointFromCircleAndTangent(const VContainer *data, VAbstractPattern *doc, quint32 toolId, QWidget *parent = nullptr); DialogPointFromCircleAndTangent(const VContainer *data, VAbstractPattern *doc, quint32 toolId,
QWidget *parent = nullptr);
~DialogPointFromCircleAndTangent() override; ~DialogPointFromCircleAndTangent() override;
auto GetPointName() const -> QString; auto GetPointName() const -> QString;
@ -87,7 +88,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointFromCircleAndTangent) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointFromCircleAndTangent) // NOLINT

View File

@ -45,7 +45,7 @@ class DialogPointOfContact;
/** /**
* @brief The DialogPointOfContact class dialog for ToolPointOfContact. Help create point and edit option. * @brief The DialogPointOfContact class dialog for ToolPointOfContact. Help create point and edit option.
*/ */
class DialogPointOfContact : public DialogTool class DialogPointOfContact final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -91,7 +91,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointOfContact) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointOfContact) // NOLINT

View File

@ -45,7 +45,7 @@ class DialogPointOfIntersection;
/** /**
* @brief The DialogPointOfIntersection class dialog for ToolPointOfIntersection. Help create point and edit option. * @brief The DialogPointOfIntersection class dialog for ToolPointOfIntersection. Help create point and edit option.
*/ */
class DialogPointOfIntersection : public DialogTool class DialogPointOfIntersection final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -75,7 +75,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointOfIntersection) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointOfIntersection) // NOLINT

View File

@ -43,7 +43,7 @@ namespace Ui
class DialogPointOfIntersectionArcs; class DialogPointOfIntersectionArcs;
} }
class DialogPointOfIntersectionArcs : public DialogTool class DialogPointOfIntersectionArcs final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
@ -77,7 +77,7 @@ protected:
* @brief SaveData Put dialog data in local variables * @brief SaveData Put dialog data in local variables
*/ */
void SaveData() override; void SaveData() override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointOfIntersectionArcs) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointOfIntersectionArcs) // NOLINT

View File

@ -43,12 +43,13 @@ namespace Ui
class DialogPointOfIntersectionCircles; class DialogPointOfIntersectionCircles;
} }
class DialogPointOfIntersectionCircles : public DialogTool class DialogPointOfIntersectionCircles final : public DialogTool
{ {
Q_OBJECT // NOLINT Q_OBJECT // NOLINT
public: public:
DialogPointOfIntersectionCircles(const VContainer *data, VAbstractPattern *doc, quint32 toolId, QWidget *parent = nullptr); DialogPointOfIntersectionCircles(const VContainer *data, VAbstractPattern *doc, quint32 toolId,
QWidget *parent = nullptr);
~DialogPointOfIntersectionCircles() override; ~DialogPointOfIntersectionCircles() override;
auto GetPointName() const -> QString; auto GetPointName() const -> QString;
@ -95,7 +96,7 @@ protected:
void SaveData() override; void SaveData() override;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
void changeEvent(QEvent *event) override; void changeEvent(QEvent *event) override;
auto IsValid() const -> bool final; auto IsValid() const -> bool override;
private: private:
Q_DISABLE_COPY_MOVE(DialogPointOfIntersectionCircles) // NOLINT Q_DISABLE_COPY_MOVE(DialogPointOfIntersectionCircles) // NOLINT

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