diff --git a/qelectrotech.pro b/qelectrotech.pro
index 5729674e9..badb86bdb 100644
--- a/qelectrotech.pro
+++ b/qelectrotech.pro
@@ -166,7 +166,8 @@ HEADERS += $$files(sources/*.h) \
$$files(sources/TerminalStrip/GraphicsItem/*.h) \
$$files(sources/TerminalStrip/GraphicsItem/properties/*.h) \
$$files(sources/xml/*.h) \
- $$files(sources/dxf/*.h)
+ $$files(sources/dxf/*.h) \
+ $$files(sources/svg/*.h)
SOURCES += $$files(sources/*.cpp) \
$$files(sources/editor/*.cpp) \
@@ -208,7 +209,8 @@ SOURCES += $$files(sources/*.cpp) \
$$files(sources/TerminalStrip/GraphicsItem/*.cpp) \
$$files(sources/TerminalStrip/GraphicsItem/properties/*.cpp) \
$$files(sources/xml/*.cpp) \
- $$files(sources/dxf/*.cpp)
+ $$files(sources/dxf/*.cpp) \
+ $$files(sources/svg/*.cpp)
# Needed for use promote QTreeWidget in terminalstripeditor.ui
INCLUDEPATH += sources/TerminalStrip/ui
diff --git a/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.cpp b/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.cpp
index b6fba13e8..84baeb591 100644
--- a/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.cpp
+++ b/sources/TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.cpp
@@ -26,8 +26,15 @@ TerminalStripLayoutPattern::TerminalStripLayoutPattern()
updateTerminalsTextOption();
}
+/**
+ * @brief TerminalStripLayoutPattern::setHeaderTextAlignment
+ * Set text alignment to @param alignment. If alignment have no
+ * flag this function do nothing
+ * @param alignment
+ */
void TerminalStripLayoutPattern::setHeaderTextAlignment(const Qt::Alignment &alignment)
{
+ if (!alignment) return;
m_header_text_alignment = alignment;
updateHeaderTextOption();
}
@@ -50,8 +57,15 @@ void TerminalStripLayoutPattern::setFont(const QFont &font) {
QETUtils::pixelSizedFont(m_font);
}
+/**
+ * @brief TerminalStripLayoutPattern::setTerminalsTextAlignment
+ * Set text alignment to @param alignment. If alignment have no
+ * flag this function do nothing
+ * @param alignment
+ */
void TerminalStripLayoutPattern::setTerminalsTextAlignment(const Qt::Alignment &alignment)
{
+ if (!alignment) return;
m_terminals_text_alignment = alignment;
updateTerminalsTextOption();
}
diff --git a/sources/qetxml.cpp b/sources/qetxml.cpp
index b22a5581c..dc35ce30a 100644
--- a/sources/qetxml.cpp
+++ b/sources/qetxml.cpp
@@ -953,4 +953,93 @@ bool qGraphicsItemPosFromXml(QGraphicsItem *item, const QDomElement &xml_elmt)
return false;
}
+/**
+ * @brief orientationToAttribute
+ * Write the Qt::orientation has an attribute of @param element.
+ * Attribute name is 'orientation' value is 'horizontal' or 'vertical'
+ * @param orientation
+ * @param element
+ */
+void orientationToAttribute(const Qt::Orientation &orientation, QDomElement &element)
+{
+ element.setAttribute(QStringLiteral("orientation"),
+ orientation == Qt::Horizontal ? QStringLiteral("Horizontal") :
+ QStringLiteral("Vertical"));
+}
+
+/**
+ * @brief orientationFromAttribute
+ * @param element
+ * @param def_value
+ * @return the Qt::Orientation read in @param element. If an error occur
+ * the returned orientation is @param def_value.
+ */
+Qt::Orientation orientationFromAttribute(const QDomElement &element, Qt::Orientation def_value)
+{
+ if (element.hasAttribute(QStringLiteral("orientation"))) {
+ const auto str {element.attribute(QStringLiteral("orientation"))};
+ if (str == QLatin1String("Horizontal"))
+ return Qt::Horizontal;
+ else if (str == QLatin1String("Vertical"))
+ return Qt::Vertical;
+ }
+ //Error occur during reading, we return the default value
+ return def_value;
+}
+
+void alignmentToAttribute(const Qt::Alignment &alignment, QDomElement &element)
+{
+ QStringList al;
+ if (alignment &Qt::AlignLeft)
+ al.append(QStringLiteral("Left"));
+ if (alignment &Qt::AlignRight)
+ al.append(QStringLiteral("Right"));
+ if (alignment &Qt::AlignHCenter)
+ al.append(QStringLiteral("HCenter"));
+ if (alignment &Qt::AlignJustify)
+ al.append(QStringLiteral("Justify"));
+ if (alignment &Qt::AlignTop)
+ al.append(QStringLiteral("Top"));
+ if (alignment &Qt::AlignBottom)
+ al.append(QStringLiteral("Bottom"));
+ if (alignment &Qt::AlignBottom)
+ al.append(QStringLiteral("VCenter"));
+ if (alignment &Qt::AlignBaseline)
+ al.append(QStringLiteral("Baseline"));
+
+ element.setAttribute(QStringLiteral("alignment"),al.join(QStringLiteral(" ")));
+}
+
+/**
+ * @brief alignmentFromAttribute
+ * @param element
+ * @return The alignment read in @param element. If an error
+ * occured the return Qt::alignment contain no set flag.
+ */
+Qt::Alignment alignmentFromAttribute(const QDomElement &element)
+{
+ Qt::Alignment al;
+ if (element.hasAttribute(QStringLiteral("alignment"))) {
+ const auto alignment {element.attribute(QStringLiteral("alignment"))};
+ if(alignment.contains(QStringLiteral("Left")))
+ al = al | Qt::AlignLeft;
+ if(alignment.contains(QStringLiteral("Right")))
+ al = al | Qt::AlignRight;
+ if(alignment.contains(QStringLiteral("HCenter")))
+ al = al | Qt::AlignHCenter;
+ if(alignment.contains(QStringLiteral("Justify")))
+ al = al | Qt::AlignJustify;
+ if(alignment.contains(QStringLiteral("Top")))
+ al = al | Qt::AlignTop;
+ if(alignment.contains(QStringLiteral("Bottom")))
+ al = al | Qt::AlignBottom;
+ if(alignment.contains(QStringLiteral("VCenter")))
+ al = al | Qt::AlignVCenter;
+ if(alignment.contains(QStringLiteral("Baseline")))
+ al = al | Qt::AlignBaseline;
+ }
+
+ return al;
+}
+
}
diff --git a/sources/qetxml.h b/sources/qetxml.h
index 9d57d2240..c5670d857 100644
--- a/sources/qetxml.h
+++ b/sources/qetxml.h
@@ -94,6 +94,12 @@ namespace QETXML
QDomElement qGraphicsItemPosToXml(QGraphicsItem *item, QDomDocument &document);
bool qGraphicsItemPosFromXml(QGraphicsItem *item, const QDomElement &xml_elmt);
+ void orientationToAttribute(const Qt::Orientation &orientation, QDomElement &element);
+ Qt::Orientation orientationFromAttribute(const QDomElement &element, Qt::Orientation def_value = Qt::Vertical);
+
+ void alignmentToAttribute(const Qt::Alignment &alignment, QDomElement &element);
+ Qt::Alignment alignmentFromAttribute (const QDomElement &element);
+
QString boolToString(bool value);
bool boolFromString(const QString &value,
bool default_value = true,
diff --git a/sources/svg/qetsvg.cpp b/sources/svg/qetsvg.cpp
new file mode 100644
index 000000000..ba5ac7d99
--- /dev/null
+++ b/sources/svg/qetsvg.cpp
@@ -0,0 +1,151 @@
+/*
+ Copyright 2006-2025 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+
+#include "qetsvg.h"
+
+#include
+#include
+#include <../qet.h>
+
+/**
+ * @brief QETSVG::rectToElmt
+ * Write a QRect as a svg rect element.
+ * @param rect
+ * @param parent_document
+ * @return
+ */
+QDomElement QETSVG::rectToElmt(const QRect &rect, QDomDocument &parent_document)
+{
+ auto dom_element = parent_document.createElement(QStringLiteral("rect"));
+ if (!rect.isNull()) {
+ dom_element.setAttribute(QStringLiteral("x"), rect.x());
+ yToAttribute(rect.y(), dom_element);
+ dom_element.setAttribute(QStringLiteral("width"), rect.width());
+ heightToAttribute(rect.height(), dom_element);
+ }
+ return dom_element;
+}
+
+/**
+ * @brief QETSVG::rectFromElmt
+ * @param xml_element : xml_element of an svg rect.
+ * The tag name must be 'rect' if not, the returned QRect is null.
+ * @return a svg rect to QRect
+ */
+QRect QETSVG::rectFromElmt(const QDomElement &xml_element)
+{
+ QRect rect;
+ if (xml_element.tagName() == QLatin1String("rect")) {
+ rect.setRect(xml_element.attribute(QStringLiteral("x"), QStringLiteral("0")).toInt(),
+ static_cast (yFromAttribute(xml_element, 0)),
+ xml_element.attribute(QStringLiteral("width"), QStringLiteral("10")).toInt(),
+ static_cast (heightFromAttribute(xml_element, 10)));
+ }
+ return rect;
+}
+
+/**
+ * @brief QETSVG::yToAttribute
+ * @param y
+ * @param xml_element
+ */
+void QETSVG::yToAttribute(const qreal &y, QDomElement &xml_element) {
+ xml_element.setAttribute(QStringLiteral("y"), QString::number(y));
+}
+
+/**
+ * @brief QETSVG::yFromAttribute
+ * @param xml_element
+ * @param def_value
+ * @return
+ */
+qreal QETSVG::yFromAttribute(const QDomElement &xml_element, const qreal &def_value) {
+ qreal value;
+ if (QET::attributeIsAReal(xml_element, QStringLiteral("y"), &value)) {
+ return value;
+ }
+ return def_value;
+}
+
+/**
+ * @brief QETSVG::heightToAttribute
+ * @param height
+ * @param xml_element
+ */
+void QETSVG::heightToAttribute(const qreal &height, QDomElement &xml_element) {
+ xml_element.setAttribute(QStringLiteral("height"), QString::number(height));
+}
+
+qreal QETSVG::heightFromAttribute(const QDomElement &xml_element, const qreal &def_value) {
+ qreal value;
+ if (QET::attributeIsAReal(xml_element, QStringLiteral("height"), &value)) {
+ return value;
+ }
+ return def_value;
+}
+
+void QETSVG::rToAttribute(const qreal &r, QDomElement &xml_element) {
+ xml_element.setAttribute(QStringLiteral("r"), QString::number(r));
+}
+
+qreal QETSVG::rFromAttribute(const QDomElement &xml_element, const qreal &def_value) {
+ qreal value;
+ if (QET::attributeIsAReal(xml_element, QStringLiteral("r"), &value)) {
+ return value;
+ }
+ return def_value;
+
+}
+
+void QETSVG::pointsToAttribute(const QVector &points, QDomElement &xml_element)
+{
+ QStringList strl;
+ for (const auto &point : points) {
+ strl.append(QString::number(point.x()) +
+ QString(",") +
+ QString::number(point.y()));
+ }
+
+ xml_element.setAttribute(QStringLiteral("points"), strl.join(" "));
+}
+
+/**
+ * @brief QETSVG::pointsFromAttribute
+ * @param xml_element
+ * @return a vector of points stored in attribute 'points' of @xml_element.
+ * The returned vector can be empty.
+ */
+QVector QETSVG::pointsFromAttribute(const QDomElement &xml_element)
+{
+ QVector vector;
+ if (const auto string_points = xml_element.attribute(QStringLiteral("points")).split(QStringLiteral(" ")) ;
+ !string_points.isEmpty()) {
+ bool x_ok, y_ok; for (const auto &point : string_points) {
+ const auto string_x_y = point.split(QStringLiteral(","));
+ if (string_x_y.size() == 2) {
+ const auto x = string_x_y[0].toDouble(&x_ok);
+ const auto y = string_x_y[1].toDouble(&y_ok);
+ if (x_ok && y_ok) {
+ vector.append(QPointF{x,y});
+ }
+ }
+ }
+ }
+
+ return vector;
+}
diff --git a/sources/svg/qetsvg.h b/sources/svg/qetsvg.h
new file mode 100644
index 000000000..037d33c7c
--- /dev/null
+++ b/sources/svg/qetsvg.h
@@ -0,0 +1,51 @@
+/*
+ Copyright 2006-2025 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#ifndef QETSVG_H
+#define QETSVG_H
+
+#include
+
+class QDomDocument;
+class QPointF;
+class QRect;
+
+/**
+ * @namespace QETSVG
+ * @brief the QETSVG namespace provide function read and write svg.
+ * Some function work on xml element (ex rect) and some other
+ * work on attribute of an element (ex x)
+ */
+namespace QETSVG
+{
+ QDomElement rectToElmt(const QRect &rect, QDomDocument &parent_document);
+ QRect rectFromElmt(const QDomElement &xml_element);
+
+ void yToAttribute(const qreal &y, QDomElement &xml_element);
+ qreal yFromAttribute(const QDomElement &xml_element, const qreal &def_value=0);
+
+ void heightToAttribute(const qreal &height, QDomElement &xml_element);
+ qreal heightFromAttribute(const QDomElement &xml_element, const qreal &def_value=10);
+
+ void rToAttribute(const qreal &r, QDomElement &xml_element);
+ qreal rFromAttribute(const QDomElement &xml_element, const qreal &def_value=1);
+
+ void pointsToAttribute(const QVector &points, QDomElement &xml_element);
+ QVector pointsFromAttribute (const QDomElement &xml_element);
+}
+
+#endif // QETSVG_H
diff --git a/sources/xml/terminalstriplayoutpatternxml.cpp b/sources/xml/terminalstriplayoutpatternxml.cpp
new file mode 100644
index 000000000..9ae8a0dbb
--- /dev/null
+++ b/sources/xml/terminalstriplayoutpatternxml.cpp
@@ -0,0 +1,191 @@
+/*
+ Copyright 2006-2025 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#include "terminalstriplayoutpatternxml.h"
+
+#include "../TerminalStrip/GraphicsItem/properties/terminalstriplayoutpattern.h"
+#include "../qetxml.h"
+#include "../svg/qetsvg.h"
+
+const QString LAYOUT_PATTERN_TAG_NAME { QStringLiteral("terminal_strip_layout_pattern") };
+const QString LAYOUTS_PATTERN_TAG_NAME { QStringLiteral("terminal_strip_layouts_pattern") };
+
+/**
+ * @brief TerminalStripLayoutPatternXml::toXml
+ * Save a vector of @class TerminalStripLayoutPattern into main xml element
+ * with tagg name 'terminal_strip_layouts_pattern' who itself embedded each single @class TerminalStripLayoutPattern
+ * into a xml element with tag name 'terminal_strip_layout_pattern' (layout without 'S' at the end)
+ * @param patterns
+ * @param document
+ * @return
+ */
+QDomElement TerminalStripLayoutPatternXml::toXml(const QVector > &patterns,
+ QDomDocument &document)
+{
+ auto dom_element = document.createElement(LAYOUTS_PATTERN_TAG_NAME);
+ for (const auto &pattern : patterns)
+ {
+ const auto child_ = toXml(pattern, document);
+ if (!child_.isNull()) {
+ dom_element.appendChild(child_);
+ }
+ }
+
+ return dom_element;
+}
+
+/**
+ * @brief TerminalStripLayoutPatternXml::fromXml
+ * Load a vector of @class TerminalStripLayoutPattern from a main xml element
+ * with tagg name 'terminal_strip_layouts_pattern' who itself have several child
+ * with tag name 'terminal_strip_layout_pattern' (layout without 'S' at the end) for every
+ * @class TerminalStripLayoutPattern to load
+ * @param element
+ * @return
+ */
+QVector > TerminalStripLayoutPatternXml::fromXml(const QDomElement &element)
+{
+ QVector > returned_vector;
+
+ for (const auto &dom_elmt : QETXML::subChild(element,
+ LAYOUTS_PATTERN_TAG_NAME,
+ LAYOUT_PATTERN_TAG_NAME))
+ {
+ auto layout_pattern = QSharedPointer::create();
+ fromXml(layout_pattern, dom_elmt);
+
+ returned_vector << layout_pattern;
+ }
+
+ return returned_vector;
+}
+
+/**
+ * @brief TerminalStripLayoutPatternXml::toXml
+ * Save a @class TerminalStripLayoutPattern to a xml element with tag name terminal_strip_layout_pattern
+ * @param pattern
+ * @param document
+ * @return
+ */
+QDomElement TerminalStripLayoutPatternXml::toXml(const QSharedPointer &pattern, QDomDocument &document)
+{
+ auto pattern_xml = document.createElement(LAYOUT_PATTERN_TAG_NAME);
+ if (!pattern.isNull()) {
+ //Write strip pattern attributes
+ pattern_xml.setAttribute(QStringLiteral("name"), pattern->m_name);
+ pattern_xml.setAttribute(QStringLiteral("uuid"), pattern->m_uuid.toString());
+
+ //Write header properties
+ auto header_xml = document.createElement(QStringLiteral("header"));
+ header_xml.appendChild(QETSVG::rectToElmt(pattern->m_header_rect, document));
+
+ auto header_text_xml = document.createElement(QStringLiteral("text"));
+ QETXML::orientationToAttribute(pattern->m_header_text_orientation, header_text_xml);
+ QETXML::alignmentToAttribute(pattern->headerTextAlignment(),header_text_xml);
+
+ //Write spacer properties
+ auto spacer_xml = document.createElement(QStringLiteral("spacer"));
+ spacer_xml.appendChild(QETSVG::rectToElmt(pattern->m_spacer_rect, document));
+
+ pattern_xml.appendChild(header_xml).appendChild(header_text_xml);
+ pattern_xml.appendChild(spacer_xml);
+
+ //Write terminals properties
+ auto terminals_xml = document.createElement(QStringLiteral("terminals"));
+ for (const auto &rect : pattern->m_terminal_rect) {
+ terminals_xml.appendChild(QETSVG::rectToElmt(rect, document));
+ }
+
+ auto terminals_text_xml = document.createElement(QStringLiteral("text"));
+ QETXML::orientationToAttribute(pattern->m_terminals_text_orientation, terminals_text_xml);
+ QETXML::alignmentToAttribute(pattern->terminalsTextAlignment(),terminals_text_xml);
+ QETSVG::yToAttribute(pattern->m_terminals_text_y, terminals_text_xml);
+ QETSVG::heightToAttribute(pattern->m_terminals_text_height, terminals_text_xml);
+ terminals_xml.appendChild(terminals_text_xml);
+
+ auto bridge_xml = document.createElement(QStringLiteral("bridges"));
+ QETSVG::rToAttribute(static_cast(pattern->m_bridge_point_d)/2, bridge_xml);
+ QETSVG::pointsToAttribute(QVector{QPointF{0, static_cast (pattern->m_bridge_point_y_offset.at(0))},
+ QPointF{0, static_cast (pattern->m_bridge_point_y_offset.at(1))},
+ QPointF{0, static_cast (pattern->m_bridge_point_y_offset.at(2))},
+ QPointF{0, static_cast (pattern->m_bridge_point_y_offset.at(3))}},
+ bridge_xml);
+ terminals_xml.appendChild(bridge_xml);
+
+ pattern_xml.appendChild(terminals_xml);
+ }
+
+ return pattern_xml;
+}
+
+/**
+ * @brief TerminalStripLayoutPatternXml::fromXml
+ * LOad a @class TerminalStripLayoutPattern from a xml element with tag name terminal_strip_layout_pattern
+ * @param layout
+ * @param element
+ */
+void TerminalStripLayoutPatternXml::fromXml(QSharedPointer &layout, const QDomElement &element)
+{
+ if (element.tagName() != LAYOUT_PATTERN_TAG_NAME) return;
+ layout->m_name = element.attribute(QStringLiteral("name"), layout->m_name);
+ layout->m_uuid.fromString(element.attribute(QStringLiteral("uuid"), layout->m_uuid.toString()));
+
+ const auto header_xml = element.firstChildElement(QStringLiteral("header"));
+ if (!header_xml.isNull() && header_xml.hasAttribute(QStringLiteral("rect"))) {
+ layout->m_header_rect = QETSVG::rectFromElmt(header_xml);
+ }
+
+ if (const auto header_text_xml = header_xml.firstChildElement(QStringLiteral("text"));
+ !header_text_xml.isNull()) {
+ layout->m_header_text_orientation = QETXML::orientationFromAttribute(header_text_xml, layout->m_header_text_orientation);
+ layout->setHeaderTextAlignment(QETXML::alignmentFromAttribute(header_text_xml));
+ }
+
+ const auto spacer_xml = element.firstChildElement(QStringLiteral("spacer"));
+ if (const auto rect = QETSVG::rectFromElmt(spacer_xml);
+ !rect.isNull()) {
+ layout->m_spacer_rect = rect;
+ }
+
+ if (const auto terminals_xml = element.firstChildElement(QStringLiteral("terminals"));
+ !terminals_xml.isNull()) {
+ layout->m_terminal_rect.clear();
+ for (const auto &terminal_rect_xml : QETXML::directChild(terminals_xml, QStringLiteral("rect"))) {
+ layout->m_terminal_rect.append(QETSVG::rectFromElmt(terminal_rect_xml)) ;
+ }
+
+ if (const auto terminals_text_xml = terminals_xml.firstChildElement(QStringLiteral("text"));
+ !terminals_text_xml.isNull()) {
+ layout->m_terminals_text_orientation = QETXML::orientationFromAttribute(terminals_text_xml, layout->m_terminals_text_orientation);
+ layout->setTerminalsTextAlignment(QETXML::alignmentFromAttribute(terminals_text_xml));
+ layout->m_terminals_text_y = QETSVG::yFromAttribute(terminals_text_xml);
+ layout->m_terminals_text_height = QETSVG::heightFromAttribute(terminals_text_xml);
+ }
+
+ if (const auto bridge_xml = terminals_xml.firstChildElement(QStringLiteral("bridges"));
+ !bridge_xml.isNull()) {
+ layout->m_bridge_point_d = QETSVG::rFromAttribute(bridge_xml, 2.5)*2;
+ if (const auto points = QETSVG::pointsFromAttribute(bridge_xml);
+ points.size() == 4) {
+ layout->m_bridge_point_y_offset[0]= static_cast(points[0].y());
+ layout->m_bridge_point_y_offset[1]= static_cast(points[1].y());
+ layout->m_bridge_point_y_offset[2]= static_cast(points[2].y());
+ layout->m_bridge_point_y_offset[3]= static_cast(points[3].y());
+ }
+ }
+ }
+}
diff --git a/sources/xml/terminalstriplayoutpatternxml.h b/sources/xml/terminalstriplayoutpatternxml.h
new file mode 100644
index 000000000..644d7ff12
--- /dev/null
+++ b/sources/xml/terminalstriplayoutpatternxml.h
@@ -0,0 +1,41 @@
+/*
+ Copyright 2006-2025 The QElectroTech Team
+ This file is part of QElectroTech.
+
+ QElectroTech is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ QElectroTech is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with QElectroTech. If not, see .
+*/
+#ifndef TERMINALSTRIPLAYOUTPATTERNXML_H
+#define TERMINALSTRIPLAYOUTPATTERNXML_H
+
+#include
+#include
+
+class TerminalStripLayoutPattern;
+
+/**
+ * @brief The TerminalStripLayoutPatternXml class
+ * A class used to save/restor a @class TerminalStripLayoutPattern to
+ * xml
+ */
+class TerminalStripLayoutPatternXml
+{
+ public:
+ static QDomElement toXml(const QVector> &patterns, QDomDocument &document);
+ static QVector> fromXml(const QDomElement &element);
+
+ static QDomElement toXml (const QSharedPointer &pattern, QDomDocument &document);
+ static void fromXml(QSharedPointer &layout, const QDomElement &element);
+};
+
+#endif // TERMINALSTRIPLAYOUTPATTERNXML_H