diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml
new file mode 100644
index 000000000..496970357
--- /dev/null
+++ b/.github/workflows/linux-build.yml
@@ -0,0 +1,79 @@
+# Linux build, unit tests, and the IPC open-forwarding regression gate.
+#
+# The existing workflows build Windows and generate documentation; nothing
+# builds QElectroTech on Linux or runs tests/ in CI. This does both.
+#
+# It runs inside an ubuntu:26.04 container rather than directly on the runner
+# because the IPC gate below needs Qt 6.10.2. The ubuntu-latest image ships
+# Qt 6.4, and whether the crash that gate covers reproduces on 6.4 has never
+# been checked -- a gate that cannot go red is worse than no gate.
+name: Linux build and tests
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ linux:
+ name: Build and test (Qt 6, Debug)
+ runs-on: ubuntu-latest
+ container: ubuntu:26.04
+
+ steps:
+ - name: Install build and test dependencies
+ run: |
+ apt-get update
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ ca-certificates build-essential cmake ninja-build git pkg-config \
+ qt6-base-dev qt6-base-private-dev qt6-tools-dev qt6-tools-dev-tools \
+ libqt6svg6-dev libqt6sql6-sqlite libsqlite3-dev libcups2-dev \
+ libxkbcommon-x11-0 \
+ xvfb openbox xdotool x11-utils
+ # extra-cmake-modules and the KF6 libraries are installed rather than
+ # left to FetchContent: without them CMake builds extra-cmake-modules
+ # from source, and its Qt Help documentation target then demands
+ # Qt6{Core,Gui,Widgets,DBus}Tools, failing the configure with an error
+ # that appears to be about QElectroTech and is not.
+ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+ extra-cmake-modules libkf6coreaddons-dev libkf6widgetsaddons-dev \
+ qt6-svg-plugins
+
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Configure
+ # Debug, not Release. Whether a use-after-free faults depends on what
+ # the allocator does with the freed block: the commit before #868
+ # crashes every time built Debug and survives every time built
+ # -O3 -DNDEBUG, so a Release job would never catch a regression here.
+ run: |
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
+ cmake -B build -G Ninja \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DQT_VERSION_MAJOR=6
+
+ - name: Build
+ run: cmake --build build --parallel $(nproc)
+
+ - name: Unit tests
+ run: xvfb-run -a ctest --test-dir build --output-on-failure
+
+ - name: IPC open-forwarding regression (#868)
+ # Fails the job only on an actual crash. An inconclusive run means the
+ # crash path was not exercised -- it proves nothing, which is not the
+ # same as a regression, and failing on it would make this job flaky
+ # rather than informative.
+ run: |
+ set +e
+ tests/ipc-regression/run.sh --binary build/qelectrotech
+ status=$?
+ set -e
+ case $status in
+ 0) echo "::notice::IPC gate passed" ;;
+ 2) echo "::warning::IPC gate inconclusive -- the crash path was not exercised, nothing was proven" ;;
+ *) echo "::error::IPC gate failed -- forwarded files are being opened inside the socket handler again"
+ exit 1 ;;
+ esac
diff --git a/.github/workflows/windows-msi.yml b/.github/workflows/windows-msi.yml
index 73d57e7ab..03428963a 100644
--- a/.github/workflows/windows-msi.yml
+++ b/.github/workflows/windows-msi.yml
@@ -42,6 +42,9 @@ jobs:
pages: write
id-token: write # Required by SignPath
+ env:
+ SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
+
outputs:
qt6_msi: ${{ steps.export.outputs.msi_name_qt6 }}
@@ -290,7 +293,8 @@ jobs:
# PR/run must never attempt a signing request.
# (cf. DieterMayerOSS:fix/msi-signing-fork-guard, d3f60c88)
- name: Sign MSI via SignPath
- if: github.repository == 'qelectrotech/qelectrotech-source-mirror'
+ id: sign
+ if: github.repository == 'qelectrotech/qelectrotech-source-mirror' && env.SIGNPATH_API_TOKEN != ''
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
@@ -345,7 +349,7 @@ jobs:
run: |
Write-Host "=== MSI build summary (${{ matrix.flavor }}) ==="
Write-Host "Version : ${{ steps.version.outputs.VERSION_DISPLAY }}"
- Write-Host "Signed : true"
+ Write-Host "Signed : ${{ steps.sign.outcome == 'success' }}"
# ---------------------------------------------------------------------------
# Job 2 : Génère et déploie la page GitHub Pages une fois le MSI publié,
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fc0fffd4..60ea552e4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -139,6 +139,7 @@ if(WIN32)
${QET_SRC_FILES}
${QM_FILES}
${QET_DIR}/qelectrotech.qrc
+ ${QET_DIR}/ico/icon-themes.qrc
)
else()
add_executable(
@@ -147,6 +148,7 @@ else()
${QET_SRC_FILES}
${QM_FILES}
${QET_DIR}/qelectrotech.qrc
+ ${QET_DIR}/ico/icon-themes.qrc
)
endif()
diff --git a/ico/icon-themes.qrc b/ico/icon-themes.qrc
new file mode 100644
index 000000000..1a3635da5
--- /dev/null
+++ b/ico/icon-themes.qrc
@@ -0,0 +1,285 @@
+
+
+
+
+ themes/qet/index.theme
+ 16x16/application-exit.png
+ 16x16/arrow-left-double.png
+ 16x16/arrow-left.png
+ 16x16/arrow-right-double.png
+ 16x16/arrow-right.png
+ 16x16/circle.png
+ 16x16/conductor-edit.png
+ 16x16/conductor-reset.png
+ 16x16/conductor.png
+ 16x16/configure-toolbars.png
+ 16x16/configure.png
+ 16x16/diagram.png
+ 16x16/dialog-cancel.png
+ 16x16/dialog-ok.png
+ 16x16/document-close.png
+ 16x16/document-export.png
+ 16x16/document-import.png
+ 16x16/document-new.png
+ 16x16/document-open-recent.png
+ 16x16/document-open.png
+ 16x16/document-print-frame.png
+ 16x16/document-print.png
+ 16x16/document-save-all.png
+ 16x16/document-save-as.png
+ 16x16/document-save.png
+ 16x16/east.png
+ 16x16/edit-clear-locationbar-ltr.png
+ 16x16/edit-clear-locationbar-rtl.png
+ 16x16/edit-clear.png
+ 16x16/edit-copy.png
+ 16x16/edit-cut.png
+ 16x16/edit-delete.png
+ 16x16/edit-download.png
+ 16x16/edit-paste.png
+ 16x16/edit-redo.png
+ 16x16/edit-rename.png
+ 16x16/edit-select-all.png
+ 16x16/edit-select-invert.png
+ 16x16/edit-select-none.png
+ 16x16/edit-table-cell-merge.png
+ 16x16/edit-table-cell-split.png
+ 16x16/edit-table-delete-column.png
+ 16x16/edit-table-delete-row.png
+ 16x16/edit-table-insert-column-left.png
+ 16x16/edit-table-insert-column-right.png
+ 16x16/edit-table-insert-row-above.png
+ 16x16/edit-table-insert-row-under.png
+ 16x16/edit-undo.png
+ 16x16/element-delete.png
+ 16x16/element-edit.png
+ 16x16/element-master.png
+ 16x16/element-new.png
+ 16x16/element-slave.png
+ 16x16/element.png
+ 16x16/endline-circle.png
+ 16x16/endline-diamond.png
+ 16x16/endline-none.png
+ 16x16/endline-simple.png
+ 16x16/endline-triangle.png
+ 16x16/export-csv.png
+ 16x16/flip.png
+ 16x16/folder-delete.png
+ 16x16/folder-edit.png
+ 16x16/folder-new.png
+ 16x16/folder-only-this.png
+ 16x16/folder-open.png
+ 16x16/folder-properties.png
+ 16x16/folder-show-all.png
+ 16x16/folder.png
+ 16x16/folio-delete.png
+ 16x16/folio-new.png
+ 16x16/folio-properties.png
+ 16x16/folio-ref-coming.png
+ 16x16/go-bottom.png
+ 16x16/go-company.png
+ 16x16/go-down-double.png
+ 16x16/go-down.png
+ 16x16/go-home.png
+ 16x16/go-top.png
+ 16x16/go-up-double.png
+ 16x16/go-up.png
+ 16x16/grid.png
+ 16x16/ground.png
+ 16x16/help-contents.png
+ 16x16/help-donate.png
+ 16x16/item-cancel.png
+ 16x16/item-copy.png
+ 16x16/item-move.png
+ 16x16/kdenlive-show-video.png
+ 16x16/label.png
+ 16x16/list-add.png
+ 16x16/list-remove.png
+ 16x16/masquer.png
+ 16x16/mirror.png
+ 16x16/move.png
+ 16x16/neutral.png
+ 16x16/north.png
+ 16x16/object-group.png
+ 16x16/object-rotate-right.png
+ 16x16/orientations.png
+ 16x16/phase.png
+ 16x16/preferences-desktop-user.png
+ 16x16/project-close.png
+ 16x16/project-delete.png
+ 16x16/project-new.png
+ 16x16/project-properties.png
+ 16x16/project.png
+ 16x16/qet.png
+ 16x16/qt.png
+ 16x16/run-dxf.png
+ 16x16/select.png
+ 16x16/south.png
+ 16x16/table-of-content.png
+ 16x16/terminal.png
+ 16x16/terminalstrip.png
+ 16x16/text-xml.png
+ 16x16/transform-rotate.png
+ 16x16/user-busy.png
+ 16x16/user-online.png
+ 16x16/view-fullscreen.png
+ 16x16/view-refresh.png
+ 16x16/view-restore.png
+ 16x16/west.png
+ 16x16/window-new.png
+ 16x16/zoom-draw.png
+ 16x16/zoom-fit-best.png
+ 16x16/zoom-in.png
+ 16x16/zoom-original.png
+ 16x16/zoom-out.png
+ 22x22/Actions-player-time-icon.png
+ 22x22/all_pages.png
+ 22x22/application-exit.png
+ 22x22/applications-development-translation.png
+ 22x22/arc.png
+ 22x22/arrow-left-double.png
+ 22x22/arrow-left.png
+ 22x22/arrow-right-double.png
+ 22x22/arrow-right.png
+ 22x22/autoconnect.png
+ 22x22/bring_forward.png
+ 22x22/conductor2.png
+ 22x22/conductor2.png
+ 22x22/configure-toolbars.png
+ 22x22/configure.png
+ 22x22/diagram.png
+ 22x22/diagram_add.png
+ 22x22/diagram_add.png
+ 22x22/diagram_bg.png
+ 22x22/diagram_del.png
+ 22x22/diagram_del.png
+ 22x22/dialog-cancel.png
+ 22x22/dialog-information.png
+ 22x22/dialog-information.png
+ 22x22/dialog-ok.png
+ 22x22/document-close.png
+ 22x22/document-export.png
+ 22x22/document-import.png
+ 22x22/document-new.png
+ 22x22/document-open-recent.png
+ 22x22/document-open.png
+ 22x22/document-print-frame.png
+ 22x22/document-print.png
+ 22x22/document-save-all.png
+ 22x22/document-save-as.png
+ 22x22/document-save.png
+ 22x22/edit-clear-locationbar-ltr.png
+ 22x22/edit-clear-locationbar-rtl.png
+ 22x22/edit-clear.png
+ 22x22/edit-copy.png
+ 22x22/edit-cut.png
+ 22x22/edit-delete.png
+ 22x22/edit-paste.png
+ 22x22/edit-redo.png
+ 22x22/edit-rename.png
+ 22x22/edit-select-all.png
+ 22x22/edit-table-cell-merge.png
+ 22x22/edit-table-cell-split.png
+ 22x22/edit-table-delete-column.png
+ 22x22/edit-table-delete-row.png
+ 22x22/edit-table-insert-column-left.png
+ 22x22/edit-table-insert-column-right.png
+ 22x22/edit-table-insert-row-above.png
+ 22x22/edit-table-insert-row-under.png
+ 22x22/edit-undo.png
+ 22x22/element-delete.png
+ 22x22/element-edit.png
+ 22x22/element-new.png
+ 22x22/ellipse.png
+ 22x22/export-csv.png
+ 22x22/folder-delete.png
+ 22x22/folder-edit.png
+ 22x22/folder-new.png
+ 22x22/folder-open.png
+ 22x22/format-text-subscript.png
+ 22x22/format-text-superscript.png
+ 22x22/go-company.png
+ 22x22/go-down.png
+ 22x22/go-home.png
+ 22x22/go-up.png
+ 22x22/grid.png
+ 22x22/guides.png
+ 22x22/hotspot.png
+ 22x22/insert-image.png
+ 22x22/label.png
+ 22x22/landscape.png
+ 22x22/line.png
+ 22x22/list-add.png
+ 22x22/list-remove.png
+ 22x22/lower.png
+ 22x22/move.png
+ 22x22/names.png
+ 22x22/object-locked.png
+ 22x22/object-rotate-right.png
+ 22x22/object-unlocked.png
+ 22x22/pdf-import.png
+ 22x22/polygon.png
+ 22x22/portrait.png
+ 22x22/preferences-desktop-user.png
+ 22x22/project-close.png
+ 22x22/project-delete.png
+ 22x22/project-new.png
+ 22x22/project.png
+ 22x22/raise.png
+ 22x22/rectangle.png
+ 22x22/restaurer.png
+ 22x22/select.png
+ 22x22/send_backward.png
+ 22x22/single_page.png
+ 22x22/start.png
+ 22x22/terminal.png
+ 22x22/terminalstrip.png
+ 22x22/text-xml.png
+ 22x22/text.png
+ 22x22/textfield.png
+ 22x22/titleblock-bottom.png
+ 22x22/titleblock-right.png
+ 22x22/transform-scale.png
+ 22x22/two_pages.png
+ 22x22/view-fit-window.png
+ 22x22/view-fullscreen.png
+ 22x22/view-refresh.png
+ 22x22/view-restore.png
+ 22x22/view_fit_width.png
+ 22x22/window-new.png
+ 22x22/zoom-draw.png
+ 22x22/zoom-fit-best.png
+ 22x22/zoom-in.png
+ 22x22/zoom-original.png
+ 22x22/zoom-out.png
+ 32x32/application-pdf.png
+ 32x32/format-text-bold.png
+ 32x32/format-text-color.png
+ 32x32/format-text-italic.png
+ 32x32/format-text-underline.png
+ 32x32/image-x-eps.png
+ 32x32/insert-link.png
+ 32x32/printer.png
+ 32x32/qt.png
+ 32x32/simplifyrichtext.png
+ 32x32/text-xml.png
+ 48x48/document-print-frame.png
+ 48x48/user-away-extended.png
+ 48x48/user-away.png
+ 48x48/view-pim-journal.png
+ 128x128/diagram.png
+ 128x128/document-export.png
+ 128x128/plasmagik.png
+ 128x128/printer.png
+ 128x128/project.png
+ 128x128/settings.png
+ breeze-icons/scalable/apps/hidef/edit-opacity.svg
+ breeze-icons/scalable/apps/hidef/image-flip-horizontal-symbolic.svg
+ breeze-icons/scalable/apps/hidef/image-flip-vertical-symbolic.svg
+ breeze-icons/scalable/apps/hidef/draw-bezier-curves.svg
+ breeze-icons/scalable/apps/hidef/transform-crop.svg
+ generated/ellipse-to-bezier.svg
+ generated/rect-to-bezier.svg
+ generated/rect-to-polyline.svg
+
+
diff --git a/ico/themes/qet/index.theme b/ico/themes/qet/index.theme
new file mode 100644
index 000000000..74c1b904b
--- /dev/null
+++ b/ico/themes/qet/index.theme
@@ -0,0 +1,30 @@
+[Icon Theme]
+Name=qet
+Comment=QElectroTech icons
+Directories=16x16,22x22,32x32,48x48,128x128,scalable
+
+[16x16]
+Size=16
+Type=Fixed
+
+[22x22]
+Size=22
+Type=Fixed
+
+[32x32]
+Size=32
+Type=Fixed
+
+[48x48]
+Size=48
+Type=Fixed
+
+[128x128]
+Size=128
+Type=Fixed
+
+[scalable]
+Size=22
+Type=Scalable
+MinSize=8
+MaxSize=256
diff --git a/misc/make_icon_themes.py b/misc/make_icon_themes.py
new file mode 100644
index 000000000..864798b1a
--- /dev/null
+++ b/misc/make_icon_themes.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# Copyright 2006-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.
+#
+# QElectroTech is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with QElectroTech. If not, see .
+"""Build QET's icon theme "qet" from the PNG and SVG sources in ico/.
+
+Run from the repository root:
+
+ python3 misc/make_icon_themes.py
+
+It writes:
+
+ ico/themes/qet/index.theme the theme description
+ ico/icon-themes.qrc resource file listing the theme
+
+The theme does not copy any file. The .qrc aliases the existing
+ico//.png files into the theme layout Qt's icon loader
+expects (themes/qet//.png), so QIcon::fromTheme("name")
+finds them. Idempotent: running it twice changes nothing.
+"""
+
+import os
+import re
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parent.parent
+ICO = ROOT / "ico"
+THEMES = ICO / "themes"
+QRC = ICO / "icon-themes.qrc"
+
+# Fixed-size folders that hold toolbar, menu and dialog icons. The 24x16
+# flags, the 22x22/color swatches and the application icons are not theme
+# icons and stay on their resource paths.
+SIZES = ["16x16", "22x22", "32x32", "48x48", "128x128"]
+
+# Table entries in sources/qeticons.cpp that pair a 16 pixel file with a
+# 22 pixel file of another name. The theme needs one name per icon, so
+# the 22 pixel file is exposed under the 16 pixel name as well.
+ALIASES = {
+ "22x22/conductor2.png": "conductor-reset",
+ "22x22/diagram_add.png": "folio-new",
+ "22x22/diagram_del.png": "folio-delete",
+ "22x22/dialog-information.png": "folio-properties",
+}
+
+# SVG icons referenced from sources/qeticons.cpp.
+SVGS = [
+ "breeze-icons/scalable/apps/hidef/edit-opacity.svg",
+ "breeze-icons/scalable/apps/hidef/image-flip-horizontal-symbolic.svg",
+ "breeze-icons/scalable/apps/hidef/image-flip-vertical-symbolic.svg",
+ "breeze-icons/scalable/apps/hidef/draw-bezier-curves.svg",
+ "breeze-icons/scalable/apps/hidef/transform-crop.svg",
+ "generated/ellipse-to-bezier.svg",
+ "generated/rect-to-bezier.svg",
+ "generated/rect-to-polyline.svg",
+]
+
+
+def write_if_changed(path, data):
+ """Write text only when the content differs, so git stays quiet."""
+ if path.exists() and path.read_text(encoding="utf-8") == data:
+ return False
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(data, encoding="utf-8")
+ return True
+
+
+def index_theme(name, comment, dirs, inherits=None):
+ lines = ["[Icon Theme]", f"Name={name}", f"Comment={comment}"]
+ if inherits:
+ lines.append(f"Inherits={inherits}")
+ lines.append("Directories=" + ",".join(dirs))
+ lines.append("")
+ for d in dirs:
+ lines.append(f"[{d}]")
+ if d == "scalable":
+ lines += ["Size=22", "Type=Scalable", "MinSize=8", "MaxSize=256"]
+ else:
+ lines += [f"Size={d.split('x')[0]}", "Type=Fixed"]
+ lines.append("")
+ return "\n".join(lines)
+
+
+def main():
+ entries = [] # (alias, source) pairs, paths relative to ico/
+ changed = 0
+
+ for size in SIZES:
+ for png in sorted((ICO / size).glob("*.png")):
+ rel = f"{size}/{png.name}"
+ names = [png.stem]
+ if rel in ALIASES:
+ names.append(ALIASES[rel])
+ for name in names:
+ entries.append((f"themes/qet/{size}/{name}.png", rel))
+
+ for rel in SVGS:
+ name = re.sub(r"-symbolic(?=\.svg$)", "", Path(rel).name)
+ entries.append((f"themes/qet/scalable/{name}", rel))
+
+ dirs = SIZES + ["scalable"]
+ changed += write_if_changed(THEMES / "qet" / "index.theme",
+ index_theme("qet", "QElectroTech icons", dirs))
+
+ qrc = ["", "",
+ '', ' ',
+ " themes/qet/index.theme"]
+ for alias, source in entries:
+ qrc.append(f' {source}')
+ qrc += [" ", "", ""]
+ changed += write_if_changed(QRC, "\n".join(qrc))
+
+ print(f"{len(entries)} theme entries; {changed} files written")
+
+
+if __name__ == "__main__":
+ os.chdir(ROOT)
+ main()
diff --git a/sources/ElementsCollection/fileelementcollectionitem.cpp b/sources/ElementsCollection/fileelementcollectionitem.cpp
index 15a6cdb83..2183507ab 100644
--- a/sources/ElementsCollection/fileelementcollectionitem.cpp
+++ b/sources/ElementsCollection/fileelementcollectionitem.cpp
@@ -456,13 +456,13 @@ void FileElementCollectionItem::setUpIcon()
if (macrosPath.endsWith("/")) macrosPath.remove(macrosPath.length() - 1, 1);
if (m_path == QETApp::commonElementsDirN())
- setIcon(QIcon(":/ico/16x16/qet.png"));
+ setIcon(QIcon::fromTheme("qet"));
else if (m_path == QETApp::companyElementsDirN())
- setIcon(QIcon(":/ico/16x16/go-company.png"));
+ setIcon(QIcon::fromTheme("go-company"));
else if (m_path == macrosPath)
- setIcon(QIcon(":/ico/16x16/go-home.png"));
+ setIcon(QIcon::fromTheme("go-home"));
else
- setIcon(QIcon(":/ico/16x16/go-home.png"));
+ setIcon(QIcon::fromTheme("go-home"));
}
else
{
diff --git a/sources/NameList/ui/namelistwidget.ui b/sources/NameList/ui/namelistwidget.ui
index f021a77a3..a38dd046d 100644
--- a/sources/NameList/ui/namelistwidget.ui
+++ b/sources/NameList/ui/namelistwidget.ui
@@ -36,7 +36,7 @@
Ajouter une ligne
-
+
:/ico/16x16/list-add.png:/ico/16x16/list-add.png
@@ -48,7 +48,7 @@
Copier dans le presse papier
-
+
:/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png
diff --git a/sources/SearchAndReplace/ui/replaceconductordialog.ui b/sources/SearchAndReplace/ui/replaceconductordialog.ui
index 4be6a94d3..f5cefc78c 100644
--- a/sources/SearchAndReplace/ui/replaceconductordialog.ui
+++ b/sources/SearchAndReplace/ui/replaceconductordialog.ui
@@ -370,7 +370,7 @@
phase
-
+
:/ico/16x16/phase.png:/ico/16x16/phase.png
@@ -397,7 +397,7 @@
neutre
-
+
:/ico/16x16/neutral.png:/ico/16x16/neutral.png
@@ -433,7 +433,7 @@
terre
-
+
:/ico/16x16/ground.png:/ico/16x16/ground.png
diff --git a/sources/SearchAndReplace/ui/replacefoliowidget.ui b/sources/SearchAndReplace/ui/replacefoliowidget.ui
index b5ee7e0df..b438180b9 100644
--- a/sources/SearchAndReplace/ui/replacefoliowidget.ui
+++ b/sources/SearchAndReplace/ui/replacefoliowidget.ui
@@ -180,7 +180,7 @@
-
+
:/ico/22x22/start.png:/ico/22x22/start.png
diff --git a/sources/SearchAndReplace/ui/searchandreplacewidget.ui b/sources/SearchAndReplace/ui/searchandreplacewidget.ui
index fcc280960..597e1f439 100644
--- a/sources/SearchAndReplace/ui/searchandreplacewidget.ui
+++ b/sources/SearchAndReplace/ui/searchandreplacewidget.ui
@@ -106,7 +106,7 @@
-
+
:/ico/16x16/go-bottom.png:/ico/16x16/go-bottom.png
@@ -123,7 +123,7 @@
-
+
:/ico/16x16/go-top.png:/ico/16x16/go-top.png
@@ -140,7 +140,7 @@
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
@@ -157,7 +157,7 @@
-
+
:/ico/16x16/configure-toolbars.png:/ico/16x16/configure-toolbars.png
diff --git a/sources/TerminalStrip/ui/freeterminaleditor.ui b/sources/TerminalStrip/ui/freeterminaleditor.ui
index f464b3e1d..4f318c60e 100644
--- a/sources/TerminalStrip/ui/freeterminaleditor.ui
+++ b/sources/TerminalStrip/ui/freeterminaleditor.ui
@@ -84,7 +84,7 @@
-
+
:/ico/22x22/dialog-ok.png:/ico/22x22/dialog-ok.png
diff --git a/sources/TerminalStrip/ui/terminalstripeditor.ui b/sources/TerminalStrip/ui/terminalstripeditor.ui
index 29f6854e3..ef65cdf9c 100644
--- a/sources/TerminalStrip/ui/terminalstripeditor.ui
+++ b/sources/TerminalStrip/ui/terminalstripeditor.ui
@@ -63,7 +63,7 @@
-
+
:/ico/16x16/dialog-ok.png:/ico/16x16/dialog-ok.png
diff --git a/sources/TerminalStrip/ui/terminalstripeditorwindow.ui b/sources/TerminalStrip/ui/terminalstripeditorwindow.ui
index f390f33cf..53b413b3b 100644
--- a/sources/TerminalStrip/ui/terminalstripeditorwindow.ui
+++ b/sources/TerminalStrip/ui/terminalstripeditorwindow.ui
@@ -54,7 +54,7 @@
-
+
:/ico/16x16/list-add.png:/ico/16x16/list-add.png
@@ -66,7 +66,7 @@
-
+
:/ico/16x16/list-remove.png:/ico/16x16/list-remove.png
@@ -78,7 +78,7 @@
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
diff --git a/sources/autoNum/ui/autonumberingdockwidget.ui b/sources/autoNum/ui/autonumberingdockwidget.ui
index 4fcd61901..b0bcc6e61 100644
--- a/sources/autoNum/ui/autonumberingdockwidget.ui
+++ b/sources/autoNum/ui/autonumberingdockwidget.ui
@@ -73,7 +73,7 @@
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
@@ -161,7 +161,7 @@
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
@@ -238,7 +238,7 @@
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
@@ -319,7 +319,7 @@
Configurer
-
+
:/ico/16x16/configure.png:/ico/16x16/configure.png
diff --git a/sources/autoNum/ui/selectautonumw.ui b/sources/autoNum/ui/selectautonumw.ui
index 3c4d953af..8da8d2e70 100644
--- a/sources/autoNum/ui/selectautonumw.ui
+++ b/sources/autoNum/ui/selectautonumw.ui
@@ -63,7 +63,7 @@
-
+
:/ico/16x16/edit-delete.png:/ico/16x16/edit-delete.png
@@ -136,7 +136,7 @@
-
+
:/ico/22x22/list-remove.png:/ico/22x22/list-remove.png
@@ -153,7 +153,7 @@
-
+
:/ico/22x22/list-add.png:/ico/22x22/list-add.png
@@ -170,7 +170,7 @@
-
+
:/ico/16x16/arrow-left.png:/ico/16x16/arrow-left.png
@@ -184,7 +184,7 @@
-
+
:/ico/16x16/arrow-right.png:/ico/16x16/arrow-right.png
diff --git a/sources/dataBase/projectdatabase.cpp b/sources/dataBase/projectdatabase.cpp
index bd0f0069d..20d2c150d 100644
--- a/sources/dataBase/projectdatabase.cpp
+++ b/sources/dataBase/projectdatabase.cpp
@@ -28,6 +28,7 @@
#include "../qetproject.h"
#include
+#include
#include
#include
@@ -132,11 +133,88 @@ QETProject *projectDataBase::project() const
}
/**
- @brief projectDataBase::newQuery
- @return a QSqlquery with query as query
- and the internal database of this class as database to use.
+ @brief projectDataBase::isReadOnlySelect
+ Every query that reaches newQuery() goes through this check first --
+ including one loaded from a saved nomenclature/summary table's
+ element (ProjectDBModel::fromXml()), which makes this a defense against
+ a crafted project file, not just a careless custom-SQL edit
+ (qelectrotech-source-mirror#886 asked for read-only enforcement on the
+ custom SQL reports feature; this covers every path into newQuery(), not
+ just that one dialog).
+
+ Deliberately simple rather than a real SQL parser: reject more than one
+ statement (blocks stacking a write after a leading SELECT with `;`), and
+ require the query to start with SELECT or WITH. A determined attacker
+ with arbitrary SQL access to a local SQLite connection can still find
+ tricks a simple prefix check won't catch; this is meant to stop the
+ ordinary mistake and the obvious payload, not to be a security boundary
+ against a hostile file assumed to already run in some other trust
+ context.
+ @param query the raw SQL text to check
+ @param error set to a human-readable reason when this returns false
+ @return true if @p query looks like a single read-only SELECT/WITH
*/
-QSqlQuery projectDataBase::newQuery(const QString &query) {
+bool projectDataBase::isReadOnlySelect(const QString &query, QString *error)
+{
+ if (error) {
+ error->clear();
+ }
+
+ QString trimmed = query.trimmed();
+ if (trimmed.endsWith(QLatin1Char(';'))) {
+ trimmed.chop(1);
+ trimmed = trimmed.trimmed();
+ }
+
+ if (trimmed.isEmpty()) {
+ if (error) {
+ *error = projectDataBase::tr("La requête est vide.");
+ }
+ return false;
+ }
+
+ if (trimmed.contains(QLatin1Char(';'))) {
+ if (error) {
+ *error = projectDataBase::tr("Une seule requête SELECT est autorisée"
+ " (le caractère ';' ne peut apparaître"
+ " qu'à la toute fin).");
+ }
+ return false;
+ }
+
+ const int first_space = trimmed.indexOf(QRegularExpression(QStringLiteral("\\s")));
+ const QString first_word = (first_space == -1 ? trimmed : trimmed.left(first_space)).toUpper();
+ if (first_word != QLatin1String("SELECT") && first_word != QLatin1String("WITH")) {
+ if (error) {
+ *error = projectDataBase::tr("Seules les requêtes en lecture seule"
+ " (SELECT ou WITH ... SELECT) sont"
+ " autorisées.");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ @brief projectDataBase::newQuery
+ @param query the SQL text to run -- must be a single read-only
+ SELECT/WITH statement, see isReadOnlySelect()
+ @param error set to a human-readable reason when the query was rejected
+ before ever reaching the database
+ @return a QSqlQuery with query as query and the internal database of
+ this class as database to use, or an unexecuted, harmless QSqlQuery if
+ the query was rejected
+*/
+QSqlQuery projectDataBase::newQuery(const QString &query, QString *error) {
+ QString reason;
+ if (!isReadOnlySelect(query, &reason)) {
+ qWarning().noquote() << "projectDataBase::newQuery: rejected query:" << reason << "--" << query;
+ if (error) {
+ *error = reason;
+ }
+ return QSqlQuery(m_data_base);
+ }
return QSqlQuery(query, m_data_base);
}
diff --git a/sources/dataBase/projectdatabase.h b/sources/dataBase/projectdatabase.h
index 2ce9266bb..abd5e966c 100644
--- a/sources/dataBase/projectdatabase.h
+++ b/sources/dataBase/projectdatabase.h
@@ -59,7 +59,8 @@ class projectDataBase : public QObject
*/
void setUpdateBlocked(bool blocked);
QETProject *project() const;
- QSqlQuery newQuery(const QString &query = QString());
+ QSqlQuery newQuery(const QString &query = QString(), QString *error = nullptr);
+ static bool isReadOnlySelect(const QString &query, QString *error = nullptr);
QSqlDatabase database() const {return m_data_base;}
int excludedConductorCount() const;
diff --git a/sources/dataBase/ui/elementquerywidget.cpp b/sources/dataBase/ui/elementquerywidget.cpp
index aafdeb32d..f5a42beb7 100644
--- a/sources/dataBase/ui/elementquerywidget.cpp
+++ b/sources/dataBase/ui/elementquerywidget.cpp
@@ -20,8 +20,15 @@
#include "../../properties/elementdata.h"
#include "../../qetapp.h"
#include "../../qetinformation.h"
+#include "../projectdatabase.h"
#include "ui_elementquerywidget.h"
+#include
+#include
+#include
+#include
+#include
+
#include
/**
@@ -94,6 +101,9 @@ ElementQueryWidget::ElementQueryWidget(QWidget *parent) :
setUpItems();
fillSavedQuery();
+
+ connect(ui->m_sql_query, &QLineEdit::textChanged, this, &ElementQueryWidget::checkQueryValidity);
+ checkQueryValidity();
}
/**
@@ -599,6 +609,8 @@ void ElementQueryWidget::on_m_edit_sql_query_cb_clicked()
m_custom_query = ui->m_sql_query->text();
updateQueryLine();
}
+
+ checkQueryValidity();
}
/**
@@ -672,6 +684,10 @@ void ElementQueryWidget::on_m_load_pb_clicked()
*/
void ElementQueryWidget::on_m_save_current_conf_pb_clicked()
{
+ if (!projectDataBase::isReadOnlySelect(queryStr())) {
+ return;
+ }
+
QFile file_(QETApp::configDir() % "/nomenclature.json");
if (file_.open(QFile::ReadWrite))
@@ -698,7 +714,147 @@ void ElementQueryWidget::on_m_save_current_conf_pb_clicked()
}
void ElementQueryWidget::on_m_save_name_le_textChanged(const QString &arg1) {
- ui->m_save_current_conf_pb->setDisabled(arg1.isEmpty());
+ Q_UNUSED(arg1)
+ checkQueryValidity();
+}
+
+/**
+ @brief ElementQueryWidget::checkQueryValidity
+ Live feedback for the custom-SQL box: only the free-text path can carry
+ anything other than a SELECT (the column/filter builder always produces
+ one), so this only actually restricts something once "Requête SQL
+ personnalisée" is checked. Same rule projectDataBase::isReadOnlySelect()
+ enforces at execution time -- this just tells the user *before* they hit
+ Preview/Export/OK instead of after (qelectrotech-source-mirror#886).
+*/
+void ElementQueryWidget::checkQueryValidity()
+{
+ if (!ui->m_edit_sql_query_cb->isChecked()) {
+ ui->m_query_warning_label->clear();
+ ui->m_save_current_conf_pb->setEnabled(!ui->m_save_name_le->text().isEmpty());
+ return;
+ }
+
+ QString reason;
+ const bool valid = projectDataBase::isReadOnlySelect(ui->m_sql_query->text(), &reason);
+ ui->m_query_warning_label->setText(valid ? QString() : reason);
+ ui->m_save_current_conf_pb->setEnabled(valid && !ui->m_save_name_le->text().isEmpty());
+}
+
+/**
+ @brief ElementQueryWidget::on_m_export_reports_pb_clicked
+ Write every saved report in nomenclature.json to a file the user picks,
+ so it can be handed to a colleague or another install
+ (qelectrotech-source-mirror#886's "import and export report definitions
+ for sharing between users or company installations").
+*/
+void ElementQueryWidget::on_m_export_reports_pb_clicked()
+{
+ QFile source(QETApp::configDir() % "/nomenclature.json");
+ if (!source.open(QFile::ReadOnly)) {
+ QMessageBox::information(this, tr("Exporter"), tr("Aucun rapport enregistré à exporter."));
+ return;
+ }
+ const auto content = source.readAll();
+ source.close();
+
+ if (QJsonDocument::fromJson(content).object().isEmpty()) {
+ QMessageBox::information(this, tr("Exporter"), tr("Aucun rapport enregistré à exporter."));
+ return;
+ }
+
+ const QString file_path = QFileDialog::getSaveFileName(
+ this, tr("Exporter les rapports"), QStringLiteral("rapports_qet.json"),
+ tr("Fichiers JSON (*.json)"));
+ if (file_path.isEmpty()) {
+ return;
+ }
+
+ QFile dest(file_path);
+ if (!dest.open(QFile::WriteOnly) || dest.write(content) == -1) {
+ QMessageBox::critical(this, tr("Erreur"), tr("Impossible d'écrire dans %1.").arg(file_path));
+ }
+}
+
+/**
+ @brief ElementQueryWidget::on_m_import_reports_pb_clicked
+ Merge a previously-exported reports file into this install's
+ nomenclature.json. A name already used locally is not overwritten
+ silently -- the user is asked, per report, whether to replace it.
+*/
+void ElementQueryWidget::on_m_import_reports_pb_clicked()
+{
+ const QString file_path = QFileDialog::getOpenFileName(
+ this, tr("Importer des rapports"), QString(), tr("Fichiers JSON (*.json)"));
+ if (file_path.isEmpty()) {
+ return;
+ }
+
+ QFile source(file_path);
+ if (!source.open(QFile::ReadOnly)) {
+ QMessageBox::critical(this, tr("Erreur"), tr("Impossible de lire %1.").arg(file_path));
+ return;
+ }
+
+ QJsonParseError parse_error;
+ const auto incoming_doc = QJsonDocument::fromJson(source.readAll(), &parse_error);
+ source.close();
+
+ if (parse_error.error != QJsonParseError::NoError || !incoming_doc.isObject()) {
+ QMessageBox::critical(
+ this, tr("Erreur"),
+ tr("%1 ne contient pas des rapports QElectroTech valides.").arg(file_path));
+ return;
+ }
+
+ const auto incoming = incoming_doc.object();
+ if (incoming.isEmpty()) {
+ QMessageBox::information(this, tr("Importer"), tr("Ce fichier ne contient aucun rapport."));
+ return;
+ }
+
+ QFile dest_file(QETApp::configDir() % "/nomenclature.json");
+ QJsonObject existing;
+ if (dest_file.open(QFile::ReadOnly)) {
+ existing = QJsonDocument::fromJson(dest_file.readAll()).object();
+ dest_file.close();
+ }
+
+ int imported = 0, skipped = 0;
+ for (auto it = incoming.begin(); it != incoming.end(); ++it)
+ {
+ if (existing.contains(it.key()))
+ {
+ const auto answer = QMessageBox::question(
+ this, tr("Rapport déjà existant"),
+ tr("Un rapport nommé « %1 » existe déjà. Le remplacer ?").arg(it.key()),
+ QMessageBox::Yes | QMessageBox::No);
+ if (answer != QMessageBox::Yes) {
+ ++skipped;
+ continue;
+ }
+ }
+ existing[it.key()] = it.value();
+ ++imported;
+ }
+
+ if (dest_file.open(QFile::WriteOnly | QFile::Truncate))
+ {
+ dest_file.write(QJsonDocument(existing).toJson());
+ dest_file.close();
+ }
+ else
+ {
+ QMessageBox::critical(this, tr("Erreur"), tr("Impossible d'écrire la configuration locale."));
+ return;
+ }
+
+ ui->m_conf_cb->clear();
+ fillSavedQuery();
+
+ QMessageBox::information(
+ this, tr("Importer"),
+ tr("%1 rapport(s) importé(s), %2 ignoré(s).").arg(imported).arg(skipped));
}
void ElementQueryWidget::on_m_choosen_list_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
diff --git a/sources/dataBase/ui/elementquerywidget.h b/sources/dataBase/ui/elementquerywidget.h
index b44377e12..f89883793 100644
--- a/sources/dataBase/ui/elementquerywidget.h
+++ b/sources/dataBase/ui/elementquerywidget.h
@@ -59,6 +59,9 @@ class ElementQueryWidget : public QWidget
void on_m_load_pb_clicked();
void on_m_save_current_conf_pb_clicked();
void on_m_save_name_le_textChanged(const QString &arg1);
+ void on_m_import_reports_pb_clicked();
+ void on_m_export_reports_pb_clicked();
+ void checkQueryValidity();
void on_m_choosen_list_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void on_m_var_list_itemDoubleClicked(QListWidgetItem *item);
void on_m_choosen_list_itemDoubleClicked(QListWidgetItem *item);
diff --git a/sources/dataBase/ui/elementquerywidget.ui b/sources/dataBase/ui/elementquerywidget.ui
index 7f3ae30fb..8300b2387 100644
--- a/sources/dataBase/ui/elementquerywidget.ui
+++ b/sources/dataBase/ui/elementquerywidget.ui
@@ -88,7 +88,7 @@
-
+
:/ico/16x16/go-up.png:/ico/16x16/go-up.png
@@ -105,7 +105,7 @@
-
+
:/ico/16x16/list-add.png:/ico/16x16/list-add.png
@@ -119,7 +119,7 @@
-
+
:/ico/16x16/list-remove.png:/ico/16x16/list-remove.png
@@ -133,7 +133,7 @@
-
+
:/ico/16x16/go-down.png:/ico/16x16/go-down.png
@@ -353,7 +353,7 @@
-
+
:/ico/16x16/folder-open.png:/ico/16x16/folder-open.png
@@ -380,7 +380,7 @@
-
+
:/ico/16x16/document-save.png:/ico/16x16/document-save.png
@@ -388,6 +388,26 @@
+ -
+
+
+ Importer des rapports depuis un fichier
+
+
+ Importer...
+
+
+
+ -
+
+
+ Exporter tous les rapports enregistrés vers un fichier
+
+
+ Exporter...
+
+
+
@@ -429,6 +449,19 @@
+ -
+
+
+ color: red;
+
+
+
+
+
+ true
+
+
+
diff --git a/sources/dataBase/ui/summaryquerywidget.ui b/sources/dataBase/ui/summaryquerywidget.ui
index d6eb50e10..de98cd343 100644
--- a/sources/dataBase/ui/summaryquerywidget.ui
+++ b/sources/dataBase/ui/summaryquerywidget.ui
@@ -76,7 +76,7 @@
-
+
:/ico/16x16/go-up.png:/ico/16x16/go-up.png
@@ -87,7 +87,7 @@
-
+
:/ico/16x16/list-add.png:/ico/16x16/list-add.png
@@ -98,7 +98,7 @@
-
+
:/ico/16x16/list-remove.png:/ico/16x16/list-remove.png
@@ -109,7 +109,7 @@
-
+
:/ico/16x16/go-down.png:/ico/16x16/go-down.png
diff --git a/sources/diagram.cpp b/sources/diagram.cpp
index 591f2b885..aa8e92399 100644
--- a/sources/diagram.cpp
+++ b/sources/diagram.cpp
@@ -801,6 +801,11 @@ void Diagram::clearEventInterface()
}
}
+bool Diagram::eventInterfaceIsRunning() const
+{
+ return m_event_interface && m_event_interface->isRunning();
+}
+
/**
@brief Diagram::conductorsAutonumName
@return the name of autonum to use.
diff --git a/sources/diagram.h b/sources/diagram.h
index d2e0f0e12..824b6dc38 100644
--- a/sources/diagram.h
+++ b/sources/diagram.h
@@ -216,6 +216,7 @@ class Diagram : public QGraphicsScene
// methods related to graphics items addition/removal on the diagram
virtual void addItem (QGraphicsItem *item);
virtual void removeItem (QGraphicsItem *item);
+ bool eventInterfaceIsRunning() const;
// methods related to graphics options
ExportProperties applyProperties(const ExportProperties &);
diff --git a/sources/diagramcommands.cpp b/sources/diagramcommands.cpp
index 3bf1be437..8c19636f6 100644
--- a/sources/diagramcommands.cpp
+++ b/sources/diagramcommands.cpp
@@ -19,6 +19,7 @@
#include "diagram.h"
#include "qetgraphicsitem/conductortextitem.h"
+#include "qetgraphicsitem/dynamicelementtextitem.h"
#include "qetgraphicsitem/element.h"
#include "qetgraphicsitem/elementtextitemgroup.h"
#include "qetinformation.h"
@@ -90,6 +91,62 @@ void PasteDiagramCommand::redo()
//make new uuid, because old uuid are the uuid of the copied element
e -> newUuid();
+ // PLC slaves carry master-specific data (type, address,
+ // function, cross-ref, etc.) in their elementInformations.
+ // Always clear those on paste so the duplicate starts clean,
+ // regardless of the user's erase-label-on-copy preference.
+ const bool is_slave = (e->linkType() == Element::Slave);
+ if (is_slave) {
+ DiagramContext dc = e->elementInformations();
+ dc.remove(QETInformation::ELMT_PLC_TYPE);
+ dc.remove(QETInformation::ELMT_PLC_ADDRESS);
+ dc.remove(QETInformation::ELMT_PLC_FUNCTION);
+ dc.remove(QETInformation::ELMT_PLC_COMMENT);
+ dc.remove(QETInformation::ELMT_PLC_CROSSREF);
+ dc.remove(QETInformation::ELMT_LABEL);
+ dc.remove(QETInformation::ELMT_PLC_TC);
+ dc.remove(QETInformation::ELMT_PLC_T1);
+ dc.remove(QETInformation::ELMT_PLC_T2);
+ dc.remove(QETInformation::ELMT_PLC_T3);
+ dc.remove(QETInformation::ELMT_PLC_T4);
+ dc.remove(QStringLiteral("xref"));
+
+ // Block alignment before setElementInformations so
+ // that elementInfoChanged() resolves texts without
+ // finishAlignment() shifting right/center-aligned items.
+ for (DynamicElementTextItem *deti : e->dynamicTextItems())
+ deti->m_block_alignment = true;
+ for (auto *group : e->textGroups())
+ group->blockAlignmentUpdate(true);
+
+ e->setElementInformations(dc);
+
+ for (DynamicElementTextItem *deti : e->dynamicTextItems())
+ deti->m_block_alignment = false;
+ for (auto *group : e->textGroups())
+ group->blockAlignmentUpdate(false);
+
+ // After setElementInformations, elementInfoChanged()
+ // resolves composite text with cleaned dc. Clear
+ // all non-UserText items directly as a safety net.
+ for (DynamicElementTextItem *deti : e->dynamicTextItems()) {
+ if (deti->textFrom() != DynamicElementTextItem::UserText) {
+ deti->m_block_alignment = true;
+ deti->setPlainText(QString());
+ deti->m_block_alignment = false;
+ }
+ }
+ for (auto *group : e->textGroups()) {
+ for (DynamicElementTextItem *deti : group->texts()) {
+ if (deti->textFrom() != DynamicElementTextItem::UserText) {
+ deti->m_block_alignment = true;
+ deti->setPlainText(QString());
+ deti->m_block_alignment = false;
+ }
+ }
+ }
+ }
+
if (settings.value("diagramcommands/erase-label-on-copy", true).toBool())
{
//Reset the information about the label, the comment and location
@@ -99,27 +156,21 @@ void PasteDiagramCommand::redo()
dc.addValue("comment", "");
dc.addValue("location", "");
- // PLC slaves store master data (type, address, comment,
- // cross-ref, etc.) in their own elementInformations.
- // Remove them the same way MasterElement::unlinkElement()
- // does, so pasted PLC slaves start clean like regular
- // slaves.
- if (e->linkType() == Element::Slave) {
- dc.remove(QETInformation::ELMT_PLC_TYPE);
- dc.remove(QETInformation::ELMT_PLC_ADDRESS);
- dc.remove(QETInformation::ELMT_PLC_FUNCTION);
- dc.remove(QETInformation::ELMT_PLC_COMMENT);
- dc.remove(QETInformation::ELMT_PLC_CROSSREF);
- dc.remove(QETInformation::ELMT_LABEL);
- dc.remove(QETInformation::ELMT_PLC_TC);
- dc.remove(QETInformation::ELMT_PLC_T1);
- dc.remove(QETInformation::ELMT_PLC_T2);
- dc.remove(QETInformation::ELMT_PLC_T3);
- dc.remove(QETInformation::ELMT_PLC_T4);
- dc.remove(QStringLiteral("xref"));
+ // Block alignment during setElementInformations
+ // for non-slaves, same as Element::fromXml() (line 890-896).
+ if (!is_slave) {
+ for (DynamicElementTextItem *deti : e->dynamicTextItems())
+ deti->m_block_alignment = true;
+ for (auto *group : e->textGroups())
+ group->blockAlignmentUpdate(true);
}
e->setElementInformations(dc);
+
+ for (DynamicElementTextItem *deti : e->dynamicTextItems())
+ deti->m_block_alignment = false;
+ for (auto *group : e->textGroups())
+ group->blockAlignmentUpdate(false);
//Reset the text of conductors, the same way the label/comment/
//location above are reset to "" rather than to some other
diff --git a/sources/diagramevent/diagrameventaddpaste.cpp b/sources/diagramevent/diagrameventaddpaste.cpp
index b08406b68..ac29b522a 100644
--- a/sources/diagramevent/diagrameventaddpaste.cpp
+++ b/sources/diagramevent/diagrameventaddpaste.cpp
@@ -23,6 +23,8 @@
#include "../qetdiagrameditor.h"
#include "../qetgraphicsitem/conductor.h"
+#include
+
#include
#include
#include
@@ -35,7 +37,7 @@
@param start_pos : where the pasted items first appear, in scene
coordinates -- normally the cursor
*/
-DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &start_pos) :
+ DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &start_pos) :
DiagramEventInterface(diagram)
{
//DiagramEventInterface::init() is called by Diagram::setEventInterface
@@ -49,20 +51,45 @@ DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &star
QDomDocument document_xml;
if (!document_xml.setContent(clipboard_text)) return;
- m_diagram->fromXml(document_xml, Diagram::snapToGrid(start_pos), false, &m_content);
+ //Load items at their original XML coordinates.
+ m_diagram->fromXml(document_xml, QPointF(), false, &m_content);
if (!m_content.count()) return;
- //Remember where each item sits relative to the group's top left, so a
- //move is one assignment per item rather than an accumulated delta.
- QRectF group_rect;
const QList movable = m_content.items(MovableItems);
+ if (movable.isEmpty()) return;
+
+ //Compute the top-left of all items' positions (not bounding
+ //rects) and snap to grid — used only for the initial cursor
+ //warp. Items stay at their original XML positions;
+ //moveTo() handles grid-snapped movement via deltas.
+ QPointF top_left;
+ bool first = true;
for (auto *item : movable) {
- group_rect = group_rect.united(item->mapToScene(item->boundingRect()).boundingRect());
+ const QPointF p = item->pos();
+ if (first) {
+ top_left = p;
+ first = false;
+ } else {
+ if (p.x() < top_left.x()) top_left.setX(p.x());
+ if (p.y() < top_left.y()) top_left.setY(p.y());
+ }
}
- const QPointF top_left = group_rect.topLeft();
+ QSettings settings;
+ const int xGrid = settings.value(QStringLiteral("diagrameditor/Xgrid"),
+ Diagram::xGrid).toInt();
+ const int yGrid = settings.value(QStringLiteral("diagrameditor/Ygrid"),
+ Diagram::yGrid).toInt();
+ const QPointF grid_origin(
+ qRound(top_left.x() / xGrid) * xGrid,
+ qRound(top_left.y() / yGrid) * yGrid);
+
+ //Store each item's position. moveTo() applies a grid-snapped
+ //delta from the baseline, so items preserve their layout and
+ //move in whole grid steps.
for (auto *item : movable) {
- m_relative_pos.insert(item, item->pos() - top_left);
+ m_relative_pos.insert(item, item->pos());
}
+ m_group_origin = grid_origin;
m_diagram->clearSelection();
for (auto *item : movable) {
@@ -70,8 +97,15 @@ DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &star
}
if (!m_diagram->views().isEmpty()) {
- if (const auto qde = QETApp::diagramEditorAncestorOf(m_diagram->views().at(0))) {
- m_status_bar = qde->statusBar();
+ if (auto *view = m_diagram->views().at(0)) {
+ if (const auto qde = QETApp::diagramEditorAncestorOf(view)) {
+ m_status_bar = qde->statusBar();
+ }
+ //Warp the cursor close to the group origin so the
+ //first mouseMoveEvent captures the correct baseline.
+ const QPoint view_pos = view->mapFromScene(m_group_origin);
+ const QPoint global_pos = view->viewport()->mapToGlobal(view_pos);
+ QCursor::setPos(global_pos);
}
}
showHint();
@@ -88,7 +122,9 @@ DiagramEventAddPaste::DiagramEventAddPaste(Diagram *diagram, const QPointF &star
DiagramEventAddPaste::~DiagramEventAddPaste()
{
if (!m_finished && m_diagram) {
- cancel();
+ removeItems();
+ m_finished = true;
+ m_running = false;
}
if (m_status_bar) {
m_status_bar->clearMessage();
@@ -129,16 +165,49 @@ void DiagramEventAddPaste::showHint()
/**
@brief DiagramEventAddPaste::moveTo
- Put the group's top left corner at @a scene_pos, snapped to the grid.
+ Compute a grid-snapped delta from the initial cursor position and
+ apply it to every item's grid-shifted position. This keeps all
+ items exactly on grid points regardless of modifier keys or
+ sub-pixel cursor-warp rounding.
*/
void DiagramEventAddPaste::moveTo(const QPointF &scene_pos)
{
- const QPointF anchor = Diagram::snapToGrid(scene_pos);
+ QSettings settings;
+ const int xGrid = settings.value(QStringLiteral("diagrameditor/Xgrid"),
+ Diagram::xGrid).toInt();
+ const int yGrid = settings.value(QStringLiteral("diagrameditor/Ygrid"),
+ Diagram::yGrid).toInt();
+
+ const auto snapGrid = [xGrid, yGrid](const QPointF &p) -> QPointF {
+ return QPointF(
+ qRound(p.x() / xGrid) * xGrid,
+ qRound(p.y() / yGrid) * yGrid);
+ };
+
+ //On the very first call, record the actual grid-snapped
+ //cursor position as baseline. The cursor warp in the
+ //constructor goes through integer rounding (mapFromScene →
+ //QPoint) so the real position may differ slightly from
+ //m_initial_cursor. Using the actual scene position avoids
+ //a one-grid-unit jump on the first mouse movement.
+ if (m_initial_cursor.isNull()) {
+ m_initial_cursor = snapGrid(scene_pos);
+ return;
+ }
+
+ const QPointF delta = snapGrid(scene_pos) - m_initial_cursor;
+
for (auto it = m_relative_pos.constBegin() ; it != m_relative_pos.constEnd() ; ++it) {
if (it.key()) {
- it.key()->setPos(anchor + it.value());
+ it.key()->setPos(it.value() + delta);
}
}
+
+ //Update conductor paths so they follow the moved terminals.
+ const QList conductors = m_content.conductors(DiagramContent::AnyConductor);
+ for (auto *conductor : conductors) {
+ conductor->updatePath();
+ }
}
void DiagramEventAddPaste::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
@@ -160,13 +229,12 @@ void DiagramEventAddPaste::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (!m_running) return;
+ event->setAccepted(true);
if (event->button() == Qt::LeftButton) {
- moveTo(event->scenePos());
commit();
} else if (event->button() == Qt::RightButton) {
cancel();
}
- event->setAccepted(true);
}
void DiagramEventAddPaste::keyPressEvent(QKeyEvent *event)
@@ -175,15 +243,15 @@ void DiagramEventAddPaste::keyPressEvent(QKeyEvent *event)
switch (event->key()) {
case Qt::Key_Escape:
- cancel();
event->setAccepted(true);
+ cancel();
break;
//Return and Enter drop the paste where it stands, so the whole
//operation can be completed without a mouse.
case Qt::Key_Return:
case Qt::Key_Enter:
- commit();
event->setAccepted(true);
+ commit();
break;
default:
break;
@@ -216,13 +284,14 @@ void DiagramEventAddPaste::commit()
void DiagramEventAddPaste::cancel()
{
if (m_finished || !m_diagram) return;
+ removeItems();
m_finished = true;
m_running = false;
+ emit finish(); // only the user-driven path signals
+}
- //Conductors first: they hold pointers to the terminals of the
- //elements below, so removing an element out from under one would
- //leave it pointing at freed memory for as long as it is still in the
- //scene.
+void DiagramEventAddPaste::removeItems()
+{
const QList conductors = m_content.conductors(DiagramContent::AnyConductor);
for (auto *conductor : conductors) {
m_diagram->removeItem(conductor);
@@ -237,5 +306,4 @@ void DiagramEventAddPaste::cancel()
m_content.clear();
m_relative_pos.clear();
- emit finish();
}
diff --git a/sources/diagramevent/diagrameventaddpaste.h b/sources/diagramevent/diagrameventaddpaste.h
index a200ca04d..28ae3854b 100644
--- a/sources/diagramevent/diagrameventaddpaste.h
+++ b/sources/diagramevent/diagrameventaddpaste.h
@@ -73,13 +73,22 @@ class DiagramEventAddPaste : public DiagramEventInterface
void commit();
void cancel();
void showHint();
+ void removeItems();
- DiagramContent m_content;
- ///Each movable item's position relative to the group's top left,
- ///taken once so repeated moves cannot accumulate rounding drift.
- QHash m_relative_pos;
- QPointer m_status_bar;
- bool m_finished{false};
+ DiagramContent m_content;
+ ///Each movable item's position relative to the group's top left,
+ ///taken once so repeated moves cannot accumulate rounding drift.
+ QHash m_relative_pos;
+ ///Top-left corner of the bounding rect of all movable items,
+ ///in scene coordinates, captured when the paste starts.
+ QPointF m_group_origin;
+ ///Cursor position (scene coords) at the moment the paste starts,
+ ///so delta-based movement can compute offsets from the initial point.
+ QPointF m_initial_cursor;
+ ///Set to true once the first moveTo() captures the real cursor position.
+ bool m_baseline_captured{false};
+ QPointer m_status_bar;
+ bool m_finished{false};
};
#endif // DIAGRAMEVENTADDPASTE_H
diff --git a/sources/diagramevent/diagrameventaddshape.cpp b/sources/diagramevent/diagrameventaddshape.cpp
index d19669e76..9795d86f8 100644
--- a/sources/diagramevent/diagrameventaddshape.cpp
+++ b/sources/diagramevent/diagrameventaddshape.cpp
@@ -317,10 +317,16 @@ void DiagramEventAddShape::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
did anything. Re-running the last known mouse position through
applyPosition() here makes the key press or release itself the
trigger, giving immediate feedback instead of waiting on chance.
+ Any other key falls back to standard handling, e.g. pressing ESC aborts the operation.
*/
void DiagramEventAddShape::keyPressEvent(QKeyEvent *event)
{
- reapplyLastPosition(event);
+ if (event->key() == Qt::Key_Shift || event->key() == Qt::Key_Control) {
+ reapplyLastPosition(event);
+ event->setAccepted(true);
+ } else {
+ DiagramEventInterface::keyPressEvent(event);
+ }
}
void DiagramEventAddShape::keyReleaseEvent(QKeyEvent *event)
diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp
index e16a02840..9e89be6cb 100644
--- a/sources/diagramview.cpp
+++ b/sources/diagramview.cpp
@@ -733,6 +733,10 @@ void DiagramView::keyPressEvent(QKeyEvent *e)
//way off the canvas for someone working without a mouse.
//Escape steps back out: first it drops the selection, then it
//hands focus to the next widget.
+ if (m_diagram && m_diagram->eventInterfaceIsRunning()) {
+ QGraphicsView::keyPressEvent(e); // let the active tool see it
+ return;
+ }
if (m_diagram && !m_diagram->selectedItems().isEmpty()) {
m_diagram->clearSelection();
} else {
diff --git a/sources/editor/ui/lineeditor.cpp b/sources/editor/ui/lineeditor.cpp
index b75dfcf39..18ec7d0be 100644
--- a/sources/editor/ui/lineeditor.cpp
+++ b/sources/editor/ui/lineeditor.cpp
@@ -156,6 +156,16 @@ bool LineEditor::setParts(QList parts)
return false;
}
+ // setPart() no-ops when parts.first() is already m_part (its own
+ // identity guard), which skips updateForm(). That is fine when this
+ // editor widget stayed on screen the whole time, but since PR #675
+ // keeps the same editor instance installed across selection changes
+ // instead of tearing it down, an already-shown single line can also be
+ // parts.first() of a later multi-selection -- and without this call
+ // the geometry spinboxes keep showing whatever was in them before,
+ // not this selection's actual first line.
+ updateForm();
+
return m_style->setParts(parts);
}
diff --git a/sources/editor/ui/polygoneditor.ui b/sources/editor/ui/polygoneditor.ui
index 98612f832..c34d26888 100644
--- a/sources/editor/ui/polygoneditor.ui
+++ b/sources/editor/ui/polygoneditor.ui
@@ -48,7 +48,7 @@
-
+
:/ico/16x16/list-add.png:/ico/16x16/list-add.png
@@ -57,7 +57,7 @@
-
+
:/ico/16x16/list-remove.png:/ico/16x16/list-remove.png
diff --git a/sources/editor/ui/qetelementeditor.cpp b/sources/editor/ui/qetelementeditor.cpp
index 9ae36def3..424cabccf 100644
--- a/sources/editor/ui/qetelementeditor.cpp
+++ b/sources/editor/ui/qetelementeditor.cpp
@@ -576,9 +576,11 @@ void QETElementEditor::updateInformations()
|| selection_xml_name == "ellipse"
|| selection_xml_name == "arc")
{
- clearToolsDock();
//We add the editor widget
ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]);
+ if (m_tools_dock_stack -> widget(1) != editor) {
+ clearToolsDock();
+ }
#if TODO_LIST
#pragma message("@TODO Check if it takes longer than setting the parts again to the editor.")
@@ -611,11 +613,15 @@ void QETElementEditor::updateInformations()
success = editor -> setParts(cep_list);
}
if (success) {
- m_tools_dock_stack -> insertWidget(1, editor);
+ if (m_tools_dock_stack -> widget(1) != editor) {
+ m_tools_dock_stack -> insertWidget(1, editor);
+ }
m_tools_dock_stack -> setCurrentIndex(1);
}
else {
qDebug() << "Editor refused part.";
+ clearToolsDock();
+ m_tools_dock_stack->setCurrentIndex(0);
}
}
return;
@@ -629,8 +635,10 @@ void QETElementEditor::updateInformations()
// multi edit for polygons makes no sense
// TODO: maybe allowing multipart edit when number of points is the same?
//We add the editor widget
- clearToolsDock();
ElementItemEditor *editor = static_cast(m_editors[selection_xml_name]);
+ if (m_tools_dock_stack -> widget(1) != editor) {
+ clearToolsDock();
+ }
CustomElementPart* part = editor -> currentPart();
bool equal = part == cep_list.first();
@@ -640,11 +648,15 @@ void QETElementEditor::updateInformations()
success = editor -> setPart(cep_list.first());
}
if (success) {
- m_tools_dock_stack -> insertWidget(1, editor);
+ if (m_tools_dock_stack -> widget(1) != editor) {
+ m_tools_dock_stack -> insertWidget(1, editor);
+ }
m_tools_dock_stack -> setCurrentIndex(1);
}
else {
qDebug() << "Editor refused part.";
+ clearToolsDock();
+ m_tools_dock_stack->setCurrentIndex(0);
}
}
return;
@@ -658,15 +670,21 @@ void QETElementEditor::updateInformations()
//There's several parts selecteds and all can be edited by style editor.
if (style_editable) {
- clearToolsDock();
ElementItemEditor *selection_editor = m_editors["style"];
+ if (m_tools_dock_stack -> widget(1) != selection_editor) {
+ clearToolsDock();
+ }
if (selection_editor) {
if (selection_editor -> setParts(cep_list)) {
- m_tools_dock_stack -> insertWidget(1, selection_editor);
+ if (m_tools_dock_stack -> widget(1) != selection_editor) {
+ m_tools_dock_stack -> insertWidget(1, selection_editor);
+ }
m_tools_dock_stack -> setCurrentIndex(1);
}
else {
qDebug() << "Editor refused part.";
+ clearToolsDock();
+ m_tools_dock_stack->setCurrentIndex(0);
}
}
}
diff --git a/sources/editor/ui/qetelementeditor.ui b/sources/editor/ui/qetelementeditor.ui
index 65a55aa8b..0ec31adc3 100644
--- a/sources/editor/ui/qetelementeditor.ui
+++ b/sources/editor/ui/qetelementeditor.ui
@@ -14,7 +14,7 @@
QElectroTech - Éditeur d'élément
-
+
:/ico/16x16/qet.png:/ico/16x16/qet.png
@@ -55,7 +55,7 @@
Coller depuis...
-
+
:/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png
@@ -202,7 +202,7 @@
-
+
:/ico/16x16/edit-select-all.png:/ico/16x16/edit-select-all.png
@@ -211,7 +211,7 @@
-
+
:/ico/22x22/document-new.png:/ico/22x22/document-new.png
@@ -220,7 +220,7 @@
-
+
:/ico/22x22/folder-open.png:/ico/22x22/folder-open.png
@@ -229,7 +229,7 @@
-
+
:/ico/22x22/folder-open.png:/ico/22x22/folder-open.png
@@ -238,7 +238,7 @@
-
+
:/ico/22x22/document-save.png:/ico/22x22/document-save.png
@@ -247,7 +247,7 @@
-
+
:/ico/22x22/document-save-as.png:/ico/22x22/document-save-as.png
@@ -256,7 +256,7 @@
-
+
:/ico/22x22/document-save.png:/ico/22x22/document-save.png
@@ -265,7 +265,7 @@
-
+
:/ico/22x22/document-export.png:/ico/22x22/document-export.png
@@ -274,7 +274,7 @@
-
+
:/ico/22x22/view-refresh.png:/ico/22x22/view-refresh.png
@@ -283,7 +283,7 @@
-
+
:/ico/16x16/application-exit.png:/ico/16x16/application-exit.png
@@ -295,7 +295,7 @@
-
+
:/ico/16x16/edit-select-none.png:/ico/16x16/edit-select-none.png
@@ -304,7 +304,7 @@
-
+
:/ico/16x16/edit-cut.png:/ico/16x16/edit-cut.png
@@ -313,7 +313,7 @@
-
+
:/ico/16x16/edit-copy.png:/ico/16x16/edit-copy.png
@@ -322,7 +322,7 @@
-
+
:/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png
@@ -331,7 +331,7 @@
-
+
:/ico/16x16/edit-paste.png:/ico/16x16/edit-paste.png
@@ -340,7 +340,7 @@
-
+
:/ico/16x16/text-xml.png:/ico/16x16/text-xml.png
@@ -349,7 +349,7 @@
-
+
:/ico/16x16/element.png:/ico/16x16/element.png
@@ -358,7 +358,7 @@
-
+
:/ico/16x16/edit-select-invert.png:/ico/16x16/edit-select-invert.png
@@ -367,7 +367,7 @@
-
+
:/ico/22x22/edit-delete.png:/ico/22x22/edit-delete.png
@@ -376,7 +376,7 @@
-
+
:/ico/22x22/names.png:/ico/22x22/names.png
@@ -385,7 +385,7 @@
-
+
:/ico/16x16/preferences-desktop-user.png:/ico/16x16/preferences-desktop-user.png
@@ -394,7 +394,7 @@
-
+
:/ico/22x22/element-edit.png:/ico/22x22/element-edit.png
@@ -403,7 +403,7 @@
-
+
:/ico/22x22/zoom-in.png:/ico/22x22/zoom-in.png
@@ -412,7 +412,7 @@
-
+
:/ico/22x22/zoom-out.png:/ico/22x22/zoom-out.png
@@ -421,7 +421,7 @@
-
+
:/ico/22x22/zoom-fit-best.png:/ico/22x22/zoom-fit-best.png
@@ -430,7 +430,7 @@
-
+
:/ico/22x22/zoom-original.png:/ico/22x22/zoom-original.png
@@ -439,7 +439,7 @@
-
+
:/ico/16x16/qet.png:/ico/16x16/qet.png
@@ -451,7 +451,7 @@
-
+
:/ico/16x16/help-contents.png:/ico/16x16/help-contents.png
@@ -463,7 +463,7 @@
-
+
:/ico/16x16/kdenlive-show-video.png:/ico/16x16/kdenlive-show-video.png
@@ -475,7 +475,7 @@
-
+
:/ico/16x16/help-donate.png:/ico/16x16/help-donate.png
@@ -487,7 +487,7 @@
-
+
:/ico/16x16/qt.png:/ico/16x16/qt.png
@@ -499,7 +499,7 @@
-
+
:/ico/16x16/orientations.png:/ico/16x16/orientations.png
@@ -508,7 +508,7 @@
-
+
:/ico/16x16/orientations.png:/ico/16x16/orientations.png
@@ -517,7 +517,7 @@
-
+
:/ico/16x16/mirror.png:/ico/16x16/mirror.png
@@ -526,7 +526,7 @@
-
+
:/ico/16x16/flip.png:/ico/16x16/flip.png
@@ -535,7 +535,7 @@
-
+
:/ico/16x16/run-dxf.png:/ico/16x16/run-dxf.png
@@ -544,7 +544,7 @@
-
+
:/ico/22x22/folder-open.png:/ico/22x22/folder-open.png
diff --git a/sources/elementspanelwidget.cpp b/sources/elementspanelwidget.cpp
index 018064da5..4aa61b7b1 100644
--- a/sources/elementspanelwidget.cpp
+++ b/sources/elementspanelwidget.cpp
@@ -28,6 +28,8 @@
#include
#include
#include "qetgraphicsitem/element.h"
+#include "qetgraphicsitem/dynamicelementtextitem.h"
+#include "qetinformation.h"
/*
When the ENABLE_PANEL_WIDGET_DND_CHECKS flag is set, the panel
@@ -668,6 +670,10 @@ void ElementsPanelWidget::duplicateDiagram()
new_diagram->fromXml(diagram_elmt, QPointF(0, 0), false, nullptr);
+ QSettings settings;
+ bool erase_labels = settings.value(
+ "diagramcommands/erase-label-on-copy", true).toBool();
+
for (QGraphicsItem *item : new_diagram->items()) {
if (Element *elmt = dynamic_cast(item)) {
// The XML round-trip kept the source elements' uuids. Give the
@@ -688,6 +694,90 @@ void ElementsPanelWidget::duplicateDiagram()
{
new_diagram->restoreText(elmt);
}
+
+ // Clear pending links so copies don't link back to
+ // the source elements via stale UUIDs.
+ elmt->clearPendingLinks();
+
+ // Clean up copied element data:
+ // 1. Slaves always lose label/formula/comment/location
+ // and PLC master data — their text comes from a
+ // master element not available on the copy.
+ // 2. Non-slaves: honour "erase-label-on-copy".
+
+ DiagramContext dc = elmt->elementInformations();
+ bool changed = false;
+
+ // Slaves always lose their label/BMK and PLC data —
+ // their text comes from the master, which is not
+ // available on the copied element.
+ if (elmt->linkType() == Element::Slave) {
+ dc.addValue("formula", "");
+ dc.addValue("label", "");
+ dc.addValue("comment", "");
+ dc.addValue("location", "");
+ changed = true;
+
+ for (const QString &key : {
+ QETInformation::ELMT_PLC_TYPE,
+ QETInformation::ELMT_PLC_ADDRESS,
+ QETInformation::ELMT_PLC_FUNCTION,
+ QETInformation::ELMT_PLC_COMMENT,
+ QETInformation::ELMT_PLC_CROSSREF,
+ QETInformation::ELMT_PLC_TC,
+ QETInformation::ELMT_PLC_T1,
+ QETInformation::ELMT_PLC_T2,
+ QETInformation::ELMT_PLC_T3,
+ QETInformation::ELMT_PLC_T4,
+ QStringLiteral("xref")}) {
+ if (dc.contains(key)) {
+ dc.remove(key);
+ changed = true;
+ }
+ }
+ }
+ // Non-slaves: honour the "erase-label-on-copy" preference.
+ else if (erase_labels) {
+ dc.addValue("formula", "");
+ dc.addValue("label", "");
+ dc.addValue("comment", "");
+ dc.addValue("location", "");
+ changed = true;
+ }
+
+ if (changed) {
+ const bool is_slave = (elmt->linkType() == Element::Slave);
+
+ // Block alignment during setElementInformations
+ // for non-slaves, same as Element::fromXml() (line 890-896).
+ // For PLC slaves, don't block — elementInfoChanged()
+ // fires (elementUseForInfo returns self) and needs
+ // finishAlignment() to adjust positions for the
+ // new (empty) text.
+ if (!is_slave) {
+ for (auto deti : elmt->dynamicTextItems())
+ deti->m_block_alignment = true;
+ }
+ elmt->setElementInformations(dc);
+ for (auto deti : elmt->dynamicTextItems())
+ deti->m_block_alignment = false;
+
+ // For non-PLC slaves, elementInfoChanged() doesn't
+ // fire (no linked master), so the text items keep
+ // their original text. Clear them directly.
+ // For PLC slaves, elementInfoChanged() already
+ // cleared the text above. Skip UserText items
+ // (free text typed by the user) in both cases.
+ if (is_slave) {
+ for (auto deti : elmt->dynamicTextItems()) {
+ if (deti->textFrom() != DynamicElementTextItem::UserText) {
+ deti->m_block_alignment = true;
+ deti->setPlainText(QString());
+ deti->m_block_alignment = false;
+ }
+ }
+ }
+ }
}
else if (Conductor *cond = dynamic_cast(item)) {
// Same reasoning for conductors: conductor.uuid is the PRIMARY
@@ -695,6 +785,16 @@ void ElementsPanelWidget::duplicateDiagram()
// so a duplicated uuid fails and the wire silently disappears
// from the wiring list and the per-element wire count.
cond->newUuid();
+
+ // Reset conductor labels when "erase-label-on-copy" is
+ // active, matching PasteDiagramCommand::redo() —
+ // "erase on copy" means erase, not "replace with the
+ // project's default new-conductor text" (see issue #413).
+ if (erase_labels) {
+ ConductorProperties cp = cond->properties();
+ cp.text = "";
+ cond->setProperties(cp);
+ }
}
}
}
diff --git a/sources/print/projectprintwindow.cpp b/sources/print/projectprintwindow.cpp
index 93de03871..e6b86efa5 100644
--- a/sources/print/projectprintwindow.cpp
+++ b/sources/print/projectprintwindow.cpp
@@ -56,7 +56,6 @@
void ProjectPrintWindow::launchDialog(QETProject *project, QPrinter::OutputFormat format, QWidget *parent)
{
auto printer_ = new QPrinter();
- QPrinter printer(QPrinter::HighResolution);
printer_->setDocName(ProjectPrintWindow::docName(project));
printer_->setPageOrientation(QPageLayout::Landscape);
@@ -150,6 +149,11 @@ ProjectPrintWindow::ProjectPrintWindow(QETProject *project, QPrinter *printer, Q
ui->m_draw_terminal_names_cb->setChecked(exp.draw_terminal_names);
ui->m_keep_conductor_color_cb->setChecked(exp.draw_colored_conductors);
+ QSettings settings;
+ ui->m_component_info_cb->setChecked(settings.value("print/default/componentinfo", false).toBool());
+ ui->m_fit_in_page_cb->setChecked(settings.value("print/default/fitinpage", true).toBool());
+ ui->m_use_full_page_cb->setChecked(settings.value("print/default/fullpage", false).toBool());
+
ui->m_date_cb->blockSignals(true);
ui->m_date_cb->setDate(QDate::currentDate());
ui->m_date_cb->blockSignals(false);
@@ -657,6 +661,16 @@ void ProjectPrintWindow::loadPageSetupForCurrentPrinter()
settings.endGroup();
}
+void ProjectPrintWindow::savePrintProperties()
+{
+ QSettings settings;
+ exportProperties().toSettings(settings, "print/default");
+ settings.setValue("print/default/componentinfo", ui->m_component_info_cb->isChecked());
+ settings.setValue("print/default/fitinpage", ui->m_fit_in_page_cb->isChecked());
+ settings.setValue("print/default/fullpage", ui->m_use_full_page_cb->isChecked());
+ settings.sync();
+}
+
void ProjectPrintWindow::savePageSetupForCurrentPrinter()
{
QSettings settings;
@@ -842,6 +856,7 @@ void ProjectPrintWindow::print()
// is created/destroyed inside that call
savePageSetupForCurrentPrinter();
+ savePrintProperties();
if (isPdf && !pdfFile.isEmpty()) {
// Defer post-processing and window close to the next event-loop
diff --git a/sources/print/projectprintwindow.h b/sources/print/projectprintwindow.h
index 3d16fce91..c023e0080 100644
--- a/sources/print/projectprintwindow.h
+++ b/sources/print/projectprintwindow.h
@@ -91,6 +91,7 @@ class ProjectPrintWindow : public QMainWindow
void setUpDiagramList();
QString settingsSectionName(const QPrinter *printer);
void loadPageSetupForCurrentPrinter();
+ void savePrintProperties();
void savePageSetupForCurrentPrinter();
void saveReloadDiagramParameters(Diagram *diagram, const ExportProperties &options, bool save);
QList selectedDiagram() const;
diff --git a/sources/print/projectprintwindow.ui b/sources/print/projectprintwindow.ui
index a1db8e411..c13399fb0 100644
--- a/sources/print/projectprintwindow.ui
+++ b/sources/print/projectprintwindow.ui
@@ -134,7 +134,7 @@
-
+
:/ico/16x16/dialog-ok.png:/ico/16x16/dialog-ok.png
@@ -305,7 +305,7 @@
-
+
:/ico/22x22/view_fit_width.png:/ico/22x22/view_fit_width.png
@@ -314,7 +314,7 @@
-
+
:/ico/22x22/view-fit-window.png:/ico/22x22/view-fit-window.png
@@ -323,7 +323,7 @@
-
+
:/ico/16x16/zoom-out.png:/ico/16x16/zoom-out.png
@@ -332,7 +332,7 @@
-
+
:/ico/16x16/zoom-in.png:/ico/16x16/zoom-in.png
@@ -341,7 +341,7 @@
-
+
:/ico/22x22/landscape.png:/ico/22x22/landscape.png
@@ -350,7 +350,7 @@
-
+
:/ico/22x22/portrait.png:/ico/22x22/portrait.png
@@ -359,7 +359,7 @@
-
+
:/ico/16x16/arrow-left-double.png:/ico/16x16/arrow-left-double.png
@@ -368,7 +368,7 @@
-
+
:/ico/16x16/arrow-left.png:/ico/16x16/arrow-left.png
@@ -377,7 +377,7 @@
-
+
:/ico/16x16/arrow-right.png:/ico/16x16/arrow-right.png
@@ -386,7 +386,7 @@
-
+
:/ico/22x22/arrow-right-double.png:/ico/22x22/arrow-right-double.png
@@ -395,7 +395,7 @@
-
+
:/ico/22x22/single_page.png:/ico/22x22/single_page.png
@@ -404,7 +404,7 @@
-
+
:/ico/22x22/two_pages.png:/ico/22x22/two_pages.png
@@ -413,7 +413,7 @@
-
+
:/ico/22x22/all_pages.png:/ico/22x22/all_pages.png
@@ -422,7 +422,7 @@
-
+
:/ico/48x48/document-print-frame.png:/ico/48x48/document-print-frame.png
diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp
index d8e625d4d..76c1203fc 100644
--- a/sources/qetapp.cpp
+++ b/sources/qetapp.cpp
@@ -120,6 +120,7 @@ QETApp::QETApp() :
}
initConfiguration();
initLanguage();
+ initIconTheme();
QET::Icons::initIcons();
initFonts();
initStyle();
@@ -2330,6 +2331,22 @@ void QETApp::initFonts()
}
}
+/**
+ @brief QETApp::initIconTheme
+ Register QET's icon theme "qet" (see misc/make_icon_themes.py and
+ ico/icon-themes.qrc) and make it the current theme, so
+ QIcon::fromTheme("name") resolves to QET's own icons on every
+ platform. Must run before QET::Icons::initIcons(), which looks icons
+ up by name.
+*/
+void QETApp::initIconTheme()
+{
+ QStringList paths = QIcon::themeSearchPaths();
+ paths.prepend(QStringLiteral(":/ico/themes"));
+ QIcon::setThemeSearchPaths(paths);
+ QIcon::setThemeName(QStringLiteral("qet"));
+}
+
/**
@brief QETApp::initStyle
Setup the gui style
@@ -2660,14 +2677,28 @@ void QETApp::checkBackupFiles()
}
}
- if (stale_files.isEmpty()) {
- // Only offer an unretrieved crash dump when there's no project
- // to recover this run -- discussion #644 step 5 is explicit
- // that the two prompts must never both show at once.
- checkCrashDump();
- return;
+ if (!stale_files.isEmpty()) {
+ offerBackupFiles(stale_files);
}
+ // Discussion #644 step 5 asks that the recovery prompt and the crash
+ // report never show at the same time -- not that the report be dropped
+ // whenever there is something to recover. Offering it here, once the
+ // recovery prompt has been answered, keeps the two sequential without
+ // losing the report after the most common crash there is: one with a
+ // project open, which always leaves a stale file behind, so the report
+ // was unreachable in exactly the case it is most wanted (issue #901).
+ checkCrashDump();
+}
+
+/**
+ @brief QETApp::offerBackupFiles
+ Ask whether to reopen the recovery files left by a previous run, and
+ open or discard them accordingly.
+ @param stale_files : the recovery files to offer
+*/
+void QETApp::offerBackupFiles(const QList &stale_files)
+{
QString text;
if(stale_files.size() == 1) {
text.append(tr("Le fichier de restauration suivant a été trouvé,
"
diff --git a/sources/qetapp.h b/sources/qetapp.h
index ee793ecb6..8242abf71 100644
--- a/sources/qetapp.h
+++ b/sources/qetapp.h
@@ -31,6 +31,7 @@ class QSplashScreen;
class QMenu;
class QAction;
class QMainWindow;
+class KAutoSaveFile;
#define QETAPP_COMMON_TBT_PROTOCOL "commontbt"
#define QETAPP_COMPANY_TBT_PROTOCOL "companytbt"
@@ -285,11 +286,13 @@ class QETApp : public QObject
void setSplashScreenStep(const QString & = QString());
void initLanguage();
void initFonts();
+ void initIconTheme();
void initStyle();
void initConfiguration();
void initSystemTray();
void buildSystemTrayMenu();
void checkBackupFiles();
+ void offerBackupFiles(const QList &stale_files);
void checkCrashDump();
void fetchWindowStats(
const QList &,
diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp
index c9f4c868e..d1a4be91b 100644
--- a/sources/qetdiagrameditor.cpp
+++ b/sources/qetdiagrameditor.cpp
@@ -430,7 +430,7 @@ void QETDiagramEditor::setUpActions()
});
// Draw or not the custom guides
- m_draw_guides = new QAction ( QIcon(":/ico/22x22/guides.png"), tr("Afficher les guides"), this);
+ m_draw_guides = new QAction ( QIcon::fromTheme("guides"), tr("Afficher les guides"), this);
m_draw_guides->setStatusTip(tr("Affiche ou masque les guides"));
m_draw_guides->setCheckable(true);
m_draw_guides->setChecked(settings.value("diagrameditor/guides_display_startup", false).toBool());
@@ -1754,6 +1754,10 @@ void QETDiagramEditor::addItemGroupTriggered(QAction *action)
// here makes the button's appearance match its actual state
// regardless of whether Qt's own change notification fired
// correctly.
+
+ if (DiagramView *dv = currentDiagramView())
+ dv->setFocus(); // so the view (and the active tool) actually receives Escape etc
+
if (QWidget *button = m_add_item_tool_bar->widgetForAction(action))
button->update();
}
diff --git a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui
index 439512405..28edea330 100644
--- a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui
+++ b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui
@@ -62,7 +62,7 @@
-
+
:/ico/16x16/arrow-right.png:/ico/16x16/arrow-right.png
@@ -104,7 +104,7 @@
-
+
:/ico/22x22/zoom-fit-best.png:/ico/22x22/zoom-fit-best.png
@@ -179,7 +179,7 @@
-
+
:/ico/16x16/arrow-left.png:/ico/16x16/arrow-left.png
@@ -203,7 +203,7 @@
-
+
:/ico/22x22/all_pages.png:/ico/22x22/all_pages.png
diff --git a/sources/qetgraphicsitem/ViewItem/ui/projectdbmodelpropertieswidget.ui b/sources/qetgraphicsitem/ViewItem/ui/projectdbmodelpropertieswidget.ui
index 3ce470886..649e756c7 100644
--- a/sources/qetgraphicsitem/ViewItem/ui/projectdbmodelpropertieswidget.ui
+++ b/sources/qetgraphicsitem/ViewItem/ui/projectdbmodelpropertieswidget.ui
@@ -20,7 +20,7 @@
Requête
-
+
:/ico/16x16/edit-rename.png:/ico/16x16/edit-rename.png
@@ -31,7 +31,7 @@
Recharger
-
+
:/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png
diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h
index 1b9ee9409..a189e632b 100644
--- a/sources/qetgraphicsitem/element.h
+++ b/sources/qetgraphicsitem/element.h
@@ -120,6 +120,11 @@ class Element : public QetGraphicsItem
QList conductors() const;
QList> AlignedFreeTerminals() const;
+ void clearPendingLinks() {
+ tmp_uuids_link.clear();
+ m_group_index_map.clear();
+ }
+
//METHODS related to information
DiagramContext elementInformations()const
{return m_data.m_informations;}
diff --git a/sources/qeticons.cpp b/sources/qeticons.cpp
index 309ef423c..39030275c 100644
--- a/sources/qeticons.cpp
+++ b/sources/qeticons.cpp
@@ -392,471 +392,401 @@ void QET::Icons::initIcons()
bool rtl = QApplication::isRightToLeft();
QTransform reverse = QTransform().scale(-1, 1);
- Add .addFile(":/ico/16x16/list-add.png");
- Add .addFile(":/ico/22x22/list-add.png");
- AddFolio .addFile(":/ico/16x16/folio-new.png");
- Allowed .addFile(":/ico/16x16/user-online.png");
- ApplicationExit .addFile(":/ico/16x16/application-exit.png");
- ApplicationExit .addFile(":/ico/22x22/application-exit.png");
- ArrowLeft .addFile(":/ico/16x16/arrow-left.png");
- ArrowLeft .addFile(":/ico/22x22/arrow-left.png");
- ArrowLeftDouble .addFile(":/ico/16x16/arrow-left-double.png");
- ArrowLeftDouble .addFile(":/ico/22x22/arrow-left-double.png");
- ArrowRight .addFile(":/ico/16x16/arrow-right.png");
- ArrowRight .addFile(":/ico/22x22/arrow-right.png");
- ArrowRightDouble .addFile(":/ico/16x16/arrow-right-double.png");
- ArrowRightDouble .addFile(":/ico/22x22/arrow-right-double.png");
- Autoconnect .addFile(":/ico/22x22/autoconnect.png");
- BringForward .addFile(":/ico/22x22/bring_forward.png");
- Cancel .addFile(":/ico/16x16/item-cancel.png");
- Company .addFile(":/ico/16x16/go-company.png");
- Company .addFile(":/ico/22x22/go-company.png");
- Conductor .addFile(":/ico/16x16/conductor.png");
- ConductorEdit .addFile(":/ico/16x16/conductor-edit.png");
- ConductorSettings .addFile(":/ico/16x16/conductor-reset.png");
- ConductorSettings .addFile(":/ico/22x22/conductor2.png");
- Configure .addFile(":/ico/16x16/configure.png");
- Configure .addFile(":/ico/22x22/configure.png");
- ConfigureToolbars .addFile(":/ico/16x16/configure-toolbars.png");
- ConfigureToolbars .addFile(":/ico/22x22/configure-toolbars.png");
- IC_CopyFile .addFile(":/ico/16x16/item-copy.png");
- DiagramAdd .addFile(":/ico/16x16/folio-new.png");
- DiagramAdd .addFile(":/ico/22x22/diagram_add.png");
- Diagram .addFile(":/ico/16x16/diagram.png");
- Diagram .addFile(":/ico/diagram.png");
- DiagramBg .addFile(":/ico/22x22/diagram_bg.png");
- DiagramDelete .addFile(":/ico/16x16/folio-delete.png");
- DiagramDelete .addFile(":/ico/22x22/diagram_del.png");
- DialogCancel .addFile(":/ico/16x16/dialog-cancel.png");
- DialogCancel .addFile(":/ico/22x22/dialog-cancel.png");
- DialogInformation .addFile(":/ico/16x16/folio-properties.png");
- DialogInformation .addFile(":/ico/22x22/dialog-information.png");
- DialogOk .addFile(":/ico/16x16/dialog-ok.png");
- DialogOk .addFile(":/ico/22x22/dialog-ok.png");
- DocumentClose .addFile(":/ico/16x16/document-close.png");
- DocumentClose .addFile(":/ico/22x22/document-close.png");
- DocumentExport .addFile(":/ico/16x16/document-export.png");
- DocumentExport .addFile(":/ico/22x22/document-export.png");
- DocumentSpreadsheet .addFile(":/ico/16x16/export-csv.png");
- DocumentExport .addFile(":/ico/128x128/document-export.png");
- DocumentImport .addFile(":/ico/16x16/document-import.png");
- DocumentImport .addFile(":/ico/22x22/document-import.png");
- DocumentNew .addFile(":/ico/16x16/document-new.png");
- DocumentNew .addFile(":/ico/22x22/document-new.png");
- DocumentOpen .addFile(":/ico/16x16/document-open.png");
- DocumentOpen .addFile(":/ico/22x22/document-open.png");
- DocumentOpenRecent .addFile(":/ico/16x16/document-open-recent.png");
- DocumentOpenRecent .addFile(":/ico/22x22/document-open-recent.png");
- DocumentPrint .addFile(":/ico/16x16/document-print.png");
- DocumentPrint .addFile(":/ico/22x22/document-print.png");
- DocumentPrintFrame .addFile(":/ico/16x16/document-print-frame.png");
- DocumentPrintFrame .addFile(":/ico/48x48/document-print-frame.png");
- DocumentSave .addFile(":/ico/16x16/document-save.png");
- DocumentSave .addFile(":/ico/22x22/document-save.png");
- DocumentSaveAll .addFile(":/ico/16x16/document-save-all.png");
- DocumentSaveAll .addFile(":/ico/22x22/document-save-all.png");
- DocumentSaveAs .addFile(":/ico/16x16/document-save-as.png");
- DocumentSaveAs .addFile(":/ico/22x22/document-save-as.png");
- East .addFile(":/ico/16x16/east.png");
- EditClear .addFile(":/ico/16x16/edit-clear.png");
- EditClear .addFile(":/ico/22x22/edit-clear.png");
- EditText .addFile(":/ico/22x22/names.png");
- adding_image .addFile(":/ico/22x22/insert-image.png");
- adding_pdf .addFile(":/ico/22x22/pdf-import.png");
+ Add = QIcon::fromTheme("list-add");
+ AddFolio = QIcon::fromTheme("folio-new");
+ Allowed = QIcon::fromTheme("user-online");
+ ApplicationExit = QIcon::fromTheme("application-exit");
+ ArrowLeft = QIcon::fromTheme("arrow-left");
+ ArrowLeftDouble = QIcon::fromTheme("arrow-left-double");
+ ArrowRight = QIcon::fromTheme("arrow-right");
+ ArrowRightDouble = QIcon::fromTheme("arrow-right-double");
+ Autoconnect = QIcon::fromTheme("autoconnect");
+ BringForward = QIcon::fromTheme("bring_forward");
+ Cancel = QIcon::fromTheme("item-cancel");
+ Company = QIcon::fromTheme("go-company");
+ Conductor = QIcon::fromTheme("conductor");
+ ConductorEdit = QIcon::fromTheme("conductor-edit");
+ ConductorSettings = QIcon::fromTheme("conductor-reset");
+ Configure = QIcon::fromTheme("configure");
+ ConfigureToolbars = QIcon::fromTheme("configure-toolbars");
+ IC_CopyFile = QIcon::fromTheme("item-copy");
+ DiagramAdd = QIcon::fromTheme("folio-new");
+ Diagram.addFile(":/ico/16x16/diagram.png");
+ Diagram.addFile(":/ico/diagram.png");
+ DiagramBg = QIcon::fromTheme("diagram_bg");
+ DiagramDelete = QIcon::fromTheme("folio-delete");
+ DialogCancel = QIcon::fromTheme("dialog-cancel");
+ DialogInformation = QIcon::fromTheme("folio-properties");
+ DialogOk = QIcon::fromTheme("dialog-ok");
+ DocumentClose = QIcon::fromTheme("document-close");
+ DocumentExport = QIcon::fromTheme("document-export");
+ DocumentSpreadsheet = QIcon::fromTheme("export-csv");
+ DocumentExport = QIcon::fromTheme("document-export");
+ DocumentImport = QIcon::fromTheme("document-import");
+ DocumentNew = QIcon::fromTheme("document-new");
+ DocumentOpen = QIcon::fromTheme("document-open");
+ DocumentOpenRecent = QIcon::fromTheme("document-open-recent");
+ DocumentPrint = QIcon::fromTheme("document-print");
+ DocumentPrintFrame = QIcon::fromTheme("document-print-frame");
+ DocumentSave = QIcon::fromTheme("document-save");
+ DocumentSaveAll = QIcon::fromTheme("document-save-all");
+ DocumentSaveAs = QIcon::fromTheme("document-save-as");
+ East = QIcon::fromTheme("east");
+ EditClear = QIcon::fromTheme("edit-clear");
+ EditText = QIcon::fromTheme("names");
+ adding_image = QIcon::fromTheme("insert-image");
+ adding_pdf = QIcon::fromTheme("pdf-import");
if (rtl) {
- EditClearLocationBar.addPixmap(QPixmap(":/ico/16x16/edit-clear-locationbar-ltr.png").transformed(reverse));
- EditClearLocationBar.addPixmap(QPixmap(":/ico/22x22/edit-clear-locationbar-ltr.png").transformed(reverse));
+ EditClearLocationBar.addPixmap(QIcon::fromTheme("edit-clear-locationbar-ltr").pixmap(16).transformed(reverse));
+ EditClearLocationBar.addPixmap(QIcon::fromTheme("edit-clear-locationbar-ltr").pixmap(22).transformed(reverse));
} else {
- EditClearLocationBar.addFile(":/ico/16x16/edit-clear-locationbar-ltr.png");
- EditClearLocationBar.addFile(":/ico/22x22/edit-clear-locationbar-ltr.png");
+ EditClearLocationBar= QIcon::fromTheme("edit-clear-locationbar-ltr");
}
- EditCopy .addFile(":/ico/16x16/edit-copy.png");
- EditCopy .addFile(":/ico/22x22/edit-copy.png");
- EditCut .addFile(":/ico/16x16/edit-cut.png");
- EditCut .addFile(":/ico/22x22/edit-cut.png");
- EditDelete .addFile(":/ico/16x16/edit-delete.png");
- EditDelete .addFile(":/ico/22x22/edit-delete.png");
- EditOpacity .addFile(":/ico/breeze-icons/scalable/apps/hidef/edit-opacity.svg");
- EditPaste .addFile(":/ico/22x22/edit-paste.png");
- EditPaste .addFile(":/ico/16x16/edit-paste.png");
+ EditCopy = QIcon::fromTheme("edit-copy");
+ EditCut = QIcon::fromTheme("edit-cut");
+ EditDelete = QIcon::fromTheme("edit-delete");
+ EditOpacity = QIcon::fromTheme("edit-opacity");
+ EditPaste = QIcon::fromTheme("edit-paste");
if (rtl) {
- EditRedo.addPixmap(QPixmap(":/ico/16x16/edit-redo.png").transformed(reverse));
- EditRedo.addPixmap(QPixmap(":/ico/22x22/edit-redo.png").transformed(reverse));
+ EditRedo.addPixmap(QIcon::fromTheme("edit-redo").pixmap(16).transformed(reverse));
+ EditRedo.addPixmap(QIcon::fromTheme("edit-redo").pixmap(22).transformed(reverse));
} else {
- EditRedo .addFile(":/ico/16x16/edit-redo.png");
- EditRedo .addFile(":/ico/22x22/edit-redo.png");
+ EditRedo = QIcon::fromTheme("edit-redo");
}
- EditRename .addFile(":/ico/16x16/edit-rename.png");
- EditRename .addFile(":/ico/22x22/edit-rename.png");
- EditSelectAll .addFile(":/ico/16x16/edit-select-all.png");
- EditSelectAll .addFile(":/ico/22x22/edit-select-all.png");
- EditSelectInvert .addFile(":/ico/16x16/edit-select-invert.png");
- EditSelectNone .addFile(":/ico/16x16/edit-select-none.png");
- EditTableCellMerge .addFile(":/ico/16x16/edit-table-cell-merge.png");
- EditTableCellMerge .addFile(":/ico/22x22/edit-table-cell-merge.png");
- EditTableCellSplit .addFile(":/ico/16x16/edit-table-cell-split.png");
- EditTableCellSplit .addFile(":/ico/22x22/edit-table-cell-split.png");
- EditTableDeleteColumn .addFile(":/ico/16x16/edit-table-delete-column.png");
- EditTableDeleteColumn .addFile(":/ico/22x22/edit-table-delete-column.png");
- EditTableDeleteRow .addFile(":/ico/16x16/edit-table-delete-row.png");
- EditTableDeleteRow .addFile(":/ico/22x22/edit-table-delete-row.png");
- EditTableInsertColumnLeft .addFile(":/ico/16x16/edit-table-insert-column-left.png");
- EditTableInsertColumnLeft .addFile(":/ico/22x22/edit-table-insert-column-left.png");
- EditTableInsertColumnRight.addFile(":/ico/16x16/edit-table-insert-column-right.png");
- EditTableInsertColumnRight.addFile(":/ico/22x22/edit-table-insert-column-right.png");
- EditTableInsertRowAbove .addFile(":/ico/16x16/edit-table-insert-row-above.png");
- EditTableInsertRowAbove .addFile(":/ico/22x22/edit-table-insert-row-above.png");
- EditTableInsertRowUnder .addFile(":/ico/16x16/edit-table-insert-row-under.png");
- EditTableInsertRowUnder .addFile(":/ico/22x22/edit-table-insert-row-under.png");
+ EditRename = QIcon::fromTheme("edit-rename");
+ EditSelectAll = QIcon::fromTheme("edit-select-all");
+ EditSelectInvert = QIcon::fromTheme("edit-select-invert");
+ EditSelectNone = QIcon::fromTheme("edit-select-none");
+ EditTableCellMerge = QIcon::fromTheme("edit-table-cell-merge");
+ EditTableCellSplit = QIcon::fromTheme("edit-table-cell-split");
+ EditTableDeleteColumn= QIcon::fromTheme("edit-table-delete-column");
+ EditTableDeleteRow = QIcon::fromTheme("edit-table-delete-row");
+ EditTableInsertColumnLeft= QIcon::fromTheme("edit-table-insert-column-left");
+ EditTableInsertColumnRight= QIcon::fromTheme("edit-table-insert-column-right");
+ EditTableInsertRowAbove= QIcon::fromTheme("edit-table-insert-row-above");
+ EditTableInsertRowUnder= QIcon::fromTheme("edit-table-insert-row-under");
if (rtl) {
- EditUndo.addPixmap(QPixmap(":/ico/16x16/edit-undo.png").transformed(reverse));
- EditUndo.addPixmap(QPixmap(":/ico/22x22/edit-undo.png").transformed(reverse));
+ EditUndo.addPixmap(QIcon::fromTheme("edit-undo").pixmap(16).transformed(reverse));
+ EditUndo.addPixmap(QIcon::fromTheme("edit-undo").pixmap(22).transformed(reverse));
} else {
- EditUndo .addFile(":/ico/16x16/edit-undo.png");
- EditUndo .addFile(":/ico/22x22/edit-undo.png");
+ EditUndo = QIcon::fromTheme("edit-undo");
}
- Element .addFile(":/ico/breeze-icons/16x16/mimetypes/application-x-qet-element.png");
- Element .addFile(":/ico/breeze-icons/22x22/mimetypes/application-x-qet-element.png");
- Element .addFile(":/ico/breeze-icons/32x32/mimetypes/application-x-qet-element.png");
- ElementDelete .addFile(":/ico/16x16/element-delete.png");
- ElementDelete .addFile(":/ico/22x22/element-delete.png");
- ElementEdit .addFile(":/ico/16x16/element-edit.png");
- ElementEdit .addFile(":/ico/22x22/element-edit.png");
- ElementNew .addFile(":/ico/16x16/element-new.png");
- ElementNew .addFile(":/ico/22x22/element-new.png");
- ElementSmall .addFile(":/ico/16x16/element.png");
- EllipseToBezier .addFile(":/ico/generated/ellipse-to-bezier.svg");
- EndLineCircle .addFile(":/ico/16x16/endline-circle.png");
- EndLineDiamond .addFile(":/ico/16x16/endline-diamond.png");
- EndLineNone .addFile(":/ico/16x16/endline-none.png");
- EndLineSimple .addFile(":/ico/16x16/endline-simple.png");
- EndLineTriangle .addFile(":/ico/16x16/endline-triangle.png");
- EPS .addFile(":/ico/32x32/image-x-eps.png");
- Flip .addFile(":/ico/16x16/flip.png");
- Folder .addFile(":/ico/16x16/folder.png");
- FolderDelete .addFile(":/ico/16x16/folder-delete.png");
- FolderDelete .addFile(":/ico/22x22/folder-delete.png");
- FolderEdit .addFile(":/ico/16x16/folder-edit.png");
- FolderEdit .addFile(":/ico/22x22/folder-edit.png");
- FolderNew .addFile(":/ico/16x16/folder-new.png");
- FolderNew .addFile(":/ico/22x22/folder-new.png");
- FolderOnlyThis .addFile(":/ico/16x16/folder-only-this.png");
- FolderOpen .addFile(":/ico/16x16/folder-open.png");
- FolderOpen .addFile(":/ico/22x22/folder-open.png");
- FolderProperties .addFile(":/ico/16x16/folder-properties.png");
- FolderShowAll .addFile(":/ico/16x16/folder-show-all.png");
- Forbidden .addFile(":/ico/16x16/user-busy.png");
- FullScreenEnter .addFile(":/ico/16x16/view-fullscreen.png");
- FullScreenEnter .addFile(":/ico/22x22/view-fullscreen.png");
- FullScreenExit .addFile(":/ico/16x16/view-restore.png");
- FullScreenExit .addFile(":/ico/22x22/view-restore.png");
- GoBottom .addFile(":/ico/16x16/go-bottom.png");
- GoDown .addFile(":/ico/16x16/go-down.png");
- GoDown .addFile(":/ico/22x22/go-down.png");
- GoDownDouble .addFile(":/ico/16x16/go-down-double.png");
- GoTop .addFile(":/ico/16x16/go-top.png");
- GoUp .addFile(":/ico/16x16/go-up.png");
- GoUp .addFile(":/ico/22x22/go-up.png");
- GoUpDouble .addFile(":/ico/16x16/go-up-double.png");
- Ground .addFile(":/ico/16x16/ground.png");
- Grid .addFile(":/ico/16x16/grid.png");
- Grid .addFile(":/ico/22x22/grid.png");
- Hide .addFile(":/ico/16x16/masquer.png");
- Home .addFile(":/ico/16x16/go-home.png");
- Home .addFile(":/ico/22x22/go-home.png");
- HotSpot .addFile(":/ico/22x22/hotspot.png");
- ImageFlipHorizontal .addFile(":/ico/breeze-icons/scalable/apps/hidef/image-flip-horizontal-symbolic.svg");
- ImageFlipVertical .addFile(":/ico/breeze-icons/scalable/apps/hidef/image-flip-vertical-symbolic.svg");
- InsertImage .addFile(":/ico/22x22/insert-image.png");
- Lower .addFile(":/ico/22x22/lower.png");
- IC_MoveFile .addFile(":/ico/16x16/item-move.png");
- Mirror .addFile(":/ico/16x16/mirror.png");
- Names .addFile(":/ico/22x22/names.png");
- Neutral .addFile(":/ico/16x16/neutral.png");
- NewDiagram .addFile(":/ico/128x128/diagram.png");
- North .addFile(":/ico/16x16/north.png");
- ObjectLocked .addFile(":/ico/22x22/object-locked.png");
- ObjectRotateRight .addFile(":/ico/16x16/object-rotate-right.png");
- ObjectRotateRight .addFile(":/ico/22x22/object-rotate-right.png");
- ObjectUnlocked .addFile(":/ico/22x22/object-unlocked.png");
- Orientations .addFile(":/ico/16x16/orientations.png");
- PartArc .addFile(":/ico/22x22/arc.png");
- PartBezier .addFile(":/ico/breeze-icons/scalable/apps/hidef/draw-bezier-curves.svg");
- PartCircle .addFile(":/ico/16x16/circle.png");
- PartEllipse .addFile(":/ico/22x22/ellipse.png");
- PartLine .addFile(":/ico/22x22/line.png");
- PartPolygon .addFile(":/ico/22x22/polygon.png");
- PartRectangle .addFile(":/ico/22x22/rectangle.png");
- PartSelect .addFile(":/ico/16x16/select.png");
- PartSelect .addFile(":/ico/22x22/select.png");
- PartText .addFile(":/ico/22x22/text.png");
- PartTextField .addFile(":/ico/22x22/textfield.png");
- PDF .addFile(":/ico/32x32/application-pdf.png");
- Phase .addFile(":/ico/16x16/phase.png");
- PrintAllPages .addFile(":/ico/22x22/all_pages.png");
- Printer .addFile(":/ico/32x32/printer.png");
- Printer .addFile(":/ico/128x128/printer.png");
- PrintLandscape .addFile(":/ico/22x22/landscape.png");
- PrintPortrait .addFile(":/ico/22x22/portrait.png");
- PrintTwoPages .addFile(":/ico/22x22/two_pages.png");
- Projects .addFile(":/ico/128x128/project.png");
- ProjectClose .addFile(":/ico/16x16/project-close.png");
- ProjectClose .addFile(":/ico/22x22/project-close.png");
- ProjectNew .addFile(":/ico/16x16/project-new.png");
- ProjectNew .addFile(":/ico/22x22/project-new.png");
- ProjectFile .addFile(":/ico/breeze-icons/16x16/mimetypes/application-x-qet-project.png");
- ProjectFile .addFile(":/ico/breeze-icons/22x22/mimetypes/application-x-qet-project.png");
- ProjectFile .addFile(":/ico/breeze-icons/32x32/mimetypes/application-x-qet-project.png");
- ProjectProperties .addFile(":/ico/16x16/project-properties.png");
- QETDonate .addFile(":/ico/16x16/help-donate.png");
- QETDownload .addFile(":/ico/16x16/edit-download.png");
- QETIcon .addFile(":/ico/256x256/qelectrotech.png");
- ProjectFileGP .addFile(":/ico/16x16/project.png");
- QETLogo .addFile(":/ico/16x16/qet.png");
- QETManual .addFile(":/ico/16x16/help-contents.png");
- QETLogo .addFile(":/ico/256x256/qet.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/128x128/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/16x16/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/22x22/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/256x256/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/32x32/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/48x48/apps/qelectrotech.png");
- QETOxygenLogo .addFile(":/ico/breeze-icons/64x64/apps/qelectrotech.png");
- QETVideo .addFile(":/ico/16x16/kdenlive-show-video.png");
- QtLogo .addFile(":/ico/16x16/qt.png");
- Raise .addFile(":/ico/22x22/raise.png");
- RectToBezier .addFile(":/ico/generated/rect-to-bezier.svg");
- RectToPolyline .addFile(":/ico/generated/rect-to-polyline.svg");
- Remove .addFile(":/ico/16x16/list-remove.png");
- Remove .addFile(":/ico/22x22/list-remove.png");
- resize_image .addFile(":/ico/22x22/transform-scale.png");
- Restore .addFile(":/ico/22x22/restaurer.png");
- RunDxf .addFile(":/ico/16x16/run-dxf.png");
- SendBackward .addFile(":/ico/22x22/send_backward.png");
- Settings .addFile(":/ico/128x128/settings.png");
- SinglePage .addFile(":/ico/22x22/single_page.png");
- South .addFile(":/ico/16x16/south.png");
- Start .addFile(":/ico/22x22/start.png");
- TableOfContent .addFile(":/ico/16x16/table-of-content.png");
- Terminal .addFile(":/ico/22x22/terminal.png");
- TerminalStrip .addFile(":/ico/16x16/terminalstrip.png");
- TerminalStrip .addFile(":/ico/22x22/terminalstrip.png");
- TitleBlock .addFile(":/ico/16x16/label.png");
- TitleBlock .addFile(":/ico/22x22/label.png");
- TitleBlockBottom .addFile(":/ico/22x22/titleblock-bottom.png");
- TitleBlockRight .addFile(":/ico/22x22/titleblock-right.png");
- TransformCrop .addFile(":/ico/breeze-icons/scalable/apps/hidef/transform-crop.svg");
- TransformRotate .addFile(":/ico/16x16/transform-rotate.png");
- UserInformations .addFile(":/ico/16x16/preferences-desktop-user.png");
- UserInformations .addFile(":/ico/22x22/preferences-desktop-user.png");
- ViewFitWidth .addFile(":/ico/22x22/view_fit_width.png");
- ViewFitWindow .addFile(":/ico/22x22/view-fit-window.png");
- ViewMove .addFile(":/ico/16x16/move.png");
- ViewMove .addFile(":/ico/22x22/move.png");
+ Element.addFile(":/ico/breeze-icons/16x16/mimetypes/application-x-qet-element.png");
+ Element.addFile(":/ico/breeze-icons/22x22/mimetypes/application-x-qet-element.png");
+ Element.addFile(":/ico/breeze-icons/32x32/mimetypes/application-x-qet-element.png");
+ ElementDelete = QIcon::fromTheme("element-delete");
+ ElementEdit = QIcon::fromTheme("element-edit");
+ ElementNew = QIcon::fromTheme("element-new");
+ ElementSmall = QIcon::fromTheme("element");
+ EllipseToBezier = QIcon::fromTheme("ellipse-to-bezier");
+ EndLineCircle = QIcon::fromTheme("endline-circle");
+ EndLineDiamond = QIcon::fromTheme("endline-diamond");
+ EndLineNone = QIcon::fromTheme("endline-none");
+ EndLineSimple = QIcon::fromTheme("endline-simple");
+ EndLineTriangle = QIcon::fromTheme("endline-triangle");
+ EPS = QIcon::fromTheme("image-x-eps");
+ Flip = QIcon::fromTheme("flip");
+ Folder = QIcon::fromTheme("folder");
+ FolderDelete = QIcon::fromTheme("folder-delete");
+ FolderEdit = QIcon::fromTheme("folder-edit");
+ FolderNew = QIcon::fromTheme("folder-new");
+ FolderOnlyThis = QIcon::fromTheme("folder-only-this");
+ FolderOpen = QIcon::fromTheme("folder-open");
+ FolderProperties = QIcon::fromTheme("folder-properties");
+ FolderShowAll = QIcon::fromTheme("folder-show-all");
+ Forbidden = QIcon::fromTheme("user-busy");
+ FullScreenEnter = QIcon::fromTheme("view-fullscreen");
+ FullScreenExit = QIcon::fromTheme("view-restore");
+ GoBottom = QIcon::fromTheme("go-bottom");
+ GoDown = QIcon::fromTheme("go-down");
+ GoDownDouble = QIcon::fromTheme("go-down-double");
+ GoTop = QIcon::fromTheme("go-top");
+ GoUp = QIcon::fromTheme("go-up");
+ GoUpDouble = QIcon::fromTheme("go-up-double");
+ Ground = QIcon::fromTheme("ground");
+ Grid = QIcon::fromTheme("grid");
+ Hide = QIcon::fromTheme("masquer");
+ Home = QIcon::fromTheme("go-home");
+ HotSpot = QIcon::fromTheme("hotspot");
+ ImageFlipHorizontal = QIcon::fromTheme("image-flip-horizontal");
+ ImageFlipVertical = QIcon::fromTheme("image-flip-vertical");
+ InsertImage = QIcon::fromTheme("insert-image");
+ Lower = QIcon::fromTheme("lower");
+ IC_MoveFile = QIcon::fromTheme("item-move");
+ Mirror = QIcon::fromTheme("mirror");
+ Names = QIcon::fromTheme("names");
+ Neutral = QIcon::fromTheme("neutral");
+ NewDiagram = QIcon::fromTheme("diagram");
+ North = QIcon::fromTheme("north");
+ ObjectLocked = QIcon::fromTheme("object-locked");
+ ObjectRotateRight = QIcon::fromTheme("object-rotate-right");
+ ObjectUnlocked = QIcon::fromTheme("object-unlocked");
+ Orientations = QIcon::fromTheme("orientations");
+ PartArc = QIcon::fromTheme("arc");
+ PartBezier = QIcon::fromTheme("draw-bezier-curves");
+ PartCircle = QIcon::fromTheme("circle");
+ PartEllipse = QIcon::fromTheme("ellipse");
+ PartLine = QIcon::fromTheme("line");
+ PartPolygon = QIcon::fromTheme("polygon");
+ PartRectangle = QIcon::fromTheme("rectangle");
+ PartSelect = QIcon::fromTheme("select");
+ PartText = QIcon::fromTheme("text");
+ PartTextField = QIcon::fromTheme("textfield");
+ PDF = QIcon::fromTheme("application-pdf");
+ Phase = QIcon::fromTheme("phase");
+ PrintAllPages = QIcon::fromTheme("all_pages");
+ Printer = QIcon::fromTheme("printer");
+ PrintLandscape = QIcon::fromTheme("landscape");
+ PrintPortrait = QIcon::fromTheme("portrait");
+ PrintTwoPages = QIcon::fromTheme("two_pages");
+ Projects = QIcon::fromTheme("project");
+ ProjectClose = QIcon::fromTheme("project-close");
+ ProjectNew = QIcon::fromTheme("project-new");
+ ProjectFile.addFile(":/ico/breeze-icons/16x16/mimetypes/application-x-qet-project.png");
+ ProjectFile.addFile(":/ico/breeze-icons/22x22/mimetypes/application-x-qet-project.png");
+ ProjectFile.addFile(":/ico/breeze-icons/32x32/mimetypes/application-x-qet-project.png");
+ ProjectProperties = QIcon::fromTheme("project-properties");
+ QETDonate = QIcon::fromTheme("help-donate");
+ QETDownload = QIcon::fromTheme("edit-download");
+ QETIcon.addFile(":/ico/256x256/qelectrotech.png");
+ // The elements panel shows the project root with this icon in a 50 px
+ // slot meant for element previews. The theme name "project" also
+ // carries the 128 px file used by the configuration dialog, and on a
+ // 2x display Qt's theme loader would pick it and fill the slot. Load
+ // the two small files directly so the item stays at 16/22 px.
+ ProjectFileGP.addFile(":/ico/themes/qet/16x16/project.png");
+ ProjectFileGP.addFile(":/ico/themes/qet/22x22/project.png");
+ QETLogo = QIcon::fromTheme("qet");
+ QETManual = QIcon::fromTheme("help-contents");
+ QETLogo.addFile(":/ico/256x256/qet.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/128x128/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/16x16/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/22x22/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/256x256/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/32x32/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/48x48/apps/qelectrotech.png");
+ QETOxygenLogo.addFile(":/ico/breeze-icons/64x64/apps/qelectrotech.png");
+ QETVideo = QIcon::fromTheme("kdenlive-show-video");
+ QtLogo = QIcon::fromTheme("qt");
+ Raise = QIcon::fromTheme("raise");
+ RectToBezier = QIcon::fromTheme("rect-to-bezier");
+ RectToPolyline = QIcon::fromTheme("rect-to-polyline");
+ Remove = QIcon::fromTheme("list-remove");
+ resize_image = QIcon::fromTheme("transform-scale");
+ Restore = QIcon::fromTheme("restaurer");
+ RunDxf = QIcon::fromTheme("run-dxf");
+ SendBackward = QIcon::fromTheme("send_backward");
+ Settings = QIcon::fromTheme("settings");
+ SinglePage = QIcon::fromTheme("single_page");
+ South = QIcon::fromTheme("south");
+ Start = QIcon::fromTheme("start");
+ TableOfContent = QIcon::fromTheme("table-of-content");
+ Terminal = QIcon::fromTheme("terminal");
+ TerminalStrip = QIcon::fromTheme("terminalstrip");
+ TitleBlock = QIcon::fromTheme("label");
+ TitleBlockBottom = QIcon::fromTheme("titleblock-bottom");
+ TitleBlockRight = QIcon::fromTheme("titleblock-right");
+ TransformCrop = QIcon::fromTheme("transform-crop");
+ TransformRotate = QIcon::fromTheme("transform-rotate");
+ UserInformations = QIcon::fromTheme("preferences-desktop-user");
+ ViewFitWidth = QIcon::fromTheme("view_fit_width");
+ ViewFitWindow = QIcon::fromTheme("view-fit-window");
+ ViewMove = QIcon::fromTheme("move");
if (rtl) {
- ViewRefresh.addPixmap(QPixmap(":/ico/16x16/view-refresh.png").transformed(reverse));
- ViewRefresh.addPixmap(QPixmap(":/ico/22x22/view-refresh.png").transformed(reverse));
+ ViewRefresh.addPixmap(QIcon::fromTheme("view-refresh").pixmap(16).transformed(reverse));
+ ViewRefresh.addPixmap(QIcon::fromTheme("view-refresh").pixmap(22).transformed(reverse));
} else {
- ViewRefresh .addFile(":/ico/16x16/view-refresh.png");
- ViewRefresh .addFile(":/ico/22x22/view-refresh.png");
+ ViewRefresh = QIcon::fromTheme("view-refresh");
}
- West .addFile(":/ico/16x16/west.png");
- WindowNew .addFile(":/ico/16x16/window-new.png");
- WindowNew .addFile(":/ico/22x22/window-new.png");
- XmlTextFile .addFile(":/ico/16x16/text-xml.png");
- XmlTextFile .addFile(":/ico/22x22/text-xml.png");
- XmlTextFile .addFile(":/ico/32x32/text-xml.png");
- ZoomDraw .addFile(":/ico/16x16/zoom-draw.png");
- ZoomDraw .addFile(":/ico/22x22/zoom-draw.png");
- ZoomFitBest .addFile(":/ico/16x16/zoom-fit-best.png");
- ZoomFitBest .addFile(":/ico/22x22/zoom-fit-best.png");
- ZoomIn .addFile(":/ico/16x16/zoom-in.png");
- ZoomIn .addFile(":/ico/22x22/zoom-in.png");
- ZoomOriginal .addFile(":/ico/16x16/zoom-original.png");
- ZoomOriginal .addFile(":/ico/22x22/zoom-original.png");
- ZoomOut .addFile(":/ico/16x16/zoom-out.png");
- ZoomOut .addFile(":/ico/22x22/zoom-out.png");
- sa .addFile(":/ico/24x16/sa.png");
- br .addFile(":/ico/24x16/br.png");
- catalonia .addFile(":/ico/24x16/catalonia.png");
- cs .addFile(":/ico/24x16/cs.png");
- da .addFile(":/ico/24x16/dk.png");
- de .addFile(":/ico/24x16/de.png");
- gr .addFile(":/ico/24x16/gr.png");
- en .addFile(":/ico/24x16/en.png");
- es .addFile(":/ico/24x16/es.png");
- fr .addFile(":/ico/24x16/fr.png");
- hr .addFile(":/ico/24x16/hr.png");
- hu .addFile(":/ico/24x16/hu.png");
- it .addFile(":/ico/24x16/it.png");
- jp .addFile(":/ico/24x16/jp.png");
- ko .addFile(":/ico/24x16/kr.png");
- pl .addFile(":/ico/24x16/pl.png");
- pt .addFile(":/ico/24x16/pt.png");
- ro .addFile(":/ico/24x16/ro.png");
- ru .addFile(":/ico/24x16/ru.png");
- sl .addFile(":/ico/24x16/sl.png");
- nl .addFile(":/ico/24x16/nl.png");
- no .addFile(":/ico/24x16/no.png");
- nl_BE .addFile(":/ico/24x16/nl_BE.png");
- tr .addFile(":/ico/24x16/tr.png");
- uk .addFile(":/ico/24x16/ua.png");
- mn .addFile(":/ico/24x16/mn.png");
- zh .addFile(":/ico/24x16/zh.png");
- se .addFile(":/ico/24x16/se.png");
- translation .addFile(":/ico/22x22/applications-development-translation.png");
- listDrawings .addFile(":/ico/48x48/view-pim-journal.png");
- AutoNum .addFile(":/ico/128x128/plasmagik.png");
- sub .addFile(":/ico/22x22/format-text-subscript.png");
- super .addFile(":/ico/22x22/format-text-superscript.png");
- textGroup .addFile(":/ico/16x16/object-group.png");
- ElementMaster .addFile(":/ico/16x16/element-master.png");
- ElementSlave .addFile(":/ico/16x16/element-slave.png");
- FolioXrefComing .addFile(":/ico/16x16/folio-ref-coming.png");
- ElementTerminal .addFile(":/ico/16x16/terminal.png");
- ColorBrown .addFile(":/ico/22x22/color/color-brown.png");
- ColorGray .addFile(":/ico/22x22/color/color-gray.png");
- ColorOrange .addFile(":/ico/22x22/color/color-orange.png");
- ColorPurple .addFile(":/ico/22x22/color/color-purple.png");
- ColorHTMLPinkPink .addFile(":/ico/22x22/color/color-01-pink-01-pink.png");
- ColorHTMLPinkLightPink .addFile(":/ico/22x22/color/color-01-pink-02-lightpink.png");
- ColorHTMLPinkHotPink .addFile(":/ico/22x22/color/color-01-pink-03-hotpink.png");
- ColorHTMLPinkDeepPink .addFile(":/ico/22x22/color/color-01-pink-04-deeppink.png");
- ColorHTMLPinkPaleVioletRed .addFile(":/ico/22x22/color/color-01-pink-05-palevioletred.png");
- ColorHTMLPinkMediumVioletRed .addFile(":/ico/22x22/color/color-01-pink-06-mediumvioletred.png");
- ColorHTMLRedLightSalmon .addFile(":/ico/22x22/color/color-02-red-01-lightsalmon.png");
- ColorHTMLRedSalmon .addFile(":/ico/22x22/color/color-02-red-02-salmon.png");
- ColorHTMLRedDarkSalmon .addFile(":/ico/22x22/color/color-02-red-03-darksalmon.png");
- ColorHTMLRedLightCoral .addFile(":/ico/22x22/color/color-02-red-04-lightcoral.png");
- ColorHTMLRedIndianRed .addFile(":/ico/22x22/color/color-02-red-05-indianred.png");
- ColorHTMLRedCrimson .addFile(":/ico/22x22/color/color-02-red-06-crimson.png");
- ColorHTMLRedFirebrick .addFile(":/ico/22x22/color/color-02-red-07-firebrick.png");
- ColorHTMLRedDarkRed .addFile(":/ico/22x22/color/color-02-red-08-darkred.png");
- ColorHTMLRedRed .addFile(":/ico/22x22/color/color-02-red-09-red.png");
- ColorHTMLOrangeOrangeRed .addFile(":/ico/22x22/color/color-03-orange-01-orangered.png");
- ColorHTMLOrangeTomato .addFile(":/ico/22x22/color/color-03-orange-02-tomato.png");
- ColorHTMLOrangeCoral .addFile(":/ico/22x22/color/color-03-orange-03-coral.png");
- ColorHTMLOrangeDarkOrange .addFile(":/ico/22x22/color/color-03-orange-04-darkorange.png");
- ColorHTMLOrangeOrange .addFile(":/ico/22x22/color/color-03-orange-05-orange.png");
- ColorHTMLYellowYellow .addFile(":/ico/22x22/color/color-04-yellow-01-yellow.png");
- ColorHTMLYellowLightYellow .addFile(":/ico/22x22/color/color-04-yellow-02-lightyellow.png");
- ColorHTMLYellowLemonChiffon .addFile(":/ico/22x22/color/color-04-yellow-03-lemonchiffon.png");
+ West = QIcon::fromTheme("west");
+ WindowNew = QIcon::fromTheme("window-new");
+ XmlTextFile = QIcon::fromTheme("text-xml");
+ ZoomDraw = QIcon::fromTheme("zoom-draw");
+ ZoomFitBest = QIcon::fromTheme("zoom-fit-best");
+ ZoomIn = QIcon::fromTheme("zoom-in");
+ ZoomOriginal = QIcon::fromTheme("zoom-original");
+ ZoomOut = QIcon::fromTheme("zoom-out");
+ sa.addFile(":/ico/24x16/sa.png");
+ br.addFile(":/ico/24x16/br.png");
+ catalonia.addFile(":/ico/24x16/catalonia.png");
+ cs.addFile(":/ico/24x16/cs.png");
+ da.addFile(":/ico/24x16/dk.png");
+ de.addFile(":/ico/24x16/de.png");
+ gr.addFile(":/ico/24x16/gr.png");
+ en.addFile(":/ico/24x16/en.png");
+ es.addFile(":/ico/24x16/es.png");
+ fr.addFile(":/ico/24x16/fr.png");
+ hr.addFile(":/ico/24x16/hr.png");
+ hu.addFile(":/ico/24x16/hu.png");
+ it.addFile(":/ico/24x16/it.png");
+ jp.addFile(":/ico/24x16/jp.png");
+ ko.addFile(":/ico/24x16/kr.png");
+ pl.addFile(":/ico/24x16/pl.png");
+ pt.addFile(":/ico/24x16/pt.png");
+ ro.addFile(":/ico/24x16/ro.png");
+ ru.addFile(":/ico/24x16/ru.png");
+ sl.addFile(":/ico/24x16/sl.png");
+ nl.addFile(":/ico/24x16/nl.png");
+ no.addFile(":/ico/24x16/no.png");
+ nl_BE.addFile(":/ico/24x16/nl_BE.png");
+ tr.addFile(":/ico/24x16/tr.png");
+ uk.addFile(":/ico/24x16/ua.png");
+ mn.addFile(":/ico/24x16/mn.png");
+ zh.addFile(":/ico/24x16/zh.png");
+ se.addFile(":/ico/24x16/se.png");
+ translation = QIcon::fromTheme("applications-development-translation");
+ listDrawings = QIcon::fromTheme("view-pim-journal");
+ AutoNum = QIcon::fromTheme("plasmagik");
+ sub = QIcon::fromTheme("format-text-subscript");
+ super = QIcon::fromTheme("format-text-superscript");
+ textGroup = QIcon::fromTheme("object-group");
+ ElementMaster = QIcon::fromTheme("element-master");
+ ElementSlave = QIcon::fromTheme("element-slave");
+ FolioXrefComing = QIcon::fromTheme("folio-ref-coming");
+ ElementTerminal = QIcon::fromTheme("terminal");
+ ColorBrown.addFile(":/ico/22x22/color/color-brown.png");
+ ColorGray.addFile(":/ico/22x22/color/color-gray.png");
+ ColorOrange.addFile(":/ico/22x22/color/color-orange.png");
+ ColorPurple.addFile(":/ico/22x22/color/color-purple.png");
+ ColorHTMLPinkPink.addFile(":/ico/22x22/color/color-01-pink-01-pink.png");
+ ColorHTMLPinkLightPink.addFile(":/ico/22x22/color/color-01-pink-02-lightpink.png");
+ ColorHTMLPinkHotPink.addFile(":/ico/22x22/color/color-01-pink-03-hotpink.png");
+ ColorHTMLPinkDeepPink.addFile(":/ico/22x22/color/color-01-pink-04-deeppink.png");
+ ColorHTMLPinkPaleVioletRed.addFile(":/ico/22x22/color/color-01-pink-05-palevioletred.png");
+ ColorHTMLPinkMediumVioletRed.addFile(":/ico/22x22/color/color-01-pink-06-mediumvioletred.png");
+ ColorHTMLRedLightSalmon.addFile(":/ico/22x22/color/color-02-red-01-lightsalmon.png");
+ ColorHTMLRedSalmon.addFile(":/ico/22x22/color/color-02-red-02-salmon.png");
+ ColorHTMLRedDarkSalmon.addFile(":/ico/22x22/color/color-02-red-03-darksalmon.png");
+ ColorHTMLRedLightCoral.addFile(":/ico/22x22/color/color-02-red-04-lightcoral.png");
+ ColorHTMLRedIndianRed.addFile(":/ico/22x22/color/color-02-red-05-indianred.png");
+ ColorHTMLRedCrimson.addFile(":/ico/22x22/color/color-02-red-06-crimson.png");
+ ColorHTMLRedFirebrick.addFile(":/ico/22x22/color/color-02-red-07-firebrick.png");
+ ColorHTMLRedDarkRed.addFile(":/ico/22x22/color/color-02-red-08-darkred.png");
+ ColorHTMLRedRed.addFile(":/ico/22x22/color/color-02-red-09-red.png");
+ ColorHTMLOrangeOrangeRed.addFile(":/ico/22x22/color/color-03-orange-01-orangered.png");
+ ColorHTMLOrangeTomato.addFile(":/ico/22x22/color/color-03-orange-02-tomato.png");
+ ColorHTMLOrangeCoral.addFile(":/ico/22x22/color/color-03-orange-03-coral.png");
+ ColorHTMLOrangeDarkOrange.addFile(":/ico/22x22/color/color-03-orange-04-darkorange.png");
+ ColorHTMLOrangeOrange.addFile(":/ico/22x22/color/color-03-orange-05-orange.png");
+ ColorHTMLYellowYellow.addFile(":/ico/22x22/color/color-04-yellow-01-yellow.png");
+ ColorHTMLYellowLightYellow.addFile(":/ico/22x22/color/color-04-yellow-02-lightyellow.png");
+ ColorHTMLYellowLemonChiffon.addFile(":/ico/22x22/color/color-04-yellow-03-lemonchiffon.png");
ColorHTMLYellowLightGoldenrodYellow.addFile(":/ico/22x22/color/color-04-yellow-04-lightgoldenrodyellow.png");
- ColorHTMLYellowPapayaWhip .addFile(":/ico/22x22/color/color-04-yellow-05-papayawhip.png");
- ColorHTMLYellowMoccasin .addFile(":/ico/22x22/color/color-04-yellow-06-moccasin.png");
- ColorHTMLYellowPeachPuff .addFile(":/ico/22x22/color/color-04-yellow-07-peachpuff.png");
- ColorHTMLYellowPaleGoldenrod .addFile(":/ico/22x22/color/color-04-yellow-08-palegoldenrod.png");
- ColorHTMLYellowKhaki .addFile(":/ico/22x22/color/color-04-yellow-09-khaki.png");
- ColorHTMLYellowDarkKhaki .addFile(":/ico/22x22/color/color-04-yellow-10-darkkhaki.png");
- ColorHTMLYellowGold .addFile(":/ico/22x22/color/color-04-yellow-11-gold.png");
- ColorHTMLBrownCornsilk .addFile(":/ico/22x22/color/color-05-brown-01-cornsilk.png");
- ColorHTMLBrownBlanchedAlmond .addFile(":/ico/22x22/color/color-05-brown-02-blanchedalmond.png");
- ColorHTMLBrownBisque .addFile(":/ico/22x22/color/color-05-brown-03-bisque.png");
- ColorHTMLBrownNavajoWhite .addFile(":/ico/22x22/color/color-05-brown-04-navajowhite.png");
- ColorHTMLBrownWheat .addFile(":/ico/22x22/color/color-05-brown-05-wheat.png");
- ColorHTMLBrownBurlywood .addFile(":/ico/22x22/color/color-05-brown-06-burlywood.png");
- ColorHTMLBrownTan .addFile(":/ico/22x22/color/color-05-brown-07-tan.png");
- ColorHTMLBrownRosyBrown .addFile(":/ico/22x22/color/color-05-brown-08-rosybrown.png");
- ColorHTMLBrownSandyBrown .addFile(":/ico/22x22/color/color-05-brown-09-sandybrown.png");
- ColorHTMLBrownGoldenrod .addFile(":/ico/22x22/color/color-05-brown-10-goldenrod.png");
- ColorHTMLBrownDarkGoldenrod .addFile(":/ico/22x22/color/color-05-brown-11-darkgoldenrod.png");
- ColorHTMLBrownPeru .addFile(":/ico/22x22/color/color-05-brown-12-peru.png");
- ColorHTMLBrownChocolate .addFile(":/ico/22x22/color/color-05-brown-13-chocolate.png");
- ColorHTMLBrownSaddleBrown .addFile(":/ico/22x22/color/color-05-brown-14-saddlebrown.png");
- ColorHTMLBrownSienna .addFile(":/ico/22x22/color/color-05-brown-15-sienna.png");
- ColorHTMLBrownBrown .addFile(":/ico/22x22/color/color-05-brown-16-brown.png");
- ColorHTMLBrownMaroon .addFile(":/ico/22x22/color/color-05-brown-17-maroon.png");
- ColorHTMLGreenDarkOliveGreen .addFile(":/ico/22x22/color/color-06-green-01-darkolivegreen.png");
- ColorHTMLGreenOlive .addFile(":/ico/22x22/color/color-06-green-02-olive.png");
- ColorHTMLGreenOliveDrab .addFile(":/ico/22x22/color/color-06-green-03-olivedrab.png");
- ColorHTMLGreenYellowGreen .addFile(":/ico/22x22/color/color-06-green-04-yellowgreen.png");
- ColorHTMLGreenLimeGreen .addFile(":/ico/22x22/color/color-06-green-05-limegreen.png");
- ColorHTMLGreenLime .addFile(":/ico/22x22/color/color-06-green-06-lime.png");
- ColorHTMLGreenLawnGreen .addFile(":/ico/22x22/color/color-06-green-07-lawngreen.png");
- ColorHTMLGreenChartreuse .addFile(":/ico/22x22/color/color-06-green-08-chartreuse.png");
- ColorHTMLGreenGreenYellow .addFile(":/ico/22x22/color/color-06-green-09-greenyellow.png");
- ColorHTMLGreenSpringGreen .addFile(":/ico/22x22/color/color-06-green-10-springgreen.png");
- ColorHTMLGreenMediumSpringGreen .addFile(":/ico/22x22/color/color-06-green-11-mediumspringgreen.png");
- ColorHTMLGreenLightGreen .addFile(":/ico/22x22/color/color-06-green-12-lightgreen.png");
- ColorHTMLGreenPaleGreen .addFile(":/ico/22x22/color/color-06-green-13-palegreen.png");
- ColorHTMLGreenDarkSeaGreen .addFile(":/ico/22x22/color/color-06-green-14-darkseagreen.png");
- ColorHTMLGreenMediumAquamarine .addFile(":/ico/22x22/color/color-06-green-15-mediumaquamarine.png");
- ColorHTMLGreenMediumSeaGreen .addFile(":/ico/22x22/color/color-06-green-16-mediumseagreen.png");
- ColorHTMLGreenSeaGreen .addFile(":/ico/22x22/color/color-06-green-17-seagreen.png");
- ColorHTMLGreenForestGreen .addFile(":/ico/22x22/color/color-06-green-18-forestgreen.png");
- ColorHTMLGreenGreen .addFile(":/ico/22x22/color/color-06-green-19-green.png");
- ColorHTMLGreenDarkGreen .addFile(":/ico/22x22/color/color-06-green-20-darkgreen.png");
- ColorHTMLCyanAqua .addFile(":/ico/22x22/color/color-07-cyan-01-aqua.png");
- ColorHTMLCyanCyan .addFile(":/ico/22x22/color/color-07-cyan-02-cyan.png");
- ColorHTMLCyanLightCyan .addFile(":/ico/22x22/color/color-07-cyan-03-lightcyan.png");
- ColorHTMLCyanPaleTurquoise .addFile(":/ico/22x22/color/color-07-cyan-04-paleturquoise.png");
- ColorHTMLCyanAquamarine .addFile(":/ico/22x22/color/color-07-cyan-05-aquamarine.png");
- ColorHTMLCyanTurquoise .addFile(":/ico/22x22/color/color-07-cyan-06-turquoise.png");
- ColorHTMLCyanMediumTurquoise .addFile(":/ico/22x22/color/color-07-cyan-07-mediumturquoise.png");
- ColorHTMLCyanDarkTurquoise .addFile(":/ico/22x22/color/color-07-cyan-08-darkturquoise.png");
- ColorHTMLCyanLightSeaGreen .addFile(":/ico/22x22/color/color-07-cyan-09-lightseagreen.png");
- ColorHTMLCyanCadetBlue .addFile(":/ico/22x22/color/color-07-cyan-10-cadetblue.png");
- ColorHTMLCyanDarkCyan .addFile(":/ico/22x22/color/color-07-cyan-11-darkcyan.png");
- ColorHTMLCyanTeal .addFile(":/ico/22x22/color/color-07-cyan-12-teal.png");
- ColorHTMLBlueLightSteelBlue .addFile(":/ico/22x22/color/color-08-blue-01-lightsteelblue.png");
- ColorHTMLBluePowderBlue .addFile(":/ico/22x22/color/color-08-blue-02-powderblue.png");
- ColorHTMLBlueLightBlue .addFile(":/ico/22x22/color/color-08-blue-03-lightblue.png");
- ColorHTMLBlueSkyBlue .addFile(":/ico/22x22/color/color-08-blue-04-skyblue.png");
- ColorHTMLBlueLightSkyBlue .addFile(":/ico/22x22/color/color-08-blue-05-lightskyblue.png");
- ColorHTMLBlueDeepSkyBlue .addFile(":/ico/22x22/color/color-08-blue-06-deepskyblue.png");
- ColorHTMLBlueDodgerBlue .addFile(":/ico/22x22/color/color-08-blue-07-dodgerblue.png");
- ColorHTMLBlueCornflowerBlue .addFile(":/ico/22x22/color/color-08-blue-08-cornflowerblue.png");
- ColorHTMLBlueSteelBlue .addFile(":/ico/22x22/color/color-08-blue-09-steelblue.png");
- ColorHTMLBlueRoyalBlue .addFile(":/ico/22x22/color/color-08-blue-10-royalblue.png");
- ColorHTMLBlueBlue .addFile(":/ico/22x22/color/color-08-blue-11-blue.png");
- ColorHTMLBlueMediumBlue .addFile(":/ico/22x22/color/color-08-blue-12-mediumblue.png");
- ColorHTMLBlueDarkBlue .addFile(":/ico/22x22/color/color-08-blue-13-darkblue.png");
- ColorHTMLBlueNavy .addFile(":/ico/22x22/color/color-08-blue-14-navy.png");
- ColorHTMLBlueMidnightBlue .addFile(":/ico/22x22/color/color-08-blue-15-midnightblue.png");
- ColorHTMLPurpleLavender .addFile(":/ico/22x22/color/color-09-purple-01-lavender.png");
- ColorHTMLPurpleThistle .addFile(":/ico/22x22/color/color-09-purple-02-thistle.png");
- ColorHTMLPurplePlum .addFile(":/ico/22x22/color/color-09-purple-03-plum.png");
- ColorHTMLPurpleViolet .addFile(":/ico/22x22/color/color-09-purple-04-violet.png");
- ColorHTMLPurpleOrchid .addFile(":/ico/22x22/color/color-09-purple-05-orchid.png");
- ColorHTMLPurpleFuchsia .addFile(":/ico/22x22/color/color-09-purple-06-fuchsia.png");
- ColorHTMLPurpleMagenta .addFile(":/ico/22x22/color/color-09-purple-07-magenta.png");
- ColorHTMLPurpleMediumOrchid .addFile(":/ico/22x22/color/color-09-purple-08-mediumorchid.png");
- ColorHTMLPurpleMediumPurple .addFile(":/ico/22x22/color/color-09-purple-09-mediumpurple.png");
- ColorHTMLPurpleBlueViolet .addFile(":/ico/22x22/color/color-09-purple-10-blueviolet.png");
- ColorHTMLPurpleDarkViolet .addFile(":/ico/22x22/color/color-09-purple-11-darkviolet.png");
- ColorHTMLPurpleDarkOrchid .addFile(":/ico/22x22/color/color-09-purple-12-darkorchid.png");
- ColorHTMLPurpleDarkMagenta .addFile(":/ico/22x22/color/color-09-purple-13-darkmagenta.png");
- ColorHTMLPurplePurple .addFile(":/ico/22x22/color/color-09-purple-14-purple.png");
- ColorHTMLPurpleIndigo .addFile(":/ico/22x22/color/color-09-purple-15-indigo.png");
- ColorHTMLPurpleDarkSlateBlue .addFile(":/ico/22x22/color/color-09-purple-16-darkslateblue.png");
- ColorHTMLPurpleSlateBlue .addFile(":/ico/22x22/color/color-09-purple-17-slateblue.png");
- ColorHTMLPurpleMediumSlateBlue .addFile(":/ico/22x22/color/color-09-purple-18-mediumslateblue.png");
- ColorHTMLWhiteWhite .addFile(":/ico/22x22/color/color-10-white-01-white.png");
- ColorHTMLWhiteSnow .addFile(":/ico/22x22/color/color-10-white-02-snow.png");
- ColorHTMLWhiteHoneydew .addFile(":/ico/22x22/color/color-10-white-03-honeydew.png");
- ColorHTMLWhiteMintCream .addFile(":/ico/22x22/color/color-10-white-04-mintcream.png");
- ColorHTMLWhiteAzure .addFile(":/ico/22x22/color/color-10-white-05-azure.png");
- ColorHTMLWhiteAliceBlue .addFile(":/ico/22x22/color/color-10-white-06-aliceblue.png");
- ColorHTMLWhiteGhostWhite .addFile(":/ico/22x22/color/color-10-white-07-ghostwhite.png");
- ColorHTMLWhiteWhiteSmoke .addFile(":/ico/22x22/color/color-10-white-08-whitesmoke.png");
- ColorHTMLWhiteSeashell .addFile(":/ico/22x22/color/color-10-white-09-seashell.png");
- ColorHTMLWhiteBeige .addFile(":/ico/22x22/color/color-10-white-10-beige.png");
- ColorHTMLWhiteOldLace .addFile(":/ico/22x22/color/color-10-white-11-oldlace.png");
- ColorHTMLWhiteFloralWhite .addFile(":/ico/22x22/color/color-10-white-12-floralwhite.png");
- ColorHTMLWhiteIvory .addFile(":/ico/22x22/color/color-10-white-13-ivory.png");
- ColorHTMLWhiteAntiqueWhite .addFile(":/ico/22x22/color/color-10-white-14-antiquewhite.png");
- ColorHTMLWhiteLinen .addFile(":/ico/22x22/color/color-10-white-15-linen.png");
- ColorHTMLWhiteLavenderBlush .addFile(":/ico/22x22/color/color-10-white-16-lavenderblush.png");
- ColorHTMLWhiteMistyRose .addFile(":/ico/22x22/color/color-10-white-17-mistyrose.png");
- ColorHTMLGrayGainsboro .addFile(":/ico/22x22/color/color-11-gray-01-gainsboro.png");
- ColorHTMLGrayLightGray .addFile(":/ico/22x22/color/color-11-gray-02-lightgray.png");
- ColorHTMLGraySilver .addFile(":/ico/22x22/color/color-11-gray-03-silver.png");
- ColorHTMLGrayDarkGray .addFile(":/ico/22x22/color/color-11-gray-04-darkgray.png");
- ColorHTMLGrayGray .addFile(":/ico/22x22/color/color-11-gray-05-gray.png");
- ColorHTMLGrayDimGray .addFile(":/ico/22x22/color/color-11-gray-06-dimgray.png");
- ColorHTMLGrayLightSlateGray .addFile(":/ico/22x22/color/color-11-gray-07-lightslategray.png");
- ColorHTMLGraySlateGray .addFile(":/ico/22x22/color/color-11-gray-08-slategray.png");
- ColorHTMLGrayDarkSlateGray .addFile(":/ico/22x22/color/color-11-gray-09-darkslategray.png");
- ColorHTMLGrayBlack .addFile(":/ico/22x22/color/color-11-gray-10-black.png");
+ ColorHTMLYellowPapayaWhip.addFile(":/ico/22x22/color/color-04-yellow-05-papayawhip.png");
+ ColorHTMLYellowMoccasin.addFile(":/ico/22x22/color/color-04-yellow-06-moccasin.png");
+ ColorHTMLYellowPeachPuff.addFile(":/ico/22x22/color/color-04-yellow-07-peachpuff.png");
+ ColorHTMLYellowPaleGoldenrod.addFile(":/ico/22x22/color/color-04-yellow-08-palegoldenrod.png");
+ ColorHTMLYellowKhaki.addFile(":/ico/22x22/color/color-04-yellow-09-khaki.png");
+ ColorHTMLYellowDarkKhaki.addFile(":/ico/22x22/color/color-04-yellow-10-darkkhaki.png");
+ ColorHTMLYellowGold.addFile(":/ico/22x22/color/color-04-yellow-11-gold.png");
+ ColorHTMLBrownCornsilk.addFile(":/ico/22x22/color/color-05-brown-01-cornsilk.png");
+ ColorHTMLBrownBlanchedAlmond.addFile(":/ico/22x22/color/color-05-brown-02-blanchedalmond.png");
+ ColorHTMLBrownBisque.addFile(":/ico/22x22/color/color-05-brown-03-bisque.png");
+ ColorHTMLBrownNavajoWhite.addFile(":/ico/22x22/color/color-05-brown-04-navajowhite.png");
+ ColorHTMLBrownWheat.addFile(":/ico/22x22/color/color-05-brown-05-wheat.png");
+ ColorHTMLBrownBurlywood.addFile(":/ico/22x22/color/color-05-brown-06-burlywood.png");
+ ColorHTMLBrownTan.addFile(":/ico/22x22/color/color-05-brown-07-tan.png");
+ ColorHTMLBrownRosyBrown.addFile(":/ico/22x22/color/color-05-brown-08-rosybrown.png");
+ ColorHTMLBrownSandyBrown.addFile(":/ico/22x22/color/color-05-brown-09-sandybrown.png");
+ ColorHTMLBrownGoldenrod.addFile(":/ico/22x22/color/color-05-brown-10-goldenrod.png");
+ ColorHTMLBrownDarkGoldenrod.addFile(":/ico/22x22/color/color-05-brown-11-darkgoldenrod.png");
+ ColorHTMLBrownPeru.addFile(":/ico/22x22/color/color-05-brown-12-peru.png");
+ ColorHTMLBrownChocolate.addFile(":/ico/22x22/color/color-05-brown-13-chocolate.png");
+ ColorHTMLBrownSaddleBrown.addFile(":/ico/22x22/color/color-05-brown-14-saddlebrown.png");
+ ColorHTMLBrownSienna.addFile(":/ico/22x22/color/color-05-brown-15-sienna.png");
+ ColorHTMLBrownBrown.addFile(":/ico/22x22/color/color-05-brown-16-brown.png");
+ ColorHTMLBrownMaroon.addFile(":/ico/22x22/color/color-05-brown-17-maroon.png");
+ ColorHTMLGreenDarkOliveGreen.addFile(":/ico/22x22/color/color-06-green-01-darkolivegreen.png");
+ ColorHTMLGreenOlive.addFile(":/ico/22x22/color/color-06-green-02-olive.png");
+ ColorHTMLGreenOliveDrab.addFile(":/ico/22x22/color/color-06-green-03-olivedrab.png");
+ ColorHTMLGreenYellowGreen.addFile(":/ico/22x22/color/color-06-green-04-yellowgreen.png");
+ ColorHTMLGreenLimeGreen.addFile(":/ico/22x22/color/color-06-green-05-limegreen.png");
+ ColorHTMLGreenLime.addFile(":/ico/22x22/color/color-06-green-06-lime.png");
+ ColorHTMLGreenLawnGreen.addFile(":/ico/22x22/color/color-06-green-07-lawngreen.png");
+ ColorHTMLGreenChartreuse.addFile(":/ico/22x22/color/color-06-green-08-chartreuse.png");
+ ColorHTMLGreenGreenYellow.addFile(":/ico/22x22/color/color-06-green-09-greenyellow.png");
+ ColorHTMLGreenSpringGreen.addFile(":/ico/22x22/color/color-06-green-10-springgreen.png");
+ ColorHTMLGreenMediumSpringGreen.addFile(":/ico/22x22/color/color-06-green-11-mediumspringgreen.png");
+ ColorHTMLGreenLightGreen.addFile(":/ico/22x22/color/color-06-green-12-lightgreen.png");
+ ColorHTMLGreenPaleGreen.addFile(":/ico/22x22/color/color-06-green-13-palegreen.png");
+ ColorHTMLGreenDarkSeaGreen.addFile(":/ico/22x22/color/color-06-green-14-darkseagreen.png");
+ ColorHTMLGreenMediumAquamarine.addFile(":/ico/22x22/color/color-06-green-15-mediumaquamarine.png");
+ ColorHTMLGreenMediumSeaGreen.addFile(":/ico/22x22/color/color-06-green-16-mediumseagreen.png");
+ ColorHTMLGreenSeaGreen.addFile(":/ico/22x22/color/color-06-green-17-seagreen.png");
+ ColorHTMLGreenForestGreen.addFile(":/ico/22x22/color/color-06-green-18-forestgreen.png");
+ ColorHTMLGreenGreen.addFile(":/ico/22x22/color/color-06-green-19-green.png");
+ ColorHTMLGreenDarkGreen.addFile(":/ico/22x22/color/color-06-green-20-darkgreen.png");
+ ColorHTMLCyanAqua.addFile(":/ico/22x22/color/color-07-cyan-01-aqua.png");
+ ColorHTMLCyanCyan.addFile(":/ico/22x22/color/color-07-cyan-02-cyan.png");
+ ColorHTMLCyanLightCyan.addFile(":/ico/22x22/color/color-07-cyan-03-lightcyan.png");
+ ColorHTMLCyanPaleTurquoise.addFile(":/ico/22x22/color/color-07-cyan-04-paleturquoise.png");
+ ColorHTMLCyanAquamarine.addFile(":/ico/22x22/color/color-07-cyan-05-aquamarine.png");
+ ColorHTMLCyanTurquoise.addFile(":/ico/22x22/color/color-07-cyan-06-turquoise.png");
+ ColorHTMLCyanMediumTurquoise.addFile(":/ico/22x22/color/color-07-cyan-07-mediumturquoise.png");
+ ColorHTMLCyanDarkTurquoise.addFile(":/ico/22x22/color/color-07-cyan-08-darkturquoise.png");
+ ColorHTMLCyanLightSeaGreen.addFile(":/ico/22x22/color/color-07-cyan-09-lightseagreen.png");
+ ColorHTMLCyanCadetBlue.addFile(":/ico/22x22/color/color-07-cyan-10-cadetblue.png");
+ ColorHTMLCyanDarkCyan.addFile(":/ico/22x22/color/color-07-cyan-11-darkcyan.png");
+ ColorHTMLCyanTeal.addFile(":/ico/22x22/color/color-07-cyan-12-teal.png");
+ ColorHTMLBlueLightSteelBlue.addFile(":/ico/22x22/color/color-08-blue-01-lightsteelblue.png");
+ ColorHTMLBluePowderBlue.addFile(":/ico/22x22/color/color-08-blue-02-powderblue.png");
+ ColorHTMLBlueLightBlue.addFile(":/ico/22x22/color/color-08-blue-03-lightblue.png");
+ ColorHTMLBlueSkyBlue.addFile(":/ico/22x22/color/color-08-blue-04-skyblue.png");
+ ColorHTMLBlueLightSkyBlue.addFile(":/ico/22x22/color/color-08-blue-05-lightskyblue.png");
+ ColorHTMLBlueDeepSkyBlue.addFile(":/ico/22x22/color/color-08-blue-06-deepskyblue.png");
+ ColorHTMLBlueDodgerBlue.addFile(":/ico/22x22/color/color-08-blue-07-dodgerblue.png");
+ ColorHTMLBlueCornflowerBlue.addFile(":/ico/22x22/color/color-08-blue-08-cornflowerblue.png");
+ ColorHTMLBlueSteelBlue.addFile(":/ico/22x22/color/color-08-blue-09-steelblue.png");
+ ColorHTMLBlueRoyalBlue.addFile(":/ico/22x22/color/color-08-blue-10-royalblue.png");
+ ColorHTMLBlueBlue.addFile(":/ico/22x22/color/color-08-blue-11-blue.png");
+ ColorHTMLBlueMediumBlue.addFile(":/ico/22x22/color/color-08-blue-12-mediumblue.png");
+ ColorHTMLBlueDarkBlue.addFile(":/ico/22x22/color/color-08-blue-13-darkblue.png");
+ ColorHTMLBlueNavy.addFile(":/ico/22x22/color/color-08-blue-14-navy.png");
+ ColorHTMLBlueMidnightBlue.addFile(":/ico/22x22/color/color-08-blue-15-midnightblue.png");
+ ColorHTMLPurpleLavender.addFile(":/ico/22x22/color/color-09-purple-01-lavender.png");
+ ColorHTMLPurpleThistle.addFile(":/ico/22x22/color/color-09-purple-02-thistle.png");
+ ColorHTMLPurplePlum.addFile(":/ico/22x22/color/color-09-purple-03-plum.png");
+ ColorHTMLPurpleViolet.addFile(":/ico/22x22/color/color-09-purple-04-violet.png");
+ ColorHTMLPurpleOrchid.addFile(":/ico/22x22/color/color-09-purple-05-orchid.png");
+ ColorHTMLPurpleFuchsia.addFile(":/ico/22x22/color/color-09-purple-06-fuchsia.png");
+ ColorHTMLPurpleMagenta.addFile(":/ico/22x22/color/color-09-purple-07-magenta.png");
+ ColorHTMLPurpleMediumOrchid.addFile(":/ico/22x22/color/color-09-purple-08-mediumorchid.png");
+ ColorHTMLPurpleMediumPurple.addFile(":/ico/22x22/color/color-09-purple-09-mediumpurple.png");
+ ColorHTMLPurpleBlueViolet.addFile(":/ico/22x22/color/color-09-purple-10-blueviolet.png");
+ ColorHTMLPurpleDarkViolet.addFile(":/ico/22x22/color/color-09-purple-11-darkviolet.png");
+ ColorHTMLPurpleDarkOrchid.addFile(":/ico/22x22/color/color-09-purple-12-darkorchid.png");
+ ColorHTMLPurpleDarkMagenta.addFile(":/ico/22x22/color/color-09-purple-13-darkmagenta.png");
+ ColorHTMLPurplePurple.addFile(":/ico/22x22/color/color-09-purple-14-purple.png");
+ ColorHTMLPurpleIndigo.addFile(":/ico/22x22/color/color-09-purple-15-indigo.png");
+ ColorHTMLPurpleDarkSlateBlue.addFile(":/ico/22x22/color/color-09-purple-16-darkslateblue.png");
+ ColorHTMLPurpleSlateBlue.addFile(":/ico/22x22/color/color-09-purple-17-slateblue.png");
+ ColorHTMLPurpleMediumSlateBlue.addFile(":/ico/22x22/color/color-09-purple-18-mediumslateblue.png");
+ ColorHTMLWhiteWhite.addFile(":/ico/22x22/color/color-10-white-01-white.png");
+ ColorHTMLWhiteSnow.addFile(":/ico/22x22/color/color-10-white-02-snow.png");
+ ColorHTMLWhiteHoneydew.addFile(":/ico/22x22/color/color-10-white-03-honeydew.png");
+ ColorHTMLWhiteMintCream.addFile(":/ico/22x22/color/color-10-white-04-mintcream.png");
+ ColorHTMLWhiteAzure.addFile(":/ico/22x22/color/color-10-white-05-azure.png");
+ ColorHTMLWhiteAliceBlue.addFile(":/ico/22x22/color/color-10-white-06-aliceblue.png");
+ ColorHTMLWhiteGhostWhite.addFile(":/ico/22x22/color/color-10-white-07-ghostwhite.png");
+ ColorHTMLWhiteWhiteSmoke.addFile(":/ico/22x22/color/color-10-white-08-whitesmoke.png");
+ ColorHTMLWhiteSeashell.addFile(":/ico/22x22/color/color-10-white-09-seashell.png");
+ ColorHTMLWhiteBeige.addFile(":/ico/22x22/color/color-10-white-10-beige.png");
+ ColorHTMLWhiteOldLace.addFile(":/ico/22x22/color/color-10-white-11-oldlace.png");
+ ColorHTMLWhiteFloralWhite.addFile(":/ico/22x22/color/color-10-white-12-floralwhite.png");
+ ColorHTMLWhiteIvory.addFile(":/ico/22x22/color/color-10-white-13-ivory.png");
+ ColorHTMLWhiteAntiqueWhite.addFile(":/ico/22x22/color/color-10-white-14-antiquewhite.png");
+ ColorHTMLWhiteLinen.addFile(":/ico/22x22/color/color-10-white-15-linen.png");
+ ColorHTMLWhiteLavenderBlush.addFile(":/ico/22x22/color/color-10-white-16-lavenderblush.png");
+ ColorHTMLWhiteMistyRose.addFile(":/ico/22x22/color/color-10-white-17-mistyrose.png");
+ ColorHTMLGrayGainsboro.addFile(":/ico/22x22/color/color-11-gray-01-gainsboro.png");
+ ColorHTMLGrayLightGray.addFile(":/ico/22x22/color/color-11-gray-02-lightgray.png");
+ ColorHTMLGraySilver.addFile(":/ico/22x22/color/color-11-gray-03-silver.png");
+ ColorHTMLGrayDarkGray.addFile(":/ico/22x22/color/color-11-gray-04-darkgray.png");
+ ColorHTMLGrayGray.addFile(":/ico/22x22/color/color-11-gray-05-gray.png");
+ ColorHTMLGrayDimGray.addFile(":/ico/22x22/color/color-11-gray-06-dimgray.png");
+ ColorHTMLGrayLightSlateGray.addFile(":/ico/22x22/color/color-11-gray-07-lightslategray.png");
+ ColorHTMLGraySlateGray.addFile(":/ico/22x22/color/color-11-gray-08-slategray.png");
+ ColorHTMLGrayDarkSlateGray.addFile(":/ico/22x22/color/color-11-gray-09-darkslategray.png");
+ ColorHTMLGrayBlack.addFile(":/ico/22x22/color/color-11-gray-10-black.png");
}
diff --git a/sources/richtext/richtexteditor.cpp b/sources/richtext/richtexteditor.cpp
index 489d3391a..9c8b9b0a6 100644
--- a/sources/richtext/richtexteditor.cpp
+++ b/sources/richtext/richtexteditor.cpp
@@ -514,19 +514,19 @@ RichTextEditorToolBar::RichTextEditorToolBar(RichTextEditor *editor,
// Bold, italic and underline buttons
m_bold_action = createCheckableAction(
- QIcon(":/ico/32x32/format-text-bold.png"),
+ QIcon::fromTheme("format-text-bold"),
tr("Texte en gras"), editor, &RichTextEditor::setFontBold, this);
ShortcutManager::instance().registerAction(m_bold_action, "richtext.bold", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_B);
addAction(m_bold_action);
m_italic_action = createCheckableAction(
- QIcon(":/ico/32x32/format-text-italic.png"),
+ QIcon::fromTheme("format-text-italic"),
tr("Texte en italique"), editor, &RichTextEditor::setFontItalic, this);
ShortcutManager::instance().registerAction(m_italic_action, "richtext.italic", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_I);
addAction(m_italic_action);
m_underline_action = createCheckableAction(
- QIcon(":/ico/32x32/format-text-underline.png"),
+ QIcon::fromTheme("format-text-underline"),
tr("Texte souligé"), editor, &RichTextEditor::setFontUnderline, this);
ShortcutManager::instance().registerAction(m_underline_action, "richtext.underline", tr("Éditeur de texte"), Qt::CTRL | Qt::Key_U);
addAction(m_underline_action);
@@ -567,13 +567,13 @@ RichTextEditorToolBar::RichTextEditorToolBar(RichTextEditor *editor,
// Superscript and subscript buttons
m_valign_sup_action = createCheckableAction(
- QIcon(":/ico/22x22/format-text-superscript.png"),
+ QIcon::fromTheme("format-text-superscript"),
tr("Superscript"),
this, &RichTextEditorToolBar::setVAlignSuper, this);
addAction(m_valign_sup_action);
m_valign_sub_action = createCheckableAction(
- QIcon(":/ico/22x22/format-text-subscript.png"),
+ QIcon::fromTheme("format-text-subscript"),
tr("Subscript"),
this, &RichTextEditorToolBar::setVAlignSub, this);
addAction(m_valign_sub_action);
@@ -601,7 +601,7 @@ RichTextEditorToolBar::RichTextEditorToolBar(RichTextEditor *editor,
// Simplify rich text
m_simplify_richtext_action = createCheckableAction(
- QIcon(":/ico/32x32/simplifyrichtext.png"),
+ QIcon::fromTheme("simplifyrichtext"),
tr("Simplify Rich Text"), editor, &RichTextEditor::setSimplifyRichText, this);
m_simplify_richtext_action->setChecked(editor->simplifyRichText());
connect(m_editor, &RichTextEditor::simplifyRichTextChanged, m_simplify_richtext_action, &QAction::setChecked);
diff --git a/sources/ui/bomexportdialog.cpp b/sources/ui/bomexportdialog.cpp
index e2ea6ce77..da2be53ca 100644
--- a/sources/ui/bomexportdialog.cpp
+++ b/sources/ui/bomexportdialog.cpp
@@ -26,6 +26,7 @@
#include
#include
+#include
#include
/**
@@ -44,6 +45,9 @@ BOMExportDialog::BOMExportDialog(QETProject *project, QWidget *parent) :
ui->m_main_layout->insertWidget(0, m_query_widget);
m_query_widget->setQuery(BomExport::defaultQuery());
on_m_format_as_bom_clicked(false);
+
+ m_preview_model = new QSqlQueryModel(this);
+ ui->m_preview_table->setModel(m_preview_model);
}
/**
@@ -89,7 +93,15 @@ QByteArray BOMExportDialog::getBom(QString *error)
error->clear();
}
m_project->dataBase()->updateDB();
- auto query_ = m_project->dataBase()->newQuery(m_query_widget->queryStr());
+ QString rejection;
+ auto query_ = m_project->dataBase()->newQuery(m_query_widget->queryStr(), &rejection);
+
+ if (!rejection.isEmpty()) {
+ if (error) {
+ *error = rejection;
+ }
+ return {};
+ }
if (!query_.exec()) {
qDebug() << "BOMExportDialog::getBom : query errir : " << query_.lastError();
@@ -130,3 +142,39 @@ void BOMExportDialog::on_m_format_as_bom_clicked(bool checked) {
m_query_widget->setGroupBy("designation", checked);
m_query_widget->setCount("COUNT(*) AS designation_qty", checked);
}
+
+/**
+ @brief BOMExportDialog::on_m_preview_pb_clicked
+ Run the current query and show its result live, without going through
+ the CSV round-trip -- lets a report be checked and adjusted before
+ committing to a file (qelectrotech-source-mirror#886).
+*/
+void BOMExportDialog::on_m_preview_pb_clicked()
+{
+ m_project->dataBase()->updateDB();
+ QString rejection;
+ auto query_ = m_project->dataBase()->newQuery(m_query_widget->queryStr(), &rejection);
+
+ if (!rejection.isEmpty()) {
+ QMessageBox::warning(this, tr("Requête refusée"), rejection);
+ return;
+ }
+
+ if (!query_.exec()) {
+ QMessageBox::warning(
+ this, tr("Erreur"),
+ tr("Erreur dans la requête :\n%1").arg(query_.lastError().text()));
+ return;
+ }
+
+ m_preview_model->setQuery(std::move(query_));
+ for (int i = 0; i < m_preview_model->columnCount(); ++i)
+ {
+ const auto field_name = m_preview_model->record().fieldName(i);
+ const auto translated = QETInformation::translatedInfoKey(field_name);
+ if (!translated.isEmpty()) {
+ m_preview_model->setHeaderData(i, Qt::Horizontal, translated);
+ }
+ }
+ ui->m_preview_table->resizeColumnsToContents();
+}
diff --git a/sources/ui/bomexportdialog.h b/sources/ui/bomexportdialog.h
index 36fa40d15..0c5a0743e 100644
--- a/sources/ui/bomexportdialog.h
+++ b/sources/ui/bomexportdialog.h
@@ -23,6 +23,7 @@
class QETProject;
class ElementQueryWidget;
+class QSqlQueryModel;
namespace Ui {
class BOMExportDialog;
@@ -44,11 +45,13 @@ class BOMExportDialog : public QDialog
private slots:
void on_m_format_as_bom_clicked(bool checked);
+ void on_m_preview_pb_clicked();
private:
Ui::BOMExportDialog *ui;
ElementQueryWidget *m_query_widget = nullptr;
QETProject *m_project = nullptr;
+ QSqlQueryModel *m_preview_model = nullptr;
};
#endif // BOMEXPORTDIALOG_H
diff --git a/sources/ui/bomexportdialog.ui b/sources/ui/bomexportdialog.ui
index b9e60b329..04b673f46 100644
--- a/sources/ui/bomexportdialog.ui
+++ b/sources/ui/bomexportdialog.ui
@@ -7,7 +7,7 @@
0
0
610
- 232
+ 480
@@ -56,6 +56,37 @@
+ -
+
+
-
+
+
+ Aperçu
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+
-
diff --git a/sources/ui/conductorpropertieswidget.ui b/sources/ui/conductorpropertieswidget.ui
index 48ea44ac8..8a31d43a3 100644
--- a/sources/ui/conductorpropertieswidget.ui
+++ b/sources/ui/conductorpropertieswidget.ui
@@ -233,7 +233,7 @@
-
+
:/ico/16x16/configure.png:/ico/16x16/configure.png
@@ -363,7 +363,7 @@
neutre
-
+
:/ico/16x16/neutral.png:/ico/16x16/neutral.png
@@ -377,7 +377,7 @@
terre
-
+
:/ico/16x16/ground.png:/ico/16x16/ground.png
@@ -391,7 +391,7 @@
phase
-
+
:/ico/16x16/phase.png:/ico/16x16/phase.png
diff --git a/sources/ui/configsaveloaderwidget.ui b/sources/ui/configsaveloaderwidget.ui
index f0b69605b..aaa8aa130 100644
--- a/sources/ui/configsaveloaderwidget.ui
+++ b/sources/ui/configsaveloaderwidget.ui
@@ -29,7 +29,7 @@
-
+
:/ico/16x16/folder-open.png:/ico/16x16/folder-open.png
@@ -40,7 +40,7 @@
-
+
:/ico/16x16/document-save.png:/ico/16x16/document-save.png
diff --git a/sources/ui/dynamicelementtextitemeditor.ui b/sources/ui/dynamicelementtextitemeditor.ui
index 66a326d4f..273637c2e 100644
--- a/sources/ui/dynamicelementtextitemeditor.ui
+++ b/sources/ui/dynamicelementtextitemeditor.ui
@@ -25,7 +25,7 @@
...
-
+
:/ico/16x16/document-save.png:/ico/16x16/document-save.png
@@ -39,7 +39,7 @@
...
-
+
:/ico/16x16/folder-open.png:/ico/16x16/folder-open.png
@@ -66,7 +66,7 @@
...
-
+
:/ico/22x22/textfield.png:/ico/22x22/textfield.png
@@ -80,7 +80,7 @@
...
-
+
:/ico/16x16/object-group.png:/ico/16x16/object-group.png
@@ -94,7 +94,7 @@
...
-
+
:/ico/16x16/list-remove.png:/ico/16x16/list-remove.png
diff --git a/sources/ui/linksingleelementwidget.cpp b/sources/ui/linksingleelementwidget.cpp
index e2c3c8b38..322e955bf 100644
--- a/sources/ui/linksingleelementwidget.cpp
+++ b/sources/ui/linksingleelementwidget.cpp
@@ -25,10 +25,14 @@
#include "../undocommand/linkelementcommand.h"
#include "../qetinformation.h"
#include "../qetproject.h"
+#include "../qetgraphicsitem/masterelement.h"
#include "../ui_linksingleelementwidget.h"
#include
#include
+#include
+#include
+#include
/**
@@ -52,6 +56,22 @@ LinkSingleElementWidget::LinkSingleElementWidget(Element *elmt,
m_show_qtwi = new QAction(tr("Montrer l'élément"), this);
m_show_element = new QAction(tr("Montrer l'élément esclave"), this);
m_save_header_state = new QAction(tr("Enregistrer la disposition"), this);
+
+ // Hide the full-masters checkbox for non-slave elements
+ const bool is_slave = (elmt && elmt->elementData().m_type == ElementData::Slave);
+ ui->m_hide_full_masters_cb->setVisible(is_slave);
+
+ // Restore persisted state before connecting to avoid toggled firing buildTree()
+ // while m_element is still null.
+ {
+ const QSignalBlocker blocker(ui->m_hide_full_masters_cb);
+ QSettings settings;
+ ui->m_hide_full_masters_cb->setChecked(
+ settings.value(QStringLiteral("link-element-widget/hideFullMasters"), false).toBool());
+ }
+
+ connect(ui->m_hide_full_masters_cb, &QCheckBox::toggled,
+ this, &LinkSingleElementWidget::hideFullMastersToggled);
connect(m_show_qtwi, &QAction::triggered, this, [=]()
{
@@ -249,6 +269,7 @@ void LinkSingleElementWidget::buildTree()
if (m_element->elementData().m_type == ElementData::Slave)
{
+ m_full_masters.clear();
for(const auto &elmt : elmt_vector)
{
@@ -288,6 +309,16 @@ void LinkSingleElementWidget::buildTree()
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_tree_widget, str_list);
m_qtwi_elmt_hash.insert(qtwi, elmt);
m_qtwi_strl_hash.insert(qtwi, search_list);
+
+ // Check if this master is full
+ if (elmt->linkType() == Element::Master) {
+ MasterElement *me = qobject_cast(elmt);
+ if (me && me->isFull()) {
+ m_full_masters.insert(qtwi);
+ if (ui->m_hide_full_masters_cb->isChecked())
+ qtwi->setHidden(true);
+ }
+ }
}
@@ -455,6 +486,8 @@ void LinkSingleElementWidget::setUpCompleter()
*/
void LinkSingleElementWidget::clearTreeWidget()
{
+ m_pending_qtwi = nullptr;
+
while(ui->m_tree_widget->topLevelItemCount())
{
QTreeWidgetItem *qtwi = ui->m_tree_widget->takeTopLevelItem(0);
@@ -467,6 +500,7 @@ void LinkSingleElementWidget::clearTreeWidget()
m_qtwi_elmt_hash.clear();
m_qtwi_strl_hash.clear();
+ m_full_masters.clear();
}
void LinkSingleElementWidget::setUpHeaderLabels()
@@ -675,6 +709,7 @@ void LinkSingleElementWidget::hideButtons()
ui->m_show_linked_pb->hide();
ui->m_show_this_pb->hide();
ui->m_search_field->show();
+ ui->m_hide_full_masters_cb->show();
}
/**
@@ -688,6 +723,7 @@ void LinkSingleElementWidget::showButtons()
ui->m_show_linked_pb->show();
ui->m_show_this_pb->show();
ui->m_search_field->hide();
+ ui->m_hide_full_masters_cb->hide();
}
void LinkSingleElementWidget::headerCustomContextMenuRequested(
@@ -783,27 +819,35 @@ void LinkSingleElementWidget::on_m_show_this_pb_clicked()
If arg1 is empty, show all items.
@param arg1
*/
-void LinkSingleElementWidget::on_m_search_field_textEdited(const QString &arg1)
+void LinkSingleElementWidget::on_m_search_field_textEdited(const QString &)
{
- //Show all items if arg1 is empty, if not hide all items
- foreach(QTreeWidgetItem *qtwi, m_qtwi_elmt_hash.keys())
- qtwi->setHidden(!arg1.isEmpty());
-
- QList qtwi_list;
-
- foreach(QTreeWidgetItem *qtwi, m_qtwi_strl_hash.keys())
+ updateItemsVisibility();
+}
+
+void LinkSingleElementWidget::hideFullMastersToggled(bool checked)
+{
+ QSettings settings;
+ settings.setValue(QStringLiteral("link-element-widget/hideFullMasters"), checked);
+ updateItemsVisibility();
+}
+
+void LinkSingleElementWidget::updateItemsVisibility()
+{
+ const QString text = ui->m_search_field->text();
+ const bool hide_full = ui->m_hide_full_masters_cb->isChecked();
+
+ for (auto it = m_qtwi_strl_hash.cbegin(); it != m_qtwi_strl_hash.cend(); ++it)
{
- foreach(QString str, m_qtwi_strl_hash.value(qtwi))
- {
- if(str.contains(arg1, Qt::CaseInsensitive))
- {
- qtwi_list << qtwi;
- continue;
+ bool match = text.isEmpty();
+ if (!match) {
+ for (const QString &str : it.value()) {
+ if (str.contains(text, Qt::CaseInsensitive)) {
+ match = true;
+ break;
+ }
}
}
+ it.key()->setHidden(!match
+ || (hide_full && m_full_masters.contains(it.key())));
}
-
- //Show items which match with arg1
- foreach(QTreeWidgetItem *qtwi, qtwi_list)
- qtwi->setHidden(false);
}
diff --git a/sources/ui/linksingleelementwidget.h b/sources/ui/linksingleelementwidget.h
index d477d107b..b41acd211 100644
--- a/sources/ui/linksingleelementwidget.h
+++ b/sources/ui/linksingleelementwidget.h
@@ -26,6 +26,7 @@
#include
class QTreeWidgetItem;
+class QCheckBox;
class Element;
class QMenu;
@@ -71,6 +72,7 @@ class LinkSingleElementWidget : public AbstractElementPropertiesEditorWidget
void setUpCompleter();
void clearTreeWidget();
void setUpHeaderLabels();
+ void updateItemsVisibility();
private slots:
void diagramWasRemovedFromProject();
@@ -87,6 +89,7 @@ class LinkSingleElementWidget : public AbstractElementPropertiesEditorWidget
void on_m_show_this_pb_clicked();
void on_m_search_field_textEdited(const QString &arg1);
+ void hideFullMastersToggled(bool checked);
private:
Ui::LinkSingleElementWidget *ui;
@@ -103,6 +106,8 @@ class LinkSingleElementWidget : public AbstractElementPropertiesEditorWidget
Element *m_showed_element = nullptr,
*m_element_to_link = nullptr;
+ QSet m_full_masters;
+
int m_pending_group_index = -1;
QMenu *m_context_menu{nullptr};
diff --git a/sources/ui/linksingleelementwidget.ui b/sources/ui/linksingleelementwidget.ui
index b31f7c10d..0488626eb 100644
--- a/sources/ui/linksingleelementwidget.ui
+++ b/sources/ui/linksingleelementwidget.ui
@@ -21,7 +21,7 @@
- -
+
-
5
@@ -57,30 +57,20 @@
- -
+
-
Recherche
-
- -
-
+
-
+
- Remarque : les éléments maîtres ayant atteint leur nombre maximal d'esclaves sont masqués.
-
-
- true
-
-
-
- true
-
+ Masquer les éléments maîtres pleins
-
diff --git a/sources/ui/masterpropertieswidget.ui b/sources/ui/masterpropertieswidget.ui
index 71eb57dd8..910ac27c0 100644
--- a/sources/ui/masterpropertieswidget.ui
+++ b/sources/ui/masterpropertieswidget.ui
@@ -136,7 +136,7 @@
-
+
:/ico/16x16/go-up.png:/ico/16x16/go-up.png
@@ -150,7 +150,7 @@
-
+
:/ico/16x16/go-down.png:/ico/16x16/go-down.png
diff --git a/sources/ui/thirdpartybinaryinstalldialog.ui b/sources/ui/thirdpartybinaryinstalldialog.ui
index 899666d2c..cbd94b056 100644
--- a/sources/ui/thirdpartybinaryinstalldialog.ui
+++ b/sources/ui/thirdpartybinaryinstalldialog.ui
@@ -33,7 +33,7 @@
Télechargement
-
+
:/ico/16x16/edit-download.png:/ico/16x16/edit-download.png
@@ -44,7 +44,7 @@
Dossier installation
-
+
:/ico/16x16/folder-open.png:/ico/16x16/folder-open.png
diff --git a/sources/ui/titleblockpropertieswidget.ui b/sources/ui/titleblockpropertieswidget.ui
index 2389eabcf..0be2a3623 100644
--- a/sources/ui/titleblockpropertieswidget.ui
+++ b/sources/ui/titleblockpropertieswidget.ui
@@ -94,7 +94,7 @@
-
+
:/ico/22x22/titleblock-bottom.png:/ico/22x22/titleblock-bottom.png
@@ -103,7 +103,7 @@
-
+
:/ico/22x22/titleblock-right.png:/ico/22x22/titleblock-right.png
@@ -121,7 +121,7 @@
-
+
:/ico/22x22/edit-rename.png:/ico/22x22/edit-rename.png
@@ -210,7 +210,7 @@
-
+
:/ico/16x16/configure.png:/ico/16x16/configure.png
@@ -305,7 +305,7 @@
-
+
:/ico/22x22/start.png:/ico/22x22/start.png
diff --git a/tests/qttest/CMakeLists.txt b/tests/qttest/CMakeLists.txt
index 855a9acd2..638d3961a 100644
--- a/tests/qttest/CMakeLists.txt
+++ b/tests/qttest/CMakeLists.txt
@@ -82,12 +82,28 @@ target_link_libraries(tst_contactusage PRIVATE Qt::Test)
add_executable(
tst_qetpalette
tst_qetpalette.cpp
+ inkcontrast.h
${QET_DIR}/sources/qetpalette.cpp
${QET_DIR}/sources/qetpalette.h)
add_test(NAME tst_qetpalette COMMAND tst_qetpalette)
target_include_directories(tst_qetpalette PRIVATE ${QET_DIR}/sources)
target_link_libraries(tst_qetpalette PRIVATE Qt::Test Qt::Widgets)
+# qeticons.cpp is compiled in so the test can check the table entries
+# themselves (icon sizes in the element panel), not only the theme files.
+add_executable(
+ tst_qeticons
+ tst_qeticons.cpp
+ inkcontrast.h
+ ${QET_DIR}/sources/qeticons.cpp
+ ${QET_DIR}/sources/qeticons.h
+ ${QET_DIR}/sources/qetpalette.cpp
+ ${QET_DIR}/sources/qetpalette.h
+ ${QET_DIR}/ico/icon-themes.qrc)
+add_test(NAME tst_qeticons COMMAND tst_qeticons)
+target_include_directories(tst_qeticons PRIVATE ${QET_DIR}/sources)
+target_link_libraries(tst_qeticons PRIVATE Qt::Test Qt::Widgets Qt::Svg)
+
add_executable(
tst_smart_device
tst_smart_device.cpp
diff --git a/tests/qttest/inkcontrast.h b/tests/qttest/inkcontrast.h
new file mode 100644
index 000000000..282a4db2e
--- /dev/null
+++ b/tests/qttest/inkcontrast.h
@@ -0,0 +1,77 @@
+/*
+ Copyright 2006-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.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#ifndef QET_TEST_INKCONTRAST_H
+#define QET_TEST_INKCONTRAST_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "qetpalette.h"
+
+/**
+ Shared helpers for the rendering tests: paint a widget on the offscreen
+ platform and measure the ink against the background.
+*/
+namespace QET {
+ namespace Test {
+ /**
+ Grab a widget for measuring. With QET_TEST_DUMP_DIR set, the
+ image is also written there as -.png so a failure
+ can be looked at.
+ */
+ inline QImage grab(QWidget *widget, const char *name)
+ {
+ const QImage image = widget->grab().toImage();
+ const QByteArray dir = qgetenv("QET_TEST_DUMP_DIR");
+ if (!dir.isEmpty())
+ image.save(QString("%1/%2-%3.png").arg(QString::fromLocal8Bit(dir),
+ QTest::currentDataTag(), name));
+ return image;
+ }
+
+ /**
+ Contrast between the background of a rendered widget (its most
+ frequent color) and the ink drawn on it (the pixel whose
+ luminance differs most from the background), inside rect.
+ */
+ inline double inkContrast(const QImage &image, const QRect &rect)
+ {
+ QHash histogram;
+ for (int y = rect.top(); y <= rect.bottom(); ++y)
+ for (int x = rect.left(); x <= rect.right(); ++x)
+ ++histogram[image.pixel(x, y)];
+
+ QRgb background = 0;
+ int best = -1;
+ for (auto it = histogram.cbegin(); it != histogram.cend(); ++it)
+ if (it.value() > best) { best = it.value(); background = it.key(); }
+
+ double contrast = 1.0;
+ for (auto it = histogram.cbegin(); it != histogram.cend(); ++it)
+ contrast = qMax(contrast, QET::Palette::contrastRatio(QColor(background),
+ QColor(it.key())));
+ return contrast;
+ }
+ }
+}
+
+#endif
diff --git a/tests/qttest/tst_qeticons.cpp b/tests/qttest/tst_qeticons.cpp
new file mode 100644
index 000000000..af5966d0d
--- /dev/null
+++ b/tests/qttest/tst_qeticons.cpp
@@ -0,0 +1,166 @@
+/*
+ Copyright 2006-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.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "inkcontrast.h"
+#include "qeticons.h"
+#include "qetpalette.h"
+
+/**
+ Checks on QET's icon theme "qet", generated by misc/make_icon_themes.py
+ into ico/icon-themes.qrc, and on the icon table that uses it.
+
+ Every icon name must resolve. A toolbar button painted with Fusion must
+ show its icon at 3:1 (WCAG 1.4.11), with the disabled state reading
+ weaker than the enabled one. And the icons the elements panel draws in
+ its 50 px slots must stay small (GitHub #870).
+*/
+class tst_qeticons : public QObject
+{
+ Q_OBJECT
+
+ private slots:
+ void initTestCase();
+ void everyIconResolves();
+ void toolbarIconIsReadable_data();
+ void toolbarIconIsReadable();
+ void panelProjectIconStaysSmall();
+};
+
+namespace {
+ const double kIconRatio = 3.0;
+
+ QStringList iconNames(const QString &theme)
+ {
+ QStringList names;
+ for (const QString &size : {"16x16", "22x22", "32x32", "48x48", "128x128", "scalable"})
+ {
+ QDir dir(QString(":/ico/themes/%1/%2").arg(theme, size));
+ for (const QString &file : dir.entryList(QDir::Files))
+ names << file.section('.', 0, -2);
+ }
+ names.removeDuplicates();
+ names.sort();
+ return names;
+ }
+}
+
+void tst_qeticons::initTestCase()
+{
+ QStringList paths = QIcon::themeSearchPaths();
+ paths.prepend(QStringLiteral(":/ico/themes"));
+ QIcon::setThemeSearchPaths(paths);
+ QIcon::setThemeName(QStringLiteral("qet"));
+ QVERIFY2(!iconNames("qet").isEmpty(), "theme has no icons: is ico/icon-themes.qrc compiled in?");
+}
+
+void tst_qeticons::everyIconResolves()
+{
+ QVERIFY(QIcon::hasThemeIcon("list-add"));
+ for (const QString &name : iconNames("qet"))
+ QVERIFY2(!QIcon::fromTheme(name).isNull(), qPrintable(QString("%1 missing").arg(name)));
+ // Names the icon table relies on that come from the alias list in
+ // misc/make_icon_themes.py, not from a file of that name at 22 pixels.
+ for (const QString &name : {"folio-new", "folio-delete", "folio-properties", "conductor-reset"})
+ QVERIFY2(!QIcon::fromTheme(name).pixmap(22).isNull(), qPrintable(name));
+}
+
+void tst_qeticons::toolbarIconIsReadable_data()
+{
+ QTest::addColumn("palette");
+ QTest::newRow("light") << QET::Palette::fusionLight();
+}
+
+/**
+ A line-art icon on a Fusion tool button, as in the diagram editor
+ toolbar. Enabled must reach 3:1; disabled must be weaker than enabled.
+*/
+void tst_qeticons::toolbarIconIsReadable()
+{
+ QFETCH(QPalette, palette);
+ QApplication::setStyle(QStyleFactory::create("Fusion"));
+ QApplication::setPalette(palette);
+
+ QMainWindow window;
+ QToolBar *toolbar = window.addToolBar("view");
+ auto make = [&](const char *name, bool enabled) {
+ auto *button = new QToolButton;
+ button->setIcon(QIcon::fromTheme("zoom-fit-best"));
+ button->setAutoRaise(true);
+ button->setEnabled(enabled);
+ button->setObjectName(name);
+ toolbar->addWidget(button);
+ return button;
+ };
+ QToolButton *enabled = make("enabled", true);
+ QToolButton *disabled = make("disabled", false);
+ window.resize(300, 100);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ const double enabled_contrast = QET::Test::inkContrast(QET::Test::grab(enabled, "enabled"), enabled->rect());
+ const double disabled_contrast = QET::Test::inkContrast(QET::Test::grab(disabled, "disabled"), disabled->rect());
+ QVERIFY2(enabled_contrast >= kIconRatio,
+ qPrintable(QString("enabled icon: %1").arg(enabled_contrast)));
+ QVERIFY2(disabled_contrast < enabled_contrast,
+ qPrintable(QString("disabled %1 reads better than enabled %2")
+ .arg(disabled_contrast).arg(enabled_contrast)));
+}
+
+/**
+ The elements panel sets a 50 px icon size so element previews are
+ large. Its project root item uses ProjectFileGP, whose theme name also
+ has a 128 px file for the configuration dialog. On a 2x display the
+ theme loader would pick that file for a 50 px request and fill the
+ slot, so the entry must not resolve through the theme name.
+*/
+void tst_qeticons::panelProjectIconStaysSmall()
+{
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ QSKIP("QIcon::pixmap(size, devicePixelRatio) needs Qt 6");
+#else
+ QET::Icons::initIcons();
+
+ const QPixmap panel = QET::Icons::ProjectFileGP.pixmap(QSize(50, 50), 2.0);
+ QVERIFY(!panel.isNull());
+ const int logical = qRound(panel.width() / panel.devicePixelRatio());
+ QVERIFY2(logical <= 22, qPrintable(QString("project root icon is %1 px in a 50 px slot").arg(logical)));
+
+ // The configuration dialog's page list still gets the large file.
+ QCOMPARE(QET::Icons::Projects.pixmap(QSize(128, 128), 1.0).width(), 128);
+#endif
+}
+
+int main(int argc, char **argv)
+{
+ if (qEnvironmentVariableIsEmpty("QT_QPA_PLATFORM"))
+ qputenv("QT_QPA_PLATFORM", "offscreen");
+ QApplication app(argc, argv);
+ tst_qeticons test;
+ QTEST_SET_MAIN_SOURCE_PATH
+ return QTest::qExec(&test, argc, argv);
+}
+
+#include "tst_qeticons.moc"
diff --git a/tests/qttest/tst_qetpalette.cpp b/tests/qttest/tst_qetpalette.cpp
index 7cc589bdd..ccbe07f15 100644
--- a/tests/qttest/tst_qetpalette.cpp
+++ b/tests/qttest/tst_qetpalette.cpp
@@ -28,9 +28,12 @@
#include
#include
+#include "inkcontrast.h"
#include "qetpalette.h"
using QET::Palette::contrastRatio;
+using QET::Test::grab;
+using QET::Test::inkContrast;
/**
Contrast checks for the palettes QET installs under the Fusion style.
@@ -94,44 +97,6 @@ namespace {
{"Link/Window", QPalette::Link, QPalette::Window},
};
- /**
- Grab a widget for measuring. With QET_TEST_DUMP_DIR set, the image
- is also written there as -.png so a failure can be
- looked at.
- */
- QImage grab(QWidget *widget, const char *name)
- {
- const QImage image = widget->grab().toImage();
- const QByteArray dir = qgetenv("QET_TEST_DUMP_DIR");
- if (!dir.isEmpty())
- image.save(QString("%1/%2-%3.png").arg(QString::fromLocal8Bit(dir),
- QTest::currentDataTag(), name));
- return image;
- }
-
- /**
- Contrast between the background of a rendered widget (its most
- frequent color) and the ink drawn on it (the pixel whose luminance
- differs most from the background), inside rect.
- */
- double inkContrast(const QImage &image, const QRect &rect)
- {
- QHash histogram;
- for (int y = rect.top(); y <= rect.bottom(); ++y)
- for (int x = rect.left(); x <= rect.right(); ++x)
- ++histogram[image.pixel(x, y)];
-
- QRgb background = 0;
- int best = -1;
- for (auto it = histogram.cbegin(); it != histogram.cend(); ++it)
- if (it.value() > best) { best = it.value(); background = it.key(); }
-
- double contrast = 1.0;
- for (auto it = histogram.cbegin(); it != histogram.cend(); ++it)
- contrast = qMax(contrast, contrastRatio(QColor(background),
- QColor(it.key())));
- return contrast;
- }
}
void tst_qetpalette::addPaletteRows()