Compare commits

...

20 Commits

Author SHA1 Message Date
Laurent Trinques 16650ed6af Update org.qelectrotech.QElectroTech.json
Auto-build doxygen docs / doxygen (push) Failing after 38s
Auto-build doxygen docs / deploy (push) Has been skipped
2026-04-06 10:19:26 +02:00
Laurent Trinques 3b3171dc93 Update org.qelectrotech.QElectroTech.json 2026-04-06 09:18:39 +02:00
Laurent Trinques 500c42c86b Delete build-aux/flatpak/patches/0001-build-Fix-the-installation-paths.patch 2026-04-06 08:41:56 +02:00
Laurent Trinques 2f3e46e488 Add files via upload 2026-04-06 08:41:27 +02:00
Laurent Trinques 290ef97ec2 Delete build-aux/flatpak/fix-appdata.patch 2026-04-06 08:37:15 +02:00
Laurent Trinques f0923e7560 Delete build-aux/flatpak/tkinter-build.patch 2026-04-06 08:36:57 +02:00
Laurent Trinques b32de35afd Add files via upload 2026-04-06 08:34:20 +02:00
Laurent Trinques 8aad1c0cab Update org.qelectrotech.QElectroTech.json 2026-04-06 08:31:42 +02:00
Laurent Trinques d365e19619 Update org.qelectrotech.QElectroTech.json 2026-04-06 06:55:18 +02:00
Laurent Trinques 27b977e9f3 Update translation TS files 2026-04-06 06:12:01 +02:00
Laurent Trinques 54e19f4074 Merge pull request #448 from ChuckNr11/master
Supplement to pull request #444 by Kellermorph
2026-04-06 05:50:03 +02:00
Laurent Trinques 8af1fd708f Merge pull request #447 from Kellermorph/feature-verdrahtungsplan
Add RAM-based wiring list export
2026-04-06 05:47:24 +02:00
ChuckNr11 a64e414d63 Fix: incorrect display after deleting a diagram in elements panel 2026-04-05 22:44:35 +02:00
ChuckNr11 2ed8d76e2d add buttons 'one page left/right' to projectView tab bar
Disable the QTabWidget internal scroll buttons and add own buttons for
scroll 'one page left' and scroll 'one page right'. The scrolled
diagrams will be activated.
2026-04-05 22:39:53 +02:00
ChuckNr11 679647f52a Change operation of elementsPanel
corresponding to operation of project and diagram tabs
- click on the item activates the corresponding diagram or project.
- double click opens the corresponding properties editor.
- selecting with the up and down arrow keys has the same effect.
2026-04-05 22:21:34 +02:00
ChuckNr11 a82f6de23b Add highlight current page in ProjectView
- on clicking project tab
- on moving diagram tab
- on adding project
- on adding diagram
2026-04-05 22:11:38 +02:00
ChuckNr11 6452e03cdc refactor: move code to other place for cleaner code
connections for projectviews are made in "addProjectView"
2026-04-05 21:56:33 +02:00
Kellermorph 51725d9d8e Replace conductornumexport.cpp with wiringlistexport.h 2026-04-05 18:32:35 +02:00
Kellermorph a45a7d4e4d Remove comments about live RAM capture
Removed commented-out code explaining live RAM capture.
2026-04-05 09:09:51 +02:00
Kellermorph bc9173d726 Add RAM-based wiring list export 2026-04-05 08:33:37 +02:00
50 changed files with 9851 additions and 5711 deletions
@@ -1,8 +1,7 @@
{
"id": "org.qelectrotech.QElectroTech",
"base-version": "5.15-23.08",
"runtime": "org.kde.Platform",
"runtime-version": "5.15-23.08",
"runtime-version": "5.15-25.08",
"sdk": "org.kde.Sdk",
"command": "qelectrotech",
"rename-desktop-file": "org.qelectrotech.qelectrotech.desktop",
@@ -18,51 +17,17 @@
"--socket=cups",
"--filesystem=host"
],
"cleanup": [
"/include",
"/man",
"/share/doc",
"/share/man",
"*.la",
"*.a"
],
"modules": [
{
"name": "tkinter",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=${FLATPAK_DEST} ."
],
"sources": [
{
"type": "git",
"url": "https://github.com/iwalton3/tkinter-standalone",
"commit": "23c793bad2429f4a81eee9f50e2d07ae845b7785"
}
],
"modules": [
{
"name": "tcl",
"sources": [
{
"type": "archive",
"url": "https://sourceforge.net/projects/tcl/files/Tcl/8.6.11/tcl8.6.11-src.tar.gz",
"sha256": "8c0486668586672c5693d7d95817cb05a18c5ecca2f40e2836b9578064088258"
}
],
"subdir": "unix",
"post-install": [
"chmod +w ${FLATPAK_DEST}/lib/libtcl8.6.so"
]
},
{
"name": "tk",
"sources": [
{
"type": "archive",
"url": "https://sourceforge.net/projects/tcl/files/Tcl/8.6.11/tk8.6.11-src.tar.gz",
"sha256": "5228a8187a7f70fa0791ef0f975270f068ba9557f57456f51eb02d9d4ea31282"
}
],
"subdir": "unix",
"post-install": [
"chmod +w ${FLATPAK_DEST}/lib/libtk8.6.so"
]
}
]
},
"tkinter.json",
"pypi-dependencies.json",
{
"name": "qelectrotech",
"buildsystem": "qmake",
@@ -76,37 +41,11 @@
},
{
"type": "patch",
"path": "patches/0001-build-Fix-the-installation-paths.patch"
"paths": [
"patches/fix-the-installation-paths.patch"
]
}
]
},
{
"name": "python3-PySimpleGUI",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} PySimpleGUI"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/d0/c3/c1ce811a1e48d5e0f2df0b393ff189fae4842ec840bb6e4db79c8da55e74/PySimpleGUI-4.41.2.tar.gz",
"sha256": "cf42d9f61f28c8e790a9c031ce900a9cee5fd2f950da2f055ed36bbc487dcf11"
}
]
},
{
"name": "python3-qet-tb-generator",
"buildsystem": "simple",
"build-commands": [
"pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} qet-tb-generator"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/70/aa/ebde0dddfbde799a4e8cf0564e52f95089105a7f562739ee1d16ff5a495a/qet_tb_generator-1.3.1.tar.gz",
"sha256": "52c9836387d54bc30ea29272068ec156fc65c3905e0cb863afd9418abc3c0907"
}
]
}
}
]
}
@@ -0,0 +1,54 @@
From 5cb80674cec7363ed00bab5248b3674ca5241c2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sabri=20=C3=9Cnal?= <yakushabb@gmail.com>
Date: Fri, 20 Feb 2026 22:56:52 +0300
Subject: [PATCH] Fix appdata paper cuts
---
misc/qelectrotech.appdata.xml | 26 ++++++++++++++++++++------
1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/misc/qelectrotech.appdata.xml b/misc/qelectrotech.appdata.xml
index dd06ab7..eb02119 100644
--- a/misc/qelectrotech.appdata.xml
+++ b/misc/qelectrotech.appdata.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2006-2023 The QElectroTech Team -->
-<application>
- <id type="desktop">qelectrotech.desktop</id>
+<component type="desktop-application">
+ <id>org.qelectrotech.QElectroTech</id>
+ <launchable type="desktop-id">qelectrotech.desktop</launchable>
<metadata_license>MIT</metadata_license>
<project_license>GPL-2.0-or-later</project_license>
<name>QElectroTech</name>
@@ -83,9 +84,22 @@
QET は要素と回路図に XML 形式を利用し、回路図エディタ、要素エディタ、表題欄エディタを含みます。
</p>
</description>
- <url type="homepage">http://qelectrotech.org</url>
+ <url type="homepage">https://qelectrotech.org</url>
+ <url type="bugtracker">https://qelectrotech.org/bugtracker</url>
+ <url type="vcs-browser">https://github.com/qelectrotech/qelectrotech-source-mirror</url>
+ <developer id="org.qelectrotech">
+ <name>QElectroTech</name>
+ </developer>
<screenshots>
- <screenshot type="default">http://download.tuxfamily.org/qet/screens/qelectrotech5.png</screenshot>
+ <screenshot type="default">
+ <image>https://qelectrotech.org/screenshots/qet_overview04.png</image>
+ </screenshot>
+ <screenshot>
+ <image>https://qelectrotech.org/screenshots/qet_overview06.png</image>
+ </screenshot>
+ <screenshot>
+ <image>https://qelectrotech.org/screenshots/qet_overview09.png</image>
+ </screenshot>
</screenshots>
- <updatecontact>qet@lists.tuxfamily.org</updatecontact>
-</application>
+ <update_contact>qet@lists.tuxfamily.org</update_contact>
+</component>
--
2.53.0
@@ -1,16 +1,6 @@
From 14f0685ddcf3a7d64bb85a3e9a9ac97c369bb508 Mon Sep 17 00:00:00 2001
From: Laurent Trinques <scorpio@qelectrotech.org>
Date: Sat, 26 Sep 2020 22:52:52 +0200
Subject: [PATCH] build: Fix the installation paths
---
qelectrotech.pro | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/qelectrotech.pro b/qelectrotech.pro
index 7baddbb08..5dcda04b6 100644
--- a/qelectrotech.pro
+++ b/qelectrotech.pro
diff -ruN a/qelectrotech.pro b/qelectrotech.pro
--- a/qelectrotech.pro 2023-04-20 11:47:07.695847458 +0200
+++ b/qelectrotech.pro 2023-04-20 11:51:14.843611898 +0200
@@ -5,18 +5,18 @@
# Chemins utilises pour la compilation et l'installation de QET
unix {
@@ -35,6 +25,3 @@ index 7baddbb08..5dcda04b6 100644
QET_APPDATA_PATH = 'share/appdata'
}
win32 {
--
2.35.1
@@ -0,0 +1,184 @@
commit 3bbb09a0598fc976d2bf8dac932b27740086c1bd
Author: Hubert Figuière <hub@figuiere.net>
Date: Sun Dec 21 17:49:43 2025 -0500
Port to Python 3.13
Signed-off-by: Hubert Figuière <hub@figuiere.net>
diff --git a/_tkinter.c b/_tkinter.c
index e537707..dfc5789 100644
--- a/_tkinter.c
+++ b/_tkinter.c
@@ -21,7 +21,6 @@ Copyright (C) 1994 Steen Lumholt.
*/
-#define PY_SSIZE_T_CLEAN
#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif
@@ -32,6 +31,9 @@ Copyright (C) 1994 Steen Lumholt.
# include "pycore_fileutils.h" // _Py_stat()
#endif
+#include "pycore_long.h" // _PyLong_IsNegative()
+#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString()
+
#ifdef MS_WINDOWS
#include <windows.h>
#endif
@@ -135,7 +137,7 @@ _get_tcl_lib_path()
struct stat stat_buf;
int stat_return_value;
- prefix = PyUnicode_FromWideChar(Py_GetPrefix(), -1);
+ (void) _PySys_GetOptionalAttrString("base_prefix", &prefix);
if (prefix == NULL) {
return NULL;
}
@@ -143,9 +145,11 @@ _get_tcl_lib_path()
/* Check expected location for an installed Python first */
tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION);
if (tcl_library_path == NULL) {
+ Py_DECREF(prefix);
return NULL;
}
tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path);
+ Py_DECREF(prefix);
if (tcl_library_path == NULL) {
return NULL;
}
@@ -959,7 +963,8 @@ AsObj(PyObject *value)
(unsigned char *)(void *)&wideValue,
sizeof(wideValue),
PY_LITTLE_ENDIAN,
- /* signed */ 1) == 0) {
+ /* signed */ 1,
+ /* with_exceptions */ 1) == 0) {
return Tcl_NewWideIntObj(wideValue);
}
PyErr_Clear();
@@ -1988,7 +1993,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg)
int v;
if (PyLong_Check(arg)) { /* int or bool */
- return PyBool_FromLong(Py_SIZE(arg) != 0);
+ return PyBool_FromLong(!_PyLong_IsZero((PyLongObject *)arg));
}
if (PyTclObject_Check(arg)) {
diff --git a/clinic/_tkinter.c.h b/clinic/_tkinter.c.h
index 9103565..f43510d 100644
--- a/clinic/_tkinter.c.h
+++ b/clinic/_tkinter.c.h
@@ -2,6 +2,8 @@
preserve
[clinic start generated code]*/
+#include "pycore_modsupport.h" // _PyArg_BadArgument()
+
PyDoc_STRVAR(_tkinter_tkapp_eval__doc__,
"eval($self, script, /)\n"
"--\n"
@@ -426,7 +428,7 @@ _tkinter_tkapp_createfilehandler(TkappObject *self, PyObject *const *args, Py_ss
goto exit;
}
file = args[0];
- mask = _PyLong_AsInt(args[1]);
+ mask = PyLong_AsInt(args[1]);
if (mask == -1 && PyErr_Occurred()) {
goto exit;
}
@@ -490,7 +492,7 @@ _tkinter_tkapp_createtimerhandler(TkappObject *self, PyObject *const *args, Py_s
if (!_PyArg_CheckPositional("createtimerhandler", nargs, 2, 2)) {
goto exit;
}
- milliseconds = _PyLong_AsInt(args[0]);
+ milliseconds = PyLong_AsInt(args[0]);
if (milliseconds == -1 && PyErr_Occurred()) {
goto exit;
}
@@ -524,7 +526,7 @@ _tkinter_tkapp_mainloop(TkappObject *self, PyObject *const *args, Py_ssize_t nar
if (nargs < 1) {
goto skip_optional;
}
- threshold = _PyLong_AsInt(args[0]);
+ threshold = PyLong_AsInt(args[0]);
if (threshold == -1 && PyErr_Occurred()) {
goto exit;
}
@@ -558,7 +560,7 @@ _tkinter_tkapp_dooneevent(TkappObject *self, PyObject *const *args, Py_ssize_t n
if (nargs < 1) {
goto skip_optional;
}
- flags = _PyLong_AsInt(args[0]);
+ flags = PyLong_AsInt(args[0]);
if (flags == -1 && PyErr_Occurred()) {
goto exit;
}
@@ -741,29 +743,29 @@ _tkinter_create(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (nargs < 4) {
goto skip_optional;
}
- interactive = _PyLong_AsInt(args[3]);
- if (interactive == -1 && PyErr_Occurred()) {
+ interactive = PyObject_IsTrue(args[3]);
+ if (interactive < 0) {
goto exit;
}
if (nargs < 5) {
goto skip_optional;
}
- wantobjects = _PyLong_AsInt(args[4]);
- if (wantobjects == -1 && PyErr_Occurred()) {
+ wantobjects = PyObject_IsTrue(args[4]);
+ if (wantobjects < 0) {
goto exit;
}
if (nargs < 6) {
goto skip_optional;
}
- wantTk = _PyLong_AsInt(args[5]);
- if (wantTk == -1 && PyErr_Occurred()) {
+ wantTk = PyObject_IsTrue(args[5]);
+ if (wantTk < 0) {
goto exit;
}
if (nargs < 7) {
goto skip_optional;
}
- sync = _PyLong_AsInt(args[6]);
- if (sync == -1 && PyErr_Occurred()) {
+ sync = PyObject_IsTrue(args[6]);
+ if (sync < 0) {
goto exit;
}
if (nargs < 8) {
@@ -814,7 +816,7 @@ _tkinter_setbusywaitinterval(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
int new_val;
- new_val = _PyLong_AsInt(arg);
+ new_val = PyLong_AsInt(arg);
if (new_val == -1 && PyErr_Occurred()) {
goto exit;
}
diff --git a/setup.py b/setup.py
index f379305..cf7b6ad 100644
--- a/setup.py
+++ b/setup.py
@@ -3,11 +3,11 @@ from distutils.core import setup, Extension
module1 = Extension('_tkinter',
libraries=['tcl8.6', 'tk8.6'],
sources=['_tkinter.c'],
- include_dirs=['/app/include/'])
+ include_dirs=['/app/include/', '/usr/include/python3.13/internal/'])
setup(
name='tkinter-standalone',
- version='3.11',
+ version='3.13',
description='Tkinter packaged as an external package for flatpak.',
ext_modules=[module1],
packages=["tkinter"]
+40
View File
@@ -0,0 +1,40 @@
{
"name": "pypi-dependencies",
"buildsystem": "simple",
"build-commands": [],
"modules": [
{
"name": "python3-PySimpleGUI",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"PySimpleGUI\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4d/d9/3de4b7ca71a7779e4f4a160088621b072a29d9b814a7fa9b5411571f4849/pysimplegui-5.0.8.3-py3-none-any.whl",
"sha256": "67e35ad6dd76e9369051261114f4711308e87815a0488f7fa28b37c29a546f8b"
}
]
},
{
"name": "python3-qet-tb-generator",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"qet-tb-generator\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4d/d9/3de4b7ca71a7779e4f4a160088621b072a29d9b814a7fa9b5411571f4849/pysimplegui-5.0.8.3-py3-none-any.whl",
"sha256": "67e35ad6dd76e9369051261114f4711308e87815a0488f7fa28b37c29a546f8b"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/63/d6/81de49a3ccec259583241fec4d79c668eff4acf9eb4d0226db36e1399f2d/qet_tb_generator-1.3.1-py3-none-any.whl",
"sha256": "80fb4af229edfd5774e61f96fa387ff394d5060abd0ca45c3c74d29de1ce9b53"
}
]
}
]
}
+58
View File
@@ -0,0 +1,58 @@
{
"//note": "The `tkinter` module is missing from the Freedesktop Sdk's Python installation",
"name": "tkinter",
"buildsystem": "simple",
"build-commands": [
"pip3 install --prefix=${FLATPAK_DEST} --no-build-isolation ."
],
"sources": [
{
"type": "git",
"url": "https://github.com/iwalton3/tkinter-standalone",
"commit": "88aa05075d90d393a29a484bce676e237d311082"
},
{
"type": "patch",
"path": "patches/tkinter-build.patch"
}
],
"modules": [
{
"name": "tcl",
"buildsystem": "autotools",
"subdir": "unix",
"post-install": [
"chmod 755 /app/lib/libtcl*.so"
],
"cleanup": [
"/bin"
],
"sources": [
{
"type": "archive",
"url": "https://prdownloads.sourceforge.net/tcl/tcl8.6.17-src.tar.gz",
"sha256": "a3903371efcce8a405c5c245d029e9f6850258a60fa3761c4d58995610949b31"
}
]
},
{
"name": "tk",
"buildsystem": "autotools",
"subdir": "unix",
"post-install": [
"chmod 755 /app/lib/libtk*.so"
],
"cleanup": [
"/bin",
"/lib/tk*/demos"
],
"sources": [
{
"type": "archive",
"url": "https://prdownloads.sourceforge.net/tcl/tk8.6.17-src.tar.gz",
"sha256": "e4982df6f969c08bf9dd858a6891059b4a3f50dc6c87c10abadbbe2fc4838946"
}
]
}
]
}
+2
View File
@@ -112,6 +112,8 @@ set(QET_SRC_FILES
${QET_DIR}/sources/conductorautonumerotation.cpp
${QET_DIR}/sources/conductorautonumerotation.h
${QET_DIR}/sources/conductornumexport.cpp
${QET_DIR}/sources/wiringlistexport.h
${QET_DIR}/sources/wiringlistexport.cpp
${QET_DIR}/sources/conductornumexport.h
${QET_DIR}/sources/conductorprofile.cpp
${QET_DIR}/sources/conductorprofile.h
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+289 -181
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+298 -190
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+288 -180
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+287 -179
View File
File diff suppressed because it is too large Load Diff
+95 -13
View File
@@ -67,7 +67,10 @@ ElementsPanel::ElementsPanel(QWidget *parent) :
connect(this, &ElementsPanel::itemDoubleClicked, this, &ElementsPanel::slot_doubleClick);
connect(this, &GenericPanel::firstActivated, [this]() {QTimer::singleShot(250, this, SLOT(reload()));});
connect(this, &ElementsPanel::panelContentChanged, this, &ElementsPanel::panelContentChange);
// manage signal itemClicked
connect(this, &ElementsPanel::itemClicked, this, &ElementsPanel::slot_clicked);
//Emit a signal instead au manage is own context menu
setContextMenuPolicy(Qt::CustomContextMenu);
}
@@ -139,15 +142,26 @@ QTreeWidgetItem *ElementsPanel::addProject(QETProject *project,
Q_UNUSED(options)
bool first_add = (first_reload_ || !projects_to_display_.contains(project));
clearSelection();
// create the QTreeWidgetItem representing the project
// create the QTreeWidgetItem representing the project
QTreeWidgetItem *qtwi_project = GenericPanel::addProject(project, nullptr, GenericPanel::All);
// the project will be inserted right before the common tb templates collection
// the project will be inserted right before the common tb templates collection
invisibleRootItem() -> insertChild(
indexOfTopLevelItem(common_tbt_collection_item_),
qtwi_project
);
if (first_add) qtwi_project -> setExpanded(true);
if (first_add){
qtwi_project -> setExpanded(true);
// on adding an project select first diagram
setCurrentItem(qtwi_project -> child(0));
qtwi_project -> child(0)->setSelected(true);
}
else {
// on adding an diagram to project select the last diagram
setCurrentItem(qtwi_project->child(qtwi_project->childCount()-2));
qtwi_project->child(qtwi_project->childCount()-2)->setSelected(true);
}
if (TitleBlockTemplatesCollection *tbt_collection = project -> embeddedTitleBlockTemplatesCollection()) {
if (QTreeWidgetItem *tbt_collection_qtwi = itemForTemplatesCollection(tbt_collection)) {
@@ -258,21 +272,28 @@ void ElementsPanel::reload()
}
/**
Gere le double-clic sur un element.
Si un double-clic sur un projet est effectue, le signal requestForProject
est emis.
Si un double-clic sur un schema est effectue, le signal requestForDiagram
est emis.
@brief ElementsPanel::slot_clicked
handle click on qtwi
@param qtwi item that was clickerd on
*/
void ElementsPanel::slot_clicked(QTreeWidgetItem *clickedItem, int) {
requestForItem(clickedItem);
}
/**
@brief ElementsPanel::slot_doubleClick
handle double click on qtwi
@param qtwi
*/
void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) {
int qtwi_type = qtwi -> type();
if (qtwi_type == QET::Project) {
QETProject *project = valueForItem<QETProject *>(qtwi);
emit(requestForProject(project));
// open project properties
emit(requestForProjectPropertiesEdition());
} else if (qtwi_type == QET::Diagram) {
Diagram *diagram = valueForItem<Diagram *>(qtwi);
diagram->showMe();
// open diagram properties
emit(requestForDiagramPropertiesEdition());
} else if (qtwi_type == QET::TitleBlockTemplate) {
TitleBlockTemplateLocation tbt = valueForItem<TitleBlockTemplateLocation>(qtwi);
emit(requestForTitleBlockTemplate(tbt));
@@ -444,3 +465,64 @@ void ElementsPanel::ensureHierarchyIsVisible(const QList<QTreeWidgetItem *> &ite
if (parent_qtwi -> isHidden()) parent_qtwi -> setHidden(false);
}
}
/**
* @brief ElementsPanel::syncTabBars
* set the project- or diagram Tab corresponding to
* the selection in the treeView
*/
void ElementsPanel::requestForItem(QTreeWidgetItem *clickedItem)
{
// activate diagram
if(clickedItem->type() == QET::Diagram){
Diagram *diagram = valueForItem<Diagram *>(clickedItem);
// if we click on diagramItem in annother project we need the other project
emit(requestForProject(projectForItem(clickedItem->parent())));
// required for keyPressEvent
// after emit the focus is on the diagram editor, we put it back to elementsPanel
this->setFocus();
// activate diagram
diagram->showMe();
}
// activate project
else if(clickedItem->type() == QET::Project) {
QETProject *project = projectForItem(clickedItem);
emit(requestForProject(project));
this->setFocus();
}
}
/**
* @brief ElementsPanel::keyPressEvent
* @param event
*/
void ElementsPanel::keyPressEvent(QKeyEvent *event)
{
switch (event->key())
{
case Qt::Key_Up:{
// check if there is another item abbove
if(!itemAbove(currentItem()))
break;
setCurrentItem(itemAbove(currentItem()));
if (currentItem()->type()==QET::Diagram || currentItem()->type()==QET::Project){
requestForItem(currentItem());
}
break;
}
case Qt::Key_Down:{
// check if there is another item below
if(!itemBelow(currentItem()))
break;
setCurrentItem(itemBelow(currentItem()));
if (currentItem()->type()==QET::Diagram || currentItem()->type()==QET::Project){
requestForItem(currentItem());
}
break;
}
default:
QTreeView::keyPressEvent(event);
}
}
+9 -2
View File
@@ -53,8 +53,13 @@ class ElementsPanel : public GenericPanel {
signals:
void requestForProject(QETProject *);
void requestForTitleBlockTemplate(const TitleBlockTemplateLocation &);
// Signal to open the project properties
void requestForProjectPropertiesEdition();
// Signal to open the diagram properties
void requestForDiagramPropertiesEdition();
public slots:
void slot_clicked(QTreeWidgetItem *, int);
void slot_doubleClick(QTreeWidgetItem *, int);
void reload();
void filter(const QString &, QET::Filtering = QET::RegularFilter);
@@ -63,7 +68,9 @@ class ElementsPanel : public GenericPanel {
void buildFilterList();
void applyCurrentFilter(const QList<QTreeWidgetItem *> &);
void ensureHierarchyIsVisible(const QList<QTreeWidgetItem *> &);
void requestForItem(QTreeWidgetItem *);
void keyPressEvent(QKeyEvent *event)override;
protected:
void startDrag(Qt::DropActions) override;
void startTitleBlockTemplateDrag(const TitleBlockTemplateLocation &);
+7
View File
@@ -120,6 +120,12 @@ ElementsPanelWidget::ElementsPanelWidget(QWidget *parent) : QWidget(parent) {
SLOT(openTitleBlockTemplate(const TitleBlockTemplateLocation &))
);
// manage double click on TreeWidgetItem
connect(elements_panel, SIGNAL(requestForProjectPropertiesEdition()), this, SLOT(editProjectProperties()) );
connect(elements_panel, SIGNAL(requestForDiagramPropertiesEdition()), this, SLOT(editDiagramProperties()) );
// manage project activation
connect(elements_panel, SIGNAL(requestForProject(QETProject*)), this, SIGNAL(requestForProject(QETProject*)));
// disposition verticale
QVBoxLayout *vlayout = new QVBoxLayout(this);
vlayout -> setContentsMargins(0,0,0,0);
@@ -236,6 +242,7 @@ void ElementsPanelWidget::deleteDiagram()
{
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
emit(requestForDiagramDeletion(selected_diagram));
elements_panel->reload();
}
}
+2 -3
View File
@@ -766,7 +766,6 @@ void GenericPanel::projectDiagramsOrderChanged(QETProject *project,
if (!moved_qtwi_diagram) return;
// remove the QTWI then insert it back at the adequate location
bool was_selected = moved_qtwi_diagram -> isSelected();
qtwi_project -> removeChild (moved_qtwi_diagram);
qtwi_project -> insertChild (to, moved_qtwi_diagram);
@@ -781,8 +780,8 @@ void GenericPanel::projectDiagramsOrderChanged(QETProject *project,
updateDiagramItem(qtwi_diagram, diagram);
}
if (was_selected)
setCurrentItem(moved_qtwi_diagram);
// select the moved diagram
setCurrentItem(qtwi_project -> child(from));
emit(panelContentChanged());
}
+57 -18
View File
@@ -721,6 +721,14 @@ void ProjectView::initActions()
m_end_view = new QAction(QET::Icons::ArrowRightDouble, tr("Aller à la fin du projet"),this);
connect(m_end_view, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(lastDiagram());});
// button to scroll one page left
m_next_view_left = new QAction(QET::Icons::ArrowLeft, tr("go one page left"),this);
connect(m_next_view_left, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(previousDiagram());});
// button to scroll one page right
m_next_view_right = new QAction(QET::Icons::ArrowRight, tr("go one page right"),this);
connect(m_next_view_right, &QAction::triggered, [this](){this->m_tab->setCurrentWidget(nextDiagram());});
}
/**
@@ -748,34 +756,65 @@ void ProjectView::initWidgets()
m_tab = new QTabWidget(this);
#endif
m_tab -> setMovable(true);
// setting UsesScrollButton ensures that when the tab bar is full, the tabs are scrolled.
m_tab -> setUsesScrollButtons(true);
// disable the internal scroll buttons of the TabWidget, we will use our own buttons.
m_tab->setStyleSheet("QTabBar QToolButton {border-image: ;border-width: 0px}");
m_tab->setStyleSheet("QTabBar::scroller {width: 0px;}");
// add layouts
QHBoxLayout *TopRightCorner_Layout = new QHBoxLayout();
TopRightCorner_Layout->setContentsMargins(0,0,0,0);
// some place left to the 'next_right_view_button' button
TopRightCorner_Layout->insertSpacing(1,10);
QToolButton *add_new_diagram_button = new QToolButton;
add_new_diagram_button -> setDefaultAction(m_add_new_diagram);
add_new_diagram_button -> setAutoRaise(true);
TopRightCorner_Layout->addWidget(add_new_diagram_button);
QHBoxLayout *TopLeftCorner_Layout = new QHBoxLayout();
TopLeftCorner_Layout->setContentsMargins(0,0,0,0);
// add buttons
QToolButton *m_next_right_view_button =new QToolButton;
m_next_right_view_button->setDefaultAction(m_next_view_right);
m_next_right_view_button->setAutoRaise(true);
TopRightCorner_Layout->addWidget(m_next_right_view_button);
connect(m_tab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
connect(m_tab, SIGNAL(tabBarDoubleClicked(int)), this, SLOT(tabDoubleClicked(int)));
connect(m_tab->tabBar(), SIGNAL(tabMoved(int, int)), this, SLOT(tabMoved(int, int)), Qt::QueuedConnection);
//arrows button to return on first view
QToolButton *m_first_view_button =new QToolButton;
m_first_view_button->setDefaultAction(m_first_view);
m_first_view_button->setAutoRaise(true);
m_tab->setCornerWidget(m_first_view_button, Qt::TopLeftCorner);
//arrows button to go on last view
QToolButton *m_end_view_button =new QToolButton;
m_end_view_button->setDefaultAction(m_end_view);
m_end_view_button->setAutoRaise(true);
TopRightCorner_Layout->addWidget(m_end_view_button);
QWidget *tabwidget=new QWidget(this);
tabwidget->setLayout(TopRightCorner_Layout);
m_tab -> setCornerWidget(tabwidget, Qt::TopRightCorner);
QToolButton *add_new_diagram_button = new QToolButton;
add_new_diagram_button -> setDefaultAction(m_add_new_diagram);
add_new_diagram_button -> setAutoRaise(true);
TopRightCorner_Layout->addWidget(add_new_diagram_button);
// some place right to the 'add_new_diagram_button' button
TopRightCorner_Layout->addSpacing(5);
QToolButton *m_first_view_button =new QToolButton;
m_first_view_button->setDefaultAction(m_first_view);
m_first_view_button->setAutoRaise(true);
TopLeftCorner_Layout->addWidget(m_first_view_button);
QToolButton *m_next_left_view_button =new QToolButton;
m_next_left_view_button->setDefaultAction(m_next_view_left);
m_next_left_view_button->setAutoRaise(true);
TopLeftCorner_Layout->addWidget(m_next_left_view_button);
// some place right to the 'first_view_button' button
TopLeftCorner_Layout->addSpacing(10);
// add widgets to tabbar
QWidget *tabwidgetRight=new QWidget(this);
tabwidgetRight->setLayout(TopRightCorner_Layout);
m_tab -> setCornerWidget(tabwidgetRight, Qt::TopRightCorner);
QWidget *tabwidgetLeft=new QWidget(this);
tabwidgetLeft->setLayout(TopLeftCorner_Layout);
m_tab -> setCornerWidget(tabwidgetLeft, Qt::TopLeftCorner);
// manage signals
connect(m_tab, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
connect(m_tab, SIGNAL(tabBarDoubleClicked(int)), this, SLOT(tabDoubleClicked(int)));
connect(m_tab->tabBar(), SIGNAL(tabMoved(int,int)), this, SLOT(tabMoved(int,int)), Qt::QueuedConnection);
fallback_widget_ -> setVisible(false);
m_tab -> setVisible(false);
+4 -2
View File
@@ -168,8 +168,10 @@ class ProjectView : public QWidget
// attributes
private:
QAction *m_add_new_diagram,
*m_first_view,
*m_end_view;
*m_first_view,
*m_end_view,
*m_next_view_left,
*m_next_view_right;
QETProject *m_project;
QVBoxLayout *layout_;
QWidget *fallback_widget_;
+45 -18
View File
@@ -45,6 +45,7 @@
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
#include "ui/diagrameditorhandlersizewidget.h"
#include "TerminalStrip/ui/addterminalstripitemdialog.h"
#include "wiringlistexport.h"
#ifdef BUILD_WITHOUT_KF5
#else
@@ -465,13 +466,23 @@ void QETDiagramEditor::setUpActions()
wne.toCsv();
}
});
#ifdef QET_EXPORT_PROJECT_DB
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
connect(m_export_project_db, &QAction::triggered, [this]() {
projectDataBase::exportDb(this->currentProject()->dataBase(), this);
// Export wiring list to CSV
m_project_export_wiring_list = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter le plan de câblage"), this);
connect(m_project_export_wiring_list, &QAction::triggered, [this]() {
QETProject *project = this->currentProject();
if (project)
{
WiringListExport wle(project, this);
wle.toCsv();
}
});
#endif
#ifdef QET_EXPORT_PROJECT_DB
m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this);
connect(m_export_project_db, &QAction::triggered, [this]() {
projectDataBase::exportDb(this->currentProject()->dataBase(), this);
});
#endif
//MDI view style
m_tabbed_view_mode = new QAction(tr("en utilisant des onglets"), this);
@@ -835,6 +846,7 @@ void QETDiagramEditor::setUpMenu()
menu_project -> addAction(m_project_export_conductor_num);
menu_project -> addAction(m_terminal_strip_dialog);
menu_project -> addAction(m_project_terminalBloc);
menu_project -> addAction(m_project_export_wiring_list);
#ifdef QET_EXPORT_PROJECT_DB
menu_project -> addSeparator();
menu_project -> addAction(m_export_project_db);
@@ -1168,18 +1180,6 @@ bool QETDiagramEditor::addProject(QETProject *project, bool update_panel)
// cree un ProjectView pour visualiser le projet
ProjectView *project_view = new ProjectView(project);
//Highlight the current page
connect(project_view, &ProjectView::diagramActivated, this, [this](DiagramView *dv) {
if (dv && dv->diagram() && pa) {
// 1. Find the item in the tree that corresponds to this diagram
QTreeWidgetItem *item = pa->elementsPanel().getItemForDiagram(dv->diagram());
// 2. If you find it, select it
if (item) {
pa->elementsPanel().setCurrentItem(item);
}
}
});
addProjectView(project_view);
undo_group.addStack(project -> undoStack());
@@ -1579,6 +1579,7 @@ void QETDiagramEditor::slot_updateActions()
m_csv_export -> setEnabled(editable_project);
m_project_export_conductor_num-> setEnabled(opened_project);
m_terminal_strip_dialog -> setEnabled(editable_project);
m_project_export_wiring_list -> setEnabled(opened_project);
#ifdef QET_EXPORT_PROJECT_DB
m_export_project_db -> setEnabled(editable_project);
#endif
@@ -1840,6 +1841,31 @@ void QETDiagramEditor::addProjectView(ProjectView *project_view)
connect(project_view, SIGNAL(errorEncountered(QString)),
this, SLOT(showError(const QString &)));
//Highlight the current page
connect(project_view, &ProjectView::diagramActivated, this, [this](DiagramView *dv) {
if (dv && dv->diagram() && pa) {
// 1. Find the item in the tree that corresponds to this diagram
QTreeWidgetItem *item = pa->elementsPanel().getItemForDiagram(dv->diagram());
// 2. If you find it, select it
if (item) {
pa->elementsPanel().setCurrentItem(item);
}
}
});
//Highlight the current page in projectView on project activation
connect(this, &QETDiagramEditor::syncElementsPanel, this, [this]() {
if (pa && currentDiagramView()) {
// In the tree, find the element that corresponds to the diagram of the selected project.
QTreeWidgetItem *item = pa->elementsPanel().getItemForDiagram(currentDiagramView()->diagram());
if (item) {
// select the diagram
pa->elementsPanel().setCurrentItem(item);
}
}
});
//We maximise the new window if the current window is inexistent or maximized
QWidget *current_window = m_workspace.activeSubWindow();
bool maximise = ((!current_window)
@@ -2348,6 +2374,7 @@ void QETDiagramEditor::subWindowActivated(QMdiSubWindow *subWindows)
slot_updateActions();
slot_updateWindowsMenu();
emit syncElementsPanel();
}
/**
+4
View File
@@ -98,6 +98,9 @@ class QETDiagramEditor : public QETMainWindow
ProjectView *findProject(const QString &) const;
QMdiSubWindow *subWindowForWidget(QWidget *) const;
signals:
void syncElementsPanel();
public slots:
void save();
void saveAs();
@@ -197,6 +200,7 @@ class QETDiagramEditor : public QETMainWindow
*m_terminal_strip_dialog = nullptr, ///<Launch terminal strip dialog
*m_project_terminalBloc, ///< generate terminal block
*m_project_export_conductor_num,///<Export the wire num to csv
*m_project_export_wiring_list, ///< Action to export the wiring list
*m_export_project_db, ///Export to file the internal database of the current project
*m_tile_window, ///< Show MDI subwindows as tile
*m_cascade_window, ///< Show MDI subwindows as cascade
+290
View File
@@ -0,0 +1,290 @@
#include "wiringlistexport.h"
#include "qetproject.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>
#include <QDomDocument>
#include <QFile>
#include <QRegularExpression>
#include <QQueue>
#include <QSet>
WiringListExport::WiringListExport(QETProject *project, QWidget *parent) :
QObject(parent),
m_project(project),
m_parent(parent)
{
}
QString WiringListExport::normalizeUuid(const QString &u) const
{
QString res = u;
res.remove('{').remove('}');
return res.trimmed().toLower();
}
QString WiringListExport::findDiagramFolio(const QDomElement &diagramElem) const
{
if (diagramElem.isNull()) return "";
if (diagramElem.hasAttribute("folio")) return diagramElem.attribute("folio");
if (diagramElem.hasAttribute("title")) return diagramElem.attribute("title");
return "";
}
QDomElement WiringListExport::climbToDiagram(QDomNode node) const
{
while (!node.isNull()) {
if (node.isElement() && node.toElement().tagName().toLower() == "diagram") {
return node.toElement();
}
node = node.parentNode();
}
return QDomElement();
}
QMap<QString, ElementInfo> WiringListExport::collectElementsInfo(const QDomElement &root) const
{
QMap<QString, ElementInfo> infoMap;
QDomNodeList elements = root.elementsByTagName("element");
for (int i = 0; i < elements.size(); ++i) {
QDomElement el = elements.at(i).toElement();
QString uuid = normalizeUuid(el.attribute("uuid", el.attribute("id", "")));
if (uuid.isEmpty()) continue;
ElementInfo info;
info.folio = findDiagramFolio(climbToDiagram(el));
QDomElement linksNode = el.firstChildElement("links_uuids");
if (!linksNode.isNull()) {
QDomNodeList linkUuids = linksNode.elementsByTagName("link_uuid");
for (int j = 0; j < linkUuids.size(); ++j) {
QString luuid = normalizeUuid(linkUuids.at(j).toElement().attribute("uuid"));
if (!luuid.isEmpty()) info.links.append(luuid);
}
}
QDomElement elInfoNode = el.firstChildElement("elementInformations");
if (!elInfoNode.isNull()) {
QDomNodeList eics = elInfoNode.elementsByTagName("elementInformation");
for (int j = 0; j < eics.size(); ++j) {
QDomElement eic = eics.at(j).toElement();
QString nameAttr = eic.attribute("name").toLower();
if (nameAttr == "label") info.label = eic.text().trimmed();
if (nameAttr == "name") info.name = eic.text().trimmed();
}
}
QString typeVal = el.attribute("type").toLower();
if (typeVal.contains("naechste") || typeVal.contains("vorherige") ||
typeVal.contains("next") || typeVal.contains("previous")) {
info.isPlaceholder = true;
}
infoMap.insert(uuid, info);
}
return infoMap;
}
QList<ConductorData> WiringListExport::collectConductors(const QDomElement &root) const
{
QList<ConductorData> conductors;
QDomNodeList conductorNodes = root.elementsByTagName("conductor");
for (int i = 0; i < conductorNodes.size(); ++i) {
QDomElement cond = conductorNodes.at(i).toElement();
if (cond.attribute("num") == "Brücke") continue;
ConductorData data;
data.index = i;
data.el1_uuid = normalizeUuid(cond.attribute("element1", cond.attribute("element1id", "")));
data.el2_uuid = normalizeUuid(cond.attribute("element2", cond.attribute("element2id", "")));
data.element1_label = cond.attribute("element1_label");
data.element2_label = cond.attribute("element2_label");
data.terminalname1 = cond.attribute("terminalname1");
data.terminalname2 = cond.attribute("terminalname2");
data.tension_protocol = cond.attribute("tension_protocol");
data.conductor_color = cond.attribute("conductor_color");
data.conductor_section = cond.attribute("conductor_section");
data.function = cond.attribute("function");
QDomElement diag = climbToDiagram(cond);
data.folio = findDiagramFolio(diag);
if (data.folio.isEmpty()) data.folio = cond.attribute("folio", cond.attribute("page", ""));
conductors.append(data);
}
return conductors;
}
void WiringListExport::resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const
{
QRegularExpression numericLabelRe("^\\d+(\\.\\d+)?$");
QMap<QString, QList<ConductorData>> el_to_cons;
for (const ConductorData &c : conductors) {
if (!c.el1_uuid.isEmpty()) el_to_cons[c.el1_uuid].append(c);
if (!c.el2_uuid.isEmpty()) el_to_cons[c.el2_uuid].append(c);
}
for (int i = 0; i < conductors.size(); ++i) {
ConductorData &c = conductors[i];
auto resolveSide = [&](const QString &startUuid, QString &outLabel, QString &outTerminal) {
if (startUuid.isEmpty() || !elementsInfo.contains(startUuid)) return;
const ElementInfo &startInfo = elementsInfo[startUuid];
if (!startInfo.links.isEmpty() || startInfo.isPlaceholder) {
QQueue<QString> q;
QSet<QString> visited;
q.enqueue(startUuid);
visited.insert(startUuid);
int depth = 0;
while (!q.isEmpty() && depth < 3) {
int levelSize = q.size();
for (int k = 0; k < levelSize; ++k) {
QString curr = q.dequeue();
if (elementsInfo.contains(curr)) {
const ElementInfo &currInfo = elementsInfo[curr];
if (!currInfo.isPlaceholder && !currInfo.label.isEmpty() && !numericLabelRe.match(currInfo.label).hasMatch()) {
outLabel = currInfo.label;
return;
}
for (const QString &lnk : currInfo.links) {
if (!visited.contains(lnk)) {
visited.insert(lnk);
q.enqueue(lnk);
}
}
}
for (const ConductorData &cond : el_to_cons.value(curr)) {
if (cond.index == c.index) continue;
QString other;
QString terminalHint;
if (cond.el1_uuid == curr) {
other = cond.el2_uuid;
terminalHint = cond.terminalname2;
} else {
other = cond.el1_uuid;
terminalHint = cond.terminalname1;
}
if (!other.isEmpty() && !visited.contains(other)) {
if (elementsInfo.contains(other)) {
const ElementInfo &oInfo = elementsInfo[other];
if (!oInfo.isPlaceholder && !oInfo.label.isEmpty() && !numericLabelRe.match(oInfo.label).hasMatch()) {
outLabel = oInfo.label;
if (outTerminal.isEmpty()) outTerminal = terminalHint;
return;
}
}
visited.insert(other);
q.enqueue(other);
}
}
}
depth++;
}
} else {
if (outLabel.isEmpty()) {
outLabel = startInfo.label.isEmpty() ? startInfo.name : startInfo.label;
}
}
};
bool p1 = elementsInfo.value(c.el1_uuid).isPlaceholder;
bool p2 = elementsInfo.value(c.el2_uuid).isPlaceholder;
if (c.element1_label.isEmpty() || p1) {
if (p1) c.element1_label = "";
resolveSide(c.el1_uuid, c.element1_label, c.terminalname1);
}
if (c.element2_label.isEmpty() || p2) {
if (p2) c.element2_label = "";
resolveSide(c.el2_uuid, c.element2_label, c.terminalname2);
}
}
}
void WiringListExport::toCsv()
{
if (!m_project) return;
QDomDocument doc = m_project->toXml();
if (doc.isNull()) {
QMessageBox::warning(m_parent, tr("Erreur"), tr("Impossible de lire la structure en mémoire du projet."));
return;
}
QFileDialog dialog(m_parent);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setWindowTitle(tr("Exporter le plan de câblage"));
dialog.setDefaultSuffix("csv");
dialog.setNameFilter(tr("Fichiers CSV (*.csv)"));
if (dialog.exec() != QDialog::Accepted) return;
QString fileName = dialog.selectedFiles().first();
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QMessageBox::warning(m_parent, tr("Erreur"), tr("Impossible d'ouvrir le fichier pour l'écriture."));
return;
}
QMap<QString, ElementInfo> elementsInfo = collectElementsInfo(doc.documentElement());
QList<ConductorData> conductors = collectConductors(doc.documentElement());
resolveEndpoints(conductors, elementsInfo);
QList<ConductorData> uniqueConductors;
QSet<QString> seenConnections;
for (const ConductorData &c : conductors) {
if (c.element1_label.isEmpty() && c.element2_label.isEmpty()) continue;
QString sideA = c.element1_label + ":" + c.terminalname1;
QString sideB = c.element2_label + ":" + c.terminalname2;
QString key = (sideA < sideB) ? (sideA + "||" + sideB) : (sideB + "||" + sideA);
if (!seenConnections.contains(key)) {
seenConnections.insert(key);
uniqueConductors.append(c);
}
}
QTextStream out(&file);
out << tr("Page", "Wiring list CSV header") << ";"
<< tr("Composant 1", "Wiring list CSV header") << ";"
<< tr("Borne 1", "Wiring list CSV header") << ";"
<< tr("Composant 2", "Wiring list CSV header") << ";"
<< tr("Borne 2", "Wiring list CSV header") << ";"
<< tr("Tension / Protocole", "Wiring list CSV header") << ";"
<< tr("Couleur du fil", "Wiring list CSV header") << ";"
<< tr("Section du fil", "Wiring list CSV header") << ";"
<< tr("Fonction", "Wiring list CSV header") << "\n";
for (const ConductorData &c : uniqueConductors) {
out << c.folio << ";"
<< c.element1_label << ";"
<< c.terminalname1 << ";"
<< c.element2_label << ";"
<< c.terminalname2 << ";"
<< c.tension_protocol << ";"
<< c.conductor_color << ";"
<< c.conductor_section << ";"
<< c.function << "\n";
}
file.close();
QMessageBox::information(m_parent, tr("Export réussi"), tr("Le plan de câblage a été exporté avec succès !"));
}
+71
View File
@@ -0,0 +1,71 @@
#ifndef WIRINGLISTEXPORT_H
#define WIRINGLISTEXPORT_H
#include <QObject>
#include <QString>
#include <QMap>
#include <QList>
#include <QStringList>
class QETProject;
class QWidget;
class QDomElement;
class QDomNode;
// Internal data structures for parsing the XML graph
struct ElementInfo {
QString folio;
QStringList links;
QString label;
QString name;
bool isPlaceholder = false;
};
struct ConductorData {
int index = 0;
QString el1_uuid;
QString el2_uuid;
QString element1_label;
QString element2_label;
QString terminalname1;
QString terminalname2;
QString tension_protocol;
QString conductor_color;
QString conductor_section;
QString function;
QString folio;
// Resolved endpoints
QString chosen_a_uuid;
QString chosen_a_label;
QString chosen_b_uuid;
QString chosen_b_label;
};
/**
* @brief The WiringListExport class
* Handles the export of the wiring list (Verdrahtungsplan) to a CSV file.
* Automatically resolves links and placeholders to find physical endpoints.
*/
class WiringListExport : public QObject
{
Q_OBJECT
public:
explicit WiringListExport(QETProject *project, QWidget *parent = nullptr);
void toCsv();
private:
QETProject *m_project;
QWidget *m_parent;
QString normalizeUuid(const QString &u) const;
QString findDiagramFolio(const QDomElement &diagramElem) const;
QDomElement climbToDiagram(QDomNode node) const;
QMap<QString, ElementInfo> collectElementsInfo(const QDomElement &root) const;
QList<ConductorData> collectConductors(const QDomElement &root) const;
void resolveEndpoints(QList<ConductorData> &conductors, const QMap<QString, ElementInfo> &elementsInfo) const;
};
#endif // WIRINGLISTEXPORT_H