mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-23 01:44:13 +02:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fc7e4a090 | |||
| 1212f48c6d | |||
| e01f46c5b0 | |||
| 3cec02b3f3 | |||
| 56f60be60a | |||
| 852f581206 | |||
| 3b626a7d1a | |||
| 069a75d44b | |||
| e1f887a036 | |||
| c5edd0a54b | |||
| 3a13287ba9 | |||
| 24776bfcf6 | |||
| 3202c145e8 | |||
| 4888ae87f3 | |||
| 59344eb565 | |||
| 5d033bf1b2 | |||
| 8985babfe7 | |||
| 29d16c3337 | |||
| 61f5e5e502 | |||
| 77bc9ed8e4 | |||
| 9b26d5dc6a | |||
| b76d8ce8a1 | |||
| 78caeaec48 | |||
| 27dea3ffab |
@@ -1 +0,0 @@
|
|||||||
*.qch filter=lfs diff=lfs merge=lfs -text
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
ca-certificates build-essential cmake ninja-build git pkg-config \
|
ca-certificates build-essential cmake ninja-build git pkg-config \
|
||||||
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
||||||
libqt6svg6-dev libqt6sql6-sqlite libsqlite3-dev libcups2-dev \
|
libqt6svg6-dev libqt6sql6-sqlite libcups2-dev \
|
||||||
libxkbcommon-x11-0 \
|
libxkbcommon-x11-0 \
|
||||||
xvfb openbox xdotool x11-utils
|
xvfb openbox xdotool x11-utils
|
||||||
# extra-cmake-modules and the KF6 libraries are installed rather than
|
# extra-cmake-modules and the KF6 libraries are installed rather than
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ jobs:
|
|||||||
mingw-w64-ucrt-x86_64-qt6-tools
|
mingw-w64-ucrt-x86_64-qt6-tools
|
||||||
mingw-w64-ucrt-x86_64-qt6-translations
|
mingw-w64-ucrt-x86_64-qt6-translations
|
||||||
mingw-w64-ucrt-x86_64-qt6-pdf
|
mingw-w64-ucrt-x86_64-qt6-pdf
|
||||||
mingw-w64-ucrt-x86_64-sqlite3
|
|
||||||
mingw-w64-ucrt-x86_64-pkg-config
|
mingw-w64-ucrt-x86_64-pkg-config
|
||||||
mingw-w64-ucrt-x86_64-kwidgetsaddons
|
mingw-w64-ucrt-x86_64-kwidgetsaddons
|
||||||
mingw-w64-ucrt-x86_64-kcoreaddons
|
mingw-w64-ucrt-x86_64-kcoreaddons
|
||||||
@@ -122,8 +121,7 @@ jobs:
|
|||||||
-DQET_EXPORT_PROJECT_DB=ON \
|
-DQET_EXPORT_PROJECT_DB=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
|
||||||
-DSQLite3_INCLUDE_DIR=/ucrt64/include \
|
|
||||||
-DSQLite3_LIBRARY=/ucrt64/lib/libsqlite3.dll.a \
|
|
||||||
..
|
..
|
||||||
ninja -j"$NPROC"
|
ninja -j"$NPROC"
|
||||||
|
|
||||||
@@ -196,13 +194,6 @@ jobs:
|
|||||||
cp /ucrt64/bin/libgcc_s_seh-1.dll "$BIN/"
|
cp /ucrt64/bin/libgcc_s_seh-1.dll "$BIN/"
|
||||||
cp /ucrt64/bin/libstdc++-6.dll "$BIN/"
|
cp /ucrt64/bin/libstdc++-6.dll "$BIN/"
|
||||||
cp /ucrt64/bin/libwinpthread-1.dll "$BIN/"
|
cp /ucrt64/bin/libwinpthread-1.dll "$BIN/"
|
||||||
SQLITE=$(find /ucrt64/bin -name "libsqlite3*.dll" | head -1)
|
|
||||||
if [ -n "$SQLITE" ]; then
|
|
||||||
cp "$SQLITE" "$BIN/"
|
|
||||||
echo "SQLite3 copied: $(basename $SQLITE)"
|
|
||||||
else
|
|
||||||
echo "WARNING: libsqlite3 not found in /ucrt64/bin/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cp "$GITHUB_WORKSPACE/build-aux/windows/QET64.nsi" "$NSIS_ROOT/"
|
cp "$GITHUB_WORKSPACE/build-aux/windows/QET64.nsi" "$NSIS_ROOT/"
|
||||||
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra.nsh" "$NSIS_ROOT/"
|
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra.nsh" "$NSIS_ROOT/"
|
||||||
|
|||||||
@@ -59,17 +59,41 @@ jobs:
|
|||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# 2. Download the portable artifact for this flavor
|
# 2. Download the portable artifact for this flavor
|
||||||
|
#
|
||||||
|
# Wrapped in nick-fields/retry: actions/download-artifact@v8 has
|
||||||
|
# shown repeated "Artifact download failed after 5 retries"
|
||||||
|
# failures on this cross-workflow download (via run-id) — not a
|
||||||
|
# real content/digest problem, just flaky Azure blob delivery.
|
||||||
|
# Two separate occurrences observed within days of each other
|
||||||
|
# (different artifact IDs/digests, same failure signature), each
|
||||||
|
# one enough to fail build-msi outright and block the rest of the
|
||||||
|
# pipeline. Retrying the whole download 3x is cheap insurance.
|
||||||
|
# Switched to `gh run download` here because nick-fields/retry
|
||||||
|
# can only retry a shell command, not re-invoke a `uses:` step.
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
- name: Download portable artifact
|
- name: Download portable artifact
|
||||||
uses: actions/download-artifact@v8
|
uses: nick-fields/retry@v3
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.portable_artifact }}
|
timeout_minutes: 10
|
||||||
path: artifact\files
|
max_attempts: 3
|
||||||
# workflow_run => use the triggering run's ID
|
retry_wait_seconds: 30
|
||||||
# workflow_dispatch => use input run_id if provided, otherwise current run
|
shell: pwsh
|
||||||
run-id: ${{ github.event.workflow_run.id || github.event.inputs.run_id || github.run_id }}
|
command: |
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
if (Test-Path "artifact\files") { Remove-Item -Recurse -Force "artifact\files" }
|
||||||
repository: ${{ github.repository }}
|
New-Item -ItemType Directory -Force -Path "artifact\files" | Out-Null
|
||||||
|
|
||||||
|
$runId = "${{ github.event.workflow_run.id || github.event.inputs.run_id || github.run_id }}"
|
||||||
|
gh run download $runId `
|
||||||
|
--repo "${{ github.repository }}" `
|
||||||
|
--name "${{ matrix.portable_artifact }}" `
|
||||||
|
--dir "artifact\files"
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "gh run download failed (exit $LASTEXITCODE)"
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# 3. Extract version
|
# 3. Extract version
|
||||||
@@ -336,7 +360,13 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Delete old nightly .msi asset
|
- name: Delete old nightly .msi asset
|
||||||
if: always()
|
# Only run if a new MSI actually exists in dist/ — otherwise the old
|
||||||
|
# (still working) nightly .msi would be deleted without anything to
|
||||||
|
# replace it, leaving the nightly release with no MSI at all until
|
||||||
|
# the next successful build (see windows-msi-pipeline notes,
|
||||||
|
# run 35694391567: an upstream artifact-download failure meant
|
||||||
|
# dist\*.msi never existed for that run).
|
||||||
|
if: always() && hashFiles('dist/*.msi') != ''
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
REPO: ${{ github.repository }}
|
REPO: ${{ github.repository }}
|
||||||
@@ -381,7 +411,20 @@ jobs:
|
|||||||
deploy-pages:
|
deploy-pages:
|
||||||
needs: build-msi
|
needs: build-msi
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: always() && needs.build-msi.result == 'success'
|
# Regenerate the page whenever the MSI job actually ran (success OR
|
||||||
|
# packaging/signing failure) — not only on full success.
|
||||||
|
# generate-page.py queries the published assets on the "nightly"
|
||||||
|
# release itself (line 407: `gh release view nightly --json assets`),
|
||||||
|
# so it already handles a missing MSI natively (empty MSI_NAME -> no
|
||||||
|
# MSI button on the page). The page only needs the exe/zip already
|
||||||
|
# published by windows-build.yml, independent of the MSI's fate.
|
||||||
|
# Only "skipped"/"cancelled" are excluded: if build-msi never ran at
|
||||||
|
# all (e.g. Windows Build itself failed), there is nothing new to
|
||||||
|
# publish and regenerating the page would be pointless.
|
||||||
|
if: >
|
||||||
|
always() &&
|
||||||
|
needs.build-msi.result != 'skipped' &&
|
||||||
|
needs.build-msi.result != 'cancelled'
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pages: write
|
pages: write
|
||||||
|
|||||||
@@ -118,17 +118,6 @@ else()
|
|||||||
"without a backtrace")
|
"without a backtrace")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(SQLite3 REQUIRED)
|
|
||||||
|
|
||||||
# CMake < 4.3 only creates the SQLite::SQLite3 target (no SQLite3::SQLite3
|
|
||||||
# alias yet), while CMake >= 4.3's bundled FindSQLite3 creates SQLite3::SQLite3
|
|
||||||
# and deprecates the old name. Add the missing alias ourselves so we can use
|
|
||||||
# the modern target name everywhere regardless of the CMake version in use
|
|
||||||
# (this project must keep building on CMake versions below 4.3, e.g. on most
|
|
||||||
# current Linux distros).
|
|
||||||
if(NOT TARGET SQLite3::SQLite3 AND TARGET SQLite::SQLite3)
|
|
||||||
add_library(SQLite3::SQLite3 ALIAS SQLite::SQLite3)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_AUTOUIC_SEARCH_PATHS ${QET_DIR}/sources/ui)
|
set(CMAKE_AUTOUIC_SEARCH_PATHS ${QET_DIR}/sources/ui)
|
||||||
|
|
||||||
@@ -284,7 +273,6 @@ target_link_libraries(
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
pugixml::pugixml
|
pugixml::pugixml
|
||||||
SingleApplication::SingleApplication
|
SingleApplication::SingleApplication
|
||||||
SQLite3::SQLite3
|
|
||||||
${KF_PRIVATE_LIBRARIES}
|
${KF_PRIVATE_LIBRARIES}
|
||||||
${QET_PRIVATE_LIBRARIES}
|
${QET_PRIVATE_LIBRARIES}
|
||||||
)
|
)
|
||||||
@@ -318,7 +306,6 @@ target_include_directories(
|
|||||||
${QET_DIR}/sources/NameList
|
${QET_DIR}/sources/NameList
|
||||||
${QET_DIR}/sources/NameList/ui
|
${QET_DIR}/sources/NameList/ui
|
||||||
${QET_DIR}/sources/utils
|
${QET_DIR}/sources/utils
|
||||||
${QET_DIR}/pugixml/src
|
|
||||||
${QET_DIR}/sources/dataBase
|
${QET_DIR}/sources/dataBase
|
||||||
${QET_DIR}/sources/dataBase/ui
|
${QET_DIR}/sources/dataBase/ui
|
||||||
${QET_DIR}/sources/factory/ui
|
${QET_DIR}/sources/factory/ui
|
||||||
|
|||||||
+7
-21
@@ -27,18 +27,12 @@ git submodule update --init --recursive
|
|||||||
| C++17 compiler | required | GCC or Clang on Unix-like platforms; MSVC or MinGW-w64 g++ on Windows — see [Choosing a compiler](#3-choosing-a-compiler-unix) / [Building on Windows](#6-building-on-windows-msvc--mingw) |
|
| C++17 compiler | required | GCC or Clang on Unix-like platforms; MSVC or MinGW-w64 g++ on Windows — see [Choosing a compiler](#3-choosing-a-compiler-unix) / [Building on Windows](#6-building-on-windows-msvc--mingw) |
|
||||||
| Qt6 base + widgets | required | |
|
| Qt6 base + widgets | required | |
|
||||||
| Qt6 **GuiPrivate** headers | required | needed for clickable PDF hyperlinks; **hard build failure** at CMake generate time if missing, see below |
|
| Qt6 **GuiPrivate** headers | required | needed for clickable PDF hyperlinks; **hard build failure** at CMake generate time if missing, see below |
|
||||||
| SQLite3 | required | used by the nomenclature/summary database |
|
|
||||||
| Qt Linguist tools (`lrelease`) | required | compiles the tracked `.ts` files into `.qm` as part of every normal build |
|
| Qt Linguist tools (`lrelease`) | required | compiles the tracked `.ts` files into `.qm` as part of every normal build |
|
||||||
| pugixml | handled automatically | fetched and built via CMake FetchContent if not already present on the system — see [pugixml](#8-pugixml) below |
|
| pugixml | handled automatically | fetched and built via CMake FetchContent if not already present on the system — see [pugixml](#8-pugixml) below |
|
||||||
| Qt Test module | required if building tests | `PACKAGE_TESTS` is `ON` by default; QtTest ships as part of the base Qt6 dev packages listed below on every platform, no extra package needed |
|
| Qt Test module | required if building tests | `PACKAGE_TESTS` is `ON` by default; QtTest ships as part of the base Qt6 dev packages listed below on every platform, no extra package needed |
|
||||||
| KDE Frameworks (KF6) | optional | see [Building without KDE Frameworks](#9-building-without-kde-frameworks) |
|
| KDE Frameworks (KF6) | optional | see [Building without KDE Frameworks](#9-building-without-kde-frameworks) |
|
||||||
| QtPdf module | optional | see [PDF page import](#7-pdf-page-import-qtpdf) |
|
| QtPdf module | optional | see [PDF page import](#7-pdf-page-import-qtpdf) |
|
||||||
|
|
||||||
A note on CMake versions: the project declares a minimum of 3.5 but is
|
|
||||||
routinely built with much newer releases; if your CMake is older than 4.3 it
|
|
||||||
simply won't have the newer `SQLite3::SQLite3` target name, which the build
|
|
||||||
script compensates for automatically. There is nothing you need to do either
|
|
||||||
way.
|
|
||||||
|
|
||||||
## 3. Building (out-of-source build)
|
## 3. Building (out-of-source build)
|
||||||
|
|
||||||
@@ -106,7 +100,7 @@ the closest match.
|
|||||||
sudo apt install \
|
sudo apt install \
|
||||||
build-essential cmake ninja-build git \
|
build-essential cmake ninja-build git \
|
||||||
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
|
||||||
libsqlite3-dev \
|
|
||||||
libkf6coreaddons-dev libkf6widgetsaddons-dev
|
libkf6coreaddons-dev libkf6widgetsaddons-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -138,7 +132,6 @@ sudo apt install libpugixml-dev
|
|||||||
sudo dnf install \
|
sudo dnf install \
|
||||||
cmake gcc-c++ git \
|
cmake gcc-c++ git \
|
||||||
qt6-qtbase-devel qt6-qtbase-private-devel qt6-qttools-devel \
|
qt6-qtbase-devel qt6-qtbase-private-devel qt6-qttools-devel \
|
||||||
sqlite-devel \
|
|
||||||
kf6-kcoreaddons-devel kf6-kwidgetsaddons-devel
|
kf6-kcoreaddons-devel kf6-kwidgetsaddons-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -155,11 +148,10 @@ Optional, for a system pugixml: `sudo dnf install pugixml-devel`.
|
|||||||
pkg install \
|
pkg install \
|
||||||
cmake git \
|
cmake git \
|
||||||
qt6-base qt6-tools \
|
qt6-base qt6-tools \
|
||||||
sqlite3 \
|
|
||||||
kf6-kcoreaddons kf6-kwidgetsaddons
|
kf6-kcoreaddons kf6-kwidgetsaddons
|
||||||
```
|
```
|
||||||
|
|
||||||
(from ports: `devel/qt6-base`, `devel/qt6-tools`, `databases/sqlite3`,
|
(from ports: `devel/qt6-base`, `devel/qt6-tools`,
|
||||||
`devel/kf6-kcoreaddons`, `x11-toolkits/kf6-kwidgetsaddons`.) Qt6's
|
`devel/kf6-kcoreaddons`, `x11-toolkits/kf6-kwidgetsaddons`.) Qt6's
|
||||||
`GuiPrivate` headers ship as part of `qt6-base` on FreeBSD, no separate
|
`GuiPrivate` headers ship as part of `qt6-base` on FreeBSD, no separate
|
||||||
package is needed. `QtPdf` is not packaged on FreeBSD at the time of writing
|
package is needed. `QtPdf` is not packaged on FreeBSD at the time of writing
|
||||||
@@ -175,7 +167,7 @@ Optional, for a system pugixml: `pkg install pugixml` (`devel/pugixml`).
|
|||||||
Using [Homebrew](https://brew.sh):
|
Using [Homebrew](https://brew.sh):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
brew install cmake qt sqlite ninja
|
brew install cmake qt ninja
|
||||||
```
|
```
|
||||||
|
|
||||||
Homebrew's `qt` formula is Qt6 and includes the private headers, so no
|
Homebrew's `qt` formula is Qt6 and includes the private headers, so no
|
||||||
@@ -193,7 +185,7 @@ Optional, for a system pugixml: `brew install pugixml`.
|
|||||||
|
|
||||||
See [Building on Windows](#6-building-on-windows-msvc--mingw) below — the
|
See [Building on Windows](#6-building-on-windows-msvc--mingw) below — the
|
||||||
package sources differ enough from the Unix-like platforms above (no system
|
package sources differ enough from the Unix-like platforms above (no system
|
||||||
package manager, SQLite3 and Qt aren't provided the same way) that it gets
|
package manager and Qt aren't provided the same way) that it gets
|
||||||
its own section.
|
its own section.
|
||||||
|
|
||||||
## 5. pugixml
|
## 5. pugixml
|
||||||
@@ -215,7 +207,7 @@ on Debian/Ubuntu, `pugixml-devel` on Fedora).
|
|||||||
Both toolchains QET's CMake build targets on Windows are covered here:
|
Both toolchains QET's CMake build targets on Windows are covered here:
|
||||||
**MSVC** (Visual Studio 2019/2022) and **MinGW-w64** (gcc). Unlike the
|
**MSVC** (Visual Studio 2019/2022) and **MinGW-w64** (gcc). Unlike the
|
||||||
Unix-like platforms above, there's no single system package manager, so
|
Unix-like platforms above, there's no single system package manager, so
|
||||||
Qt, SQLite3 and (optionally) KDE Frameworks each need to be sourced
|
Qt and (optionally) KDE Frameworks each need to be sourced
|
||||||
separately per toolchain.
|
separately per toolchain.
|
||||||
|
|
||||||
One piece of good news either way: unlike Debian/Fedora, the official Qt
|
One piece of good news either way: unlike Debian/Fedora, the official Qt
|
||||||
@@ -236,11 +228,7 @@ normally use `-DBUILD_WITH_KF=OFF` (see the
|
|||||||
1. Install Visual Studio with the "Desktop development with C++" workload,
|
1. Install Visual Studio with the "Desktop development with C++" workload,
|
||||||
and install Qt6 for MSVC (e.g. the `msvc2019_64` or `msvc2022_64` kit)
|
and install Qt6 for MSVC (e.g. the `msvc2019_64` or `msvc2022_64` kit)
|
||||||
via the [Qt Online Installer](https://www.qt.io/download-qt-installer).
|
via the [Qt Online Installer](https://www.qt.io/download-qt-installer).
|
||||||
2. Get SQLite3 — the simplest route is [vcpkg](https://vcpkg.io):
|
2. Configure and build from an "x64 Native Tools Command Prompt for VS":
|
||||||
```bat
|
|
||||||
vcpkg install sqlite3:x64-windows
|
|
||||||
```
|
|
||||||
3. Configure and build from an "x64 Native Tools Command Prompt for VS":
|
|
||||||
```bat
|
```bat
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -G "Visual Studio 17 2022" -A x64 ^
|
cmake .. -G "Visual Studio 17 2022" -A x64 ^
|
||||||
@@ -293,9 +281,7 @@ Using the Qt Online Installer's bundled MinGW kit instead: point
|
|||||||
`CMAKE_PREFIX_PATH` at that kit (e.g. `C:\Qt\6.x.x\mingw_64`) and make sure
|
`CMAKE_PREFIX_PATH` at that kit (e.g. `C:\Qt\6.x.x\mingw_64`) and make sure
|
||||||
its bundled `g++.exe` comes first on `PATH`, or pass
|
its bundled `g++.exe` comes first on `PATH`, or pass
|
||||||
`-DCMAKE_C_COMPILER`/`-DCMAKE_CXX_COMPILER` explicitly so CMake doesn't pick
|
`-DCMAKE_C_COMPILER`/`-DCMAKE_CXX_COMPILER` explicitly so CMake doesn't pick
|
||||||
up a different MinGW installation. SQLite3 still has to come from elsewhere
|
up a different MinGW installation.
|
||||||
in this path — vcpkg with a `mingw`-flavoured triplet, or MSYS2's package as
|
|
||||||
above.
|
|
||||||
|
|
||||||
## 7. Qt6 private headers (mandatory)
|
## 7. Qt6 private headers (mandatory)
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ parts:
|
|||||||
source: .
|
source: .
|
||||||
stage-packages:
|
stage-packages:
|
||||||
- git
|
- git
|
||||||
- sqlite3
|
|
||||||
- xdg-user-dirs
|
- xdg-user-dirs
|
||||||
- libqt6qml6
|
- libqt6qml6
|
||||||
# libxcb-cursor0 workaround was needed against the Qt5/KF5 core22 content
|
# libxcb-cursor0 workaround was needed against the Qt5/KF5 core22 content
|
||||||
@@ -82,7 +81,7 @@ parts:
|
|||||||
- git
|
- git
|
||||||
- cmake
|
- cmake
|
||||||
- ninja-build
|
- ninja-build
|
||||||
- libsqlite3-dev
|
|
||||||
- qt6-tools-dev
|
- qt6-tools-dev
|
||||||
- qt6-base-private-dev
|
- qt6-base-private-dev
|
||||||
- qt6-declarative-dev
|
- qt6-declarative-dev
|
||||||
|
|||||||
@@ -62,7 +62,9 @@ if(WIN32)
|
|||||||
# puts the .qm files (see build-aux/windows/QElectroTech.wxs and the
|
# puts the .qm files (see build-aux/windows/QElectroTech.wxs and the
|
||||||
# windows-build workflow), and what the shortcuts pass as --lang-dir.
|
# windows-build workflow), and what the shortcuts pass as --lang-dir.
|
||||||
set(QET_LANG_PATH "lang/")
|
set(QET_LANG_PATH "lang/")
|
||||||
|
set(QET_EXAMPLES_PATH "examples/")
|
||||||
set(QET_LICENSE_PATH "./")
|
set(QET_LICENSE_PATH "./")
|
||||||
|
set(QET_ICONS_PATH "icons/hicolor/")
|
||||||
# Liste des ressources Windows
|
# Liste des ressources Windows
|
||||||
#RC_FILE = qelectrotech.rc
|
#RC_FILE = qelectrotech.rc
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -507,10 +507,6 @@ set(QET_SRC_FILES
|
|||||||
${QET_DIR}/sources/PropertiesEditor/propertieseditorwidget.cpp
|
${QET_DIR}/sources/PropertiesEditor/propertieseditorwidget.cpp
|
||||||
${QET_DIR}/sources/PropertiesEditor/propertieseditorwidget.h
|
${QET_DIR}/sources/PropertiesEditor/propertieseditorwidget.h
|
||||||
|
|
||||||
${QET_DIR}/pugixml/src/pugiconfig.hpp
|
|
||||||
${QET_DIR}/pugixml/src/pugixml.cpp
|
|
||||||
${QET_DIR}/pugixml/src/pugixml.hpp
|
|
||||||
|
|
||||||
${QET_DIR}/sources/qetgraphicsitem/conductor.cpp
|
${QET_DIR}/sources/qetgraphicsitem/conductor.cpp
|
||||||
${QET_DIR}/sources/qetgraphicsitem/conductor.h
|
${QET_DIR}/sources/qetgraphicsitem/conductor.h
|
||||||
${QET_DIR}/sources/qetgraphicsitem/conductortextitem.cpp
|
${QET_DIR}/sources/qetgraphicsitem/conductortextitem.cpp
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#Based on raspberry pi 5 8 Gb Trixie
|
#Based on raspberry pi 5 8 Gb Trixie
|
||||||
#sudo apt install git ssh rsync libqt5svg5-dev qt5-qmake qtbase5-dev libkf5widgetsaddons-dev libkf5coreaddons-dev libsqlite3-dev pkgconf libqt5waylandclient5-dev libqt5waylandcompositor5-dev g++ make
|
#sudo apt install git ssh rsync libqt5svg5-dev qt5-qmake qtbase5-dev libkf5widgetsaddons-dev libkf5coreaddons-dev pkgconf libqt5waylandclient5-dev libqt5waylandcompositor5-dev g++ make
|
||||||
#mkdir -p AppImage/0.100.0/aarch64
|
#mkdir -p AppImage/0.100.0/aarch64
|
||||||
# Get GIT sources
|
# Get GIT sources
|
||||||
#git clone --recursive https://github.com/qelectrotech/qelectrotech-source-mirror.git
|
#git clone --recursive https://github.com/qelectrotech/qelectrotech-source-mirror.git
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
#include "../NameList/nameslist.h"
|
#include "../NameList/nameslist.h"
|
||||||
#include "../diagramcontext.h"
|
#include "../diagramcontext.h"
|
||||||
#include "pugixml/src/pugixml.hpp"
|
#include "pugixml.hpp"
|
||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef NAMES_LIST_H
|
#ifndef NAMES_LIST_H
|
||||||
#define NAMES_LIST_H
|
#define NAMES_LIST_H
|
||||||
#include "pugixml/src/pugixml.hpp"
|
#include "pugixml.hpp"
|
||||||
|
|
||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -171,20 +171,20 @@ MoveTerminalCommand::MoveTerminalCommand(QSharedPointer<PhysicalTerminal> termin
|
|||||||
QString text;
|
QString text;
|
||||||
if (t_label.isEmpty()) {
|
if (t_label.isEmpty()) {
|
||||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers un groupe de bornes");
|
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers un autre groupe de bornes");
|
||||||
else if (strip_name.isEmpty())
|
else if (strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers le groupe de bornes %1").arg(new_strip_name);
|
text = QObject::tr("Déplacer une borne d'un groupe de bornes vers le groupe de bornes %1").arg(new_strip_name);
|
||||||
else if (new_strip_name.isEmpty())
|
else if (new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers un groupe de bornes").arg(strip_name);
|
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers un autre groupe de bornes").arg(strip_name);
|
||||||
else
|
else
|
||||||
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers le groupe de bornes %2").arg(strip_name, new_strip_name);
|
text = QObject::tr("Déplacer une borne du groupe de bornes %1 vers le groupe de bornes %2").arg(strip_name, new_strip_name);
|
||||||
} else {
|
} else {
|
||||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers un groupe de bornes").arg(t_label);
|
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers un autre groupe de bornes").arg(t_label);
|
||||||
else if (strip_name.isEmpty())
|
else if (strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers le groupe de bornes %2").arg(t_label, new_strip_name);
|
text = QObject::tr("Déplacer la borne %1 d'un groupe de bornes vers le groupe de bornes %2").arg(t_label, new_strip_name);
|
||||||
else if (new_strip_name.isEmpty())
|
else if (new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers un groupe de bornes").arg(t_label, strip_name);
|
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers un autre groupe de bornes").arg(t_label, strip_name);
|
||||||
else
|
else
|
||||||
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers le groupe de bornes %3").arg(t_label, strip_name, new_strip_name);
|
text = QObject::tr("Déplacer la borne %1 du groupe de bornes %2 vers le groupe de bornes %3").arg(t_label, strip_name, new_strip_name);
|
||||||
}
|
}
|
||||||
@@ -205,11 +205,11 @@ MoveTerminalCommand::MoveTerminalCommand(QVector<QSharedPointer<PhysicalTerminal
|
|||||||
|
|
||||||
QString text;
|
QString text;
|
||||||
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
if (strip_name.isEmpty() && new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers un groupe de bornes", "", count);
|
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers un autre groupe de bornes", "", count);
|
||||||
else if (strip_name.isEmpty())
|
else if (strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers le groupe de bornes %1", "", count).arg(new_strip_name);
|
text = QObject::tr("Déplacer %n borne(s) d'un groupe de bornes vers le groupe de bornes %1", "", count).arg(new_strip_name);
|
||||||
else if (new_strip_name.isEmpty())
|
else if (new_strip_name.isEmpty())
|
||||||
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers un groupe de bornes", "", count).arg(strip_name);
|
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers un autre groupe de bornes", "", count).arg(strip_name);
|
||||||
else
|
else
|
||||||
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers le groupe de bornes %2", "", count).arg(strip_name, new_strip_name);
|
text = QObject::tr("Déplacer %n borne(s) du groupe de bornes %1 vers le groupe de bornes %2", "", count).arg(strip_name, new_strip_name);
|
||||||
setText(text);
|
setText(text);
|
||||||
|
|||||||
@@ -28,11 +28,11 @@
|
|||||||
#include "../qetproject.h"
|
#include "../qetproject.h"
|
||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QFile>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
|
|
||||||
#include <QSqlDriver>
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1246,23 +1246,6 @@ void projectDataBase::bindDiagramInfoValues(QSqlQuery &query, Diagram *diagram)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
/**
|
|
||||||
@brief projectDataBase::sqliteHandle
|
|
||||||
@param db
|
|
||||||
@return the sqlite3 handler class used internally by db
|
|
||||||
*/
|
|
||||||
sqlite3 *projectDataBase::sqliteHandle(QSqlDatabase *db)
|
|
||||||
{
|
|
||||||
sqlite3 *handle = nullptr;
|
|
||||||
|
|
||||||
QVariant v = db->driver()->handle();
|
|
||||||
if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0) {
|
|
||||||
handle = *static_cast<sqlite3 **>(v.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief projectDataBase::exportDb
|
* @brief projectDataBase::exportDb
|
||||||
@@ -1298,27 +1281,19 @@ void projectDataBase::exportDb(projectDataBase *db,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString connection_name("export_project_db_" % db->project()->uuid().toString());
|
// VACUUM INTO requires the destination not to exist. QFileDialog may ask
|
||||||
|
// about overwriting, but it does not remove the existing file for us.
|
||||||
if (true) //Enter in a scope only to nicely use QSqlDatabase::removeDatabase just after the end of the scope
|
if (QFile::exists(path_) && !QFile::remove(path_)) {
|
||||||
{
|
qWarning() << "Unable to replace project database export:" << path_;
|
||||||
auto file_db = QSqlDatabase::addDatabase("QSQLITE", connection_name);
|
|
||||||
file_db.setDatabaseName(path_);
|
|
||||||
if (!file_db.open()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto memory_db_handle = sqliteHandle(&db->m_data_base);
|
// VACUUM INTO creates a standalone copy of the current database without
|
||||||
auto file_db_handle = sqliteHandle(&file_db);
|
// requiring access to the SQLite driver's native connection handle.
|
||||||
|
const auto escaped_path = path_.replace("'", "''");
|
||||||
auto sqlite_backup = sqlite3_backup_init(file_db_handle, "main", memory_db_handle, "main");
|
QSqlQuery query(db->m_data_base);
|
||||||
if (sqlite_backup)
|
if (!query.exec("VACUUM INTO '" % escaped_path % "'")) {
|
||||||
{
|
qWarning() << "Unable to export project database:" << query.lastError().text();
|
||||||
sqlite3_backup_step(sqlite_backup, -1);
|
|
||||||
sqlite3_backup_finish(sqlite_backup);
|
|
||||||
}
|
}
|
||||||
file_db.close();
|
|
||||||
}
|
|
||||||
QSqlDatabase::removeDatabase(connection_name);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ class projectDataBase : public QObject
|
|||||||
|
|
||||||
#ifdef QET_EXPORT_PROJECT_DB
|
#ifdef QET_EXPORT_PROJECT_DB
|
||||||
public:
|
public:
|
||||||
static sqlite3 *sqliteHandle(QSqlDatabase *db);
|
|
||||||
static void exportDb(projectDataBase *db,
|
static void exportDb(projectDataBase *db,
|
||||||
QWidget *parent = nullptr,
|
QWidget *parent = nullptr,
|
||||||
const QString &caption = QString(),
|
const QString &caption = QString(),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef DIAGRAM_CONTEXT_H
|
#ifndef DIAGRAM_CONTEXT_H
|
||||||
#define DIAGRAM_CONTEXT_H
|
#define DIAGRAM_CONTEXT_H
|
||||||
#include "pugixml/src/pugixml.hpp"
|
#include "pugixml.hpp"
|
||||||
|
|
||||||
#include <QDomElement>
|
#include <QDomElement>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "QPropertyUndoCommand/qpropertyundocommand.h"
|
#include "QPropertyUndoCommand/qpropertyundocommand.h"
|
||||||
#include "diagram.h"
|
#include "diagram.h"
|
||||||
|
#include "qetapp.h"
|
||||||
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
||||||
#include "qetgraphicsitem/elementtextitemgroup.h"
|
#include "qetgraphicsitem/elementtextitemgroup.h"
|
||||||
|
|
||||||
@@ -146,5 +147,5 @@ QString ElementTextsMover::undoText() const
|
|||||||
if (parts.isEmpty())
|
if (parts.isEmpty())
|
||||||
return QString(); // should never occur
|
return QString(); // should never occur
|
||||||
|
|
||||||
return QObject::tr("Déplacer %1").arg(QLocale().createSeparatedList(parts));
|
return QObject::tr("Déplacer %1").arg(QLocale(QETApp::interfaceLanguage()).createSeparatedList(parts));
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-9
@@ -16,6 +16,7 @@
|
|||||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include "qet.h"
|
#include "qet.h"
|
||||||
|
#include "qetapp.h"
|
||||||
#include "qeticons.h"
|
#include "qeticons.h"
|
||||||
#include "shortcutmanager.h"
|
#include "shortcutmanager.h"
|
||||||
|
|
||||||
@@ -276,7 +277,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n élément(s)",
|
"%n élément(s)",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
elements_count
|
elements_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -286,7 +287,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n conducteur(s)",
|
"%n conducteur(s)",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
conductors_count
|
conductors_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -296,7 +297,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n champ(s) de texte",
|
"%n champ(s) de texte",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
texts_count
|
texts_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -306,7 +307,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n image(s)",
|
"%n image(s)",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
images_count
|
images_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -316,7 +317,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n forme(s)",
|
"%n forme(s)",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
shapes_count
|
shapes_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -326,7 +327,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n texte(s) d'élément",
|
"%n texte(s) d'élément",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
element_text_count
|
element_text_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -336,7 +337,7 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n tableau(s)",
|
"%n tableau(s)",
|
||||||
"part of a enumerative partial sentence listing the content of diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
tables_count
|
tables_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -346,13 +347,13 @@ QString QET::ElementsAndConductorsSentence(
|
|||||||
parts.append(
|
parts.append(
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
"%n plan(s) de bornes",
|
"%n plan(s) de bornes",
|
||||||
"part of a enumerative partial sentence listing the content of a diagram",
|
"Sentence fragment used in an automatically generated list of different objects, e.g. objects moved at the same time, which will be combined into a sentence.",
|
||||||
terminal_strip_count
|
terminal_strip_count
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return QLocale().createSeparatedList(parts);
|
return QLocale(QETApp::interfaceLanguage()).createSeparatedList(parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+85
-2
@@ -236,7 +236,7 @@ QString QETApp::loadedQtTranslationFile()
|
|||||||
void QETApp::setLanguage(const QString &desired_language) {
|
void QETApp::setLanguage(const QString &desired_language) {
|
||||||
QString languages_path = languagesPath();
|
QString languages_path = languagesPath();
|
||||||
|
|
||||||
QLocale::setDefault(QLocale(desired_language));
|
m_interface_language = desired_language;
|
||||||
|
|
||||||
// load Qt library translations
|
// load Qt library translations
|
||||||
QString qt_l10n_path = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
|
QString qt_l10n_path = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
|
||||||
@@ -1816,6 +1816,81 @@ void QETApp::useSystemPalette(bool use) {
|
|||||||
QET::Palette::refreshStyleSheets();
|
QET::Palette::refreshStyleSheets();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief QETApp::useCustomPalette
|
||||||
|
Apply a user-chosen color as the application-wide palette.
|
||||||
|
Builds a full QPalette from \a color, keeping the system palette
|
||||||
|
as a fallback for roles we don't touch.
|
||||||
|
@param color the user-chosen base color
|
||||||
|
*/
|
||||||
|
void QETApp::useCustomPalette(const QColor &color) {
|
||||||
|
if (!color.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Derive readable text colors from the chosen color.
|
||||||
|
const bool dark = color.lightness() < 128;
|
||||||
|
const QColor text = dark ? QColor(220, 220, 220) : QColor(30, 30, 30);
|
||||||
|
const QColor disabled_text = dark ? QColor(175, 175, 175) : QColor(128, 128, 128);
|
||||||
|
|
||||||
|
// Slightly lighter/darker for button and window shading.
|
||||||
|
QColor button = color;
|
||||||
|
button = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.08, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.08, 0.0));
|
||||||
|
QColor light = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.15, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.15, 0.0));
|
||||||
|
QColor mid = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() + 0.04, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.04, 0.0));
|
||||||
|
QColor dark_c = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() - 0.04, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.12, 0.0));
|
||||||
|
QColor shadow = QColor::fromHslF(color.hslHueF(),
|
||||||
|
color.hslSaturationF(),
|
||||||
|
dark ? qMin(color.lightnessF() - 0.10, 1.0)
|
||||||
|
: qMax(color.lightnessF() - 0.20, 0.0));
|
||||||
|
|
||||||
|
QPalette p;
|
||||||
|
// Active and Inactive get the same colors; only Disabled differs.
|
||||||
|
for (auto group : {QPalette::Active, QPalette::Inactive}) {
|
||||||
|
p.setColor(group, QPalette::Window, color);
|
||||||
|
p.setColor(group, QPalette::WindowText, text);
|
||||||
|
p.setColor(group, QPalette::Base, color);
|
||||||
|
p.setColor(group, QPalette::AlternateBase, button);
|
||||||
|
p.setColor(group, QPalette::Text, text);
|
||||||
|
p.setColor(group, QPalette::Button, button);
|
||||||
|
p.setColor(group, QPalette::ButtonText, text);
|
||||||
|
p.setColor(group, QPalette::BrightText, dark ? QColor(255,90,90) : Qt::white);
|
||||||
|
p.setColor(group, QPalette::Highlight, QColor(30, 96, 176));
|
||||||
|
p.setColor(group, QPalette::HighlightedText, Qt::white);
|
||||||
|
p.setColor(group, QPalette::ToolTipBase, button);
|
||||||
|
p.setColor(group, QPalette::ToolTipText, text);
|
||||||
|
p.setColor(group, QPalette::Light, light);
|
||||||
|
p.setColor(group, QPalette::Midlight, mid);
|
||||||
|
p.setColor(group, QPalette::Mid, mid);
|
||||||
|
p.setColor(group, QPalette::Dark, dark_c);
|
||||||
|
p.setColor(group, QPalette::Shadow, shadow);
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
||||||
|
p.setColor(group, QPalette::Accent, QColor(30, 96, 176));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::WindowText, disabled_text);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::Text, disabled_text);
|
||||||
|
p.setColor(QPalette::Disabled, QPalette::ButtonText, disabled_text);
|
||||||
|
|
||||||
|
qApp->setPalette(p);
|
||||||
|
qApp->setStyleSheet(QString());
|
||||||
|
|
||||||
|
// Switch icon theme to match light/dark.
|
||||||
|
applyIconTheme(p);
|
||||||
|
QET::Palette::refreshStyleSheets();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief QETApp::quitQET
|
@brief QETApp::quitQET
|
||||||
Request the closing of all windows;
|
Request the closing of all windows;
|
||||||
@@ -2404,7 +2479,13 @@ void QETApp::initStyle()
|
|||||||
|
|
||||||
//Apply or not the system style
|
//Apply or not the system style
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
useSystemPalette(settings.value("usesystemcolors", true).toBool());
|
if (settings.value("usesystemcolors", true).toBool()) {
|
||||||
|
useSystemPalette(true);
|
||||||
|
} else if (settings.contains("customapplicationcolor")) {
|
||||||
|
useCustomPalette(QColor(settings.value("customapplicationcolor").toString()));
|
||||||
|
} else {
|
||||||
|
useSystemPalette(false);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS) && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
#if defined(Q_OS_MACOS) && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||||
// Setting an application palette stops Qt from following the OS
|
// Setting an application palette stops Qt from following the OS
|
||||||
@@ -3045,3 +3126,5 @@ int QETApp::projectId(const QETProject *project) {
|
|||||||
}
|
}
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QETApp::m_interface_language;
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class QETApp : public QObject
|
|||||||
public:
|
public:
|
||||||
static QETApp *instance();
|
static QETApp *instance();
|
||||||
void setLanguage(const QString &);
|
void setLanguage(const QString &);
|
||||||
|
static QString interfaceLanguage() { return m_interface_language; }
|
||||||
static QString langFromSetting ();
|
static QString langFromSetting ();
|
||||||
void switchLayout(Qt::LayoutDirection);
|
void switchLayout(Qt::LayoutDirection);
|
||||||
static void printHelp();
|
static void printHelp();
|
||||||
@@ -247,6 +248,8 @@ class QETApp : public QObject
|
|||||||
static QString m_user_custom_tbt_dir;
|
static QString m_user_custom_tbt_dir;
|
||||||
static QString m_user_macros_dir;
|
static QString m_user_macros_dir;
|
||||||
|
|
||||||
|
static QString m_interface_language;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void systray(QSystemTrayIcon::ActivationReason);
|
void systray(QSystemTrayIcon::ActivationReason);
|
||||||
void reduceEveryEditor();
|
void reduceEveryEditor();
|
||||||
@@ -263,6 +266,7 @@ class QETApp : public QObject
|
|||||||
void setMainWindowVisible(QMainWindow *, bool);
|
void setMainWindowVisible(QMainWindow *, bool);
|
||||||
void invertMainWindowVisibility(QWidget *);
|
void invertMainWindowVisibility(QWidget *);
|
||||||
void useSystemPalette(bool);
|
void useSystemPalette(bool);
|
||||||
|
void useCustomPalette(const QColor &color);
|
||||||
void quitQET();
|
void quitQET();
|
||||||
void checkRemainingWindows();
|
void checkRemainingWindows();
|
||||||
void openFiles(const QETArguments &);
|
void openFiles(const QETArguments &);
|
||||||
|
|||||||
@@ -732,6 +732,16 @@ void DynamicElementTextItem::paint(QPainter *painter, const QStyleOptionGraphics
|
|||||||
{
|
{
|
||||||
DiagramTextItem::paint(painter, option, widget);
|
DiagramTextItem::paint(painter, option, widget);
|
||||||
|
|
||||||
|
//Only ever repositions already-existing sibling items here --
|
||||||
|
//never adds or removes one. paint() runs while QGraphicsScene is
|
||||||
|
//iterating its item list to draw it, and mutating that list mid
|
||||||
|
//-iteration (which addResizeHandles()/removeResizeHandles() do,
|
||||||
|
//through QGraphicsScene::addItem()/removeItem()) crashes. An
|
||||||
|
//earlier version of this fix called them from here and crashed
|
||||||
|
//qelectrotech reproducibly on deselecting a text (SIGABRT); see
|
||||||
|
//refreshResizeHandlesVisibility() for where that now happens
|
||||||
|
//instead -- itemChange(), Qt's own safe hook for exactly this,
|
||||||
|
//already used below for this item's own selection.
|
||||||
if (m_left_resize_handle || m_right_resize_handle)
|
if (m_left_resize_handle || m_right_resize_handle)
|
||||||
updateResizeHandlesPos();
|
updateResizeHandlesPos();
|
||||||
|
|
||||||
@@ -826,10 +836,7 @@ QVariant DynamicElementTextItem::itemChange(QGraphicsItem::GraphicsItemChange ch
|
|||||||
}
|
}
|
||||||
else if (change == QGraphicsItem::ItemSelectedHasChanged)
|
else if (change == QGraphicsItem::ItemSelectedHasChanged)
|
||||||
{
|
{
|
||||||
if (value.toBool())
|
refreshResizeHandlesVisibility();
|
||||||
addResizeHandles();
|
|
||||||
else
|
|
||||||
removeResizeHandles();
|
|
||||||
}
|
}
|
||||||
else if (change == QGraphicsItem::ItemSceneHasChanged && !scene())
|
else if (change == QGraphicsItem::ItemSceneHasChanged && !scene())
|
||||||
{
|
{
|
||||||
@@ -878,6 +885,31 @@ bool DynamicElementTextItem::sceneEventFilter(QGraphicsItem *watched, QEvent *ev
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief DynamicElementTextItem::refreshResizeHandlesVisibility
|
||||||
|
Show the resize handles when this text is selected directly, OR when its
|
||||||
|
parent element is -- which is what an ordinary click without Shift
|
||||||
|
selects (DynamicElementTextItem::mousePressEvent() forwards a plain
|
||||||
|
click to the parent, so dragging a symbol by its label moves the whole
|
||||||
|
symbol; a pre-existing, unrelated behaviour, left untouched here).
|
||||||
|
Without this, the handles were reachable only via Shift+click or a
|
||||||
|
right-click's context menu, neither of which a user reaches for to
|
||||||
|
resize a text field (qelectrotech#591, reported by @arummler).
|
||||||
|
|
||||||
|
Called from itemChange() -- both this item's own ItemSelectedHasChanged,
|
||||||
|
below, and Element::itemChange() on the parent's, which calls this on
|
||||||
|
every one of its texts. Not from paint(): see the comment there for why
|
||||||
|
that crashed.
|
||||||
|
*/
|
||||||
|
void DynamicElementTextItem::refreshResizeHandlesVisibility()
|
||||||
|
{
|
||||||
|
const bool handles_wanted = isSelected() || (m_parent_element && m_parent_element->isSelected());
|
||||||
|
if (handles_wanted && !m_left_resize_handle)
|
||||||
|
addResizeHandles();
|
||||||
|
else if (!handles_wanted && m_left_resize_handle)
|
||||||
|
removeResizeHandles();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief DynamicElementTextItem::addResizeHandles
|
@brief DynamicElementTextItem::addResizeHandles
|
||||||
Create and show the two width-resize handles (left/right edge of
|
Create and show the two width-resize handles (left/right edge of
|
||||||
@@ -917,20 +949,32 @@ void DynamicElementTextItem::removeResizeHandles()
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
@brief DynamicElementTextItem::updateResizeHandlesPos
|
@brief DynamicElementTextItem::updateResizeHandlesPos
|
||||||
Keep the two resize handles at the vertical middle of frameRect()'s left
|
Keep the two resize handles at the vertical middle of boundingRect()'s
|
||||||
and right edges, in scene coordinates -- called on every paint() so it
|
left and right edges, in scene coordinates -- called on every paint() so
|
||||||
stays correct across every kind of change that can move this item or
|
it stays correct across every kind of change that can move this item or
|
||||||
change its size (position, rotation, font, text, textWidth...) without
|
change its size (position, rotation, font, text, textWidth...) without
|
||||||
needing a dedicated hook for each one.
|
needing a dedicated hook for each one.
|
||||||
|
|
||||||
|
Deliberately boundingRect(), not frameRect(): frameRect() is a tight box
|
||||||
|
around the text's own natural (idealWidth()) size, re-centred inside
|
||||||
|
boundingRect() -- it does not grow with textWidth(). Once a text has
|
||||||
|
been widened, that leaves a growing gap between the tight frame and the
|
||||||
|
dashed selection outline QGraphicsView draws at boundingRect(), which is
|
||||||
|
the box a user actually sees and expects a resize handle to sit on
|
||||||
|
(qelectrotech#591, reported by @arummler: "the drag elements should be
|
||||||
|
on the border of the box"). boundingRect() reflects the full
|
||||||
|
textWidth() (it is QGraphicsTextItem's own, driven by the document's
|
||||||
|
laid-out size), so the handles now track the box that is visibly
|
||||||
|
resized rather than the text glyphs inside it.
|
||||||
*/
|
*/
|
||||||
void DynamicElementTextItem::updateResizeHandlesPos()
|
void DynamicElementTextItem::updateResizeHandlesPos()
|
||||||
{
|
{
|
||||||
if (!m_left_resize_handle || !m_right_resize_handle)
|
if (!m_left_resize_handle || !m_right_resize_handle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QRectF fr = frameRect();
|
QRectF br = boundingRect();
|
||||||
m_left_resize_handle->setPos(mapToScene(QPointF(fr.left(), fr.center().y())));
|
m_left_resize_handle->setPos(mapToScene(QPointF(br.left(), br.center().y())));
|
||||||
m_right_resize_handle->setPos(mapToScene(QPointF(fr.right(), fr.center().y())));
|
m_right_resize_handle->setPos(mapToScene(QPointF(br.right(), br.center().y())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1289,9 +1333,15 @@ void DynamicElementTextItem::updateLabel()
|
|||||||
|
|
||||||
|
|
||||||
if(m_text_from == ElementInfo && element) {
|
if(m_text_from == ElementInfo && element) {
|
||||||
setPlainText(element->actualLabel());
|
QString new_label = element->actualLabel();
|
||||||
|
if (toPlainText() != new_label) {
|
||||||
|
setPlainText(new_label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (m_text_from == CompositeText) {
|
else if (m_text_from == CompositeText) {
|
||||||
|
// Use actualLabel() to ensure %{label} reflects the current
|
||||||
|
// resolved label (e.g. after a folio/page-number change)
|
||||||
|
dc.addValue(QStringLiteral("label"), element->actualLabel());
|
||||||
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, dc));
|
setPlainText(autonum::AssignVariables::replaceVariable(m_composite_text, dc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,6 +121,12 @@ class DynamicElementTextItem : public DiagramTextItem
|
|||||||
void setRotationPointCenter(bool set);
|
void setRotationPointCenter(bool set);
|
||||||
bool rotationPointCenter() const;
|
bool rotationPointCenter() const;
|
||||||
|
|
||||||
|
//Called by Element::itemChange() when the PARENT's selection
|
||||||
|
//changes, so the parent can keep each of its texts' resize
|
||||||
|
//handles in sync with its own selection state. Public for that;
|
||||||
|
//see the .cpp for why it exists.
|
||||||
|
void refreshResizeHandlesVisibility();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
|||||||
@@ -1664,6 +1664,31 @@ void Element::hoverLeaveEvent(QGraphicsSceneHoverEvent *e)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Element::itemChange
|
||||||
|
On ItemSelectedHasChanged, tell each of this element's own dynamic texts
|
||||||
|
to re-check whether its resize handles should be showing --
|
||||||
|
DynamicElementTextItem::refreshResizeHandlesVisibility() shows them when
|
||||||
|
either the text itself or its parent (this) is selected. An ordinary
|
||||||
|
click with no Shift selects the parent, not the text
|
||||||
|
(DynamicElementTextItem::mousePressEvent() forwards it), so without this
|
||||||
|
a plain click on a symbol never showed the resize handles this PR adds
|
||||||
|
to its texts (qelectrotech#591, reported by @arummler) -- only
|
||||||
|
Shift+click or a right-click's context menu did, since those are the
|
||||||
|
paths that leave the text itself selected.
|
||||||
|
*/
|
||||||
|
QVariant Element::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (change == QGraphicsItem::ItemSelectedHasChanged)
|
||||||
|
{
|
||||||
|
const QList<DynamicElementTextItem *> texts = dynamicTextItems();
|
||||||
|
for (DynamicElementTextItem *deti : texts) {
|
||||||
|
deti->refreshResizeHandlesVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QetGraphicsItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Element::setUpFormula
|
@brief Element::setUpFormula
|
||||||
Set up the formula used to create the label of this element
|
Set up the formula used to create the label of this element
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ class Element : public QetGraphicsItem
|
|||||||
QGraphicsSceneMouseEvent *event) override;
|
QGraphicsSceneMouseEvent *event) override;
|
||||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *) override;
|
void hoverEnterEvent(QGraphicsSceneHoverEvent *) override;
|
||||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override;
|
void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override;
|
||||||
|
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//ATTRIBUTES related to linked element
|
//ATTRIBUTES related to linked element
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QMdiArea>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
|
#include <QTabBar>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -307,4 +309,10 @@ void QET::Palette::refreshStyleSheets()
|
|||||||
for (QWidget *widget : widgets)
|
for (QWidget *widget : widgets)
|
||||||
if (!widget->styleSheet().isEmpty())
|
if (!widget->styleSheet().isEmpty())
|
||||||
widget->setStyleSheet(widget->styleSheet());
|
widget->setStyleSheet(widget->styleSheet());
|
||||||
|
|
||||||
|
// Force an immediate repaint on tab bars and MDI areas so their text
|
||||||
|
// updates together with the rest of the UI, not one event loop later.
|
||||||
|
for (QWidget *widget : widgets)
|
||||||
|
if (qobject_cast<QTabBar *>(widget) || qobject_cast<QMdiArea *>(widget))
|
||||||
|
widget->update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "../../utils/qetsettings.h"
|
#include "../../utils/qetsettings.h"
|
||||||
#include "../../utils/qetutils.h"
|
#include "../../utils/qetutils.h"
|
||||||
#include "../../qetmessagebox.h"
|
#include "../../qetmessagebox.h"
|
||||||
|
#include "../nokde/kcolorbutton.h"
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFontDialog>
|
#include <QFontDialog>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
@@ -74,6 +75,12 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
|||||||
ui->DiagramEditor_Grid_PointSize_min_sb->setValue(settings.value("diagrameditor/grid_pointsize_min", 1).toInt());
|
ui->DiagramEditor_Grid_PointSize_min_sb->setValue(settings.value("diagrameditor/grid_pointsize_min", 1).toInt());
|
||||||
ui->DiagramEditor_Grid_PointSize_max_sb->setValue(settings.value("diagrameditor/grid_pointsize_max", 1).toInt());
|
ui->DiagramEditor_Grid_PointSize_max_sb->setValue(settings.value("diagrameditor/grid_pointsize_max", 1).toInt());
|
||||||
ui->m_use_system_color_cb->setChecked(settings.value("usesystemcolors", "true").toBool());
|
ui->m_use_system_color_cb->setChecked(settings.value("usesystemcolors", "true").toBool());
|
||||||
|
bool sysColors = ui->m_use_system_color_cb->isChecked();
|
||||||
|
ui->m_custom_app_color_kpb->setEnabled(!sysColors);
|
||||||
|
if (settings.contains("customapplicationcolor"))
|
||||||
|
ui->m_custom_app_color_kpb->setColor(QColor(settings.value("customapplicationcolor").toString()));
|
||||||
|
else
|
||||||
|
ui->m_custom_app_color_kpb->setColor(QApplication::palette().color(QPalette::Window));
|
||||||
bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
|
bool tabbed = settings.value("diagrameditor/viewmode", "tabbed") == "tabbed";
|
||||||
if(tabbed)
|
if(tabbed)
|
||||||
ui->m_use_tab_mode_rb->setChecked(true);
|
ui->m_use_tab_mode_rb->setChecked(true);
|
||||||
@@ -206,7 +213,17 @@ void GeneralConfigurationPage::applyConf()
|
|||||||
bool must_use_system_colors = ui->m_use_system_color_cb->isChecked();
|
bool must_use_system_colors = ui->m_use_system_color_cb->isChecked();
|
||||||
settings.setValue("usesystemcolors", must_use_system_colors);
|
settings.setValue("usesystemcolors", must_use_system_colors);
|
||||||
if (was_using_system_colors != must_use_system_colors) {
|
if (was_using_system_colors != must_use_system_colors) {
|
||||||
QETApp::instance()->useSystemPalette(must_use_system_colors);
|
if (must_use_system_colors) {
|
||||||
|
QETApp::instance()->useSystemPalette(true);
|
||||||
|
} else {
|
||||||
|
QColor custom_color = ui->m_custom_app_color_kpb->color();
|
||||||
|
settings.setValue("customapplicationcolor", custom_color.name());
|
||||||
|
QETApp::instance()->useCustomPalette(custom_color);
|
||||||
|
}
|
||||||
|
} else if (!must_use_system_colors) {
|
||||||
|
QColor custom_color = ui->m_custom_app_color_kpb->color();
|
||||||
|
settings.setValue("customapplicationcolor", custom_color.name());
|
||||||
|
QETApp::instance()->useCustomPalette(custom_color);
|
||||||
}
|
}
|
||||||
settings.setValue("border-columns_0",ui->m_border_0->isChecked());
|
settings.setValue("border-columns_0",ui->m_border_0->isChecked());
|
||||||
settings.setValue("lang", ui->m_lang_cb->itemData(ui->m_lang_cb->currentIndex()).toString());
|
settings.setValue("lang", ui->m_lang_cb->itemData(ui->m_lang_cb->currentIndex()).toString());
|
||||||
@@ -625,3 +642,14 @@ void GeneralConfigurationPage::on_m_hdpi_round_cb_clicked(bool checked)
|
|||||||
ui->m_hdpi_round_policy_cb->setEnabled(checked);
|
ui->m_hdpi_round_policy_cb->setEnabled(checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief GeneralConfigurationPage::on_m_use_system_color_cb_toggled
|
||||||
|
Enable/disable the custom color picker when the system color
|
||||||
|
checkbox is toggled.
|
||||||
|
@param checked
|
||||||
|
*/
|
||||||
|
void GeneralConfigurationPage::on_m_use_system_color_cb_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->m_custom_app_color_kpb->setEnabled(!checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class GeneralConfigurationPage : public ConfigPage
|
|||||||
void on_ElementEditor_Grid_PointSize_min_sb_valueChanged(int value);
|
void on_ElementEditor_Grid_PointSize_min_sb_valueChanged(int value);
|
||||||
|
|
||||||
void on_m_hdpi_round_cb_clicked(bool checked);
|
void on_m_hdpi_round_cb_clicked(bool checked);
|
||||||
|
void on_m_use_system_color_cb_toggled(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillLang();
|
void fillLang();
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
<string>Apparence</string>
|
<string>Apparence</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="m_system_color_layout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="m_use_system_color_cb">
|
<widget class="QCheckBox" name="m_use_system_color_cb">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@@ -31,6 +33,15 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="KColorButton" name="m_custom_app_color_kpb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Couleur de l'application</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -1161,4 +1172,11 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
|
|||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KColorButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header>nokde/kcolorbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
</ui>
|
</ui>
|
||||||
|
|||||||
@@ -314,31 +314,15 @@ void LinkElementCommand::redo()
|
|||||||
if(m_element->diagram()) m_element->diagram()->showMe();
|
if(m_element->diagram()) m_element->diagram()->showMe();
|
||||||
makeLink(m_linked_after);
|
makeLink(m_linked_after);
|
||||||
|
|
||||||
//If the action is to link two reports together, we check if the conductors
|
//If the action is to link two reports together, and the conductors
|
||||||
//of the new potential have the same text, function, and protocol.
|
//of the new potential disagree on a property that matters, a
|
||||||
//if not, a dialog ask what do to.
|
//dialog asks what to do. See reportLinkNeedsPotentialChoice() for
|
||||||
|
//what "disagree" checks and the bug fixed there (bugtracker #974).
|
||||||
if (m_first_redo && (m_element->linkType() & Element::AllReport) \
|
if (m_first_redo && (m_element->linkType() & Element::AllReport) \
|
||||||
&& m_element->conductors().size() \
|
&& m_element->conductors().size() \
|
||||||
&& m_linked_after.size() && m_linked_after.first()->conductors().size())
|
&& m_linked_after.size() && m_linked_after.first()->conductors().size())
|
||||||
{
|
{
|
||||||
//fill list of potential
|
if (reportLinkNeedsPotentialChoice(m_element, m_linked_after.first()))
|
||||||
QSet <Conductor *> c_list = m_element->conductors().first()->relatedPotentialConductors();
|
|
||||||
c_list << m_element->conductors().first();
|
|
||||||
//fill list of text
|
|
||||||
QStringList str_txt;
|
|
||||||
QStringList str_funct;
|
|
||||||
QStringList str_tens;
|
|
||||||
for (const Conductor *c : c_list)
|
|
||||||
{
|
|
||||||
str_txt << c->properties().text;
|
|
||||||
str_funct << c->properties().m_function;
|
|
||||||
str_tens << c->properties().m_tension_protocol;
|
|
||||||
str_tens << c->properties().m_wire_color;
|
|
||||||
str_tens << c->properties().m_wire_section;
|
|
||||||
}
|
|
||||||
|
|
||||||
//check text list, isn't same in potential, ask user what to do
|
|
||||||
if (!QET::eachStrIsEqual(str_txt) || !QET::eachStrIsEqual(str_funct) || !QET::eachStrIsEqual(str_tens))
|
|
||||||
{
|
{
|
||||||
PotentialSelectorDialog psd(m_element, this);
|
PotentialSelectorDialog psd(m_element, this);
|
||||||
psd.exec();
|
psd.exec();
|
||||||
@@ -348,6 +332,64 @@ void LinkElementCommand::redo()
|
|||||||
QUndoCommand::redo();
|
QUndoCommand::redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief LinkElementCommand::reportLinkNeedsPotentialChoice
|
||||||
|
Whether linking these two report elements (next_report/previous_report)
|
||||||
|
would pop PotentialSelectorDialog -- i.e. whether their conductors (if
|
||||||
|
any exist yet, on either side) disagree on a property redo() cares
|
||||||
|
about. Exposed as its own static method, rather than left inline in
|
||||||
|
redo(), for the same reason ConductorCreator::needsPotentialChoice()
|
||||||
|
is: a caller with nobody there to answer a modal dialog (the scripting
|
||||||
|
API) can check first and decline, and the condition cannot drift away
|
||||||
|
from the one redo() actually applies.
|
||||||
|
|
||||||
|
Bug fixed here (bugtracker #974): the original check built ONE
|
||||||
|
combined list from three unrelated fields (tension_protocol,
|
||||||
|
wire_color, wire_section) and tested that whole list for equality --
|
||||||
|
comparing a tension-protocol string against a wire-colour string is
|
||||||
|
never equal even when each field individually matches across every
|
||||||
|
conductor, and wire_color/wire_section are ConductorProperties::
|
||||||
|
m_wire_color/m_wire_section, a separate free-text documentation pair
|
||||||
|
that says nothing about how the wire is actually drawn (that is
|
||||||
|
"color"/"style"). Net effect: the dialog could not reliably detect a
|
||||||
|
real mismatch, including the exact case #974 reported -- two
|
||||||
|
report-linked conductors drawn in different colours -- and could just
|
||||||
|
as easily fire on conductors that matched in every way that mattered.
|
||||||
|
Comparing each relevant field (text/num, function, tension protocol,
|
||||||
|
colour, line style) on its own fixes both.
|
||||||
|
|
||||||
|
@param element_a @param element_b the two elements about to be (or
|
||||||
|
already) linked; order does not matter
|
||||||
|
@return true if the dialog would (or does) open
|
||||||
|
*/
|
||||||
|
bool LinkElementCommand::reportLinkNeedsPotentialChoice(Element *element_a, Element *element_b)
|
||||||
|
{
|
||||||
|
if (!element_a || !element_b) return false;
|
||||||
|
if (element_a->conductors().isEmpty() || element_b->conductors().isEmpty()) return false;
|
||||||
|
|
||||||
|
QSet<Conductor *> c_list;
|
||||||
|
for (Element *e : {element_a, element_b})
|
||||||
|
{
|
||||||
|
if (e->conductors().isEmpty()) continue;
|
||||||
|
c_list << e->conductors().first();
|
||||||
|
c_list += e->conductors().first()->relatedPotentialConductors();
|
||||||
|
}
|
||||||
|
if (c_list.size() < 2) return false;
|
||||||
|
|
||||||
|
QStringList str_txt, str_funct, str_tens, str_color, str_style;
|
||||||
|
for (const Conductor *c : std::as_const(c_list))
|
||||||
|
{
|
||||||
|
str_txt << c->properties().text;
|
||||||
|
str_funct << c->properties().m_function;
|
||||||
|
str_tens << c->properties().m_tension_protocol;
|
||||||
|
str_color << c->properties().color.name();
|
||||||
|
str_style << QString::number(int(c->properties().style));
|
||||||
|
}
|
||||||
|
return !QET::eachStrIsEqual(str_txt) || !QET::eachStrIsEqual(str_funct)
|
||||||
|
|| !QET::eachStrIsEqual(str_tens) || !QET::eachStrIsEqual(str_color)
|
||||||
|
|| !QET::eachStrIsEqual(str_style);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief LinkElementCommand::setUpNewLink
|
@brief LinkElementCommand::setUpNewLink
|
||||||
Update the content of m_link_after with the content of element_list.
|
Update the content of m_link_after with the content of element_list.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class LinkElementCommand : public QUndoCommand
|
|||||||
bool mergeWith(const QUndoCommand *other) override;
|
bool mergeWith(const QUndoCommand *other) override;
|
||||||
|
|
||||||
static bool isLinkable (Element *element_a, Element *element_b, bool already_linked = false);
|
static bool isLinkable (Element *element_a, Element *element_b, bool already_linked = false);
|
||||||
|
static bool reportLinkNeedsPotentialChoice(Element *element_a, Element *element_b);
|
||||||
|
|
||||||
void setLink (const QList<Element *>& element_list);
|
void setLink (const QList<Element *>& element_list);
|
||||||
void setLink (Element *element_);
|
void setLink (Element *element_);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ m_diagram(diagram)
|
|||||||
parts << QObject::tr("%n texte(s)", "", texts_list.count());
|
parts << QObject::tr("%n texte(s)", "", texts_list.count());
|
||||||
if (groups_list.count())
|
if (groups_list.count())
|
||||||
parts << QObject::tr("%n groupe(s) de textes", "", groups_list.count());
|
parts << QObject::tr("%n groupe(s) de textes", "", groups_list.count());
|
||||||
setText(QObject::tr("Pivoter %1").arg(QLocale().createSeparatedList(parts)));
|
setText(QObject::tr("Pivoter %1").arg(QLocale(QETApp::interfaceLanguage()).createSeparatedList(parts)));
|
||||||
|
|
||||||
for(DiagramTextItem *dti : texts_list)
|
for(DiagramTextItem *dti : texts_list)
|
||||||
setupAnimation(dti, "rotation", dti->rotation(), m_rotation);
|
setupAnimation(dti, "rotation", dti->rotation(), m_rotation);
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ add_executable(
|
|||||||
${QET_DIR}/sources/shortcutmanager.cpp)
|
${QET_DIR}/sources/shortcutmanager.cpp)
|
||||||
add_test(NAME tst_qetstrings COMMAND tst_qetstrings)
|
add_test(NAME tst_qetstrings COMMAND tst_qetstrings)
|
||||||
target_include_directories(tst_qetstrings PRIVATE ${QET_DIR}/sources)
|
target_include_directories(tst_qetstrings PRIVATE ${QET_DIR}/sources)
|
||||||
target_link_libraries(tst_qetstrings PRIVATE Qt::Test Qt::Widgets Qt::Xml)
|
target_link_libraries(tst_qetstrings PRIVATE Qt::Test Qt::Widgets Qt::Xml pugixml::pugixml)
|
||||||
|
|
||||||
# CrashHandler::formatInt() -- the async-signal-safe decimal formatter the
|
# CrashHandler::formatInt() -- the async-signal-safe decimal formatter the
|
||||||
# signal handler uses for the "Signal: N" line of a crash dump. Compiles
|
# signal handler uses for the "Signal: N" line of a crash dump. Compiles
|
||||||
@@ -179,11 +179,10 @@ add_test(NAME tst_crashdumps COMMAND tst_crashdumps)
|
|||||||
target_include_directories(tst_crashdumps PRIVATE
|
target_include_directories(tst_crashdumps PRIVATE
|
||||||
${QET_DIR}
|
${QET_DIR}
|
||||||
${QET_DIR}/sources
|
${QET_DIR}/sources
|
||||||
${QET_DIR}/sources/NameList
|
${QET_DIR}/sources/NameList)
|
||||||
${QET_DIR}/pugixml/src)
|
|
||||||
if(Backtrace_FOUND)
|
if(Backtrace_FOUND)
|
||||||
target_link_libraries(tst_crashdumps PRIVATE
|
target_link_libraries(tst_crashdumps PRIVATE
|
||||||
Qt::Test Qt::Widgets Qt::Xml ${Backtrace_LIBRARIES})
|
Qt::Test Qt::Widgets Qt::Xml pugixml::pugixml ${Backtrace_LIBRARIES})
|
||||||
else()
|
else()
|
||||||
target_link_libraries(tst_crashdumps PRIVATE Qt::Test Qt::Widgets Qt::Xml)
|
target_link_libraries(tst_crashdumps PRIVATE Qt::Test Qt::Widgets Qt::Xml)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
#include "qet.h"
|
#include "qet.h"
|
||||||
|
#include "qetapp.h"
|
||||||
|
|
||||||
|
QString QETApp::m_interface_language;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
QET::joinWithSpaces() / QET::splitWithSpaces() are the wire format for the
|
QET::joinWithSpaces() / QET::splitWithSpaces() are the wire format for the
|
||||||
|
|||||||
Reference in New Issue
Block a user