Automatic crash reports.

This commit is contained in:
Roman Telezhynskyi 2024-03-12 16:39:44 +02:00
parent fb15284483
commit 33a5939c18
55 changed files with 1498 additions and 350 deletions

View File

@ -125,10 +125,12 @@ linux_qt5_qbs_task_template: &LINUX_QT5_QBS_TASK_TEMPLATE
appimage_task_template: &APPIMAGE_TASK_TEMPLATE
pip_cache:
folder: ${PIP_CACHE_DIR}
conan_cache:
folder: "~/.conan/data"
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"
- python3 --version
- pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0'
- pip3 install --user --upgrade pip dropbox py7zr 'urllib3<2.0' conan==1.63.0
build_script:
- uname -a
- mkdir -pm 0700 $XDG_RUNTIME_DIR
@ -143,12 +145,25 @@ appimage_task_template: &APPIMAGE_TASK_TEMPLATE
- ${COMPILER} --version
- qmake --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-qt /opt/qt515/bin/qmake qt5
- qbs config defaultProfile qt5
- 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
- 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
- ccache -s
deploy_script:
@ -228,6 +243,7 @@ linux_task:
QT_VERSION: Qt6
ARCH: x86_64
TARGET_PLATFORM: "Linux"
VALENTINA_VERSION: 0_7_52
container:
cpu: 4
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/xerces-c/*
- python3 --version
- pip3 install --user --upgrade pip dropbox py7zr '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"
- qmake --version
- which qmake
- 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:
- echo $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}
- 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
- 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 config --list profiles
- qbs setup-qt /opt/homebrew/opt/qt6/bin/qmake qt6
- qbs config defaultProfile qt6
- 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
- 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
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
@ -412,6 +437,7 @@ macos_task:
TARGET_PLATFORM: "macOS_12.4+"
MACOS_DEPLOYMENT_TARGET: 12.0
ENABLE_CCACHE: true
VALENTINA_VERSION: 0_7_52
matrix:
- name: 'macOS Monterey 12 [signle bundle, no tests]'
env:

13
.gitignore vendored
View File

@ -73,7 +73,6 @@ cov-int/
*.la
*.a
*.lib
*.lo
# Executables
*.exe
@ -117,7 +116,6 @@ Makefile*
*.xcodeproj
# OSX specific
.DS_Store
.AppleDouble
.LSOverride
@ -173,3 +171,14 @@ __pycache__
# Sonar Cloud
.scannerwork
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.
- Minimal Qt version increased to Qt 5.15. Minimal C++ standard to C++17.
- Updated Windows installer.
- Automatic crash reports.
# Valentina 0.7.52 September 12, 2022
- Fix crash when default locale is ru.

View File

@ -40,6 +40,7 @@ environment:
ACCESS_TOKEN:
secure: RUhnEHqaR8KhalOMWwZZOoO342Ja50QV4KpEWdm9g3pG+jG7i6aJqUmeKF1l5VN6dzksk1u+yN6pOLnU8oGcaVQ6v+1dpKK1oZvF0tyHhNE=
APPVEYOR_SAVE_CACHE_ON_ERROR: "true"
VALENTINA_VERSION: 0_7_52
matrix:
- job_name: Windows_Qt_6_5_(MSVC_x64)
@ -398,15 +399,26 @@ for:
build_script:
- conan profile list
- conan install . -s os=Windows --build=missing -pr valentina
- 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%
- 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 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:
- path
- if "%RUN_TESTS%" == "true" (qbs -p autotest-runner -d %APPVEYOR_BUILD_FOLDER%\build profile:qt6 config:release)
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
on_finish:
@ -537,7 +549,7 @@ for:
secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs=
cache:
#- /Users/appveyor/.conan/data -> conanfile.py
- /Users/appveyor/.conan/data -> conanfile.py
- $HOME/brew_cache_dir
init:
@ -643,7 +655,7 @@ for:
fi
- 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 PATH="$PATH:`python3 -m site --user-base`/bin:$QTDIR/bin"
- echo $PATH
@ -663,13 +675,28 @@ for:
build_script:
- 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 config --list profiles
- qbs setup-qt $(brew --prefix qt6)/bin/qmake qt6
- qbs config defaultProfile qt6
- 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
- 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
- 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 --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
# from blocking the CI
- echo "Create keychain profile"
@ -720,7 +747,7 @@ for:
secure: B8yHPBym+BTDPK5ZCg7WlSnUCHLbcim8WqLTC6/PSNs=
cache:
#- /Users/appveyor/.conan/data -> conanfile.py
- /Users/appveyor/.conan/data -> conanfile.py
- $HOME/brew_cache_dir
init:
@ -827,7 +854,7 @@ for:
fi
- 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"
- echo $PATH
- clang --version
@ -846,13 +873,27 @@ for:
build_script:
- 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 config --list profiles
- qbs setup-qt ${QTDIR}/bin/qmake qt5
- qbs config defaultProfile qt5
- 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
- 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
- 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 --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
# from blocking the CI
- echo "Create keychain profile"

View File

@ -4,8 +4,16 @@ from conan import ConanFile
class Recipe(ConanFile):
settings = "os"
requires = "xerces-c/[~3.2]"
default_options = {"xerces-c/*:shared": True}
requires = "xerces-c/[~3.2]", "crashpad/cci.20220219", "breakpad/cci.20210521"
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):
if self.settings.os == "Linux":
@ -13,3 +21,11 @@ class Recipe(ConanFile):
if self.settings.os == "Macos" and "MACOS_DEPLOYMENT_TARGET" in os.environ:
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
installDir: buildconfig.installLibraryPath
}
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
qbs.debugInformation: true
}
}

View File

@ -33,6 +33,11 @@ VApp {
cpp.dynamicLibraries: ["icudata", "icui18n", "icuuc"]
}
Properties {
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
qbs.debugInformation: true
}
Group {
name: "Translations"
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.TextFile
import "utils.js" as Utils
ModuleProvider {
relativeSearchPaths: {
var conanPackageDir = FileInfo.cleanPath(FileInfo.joinPaths(outputBaseDir, "../../..", "genconan"));
@ -25,8 +27,6 @@ ModuleProvider {
file.close();
console.info(JSON.stringify(fileContent));
var deps = fileContent.dependencies;
for(i in deps){
@ -48,11 +48,11 @@ ModuleProvider {
// module name can be invalid for Javascrip. Search for alternative names for cmake.
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"))
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;
}
@ -63,15 +63,18 @@ ModuleProvider {
var moduleFile = new TextFile(FileInfo.joinPaths(moduleDir, moduleName + ".qbs"), TextFile.WriteOnly);
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');
}
var cppLibraries = shared ? "\tcpp.dynamicLibraries: " : "\tcpp.staticLibraries: ";
var cppLibrariesTag = shared ? "dynamiclibrary" : "staticlibrary";
var cppLibrarySuffix = shared ? "cpp.dynamicLibrarySuffix" : "cpp.staticLibrarySuffix";
moduleFile.write("import qbs\n" +
"Module {\n" +
"\tDepends { name: \"cpp\" }\n\n" +
"\tproperty bool installBin: false\n" +
"\tproperty bool installLib: false\n" +
"\tproperty bool installRes: false\n" +
@ -81,10 +84,9 @@ ModuleProvider {
"\tproperty string resInstallDir: \"res\"\n" +
"\tproperty string includeInstallDir: \"include\"\n" +
"\tproperty stringList binFilePatterns: [\"**/*\"]\n" +
"\tproperty stringList libFilePatterns: [\"**/*\"]\n" +
"\tproperty stringList libFilePatterns: [\"**/*\" + " + cppLibrarySuffix + "]\n" +
"\tproperty stringList resFilePatterns: [\"**/*\"]\n" +
"\tproperty stringList includeFilePatterns: [\"**/*\"]\n\n" +
"\tDepends { name: \"cpp\" }\n\n" +
"\tcpp.includePaths: " + 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" +
@ -94,9 +96,9 @@ ModuleProvider {
function writeGroups(file, moduleName, prefix, pathList, install) {
for(j in pathList) {
file.write("\tGroup {\n" +
"\t\tname: \"" + prefix + (j > 0 ? j : "") + "\"\n" +
"\t\tprefix: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "/\"\n" +
"\t\tfilesAreTargets: true\n");
"\t\tname: \"" + prefix + (j > 0 ? j : "") + "\"\n" +
"\t\tprefix: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "/\"\n" +
"\t\tfilesAreTargets: true\n");
if (install)
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.installSourceBase: \"" + FileInfo.fromNativeSeparators(pathList[j]) + "\"\n");
file.write("\t\tfiles: product.conan." + moduleName + "." + prefix + "FilePatterns\n" +
"\t}\n");
file.write("\t\tfiles: product.conan." + moduleName + "." + prefix + "FilePatterns\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, "lib", deps[i].lib_paths, shared);
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.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;
}
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
@ -140,6 +152,9 @@ Module {
if (enableMultiBundle)
defines.push('MULTI_BUNDLE');
if (useConanPackages && conanCrashReportingEnabled)
defines.push('CRASH_REPORTING');
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;
}
}

View File

@ -7,11 +7,14 @@ import qbs.Utilities
Module {
property string type: typeProbe.type
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: {
if (type === "git")
return "git";
return "git" + executableSuffix;
if (type === "svn")
return "svn";
return "svn" + executableSuffix;
}
property string headerFileName: "vcs-repo-state.h"
@ -101,13 +104,14 @@ Module {
// 3. latest commit is gSHA
proc.exec(tool, ["describe", "--always", "HEAD"], true);
repoState = proc.readStdOut().trim();
if (repoState)
if (repoState) {
found = true;
const tagSections = repoState.split("-");
repoStateTag = tagSections[0];
repoStateDistance = tagSections[1];
repoStateRevision = tagSections[2];
}
} finally {
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)

View File

@ -117,6 +117,21 @@ PuzzlePreferencesConfigurationPage::PuzzlePreferencesConfigurationPage(QWidget *
// Tab Privacy
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());
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;
}

View File

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

View File

@ -522,22 +522,75 @@ This option will take an affect after restart.</string>
<attribute name="title">
<string>Privacy</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_11">
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
<widget class="QGroupBox" name="groupBox_12">
<property name="title">
<string>Usage statistic</string>
</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>
</item>
<item>
<widget class="QLabel" name="label">
<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>
<widget class="QGroupBox" name="groupBoxCrashReports">
<property name="title">
<string>Crash reports</string>
</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>
</item>
<item>

View File

@ -35,6 +35,11 @@
#include <xercesc/util/PlatformUtils.hpp>
#endif
#ifdef CRASH_REPORTING
#include "../vmisc/crashhandler/crashhandler.h"
#include "version.h"
#endif
// Fix bug in Qt. Deprecation warning in QMessageBox::critical.
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
#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_dark_theme); // NOLINT
#ifdef CRASH_REPORTING
InitializeCrashpad(QStringLiteral(VER_PRODUCTNAME_STR).toLower());
#endif
#if defined(Q_OS_WIN)
VAbstractApplication::WinAttachConsole();
#endif

View File

@ -36,11 +36,17 @@ VToolApp {
type: base.concat("install_root_svg_fonts")
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.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: [
"main.cpp",
"vpapplication.cpp",

View File

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

View File

@ -115,6 +115,21 @@ TapePreferencesConfigurationPage::TapePreferencesConfigurationPage(QWidget *pare
// Tab Privacy
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());
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;
}

View File

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

View File

@ -312,20 +312,73 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
<widget class="QGroupBox" name="groupBox_10">
<property name="title">
<string>Usage statistic</string>
</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>
</item>
<item>
<widget class="QLabel" name="label">
<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>
<widget class="QGroupBox" name="groupBoxCrashReports">
<property name="title">
<string>Crash reports</string>
</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>
</item>
<item>

View File

@ -35,6 +35,11 @@
#include <xercesc/util/PlatformUtils.hpp>
#endif
#ifdef CRASH_REPORTING
#include "../vmisc/crashhandler/crashhandler.h"
#include "version.h"
#endif
// Fix bug in Qt. Deprecation warning in QMessageBox::critical.
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
#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_dark_theme); // NOLINT
#ifdef CRASH_REPORTING
InitializeCrashpad(QStringLiteral(VER_PRODUCTNAME_STR).toLower());
#endif
#if defined(Q_OS_WIN)
VAbstractApplication::WinAttachConsole();
#endif

View File

@ -18,12 +18,14 @@ VToolApp {
Depends {
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 {
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.
@ -45,11 +47,17 @@ VToolApp {
multibundle.targetApps: ["Valentina"]
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.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: [
"main.cpp",
"tkmmainwindow.cpp",

View File

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

View File

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

View File

@ -29,9 +29,11 @@
#ifndef VERSION_H
#define VERSION_H
#define VER_INTERNALNAME_STR "Tape" // 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)
#include "../../libs/vmisc/projectversion.h"
#define VER_INTERNALNAME_STR "Tape" // 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

View File

@ -92,8 +92,6 @@ Q_LOGGING_CATEGORY(vApp, "v.application") // NOLINT
QT_WARNING_POP
Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3;
namespace
{
auto AppFilePath(const QString &appName) -> QString
@ -537,38 +535,13 @@ auto VApplication::PuzzleFilePath() -> QString
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
{
// Keep in sync with VCrashPaths::GetAttachmentPath
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()
{
@ -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()
{

View File

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

View File

@ -176,6 +176,21 @@ PreferencesConfigurationPage::PreferencesConfigurationPage(QWidget *parent)
// Tab Privacy
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());
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;
}

View File

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

View File

@ -661,22 +661,75 @@
<attribute name="title">
<string>Privacy</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
<widget class="QGroupBox" name="groupBox_10">
<property name="title">
<string>Usage statistic</string>
</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>
</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>
<widget class="QGroupBox" name="groupBoxCrashReports">
<property name="title">
<string>Crash reports</string>
</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>
</item>
<item>

View File

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

View File

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

View File

@ -51,7 +51,7 @@ VToolApp {
type: base.concat("install_root_svg_fonts")
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.binInstallDir: qbs.installPrefix + "/" + buildconfig.installBinaryPath
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: [
"main.cpp",
"mainwindow.cpp",

View File

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

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 "ui_dialogaskcollectstatistic.h"
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include "../vabstractapplication.h"
//---------------------------------------------------------------------------------------------------------------------
DialogAskCollectStatistic::DialogAskCollectStatistic(QWidget *parent)
: QDialog(parent),
ui(new Ui::DialogAskCollectStatistic)
{
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();
}
//---------------------------------------------------------------------------------------------------------------------
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);
~DialogAskCollectStatistic() override;
auto CollectStatistic() -> bool;
auto CollectStatistic() const -> bool;
auto SendCrashReport() const -> bool;
auto UserEmail() const -> QString;
private:
Q_DISABLE_COPY_MOVE(DialogAskCollectStatistic) // NOLINT

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>183</height>
<width>593</width>
<height>406</height>
</rect>
</property>
<property name="windowTitle">
@ -19,23 +19,79 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="checkBoxSendUsageStatistics">
<property name="text">
<string>Send usage statistics</string>
</property>
<property name="checked">
<bool>true</bool>
<widget class="QGroupBox" name="groupBox_12">
<property name="title">
<string>Usage statistic</string>
</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>
</item>
<item>
<widget class="QLabel" name="label">
<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>
<widget class="QGroupBox" name="groupBoxCrashReports">
<property name="title">
<string>Crash reports</string>
</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>
</item>
<item>

View File

@ -58,7 +58,7 @@ constexpr inline auto AppVersion() -> unsigned
#define VER_PRODUCTVERSION VER_FILEVERSION
#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_INTERNALNAME_STR "Valentina" // Defined in program
#define VER_LEGALCOPYRIGHT_STR "Copyright © 2014-2022 Valentina Team"

View File

@ -30,6 +30,7 @@
#include "compatibility.h"
#include "svgfont/vsvgfontdatabase.h"
#include "vlockguard.h"
#include "vtranslator.h"
#include "QtConcurrent/qtconcurrentrun.h"
@ -67,6 +68,8 @@ using namespace Qt::Literals::StringLiterals;
namespace
{
Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3;
auto FilterLocales(const QStringList &locales) -> QStringList
{
QStringList filtered;
@ -625,3 +628,75 @@ void VAbstractApplication::InitHighDpiScaling(int argc, char *argv[])
Q_UNUSED(argv);
#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)
static void InitHighDpiScaling(int argc, char *argv[]);
static auto LogDirPath() -> QString;
static auto CreateLogDir() -> bool;
static void ClearOldLogs();
protected:
QUndoStack *undoStack;

View File

@ -131,6 +131,13 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingConfigurationInteractiveTools, (
Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingConfigurationDontUseNativeDialog,
("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, settingPatternForbidFlipping, ("pattern/forbidFlipping"_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.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;
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:
void SVGFontsPathChanged(const QString &oldPath, const QString &newPath);
void KnownMeasurementsPathChanged(const QString &oldPath, const QString &newPath);

View File

@ -2,6 +2,12 @@ import qbs.Utilities
VLib {
Depends { name: "Qt"; submodules: ["core", "printsupport", "gui", "widgets"] }
Depends { name: "buildconfig" }
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
name: "VMiscLib"
files: {
@ -178,9 +184,25 @@ VLib {
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 {
Depends { name: "cpp" }
Depends { name: "Qt"; submodules: ["printsupport", "widgets"] }
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
cpp.includePaths: [exportingProduct.sourceDirectory]
}
}

View File

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

View File

@ -10,14 +10,20 @@ VTestApp {
Depends {
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 {
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
}
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
name: "CollectionTest"
buildconfig.appTarget: qbs.targetOS.contains("macos") ? "CollectionTest" : "collectionTest"

View File

@ -9,12 +9,19 @@ VTestApp {
Depends {
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 {
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
}
Depends {
name: "conan.crashpad";
condition: buildconfig.useConanPackages && buildconfig.conanCrashReportingEnabled
}
name: "TranslationsTest"

View File

@ -4,10 +4,12 @@ import "qbs/imports/conan/ConanfileProbe.qbs" as ConanfileProbe
Project {
name: "Valentina"
minimumQbsVersion: "1.21"
minimumQbsVersion: "1.22"
qbsModuleProviders: ["Qt", "conan", "qbspkgconfig"]
property bool enableConan: false
property bool conanWithXerces: false
property bool conanWithCrashReporting: false
property string minimumMacosVersion: undefined
property string minimumQtVersion: "5.15"
property stringList conanProfiles: []
@ -16,10 +18,19 @@ Project {
// Temporary probe until qbs doesn't support conan 2.0
ConanfileProbe {
id: thirdPartyConanPackages
condition: enableConan
condition: enableConan && (conanWithXerces || conanWithCrashReporting)
conanfilePath: project.sourceDirectory + "/conanfile.py"
verbose: true
profiles: conanProfiles
options: {
var o = {};
if (conanWithXerces)
o.with_xerces = "True";
if (conanWithCrashReporting)
o.with_crash_reporting = "True";
return o;
}
}
references: [