Merge branch 'master' into fix/slave-xref-color-dark-theme-bug247

# Conflicts:
#	sources/qetgraphicsitem/dynamicelementtextitem.cpp
This commit is contained in:
ispyisail
2026-09-12 22:42:11 +12:00
288 changed files with 80732 additions and 35497 deletions
+91 -369
View File
@@ -11,356 +11,7 @@ concurrency:
jobs:
# =============================================================================
# Job 1: Qt5 build (stable track)
# =============================================================================
build-windows:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
submodules: recursive
fetch-depth: 0
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
cache: true
install: >-
git
mingw-w64-ucrt-x86_64-ccache
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-qt5-base
mingw-w64-ucrt-x86_64-qt5-svg
mingw-w64-ucrt-x86_64-qt5-tools
mingw-w64-ucrt-x86_64-qt5-translations
mingw-w64-ucrt-x86_64-qt5-pdf
mingw-w64-ucrt-x86_64-sqlite3
mingw-w64-ucrt-x86_64-pkg-config
mingw-w64-ucrt-x86_64-kwidgetsaddons
mingw-w64-ucrt-x86_64-kcoreaddons
mingw-w64-ucrt-x86_64-extra-cmake-modules
mingw-w64-ucrt-x86_64-nsis
mingw-w64-ucrt-x86_64-angleproject
- name: Cache ccache
uses: actions/cache@v5
with:
path: C:\Users\runneradmin\AppData\Local\ccache
key: ccache-windows-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
ccache-windows-${{ github.ref_name }}-
ccache-windows-
- name: Configure ccache
shell: msys2 {0}
run: |
/ucrt64/bin/ccache --set-config=max_size=500M
/ucrt64/bin/ccache --set-config=compression=true
/ucrt64/bin/ccache -z
echo "=== ccache config ==="
/ucrt64/bin/ccache -p
- name: Patch NSIS Welcome page — fix title font size
shell: msys2 {0}
run: |
set -euo pipefail
WELCOME_NSH=$(find /ucrt64 -path "*/Modern UI 2/Pages/Welcome.nsh" | head -1)
if [ -z "$WELCOME_NSH" ]; then
echo "WARNING: Welcome.nsh not found, skipping font patch"
else
echo "Patching: $WELCOME_NSH"
sed -i '/WelcomePage\.Title\.Font/s/"[0-9]\+" "700"/"10" "700"/' "$WELCOME_NSH"
grep 'WelcomePage.Title.Font' "$WELCOME_NSH"
echo " OK font size patched to 10"
fi
FINISH_NSH=$(find /ucrt64 -path "*/Modern UI 2/Pages/Finish.nsh" | head -1)
if [ -z "$FINISH_NSH" ]; then
echo "WARNING: Finish.nsh not found, skipping font patch"
else
echo "Patching: $FINISH_NSH"
sed -i '/FinishPage\.Title\.Font/s/"[0-9]\+" "700"/"10" "700"/' "$FINISH_NSH"
grep 'FinishPage.Title.Font' "$FINISH_NSH"
echo " OK font size patched to 10"
fi
- name: Force Qt5 — remove Qt6 cmake + tools
shell: msys2 {0}
run: |
set -euo pipefail
rm -rf /ucrt64/lib/cmake/Qt6
pacman -R --noconfirm mingw-w64-ucrt-x86_64-qt6-tools 2>/dev/null || true
echo "=== windeployqt binaries ==="
ls /ucrt64/bin/windeployqt* || echo "NO windeployqt found!"
- name: Build with cmake
shell: msys2 {0}
run: |
set -euo pipefail
cd "$GITHUB_WORKSPACE"
mkdir build && cd build
NPROC=$(nproc)
echo "Available CPUs: $NPROC"
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=/ucrt64 \
-DQt5_DIR=/ucrt64/lib/cmake/Qt5 \
-DQT_VERSION_MAJOR=5 \
-DCMAKE_DISABLE_FIND_PACKAGE_Qt6=ON \
-DBUILD_TESTING=OFF \
-DCMAKE_POLICY_DEFAULT_CMP0077=NEW \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_CXX_FLAGS="-DQET_EXPORT_PROJECT_DB" \
-DCMAKE_C_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"
- name: Show ccache stats
shell: msys2 {0}
run: |
echo "=== ccache statistics ==="
/ucrt64/bin/ccache -s
- name: Verify exe was built
shell: msys2 {0}
run: |
set -euo pipefail
EXE=$(find "$GITHUB_WORKSPACE/build" -maxdepth 3 -iname "qelectrotech.exe" | head -1)
if [ -z "$EXE" ]; then
echo "ERROR: no qelectrotech.exe found in build/"
find "$GITHUB_WORKSPACE/build" -maxdepth 3 -name "*.exe" || true
exit 1
fi
SIZE=$(stat -c%s "$EXE")
echo "Exe found: $EXE ($SIZE bytes)"
[ "$SIZE" -gt 100000 ] || { echo "ERROR: exe too small"; exit 1; }
- name: Deploy — copy exe + windeployqt + DLLs
shell: msys2 {0}
run: |
set -euo pipefail
NSIS_ROOT="$GITHUB_WORKSPACE/nsis_root"
FILES="$NSIS_ROOT/files"
BIN="$FILES/bin"
mkdir -p "$BIN"
EXE=$(find "$GITHUB_WORKSPACE/build" -maxdepth 3 -iname "qelectrotech.exe" | head -1)
echo "Copying exe: $EXE -> $BIN/QElectroTech.exe"
cp "$EXE" "$BIN/QElectroTech.exe"
cd "$BIN"
/ucrt64/bin/windeployqt-qt5 \
--release \
--no-translations \
--no-compiler-runtime \
./QElectroTech.exe || true
echo "=== 3-pass transitive DLL scan ==="
set +e
for PASS in 1 2 3; do
echo "-- Pass $PASS --"
for bin_file in "$BIN"/*.dll "$BIN"/*.exe "$BIN"/sqldrivers/*.dll "$BIN"/platforms/*.dll "$BIN"/imageformats/*.dll; do
[ -f "$bin_file" ] || continue
while IFS= read -r line; do
dll_path=$(echo "$line" | awk '{print $3}')
[ -f "$dll_path" ] || continue
dll_name=$(basename "$dll_path")
dst="$BIN/$dll_name"
if [ ! -f "$dst" ]; then
cp "$dll_path" "$dst"
echo " Copied (pass $PASS): $dll_name"
fi
done < <(ldd "$bin_file" 2>/dev/null | grep -i '/ucrt64/bin/')
done
done
set -e
DLL_COUNT=$(find "$BIN" -name "*.dll" | wc -l)
echo "=== $DLL_COUNT DLLs present after scan ==="
ls -lh "$BIN/QElectroTech.exe" || { echo "ERROR: exe missing from bin/"; exit 1; }
[ "$DLL_COUNT" -gt 5 ] || { echo "ERROR: too few DLLs"; exit 1; }
cd "$GITHUB_WORKSPACE"
cp /ucrt64/bin/libgcc_s_seh-1.dll "$BIN/"
cp /ucrt64/bin/libstdc++-6.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/lang_extra.nsh" "$NSIS_ROOT/"
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra_fr.nsh" "$NSIS_ROOT/"
cp "$GITHUB_WORKSPACE/build-aux/windows/lang_extra_missing.nsh" "$NSIS_ROOT/"
cp -r "$GITHUB_WORKSPACE/build-aux/windows/nsis_base/." "$NSIS_ROOT/"
curl -fsSL \
"https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/refs/heads/master/misc/Lancer%20QET.bat" \
-o "$FILES/Lancer QET.bat"
cp -r "$GITHUB_WORKSPACE/elements" "$FILES/elements" || true
cp -r "$GITHUB_WORKSPACE/titleblocks" "$FILES/titleblocks" || true
cp -r "$GITHUB_WORKSPACE/examples" "$FILES/examples" || true
cp -r "$GITHUB_WORKSPACE/fonts" "$FILES/fonts" || true
cp -r "$GITHUB_WORKSPACE/lang" "$FILES/lang" || true
find "$GITHUB_WORKSPACE/build" -name "*.qm" -exec cp {} "$FILES/lang/" \; 2>/dev/null || true
echo "=== .qm files in files/lang/ ==="
ls "$FILES/lang/"*.qm 2>/dev/null | wc -l || echo "0 .qm files"
for f in LICENSE ChangeLog CREDIT README ELEMENTS.LICENSE; do
cp "$GITHUB_WORKSPACE/$f" "$FILES/$f" 2>/dev/null || true
done
echo "=== Verification of key files in files/ ==="
for f in LICENSE ChangeLog CREDIT README ELEMENTS.LICENSE \
qet_uninstall_file_associations.reg register_filetypes.bat "Lancer QET.bat"; do
[ -f "$FILES/$f" ] \
&& echo " OK : $f" \
|| echo " MISSING: $f"
done
for d in ico elements lang titleblocks fonts examples bin; do
[ -d "$FILES/$d" ] \
&& echo " OK : $d/" \
|| echo " MISSING: $d/"
done
- name: Extract version for installer name
shell: msys2 {0}
id: qet_version
run: |
set -euo pipefail
GITCOMMIT=$(git -C "$GITHUB_WORKSPACE" rev-parse --short HEAD)
A=$(git -C "$GITHUB_WORKSPACE" rev-list HEAD --count)
HEAD=$(( A + 473 ))
VERSION=$(grep 'return QVersionNumber{' "$GITHUB_WORKSPACE/sources/qetversion.cpp" \
| head -1 \
| awk -F '{' '{ print $2 }' \
| awk -F '}' '{ print $1 }' \
| sed -e 's/,/./g' -e 's/ //g')
[ -z "$VERSION" ] && VERSION="dev"
FULL_VERSION="${VERSION}-r${HEAD}-${GITCOMMIT}_x86_64-win64"
echo "version=$FULL_VERSION" >> "$GITHUB_OUTPUT"
echo "base_version=$VERSION" >> "$GITHUB_OUTPUT"
echo "gitcommit=$GITCOMMIT" >> "$GITHUB_OUTPUT"
echo "head=$HEAD" >> "$GITHUB_OUTPUT"
echo "VERSION : $VERSION"
echo "GITCOMMIT : $GITCOMMIT"
echo "HEAD (rev) : $HEAD"
echo "FULL : $FULL_VERSION"
- name: Patch QET64.nsi — version + exe name + absolute paths
shell: msys2 {0}
run: |
set -euo pipefail
VERSION="${{ steps.qet_version.outputs.version }}"
NSI="$GITHUB_WORKSPACE/nsis_root/QET64.nsi"
FILES_WIN=$(cygpath -w "$GITHUB_WORKSPACE/nsis_root/files")
SCRIPT="$GITHUB_WORKSPACE/build-aux/windows/patch_nsi.py"
python3 "$SCRIPT" "$NSI" "$VERSION" "$FILES_WIN"
echo "=== Verification ==="
grep 'SOFT_VERSION' "$NSI" | head -1
grep -m2 'nsis_root' "$NSI" | head -2
echo "=== Contents of nsis_root/files/ ==="
ls "$GITHUB_WORKSPACE/nsis_root/files/"
- name: Build NSIS installer
shell: msys2 {0}
run: |
set -euo pipefail
NSIS_ROOT="$GITHUB_WORKSPACE/nsis_root"
cd "$NSIS_ROOT"
echo "=== CWD : $(pwd) ==="
MSYS2_ARG_CONV_EXCL="*" makensis /V4 QET64.nsi
RC=$?
echo "=== Contents of nsis_root after makensis ==="
ls "$NSIS_ROOT/"
[ $RC -eq 0 ] || { echo "ERROR: makensis failed (exit $RC)"; exit 1; }
- name: Move installer to dist/
shell: msys2 {0}
run: |
set -euo pipefail
mkdir -p "$GITHUB_WORKSPACE/dist"
INSTALLER=$(find "$GITHUB_WORKSPACE/nsis_root" -maxdepth 1 -iname "installer_*.exe" | head -1)
if [ -z "$INSTALLER" ]; then
echo "ERROR: no installer .exe found in nsis_root/"
ls "$GITHUB_WORKSPACE/nsis_root/"
exit 1
fi
echo "Moving: $INSTALLER -> dist/"
mv "$INSTALLER" "$GITHUB_WORKSPACE/dist/"
- name: Upload build logs on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: build-logs
path: |
build/CMakeFiles/*.log
nsis_root/files/bin/
if-no-files-found: warn
- name: Zip portable (readytouse)
id: zip_portable
shell: pwsh
run: |
$version = "${{ steps.qet_version.outputs.base_version }}"
$head = "${{ steps.qet_version.outputs.head }}"
$zipName = "qelectrotech-${version}+git${head}-x86-win64-readytouse.zip"
$src = "$env:GITHUB_WORKSPACE\nsis_root\files"
$dst = "$env:GITHUB_WORKSPACE\dist\$zipName"
$7z = "C:\Program Files\7-Zip\7z.exe"
New-Item -ItemType Directory -Force -Path "$env:GITHUB_WORKSPACE\dist" | Out-Null
& $7z a -tzip -mx=5 -mmt=on $dst "$src\*"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$sizeMB = [math]::Round((Get-Item $dst).Length / 1MB, 1)
Write-Output "ZIP created: $zipName ($sizeMB MB)"
"zip_name=$zipName" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
- name: Upload portable (files/ without installer)
uses: actions/upload-artifact@v7
with:
name: qelectrotech-${{ steps.qet_version.outputs.base_version }}+git${{ steps.qet_version.outputs.head }}-x86-win64-readytouse
path: dist/${{ steps.zip_portable.outputs.zip_name }}
retention-days: 40
- name: Upload NSIS installer
uses: actions/upload-artifact@v7
with:
name: qelectrotech-windows-installer
path: dist/Installer_*.exe
retention-days: 40
- name: Upload portable (nom fixe pour le workflow MSI)
uses: actions/upload-artifact@v7
with:
name: qelectrotech-windows-portable
path: nsis_root/files/
retention-days: 40
# =============================================================================
# Job 2: Qt6 build (EXPERIMENTAL track)
# Job 1: Windows build (Qt6/KF6 — sole track since the Qt5 track was removed)
#
# Version label: the C++ source (sources/qetversion.cpp) intentionally stays
# Qt-agnostic — QT_VERSION-based detection inside the binary proved unreliable
@@ -368,6 +19,9 @@ jobs:
# certainty which Qt major version it configured (-DQT_VERSION_MAJOR=6), so it
# is safe to label the *package* "0.200.1" at this level, without touching
# QetVersion::currentVersion() or making the binary self-detect its Qt build.
#
# Job id kept as "build-windows-qt6" (not renamed to "build-windows") in case
# branch protection / required status checks reference this exact job name.
# =============================================================================
build-windows-qt6:
runs-on: windows-latest
@@ -397,6 +51,9 @@ jobs:
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-kwidgetsaddons
mingw-w64-ucrt-x86_64-kcoreaddons
mingw-w64-ucrt-x86_64-extra-cmake-modules
mingw-w64-ucrt-x86_64-nsis
mingw-w64-ucrt-x86_64-angleproject
@@ -456,11 +113,12 @@ jobs:
-DCMAKE_PREFIX_PATH=/ucrt64 \
-DQt6_DIR=/ucrt64/lib/cmake/Qt6 \
-DQT_VERSION_MAJOR=6 \
-DBUILD_WITH_KF5=OFF \
-DBUILD_WITH_KF=ON \
-DBUILD_KF=OFF \
-DPACKAGE_TESTS=OFF \
-DCMAKE_POLICY_DEFAULT_CMP0077=NEW \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-DCMAKE_CXX_FLAGS="-DQET_EXPORT_PROJECT_DB" \
-DQET_EXPORT_PROJECT_DB=ON \
-DCMAKE_C_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=/ucrt64/bin/ccache \
-DSQLite3_INCLUDE_DIR=/ucrt64/include \
@@ -559,10 +217,71 @@ jobs:
cp -r "$GITHUB_WORKSPACE/examples" "$FILES/examples" || true
cp -r "$GITHUB_WORKSPACE/fonts" "$FILES/fonts" || true
cp -r "$GITHUB_WORKSPACE/lang" "$FILES/lang" || true
find "$GITHUB_WORKSPACE/build" -name "*.qm" -exec cp {} "$FILES/lang/" \; 2>/dev/null || true
echo "=== .qm files in files/lang/ ==="
ls "$FILES/lang/"*.qm 2>/dev/null | wc -l || echo "0 .qm files"
# --- Translations ---
# Since PR #751 the .qm files are no longer tracked in git: lrelease
# generates them in build/lang/ (OUTPUT_LOCATION "lang", relative to
# the build dir). Expected set = the .ts listed in TS_FILES
# (cmake/qet_compilation_vars.cmake): a missing .qm fails the job
# instead of silently shipping an untranslated build; a .ts present
# in lang/ but not listed in TS_FILES only raises a warning.
# find/grep only, no shell glob: $GITHUB_WORKSPACE is a Windows path
# (D:\a\...) and its backslashes break glob patterns.
QM_SRC="$GITHUB_WORKSPACE/build/lang"
mkdir -p "$FILES/lang"
TS_LISTED=$(grep -o 'lang/qet_[A-Za-z_]*\.ts' "$GITHUB_WORKSPACE/cmake/qet_compilation_vars.cmake" \
| sed -e 's#^lang/##' -e 's#\.ts$##' | LC_ALL=C sort -u || true)
[ -n "$TS_LISTED" ] || { echo "ERROR: cannot read TS_FILES from cmake/qet_compilation_vars.cmake"; exit 1; }
TS_PRESENT=$(find "$GITHUB_WORKSPACE/lang" -maxdepth 1 -name 'qet_*.ts' -exec basename {} .ts \; | LC_ALL=C sort)
UNLISTED=$(LC_ALL=C comm -13 <(echo "$TS_LISTED") <(echo "$TS_PRESENT"))
if [ -n "$UNLISTED" ]; then
echo "::warning::.ts files not in TS_FILES, no .qm built:" $UNLISTED
fi
find "$QM_SRC" -maxdepth 1 -name 'qet_*.qm' -exec cp {} "$FILES/lang/" \; 2>/dev/null || true
QM_PRESENT=$(find "$FILES/lang" -maxdepth 1 -name 'qet_*.qm' -exec basename {} .qm \; | LC_ALL=C sort)
MISSING=$(LC_ALL=C comm -23 <(echo "$TS_LISTED") <(echo "$QM_PRESENT"))
QM_COUNT=$(printf '%s\n' "$QM_PRESENT" | grep -c . || true)
TS_COUNT=$(printf '%s\n' "$TS_LISTED" | grep -c .)
echo "=== $QM_COUNT .qm files copied to files/lang/ (expected: $TS_COUNT) ==="
if [ -n "$MISSING" ]; then
echo "ERROR: missing translations:" $MISSING
find "$GITHUB_WORKSPACE/build" -name '*.qm' || true
exit 1
fi
# Qt's own translations (OK/Cancel buttons, standard dialogs...):
# they come from qtbase_XX.qm, not from QET's .ts, and windeployqt
# runs with --no-translations. QETApp::setLanguage() falls back to
# lang/qt_XX.qm, so copy each qtbase_XX.qm there under that name
# (qtbase_XX.qm is standalone, unlike Qt's qt_XX.qm meta catalogs).
QT_TR_DIR=/ucrt64/share/qt6/translations
if [ ! -d "$QT_TR_DIR" ]; then
QT_TR_DIR=$(cygpath -u "$(/ucrt64/bin/qtpaths6 --query QT_INSTALL_TRANSLATIONS 2>/dev/null)" 2>/dev/null || true)
fi
find "$QT_TR_DIR" -maxdepth 1 -name 'qtbase_*.qm' 2>/dev/null | while read -r f; do
l=$(basename "$f" .qm)
cp "$f" "$FILES/lang/qt_${l#qtbase_}.qm"
done
# QET languages Qt only ships with a region (pt -> pt_PT, zh -> zh_CN):
# QTranslator only shortens codes (fr_FR -> fr), it never extends them.
for q in $TS_LISTED; do
l=${q#qet_}
if [ ! -e "$FILES/lang/qt_$l.qm" ]; then
if [ -e "$QT_TR_DIR/qtbase_${l}_${l^^}.qm" ]; then
alt="$QT_TR_DIR/qtbase_${l}_${l^^}.qm"
else
alt=$(find "$QT_TR_DIR" -maxdepth 1 -name "qtbase_${l}_*.qm" 2>/dev/null | LC_ALL=C sort | head -1 || true)
fi
if [ -n "$alt" ]; then
cp "$alt" "$FILES/lang/qt_$l.qm"
fi
fi
done
QT_QM_COUNT=$(find "$FILES/lang" -maxdepth 1 -name 'qt_*.qm' | wc -l)
echo "=== $QT_QM_COUNT Qt translation files (qt_*.qm) copied from $QT_TR_DIR ==="
if [ "$QT_QM_COUNT" -eq 0 ]; then
echo "ERROR: no qtbase_*.qm found in '$QT_TR_DIR' (mingw-w64-ucrt-x86_64-qt6-translations installed?)"
exit 1
fi
for f in LICENSE ChangeLog CREDIT README ELEMENTS.LICENSE; do
cp "$GITHUB_WORKSPACE/$f" "$FILES/$f" 2>/dev/null || true
@@ -594,8 +313,8 @@ jobs:
# Deliberately NOT parsed from sources/qetversion.cpp: the CI job
# already knows for certain it configured Qt6 (-DQT_VERSION_MAJOR=6),
# so the "0.200.1" experimental-track label is set here explicitly
# rather than relying on in-binary Qt version detection.
# so the "0.200.1" version label is set here explicitly rather than
# relying on in-binary Qt version detection.
VERSION="0.200.1"
FULL_VERSION="${VERSION}-qt6-r${HEAD}-${GITCOMMIT}_x86_64-win64"
@@ -704,43 +423,47 @@ jobs:
retention-days: 40
# ---------------------------------------------------------------------------
# Job 3 : Publie les assets nightly (exe + zip, Qt5 et Qt6) sur la release
# Job 2 : Publie les assets nightly (exe + zip) sur la release
# Ne tourne que sur push master (pas sur les PRs)
# ---------------------------------------------------------------------------
publish-nightly-assets:
needs: [build-windows, build-windows-qt6]
needs: [build-windows-qt6]
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
permissions:
contents: write
steps:
- name: Download installer artifacts (Qt5 + Qt6)
- name: Download installer artifact
uses: actions/download-artifact@v8
with:
pattern: qelectrotech-windows-installer*
path: downloaded/installer/
merge-multiple: true
- name: Download portable artifacts (Qt5 + Qt6)
- name: Download portable artifact
uses: actions/download-artifact@v8
with:
pattern: qelectrotech-*-readytouse
path: downloaded/portable/
merge-multiple: true
- name: Delete old nightly assets (.exe and .zip)
# Only Qt6-tagged assets are deleted/replaced here. Assets without "qt6"
# in the name are the frozen Qt5 legacy build (last one ever published,
# before the Qt5 CI job was removed) — deliberately left untouched so
# they stay downloadable indefinitely instead of disappearing.
- name: Delete old nightly Qt6 assets (.exe and .zip)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
gh release view nightly --repo "$REPO" --json assets \
--jq '.assets[] | select(.name | test("\\.(exe|zip)$")) | .name' \
--jq '.assets[] | select(.name | test("qt6")) | select(.name | test("\\.(exe|zip)$")) | .name' \
| while read -r name; do
echo "Deleting old asset: $name"
echo "Deleting old Qt6 asset: $name"
gh release delete-asset nightly "$name" --repo "$REPO" --yes
done
echo "Old .exe and .zip assets deleted."
echo "Old Qt6 .exe and .zip assets deleted (legacy Qt5 assets left untouched)."
- name: Update nightly release
uses: softprops/action-gh-release@v3
@@ -759,8 +482,7 @@ jobs:
> ⚠️ This is a development version; it introduces new features you want, but may cause bugs that have not yet been identified yet.
> For stable releases, see the [Releases page](https://github.com/${{ github.repository }}/releases).
> 🧪 **Qt6 builds are experimental.** Files tagged `-qt6-` are built against Qt6 and are not yet
> as tested as the Qt5 track. Expect rough edges; report issues clearly labelled "Qt6".
> 🗄️ Files without `-qt6-` in the name are the last Qt5 build ever published (frozen, unmaintained). Files tagged `-qt6-` are the actively maintained build.
prerelease: true
make_latest: false
files: |
@@ -769,4 +491,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
# GitHub Pages is generated and deployed by windows-msi.yml
# after the MSI upload, so that all URLs (exe/zip/msi, Qt5+Qt6) are known.
# after the MSI upload, so that all URLs (exe/zip/msi) are known.
+43 -48
View File
@@ -25,18 +25,17 @@ jobs:
strategy:
fail-fast: false
# Single-entry matrix kept on purpose (rather than flattening the job):
# matrix.flavor is used as part of the MSI ProductCode seed, so changing
# it would generate a new ProductCode and break upgrade detection for
# existing installs. Keeping "qt6" here preserves continuity.
matrix:
include:
- flavor: qt5
portable_artifact: qelectrotech-windows-portable
version_source: qetversion # parsed from sources/qetversion.cpp
label_suffix: ""
experimental: false
- flavor: qt6
portable_artifact: qelectrotech-windows-portable-qt6
version_source: hardcoded # see note in "Extract version" step
label_suffix: "-qt6-EXPERIMENTAL"
experimental: true
label_suffix: "-qt6"
experimental: false
permissions:
contents: write
@@ -44,7 +43,6 @@ jobs:
id-token: write # Required by SignPath
outputs:
qt5_msi: ${{ steps.export.outputs.msi_name_qt5 }}
qt6_msi: ${{ steps.export.outputs.msi_name_qt6 }}
steps:
@@ -72,14 +70,12 @@ jobs:
# ----------------------------------------------------------------
# 3. Extract version
# Qt5: parsed from sources/qetversion.cpp (single source of truth
# for the software's own reported version).
# Qt6: hardcoded "0.200.1" here — deliberately NOT parsed from the
# binary/source, since Qt-version self-detection inside the
# compiled code proved unreliable (see commit e1aa65f). The CI
# matrix entry already knows for certain which flavor it is
# packaging, so the experimental-track label is set explicitly
# at the packaging level instead.
# packaging, so the version label is set explicitly at the
# packaging level instead.
# ----------------------------------------------------------------
- name: Extract version
id: version
@@ -125,10 +121,9 @@ jobs:
Write-Host "Version MSI : $verMsi"
Write-Host "Version display : $verDisplay"
# Qt platform argument: only Qt5 needs the QTBUG-83161 font-rendering
# workaround (GDI backend). Qt6 uses DirectWrite by default and does
# not need it. Computed once here so both the bundled "Lancer QET.bat"
# and the MSI shortcuts (wix build -d QtPlatformArgs=...) stay in sync.
# Qt platform argument: kept from the Qt5 era (QTBUG-83161
# font-rendering workaround, GDI backend). Qt6 uses DirectWrite by
# default and does not need it, so this always resolves empty now.
if ("${{ matrix.flavor }}" -eq "qt5") {
$qtArgs = "-platform windows:fontengine=freetype"
} else {
@@ -228,10 +223,10 @@ jobs:
Write-Host "Lancer QET.bat replaced for MSI installation (qtArgs: '$qtArgs')."
# ----------------------------------------------------------------
# 9. Build the MSI (unsigned)
# Qt6 (experimental) uses a distinct ProductCode seed so it never
# collides with / upgrades over the Qt5 MSI — they must be able to
# coexist as clearly separate installs.
# 9. Build the MSI (unsigned at this stage — signing happens below)
# Qt6 keeps its own ProductCode seed (distinct from the retired Qt5
# MSI), so a machine that still has the old Qt5 MSI installed gets a
# separate, coexisting install rather than an unexpected upgrade.
# ----------------------------------------------------------------
- name: Build MSI
shell: pwsh
@@ -289,12 +284,13 @@ jobs:
retention-days: 1
if-no-files-found: error
# Qt6 stays on the unsigned/experimental track (no signing request for
# this flavor), and forks never have the SignPath secrets, so guard on
# both: only qt5, and only in the upstream repo.
# Qt6 is now signed too (previously excluded while Qt5 was the stable
# track and Qt6 was experimental-only). The remaining guard is the fork
# check: forks never have the SignPath secrets, and a fork-originated
# PR/run must never attempt a signing request.
# (cf. DieterMayerOSS:fix/msi-signing-fork-guard, d3f60c88)
- name: Sign MSI via SignPath
if: matrix.flavor == 'qt5' && github.repository == 'qelectrotech/qelectrotech-source-mirror'
if: github.repository == 'qelectrotech/qelectrotech-source-mirror'
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
@@ -314,15 +310,14 @@ jobs:
retention-days: 40
if-no-files-found: error
- name: Delete old nightly .msi asset for this flavor
- name: Delete old nightly .msi asset
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
$pattern = if ("${{ matrix.flavor }}" -eq "qt6") { "-qt6-EXPERIMENTAL.*\\.msi$" } else { "\\.msi$" }
$pattern = "-qt6.*\\.msi$"
$names = gh release view nightly --repo $env:REPO --json assets --jq ".assets[] | select(.name | test(`"$pattern`")) | .name"
foreach ($name in ($names -split "`n" | Where-Object { $_ })) {
if ("${{ matrix.flavor }}" -eq "qt5" -and $name -match "-qt6-EXPERIMENTAL") { continue }
Write-Host "Deleting old asset: $name"
gh release delete-asset nightly $name --repo $env:REPO --yes
}
@@ -342,11 +337,7 @@ jobs:
shell: pwsh
run: |
$name = "$env:MSI_NAME"
if ("${{ matrix.flavor }}" -eq "qt6") {
echo "msi_name_qt6=$name" >> $env:GITHUB_OUTPUT
} else {
echo "msi_name_qt5=$name" >> $env:GITHUB_OUTPUT
}
echo "msi_name_qt6=$name" >> $env:GITHUB_OUTPUT
- name: Summary
if: always()
@@ -354,11 +345,11 @@ jobs:
run: |
Write-Host "=== MSI build summary (${{ matrix.flavor }}) ==="
Write-Host "Version : ${{ steps.version.outputs.VERSION_DISPLAY }}"
Write-Host "Experimental : ${{ matrix.experimental }}"
Write-Host "Signed : true"
# ---------------------------------------------------------------------------
# Job 2 : Génère et déploie la page GitHub Pages une fois les DEUX MSI
# (Qt5 + Qt6) publiés, pour que toutes les URLs soient connues.
# Job 2 : Génère et déploie la page GitHub Pages une fois le MSI publié,
# pour que toutes les URLs soient connues.
# ---------------------------------------------------------------------------
deploy-pages:
needs: build-msi
@@ -388,13 +379,17 @@ jobs:
ASSETS=$(gh release view nightly --repo "$REPO" --json assets --jq '.assets[].name')
EXE_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.exe$' | head -1)
ZIP_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.zip$' | head -1)
MSI_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.msi$' | head -1 || echo "")
EXE_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.exe$' | head -1)
ZIP_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.zip$' | head -1)
MSI_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.msi$' | head -1 || echo "")
EXE_QT6_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.exe$' | head -1 || echo "")
ZIP_QT6_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.zip$' | head -1 || echo "")
MSI_QT6_NAME=$(echo "$ASSETS" | grep 'qt6' | grep '\.msi$' | head -1 || echo "")
# Legacy Qt5 assets (no "qt6" in the name): last ever published,
# frozen — windows-build.yml/windows-msi.yml no longer delete or
# replace these, so they keep pointing at the same files release
# after release. Rendered as a separate "legacy" section if present.
LEGACY_EXE_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.exe$' | head -1 || echo "")
LEGACY_ZIP_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.zip$' | head -1 || echo "")
LEGACY_MSI_NAME=$(echo "$ASSETS" | grep -v 'qt6' | grep '\.msi$' | head -1 || echo "")
BASE="https://github.com/$REPO/releases/download/nightly"
INSTALLER_URL="$BASE/$EXE_NAME"
@@ -402,12 +397,12 @@ jobs:
MSI_URL=""
[ -n "$MSI_NAME" ] && MSI_URL="$BASE/$MSI_NAME"
INSTALLER_QT6_URL=""
PORTABLE_QT6_URL=""
MSI_QT6_URL=""
[ -n "$EXE_QT6_NAME" ] && INSTALLER_QT6_URL="$BASE/$EXE_QT6_NAME"
[ -n "$ZIP_QT6_NAME" ] && PORTABLE_QT6_URL="$BASE/$ZIP_QT6_NAME"
[ -n "$MSI_QT6_NAME" ] && MSI_QT6_URL="$BASE/$MSI_QT6_NAME"
LEGACY_INSTALLER_URL=""
LEGACY_PORTABLE_URL=""
LEGACY_MSI_URL=""
[ -n "$LEGACY_EXE_NAME" ] && LEGACY_INSTALLER_URL="$BASE/$LEGACY_EXE_NAME"
[ -n "$LEGACY_ZIP_NAME" ] && LEGACY_PORTABLE_URL="$BASE/$LEGACY_ZIP_NAME"
[ -n "$LEGACY_MSI_NAME" ] && LEGACY_MSI_URL="$BASE/$LEGACY_MSI_NAME"
SHA="${{ github.event.workflow_run.head_sha || github.sha }}"
SHORT="${SHA:0:7}"
@@ -417,7 +412,7 @@ jobs:
export DATE SHORT REPO SHA RUN_URL RUN_NUMBER
export INSTALLER_URL PORTABLE_URL MSI_URL
export INSTALLER_QT6_URL PORTABLE_QT6_URL MSI_QT6_URL
export LEGACY_INSTALLER_URL LEGACY_PORTABLE_URL LEGACY_MSI_URL
python3 source/build-aux/generate-page.py
+2 -1
View File
@@ -6,4 +6,5 @@
doc/*
!doc/QElectroTech.qch
QElectroTech.tag
!doc/doc-utils
!doc/doc-utils
lang/*.qm
+156 -33
View File
@@ -19,7 +19,7 @@ include(cmake/hoto_update_cmake_message.cmake)
cmake_minimum_required(VERSION 3.5...4.2)
project(qelectrotech
VERSION 0.100.1
VERSION 0.200.1
DESCRIPTION "QET is a CAD/CAE editor focusing on schematics drawing features."
HOMEPAGE_URL "https://qelectrotech.org/"
LANGUAGES C CXX)
@@ -36,7 +36,7 @@ set(QET_DIR ${PROJECT_SOURCE_DIR})
# includes below, so every subdirectory and every FetchContent dependency
# sees a consistent, already-defined value.
if(NOT DEFINED QT_VERSION_MAJOR)
set(QT_VERSION_MAJOR 5)
set(QT_VERSION_MAJOR 6)
endif()
# Some third-party CMake projects we pull in via FetchContent (e.g.
@@ -48,19 +48,11 @@ endif()
# INTERFACE_QT_MAJOR_VERSION mismatch at generate time.
set(QT_DEFAULT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (5 or 6)" FORCE)
# Add sub directories
option(PACKAGE_TESTS "Build the tests" ON)
if(PACKAGE_TESTS)
message("Add sub directory tests")
add_subdirectory(tests)
endif()
include(cmake/paths_compilation_installation.cmake)
include(cmake/start_options.cmake)
include(cmake/developer_options.cmake)
include(cmake/git_update_submodules.cmake)
include(cmake/git_last_commit_sha.cmake)
include(cmake/fetch_kdeaddons.cmake)
include(cmake/fetch_singleapplication.cmake)
include(cmake/fetch_pugixml.cmake)
include(cmake/qet_compilation_vars.cmake)
@@ -78,12 +70,43 @@ find_package(
${QET_COMPONENTS}
REQUIRED)
# Qt6 only creates the Qt::GuiPrivate target (used for QPdfEngine::drawHyperlink)
# when the GuiPrivate component is explicitly requested. Qt5 has no such
# component package and creates the target implicitly with Gui, so only
# request it on Qt6 - requesting it on Qt5 fails the whole configure.
# <private/qpdf_p.h> (QPdfEngine::drawHyperlink) needs Qt's private GUI module.
# Qt >= 6.7 ships it as a proper find_package component, but some distro
# packages (e.g. Ubuntu's qt6-base-private-dev) omit Qt6GuiPrivateConfig.cmake
# and only provide the implicit Qt6::GuiPrivate target created alongside
# Qt6::Gui. Try the component quietly, then verify the target below so a
# missing private-headers package fails here instead of at compile time.
# Qt5 has no such component as its GuiPrivate target always exists once Gui is found.
if(QT_VERSION_MAJOR GREATER_EQUAL 6)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS GuiPrivate)
find_package(Qt6 QUIET COMPONENTS GuiPrivate)
endif()
if(QT_VERSION_MAJOR GREATER_EQUAL 6 AND NOT TARGET Qt6::GuiPrivate)
message(FATAL_ERROR
"Qt6::GuiPrivate was not found. It is required for PDF hyperlink "
"support (<private/qpdf_p.h>). Install the Qt6 private headers "
"(e.g. 'qt6-base-private-dev' on Debian/Ubuntu) or use a Qt build "
"that provides the GuiPrivate component.")
endif()
# PDF page import (toolbar "Ajouter un PDF") needs the QtPdf module and,
# specifically, QPdfDocument::pagePointSize() which only exists since Qt 6.4.
# Unlike GuiPrivate above, a missing QtPdf module is NOT fatal here: some
# Qt6 distributions (e.g. the Flatpak org.kde.Platform runtime) don't ship
# it at all, since it lives in the qtwebengine source tree rather than Qt6
# core. When it's missing, or too old, the feature is silently disabled -
# see the QT_VERSION_CHECK / QET_HAS_QTPDF guards in diagrameventaddpdf.*
# and pdfpagesdialog.*.
set(QET_HAS_QTPDF FALSE)
if(QT_VERSION_MAJOR GREATER_EQUAL 6)
find_package(Qt6 QUIET COMPONENTS Pdf)
if(TARGET Qt6::Pdf AND NOT Qt6_VERSION VERSION_LESS 6.4.0)
set(QET_HAS_QTPDF TRUE)
list(APPEND QET_PRIVATE_LIBRARIES Qt::Pdf)
add_compile_definitions(QET_HAS_QTPDF)
else()
message(STATUS "QtPdf module not available (or Qt < 6.4): PDF page import feature disabled")
endif()
endif()
find_package(SQLite3 REQUIRED)
@@ -100,25 +123,20 @@ endif()
set(CMAKE_AUTOUIC_SEARCH_PATHS ${QET_DIR}/sources/ui)
# The default build only compiles the tracked .ts files to .qm (lrelease).
# Refreshing the .ts from the sources (lupdate) is a developer action behind
# the explicit "update_translations" target below: running lupdate on every
# build rewrote tracked files as a side effect, and under high parallelism
# lupdate rewriting a .ts while lrelease read the same file made the build
# fail with "Premature end of document".
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${QET_DIR}/lang")
if(QT_VERSION_MAJOR EQUAL 6)
qt6_add_translation(QM_FILES ${TS_FILES})
set(KF_MAJOR_VERSION 6)
else()
qt5_add_translation(QM_FILES ${TS_FILES})
set(KF_MAJOR_VERSION 5)
endif()
include(cmake/fetch_kdeaddons.cmake)
add_custom_target(update_translations
COMMAND $<TARGET_FILE:Qt${QT_VERSION_MAJOR}::lupdate> ${CMAKE_SOURCE_DIR}/sources -ts ${TS_FILES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Updating .ts files from sources/ (lupdate) - developer target, run explicitly"
VERBATIM
)
# Add sub directories
option(PACKAGE_TESTS "Build the tests" ON)
if(PACKAGE_TESTS)
message("Add sub directory tests")
enable_testing()
add_subdirectory(tests)
endif()
# als laatse
include(cmake/define_definitions.cmake)
@@ -145,6 +163,109 @@ else()
)
endif()
if(APPLE)
# CFBundleIdentifier must not be empty. CMake's default Info.plist
# template fills it from MACOSX_BUNDLE_GUI_IDENTIFIER; with that unset
# the bundle ships an empty identifier, LaunchServices never registers
# the .app, and AppKit's open/save panel service (which is keyed on the
# client's bundle id) silently presents nothing -- every
# QFileDialog::getOpenFileName()/getSaveFileName() call returns an empty
# string without a panel ever appearing, so File > Open and File > Save
# as do nothing at all.
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_GUI_IDENTIFIER "org.qelectrotech.QElectroTech"
MACOSX_BUNDLE_BUNDLE_NAME "QElectroTech"
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
MACOSX_BUNDLE_COPYRIGHT "Copyright 2006-2026 The QElectroTech Team"
)
endif()
# The default build only compiles the tracked .ts files to .qm (lrelease).
# Refreshing the .ts from the sources (lupdate) is a developer action behind
# the explicit "update_translations" target below: running lupdate on every
# build rewrote tracked files as a side effect, and under high parallelism
# lupdate rewriting a .ts while lrelease read the same file made the build
# fail with "Premature end of document".
set_source_files_properties(
${TS_FILES}
PROPERTIES OUTPUT_LOCATION "lang"
)
if(QT_VERSION_MAJOR EQUAL 6)
if(Qt6_VERSION VERSION_LESS "6.2")
# Qt 6.06.1
qt6_add_translation(QM_FILES ${TS_FILES})
# qt6_add_translation() only creates custom commands. Something must
# depend on their outputs for them to run during the default build.
add_custom_target(${PROJECT_NAME}_lrelease ALL
DEPENDS ${QM_FILES}
)
add_custom_target(update_translations
COMMAND
$<TARGET_FILE:Qt6::lupdate>
"${CMAKE_SOURCE_DIR}/sources"
-ts ${TS_FILES}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT
"Updating .ts files from sources/ (lupdate) - developer target"
VERBATIM
)
elseif(Qt6_VERSION VERSION_LESS "6.7")
# Qt 6.26.6: old target-based signature
qt_add_lrelease(
${PROJECT_NAME}
TS_FILES ${TS_FILES}
QM_FILES_OUTPUT_VARIABLE QM_FILES
)
# Automatically creates the update_translations umbrella target.
qt_add_lupdate(
${PROJECT_NAME}
TS_FILES ${TS_FILES}
)
else()
# Qt 6.7+: new signature
qt_add_lrelease(
TS_FILES ${TS_FILES}
LRELEASE_TARGET ${PROJECT_NAME}_lrelease
QM_FILES_OUTPUT_VARIABLE QM_FILES
)
qt_add_lupdate(
SOURCE_TARGETS ${PROJECT_NAME}
TS_FILES ${TS_FILES}
LUPDATE_TARGET update_translations
NO_GLOBAL_TARGET
)
endif()
else()
# Qt 5
qt5_add_translation(QM_FILES ${TS_FILES})
# Likewise, qt5_add_translation() needs a target depending on its outputs,
# unless QM_FILES are already consumed elsewhere.
add_custom_target(${PROJECT_NAME}_lrelease ALL
DEPENDS ${QM_FILES}
)
add_custom_target(update_translations
COMMAND
$<TARGET_FILE:Qt5::lupdate>
"${CMAKE_SOURCE_DIR}/sources"
-ts ${TS_FILES}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT
"Updating .ts files from sources/ (lupdate) - developer target"
VERBATIM
)
endif()
# Optional precompiled headers -- see QET_ENABLE_PCH in
# cmake/developer_options.cmake for what this trades away.
#
@@ -180,7 +301,7 @@ target_link_libraries(
pugixml::pugixml
SingleApplication::SingleApplication
SQLite3::SQLite3
${KF5_PRIVATE_LIBRARIES}
${KF_PRIVATE_LIBRARIES}
${QET_PRIVATE_LIBRARIES}
)
@@ -221,7 +342,7 @@ target_include_directories(
${QET_DIR}/sources/svg
)
if(NOT BUILD_WITH_KF5)
if(NOT BUILD_WITH_KF)
target_include_directories(
${PROJECT_NAME}
PRIVATE
@@ -229,7 +350,9 @@ if(NOT BUILD_WITH_KF5)
)
endif()
install(TARGETS ${PROJECT_NAME})
install(TARGETS ${PROJECT_NAME}
BUNDLE DESTINATION .
)
if (NOT MINGW)
install(DIRECTORY ico/breeze-icons/16x16 DESTINATION ${QET_ICONS_PATH})
+1
View File
@@ -20,6 +20,7 @@ All notable changes to QElectroTech are documented here.
### 🐛 Bug Fixes
- Fix #798: clamp element-editor and diagram-view zoom to prevent view-transform overflow crash on scroll-wheel zoom ([3ca5d4a](../../commit/3ca5d4ab2))
- Fix(windows-msi): inject rev into MSI Version Build field ([e19f523](../../commit/e19f5232277efb37435cb65a83563d73333d62ec))
- Fix #391: use wide-char path for pugixml on Windows to handle Unicode paths ([31edf30](../../commit/31edf30c619213368e9b592b51be6ca8190db831))
- Fix(#283): restore center alignment when loading table config ([f55ba56](../../commit/f55ba568f68293e06436899bcc831431e9d27295))
+1 -1
View File
@@ -48,7 +48,7 @@ PROJECT_NAME = QElectroTech
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = " 0.100.0-dev"
PROJECT_NUMBER = " 0.200.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+2 -2
View File
@@ -48,8 +48,8 @@ Here are the technical choices made for the software development:
* Coding language: [C++](https://en.wikipedia.org/wiki/C%2B%2B)
* GUI translations: [Qt Linguist](http://doc.qt.io/qt-5/qtlinguist-index.html)
* Version control: [GIT](https://github.com/qelectrotech/qelectrotech-source-mirror.git)
* Doxygen documentation :[Doxygen](https://qelectrotech.github.io/qelectrotech-source-mirror/)
* QtCreator qch doxygen :[QElectroTech.qch](https://github.com/qelectrotech/qelectrotech-source-mirror/blob/master/doc/QElectroTech.qch)
* Doxygen documentation :[Doxygen](https://download.qelectrotech.org/qet/doxygen/html/)
* QtCreator qch doxygen :[QElectroTech.qch](https://download.qelectrotech.org/qet/doxygen/QElectroTech.qch)
* File format for projects, elements and titleblocks: [XML](http://www.w3schools.com/xml/xml_whatis.asp)
* Main development platform: [GNU/Linux](http://getgnulinux.org/en/linux/)
* Targeted platforms: Windows, GNU/Linux, Mac OS X, BSDs
@@ -1,8 +1,10 @@
{
"id": "org.qelectrotech.QElectroTech",
"runtime": "org.kde.Platform",
"runtime-version": "5.15-25.08",
"runtime-version": "6.11",
"sdk": "org.kde.Sdk",
"base": "io.qt.qtwebengine.BaseApp",
"base-version": "6.11",
"command": "qelectrotech",
"rename-desktop-file": "org.qelectrotech.qelectrotech.desktop",
"rename-appdata-file": "qelectrotech.appdata.xml",
@@ -25,12 +27,26 @@
"*.la",
"*.a"
],
"cleanup-commands": [
"/app/cleanup-BaseApp.sh"
],
"modules": [
"tkinter.json",
"pypi-dependencies.json",
{
"name": "qelectrotech",
"buildsystem": "qmake",
"buildsystem": "cmake",
"config-opts": [
"-DCMAKE_INSTALL_PREFIX=/app",
"-DQT_VERSION_MAJOR=6",
"-DBUILD_WITH_KF=ON",
"-DBUILD_KF=OFF",
"-DPACKAGE_TESTS=OFF",
"-DBUILD_PUGIXML=ON",
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON",
"-DFETCHCONTENT_SOURCE_DIR_PUGIXML=/run/build/qelectrotech/pugixml",
"-DQET_EXPORT_PROJECT_DB=ON"
],
"post-install": [
"mv ${FLATPAK_DEST}/share/mime/packages/qelectrotech.xml ${FLATPAK_DEST}/share/mime/packages/org.qelectrotech.QElectroTech.xml"
],
@@ -38,12 +54,6 @@
{
"type": "dir",
"path": "../.."
},
{
"type": "patch",
"paths": [
"patches/fix-the-installation-paths.patch"
]
}
]
}
+42 -33
View File
@@ -2,11 +2,19 @@
"""
generate-page.py — Generates gh-pages/index.html for QElectroTech nightly builds.
Called from windows-msi.yml deploy-pages job.
Environment variables required:
DATE, SHORT, REPO, SHA, RUN_URL, RUN_NUMBER,
INSTALLER_URL, PORTABLE_URL, MSI_URL (optional)
Optional (Qt6 experimental track — omitted entirely if empty):
INSTALLER_QT6_URL, PORTABLE_QT6_URL, MSI_QT6_URL
Optional (frozen Qt5 legacy build — omitted entirely if empty):
LEGACY_INSTALLER_URL, LEGACY_PORTABLE_URL, LEGACY_MSI_URL
NOTE: Windows Qt5 CI build removed (Qt6 is now the sole track built and
signed going forward). INSTALLER_URL / PORTABLE_URL / MSI_URL point to the
Qt6 build artifacts. The LEGACY_* variables, when set, point to the last
Qt5 nightly assets that were ever published — kept downloadable but frozen
(windows-build.yml no longer regenerates or deletes them).
"""
import os
@@ -20,9 +28,9 @@ installer_url = os.environ.get("INSTALLER_URL", "")
portable_url = os.environ.get("PORTABLE_URL", "")
msi_url = os.environ.get("MSI_URL", "")
installer_qt6_url = os.environ.get("INSTALLER_QT6_URL", "")
portable_qt6_url = os.environ.get("PORTABLE_QT6_URL", "")
msi_qt6_url = os.environ.get("MSI_QT6_URL", "")
legacy_installer_url = os.environ.get("LEGACY_INSTALLER_URL", "")
legacy_portable_url = os.environ.get("LEGACY_PORTABLE_URL", "")
legacy_msi_url = os.environ.get("LEGACY_MSI_URL", "")
msi_block = ""
if msi_url:
@@ -32,43 +40,44 @@ if msi_url:
<span class="btn-text">Windows Installer .msi<small>.msi &mdash; for enterprise / GPO deployment</small></span>
</a>"""
# Qt6 experimental section — only rendered if at least one Qt6 asset exists.
qt6_block = ""
if installer_qt6_url or portable_qt6_url or msi_qt6_url:
qt6_msi_btn = ""
if msi_qt6_url:
qt6_msi_btn = f"""
<a class="btn btn-msi" href="{msi_qt6_url}">
# Legacy Qt5 section — only rendered if at least one legacy asset exists.
legacy_block = ""
if legacy_installer_url or legacy_portable_url or legacy_msi_url:
legacy_installer_btn = ""
if legacy_installer_url:
legacy_installer_btn = f"""
<a class="btn btn-secondary" href="{legacy_installer_url}">
<span class="btn-icon">&#11015;</span>
<span class="btn-text">Windows Installer .msi (Qt6)<small>.msi &mdash; experimental, for enterprise / GPO deployment</small></span>
<span class="btn-text">Windows Installer (Qt5, legacy)<small>.exe &mdash; frozen, no longer updated</small></span>
</a>"""
qt6_installer_btn = ""
if installer_qt6_url:
qt6_installer_btn = f"""
<a class="btn btn-primary" href="{installer_qt6_url}">
legacy_msi_btn = ""
if legacy_msi_url:
legacy_msi_btn = f"""
<a class="btn btn-secondary" href="{legacy_msi_url}">
<span class="btn-icon">&#11015;</span>
<span class="btn-text">Windows Installer (Qt6)<small>.exe &mdash; experimental, includes all dependencies</small></span>
<span class="btn-text">Windows Installer .msi (Qt5, legacy)<small>.msi &mdash; frozen, no longer updated</small></span>
</a>"""
qt6_portable_btn = ""
if portable_qt6_url:
qt6_portable_btn = f"""
<a class="btn btn-secondary" href="{portable_qt6_url}">
legacy_portable_btn = ""
if legacy_portable_url:
legacy_portable_btn = f"""
<a class="btn btn-secondary" href="{legacy_portable_url}">
<span class="btn-icon">&#128230;</span>
<span class="btn-text">Windows Portable (Qt6)<small>.zip &mdash; experimental, no installation required</small></span>
<span class="btn-text">Windows Portable (Qt5, legacy)<small>.zip &mdash; frozen, no longer updated</small></span>
</a>"""
qt6_block = f"""
legacy_block = f"""
<div class="card">
<h2>&#129514; Windows &mdash; x86_64 &mdash; Qt6 track</h2>
<h2>&#128451; Windows &mdash; x86_64 &mdash; Qt5 (legacy, unmaintained)</h2>
<div class="warning">
&#9888;&#65039; <strong>Experimental.</strong> These Qt6-based installer, portable and MSI
builds are new and not as thoroughly tested as the Qt5 track above. Expect rough
edges; please report issues and mention &quot;Qt6&quot; explicitly.
&#128451; <strong>Legacy build &mdash; frozen, no longer updated.</strong> This is the
last Qt5 build published before Windows CI switched to Qt6 only. Kept available for
anyone who still needs it, but it will not receive further fixes or security updates.
Please migrate to the Qt6 build above when you can.
</div>
<div class="downloads">
{qt6_installer_btn}
{qt6_msi_btn}
{qt6_portable_btn}
{legacy_installer_btn}
{legacy_msi_btn}
{legacy_portable_btn}
</div>
</div>"""
@@ -126,7 +135,7 @@ For production use, download a <a href="https://github.com/{repo}/releases">stab
</div>
</div>
<div class="card">
<h2>&#127993; Windows &mdash; x86_64 &mdash; Qt5 track</h2>
<h2>&#127993; Windows &mdash; x86_64</h2>
<div class="downloads">
<a class="btn btn-primary" href="{installer_url}">
<span class="btn-icon">&#11015;</span>
@@ -143,7 +152,7 @@ For production use, download a <a href="https://github.com/{repo}/releases">stab
</a>
</div>
</div>
{qt6_block}
{legacy_block}
</main>
<footer>
Auto-generated by GitHub Actions &nbsp;&middot;&nbsp;
+45 -37
View File
@@ -1,48 +1,39 @@
name: qelectrotech
title: QElectroTech
base: core22
base: core24
adopt-info: qelectrotech
license: GPL-2.0
summary: Electrical diagram editor
description: |
QElectroTech, or QET in short, is a libre and open source desktop application
QElectroTech, or QET in short, is a libre and open source desktop application
to create diagrams and schematics.
grade: stable
confinement: strict
compression: lzo
architectures:
- build-on: amd64
build-for: amd64
- build-on: arm64
build-for: arm64
layout:
/usr/local/share/qelectrotech:
symlink: $SNAP/usr/local/share/qelectrotech
platforms:
amd64:
arm64:
apps:
qelectrotech:
command: usr/local/bin/qelectrotech
command: usr/bin/qelectrotech
common-id: qelectrotech.desktop
extensions:
- kde-neon
extensions:
- kde-neon-6
plugs: &plugs [opengl, unity7, home, removable-media, gsettings, network, cups-control, wayland, x11]
environment: &env
TCL_LIBRARY: $SNAP/usr/share/tcltk/tcl8.6
HOME: $SNAP_USER_COMMON
PYTHONPATH: $SNAP:$SNAP/lib/python3.10/site-packages:$SNAP/usr/lib/python3.10:$SNAP/usr/lib/python3.10/lib-dynload
PYTHONPATH: $SNAP:$SNAP/lib/python3.12/site-packages:$SNAP/usr/lib/python3.12:$SNAP/usr/lib/python3.12/lib-dynload
qet-tb-generator:
command: bin/qet_tb_generator
extensions:
- kde-neon
extensions:
- kde-neon-6
plugs: *plugs
environment: *env
parts:
launchers:
plugin: dump
@@ -55,7 +46,7 @@ parts:
source: https://github.com/raulroda/qet_tb_generator-plugin.git
source-tag: v1.31
python-packages: [PySimpleGUI]
stage-packages:
stage-packages:
- python3-lxml
- python3-tk
- libtk8.6
@@ -63,16 +54,17 @@ parts:
kde-sdk-setup:
plugin: nil
build-snaps:
- kf5-5-110-qt-5-15-11-core22-sdk
- kf6-core24-sdk
- kde-qt6-core24-sdk
build-packages:
- g++
- mesa-common-dev
- libglvnd-dev
- rsync
override-build: |
rsync -a --ignore-existing /snap/kf5-5-110-qt-5-15-11-core22-sdk/current/ /
rsync -a --ignore-existing /snap/kf6-core24-sdk/current/ /
rsync -a --ignore-existing /snap/kde-qt6-core24-sdk/current/ /
qelectrotech:
after: [kde-sdk-setup]
plugin: nil
@@ -81,37 +73,53 @@ parts:
- git
- sqlite3
- xdg-user-dirs
# libxcb-cursor0 was added as a hard dependency of the Qt5 xcb platform
# plugin in Qt 5.15.x. The kf5-5-110-qt-5-15-11-core22 content snap does
# not bundle it, so dlopen() of libqxcb.so fails on Ubuntu 24.04 hosts
# with "found but could not load" (issue #373). Staging the 22.04 build
# of this library satisfies the dep without changing base or Qt version.
# libxcb-cursor0 workaround was needed against the Qt5/KF5 core22 content
# snap (issue #373). Not yet re-verified against kf6-core24 — remove this
# if the Qt6 xcb platform plugin loads cleanly without it.
- libxcb-cursor0
build-packages:
- git
- cmake
- ninja-build
- libsqlite3-dev
- qt6-tools-dev
- qt6-base-private-dev
- pkgconf
# Qt6 PrintSupport records Cups::Cups as a third-party dependency
# (qprint_p.h includes <cups/ppd.h>), so find_package(Qt6 PrintSupport)
# runs FindCups at configure time and fails without the CUPS headers.
# Build-time only: nothing from it is staged into the snap.
- libcups2-dev
override-build: |
displayed_version=$(cat sources/qetversion.cpp | grep "return QVersionNumber{"| head -n 1| awk -F "{" '{ print $2 }' | awk -F "}" '{ print $1 }' | sed -e 's/,/./g' -e 's/ //g')
snap_version="${displayed_version}-g$(git rev-parse --short=8 HEAD)"
modified_displayed_version="${snap_version}.snap"
sed -i -E "s|const QString displayedVersion =.*|const QString displayedVersion =\"$modified_displayed_version\";|" sources/qet.h
craftctl set version="$snap_version"
qmake "$CRAFT_PART_SRC/qelectrotech.pro"
make -j${CRAFT_PARALLEL_BUILD_COUNT}
make install INSTALL_ROOT="$CRAFT_PART_INSTALL"
cmake -G Ninja -B build -S "$CRAFT_PART_SRC" \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DQT_VERSION_MAJOR=6 \
-DBUILD_WITH_KF=ON \
-DBUILD_KF=OFF \
-DPACKAGE_TESTS=OFF \
-DBUILD_PUGIXML=ON \
-DQET_EXPORT_PROJECT_DB=ON
ninja -C build -j${CRAFT_PARALLEL_BUILD_COUNT}
DESTDIR="$CRAFT_PART_INSTALL" ninja -C build install
override-stage: |
craftctl default
# patch desktop file with correct icon path
SED_CMD="sed -i -E s|^Icon=(.*)|Icon=\${SNAP}/usr/local/share/icons/hicolor/128x128/apps/\1.png|g"
$SED_CMD usr/local/share/applications/org.qelectrotech.qelectrotech.desktop
SED_CMD="sed -i -E s|^Icon=(.*)|Icon=\${SNAP}/usr/share/icons/hicolor/128x128/apps/\1.png|g"
$SED_CMD usr/share/applications/org.qelectrotech.qelectrotech.desktop
cleanup:
after: [qelectrotech, qet-tb-generator]
plugin: nil
build-snaps: [kf5-5-110-qt-5-15-11-core22]
build-snaps: [kf6-core24]
override-prime: |
set -eux
for snap in "kf5-5-110-qt-5-15-11-core22"; do # List all content-snaps you're using here
for snap in "kf6-core24"; do # List all content-snaps you're using here
cd "/snap/$snap/current" && find . -type f,l -exec rm -f "$CRAFT_PRIME/{}" "$CRAFT_PRIME/usr/{}" \;
done
for cruft in bug lintian man; do
+2 -2
View File
@@ -40,8 +40,8 @@ git clone --recursive https://github.com/qelectrotech/qelectrotech-source-mirror
Here are the technical choices made for the software development:
* Integrated development environment: [Qt Framework](https://www.qt.io/ide/)
* Libraries: Qt 5.x
* [KF5 Framework](https://github.com/KDE)
* Libraries: Qt 5.x / Qt 6.x
* [KF5/6 Framework](https://github.com/KDE)
[Cmake](https://cmake.org/install/)
[kcoreaddons](https://github.com/KDE/kcoreaddons/tree/kf5)
[kwidgetsaddons](https://github.com/KDE/kwidgetsaddons/tree/kf5).
+11 -11
View File
@@ -25,24 +25,24 @@ message("INSTALL_PREFIX " ${INSTALL_PREFIX})
message("QET_BINARY_PATH " ${QET_BINARY_PATH})
if(${QET_COMMON_COLLECTION_PATH} STRGREATER "")
message("QET_COMMON_COLLECTION_PATH " ${INSTALL_PREFIX}${QET_COMMON_COLLECTION_PATH})
add_definitions(-DQET_COMMON_COLLECTION_PATH=${INSTALL_PREFIX}${QET_COMMON_COLLECTION_PATH})
message("QET_COMMON_COLLECTION_PATH " ${COMPIL_PREFIX}${QET_COMMON_COLLECTION_PATH})
add_definitions(-DQET_COMMON_COLLECTION_PATH=${COMPIL_PREFIX}${QET_COMMON_COLLECTION_PATH})
endif()
if(${QET_COMMON_TBT_PATH} STRGREATER "")
message("QET_COMMON_TBT_PATH " ${INSTALL_PREFIX}${QET_COMMON_TBT_PATH})
add_definitions(-DQET_COMMON_TBT_PATH=${INSTALL_PREFIX}${QET_COMMON_TBT_PATH})
message("QET_COMMON_TBT_PATH " ${COMPIL_PREFIX}${QET_COMMON_TBT_PATH})
add_definitions(-DQET_COMMON_TBT_PATH=${COMPIL_PREFIX}${QET_COMMON_TBT_PATH})
endif()
if(${QET_LANG_PATH_RELATIVE_TO_BINARY_PATH})
add_definitions(-DQET_LANG_PATH_RELATIVE_TO_BINARY_PATH)
endif()
if(${QET_LANG_PATH} STRGREATER "")
message("QET_LANG_PATH " ${INSTALL_PREFIX}${QET_LANG_PATH})
add_definitions(-DQET_LANG_PATH=${INSTALL_PREFIX}${QET_LANG_PATH})
message("QET_LANG_PATH " ${COMPIL_PREFIX}${QET_LANG_PATH})
add_definitions(-DQET_LANG_PATH=${COMPIL_PREFIX}${QET_LANG_PATH})
endif()
if (NOT MINGW)
if(${QET_EXAMPLES_PATH} STRGREATER "")
message("QET_EXAMPLES_PATH " ${INSTALL_PREFIX}${QET_EXAMPLES_PATH})
add_definitions(-DQET_EXAMPLES_PATH=${INSTALL_PREFIX}${QET_EXAMPLES_PATH})
message("QET_EXAMPLES_PATH " ${COMPIL_PREFIX}${QET_EXAMPLES_PATH})
add_definitions(-DQET_EXAMPLES_PATH=${COMPIL_PREFIX}${QET_EXAMPLES_PATH})
endif()
endif()
@@ -62,10 +62,10 @@ message("PROJECT_SOURCE_DIR :" ${PROJECT_SOURCE_DIR})
message("QET_DIR :" ${QET_DIR})
message("GIT_COMMIT_SHA :" ${GIT_COMMIT_SHA})
if(BUILD_WITH_KF5)
message("KF5_GIT_TAG :" ${KF5_GIT_TAG})
if(BUILD_WITH_KF)
message("KF_GIT_TAG :" ${KF_GIT_TAG})
else()
add_definitions(-DBUILD_WITHOUT_KF5)
add_definitions(-DBUILD_WITHOUT_KF)
endif()
message("QET_COMPONENTS :" ${QET_COMPONENTS})
message("QT_VERSION_MAJOR :" ${QT_VERSION_MAJOR})
+5 -2
View File
@@ -31,8 +31,11 @@ add_definitions(-DQT_MESSAGELOGCONTEXT)
# In order to do so, uncomment the following line.
#add_definitions(-DTODO_LIST)
# Build with KF5
option(BUILD_WITH_KF5 "Build with KF5" ON)
# Build with KDE Frameworks. The major version (KF5/KF6) is derived
# automatically from QT_VERSION_MAJOR -- KDE Frameworks deliberately
# mirrors Qt's own major version numbering, so there is no independent
# choice to make here. See cmake/fetch_kdeaddons.cmake.
option(BUILD_WITH_KF "Build with KDE Frameworks" ON)
# Precompiled headers for the Qt umbrella headers.
#
+58 -36
View File
@@ -16,52 +16,74 @@
message(" - fetch_kdeaddons")
if(BUILD_WITH_KF5)
# TODO remove path as soon as Qt5 gets retired
if(BUILD_WITH_KF)
Include(FetchContent)
option(BUILD_KF5 "Build KF5 libraries, use system ones otherwise" YES)
option(BUILD_KF "Build KF libraries, use system ones otherwise" YES)
if(BUILD_KF5)
if(BUILD_KF)
if(NOT DEFINED KF5_GIT_TAG)
#https://qelectrotech.org/forum/viewtopic.php?pid=13924#p13924
set(KF5_GIT_TAG v5.77.0)
if(KF_MAJOR_VERSION EQUAL 5)
if(NOT DEFINED KF_GIT_TAG)
#https://qelectrotech.org/forum/viewtopic.php?pid=13924#p13924
set(KF_GIT_TAG v5.77.0)
endif()
else()
if(NOT DEFINED KF_GIT_TAG)
# this is a more or less random version, taken as an conservative approach
set(KF_GIT_TAG v6.10.0)
endif()
endif()
# using a function in order to limit the scope of the variables
# with CMake >=3.25 we could use a block()
function(qet_make_kf_available)
# Fix stop the run autotests of kcoreaddons
# see
# https://invent.kde.org/frameworks/kcoreaddons/-/blob/master/CMakeLists.txt#L98
# issue:
# CMake Error at /usr/share/ECM/modules/ECMAddTests.cmake:89 (add_executable):
# Cannot find source file:
# see
# https://qelectrotech.org/forum/viewtopic.php?pid=13929#p13929
set(KDE_SKIP_TEST_SETTINGS ON)
set(BUILD_TESTING OFF)
# QElectroTech is a plain QtWidgets application with no QML anywhere in
# it; these disable optional features of the fetched KF modules that
# would otherwise pull in extra Qt6 components (e.g. Qt6Qml) we don't
# have and don't need.
set(BUILD_DESIGNERPLUGIN OFF)
set(KCOREADDONS_USE_QML OFF)
set(BUILD_QCH OFF)
set(BUILD_SHARED_LIBS OFF)
# Fix stop the run autotests of kcoreaddons
# see
# https://invent.kde.org/frameworks/kcoreaddons/-/blob/master/CMakeLists.txt#L98
# issue:
# CMake Error at /usr/share/ECM/modules/ECMAddTests.cmake:89 (add_executable):
# Cannot find source file:
# see
# https://qelectrotech.org/forum/viewtopic.php?pid=13929#p13929
set(KDE_SKIP_TEST_SETTINGS "TRUE")
set(BUILD_TESTING "0")
FetchContent_Declare(
ecm
GIT_REPOSITORY https://invent.kde.org/frameworks/extra-cmake-modules.git
GIT_TAG ${KF5_GIT_TAG})
FetchContent_MakeAvailable(ecm)
FetchContent_Declare(
ecm
GIT_REPOSITORY https://invent.kde.org/frameworks/extra-cmake-modules.git
GIT_TAG ${KF_GIT_TAG})
FetchContent_MakeAvailable(ecm)
FetchContent_Declare(
kcoreaddons
GIT_REPOSITORY https://invent.kde.org/frameworks/kcoreaddons.git
GIT_TAG ${KF5_GIT_TAG})
FetchContent_MakeAvailable(kcoreaddons)
FetchContent_Declare(
kcoreaddons
GIT_REPOSITORY https://invent.kde.org/frameworks/kcoreaddons.git
GIT_TAG ${KF_GIT_TAG})
FetchContent_MakeAvailable(kcoreaddons)
FetchContent_Declare(
kwidgetsaddons
GIT_REPOSITORY https://invent.kde.org/frameworks/kwidgetsaddons.git
GIT_TAG ${KF5_GIT_TAG})
FetchContent_MakeAvailable(kwidgetsaddons)
FetchContent_Declare(
kwidgetsaddons
GIT_REPOSITORY https://invent.kde.org/frameworks/kwidgetsaddons.git
GIT_TAG ${KF_GIT_TAG})
FetchContent_MakeAvailable(kwidgetsaddons)
endfunction()
qet_make_kf_available()
else()
find_package(KF5CoreAddons REQUIRED)
find_package(KF5WidgetsAddons REQUIRED)
find_package(KF${KF_MAJOR_VERSION}CoreAddons REQUIRED)
find_package(KF${KF_MAJOR_VERSION}WidgetsAddons REQUIRED)
endif()
set(KF5_PRIVATE_LIBRARIES
KF5::WidgetsAddons
KF5::CoreAddons
set(KF_PRIVATE_LIBRARIES
KF${KF_MAJOR_VERSION}::WidgetsAddons
KF${KF_MAJOR_VERSION}::CoreAddons
)
endif()
+1 -1
View File
@@ -26,7 +26,7 @@ if(BUILD_PUGIXML)
pugixml
GIT_REPOSITORY https://github.com/zeux/pugixml.git
GIT_TAG v1.15)
set(PUGIXML_INSTALL OFF CACHE INTERNAL "")
FetchContent_MakeAvailable(pugixml)
else()
find_package(pugixml REQUIRED)
+8
View File
@@ -23,6 +23,14 @@ set(QAPPLICATION_CLASS QApplication)
Include(FetchContent)
if(EXISTS "${CMAKE_SOURCE_DIR}/SingleApplication/CMakeLists.txt")
# Submodule deja present dans l'arbre source (clone --recursive, tarball
# de distro deja peuple via "git submodule update", etc.) : on l'utilise
# tel quel, sans acces reseau. Necessaire pour les builds hors-ligne
# (pbuilder/sbuild avec FETCHCONTENT_FULLY_DISCONNECTED=ON, Launchpad PPA...).
set(FETCHCONTENT_SOURCE_DIR_SINGLEAPPLICATION "${CMAKE_SOURCE_DIR}/SingleApplication")
endif()
FetchContent_Declare(
SingleApplication
GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication.git
+3 -3
View File
@@ -20,15 +20,15 @@ message(" - paths_compilation_installation")
if(UNIX AND NOT APPLE)
# for Linux, BSD, Solaris, Minix
set(COMPIL_PREFIX "/usr/local/")
set(INSTALL_PREFIX "/usr/local/")
set(COMPIL_PREFIX "${CMAKE_INSTALL_PREFIX}/")
set(INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/")
set(QET_BINARY_PATH "bin/")
set(QET_COMMON_COLLECTION_PATH "share/qelectrotech/elements/")
set(QET_COMMON_TBT_PATH "share/qelectrotech/titleblocks/")
set(QET_LANG_PATH "share/qelectrotech/lang/")
set(QET_EXAMPLES_PATH "share/qelectrotech/examples/")
set(QET_LICENSE_PATH "doc/qelectrotech/")
set(QET_MIME_PACKAGE_PATH "../share/mime/packages/")
set(QET_MIME_PACKAGE_PATH "share/mime/packages/")
set(QET_DESKTOP_PATH "share/applications/")
set(QET_ICONS_PATH "share/icons/hicolor/")
set(QET_MAN_PATH "man/")
+40 -4
View File
@@ -33,6 +33,13 @@ set(QET_COMPONENTS
Widgets
Concurrent)
# Note: Pdf is intentionally NOT in this list. Some Qt6 distributions
# (notably the Flatpak org.kde.Platform runtime) don't ship the QtPdf
# module at all - it lives in the qtwebengine source tree, not Qt6 core.
# Requesting it here as a REQUIRED component would fail the whole
# configure on those setups. It is probed separately, QUIET and
# non-fatal, right after the main find_package() call below.
set(QET_PRIVATE_LIBRARIES
Qt::PrintSupport
Qt::Gui
@@ -45,6 +52,9 @@ set(QET_PRIVATE_LIBRARIES
Qt::Concurrent
)
# Qt::Pdf is appended conditionally in CMakeLists.txt, once we know
# whether the module was actually found (see QET_HAS_QTPDF).
set(QET_RES_FILES
${QET_DIR}/sources/autoNum/ui/autonumberingdockwidget.ui
${QET_DIR}/sources/autoNum/ui/autonumberingmanagementw.ui
@@ -91,7 +101,6 @@ set(QET_RES_FILES
${QET_DIR}/sources/ui/configsaveloaderwidget.ui
${QET_DIR}/sources/ui/diagramcontextwidget.ui
${QET_DIR}/sources/ui/diagrameditorhandlersizewidget.ui
${QET_DIR}/sources/ui/diagramselection.ui
${QET_DIR}/sources/ui/dialogwaiting.ui
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.ui
${QET_DIR}/sources/ui/elementinfopartwidget.ui
@@ -165,7 +174,11 @@ set(QET_SRC_FILES
${QET_DIR}/sources/conductornumexport.cpp
${QET_DIR}/sources/wiringlistexport.h
${QET_DIR}/sources/wiringlistexport.cpp
${QET_DIR}/sources/ui/wiringlistdialog.h
${QET_DIR}/sources/ui/wiringlistdialog.cpp
${QET_DIR}/sources/conductornumexport.h
${QET_DIR}/sources/bomexport.cpp
${QET_DIR}/sources/bomexport.h
${QET_DIR}/sources/conductorprofile.cpp
${QET_DIR}/sources/conductorprofile.h
${QET_DIR}/sources/conductorproperties.cpp
@@ -177,6 +190,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/configdialog.h
${QET_DIR}/sources/createdxf.cpp
${QET_DIR}/sources/createdxf.h
${QET_DIR}/sources/dxfpaintdevice.cpp
${QET_DIR}/sources/dxfpaintdevice.h
${QET_DIR}/sources/diagramcommands.cpp
${QET_DIR}/sources/diagramcommands.h
${QET_DIR}/sources/diagramcontent.cpp
@@ -307,6 +322,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/diagramevent/diagrameventaddimage.h
${QET_DIR}/sources/diagramevent/diagrameventaddshape.cpp
${QET_DIR}/sources/diagramevent/diagrameventaddshape.h
${QET_DIR}/sources/diagramevent/diagrameventaddpath.cpp
${QET_DIR}/sources/diagramevent/diagrameventaddpath.h
${QET_DIR}/sources/diagramevent/diagrameventaddtext.cpp
${QET_DIR}/sources/diagramevent/diagrameventaddtext.h
${QET_DIR}/sources/diagramevent/diagrameventinterface.cpp
@@ -460,6 +477,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/project/projectusagetracker.cpp
${QET_DIR}/sources/project/projectusagetracker.h
${QET_DIR}/sources/properties/deviceinformation.cpp
${QET_DIR}/sources/properties/deviceinformation.h
${QET_DIR}/sources/properties/elementdata.cpp
${QET_DIR}/sources/properties/elementdata.h
${QET_DIR}/sources/properties/propertiesinterface.cpp
@@ -507,6 +526,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/qetgraphicsitem/qetgraphicsitem.h
${QET_DIR}/sources/qetgraphicsitem/qetshapeitem.cpp
${QET_DIR}/sources/qetgraphicsitem/qetshapeitem.h
${QET_DIR}/sources/qetgraphicsitem/shapetransform.cpp
${QET_DIR}/sources/qetgraphicsitem/shapetransform.h
${QET_DIR}/sources/qetgraphicsitem/qgraphicsitemutility.cpp
${QET_DIR}/sources/qetgraphicsitem/qgraphicsitemutility.h
${QET_DIR}/sources/qetgraphicsitem/reportelement.cpp
@@ -687,8 +708,6 @@ set(QET_SRC_FILES
${QET_DIR}/sources/ui/diagrampropertiesdialog.h
${QET_DIR}/sources/ui/diagrampropertieseditordockwidget.cpp
${QET_DIR}/sources/ui/diagrampropertieseditordockwidget.h
${QET_DIR}/sources/ui/diagramselection.cpp
${QET_DIR}/sources/ui/diagramselection.h
${QET_DIR}/sources/ui/backupdialog.cpp
${QET_DIR}/sources/ui/backupdialog.h
${QET_DIR}/sources/ui/dialogwaiting.cpp
@@ -709,8 +728,12 @@ set(QET_SRC_FILES
${QET_DIR}/sources/ui/elementpropertieswidget.h
${QET_DIR}/sources/ui/formulaassistantdialog.cpp
${QET_DIR}/sources/ui/formulaassistantdialog.h
${QET_DIR}/sources/ui/imagecropdialog.cpp
${QET_DIR}/sources/ui/imagecropdialog.h
${QET_DIR}/sources/ui/imagepropertieswidget.cpp
${QET_DIR}/sources/ui/imagepropertieswidget.h
${QET_DIR}/sources/ui/imagetransparentcolordialog.cpp
${QET_DIR}/sources/ui/imagetransparentcolordialog.h
${QET_DIR}/sources/ui/importelementdialog.cpp
${QET_DIR}/sources/ui/importelementdialog.h
${QET_DIR}/sources/ui/importelementtextpatterndialog.cpp
@@ -781,6 +804,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/undocommand/setautonumcontextcommand.h
${QET_DIR}/sources/undocommand/rotateselectioncommand.cpp
${QET_DIR}/sources/undocommand/rotateselectioncommand.h
${QET_DIR}/sources/undocommand/promoteshapecommand.cpp
${QET_DIR}/sources/undocommand/promoteshapecommand.h
${QET_DIR}/sources/undocommand/rotatetextscommand.cpp
${QET_DIR}/sources/undocommand/rotatetextscommand.h
${QET_DIR}/sources/undocommand/movegraphicsitemcommand.cpp
@@ -801,7 +826,7 @@ set(QET_SRC_FILES
${QET_DIR}/sources/xml/terminalstriplayoutpatternxml.h
)
if(NOT BUILD_WITH_KF5)
if(NOT BUILD_WITH_KF)
list(APPEND QET_SRC_FILES
${QET_DIR}/sources/ui/nokde/kautosavefile.cpp
${QET_DIR}/sources/ui/nokde/kautosavefile.h
@@ -812,6 +837,16 @@ if(NOT BUILD_WITH_KF5)
)
endif()
# Qt6-only: PDF page import files
if(QT_VERSION_MAJOR GREATER_EQUAL 6)
list(APPEND QET_SRC_FILES
${QET_DIR}/sources/diagramevent/diagrameventaddpdf.cpp
${QET_DIR}/sources/diagramevent/diagrameventaddpdf.h
${QET_DIR}/sources/ui/pdfpagesdialog.cpp
${QET_DIR}/sources/ui/pdfpagesdialog.h
)
endif()
set(TS_FILES
${QET_DIR}/lang/qet_ar.ts
${QET_DIR}/lang/qet_ca.ts
@@ -827,6 +862,7 @@ set(TS_FILES
${QET_DIR}/lang/qet_hu.ts
${QET_DIR}/lang/qet_it.ts
${QET_DIR}/lang/qet_ja.ts
${QET_DIR}/lang/qet_ko.ts
${QET_DIR}/lang/qet_mn.ts
${QET_DIR}/lang/qet_nb.ts
${QET_DIR}/lang/qet_nl.ts
+6 -2
View File
@@ -28,5 +28,9 @@ add_definitions(-DQET_ALLOW_OVERRIDE_CD_OPTION)
# Comment the line below to deactivate the --data-dir option
add_definitions(-DQET_ALLOW_OVERRIDE_DD_OPTION)
#comment the line below to disable the project database export
#add_definitions(-DQET_EXPORT_PROJECT_DB) #error Todo
# Enable project database export when requested by the build system.
option(QET_EXPORT_PROJECT_DB "Enable project database export" OFF)
if(QET_EXPORT_PROJECT_DB)
add_compile_definitions(QET_EXPORT_PROJECT_DB)
endif()
+93
View File
@@ -0,0 +1,93 @@
# Smart Device Information and BOM CSV
## Architecture
- A `.qet` project is XML. Placed component properties are held in
`ElementData::m_informations`, a `DiagramContext`, and are serialized by the
existing `Element::fromXml()` and `Element::toXml()` path.
- `DeviceInformation` is a typed view over that existing context. It does not
introduce a second data store. Updates made by the properties editor continue
to use `ChangeElementInformationCommand`, including undo/redo and dirty state.
- The project database copies element contexts into `element_info` and exposes
reporting fields through `element_nomenclature_view`.
- GUI and CLI BOM exports both use `BomExport::defaultQuery()` against that
view. The existing `BOMExportDialog` remains the only GUI export entry point;
users can still customize columns, filters, and grouped/ungrouped output.
## Device Properties
| Device field | XML/context key | Default BOM |
| --- | --- | --- |
| Device tag | `label` | Yes |
| Manufacturer | `manufacturer` | Yes |
| Part number | `manufacturer_reference` | Yes |
| Model | `model` | Yes |
| Description | `description` | Yes |
| Category | `category` | Yes |
| Quantity | `quantity` | Yes |
| Voltage rating | `voltage_rating` | Yes |
| Current rating | `current_rating` | Yes |
| Page | `folio` from the diagram | Yes |
| Notes | `notes` | Yes |
The five new context keys are `model`, `category`, `voltage_rating`,
`current_rating`, and `notes`. They are available in the existing information
editor for Simple and Master elements, in symbol definitions, in the SQL
nomenclature view, and in the export column picker.
No XML version bump or migration is required. Missing keys read as empty
strings, empty properties are omitted by the existing writer, and unknown
context keys remain preserved. Quantity and ratings stay free text so existing
unit conventions and decimal quantities are not changed implicitly.
## BOM Policy
The default BOM query exports one row per Simple or Master element. Slave
contacts, terminal-strip elements, reports, thumbnails, and conductor
definitions are excluded. A Master device is counted once and PLC I/O entries
are not expanded. The existing `exclude_from_bom` property is honored by the
SQL view, including common true representations (`true`, `1`, `yes`, `on`).
The default columns are:
`Device tag, Designation, Manufacturer, Part number, Model, Description,
Category, Quantity, Voltage rating, Current rating, Page, Notes`.
The existing **Format as bill of materials** checkbox provides grouped output;
it is off by default so the initial export remains ungrouped. Users may change
the query and column order through the existing dialog. The command-line
`--export-bom` operation uses the same default query and column order.
CSV output is UTF-8 with a BOM, semicolon-delimited, and quotes every field.
Embedded quotes are doubled and embedded newlines are retained. `QSaveFile`
provides atomic replacement; query, open, write, and commit failures are
reported without deleting an existing destination first.
## Verification
The smart-device test is registered explicitly in
`tests/qttest/CMakeLists.txt` and uses only Qt Test and Qt SQL. It is therefore
part of the normal cross-platform CMake/CTest flow:
```sh
cmake -S . -B build -DPACKAGE_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure
```
`tst_smart_device` checks the metadata column contract, Simple/Master filtering,
stable page ordering, UTF-8 with Latin and non-Latin samples, CSV escaping, and
atomic write success/failure. Existing project XML save/load tests cover the
generic `DiagramContext` persistence path used by the new keys.
Manual checks:
1. Open an existing project and edit a Simple or Master element's information.
2. Set all device fields, apply, undo, redo, save, close, and reopen.
3. Open Project > Export as CSV and verify the device columns are preselected.
4. Export with grouping both disabled and enabled.
5. Verify leading-zero part numbers, non-Latin text, quotes, and newlines in a
UTF-8 CSV reader.
Cable management, terminal-strip planning, automatic wire numbering, PLC I/O
expansion, panel layout, and manufacturer catalog integration are out of scope.
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
</defs>
<g transform="translate(1,1)">
<path style="fill:currentColor;fill-opacity:1;stroke:none" d="m18.5 4c-.65424 0-1.202197.418077-1.408203 1h-13.0918v1c3.601 0 6.5 2.899 6.5 6.5 0 1.905514-.822115 3.601777-2.121094 4.787109-.245727-.180239-.548776-.287109-.878906-.287109-.831 0-1.5.669-1.5 1.5 0 .831.669 1.5 1.5 1.5.65424 0 1.202197-.418077 1.408203-1h4.091797v1h3v-3h-3v1h-3.912109c1.479147-1.367931 2.412109-3.317097 2.412109-5.5 0-2.788667-1.510668-5.207469-3.757813-6.5h9.349609c.206006.581923.753963 1 1.408203 1 .831 0 1.5-.669 1.5-1.5 0-.831-.669-1.5-1.5-1.5m0 1c.277 0 .5.223.5.5 0 .277-.223.5-.5.5-.06925 0-.135453-.013828-.195312-.039063-.179579-.075703-.304688-.253188-.304688-.460938 0-.06925.013828-.135453.039062-.195313.075704-.179578.253188-.304688.460938-.304688m-11 13c.277 0 .5.223.5.5 0 .277-.223.5-.5.5-.277 0-.5-.223-.5-.5 0-.277.223-.5.5-.5m6.5 0h1v1h-1v-1z" transform="translate(-.99999-.99999)" class="ColorScheme-Text"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
<g transform="translate(1,1)">
<g class="ColorScheme-Text" fill="currentColor">
<path d="m6 14c0 2.77 2.23 5 5 5s5-2.23 5-5z" fill-rule="evenodd" opacity=".66"/>
<path d="m7.482 10c-.34.586-.65 1.148-.886 1.676a4.958 4.958 0 0 0 -.596 2.324h10c0-.845-.228-1.627-.596-2.324a18.518 18.518 0 0 0 -.886-1.676z" fill-rule="evenodd" opacity=".33"/>
<path d="m11 3c-.973 3.405-3.354 6.332-4.404 8.676a4.958 4.958 0 0 0 -.596 2.324c0 2.77 2.23 5 5 5s5-2.23 5-5c0-.845-.228-1.627-.596-2.324-1.05-2.344-3.431-5.271-4.404-8.676zm0 2.393c1.194 2.668 2.747 5.027 3.492 6.691l.012.03.016.029a3.94 3.94 0 0 1 .48 1.857c0 2.233-1.767 4-4 4a3.97 3.97 0 0 1 -4-4c0-.665.177-1.283.48-1.857l.016-.03.012-.029c.745-1.664 2.298-4.023 3.492-6.691z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 983 B

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 4 2 L 4 3 L 5 3 L 5 2 L 4 2 z M 11 2 L 11 3 L 12 3 L 12 2 L 11 2 z M 2 4 L 2 12 L 7 12 L 7 10 L 9 10 L 9 12 L 14 12 L 14 4 L 9 4 L 9 6 L 7 6 L 7 4 L 2 4 z M 3 5 L 6 5 L 6 11 L 3 11 L 3 5 z M 10 5 L 13 5 L 13 11 L 10 11 L 10 5 z M 11 6 L 11 10 L 12 10 L 12 6 L 11 6 z M 7 7 L 9 7 L 9 9 L 7 9 L 7 7 z M 4 13 L 4 14 L 5 14 L 5 13 L 4 13 z M 11 13 L 11 14 L 12 14 L 12 13 L 11 13 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 716 B

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 4 2 L 4 7 L 6 7 L 6 9 L 4 9 L 4 14 L 12 14 L 12 9 L 10 9 L 10 7 L 12 7 L 12 2 L 4 2 z M 5 3 L 11 3 L 11 6 L 5 6 L 5 3 z M 2 4 L 2 5 L 3 5 L 3 4 L 2 4 z M 13 4 L 13 5 L 14 5 L 14 4 L 13 4 z M 7 7 L 9 7 L 9 9 L 7 9 L 7 7 z M 5 10 L 11 10 L 11 13 L 5 13 L 5 10 z M 2 11 L 2 12 L 3 12 L 3 11 L 2 11 z M 6 11 L 6 12 L 10 12 L 10 11 L 6 11 z M 13 11 L 13 12 L 14 12 L 14 11 L 13 11 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 716 B

@@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#232629;
}
</style>
</defs>
<g transform="translate(1,1)">
<path style="fill:currentColor;fill-opacity:1;stroke:none" d="M 3 3 L 3 5 L 3 6 L 6 6 L 6 5 L 6 3 L 4 3 L 3 3 z M 16 3 L 16 4 L 16 5 L 16 6 L 17 6 L 18 6 L 19 6 L 19 5 L 19 4 L 19 3 L 16 3 z M 4 4 L 5 4 L 5 5 L 4 5 L 4 4 z M 17 4 L 18 4 L 18 5 L 17 5 L 17 4 z M 7 5 L 7 6 L 9 6 L 9 5 L 7 5 z M 10 5 L 10 6 L 12 6 L 12 5 L 10 5 z M 13 5 L 13 6 L 15 6 L 15 5 L 13 5 z M 5 7 L 5 9 L 6 9 L 6 7 L 5 7 z M 16 7 L 16 9 L 17 9 L 17 7 L 16 7 z M 5 10 L 5 12 L 6 12 L 6 10 L 5 10 z M 16 10 L 16 12 L 17 12 L 17 10 L 16 10 z M 5 13 L 5 15 L 6 15 L 6 13 L 5 13 z M 16 13 L 16 15 L 17 15 L 17 13 L 16 13 z M 3 16 L 3 17 L 3 19 L 4 19 L 5 19 L 6 19 L 6 16 L 3 16 z M 7 16 L 7 17 L 9 17 L 9 16 L 7 16 z M 10 16 L 10 17 L 12 17 L 12 16 L 10 16 z M 13 16 L 13 17 L 15 17 L 15 16 L 13 16 z M 16 16 L 16 17 L 16 18 L 16 19 L 17 19 L 18 19 L 19 19 L 19 18 L 19 17 L 19 16 L 17 16 L 16 16 z M 4 17 L 5 17 L 5 18 L 4 18 L 4 17 z M 17 17 L 18 17 L 18 18 L 17 18 L 17 17 z " class="ColorScheme-Text"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
View File
Binary file not shown.
+1879 -1023
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1024
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1873 -1023
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1024
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1741 -966
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1024
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1889 -1033
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1872 -1025
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1866 -1017
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1869 -1018
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+2396 -1495
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1873 -1025
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1867 -1022
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1868 -1021
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1024
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1870 -1022
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+2245 -1361
View File
File diff suppressed because it is too large Load Diff
+1864 -1015
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1873 -1024
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1867 -1021
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+2246 -1367
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1020
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1866 -1015
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1873 -1026
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1866 -1015
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1868 -1015
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1866 -1015
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1869 -1022
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1868 -1023
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+1871 -1022
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+2132 -1266
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -40,9 +40,9 @@
<key>CFBundleExecutable</key>
<string>qelectrotech</string>
<key>CFBundleIconFile</key>
<string>qelectrotech.icns</string>
<string>qelectrotech</string>
<key>CFBundleIdentifier</key>
<string>org.qelectrotech</string>
<string>org.qelectrotech.QElectroTech</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
+593
View File
@@ -0,0 +1,593 @@
#!/bin/sh
# Copyright 2026 The QElectroTech Team
# This file is part of QElectroTech.
# QElectroTech 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 2 of the License, or
# (at your option) any later version.
# Suppose que l'environnement a ete prepare via macos_homebrew_setup.sh
# (Homebrew, Qt6, cmake, ninja, kf6-kwidgetsaddons, kf6-kcoreaddons).
#
# Remplace l'ancien misc/MacQetDeploy_arm64.sh (qmake/Qt5) par un
# build CMake/Qt6/KF6. La chaine de signature/notarization/DMG est
# reprise a l'identique de l'ancien script (eprouvee, ne pas y toucher
# sans raison).
# configuration
APPNAME='qelectrotech'
BUNDLE=$APPNAME.app
IDENTITY="Developer ID Application: Laurent TRINQUES (Y73WZ6WZ5X)"
QT_MAJOR="${QT_MAJOR:-6}"
BUILD_WITH_KF="${BUILD_WITH_KF:-ON}"
BUILD_DIR="build-macos-arm64"
# Temp paths
RW_DMG="/tmp/qet_rw.dmg"
MOUNT_POINT="/tmp/qet_dmg_mount"
STAGING="/tmp/qet_dmg_staging"
# Script location
current_dir=$(dirname "$0")
cd "${current_dir}/../"
current_dir=$(PWD)
### get system configuration ########################################
echo
echo "______________________________________________________________"
echo "This script prepares a Qt6/KF6 application bundle for deployment."
echo "This script :"
echo "\t - update the git depot"
echo "\t - configure and build via CMake,"
echo "\t - copy over required Qt frameworks,"
echo "\t - copy additional files: translations, titleblocks and elements,"
echo "\t - notarize the .app, then create a signed DMG."
echo
QT_PREFIX=$(brew --prefix qt 2>/dev/null || true)
if [ -z "$QT_PREFIX" ] || [ ! -d "$QT_PREFIX/lib/QtCore.framework" ] ; then
echo "ERROR: cannot find Qt6 via Homebrew. Run macos_homebrew_setup.sh first."
exit 1
fi
export CMAKE_PREFIX_PATH="$QT_PREFIX:$CMAKE_PREFIX_PATH"
### GIT ####################################################
echo
echo "______________________________________________________________"
echo "Run GIT:"
git submodule init
git submodule update
git pull --recurse-submodules
git pull
GITCOMMIT=$(git rev-parse --short HEAD)
A=$(git rev-list HEAD --count)
HEAD=$(($A+473))
VERSION=$(cat sources/qetversion.cpp | grep "return QVersionNumber{"| head -n 1| awk -F "{" '{ print $2 }' | awk -F "}" '{ print $1 }' | sed -e 's/,/./g' -e 's/ //g')
DMG_NAME="${APPNAME}-$VERSION-r$HEAD-arm64.dmg"
DMG_PATH="build-aux/mac-osx/$DMG_NAME"
if [ -e "$DMG_PATH" ] ; then
echo "There are not new updates, make disk image can"
echo "take a lot of time (5 min). Can you continu?"
echo "[y/n]"
read userinput
if [ "$userinput" == "n" ] ; then
echo
echo "Process is stopped."
echo
exit
fi
fi
### build with CMake #################################################
echo
echo "______________________________________________________________"
echo "Run CMake configure + build (Qt${QT_MAJOR}, BUILD_WITH_KF=${BUILD_WITH_KF}):"
if [ -d $BUNDLE ] ; then
echo "Removing old bundle..."
rm -rf $BUNDLE
fi
if [ -d "$BUILD_DIR" ] ; then
echo "Removing old build directory..."
rm -rf "$BUILD_DIR"
fi
cmake -S . -B "$BUILD_DIR" -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DQT_VERSION_MAJOR=$QT_MAJOR \
-DBUILD_WITH_KF=$BUILD_WITH_KF \
-DBUILD_KF=OFF \
-DQET_EXPORT_PROJECT_DB=ON \
-DPACKAGE_TESTS=OFF
if [ $? -ne 0 ]; then
echo "ERROR: cmake configure failed."
exit 1
fi
START_TIME=$SECONDS
coeur=$(sysctl hw.ncpu | awk '{print $2}')
cmake --build "$BUILD_DIR" -j$(($coeur + 1))
if [ $? -ne 0 ]; then
ELAPSED_TIME=$(($SECONDS - $START_TIME))
echo
echo "cmake build failed - $(($ELAPSED_TIME/60)) min $(($ELAPSED_TIME%60)) sec"
exit 1
fi
ELAPSED_TIME=$(($SECONDS - $START_TIME))
echo
echo "The time of compilation is $(($ELAPSED_TIME/60)) min $(($ELAPSED_TIME%60)) sec"
# Le .app sort a la racine de $BUILD_DIR : add_executable(... MACOSX_BUNDLE)
# sans RUNTIME_OUTPUT_DIRECTORY dans CMakeLists.txt.
echo "Copying built bundle into place..."
cp -R "$BUILD_DIR/qelectrotech.app" "./$BUNDLE"
if [ ! -d "$BUNDLE" ] ; then
echo "ERROR: expected bundle \"$BUNDLE\" not found after cmake build."
exit 1
fi
### copy over frameworks ############################################
echo
echo "______________________________________________________________"
echo "Copy Qt libraries and private frameworks:"
if [ ! -d $BUNDLE ] ; then
echo "ERROR: cannot find application bundle \"$BUNDLE\" in current directory"
exit 1
fi
macdeployqt $BUNDLE
### fix Homebrew dependencies macdeployqt could not handle ##########
# Recent Homebrew bottles (brotli, webp, sharpyuv...) reference their own
# dependencies as @rpath/libX.dylib. macdeployqt only resolves @rpath in
# Contents/lib and in Qt's lib dir (-libpath does not help): it prints
# "Cannot resolve rpath" and leaves some references untouched, either
# absolute /opt/homebrew paths or @rpath libs missing from the bundle.
# Fix both here: every /opt/homebrew reference is rewritten to
# @rpath/libX.dylib (install ids too), and every @rpath/libX.dylib is
# copied into Contents/Frameworks, where the executable's LC_RPATH
# (@executable_path/../Frameworks) lets dyld find it. Everything is signed
# below with the rest of Frameworks/.
echo
echo "______________________________________________________________"
echo "Fix Homebrew dependencies left by macdeployqt:"
FW="$BUNDLE/Contents/Frameworks"
chmod -R u+w "$BUNDLE/Contents/MacOS" "$FW" "$BUNDLE/Contents/PlugIns" 2>/dev/null
# Every Mach-O candidate of the bundle (otool silently ignores the others)
list_macho() {
find "$BUNDLE/Contents/MacOS" "$FW" "$BUNDLE/Contents/PlugIns" -type f \
\( -name '*.dylib' -o -perm -u+x \) 2>/dev/null
}
# Dependencies of one binary, without its own install id (dylibs only)
list_deps() {
_id=$(otool -D "$1" 2>/dev/null | sed -n 2p)
otool -L "$1" 2>/dev/null | awk 'NR>1 { print $1 }' | while read _dep; do
[ "$_dep" = "$_id" ] || echo "$_dep"
done
}
# The @rpath/libX.dylib names referenced anywhere in the bundle
list_rpath_libs() {
list_macho | while read bin; do
list_deps "$bin" | sed -n 's#^@rpath/\([^/]*\.dylib\)$#\1#p'
done | LC_ALL=C sort -u
}
if ! otool -l "$BUNDLE/Contents/MacOS/$APPNAME" | grep -q "@executable_path/../Frameworks" ; then
install_name_tool -add_rpath "@executable_path/../Frameworks" "$BUNDLE/Contents/MacOS/$APPNAME"
echo " Added LC_RPATH @executable_path/../Frameworks to $APPNAME"
fi
# 3 passes, since each copied library can bring its own dependencies:
# a. rewrite absolute /opt/homebrew references (install ids included),
# copying the referenced library into Frameworks/ if needed
# b. copy the @rpath/libX.dylib still missing from Frameworks/
for PASS in 1 2 3; do
list_macho | while read bin; do
_id=$(otool -D "$bin" 2>/dev/null | sed -n 2p)
case "$_id" in
/opt/homebrew/*)
install_name_tool -id "@rpath/$(basename "$_id")" "$bin" 2>/dev/null
echo " Fixed id (pass $PASS): $(basename "$bin")"
;;
esac
list_deps "$bin" | grep '^/opt/homebrew/' | while read ref; do
name=$(basename "$ref")
if [ ! -e "$FW/$name" ]; then
cp -L "$ref" "$FW/$name" && chmod u+w "$FW/$name"
echo " Copied (pass $PASS): $name"
fi
install_name_tool -change "$ref" "@rpath/$name" "$bin" 2>/dev/null
echo " Fixed ref (pass $PASS): $(basename "$bin") -> @rpath/$name"
done
done
list_rpath_libs | while read lib; do
if [ ! -e "$FW/$lib" ] && [ -e "/opt/homebrew/lib/$lib" ]; then
cp -L "/opt/homebrew/lib/$lib" "$FW/$lib" && chmod u+w "$FW/$lib"
echo " Copied (pass $PASS): $lib"
fi
done
done
# 3. Checks
UNRESOLVED=$(list_rpath_libs | while read lib; do [ -e "$FW/$lib" ] || echo "$lib"; done)
if [ -n "$UNRESOLVED" ]; then
echo "ERROR: @rpath libraries still missing from Frameworks/:" $UNRESOLVED
exit 1
fi
HOMEBREW_REFS=$(list_macho | while read bin; do
otool -L "$bin" 2>/dev/null | awk 'NR>1 { print $1 }' | grep '^/opt/homebrew/' \
| sed "s#^# $(basename "$bin") -> #"
done)
if [ -n "$HOMEBREW_REFS" ]; then
echo "ERROR: bundle still references Homebrew paths:"
echo "$HOMEBREW_REFS"
exit 1
fi
echo "All dependencies resolved inside the bundle."
### install Info.plist and app icon #################################
# NOTE: this must run AFTER macdeployqt, not before. macdeployqt
# rewrites/regenerates parts of Contents/Resources, and files copied
# there beforehand (e.g. the .icns icons) do not reliably survive it
# and end up missing from the final bundle, causing the app to show
# the generic placeholder icon instead of the real one. Info.plist
# itself lives directly in Contents/ and happens to survive either
# way, but keep it here too so this whole "final metadata" step stays
# in one place, after macdeployqt is done touching the bundle.
echo
echo "______________________________________________________________"
echo "Install Info.plist and app icon:"
cp -R ${current_dir}/misc/Info.plist $BUNDLE/Contents/
cp -R ${current_dir}/ico/mac_icon/*.icns $BUNDLE/Contents/Resources/
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $VERSION r$HEAD" "$BUNDLE/Contents/Info.plist"
### add missing files ###############################################
echo
echo "______________________________________________________________"
echo "Copy missing files:"
QET_ELMT_DIR="${current_dir}/elements/"
QET_TBT_DIR="${current_dir}/titleblocks/"
QET_LANG_DIR="${current_dir}/lang/"
QET_EXAMPLES_DIR="${current_dir}/examples/"
QET_FONTS_DIR="${current_dir}/fonts/"
QET_LICENSES_DIR="${current_dir}/licenses/"
if [ -d "${QET_ELMT_DIR}" ]; then
cp -R ${QET_ELMT_DIR} $BUNDLE/Contents/Resources/elements
fi
if [ -d "${QET_TBT_DIR}" ]; then
cp -R ${QET_TBT_DIR} $BUNDLE/Contents/Resources/titleblocks
fi
# Traductions : depuis la PR #751, les .qm ne sont plus versionnes ; lrelease
# les genere dans $BUILD_DIR/lang/. Jeu attendu = les .ts listes dans TS_FILES
# (cmake/qet_compilation_vars.cmake) : un .qm manquant arrete le script, un
# .ts present dans lang/ mais absent de TS_FILES donne seulement un WARNING.
# Fichiers temporaires plutot que <(...) : /bin/sh de macOS (bash 3.2 en mode
# POSIX) n'a pas la substitution de processus.
QM_SRC="${current_dir}/${BUILD_DIR}/lang"
QM_TMP=$(mktemp -d /tmp/qet_qm.XXXXXX)
grep -o 'lang/qet_[A-Za-z_]*\.ts' "${current_dir}/cmake/qet_compilation_vars.cmake" \
| sed -e 's#^lang/##' -e 's#\.ts$##' | LC_ALL=C sort -u > "$QM_TMP/listed"
if [ ! -s "$QM_TMP/listed" ]; then
echo "ERROR: cannot read TS_FILES from cmake/qet_compilation_vars.cmake"
rm -rf "$QM_TMP"
exit 1
fi
find "${QET_LANG_DIR}" -maxdepth 1 -name 'qet_*.ts' -exec basename {} .ts \; | LC_ALL=C sort > "$QM_TMP/present"
UNLISTED=$(LC_ALL=C comm -13 "$QM_TMP/listed" "$QM_TMP/present")
if [ -n "$UNLISTED" ]; then
echo "WARNING: .ts files not in TS_FILES, no .qm built:" $UNLISTED
fi
mkdir -p $BUNDLE/Contents/Resources/lang
find "${QM_SRC}" -maxdepth 1 -name 'qet_*.qm' -exec cp {} $BUNDLE/Contents/Resources/lang/ \; 2>/dev/null
find $BUNDLE/Contents/Resources/lang -maxdepth 1 -name 'qet_*.qm' -exec basename {} .qm \; | LC_ALL=C sort > "$QM_TMP/built"
MISSING=$(LC_ALL=C comm -23 "$QM_TMP/listed" "$QM_TMP/built")
echo "$(wc -l < "$QM_TMP/built" | tr -d ' ') .qm files copied to Contents/Resources/lang (expected: $(wc -l < "$QM_TMP/listed" | tr -d ' '))"
# Traductions de Qt lui-meme (boutons OK/Annuler, dialogues standard...) :
# elles viennent de qtbase_XX.qm, pas des .ts de QET, et macdeployqt ne les
# deploie pas. QETApp::setLanguage() charge "qt_XX" depuis le chemin de
# traductions de Qt (absent du bundle), puis depuis le dossier lang/ de QET :
# on y depose donc chaque qtbase_XX.qm sous le nom qt_XX.qm. qtbase_XX.qm est
# autonome, contrairement aux qt_XX.qm de Qt qui dependent de tous les modules.
# Premier dossier contenant des qtbase_*.qm : celui annonce par qtpaths, puis
# la formule Homebrew separee qttranslations, puis les autres emplacements
# Homebrew possibles. Homebrew fait de ces dossiers des liens symboliques
# (-> Cellar/qttranslations/...) : find doit donc les suivre (-L), sinon il
# ne voit que le lien lui-meme et ne trouve aucun fichier dedans.
QT_TR_DIR=""
for d in "$("$QT_PREFIX/bin/qtpaths" --query QT_INSTALL_TRANSLATIONS 2>/dev/null)" \
"$(brew --prefix qttranslations 2>/dev/null)/share/qt/translations" \
"$QT_PREFIX/share/qt/translations" \
/opt/homebrew/share/qt/translations \
/opt/homebrew/opt/*/share/qt/translations ; do
if ls "$d"/qtbase_*.qm >/dev/null 2>&1 ; then
QT_TR_DIR="$d"
break
fi
done
LANG_DST="$BUNDLE/Contents/Resources/lang"
find -L "$QT_TR_DIR" -maxdepth 1 -name 'qtbase_*.qm' 2>/dev/null | while read f; do
l=$(basename "$f" .qm | sed 's/^qtbase_//')
cp "$f" "$LANG_DST/qt_$l.qm"
done
# Langues QET sans equivalent Qt exact (pt -> pt_PT, zh -> zh_CN...) :
# QTranslator ne sait que raccourcir le code (fr_FR -> fr), pas l'allonger.
# On prefere la variante "principale" (pt_PT), sinon la premiere trouvee.
sed 's/^qet_//' "$QM_TMP/listed" | while read l; do
if [ ! -e "$LANG_DST/qt_$l.qm" ]; then
main="$QT_TR_DIR/qtbase_${l}_$(echo "$l" | tr 'a-z' 'A-Z').qm"
if [ -e "$main" ]; then
alt="$main"
else
alt=$(find -L "$QT_TR_DIR" -maxdepth 1 -name "qtbase_${l}_*.qm" 2>/dev/null | LC_ALL=C sort | head -1)
fi
[ -n "$alt" ] && cp "$alt" "$LANG_DST/qt_$l.qm"
fi
done
QT_QM_COUNT=$(find "$LANG_DST" -maxdepth 1 -name 'qt_*.qm' | wc -l | tr -d ' ')
echo "${QT_QM_COUNT} Qt translation files (qt_*.qm) copied from ${QT_TR_DIR:-<not found>}"
if [ "${QT_QM_COUNT}" -eq 0 ]; then
echo "ERROR: no qtbase_*.qm found (Qt translations not installed?)."
echo " Check with: find /opt/homebrew -name 'qtbase_fr.qm'"
rm -rf "$QM_TMP"
exit 1
fi
rm -rf "$QM_TMP"
if [ -n "$MISSING" ]; then
echo "ERROR: missing translations:" $MISSING
exit 1
fi
if [ -d "${QET_EXAMPLES_DIR}" ]; then
mkdir $BUNDLE/Contents/Resources/examples
cp ${current_dir}/examples/*.qet $BUNDLE/Contents/Resources/examples
fi
if [ -d "${QET_FONTS_DIR}" ]; then
mkdir $BUNDLE/Contents/Resources/fonts
cp ${current_dir}/fonts/*.ttf $BUNDLE/Contents/Resources/fonts
fi
if [ -d "${QET_LICENSES_DIR}" ]; then
cp -R -L ${QET_LICENSES_DIR} $BUNDLE/Contents/Resources/licenses
fi
### Sign the bundle #################################################
# Sign in correct order: all dylibs first (including flat libs copied
# by macdeployqt from Homebrew), then frameworks, plugins, bundle last.
echo
echo "______________________________________________________________"
echo "Code signing (dylibs -> frameworks -> plugins -> bundle):"
echo "-- Signing dylibs in Frameworks/..."
find "$BUNDLE/Contents/Frameworks" -name "*.dylib" | while read lib; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
done
echo "-- Signing .framework bundles..."
find "$BUNDLE/Contents/Frameworks" -maxdepth 1 -name "*.framework" | while read fw; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$fw"
done
echo "-- Signing plugins..."
find "$BUNDLE/Contents/PlugIns" \( -name "*.dylib" -o -name "*.so" \) | while read lib; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
done
echo "-- Signing dylibs in MacOS/..."
find "$BUNDLE/Contents/MacOS" -name "*.dylib" | while read lib; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
done
echo "-- Signing main executable..."
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
"$BUNDLE/Contents/MacOS/$APPNAME"
echo "-- Signing bundle..."
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$BUNDLE"
echo
echo "Verifying bundle signature..."
codesign --verify --deep --strict --verbose=2 "$BUNDLE"
if [ $? -ne 0 ]; then
echo "ERROR: bundle signature verification failed, aborting."
exit 1
fi
spctl -a -vv "$BUNDLE"
echo "Bundle signature OK."
### Notarize the .app (via temporary ZIP) ###########################
echo
echo "______________________________________________________________"
echo "Create temporary ZIP for notarization:"
NOTARIZE_ZIP="/tmp/${APPNAME}-$VERSION-r$HEAD-arm64-notarize.zip"
/usr/bin/ditto -c -k --keepParent "$BUNDLE" "$NOTARIZE_ZIP"
echo -e "\033[1;31mWould you like to notarize the .app \"${APPNAME}-${VERSION}-r${HEAD}\", n/Y?\033[m"
read a
if [[ $a == "Y" || $a == "y" ]]; then
echo
echo "______________________________________________________________"
echo "Notarizing .app:"
xcrun notarytool submit "$NOTARIZE_ZIP" --keychain-profile "org.qelectrotech" --wait
if [ $? -ne 0 ]; then
echo "ERROR: notarization failed. Check the log with:"
echo " xcrun notarytool log <submission-id> --keychain-profile org.qelectrotech"
rm -f "$NOTARIZE_ZIP"
exit 1
fi
else
echo -e "\033[1;33mExit.\033[m"
fi
rm -f "$NOTARIZE_ZIP"
### Staple the .app #################################################
echo -e "\033[1;31mWould you like to staple the .app \"${APPNAME}-${VERSION}-r${HEAD}\", n/Y?\033[m"
read a
if [[ $a == "Y" || $a == "y" ]]; then
xcrun stapler staple -v "$BUNDLE"
if [ $? -ne 0 ]; then
echo "ERROR: stapling .app failed."
exit 1
fi
xcrun stapler validate -v "$BUNDLE"
spctl -a -vv "$BUNDLE"
echo ".app stapled OK."
else
echo -e "\033[1;33mExit.\033[m"
fi
### Create staging folder with Applications symlink #################
echo
echo "______________________________________________________________"
echo "Preparing DMG staging folder:"
rm -rf "$STAGING"
mkdir -p "$STAGING"
cp -R "$BUNDLE" "$STAGING/"
ln -s /Applications "$STAGING/Applications"
### Create writable DMG (UDRW) ######################################
echo
echo "______________________________________________________________"
echo "Create writable DMG (UDRW) and re-sign .app inside:"
rm -f "$RW_DMG"
hdiutil create \
-volname "QElectroTech $VERSION" \
-srcfolder "$STAGING" \
-ov \
-format UDRW \
-fs HFS+ \
"$RW_DMG"
if [ $? -ne 0 ]; then
echo "ERROR: hdiutil failed to create writable DMG."
rm -rf "$STAGING"
exit 1
fi
rm -rf "$MOUNT_POINT"
mkdir -p "$MOUNT_POINT"
hdiutil attach "$RW_DMG" -mountpoint "$MOUNT_POINT" -nobrowse -noverify
if [ $? -ne 0 ]; then
echo "ERROR: failed to mount writable DMG."
rm -f "$RW_DMG"
rm -rf "$STAGING"
exit 1
fi
echo "-- Re-signing dylibs inside DMG..."
find "$MOUNT_POINT/$BUNDLE/Contents/Frameworks" -name "*.dylib" | while read lib; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
done
find "$MOUNT_POINT/$BUNDLE/Contents/Frameworks" -maxdepth 1 -name "*.framework" | while read fw; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$fw"
done
find "$MOUNT_POINT/$BUNDLE/Contents/PlugIns" \( -name "*.dylib" -o -name "*.so" \) | while read lib; do
codesign --force --sign "$IDENTITY" --timestamp --options=runtime "$lib"
done
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
"$MOUNT_POINT/$BUNDLE/Contents/MacOS/$APPNAME"
codesign --force --sign "$IDENTITY" --timestamp --options=runtime \
"$MOUNT_POINT/$BUNDLE"
echo "Verifying bundle signature inside DMG..."
codesign --verify --deep --strict --verbose=2 "$MOUNT_POINT/$BUNDLE"
if [ $? -ne 0 ]; then
echo "ERROR: bundle signature invalid inside DMG, aborting."
hdiutil detach "$MOUNT_POINT"
rm -f "$RW_DMG"
rm -rf "$STAGING" "$MOUNT_POINT"
exit 1
fi
echo "Bundle signature inside DMG OK."
hdiutil detach "$MOUNT_POINT"
### Convert UDRW to final compressed UDZO ###########################
echo
echo "______________________________________________________________"
echo "Convert to final compressed DMG (UDZO):"
mkdir -p "build-aux/mac-osx"
rm -f "$DMG_PATH"
hdiutil convert "$RW_DMG" \
-format UDZO \
-o "$DMG_PATH"
if [ $? -ne 0 ]; then
echo "ERROR: hdiutil convert failed."
rm -f "$RW_DMG"
rm -rf "$STAGING" "$MOUNT_POINT"
exit 1
fi
rm -f "$RW_DMG"
rm -rf "$STAGING" "$MOUNT_POINT"
### Sign the final DMG ##############################################
echo "Signing final DMG..."
codesign --sign "$IDENTITY" --timestamp "$DMG_PATH"
### Notarize and staple the final DMG ###############################
echo -e "\033[1;31mWould you like to notarize the DMG \"${DMG_NAME}\", n/Y?\033[m"
read a
if [[ $a == "Y" || $a == "y" ]]; then
echo
echo "______________________________________________________________"
echo "Notarizing DMG:"
xcrun notarytool submit "$DMG_PATH" --keychain-profile "org.qelectrotech" --wait
if [ $? -ne 0 ]; then
echo "ERROR: DMG notarization failed. Check the log with:"
echo " xcrun notarytool log <submission-id> --keychain-profile org.qelectrotech"
exit 1
fi
echo "Stapling DMG..."
xcrun stapler staple "$DMG_PATH"
if [ $? -ne 0 ]; then
echo "ERROR: stapling DMG failed."
exit 1
fi
echo "DMG notarized and stapled OK."
spctl -a -vv "$DMG_PATH"
else
echo -e "\033[1;33mExit.\033[m"
fi
### Clean up bundle #################################################
rm -rf "$BUNDLE"
echo
echo "______________________________________________________________"
echo "The process is done."
echo "DMG is in the folder 'build-aux/mac-osx'."
### Upload via rsync ################################################
echo -e "\033[1;31mWould you like to upload MacOS package \"${DMG_NAME}\", n/Y?\033[m"
read a
if [[ $a == "Y" || $a == "y" ]]; then
cp -Rf "$DMG_PATH" /Users/laurent/MAC_OS_X/
rsync -e ssh -av --delete-after --no-owner --no-g --chmod=g+w \
--progress --exclude='.DS_Store' \
/Users/laurent/MAC_OS_X/ \
server:download.qelectrotech.org/qet/builds/MAC_OS_X/arm64/
if [ $? != 0 ]; then
echo "RSYNC ERROR: problem syncing ${DMG_NAME}, retrying..."
rsync -e ssh -av --delete-after --no-owner --no-g --chmod=g+w \
--progress --exclude='.DS_Store' \
/Users/laurent/MAC_OS_X/ \
server:download.qelectrotech.org/qet/builds/MAC_OS_X/arm64/
fi
else
echo -e "\033[1;33mExit.\033[m"
fi
+9
View File
@@ -140,6 +140,7 @@
<file>ico/22x22/go-up.png</file>
<file>ico/22x22/hotspot.png</file>
<file>ico/22x22/insert-image.png</file>
<file>ico/22x22/pdf-import.png</file>
<file>ico/22x22/label.png</file>
<file>ico/22x22/landscape.png</file>
<file>ico/22x22/line.png</file>
@@ -547,6 +548,14 @@
<file>ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-element.svgz</file>
<file>ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-project.svgz</file>
<file>ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-titleblock.svgz</file>
<file>ico/breeze-icons/scalable/apps/hidef/draw-bezier-curves.svg</file>
<file>ico/breeze-icons/scalable/apps/hidef/transform-crop.svg</file>
<file>ico/breeze-icons/scalable/apps/hidef/image-flip-horizontal-symbolic.svg</file>
<file>ico/breeze-icons/scalable/apps/hidef/image-flip-vertical-symbolic.svg</file>
<file>ico/breeze-icons/scalable/apps/hidef/edit-opacity.svg</file>
<file>ico/generated/rect-to-polyline.svg</file>
<file>ico/generated/rect-to-bezier.svg</file>
<file>ico/generated/ellipse-to-bezier.svg</file>
<file>ico/16x16/object-group.png</file>
<file>ico/mac_icon/elmt.icns</file>
<file>ico/mac_icon/qelectrotech.icns</file>
@@ -38,6 +38,20 @@ ElementsCollectionModel::ElementsCollectionModel(QObject *parent) :
{
}
/**
@brief ElementsCollectionModel::~ElementsCollectionModel
Destructor. loadCollections() may still have background threads
(via QtConcurrent::map()) running setUpData() on this model's items
when the model is destroyed (e.g. the user cancels the dialog before
loading finishes). Wait for them here so QStandardItemModel's
destructor doesn't free items out from under them, which used to
crash the whole application (bugtracker #291).
*/
ElementsCollectionModel::~ElementsCollectionModel()
{
m_future.waitForFinished();
}
/**
@brief ElementsCollectionModel::data
Reimplemented from QStandardItemModel
@@ -49,6 +63,7 @@ QVariant ElementsCollectionModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DecorationRole) {
QStandardItem *item = itemFromIndex(index);
if (!item) return QStandardItemModel::data(index, role);
if (item->type() == FileElementCollectionItem::Type)
static_cast<FileElementCollectionItem*>(item)->setUpIcon();
@@ -316,7 +331,6 @@ void ElementsCollectionModel::loadMacrosCollection()
void ElementsCollectionModel::addMacrosCollection(bool set_data)
{
QString macrosPath = QETApp::userMacrosDir();
qDebug() << "=== MAKRO PFAD CHECK ===" << macrosPath;
if (macrosPath.endsWith("/")) {
macrosPath.remove(macrosPath.length() - 1, 1);
}
@@ -35,6 +35,7 @@ class ElementsCollectionModel : public QStandardItemModel
public:
ElementsCollectionModel(QObject *parent = Q_NULLPTR);
~ElementsCollectionModel() override;
QVariant data(const QModelIndex &index, int role) const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;

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