mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-06-10 12:53:14 +02:00
Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f70468a29 | |||
| f60acad3b3 | |||
| 03bb97b529 | |||
| a4b90f3cc7 | |||
| d57a219977 | |||
| 03afa9e318 | |||
| 37cec4afce | |||
| 12f04a7b08 | |||
| ba77b3dabb | |||
| 2e6953bbd0 | |||
| c4e05f817c | |||
| eb8f859038 | |||
| 16650ed6af | |||
| 3b3171dc93 | |||
| 500c42c86b | |||
| 2f3e46e488 | |||
| 290ef97ec2 | |||
| f0923e7560 | |||
| b32de35afd | |||
| 8aad1c0cab | |||
| d365e19619 | |||
| 27b977e9f3 | |||
| 54e19f4074 | |||
| 8af1fd708f | |||
| a64e414d63 | |||
| 2ed8d76e2d | |||
| 679647f52a | |||
| a82f6de23b | |||
| 6452e03cdc | |||
| 51725d9d8e | |||
| a45a7d4e4d | |||
| bc9173d726 | |||
| 19712d72ef | |||
| f23ec620dc | |||
| 47d2107d99 | |||
| 0a4c3f4601 | |||
| ab24b74c72 | |||
| 380d12e675 | |||
| d0d3194afa | |||
| b18f5f5e41 | |||
| 8a1b0575ab | |||
| 67ec648706 | |||
| 9b77b4d4fa | |||
| 225edec091 | |||
| 62dbaddab2 | |||
| f5857bb1fd | |||
| 825eeb77e4 | |||
| 780cf8b054 | |||
| 605392cf9b | |||
| 3795ddb1f5 | |||
| ecee2209e6 | |||
| 246dd0a42f | |||
| 89a4aaac28 | |||
| 79edc3fbb7 | |||
| 52f61ab500 | |||
| 1bbb374094 | |||
| c220d84fcb | |||
| 4834d41432 | |||
| 378aa8899f | |||
| 0cd71cbe16 | |||
| 9344515d2a | |||
| 9149128f7a | |||
| 5296c1b478 | |||
| b4c8af55d3 | |||
| cb47094a1f | |||
| 3f1db24d6d | |||
| 1af0c1ca8b | |||
| bea1fb4353 | |||
| 2f69716e3c | |||
| 277fa087bc | |||
| 9693df4252 | |||
| 6b80fbb08d | |||
| 7425c83231 |
@@ -15,10 +15,10 @@ The main goal of the developers is to provide a libre, easy to use and effective
|
||||
|
||||
### Version
|
||||
|
||||
The current stable version is 0.90 and was released on 2023.01.06.
|
||||
The current stable version is 0.100 and was released on 2026.01.25.
|
||||
Once it has been officially released, the stable version is always frozen and is no longer developed.
|
||||
|
||||
New functionalities, bug and issue fixings are further made in the development version (currently 0.100), which can also be [downloaded](https://qelectrotech.org/download.php).
|
||||
New functionalities, bug and issue fixings are further made in the development version (currently 0.100.1 or 0.200.0 if based on new Qt6 port), which can also be [downloaded](https://qelectrotech.org/download.php).
|
||||
|
||||
Users who want to test and take benefits from the last software implementations should use the development version. But... use it at your own risk, since things are sometimes broken or only partially implemented until they are done!
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+3
-16
@@ -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"]
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -88,6 +88,7 @@ set(QET_RES_FILES
|
||||
${QET_DIR}/sources/ui/dynamicelementtextitemeditor.ui
|
||||
${QET_DIR}/sources/ui/elementinfopartwidget.ui
|
||||
${QET_DIR}/sources/ui/elementinfowidget.ui
|
||||
${QET_DIR}/sources/ui/terminalnumberingdialog.ui
|
||||
${QET_DIR}/sources/ui/formulaassistantdialog.ui
|
||||
${QET_DIR}/sources/ui/imagepropertieswidget.ui
|
||||
${QET_DIR}/sources/ui/importelementdialog.ui
|
||||
@@ -112,6 +113,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
|
||||
@@ -630,6 +633,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/ui/elementinfopartwidget.h
|
||||
${QET_DIR}/sources/ui/elementinfowidget.cpp
|
||||
${QET_DIR}/sources/ui/elementinfowidget.h
|
||||
${QET_DIR}/sources/ui/terminalnumberingdialog.cpp
|
||||
${QET_DIR}/sources/ui/terminalnumberingdialog.h
|
||||
${QET_DIR}/sources/ui/elementpropertieswidget.cpp
|
||||
${QET_DIR}/sources/ui/elementpropertieswidget.h
|
||||
${QET_DIR}/sources/ui/formulaassistantdialog.cpp
|
||||
|
||||
+1
-1
Submodule elements updated: 4e7f569dca...2bc4c95cc4
+777
-533
File diff suppressed because it is too large
Load Diff
+948
-665
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+920
-534
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+785
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+781
-536
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+776
-532
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+1063
-905
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+14539
File diff suppressed because it is too large
Load Diff
+777
-534
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+779
-535
File diff suppressed because it is too large
Load Diff
+942
-664
File diff suppressed because it is too large
Load Diff
+777
-534
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
+777
-533
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ Icon=qelectrotech
|
||||
Terminal=false
|
||||
Type=Application
|
||||
MimeType=application/x-qet-project;application/x-qet-element;application/x-qet-titleblock;
|
||||
Categories=Graphics;Qt;VectorGraphics;Science;Electricity;Engineering;
|
||||
Categories=Graphics;
|
||||
Keywords=Graphics;Science;Electricity;Engineering;
|
||||
Comment=Edit electrical diagrams.
|
||||
Comment[ar]=تحرير مخططات كهربائية
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2006-2026 The QElectroTech Team -->
|
||||
<application>
|
||||
<id type="desktop">qelectrotech.desktop</id>
|
||||
<component type="desktop-application">
|
||||
<id>org.qelectrotech.QElectroTech</id>
|
||||
<launchable type="desktop-id">org.qelectrotech.QElectroTech.desktop</launchable>
|
||||
<metadata_license>MIT</metadata_license>
|
||||
<project_license>GPL-2.0-or-later</project_license>
|
||||
<name>QElectroTech</name>
|
||||
@@ -25,7 +26,7 @@
|
||||
<summary xml:lang="ru">Редактор электрических схем</summary>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<releases>
|
||||
<release version="0.9-dev" date="2021-02-21"/>
|
||||
<release version="0.100.1-dev" date="2026"/>
|
||||
</releases>
|
||||
<description>
|
||||
<p>
|
||||
@@ -93,9 +94,20 @@
|
||||
Приложение использует для хранения проектов и библиотек элементов файлы в XML формате. Приложение помимо редактора электричесих схем, содержит также редакторы элементов и редактор шаблонов листов.
|
||||
</p>
|
||||
</description>
|
||||
<url type="homepage">http://qelectrotech.org</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">http://download.tuxfamily.org/qet/screens/qelectrotech5.png</screenshot>
|
||||
</screenshots>
|
||||
<updatecontact>qet@lists.tuxfamily.org</updatecontact>
|
||||
</application>
|
||||
<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>
|
||||
<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>
|
||||
<update_contact>scorpio@qelectrotech.org</update_contact>
|
||||
</component>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
Copyright 2006-2026 The QElectroTech Team
|
||||
This file is part of QElectroTech.
|
||||
|
||||
@@ -96,8 +96,18 @@ void ElementPropertiesEditorWidget::upDateInterface()
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
ui->m_master_type_cb->setCurrentIndex(
|
||||
ui->m_master_type_cb->findData (
|
||||
m_data.m_master_type));
|
||||
ui->m_master_type_cb->findData (
|
||||
m_data.m_master_type));
|
||||
|
||||
// NEU: Checkbox und Zahlenbox für max_slaves einstellen
|
||||
if (m_data.m_max_slaves == -1) {
|
||||
ui->max_slaves_checkbox->setChecked(false);
|
||||
ui->max_slaves_spinbox->setEnabled(false);
|
||||
} else {
|
||||
ui->max_slaves_checkbox->setChecked(true);
|
||||
ui->max_slaves_spinbox->setEnabled(true);
|
||||
ui->max_slaves_spinbox->setValue(m_data.m_max_slaves);
|
||||
}
|
||||
} else if (m_data.m_type == ElementData::Terminal) {
|
||||
ui->m_terminal_type_cb->setCurrentIndex(
|
||||
ui->m_terminal_type_cb->findData(
|
||||
@@ -151,10 +161,13 @@ void ElementPropertiesEditorWidget::setUpInterface()
|
||||
ui->m_terminal_func_cb->addItem(tr("Phase"), ElementData::TFPhase);
|
||||
ui->m_terminal_func_cb->addItem(tr("Neutre"), ElementData::TFNeutral);
|
||||
|
||||
//Disable the edition of the first column of the information tree
|
||||
//by this little workaround
|
||||
//Disable the edition of the first column of the information tree
|
||||
//by this little workaround
|
||||
ui->m_tree->setItemDelegate(new EditorDelegate(this));
|
||||
ui->m_tree->header()->resizeSection(0, 150);
|
||||
|
||||
// NEU: Checkbox mit der Zahlenbox verbinden (Aktivieren/Deaktivieren)
|
||||
connect(ui->max_slaves_checkbox, SIGNAL(toggled(bool)), ui->max_slaves_spinbox, SLOT(setEnabled(bool)));
|
||||
|
||||
populateTree();
|
||||
}
|
||||
|
||||
@@ -226,6 +239,13 @@ void ElementPropertiesEditorWidget::on_m_buttonBox_accepted()
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Master) {
|
||||
m_data.m_master_type = ui->m_master_type_cb->currentData().value<ElementData::MasterType>();
|
||||
|
||||
//If the checkbox is checked, save the number; otherwise, -1 (infinity)
|
||||
if (ui->max_slaves_checkbox->isChecked()) {
|
||||
m_data.m_max_slaves = ui->max_slaves_spinbox->value();
|
||||
} else {
|
||||
m_data.m_max_slaves = -1;
|
||||
}
|
||||
}
|
||||
else if (m_data.m_type == ElementData::Terminal)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>527</width>
|
||||
<height>442</height>
|
||||
<height>492</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -104,6 +104,23 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_master_type_cb"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="max_slaves_checkbox">
|
||||
<property name="text">
|
||||
<string>Définir le nombre maximal d'esclaves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="max_slaves_spinbox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
+95
-13
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 &);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,28 +480,33 @@ void ElementsPanelWidget::keyPressEvent (QKeyEvent *e) {
|
||||
break;
|
||||
case Qt::Key_F3:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUp(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F4:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDown(selected_diagram));
|
||||
}
|
||||
break;
|
||||
case Qt::Key_F5:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpTop(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F6:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F7:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveDownx100(selected_diagram));
|
||||
}
|
||||
|
||||
@@ -502,12 +514,14 @@ void ElementsPanelWidget::keyPressEvent (QKeyEvent *e) {
|
||||
break;
|
||||
case Qt::Key_F8:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx10(selected_diagram));
|
||||
}
|
||||
|
||||
break;
|
||||
case Qt::Key_F9:
|
||||
if (Diagram *selected_diagram = elements_panel -> selectedDiagram()) {
|
||||
elements_panel->setSelectedItem(elements_panel->getItemForDiagram(selected_diagram));
|
||||
emit(requestForDiagramMoveUpx100(selected_diagram));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -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,14 @@ void GenericPanel::projectDiagramsOrderChanged(QETProject *project,
|
||||
updateDiagramItem(qtwi_diagram, diagram);
|
||||
}
|
||||
|
||||
if (was_selected)
|
||||
// select the moved diagram
|
||||
if(m_selected_item){
|
||||
setCurrentItem(moved_qtwi_diagram);
|
||||
}
|
||||
else{
|
||||
setCurrentItem(qtwi_project -> child(from));
|
||||
}
|
||||
m_selected_item = nullptr;
|
||||
|
||||
emit(panelContentChanged());
|
||||
}
|
||||
@@ -1041,3 +1046,12 @@ void GenericPanel::emitFirstActivated()
|
||||
{
|
||||
emit(firstActivated());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GenericPanel::setSelectedItem
|
||||
@param selectedItem
|
||||
*/
|
||||
void GenericPanel::setSelectedItem(QTreeWidgetItem *selectedItem)
|
||||
{
|
||||
m_selected_item = selectedItem;
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@ class GenericPanel : public QTreeWidget {
|
||||
virtual QTreeWidgetItem *addDiagram(Diagram *,
|
||||
QTreeWidgetItem * = nullptr,
|
||||
PanelOptions = AddAllChild);
|
||||
protected:
|
||||
virtual QTreeWidgetItem *getItemForDiagram(Diagram *, bool * = nullptr);
|
||||
protected:
|
||||
virtual QTreeWidgetItem *updateDiagramItem(QTreeWidgetItem *,
|
||||
Diagram *,
|
||||
PanelOptions = AddAllChild,
|
||||
@@ -171,6 +171,9 @@ class GenericPanel : public QTreeWidget {
|
||||
const QString &);
|
||||
|
||||
// various other methods
|
||||
public:
|
||||
void setSelectedItem(QTreeWidgetItem *selectedItem);
|
||||
|
||||
protected:
|
||||
virtual QString defaultText(QET::ItemType);
|
||||
virtual QIcon defaultIcon(QET::ItemType);
|
||||
@@ -222,5 +225,7 @@ class GenericPanel : public QTreeWidget {
|
||||
representing a title block template
|
||||
*/
|
||||
QHash<TitleBlockTemplateLocation, QTreeWidgetItem *> tb_templates_;
|
||||
|
||||
QTreeWidgetItem *m_selected_item = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
+57
-18
@@ -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);
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -76,6 +76,16 @@ QDomElement ElementData::kindInfoToXml(QDomDocument &document)
|
||||
xml_type.appendChild(type_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_type);
|
||||
|
||||
// Save max_slaves only if a specific limit is set (not default -1)
|
||||
if (m_max_slaves != -1) {
|
||||
auto xml_max_slaves = document.createElement(QStringLiteral("kindInformation"));
|
||||
xml_max_slaves.setAttribute(QStringLiteral("name"), QStringLiteral("max_slaves"));
|
||||
auto max_slaves_txt = document.createTextNode(QString::number(m_max_slaves));
|
||||
xml_max_slaves.appendChild(max_slaves_txt);
|
||||
|
||||
returned_elmt.appendChild(xml_max_slaves);
|
||||
}
|
||||
}
|
||||
else if (m_type == ElementData::Slave)
|
||||
{
|
||||
@@ -558,9 +568,12 @@ void ElementData::kindInfoFromXml(const QDomElement &xml_element)
|
||||
}
|
||||
auto name = dom_elmt.attribute(QStringLiteral("name"));
|
||||
|
||||
if (m_type == ElementData::Master &&
|
||||
name == QLatin1String("type")) {
|
||||
m_master_type = masterTypeFromString(dom_elmt.text());
|
||||
if (m_type == ElementData::Master) {
|
||||
if (name == QLatin1String("type")) {
|
||||
m_master_type = masterTypeFromString(dom_elmt.text());
|
||||
} else if (name == QLatin1String("max_slaves")) {
|
||||
m_max_slaves = dom_elmt.text().toInt();
|
||||
}
|
||||
}
|
||||
else if (m_type == ElementData::Slave ) {
|
||||
if (name == QLatin1String("type")) {
|
||||
|
||||
@@ -134,6 +134,7 @@ class ElementData : public PropertiesInterface
|
||||
ElementData::Type m_type = ElementData::Simple;
|
||||
|
||||
ElementData::MasterType m_master_type = ElementData::Coil;
|
||||
int m_max_slaves{-1};
|
||||
|
||||
ElementData::SlaveType m_slave_type = ElementData::SSimple;
|
||||
ElementData::SlaveState m_slave_state = ElementData::NO;
|
||||
@@ -141,7 +142,7 @@ class ElementData : public PropertiesInterface
|
||||
ElementData::TerminalType m_terminal_type = ElementData::TTGeneric;
|
||||
ElementData::TerminalFunction m_terminal_function = ElementData::TFGeneric;
|
||||
|
||||
int m_contact_count = 1;
|
||||
int m_contact_count{1};
|
||||
DiagramContext m_informations;
|
||||
NamesList m_names_list;
|
||||
QString m_drawing_information;
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#include "TerminalStrip/ui/terminalstripeditorwindow.h"
|
||||
#include "ui/diagrameditorhandlersizewidget.h"
|
||||
#include "TerminalStrip/ui/addterminalstripitemdialog.h"
|
||||
#include "wiringlistexport.h"
|
||||
#include "ui/terminalnumberingdialog.h"
|
||||
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#else
|
||||
@@ -465,13 +467,27 @@ 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
|
||||
|
||||
// Terminal Numbering
|
||||
m_terminal_numbering = new QAction(QET::Icons::TerminalStrip, tr("Numérotation automatique des bornes"), this);
|
||||
connect(m_terminal_numbering, &QAction::triggered, this, &QETDiagramEditor::slot_terminalNumbering);
|
||||
|
||||
#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 +851,8 @@ 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);
|
||||
menu_project -> addAction(m_terminal_numbering);
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
menu_project -> addSeparator();
|
||||
menu_project -> addAction(m_export_project_db);
|
||||
@@ -1567,6 +1585,8 @@ 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);
|
||||
m_terminal_numbering -> setEnabled(editable_project);
|
||||
#ifdef QET_EXPORT_PROJECT_DB
|
||||
m_export_project_db -> setEnabled(editable_project);
|
||||
#endif
|
||||
@@ -1828,6 +1848,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)
|
||||
@@ -2336,6 +2381,7 @@ void QETDiagramEditor::subWindowActivated(QMdiSubWindow *subWindows)
|
||||
|
||||
slot_updateActions();
|
||||
slot_updateWindowsMenu();
|
||||
emit syncElementsPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2471,7 +2517,27 @@ void QETDiagramEditor::generateTerminalBlock()
|
||||
#endif
|
||||
if ( !success ) {
|
||||
QMessageBox::warning(nullptr,
|
||||
QObject::tr("Error launching qet_tb_generator plugin"),
|
||||
message);
|
||||
QObject::tr("Error launching qet_tb_generator plugin"),
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief QETDiagramEditor::slot_terminalNumbering
|
||||
* Opens the dialog for automatic terminal numbering and applies the generated undo command.
|
||||
*/
|
||||
void QETDiagramEditor::slot_terminalNumbering() {
|
||||
TerminalNumberingDialog dialog(this);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
QETProject *project = currentProject();
|
||||
if (!project) return;
|
||||
|
||||
// Fetch the generated undo command from the dialog logic
|
||||
QUndoCommand *macro = dialog.getUndoCommand(project);
|
||||
|
||||
// If changes were made, push them to the global undo stack
|
||||
if (macro) {
|
||||
undo_group.activeStack()->push(macro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ class RecentFiles;
|
||||
class DiagramPropertiesEditorDockWidget;
|
||||
class ElementsCollectionWidget;
|
||||
class AutoNumberingDockWidget;
|
||||
class TerminalNumberingDialog;
|
||||
|
||||
#ifdef BUILD_WITHOUT_KF5
|
||||
#else
|
||||
@@ -98,6 +99,9 @@ class QETDiagramEditor : public QETMainWindow
|
||||
ProjectView *findProject(const QString &) const;
|
||||
QMdiSubWindow *subWindowForWidget(QWidget *) const;
|
||||
|
||||
signals:
|
||||
void syncElementsPanel();
|
||||
|
||||
public slots:
|
||||
void save();
|
||||
void saveAs();
|
||||
@@ -129,6 +133,7 @@ class QETDiagramEditor : public QETMainWindow
|
||||
void projectWasClosed(ProjectView *);
|
||||
void editProjectProperties(ProjectView *);
|
||||
void editProjectProperties(QETProject *);
|
||||
void slot_terminalNumbering();
|
||||
void editDiagramProperties(DiagramView *);
|
||||
void editDiagramProperties(Diagram *);
|
||||
void addDiagramToProject(QETProject *);
|
||||
@@ -197,6 +202,8 @@ 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_terminal_numbering, ///< Action to launch terminal numbering
|
||||
*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
|
||||
|
||||
@@ -1351,6 +1351,7 @@ void DynamicElementTextItem::updateXref()
|
||||
{
|
||||
m_slave_Xref_item = new QGraphicsTextItem(xref_label, this);
|
||||
m_slave_Xref_item->setFont(QETApp::diagramTextsFont(5));
|
||||
m_slave_Xref_item->setDefaultTextColor(Qt::black);
|
||||
m_slave_Xref_item->installSceneEventFilter(this);
|
||||
|
||||
m_update_slave_Xref_connection << connect(m_master_element.data(), &Element::xChanged, this, &DynamicElementTextItem::updateXref);
|
||||
|
||||
@@ -183,3 +183,27 @@ void MasterElement::aboutDeleteXref()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief MasterElement::isFull
|
||||
* @return true if the master has reached its maximum number of slaves
|
||||
*/
|
||||
bool MasterElement::isFull() const
|
||||
{
|
||||
// Set default value to -1 (unlimited slaves)
|
||||
int max_slaves = -1;
|
||||
QVariant max_slaves_variant = kindInformations().value("max_slaves");
|
||||
|
||||
// Overwrite default if a valid limit is defined in the element's XML
|
||||
if (max_slaves_variant.isValid() && !max_slaves_variant.toString().isEmpty()) {
|
||||
max_slaves = max_slaves_variant.toInt();
|
||||
}
|
||||
|
||||
// If no limit is set (-1), the master is never full
|
||||
if (max_slaves == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if current connected elements reached or exceeded the limit
|
||||
return connected_elements.size() >= max_slaves;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class MasterElement : public Element
|
||||
void unlinkElement (Element *elmt) override;
|
||||
void initLink (QETProject *project) override;
|
||||
QRectF XrefBoundingRect() const;
|
||||
|
||||
bool isFull() const; // Check Slave-Limit
|
||||
|
||||
protected:
|
||||
QVariant itemChange(
|
||||
|
||||
@@ -160,6 +160,7 @@ void ElementInfoWidget::enableLiveEdit()
|
||||
{
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list)
|
||||
connect(eipw, &ElementInfoPartWidget::textChanged, this, &ElementInfoWidget::apply);
|
||||
connect(ui->m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,6 +171,7 @@ void ElementInfoWidget::disableLiveEdit()
|
||||
{
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list)
|
||||
disconnect(eipw, &ElementInfoPartWidget::textChanged, this, &ElementInfoWidget::apply);
|
||||
disconnect(ui->m_auto_num_locked_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,6 +195,12 @@ void ElementInfoWidget::buildInterface()
|
||||
}
|
||||
|
||||
ui->scroll_vlayout->addStretch();
|
||||
// Show checkbox only if the element is a terminal
|
||||
if (m_element.data()->elementData().m_type == ElementData::Terminal) {
|
||||
ui->m_auto_num_locked_cb->setVisible(true);
|
||||
} else {
|
||||
ui->m_auto_num_locked_cb->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,6 +239,11 @@ void ElementInfoWidget::updateUi()
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list) {
|
||||
eipw -> setText (element_info[eipw->key()].toString());
|
||||
}
|
||||
// Load the lock status for auto numbering
|
||||
if (m_element->elementData().m_type == ElementData::Terminal) {
|
||||
QString lock_value = element_info.value(QStringLiteral("auto_num_locked")).toString();
|
||||
ui->m_auto_num_locked_cb->setChecked(lock_value == QLatin1String("true"));
|
||||
}
|
||||
|
||||
if (m_live_edit) {
|
||||
enableLiveEdit();
|
||||
@@ -259,6 +272,10 @@ DiagramContext ElementInfoWidget::currentInfo() const
|
||||
}
|
||||
}
|
||||
|
||||
// Save the auto numbering lock status
|
||||
if (m_element->elementData().m_type == ElementData::Terminal) {
|
||||
info_.addValue(QStringLiteral("auto_num_locked"), ui->m_auto_num_locked_cb->isChecked() ? QStringLiteral("true") : QStringLiteral("false"));
|
||||
}
|
||||
return info_;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,19 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_auto_num_locked_cb">
|
||||
<property name="text">
|
||||
<string>Exclure de la numérotation auto</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">margin: 5px; font-weight: bold;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@@ -372,6 +372,10 @@ QWidget *ElementPropertiesWidget::generalWidget()
|
||||
description_string += QString(tr("Rotation : %1°\n")).arg(m_element.data()->rotation());
|
||||
description_string += QString(tr("Dimensions : %1*%2\n")).arg(m_element -> size().width()).arg(m_element -> size().height());
|
||||
description_string += QString(tr("Bornes : %1\n")).arg(m_element -> terminals().count());
|
||||
if (m_element->linkType() == Element::Master){
|
||||
description_string += QString(tr("Nombre maximum de contacts esclaves définis : %1\n")).arg(m_element -> elementData().m_max_slaves);
|
||||
description_string += QString(tr("Nombre de contacts esclaves utilisés : %1\n")).arg(m_element ->linkedElements().count());
|
||||
}
|
||||
description_string += QString(tr("Emplacement : %1\n")).arg(m_element.data()->location().toString());
|
||||
|
||||
// widget himself
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "linksingleelementwidget.h"
|
||||
|
||||
#include "../qetgraphicsitem/masterelement.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
#include "../diagram.h"
|
||||
#include "../diagramposition.h"
|
||||
@@ -386,7 +386,22 @@ QVector <QPointer<Element>> LinkSingleElementWidget::availableElements()
|
||||
|
||||
//If element is linked, remove is parent from the list
|
||||
if(!m_element->isFree()) elmt_vector.removeAll(m_element->linkedElements().first());
|
||||
|
||||
// Filter out all master elements from the list
|
||||
for (int i = elmt_vector.size() - 1; i >= 0; --i) {
|
||||
Element *elmt = elmt_vector.at(i);
|
||||
|
||||
// If the item in the list is a master
|
||||
if (elmt->linkType() == Element::Master) {
|
||||
|
||||
// We convert the generic element pointer into a MasterElement pointer
|
||||
MasterElement *master = static_cast<MasterElement*>(elmt);
|
||||
|
||||
// If the master is full, we'll remove it from the list!
|
||||
if (master->isFull()) {
|
||||
elmt_vector.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return elmt_vector;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>389</width>
|
||||
<height>442</height>
|
||||
<height>460</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -64,6 +64,23 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QLabel" name="m_hidden_masters_label">
|
||||
<property name="text">
|
||||
<string>Remarque : les éléments maîtres ayant atteint leur nombre maximal d'esclaves sont masqués.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "masterpropertieswidget.h"
|
||||
|
||||
#include "../diagram.h"
|
||||
@@ -25,64 +25,65 @@
|
||||
#include "ui_masterpropertieswidget.h"
|
||||
|
||||
#include <QListWidgetItem>
|
||||
#include <QMessageBox>
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::MasterPropertiesWidget
|
||||
Default constructor
|
||||
@param elmt
|
||||
@param parent
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::MasterPropertiesWidget
|
||||
* Default constructor
|
||||
* @param elmt
|
||||
* @param parent
|
||||
*/
|
||||
MasterPropertiesWidget::MasterPropertiesWidget(Element *elmt, QWidget *parent) :
|
||||
AbstractElementPropertiesEditorWidget(parent),
|
||||
ui(new Ui::MasterPropertiesWidget),
|
||||
m_project(nullptr)
|
||||
AbstractElementPropertiesEditorWidget(parent),
|
||||
ui(new Ui::MasterPropertiesWidget),
|
||||
m_project(nullptr)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
||||
ui->m_free_tree_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
ui->m_link_tree_widget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
|
||||
QStringList list;
|
||||
QSettings settings;
|
||||
if (settings.value("genericpanel/folio", false).toBool()) {
|
||||
list << tr("Vignette")
|
||||
<< tr("Label de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
<< tr("Label de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
}
|
||||
else {
|
||||
list << tr("Vignette")
|
||||
<< tr("N° de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
<< tr("N° de folio")
|
||||
<< tr("Titre de folio")
|
||||
<< tr("Position");
|
||||
}
|
||||
ui->m_free_tree_widget->setHeaderLabels(list);
|
||||
ui->m_link_tree_widget->setHeaderLabels(list);
|
||||
|
||||
|
||||
m_context_menu = new QMenu(this);
|
||||
m_link_action = new QAction(tr("Lier l'élément"), this);
|
||||
m_unlink_action = new QAction(tr("Délier l'élément"), this);
|
||||
m_show_qtwi = new QAction(tr("Montrer l'élément"), this);
|
||||
m_show_element = new QAction(tr("Montrer l'élément maître"), this);
|
||||
m_save_header_state = new QAction(tr("Enregistrer la disposition"), this);
|
||||
|
||||
|
||||
connect(ui->m_free_tree_widget, &QTreeWidget::itemDoubleClicked,
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
connect(ui->m_link_tree_widget, &QTreeWidget::itemDoubleClicked,
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
|
||||
this, &MasterPropertiesWidget::showElementFromTWI);
|
||||
|
||||
connect(ui->m_free_tree_widget, &QTreeWidget::customContextMenuRequested,
|
||||
[this](QPoint point) {this->customContextMenu(point, 1);});
|
||||
[this](QPoint point) {this->customContextMenu(point, 1);});
|
||||
connect(ui->m_link_tree_widget, &QTreeWidget::customContextMenuRequested,
|
||||
[this](QPoint point) {this->customContextMenu(point, 2);});
|
||||
|
||||
[this](QPoint point) {this->customContextMenu(point, 2);});
|
||||
|
||||
connect(m_link_action, &QAction::triggered,
|
||||
this, &MasterPropertiesWidget::on_link_button_clicked);
|
||||
this, &MasterPropertiesWidget::on_link_button_clicked);
|
||||
connect(m_unlink_action, &QAction::triggered,
|
||||
this, &MasterPropertiesWidget::on_unlink_button_clicked);
|
||||
this, &MasterPropertiesWidget::on_unlink_button_clicked);
|
||||
connect(m_show_qtwi, &QAction::triggered,
|
||||
[this]() {this->showElementFromTWI(this->m_qtwi_at_context_menu,0);});
|
||||
|
||||
[this]() {this->showElementFromTWI(this->m_qtwi_at_context_menu,0);});
|
||||
|
||||
connect(m_show_element, &QAction::triggered, [this]()
|
||||
{
|
||||
this->m_element->diagram()->showMe();
|
||||
@@ -90,46 +91,46 @@ MasterPropertiesWidget::MasterPropertiesWidget(Element *elmt, QWidget *parent) :
|
||||
if(this->m_showed_element)
|
||||
m_showed_element->setHighlighted(false);
|
||||
});
|
||||
|
||||
|
||||
QHeaderView *qhv = ui->m_free_tree_widget->header();
|
||||
qhv->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(qhv, &QHeaderView::customContextMenuRequested,
|
||||
this, &MasterPropertiesWidget::headerCustomContextMenuRequested);
|
||||
this, &MasterPropertiesWidget::headerCustomContextMenuRequested);
|
||||
connect(m_save_header_state, &QAction::triggered, [qhv]()
|
||||
{
|
||||
QByteArray qba = qhv->saveState();
|
||||
QSettings settings;
|
||||
settings.setValue("link-element-widget/master-state", qba);
|
||||
});
|
||||
|
||||
|
||||
setElement(elmt);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::~MasterPropertiesWidget
|
||||
Destructor
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::~MasterPropertiesWidget
|
||||
* Destructor
|
||||
*/
|
||||
MasterPropertiesWidget::~MasterPropertiesWidget()
|
||||
{
|
||||
if (m_showed_element)
|
||||
m_showed_element->setHighlighted(false);
|
||||
|
||||
|
||||
if(m_element)
|
||||
m_element->setHighlighted(false);
|
||||
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::setElement
|
||||
Set the element to be edited
|
||||
@param element
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::setElement
|
||||
* Set the element to be edited
|
||||
* @param element
|
||||
*/
|
||||
void MasterPropertiesWidget::setElement(Element *element)
|
||||
{
|
||||
if (m_element == element)
|
||||
return;
|
||||
|
||||
|
||||
if (m_showed_element)
|
||||
{
|
||||
m_showed_element->setHighlighted(false);
|
||||
@@ -137,40 +138,40 @@ void MasterPropertiesWidget::setElement(Element *element)
|
||||
}
|
||||
if (m_element)
|
||||
m_element->setHighlighted(false);
|
||||
|
||||
|
||||
if (m_project)
|
||||
disconnect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
|
||||
if(Q_LIKELY(element->diagram() && element->diagram()->project()))
|
||||
{
|
||||
m_project = element->diagram()->project();
|
||||
connect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
}
|
||||
else
|
||||
m_project = nullptr;
|
||||
if(Q_LIKELY(element->diagram() && element->diagram()->project()))
|
||||
{
|
||||
m_project = element->diagram()->project();
|
||||
connect(m_project, SIGNAL(diagramRemoved(QETProject*,Diagram*)),
|
||||
this, SLOT(diagramWasdeletedFromProject()));
|
||||
}
|
||||
else
|
||||
m_project = nullptr;
|
||||
|
||||
//Keep up to date this widget when the linked elements of m_element change
|
||||
if (m_element)
|
||||
disconnect(m_element.data(), &Element::linkedElementChanged,
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
m_element = element;
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
m_element = element;
|
||||
connect(m_element.data(), &Element::linkedElementChanged,
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
this, &MasterPropertiesWidget::updateUi);
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::apply
|
||||
If link between edited element and other change,
|
||||
apply the change with a QUndoCommand (got with method associatedUndo)
|
||||
pushed to the stack of element project.
|
||||
Return true if link change, else false
|
||||
@note is void no Return ???
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::apply
|
||||
* If link between edited element and other change,
|
||||
* apply the change with a QUndoCommand (got with method associatedUndo)
|
||||
* pushed to the stack of element project.
|
||||
* Return true if link change, else false
|
||||
* @note is void no Return ???
|
||||
*/
|
||||
void MasterPropertiesWidget::apply()
|
||||
{
|
||||
if (QUndoCommand *undo = associatedUndo())
|
||||
@@ -178,25 +179,25 @@ void MasterPropertiesWidget::apply()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::reset
|
||||
Reset current widget, clear eveything and rebuild widget.
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::reset
|
||||
* Reset current widget, clear eveything and rebuild widget.
|
||||
*/
|
||||
void MasterPropertiesWidget::reset()
|
||||
{
|
||||
foreach (QTreeWidgetItem *qtwi, m_qtwi_hash.keys())
|
||||
delete qtwi;
|
||||
|
||||
|
||||
m_qtwi_hash.clear();
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::associatedUndo
|
||||
If link between the edited element and other change,
|
||||
return a QUndoCommand with this change.
|
||||
If no change return nullptr.
|
||||
@return
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::associatedUndo
|
||||
* If link between the edited element and other change,
|
||||
* return a QUndoCommand with this change.
|
||||
* If no change return nullptr.
|
||||
* @return
|
||||
*/
|
||||
QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
{
|
||||
QList <Element *> to_link;
|
||||
@@ -205,7 +206,7 @@ QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
for (int i=0; i<ui->m_link_tree_widget->topLevelItemCount(); i++)
|
||||
to_link << m_qtwi_hash[ui->m_link_tree_widget->topLevelItem(i)];
|
||||
|
||||
//The two list contain the same element, there is no change
|
||||
//The two list contain the same element, there is no change
|
||||
if (to_link.size() == linked_.size())
|
||||
{
|
||||
bool equal = true;
|
||||
@@ -229,11 +230,11 @@ QUndoCommand* MasterPropertiesWidget::associatedUndo() const
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::setLiveEdit
|
||||
@param live_edit = true : live edit is enable
|
||||
else false : live edit is disable.
|
||||
@return always true because live edit is handled by this editor widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::setLiveEdit
|
||||
* @param live_edit = true : live edit is enable
|
||||
* else false : live edit is disable.
|
||||
* @return always true because live edit is handled by this editor widget
|
||||
*/
|
||||
bool MasterPropertiesWidget::setLiveEdit(bool live_edit)
|
||||
{
|
||||
m_live_edit = live_edit;
|
||||
@@ -241,9 +242,9 @@ bool MasterPropertiesWidget::setLiveEdit(bool live_edit)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::updateUi
|
||||
Build the interface of the widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::updateUi
|
||||
* Build the interface of the widget
|
||||
*/
|
||||
void MasterPropertiesWidget::updateUi()
|
||||
{
|
||||
ui->m_free_tree_widget->clear();
|
||||
@@ -256,75 +257,75 @@ void MasterPropertiesWidget::updateUi()
|
||||
ElementProvider elmt_prov(m_project);
|
||||
QSettings settings;
|
||||
|
||||
//Build the list of free available element
|
||||
//Build the list of free available element
|
||||
QList <QTreeWidgetItem *> items_list;
|
||||
for(const auto &elmt : elmt_prov.freeElement(ElementData::Slave))
|
||||
{
|
||||
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_free_tree_widget);
|
||||
qtwi->setIcon(0, elmt->pixmap());
|
||||
|
||||
|
||||
if(settings.value("genericpanel/folio", false).toBool())
|
||||
{
|
||||
autonum::sequentialNumbers seq;
|
||||
QString F =autonum::AssignVariables::formulaToLabel(
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
qtwi->setText(1, F);
|
||||
}
|
||||
else
|
||||
{
|
||||
qtwi->setText(1, QString::number(
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
qtwi->setText(2, elmt->diagram()->title());
|
||||
qtwi->setText(4, elmt->diagram()->convertPosition(
|
||||
elmt->scenePos()).toString());
|
||||
elmt->scenePos()).toString());
|
||||
items_list.append(qtwi);
|
||||
m_qtwi_hash.insert(qtwi, elmt);
|
||||
}
|
||||
|
||||
|
||||
ui->m_free_tree_widget->addTopLevelItems(items_list);
|
||||
items_list.clear();
|
||||
|
||||
//Build the list of already linked element
|
||||
//Build the list of already linked element
|
||||
const QList<Element *> link_list = m_element->linkedElements();
|
||||
for(Element *elmt : link_list)
|
||||
{
|
||||
QTreeWidgetItem *qtwi = new QTreeWidgetItem(ui->m_link_tree_widget);
|
||||
qtwi->setIcon(0, elmt->pixmap());
|
||||
|
||||
|
||||
if(settings.value("genericpanel/folio", false).toBool())
|
||||
{
|
||||
autonum::sequentialNumbers seq;
|
||||
QString F =autonum::AssignVariables::formulaToLabel(
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
elmt->diagram()->border_and_titleblock.folio(),
|
||||
seq,
|
||||
elmt->diagram(),
|
||||
elmt);
|
||||
qtwi->setText(1, F);
|
||||
}
|
||||
else
|
||||
{
|
||||
qtwi->setText(1, QString::number(
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
elmt->diagram()->folioIndex()
|
||||
+ 1));
|
||||
}
|
||||
|
||||
qtwi->setText(2, elmt->diagram()->title());
|
||||
qtwi->setText(3, elmt->diagram()->convertPosition(
|
||||
elmt->scenePos()).toString());
|
||||
elmt->scenePos()).toString());
|
||||
items_list.append(qtwi);
|
||||
m_qtwi_hash.insert(qtwi, elmt);
|
||||
}
|
||||
|
||||
|
||||
if(items_list.count())
|
||||
ui->m_link_tree_widget->addTopLevelItems(items_list);
|
||||
|
||||
|
||||
QVariant v = settings.value("link-element-widget/master-state");
|
||||
if(!v.isNull())
|
||||
{
|
||||
@@ -334,9 +335,9 @@ void MasterPropertiesWidget::updateUi()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::headerCustomContextMenuRequested
|
||||
@param pos
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::headerCustomContextMenuRequested
|
||||
* @param pos
|
||||
*/
|
||||
void MasterPropertiesWidget::headerCustomContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
m_context_menu->clear();
|
||||
@@ -345,36 +346,57 @@ void MasterPropertiesWidget::headerCustomContextMenuRequested(const QPoint &pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::on_link_button_clicked
|
||||
move current item in the free_list to linked_list
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::on_link_button_clicked
|
||||
* Moves the current item from the free_list to the linked_list,
|
||||
* provided the master's slave limit has not been reached.
|
||||
*/
|
||||
void MasterPropertiesWidget::on_link_button_clicked()
|
||||
{
|
||||
//take the current item from free_list and push it to linked_list
|
||||
// Get the maximum number of allowed slaves from the element's information
|
||||
QVariant max_slaves_variant = m_element->kindInformations().value("max_slaves");
|
||||
|
||||
if (max_slaves_variant.isValid() && !max_slaves_variant.toString().isEmpty()) {
|
||||
int max_slaves = max_slaves_variant.toInt();
|
||||
int current_slaves = ui->m_link_tree_widget->topLevelItemCount();
|
||||
|
||||
// If a limit is set and reached
|
||||
if (max_slaves != -1 && current_slaves >= max_slaves) {
|
||||
|
||||
|
||||
// Show a message box with the actual window as parent to ensure it's on top
|
||||
QMessageBox::warning(this->window(),
|
||||
tr("Nombre maximal d'esclaves atteint."),
|
||||
tr("Cet élément maître ne peut plus accepter aucun nouveau contact esclave, la limite fixée a été atteinte (Limite: %1).").arg(max_slaves));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Move current item from free_list to linked_list
|
||||
QTreeWidgetItem *qtwi = ui->m_free_tree_widget->currentItem();
|
||||
if (qtwi)
|
||||
{
|
||||
ui->m_free_tree_widget->takeTopLevelItem(
|
||||
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_free_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_link_tree_widget->insertTopLevelItem(0, qtwi);
|
||||
|
||||
|
||||
if(m_live_edit)
|
||||
apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::on_unlink_button_clicked
|
||||
move current item in linked_list to free_list
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::on_unlink_button_clicked
|
||||
* move current item in linked_list to free_list
|
||||
*/
|
||||
void MasterPropertiesWidget::on_unlink_button_clicked()
|
||||
{
|
||||
//take the current item from linked_list and push it to free_list
|
||||
//take the current item from linked_list and push it to free_list
|
||||
QTreeWidgetItem *qtwi = ui->m_link_tree_widget->currentItem();
|
||||
if(qtwi)
|
||||
{
|
||||
ui->m_link_tree_widget->takeTopLevelItem(
|
||||
ui->m_link_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_link_tree_widget->indexOfTopLevelItem(qtwi));
|
||||
ui->m_free_tree_widget->insertTopLevelItem(0, qtwi);
|
||||
|
||||
if(m_live_edit)
|
||||
@@ -383,18 +405,18 @@ void MasterPropertiesWidget::on_unlink_button_clicked()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::showElementFromTWI
|
||||
Show the element corresponding to the given QTreeWidgetItem
|
||||
@param qtwi
|
||||
@param column
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::showElementFromTWI
|
||||
* Show the element corresponding to the given QTreeWidgetItem
|
||||
* @param qtwi
|
||||
* @param column
|
||||
*/
|
||||
void MasterPropertiesWidget::showElementFromTWI(QTreeWidgetItem *qtwi, int column)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
if (m_showed_element)
|
||||
{
|
||||
disconnect(m_showed_element, SIGNAL(destroyed()),
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
m_showed_element -> setHighlighted(false);
|
||||
}
|
||||
if (m_element)
|
||||
@@ -404,23 +426,23 @@ void MasterPropertiesWidget::showElementFromTWI(QTreeWidgetItem *qtwi, int colum
|
||||
m_showed_element->diagram()->showMe();
|
||||
m_showed_element->setHighlighted(true);
|
||||
connect(m_showed_element, SIGNAL(destroyed()),
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
this, SLOT(showedElementWasDeleted()));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::showedElementWasDeleted
|
||||
Set to nullptr the current showed element when he was deleted
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::showedElementWasDeleted
|
||||
* Set to nullptr the current showed element when he was deleted
|
||||
*/
|
||||
void MasterPropertiesWidget::showedElementWasDeleted()
|
||||
{
|
||||
m_showed_element = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::diagramWasdeletedFromProject
|
||||
This slot is called when a diagram is removed from the parent project
|
||||
of edited element to update the content of this widget
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::diagramWasdeletedFromProject
|
||||
* This slot is called when a diagram is removed from the parent project
|
||||
* of edited element to update the content of this widget
|
||||
*/
|
||||
void MasterPropertiesWidget::diagramWasdeletedFromProject()
|
||||
{
|
||||
// We use a timer because if the removed diagram
|
||||
@@ -431,11 +453,11 @@ void MasterPropertiesWidget::diagramWasdeletedFromProject()
|
||||
}
|
||||
|
||||
/**
|
||||
@brief MasterPropertiesWidget::customContextMenu
|
||||
Display a context menu
|
||||
@param pos
|
||||
@param i : the tree widget where the context menu was requested.
|
||||
*/
|
||||
* @brief MasterPropertiesWidget::customContextMenu
|
||||
* Display a context menu
|
||||
* @param pos
|
||||
* @param i : the tree widget where the context menu was requested.
|
||||
*/
|
||||
void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
{
|
||||
// add the size of the header to display the topleft of the QMenu
|
||||
@@ -444,14 +466,14 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
// section related to QAbstractScrollArea
|
||||
QPoint point = pos;
|
||||
point.ry()+=ui->m_free_tree_widget->header()->height();
|
||||
|
||||
|
||||
m_context_menu->clear();
|
||||
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
point = ui->m_free_tree_widget->mapToGlobal(point);
|
||||
|
||||
//Context at for free tree widget
|
||||
|
||||
//Context at for free tree widget
|
||||
if (ui->m_free_tree_widget->currentItem())
|
||||
{
|
||||
m_qtwi_at_context_menu = ui->m_free_tree_widget->currentItem();
|
||||
@@ -462,8 +484,8 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
else
|
||||
{
|
||||
point = ui->m_link_tree_widget->mapToGlobal(point);
|
||||
|
||||
//context at for link tre widget
|
||||
|
||||
//context at for link tre widget
|
||||
if (ui->m_link_tree_widget->currentItem())
|
||||
{
|
||||
m_qtwi_at_context_menu = ui->m_link_tree_widget->currentItem();
|
||||
@@ -471,7 +493,7 @@ void MasterPropertiesWidget::customContextMenu(const QPoint &pos, int i)
|
||||
m_context_menu->addAction(m_show_qtwi);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_context_menu->addAction(m_show_element);
|
||||
m_context_menu->popup(point);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
#include "terminalnumberingdialog.h"
|
||||
#include "ui_terminalnumberingdialog.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../undocommand/changeelementinformationcommand.h"
|
||||
#include <QUndoCommand>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::TerminalNumberingDialog
|
||||
* Constructor
|
||||
* @param parent
|
||||
*/
|
||||
TerminalNumberingDialog::TerminalNumberingDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TerminalNumberingDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::~TerminalNumberingDialog
|
||||
* Destructor
|
||||
*/
|
||||
TerminalNumberingDialog::~TerminalNumberingDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::isXAxisPriority
|
||||
* @return true if X axis has priority, false if Y axis has priority
|
||||
*/
|
||||
bool TerminalNumberingDialog::isXAxisPriority() const
|
||||
{
|
||||
return ui->rb_priority_x->isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::isAlphanumeric
|
||||
* @return true if alphanumeric sorting is enabled, false if numeric only
|
||||
*/
|
||||
bool TerminalNumberingDialog::isAlphanumeric() const
|
||||
{
|
||||
return ui->rb_type_alpha->isChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TerminalNumberingDialog::getUndoCommand
|
||||
* Scans the given project for terminals, sorts them according to user preferences
|
||||
* (X/Y axis, alphanumeric rules), and generates an undo command containing all label changes.
|
||||
* * @param project Pointer to the current QETProject
|
||||
* @return QUndoCommand* containing the modifications, or nullptr if no changes are needed.
|
||||
*/
|
||||
QUndoCommand* TerminalNumberingDialog::getUndoCommand(QETProject *project) const {
|
||||
if (!project) return nullptr;
|
||||
|
||||
bool axisX = isXAxisPriority();
|
||||
bool alpha = isAlphanumeric();
|
||||
|
||||
// 1. Helper structure to store and sort terminal data
|
||||
struct TermInfo {
|
||||
Element *elmt;
|
||||
QString prefix;
|
||||
QString suffix;
|
||||
int folioIndex;
|
||||
qreal x;
|
||||
qreal y;
|
||||
};
|
||||
QList<TermInfo> termList;
|
||||
|
||||
// 2. Collect all terminals from all folios in the project
|
||||
foreach (Diagram *diagram, project->diagrams()) {
|
||||
int fIndex = diagram->folioIndex();
|
||||
foreach (QGraphicsItem *qgi, diagram->items()) {
|
||||
if (Element *elmt = qgraphicsitem_cast<Element *>(qgi)) {
|
||||
|
||||
// Check if the element is actually a terminal
|
||||
if (elmt->elementData().m_type == ElementData::Terminal) {
|
||||
DiagramContext info = elmt->elementInformations();
|
||||
|
||||
// Ignore locked terminals (if the user checked a 'lock' property)
|
||||
if (info.value(QStringLiteral("auto_num_locked")).toString() == QLatin1String("true")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString label = elmt->actualLabel();
|
||||
if (label.isEmpty()) continue;
|
||||
|
||||
// Split prefix (e.g., "-X1") and suffix (e.g., "1" or "A")
|
||||
QString prefix = label;
|
||||
QString suffix = "";
|
||||
int colonIndex = label.lastIndexOf(':');
|
||||
if (colonIndex != -1) {
|
||||
prefix = label.left(colonIndex);
|
||||
suffix = label.mid(colonIndex + 1);
|
||||
}
|
||||
|
||||
// If user chose purely numeric, skip terminals with alphabetical suffixes
|
||||
if (!alpha && !suffix.isEmpty()) {
|
||||
bool isNum;
|
||||
suffix.toInt(&isNum);
|
||||
if (!isNum) continue;
|
||||
}
|
||||
|
||||
TermInfo ti;
|
||||
ti.elmt = elmt;
|
||||
ti.prefix = prefix;
|
||||
ti.suffix = suffix;
|
||||
ti.folioIndex = fIndex;
|
||||
ti.x = elmt->pos().x();
|
||||
ti.y = elmt->pos().y();
|
||||
termList.append(ti);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sort terminals based on user selection (X or Y axis priority)
|
||||
std::sort(termList.begin(), termList.end(), [axisX](const TermInfo &a, const TermInfo &b) {
|
||||
// First sort by BMK Prefix alphabetically (case insensitive)
|
||||
int prefixCmp = a.prefix.compare(b.prefix, Qt::CaseInsensitive);
|
||||
if (prefixCmp != 0) return prefixCmp < 0;
|
||||
|
||||
// Then sort by folio (page) index
|
||||
if (a.folioIndex != b.folioIndex) return a.folioIndex < b.folioIndex;
|
||||
|
||||
// Finally sort by coordinates (with a 1.0px tolerance to handle slight misalignments)
|
||||
if (axisX) {
|
||||
if (qAbs(a.x - b.x) > 1.0) return a.x < b.x;
|
||||
return a.y < b.y;
|
||||
} else {
|
||||
if (qAbs(a.y - b.y) > 1.0) return a.y < b.y;
|
||||
return a.x < b.x;
|
||||
}
|
||||
});
|
||||
|
||||
// 4. Generate new numbering and create the undo command macro
|
||||
QUndoCommand *macro = new QUndoCommand(QObject::tr("Automatic terminal numbering"));
|
||||
QMap<QString, int> counters;
|
||||
|
||||
foreach (const TermInfo &ti, termList) {
|
||||
// Increment the counter for this terminal block (e.g., "-X3")
|
||||
counters[ti.prefix]++;
|
||||
int newNum = counters[ti.prefix];
|
||||
|
||||
// Determine if the original suffix was a pure number
|
||||
QString newLabel;
|
||||
bool isNum;
|
||||
ti.suffix.toInt(&isNum);
|
||||
|
||||
if (isNum || ti.suffix.isEmpty()) {
|
||||
// If it was a number (e.g., "1") or empty, update it with the new counter
|
||||
newLabel = ti.prefix + ":" + QString::number(newNum);
|
||||
} else {
|
||||
// If it was alphabetical (e.g., "N", "PE"), keep the original text but consume the count!
|
||||
newLabel = ti.prefix + ":" + ti.suffix;
|
||||
}
|
||||
|
||||
DiagramContext oldInfo = ti.elmt->elementInformations();
|
||||
DiagramContext newInfo = oldInfo;
|
||||
newInfo.addValue(QStringLiteral("label"), newLabel);
|
||||
|
||||
// Create an undo command only if the label actually changes
|
||||
if (oldInfo != newInfo) {
|
||||
new ChangeElementInformationCommand(ti.elmt, oldInfo, newInfo, macro);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Return the macro if it contains changes, otherwise delete and return null
|
||||
if (macro->childCount() > 0) {
|
||||
return macro;
|
||||
} else {
|
||||
delete macro;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef TERMINALNUMBERINGDIALOG_H
|
||||
#define TERMINALNUMBERINGDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QETProject;
|
||||
class QUndoCommand;
|
||||
|
||||
namespace Ui {
|
||||
class TerminalNumberingDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The TerminalNumberingDialog class
|
||||
* Dialog to configure the automatic numbering of terminals.
|
||||
*/
|
||||
class TerminalNumberingDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TerminalNumberingDialog(QWidget *parent = nullptr);
|
||||
~TerminalNumberingDialog();
|
||||
|
||||
// Getters for the user's choices
|
||||
bool isXAxisPriority() const;
|
||||
bool isAlphanumeric() const;
|
||||
|
||||
QUndoCommand* getUndoCommand(QETProject *project) const;
|
||||
|
||||
private:
|
||||
Ui::TerminalNumberingDialog *ui;
|
||||
};
|
||||
|
||||
#endif // TERMINALNUMBERINGDIALOG_H
|
||||
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TerminalNumberingDialog</class>
|
||||
<widget class="QDialog" name="TerminalNumberingDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Numérotation automatique des bornes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_description">
|
||||
<property name="text">
|
||||
<string>Cette fonction numérote les bornes du projet selon leur position. Les bornes vides ou verrouillées sont ignorées.Le marquage des bornes doit être configuré au préalable comme suit : '-X:AB'. La partie avant les deux-points (le bornier) peut être nommée au choix. 'AB' peut être composé de chiffres ou de lettres."</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_axis">
|
||||
<property name="title">
|
||||
<string>Priorité des axes</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_priority_x">
|
||||
<property name="text">
|
||||
<string>Priorité à l'axe X (horizontal)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_priority_y">
|
||||
<property name="text">
|
||||
<string>Priorité à l'axe Y (vertical)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_type">
|
||||
<property name="title">
|
||||
<string>Type de numérotation</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_type_num">
|
||||
<property name="text">
|
||||
<string>Numérique uniquement (1, 2, 3...)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb_type_alpha">
|
||||
<property name="text">
|
||||
<string>Alphanumérique (A, B, C... 1, 2...)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>TerminalNumberingDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>TerminalNumberingDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -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 !"));
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user