Merge pull request #1592 from ispyisail/refactor/qetz-reader-writer

Move reading and writing a .qetz file into classes of their own
This commit is contained in:
ispyisail
2026-10-23 23:01:34 +13:00
committed by GitHub
7 changed files with 203 additions and 53 deletions
+4
View File
@@ -173,6 +173,10 @@ set(QET_SRC_FILES
${QET_DIR}/sources/container/qetcontainer.h
${QET_DIR}/sources/container/qetzip.cpp
${QET_DIR}/sources/container/qetzip.h
${QET_DIR}/sources/container/qetzreader.cpp
${QET_DIR}/sources/container/qetzreader.h
${QET_DIR}/sources/container/qetzwriter.cpp
${QET_DIR}/sources/container/qetzwriter.h
${QET_DIR}/sources/borderproperties.cpp
${QET_DIR}/sources/borderproperties.h
${QET_DIR}/sources/bordertitleblock.cpp
+50
View File
@@ -0,0 +1,50 @@
/*
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 "qetzreader.h"
#include "qetzip.h"
/**
@brief QetzReader::read
Read @p content, the bytes of a .qet or a .qetz, into @p document.
For a .qetz, its entries, folio parts, pictures and format are kept.
@return false, with @p error set, if it cannot be read
*/
bool QetzReader::read(const QByteArray &content, QDomDocument *document, QString *error)
{
m_files.clear();
m_folio_parts.clear();
m_format = 0;
bool read = false;
if (QetContainer::isZip(content)) {
QList<QetZip::Entry> entries;
read = QetZip::fromBytes(content, &entries, error)
&& QetContainer::join(entries, document, error, &m_folio_parts,
&m_pictures, &m_format);
if (read)
for (const QetZip::Entry &entry : std::as_const(entries))
m_files.insert(entry.name, entry.data);
} else {
read = QetContainer::readDocument(content, document, error);
}
if (!read) {
m_pictures.clear();
m_folio_parts.clear();
}
return read;
}
+59
View File
@@ -0,0 +1,59 @@
/*
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/>.
*/
#ifndef QETZREADER_H
#define QETZREADER_H
#include "qetcontainer.h"
#include <QByteArray>
#include <QDomDocument>
#include <QHash>
#include <QString>
#include <QStringList>
/**
@brief The QetzReader class
Reads the bytes of a project file, a .qet or a .qetz, into its project
document, and keeps what a .qetz holds beside that document for as long
as the project is open: its entries (a save copies the parts of the
folios not built from them), the part each folio was read from, its
pictures and its format.
*/
class QetzReader
{
public:
bool read(const QByteArray &content, QDomDocument *document, QString *error = nullptr);
/// The format the .qetz says it is; 0 for a .qet
int format() const {return m_format;}
/// The entries of the .qetz read, by name
const QHash<QString, QByteArray> &files() const {return m_files;}
QByteArray file(const QString &name) const {return m_files.value(name);}
/// The part each folio was read from, in order
const QStringList &folioParts() const {return m_folio_parts;}
/// The picture in @p file, or an empty array when there is none
QByteArray picture(const QString &file) const {return m_pictures.value(file);}
private:
QHash<QString, QByteArray> m_files;
QStringList m_folio_parts;
QetContainer::Pictures m_pictures;
int m_format = 0;
};
#endif // QETZREADER_H
+39
View File
@@ -0,0 +1,39 @@
/*
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 "qetzwriter.h"
#include "../qetversion.h"
#include "qetcontainer.h"
#include "qetzip.h"
/**
@brief QetzWriter::write
Write the project document @p project to @p path as a .qetz: the same
document, in parts, zipped (#1440). The file is replaced only once
the whole archive is written. @p kept_from: the entries of the .qetz
read, whose parts the folios not built are copied from.
*/
bool QetzWriter::write(const QDomDocument &project, const QString &path, QString *error,
const QHash<QString, QByteArray> &kept_from)
{
QList<QetZip::Entry> entries = QetContainer::split(
project,
QStringLiteral("QElectroTech %1").arg(QetVersion::currentVersion().toString()),
error, kept_from);
return !entries.isEmpty() && QetZip::write(path, entries, error);
}
+36
View File
@@ -0,0 +1,36 @@
/*
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/>.
*/
#ifndef QETZWRITER_H
#define QETZWRITER_H
#include <QByteArray>
#include <QDomDocument>
#include <QHash>
#include <QString>
/**
@brief The QetzWriter namespace
Writes a project document as a .qetz file.
*/
namespace QetzWriter
{
bool write(const QDomDocument &project, const QString &path, QString *error = nullptr,
const QHash<QString, QByteArray> &kept_from = QHash<QString, QByteArray>());
}
#endif // QETZWRITER_H
+11 -43
View File
@@ -19,6 +19,7 @@
#include "qetproject.h"
#include "container/qetcontainer.h"
#include "container/qetcontainerdb.h"
#include "container/qetzwriter.h"
#include "ElementsCollection/xmlelementcollection.h"
#include "autoNum/assignvariables.h"
@@ -294,7 +295,7 @@ QUuid QETProject::uuid() const
*/
QByteArray QETProject::containerPicture(const QString &file) const
{
return m_container_pictures.value(file);
return m_container.picture(file);
}
/**
@@ -528,27 +529,10 @@ QETProject::ProjectState QETProject::openFile(QFile *file)
QString read_error;
//A .qetz: its entries are kept, for a save to copy the parts of the
//folios not built (stage D4)
m_container_files.clear();
m_folio_parts.clear();
bool read = false;
int container_format = 0;
if (QetContainer::isZip(content)) {
QList<QetZip::Entry> entries;
read = QetZip::fromBytes(content, &entries, &read_error)
&& QetContainer::join(entries, &xml_project, &read_error, &m_folio_parts,
&m_container_pictures, &container_format);
if (read)
for (const QetZip::Entry &entry : std::as_const(entries))
m_container_files.insert(entry.name, entry.data);
} else {
read = QetContainer::readDocument(content, &xml_project, &read_error);
}
if (!read)
if (!m_container.read(content, &xml_project, &read_error))
{
qWarning().noquote() << "Unable to read" << fi.fileName() << ":" << read_error;
m_open_error = read_error;
m_container_pictures.clear();
m_folio_parts.clear();
if(opened_here) {
file->close();
}
@@ -581,13 +565,13 @@ QETProject::ProjectState QETProject::openFile(QFile *file)
//Written by a later QElectroTech that lets this one read it: saving
//here would drop what this version does not know
m_from_later_version = container_format > QetContainer::Format;
m_from_later_version = m_container.format() > QetContainer::Format;
if (!fi.isWritable() || m_from_later_version) {
setReadOnly(true);
}
if (m_from_later_version) {
qInfo().noquote() << QStringLiteral("Project %1 is of .qetz format %2 (this version writes %3): opened read-only")
.arg(fi.fileName()).arg(container_format).arg(QetContainer::Format);
.arg(fi.fileName()).arg(m_container.format()).arg(QetContainer::Format);
}
if(opened_here) {
file->close();
@@ -2757,22 +2741,6 @@ QString QETProject::openFileFilter()
return tr("QElectroTech project (*.qet *.qetz)");
}
/**
@brief QETProject::writeContainer
Write the project document @p project to @p path as a .qetz: the same
document, in parts, zipped (#1440). The file is replaced only once
the whole archive is written.
*/
bool QETProject::writeContainer(const QDomDocument &project, const QString &path, QString *error,
const QHash<QString, QByteArray> &kept_from)
{
QList<QetZip::Entry> entries = QetContainer::split(
project,
QStringLiteral("QElectroTech %1").arg(QetVersion::currentVersion().toString()),
error, kept_from);
return !entries.isEmpty() && QetZip::write(path, entries, error);
}
/**
@brief QETProject::writeContainerFile
Write this project to @p path as a .qetz
@@ -2783,8 +2751,8 @@ bool QETProject::writeContainerFile(const QString &path, QString *error)
//what building them would write (toXml()); every other folio built
QStringList kept;
const QDomDocument document = toXml(nullptr, &kept);
return writeContainer(document, path, error,
kept.isEmpty() ? QHash<QString, QByteArray>() : m_container_files);
return QetzWriter::write(document, path, error,
kept.isEmpty() ? QHash<QString, QByteArray>() : m_container.files());
}
/**
@@ -3651,10 +3619,10 @@ void QETProject::readProjectXml(QDomDocument &xml_project)
for (Diagram *diagram : std::as_const(m_diagrams_list))
if (!diagram->isLoaded() && diagram->keptText().isEmpty())
m_kept_folios_trusted = false;
m_kept_parts_trusted = !m_folio_parts.isEmpty() && unloadedFolioCount() > 0
m_kept_parts_trusted = !m_container.folioParts().isEmpty() && unloadedFolioCount() > 0
&& m_project_qet_version == QetVersion::currentVersion()
&& m_data_base.rowsFromDocument()
&& QetContainerDb::currentFormat(m_container_files.value(QStringLiteral("project.sqlite")));
&& QetContainerDb::currentFormat(m_container.file(QStringLiteral("project.sqlite")));
for (Diagram *diagram : std::as_const(m_diagrams_list))
if (!diagram->isLoaded() && diagram->keptPart().isEmpty())
m_kept_parts_trusted = false;
@@ -3823,8 +3791,8 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project)
m_deferring_folios = false;
if (!diagram->isLoaded() && !line_starts.isEmpty())
diagram->setKeptText(folio_text(diagram_xml_element));
if (!diagram->isLoaded() && m_folio_parts.size() == diagram_nodes.length())
diagram->setKeptPart(m_folio_parts.at(i));
if (!diagram->isLoaded() && m_container.folioParts().size() == diagram_nodes.length())
diagram->setKeptPart(m_container.folioParts().at(i));
m_data_base.placeFolio(diagram);
if(dlgWaiting)
dlgWaiting->setDetail(diagram->title());
+4 -10
View File
@@ -34,6 +34,7 @@
#include "diagram.h"
#include "autoNum/assignvariables.h"
#include "container/qetcontainerdb.h"
#include "container/qetzreader.h"
#include "projectlock.h"
#ifdef BUILD_WITHOUT_KF
# include "ui/nokde/kautosavefile.h"
@@ -472,9 +473,6 @@ class QETProject : public QObject
static bool isContainerPath(const QString &path);
static QString openFileFilter();
QETResult writeCopyForOlderVersions(const QString &path);
static bool writeContainer(const QDomDocument &project, const QString &path,
QString *error = nullptr,
const QHash<QString, QByteArray> &kept_from = QHash<QString, QByteArray>());
bool writeContainerFile(const QString &path, QString *error = nullptr);
private:
static QUuid derivedUuid(const QByteArray &content);
@@ -486,9 +484,9 @@ class QETProject : public QObject
static bool m_backup_enabled;
/// Something changed since the last backup, see writeBackup()
bool m_backup_needed = true;
/// The pictures of the .qetz this project was opened from, see
/// containerPicture()
QHash<QString, QByteArray> m_container_pictures;
/// What the file this project was opened from holds beside its
/// document: a .qetz's entries, folio parts and pictures
QetzReader m_container;
/// File path this project is saved to
QString m_file_path;
/// Current state of the project
@@ -562,10 +560,6 @@ class QETProject : public QObject
/// Saving a .qetz may copy the part of a folio not built
/// (toXml(), stage D4)
bool m_kept_parts_trusted = false;
/// The entries of the .qetz opened, and the part each folio
/// was read from, in order
QHash<QString, QByteArray> m_container_files;
QStringList m_folio_parts;
bool m_kept_folios_stale = false;
/// Something was edited since the project was opened: a table
/// filled from the database may have changed