Terminal strip: save the layout (font, cell sizes...) in the project

The default terminal strip layout was rebuilt at every project load,
so the font size set in the layout editor was reset to 15 px.
Add TerminalStripLayoutPattern::toXml/fromXml and
TerminalStripLayoutsHandler::toXml/fromXml, write a
<terminal_strip_layout> element in QETProject::toXml() and read it
before the diagrams are loaded. Projects without it keep the defaults.
This commit is contained in:
Laurent Trinques
2026-10-10 09:49:42 +02:00
parent da31e93b1f
commit daa648099b
5 changed files with 216 additions and 0 deletions
@@ -18,6 +18,8 @@
#include "terminalstriplayoutpattern.h"
#include "../../../utils/qetutils.h"
#include <QDomDocument>
TerminalStripLayoutPattern::TerminalStripLayoutPattern()
{
m_font.setPixelSize(15);
@@ -116,3 +118,176 @@ void TerminalStripLayoutPattern::updateTerminalsTextOption()
m_xref_text_option.setAlignment(m_xref_text_alignment);
m_xref_text_option.setWrapMode(QTextOption::WordWrap);
}
namespace
{
void rectToXml(QDomElement &element, const QString &name, const QRectF &rect)
{
element.setAttribute(name + QStringLiteral("_x"), rect.x());
element.setAttribute(name + QStringLiteral("_y"), rect.y());
element.setAttribute(name + QStringLiteral("_w"), rect.width());
element.setAttribute(name + QStringLiteral("_h"), rect.height());
}
QRectF rectFromXml(const QDomElement &element, const QString &name, const QRectF &default_rect)
{
auto value = [&element, &name](const QString &suffix, qreal default_value)
{
bool ok = false;
const auto v = element.attribute(name + suffix).toDouble(&ok);
return ok ? v : default_value;
};
return QRectF(value(QStringLiteral("_x"), default_rect.x()),
value(QStringLiteral("_y"), default_rect.y()),
value(QStringLiteral("_w"), default_rect.width()),
value(QStringLiteral("_h"), default_rect.height()));
}
qreal realFromXml(const QDomElement &element, const QString &name, qreal default_value)
{
bool ok = false;
const auto v = element.attribute(name).toDouble(&ok);
return ok ? v : default_value;
}
QString orientationToString(Qt::Orientation orientation) {
return orientation == Qt::Horizontal ? QStringLiteral("horizontal") : QStringLiteral("vertical");
}
Qt::Orientation orientationFromXml(const QDomElement &element, const QString &name, Qt::Orientation default_value)
{
const auto v = element.attribute(name);
if (v == QLatin1String("horizontal")) return Qt::Horizontal;
if (v == QLatin1String("vertical")) return Qt::Vertical;
return default_value;
}
Qt::Alignment alignmentFromXml(const QDomElement &element, const QString &name, Qt::Alignment default_value)
{
bool ok = false;
const auto v = element.attribute(name).toInt(&ok);
return ok && v ? Qt::Alignment(static_cast<Qt::AlignmentFlag>(v)) : default_value;
}
}
/**
* @brief TerminalStripLayoutPattern::xmlTagName
* @return the tag name of the xml element used by toXml / fromXml
*/
QString TerminalStripLayoutPattern::xmlTagName() {
return QStringLiteral("terminal_strip_layout");
}
/**
* @brief TerminalStripLayoutPattern::toXml
* Save all the values of this layout, including the font.
* The font is saved by hand (family, pixel size, bold, italic) and not with
* QFont::toString() because the format of this string is different between Qt5 and Qt6.
* @param document
* @return the xml element
*/
QDomElement TerminalStripLayoutPattern::toXml(QDomDocument &document) const
{
auto element = document.createElement(xmlTagName());
rectToXml(element, QStringLiteral("header"), m_header_rect);
element.setAttribute(QStringLiteral("header_text_orientation"), orientationToString(m_header_text_orientation));
element.setAttribute(QStringLiteral("header_text_alignment"), static_cast<int>(m_header_text_alignment));
rectToXml(element, QStringLiteral("spacer"), m_spacer_rect);
element.setAttribute(QStringLiteral("font_family"), m_font.family());
element.setAttribute(QStringLiteral("font_pixel_size"), m_font.pixelSize());
element.setAttribute(QStringLiteral("font_bold"), m_font.bold() ? 1 : 0);
element.setAttribute(QStringLiteral("font_italic"), m_font.italic() ? 1 : 0);
for (auto i = 0; i < m_terminal_rect.size(); ++i) {
rectToXml(element, QStringLiteral("terminal_%1").arg(i), m_terminal_rect.at(i));
}
element.setAttribute(QStringLiteral("terminals_text_height"), m_terminals_text_height);
element.setAttribute(QStringLiteral("terminals_text_y"), m_terminals_text_y);
element.setAttribute(QStringLiteral("terminals_text_orientation"), orientationToString(m_terminals_text_orientation));
element.setAttribute(QStringLiteral("terminals_text_alignment"), static_cast<int>(m_terminals_text_alignment));
element.setAttribute(QStringLiteral("xref_text_height"), m_xref_text_height);
element.setAttribute(QStringLiteral("xref_text_y"), m_xref_text_y);
element.setAttribute(QStringLiteral("xref_text_orientation"), orientationToString(m_xref_text_orientation));
element.setAttribute(QStringLiteral("xref_text_alignment"), static_cast<int>(m_xref_text_alignment));
element.setAttribute(QStringLiteral("type_symbol_y"), m_type_symbol_y);
element.setAttribute(QStringLiteral("type_symbol_height"), m_type_symbol_height);
element.setAttribute(QStringLiteral("connection_length"), m_connection_length);
element.setAttribute(QStringLiteral("cable_wire_length"), m_cable_wire_length);
element.setAttribute(QStringLiteral("cable_length"), m_cable_length);
element.setAttribute(QStringLiteral("cable_end_length"), m_cable_end_length);
element.setAttribute(QStringLiteral("bridge_point_d"), m_bridge_point_d);
for (auto i = 0; i < m_bridge_point_y_offset.size(); ++i) {
element.setAttribute(QStringLiteral("bridge_point_y_offset_%1").arg(i), m_bridge_point_y_offset.at(i));
}
return element;
}
/**
* @brief TerminalStripLayoutPattern::fromXml
* Load the values saved by toXml. A value missing in @a layout_element
* (project saved with an older version) keep the current value of this layout.
* @param layout_element
*/
void TerminalStripLayoutPattern::fromXml(const QDomElement &layout_element)
{
if (layout_element.isNull()) {
return;
}
m_header_rect = rectFromXml(layout_element, QStringLiteral("header"), m_header_rect);
m_header_text_orientation = orientationFromXml(layout_element, QStringLiteral("header_text_orientation"), m_header_text_orientation);
setHeaderTextAlignment(alignmentFromXml(layout_element, QStringLiteral("header_text_alignment"), m_header_text_alignment));
m_spacer_rect = rectFromXml(layout_element, QStringLiteral("spacer"), m_spacer_rect);
auto font_ = m_font;
if (layout_element.hasAttribute(QStringLiteral("font_family"))) {
font_.setFamily(layout_element.attribute(QStringLiteral("font_family")));
}
const auto pixel_size = layout_element.attribute(QStringLiteral("font_pixel_size")).toInt();
if (pixel_size > 0) {
font_.setPixelSize(pixel_size);
}
if (layout_element.hasAttribute(QStringLiteral("font_bold"))) {
font_.setBold(layout_element.attribute(QStringLiteral("font_bold")).toInt() != 0);
}
if (layout_element.hasAttribute(QStringLiteral("font_italic"))) {
font_.setItalic(layout_element.attribute(QStringLiteral("font_italic")).toInt() != 0);
}
setFont(font_);
for (auto i = 0; i < m_terminal_rect.size(); ++i) {
m_terminal_rect[i] = rectFromXml(layout_element, QStringLiteral("terminal_%1").arg(i), m_terminal_rect.at(i));
}
m_terminals_text_height = realFromXml(layout_element, QStringLiteral("terminals_text_height"), m_terminals_text_height);
m_terminals_text_y = realFromXml(layout_element, QStringLiteral("terminals_text_y"), m_terminals_text_y);
m_terminals_text_orientation = orientationFromXml(layout_element, QStringLiteral("terminals_text_orientation"), m_terminals_text_orientation);
setTerminalsTextAlignment(alignmentFromXml(layout_element, QStringLiteral("terminals_text_alignment"), m_terminals_text_alignment));
m_xref_text_height = realFromXml(layout_element, QStringLiteral("xref_text_height"), m_xref_text_height);
m_xref_text_y = realFromXml(layout_element, QStringLiteral("xref_text_y"), m_xref_text_y);
m_xref_text_orientation = orientationFromXml(layout_element, QStringLiteral("xref_text_orientation"), m_xref_text_orientation);
setXrefTextAlignment(alignmentFromXml(layout_element, QStringLiteral("xref_text_alignment"), m_xref_text_alignment));
m_type_symbol_y = realFromXml(layout_element, QStringLiteral("type_symbol_y"), m_type_symbol_y);
m_type_symbol_height = realFromXml(layout_element, QStringLiteral("type_symbol_height"), m_type_symbol_height);
m_connection_length = realFromXml(layout_element, QStringLiteral("connection_length"), m_connection_length);
m_cable_wire_length = realFromXml(layout_element, QStringLiteral("cable_wire_length"), m_cable_wire_length);
m_cable_length = realFromXml(layout_element, QStringLiteral("cable_length"), m_cable_length);
m_cable_end_length = realFromXml(layout_element, QStringLiteral("cable_end_length"), m_cable_end_length);
m_bridge_point_d = realFromXml(layout_element, QStringLiteral("bridge_point_d"), m_bridge_point_d);
for (auto i = 0; i < m_bridge_point_y_offset.size(); ++i) {
m_bridge_point_y_offset[i] = realFromXml(layout_element, QStringLiteral("bridge_point_y_offset_%1").arg(i), m_bridge_point_y_offset.at(i));
}
}
@@ -18,6 +18,7 @@
#ifndef TERMINALSTRIPLAYOUTPATTERN_H
#define TERMINALSTRIPLAYOUTPATTERN_H
#include <QDomElement>
#include <QFont>
#include <QRect>
#include <QSize>
@@ -103,6 +104,11 @@ class TerminalStripLayoutPattern
QUuid m_uuid{QUuid::createUuid()};
QString m_name;
//Save / load of the layout in the project xml
QDomElement toXml(QDomDocument &document) const;
void fromXml(const QDomElement &layout_element);
static QString xmlTagName();
private:
void updateHeaderTextOption();
void updateTerminalsTextOption();
@@ -17,6 +17,7 @@
*/
#include "terminalstriplayoutshandler.h"
#include <QDomDocument>
#include <QObject>
TerminalStripLayoutsHandler::TerminalStripLayoutsHandler()
@@ -30,3 +31,27 @@ QSharedPointer<TerminalStripLayoutPattern> TerminalStripLayoutsHandler::defaultL
{
return m_default_layout;
}
/**
* @brief TerminalStripLayoutsHandler::toXml
* Append the default layout (font included) as a child of @a parent_element
* @param parent_element
*/
void TerminalStripLayoutsHandler::toXml(QDomElement &parent_element) const
{
auto document = parent_element.ownerDocument();
parent_element.appendChild(m_default_layout->toXml(document));
}
/**
* @brief TerminalStripLayoutsHandler::fromXml
* Load the default layout from the child of @a parent_element, if any.
* The existing layout object is modified in place because the terminal
* strip items share it.
* @param parent_element
*/
void TerminalStripLayoutsHandler::fromXml(const QDomElement &parent_element)
{
m_default_layout->fromXml(
parent_element.firstChildElement(TerminalStripLayoutPattern::xmlTagName()));
}
@@ -18,6 +18,7 @@
#ifndef TERMINALSTRIPLAYOUTSHANDLER_H
#define TERMINALSTRIPLAYOUTSHANDLER_H
#include <QDomElement>
#include <QSet>
#include <QSharedPointer>
@@ -33,6 +34,9 @@ class TerminalStripLayoutsHandler
TerminalStripLayoutsHandler();
QSharedPointer<TerminalStripLayoutPattern> defaultLayout();
void toXml(QDomElement &parent_element) const;
void fromXml(const QDomElement &parent_element);
private:
QSet<QSharedPointer<TerminalStripLayoutPattern>> m_layout_set;
QSharedPointer<TerminalStripLayoutPattern> m_default_layout;
+6
View File
@@ -1587,6 +1587,8 @@ QDomDocument QETProject::toXml()
//Write terminal strip to xml
if (m_terminal_strip_vector.count())
{
m_project_properties_handler.terminalStripLayoutHandler().toXml(project_root);
auto xml_strip = xml_doc.createElement(QStringLiteral("terminal_strips"));
for (auto &strip : m_terminal_strip_vector) {
xml_strip.appendChild(strip->toXml(xml_doc));
@@ -2092,6 +2094,10 @@ void QETProject::readProjectXml(QDomDocument &xml_project)
readElementsCollectionXml(xml_project);
const qint64 elements_ms = phase_timer.restart();
//Load the layout of the terminal strip (font, size of cells...),
//before the diagrams because the terminal strip items use it
m_project_properties_handler.terminalStripLayoutHandler().fromXml(xml_project.documentElement());
//Load the diagrams
readDiagramsXml(xml_project);
const qint64 diagrams_ms = phase_timer.restart();