From b145a25abf35828b19c05b2d15fd5dc229236c1b Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Sat, 28 Oct 2023 08:56:05 +0300 Subject: [PATCH] Known measurements database. --- src/libs/ifc/ifc.qbs | 2 + src/libs/ifc/ifcdef.cpp | 1 + src/libs/ifc/ifcdef.h | 1 + src/libs/ifc/schema.qrc | 1 + .../ifc/schema/known_measurements/v1.0.0.xsd | 75 +++ src/libs/ifc/xml/vdomdocument.cpp | 8 +- src/libs/ifc/xml/vdomdocument.h | 8 + .../ifc/xml/vknownmeasurementsconverter.cpp | 137 ++++ .../ifc/xml/vknownmeasurementsconverter.h | 70 ++ src/libs/ifc/xml/vlayoutconverter.cpp | 4 +- src/libs/ifc/xml/vpatternimage.cpp | 12 + src/libs/ifc/xml/vpatternimage.h | 4 + src/libs/ifc/xml/xml.pri | 7 +- .../knownmeasurements/vknownmeasurement.h | 45 ++ .../knownmeasurements/vknownmeasurements.cpp | 162 +++++ .../knownmeasurements/vknownmeasurements.h | 80 +++ .../knownmeasurements/vknownmeasurements_p.h | 62 ++ .../vknownmeasurementsdatabase.cpp | 156 +++++ .../vknownmeasurementsdatabase.h | 70 ++ .../vknownmeasurementsdocument.cpp | 601 ++++++++++++++++++ .../vknownmeasurementsdocument.h | 98 +++ src/libs/vformat/vformat.pri | 14 +- src/libs/vformat/vformat.qbs | 8 + src/libs/vformat/vmeasurements.cpp | 116 ++-- src/libs/vformat/vmeasurements.h | 11 +- 25 files changed, 1691 insertions(+), 62 deletions(-) create mode 100644 src/libs/ifc/schema/known_measurements/v1.0.0.xsd create mode 100644 src/libs/ifc/xml/vknownmeasurementsconverter.cpp create mode 100644 src/libs/ifc/xml/vknownmeasurementsconverter.h create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurement.h create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurements.cpp create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurements.h create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurements_p.h create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.cpp create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.h create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.cpp create mode 100644 src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.h diff --git a/src/libs/ifc/ifc.qbs b/src/libs/ifc/ifc.qbs index 84f01269d..12cb978bd 100644 --- a/src/libs/ifc/ifc.qbs +++ b/src/libs/ifc/ifc.qbs @@ -86,6 +86,8 @@ VLib { "vabstractmconverter.cpp", "vlabeltemplateconverter.cpp", "vwatermarkconverter.cpp", + "vknownmeasurementsconverter.cpp", + "vknownmeasurementsconverter.h", ] } diff --git a/src/libs/ifc/ifcdef.cpp b/src/libs/ifc/ifcdef.cpp index 1a59f8f8e..c9c02c351 100644 --- a/src/libs/ifc/ifcdef.cpp +++ b/src/libs/ifc/ifcdef.cpp @@ -148,6 +148,7 @@ const QString AttrCurve1Alias2 = QStringLiteral("curve1Alias2"); const QString AttrCurve2Alias1 = QStringLiteral("curve2Alias1"); const QString AttrCurve2Alias2 = QStringLiteral("curve2Alias2"); const QString AttrLayoutVersion = QStringLiteral("version"); +const QString AttrKMVersion = QStringLiteral("version"); const QString TypeLineDefault = QStringLiteral("default"); const QString TypeLineNone = QStringLiteral("none"); diff --git a/src/libs/ifc/ifcdef.h b/src/libs/ifc/ifcdef.h index 4ffdf942d..9034112fe 100644 --- a/src/libs/ifc/ifcdef.h +++ b/src/libs/ifc/ifcdef.h @@ -165,6 +165,7 @@ extern const QString AttrCurve1Alias2; extern const QString AttrCurve2Alias1; extern const QString AttrCurve2Alias2; extern const QString AttrLayoutVersion; +extern const QString AttrKMVersion; extern const QString TypeLineDefault; extern const QString TypeLineNone; diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc index 27c49af91..fd39d015e 100644 --- a/src/libs/ifc/schema.qrc +++ b/src/libs/ifc/schema.qrc @@ -101,5 +101,6 @@ schema/layout/v0.1.4.xsd schema/layout/v0.1.5.xsd schema/layout/v0.1.6.xsd + schema/known_measurements/v1.0.0.xsd diff --git a/src/libs/ifc/schema/known_measurements/v1.0.0.xsd b/src/libs/ifc/schema/known_measurements/v1.0.0.xsd new file mode 100644 index 000000000..5d4d5c84e --- /dev/null +++ b/src/libs/ifc/schema/known_measurements/v1.0.0.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vdomdocument.cpp b/src/libs/ifc/xml/vdomdocument.cpp index 57d303e77..f0d185cb3 100644 --- a/src/libs/ifc/xml/vdomdocument.cpp +++ b/src/libs/ifc/xml/vdomdocument.cpp @@ -832,7 +832,7 @@ auto VDomDocument::SaveDocument(const QString &fileName, QString &error) -> bool // cppcheck-suppress unusedFunction auto VDomDocument::Major() const -> QString { - QString version = UniqueTagText(TagVersion, "0.0.0"); + QString version = UniqueTagText(TagVersion, "0.0.0"_L1); QStringList v = version.split('.'_L1); return v.at(0); } @@ -841,7 +841,7 @@ auto VDomDocument::Major() const -> QString // cppcheck-suppress unusedFunction auto VDomDocument::Minor() const -> QString { - QString version = UniqueTagText(TagVersion, "0.0.0"); + QString version = UniqueTagText(TagVersion, "0.0.0"_L1); QStringList v = version.split('.'_L1); return v.at(1); } @@ -850,7 +850,7 @@ auto VDomDocument::Minor() const -> QString // cppcheck-suppress unusedFunction auto VDomDocument::Patch() const -> QString { - QString version = UniqueTagText(TagVersion, "0.0.0"); + QString version = UniqueTagText(TagVersion, "0.0.0"_L1); QStringList v = version.split('.'_L1); return v.at(2); } @@ -880,7 +880,7 @@ auto VDomDocument::GetFormatVersionStr() const -> QString return domElement.text(); } } - return QString(QStringLiteral("0.0.0")); + return "0.0.0"_L1; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/ifc/xml/vdomdocument.h b/src/libs/ifc/xml/vdomdocument.h index 690e347fc..730569778 100644 --- a/src/libs/ifc/xml/vdomdocument.h +++ b/src/libs/ifc/xml/vdomdocument.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,13 @@ inline void VDomDocument::SetAttribute(QDomElement &domElement, c domElement.setAttribute(name, value); } +//--------------------------------------------------------------------------------------------------------------------- +template <> +inline void VDomDocument::SetAttribute(QDomElement &domElement, const QString &name, const QUuid &value) const +{ + domElement.setAttribute(name, value.toString()); +} + //--------------------------------------------------------------------------------------------------------------------- template <> inline void VDomDocument::SetAttribute(QDomElement &domElement, const QString &name, const QChar &value) const diff --git a/src/libs/ifc/xml/vknownmeasurementsconverter.cpp b/src/libs/ifc/xml/vknownmeasurementsconverter.cpp new file mode 100644 index 000000000..4051ceb39 --- /dev/null +++ b/src/libs/ifc/xml/vknownmeasurementsconverter.cpp @@ -0,0 +1,137 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsconverter.cpp + ** @author Roman Telezhynskyi + ** @date 26 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#include "vknownmeasurementsconverter.h" + +#include + +#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) +#include "../vmisc/compatibility.h" +#endif + +using namespace Qt::Literals::StringLiterals; + +/* + * Version rules: + * 1. Version have three parts "major.minor.patch"; + * 2. major part only for stable releases; + * 3. minor - 10 or more patch changes, or one big change; + * 4. patch - little change. + */ + +const QString VKnownMeasurementsConverter::KnownMeasurementsMinVerStr = QStringLiteral("1.0.0"); +const QString VKnownMeasurementsConverter::KnownMeasurementsMaxVerStr = QStringLiteral("1.0.0"); +const QString VKnownMeasurementsConverter::CurrentSchema = QStringLiteral("://schema/known_measurements/v1.0.0.xsd"); + +// VKnownMeasurementsConverter::KnownMeasurementsMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! +// VKnownMeasurementsConverter::KnownMeasurementsMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! + +//--------------------------------------------------------------------------------------------------------------------- +VKnownMeasurementsConverter::VKnownMeasurementsConverter(const QString &fileName) + : VAbstractConverter(fileName) +{ + m_ver = GetFormatVersion(VKnownMeasurementsConverter::GetFormatVersionStr()); + ValidateInputFile(CurrentSchema); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::GetFormatVersionStr() const -> QString +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + const QDomElement layoutElement = root.toElement(); + if (not layoutElement.isNull()) + { + return GetParametrString(layoutElement, AttrKMVersion, "0.0.0"_L1); + } + } + return "0.0.0"_L1; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::XSDSchemas() -> QHash +{ + static auto schemas = QHash{std::make_pair(FormatVersion(1, 0, 0), CurrentSchema)}; + + return schemas; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::MinVer() const -> unsigned int +{ + return KnownMeasurementsMinVer; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::MaxVer() const -> unsigned int +{ + return KnownMeasurementsMaxVer; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::MinVerStr() const -> QString +{ + return KnownMeasurementsMinVerStr; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::MaxVerStr() const -> QString +{ + return KnownMeasurementsMaxVerStr; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsConverter::ApplyPatches() +{ + switch (m_ver) + { + case (FormatVersion(1, 0, 0)): + break; + default: + InvalidVersion(m_ver); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsConverter::DowngradeToCurrentMaxVersion() +{ + SetVersion(KnownMeasurementsMaxVerStr); + Save(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::IsReadOnly() const -> bool +{ + return false; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsConverter::Schemas() const -> QHash +{ + return XSDSchemas(); +} diff --git a/src/libs/ifc/xml/vknownmeasurementsconverter.h b/src/libs/ifc/xml/vknownmeasurementsconverter.h new file mode 100644 index 000000000..4687b0096 --- /dev/null +++ b/src/libs/ifc/xml/vknownmeasurementsconverter.h @@ -0,0 +1,70 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsconverter.h + ** @author Roman Telezhynskyi + ** @date 26 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENTSCONVERTER_H +#define VKNOWNMEASUREMENTSCONVERTER_H + +#include "../vmisc/projectversion.h" +#include "vabstractconverter.h" + +class VKnownMeasurementsConverter : public VAbstractConverter +{ + Q_OBJECT // NOLINT + +public: + explicit VKnownMeasurementsConverter(const QString &fileName); + ~VKnownMeasurementsConverter() override = default; + + auto GetFormatVersionStr() const -> QString override; + + static const QString KnownMeasurementsMaxVerStr; + static const QString CurrentSchema; + static Q_DECL_CONSTEXPR const unsigned KnownMeasurementsMinVer = FormatVersion(1, 0, 0); + static Q_DECL_CONSTEXPR const unsigned KnownMeasurementsMaxVer = FormatVersion(1, 0, 0); + + static auto XSDSchemas() -> QHash; + +protected: + auto MinVer() const -> unsigned override; + auto MaxVer() const -> unsigned override; + + auto MinVerStr() const -> QString override; + auto MaxVerStr() const -> QString override; + + void ApplyPatches() override; + void DowngradeToCurrentMaxVersion() override; + + auto IsReadOnly() const -> bool override; + + auto Schemas() const -> QHash override; + +private: + Q_DISABLE_COPY_MOVE(VKnownMeasurementsConverter) // NOLINT + static const QString KnownMeasurementsMinVerStr; +}; + +#endif // VKNOWNMEASUREMENTSCONVERTER_H diff --git a/src/libs/ifc/xml/vlayoutconverter.cpp b/src/libs/ifc/xml/vlayoutconverter.cpp index 594824846..6df412ce0 100644 --- a/src/libs/ifc/xml/vlayoutconverter.cpp +++ b/src/libs/ifc/xml/vlayoutconverter.cpp @@ -132,10 +132,10 @@ auto VLayoutConverter::GetFormatVersionStr() const -> QString const QDomElement layoutElement = root.toElement(); if (not layoutElement.isNull()) { - return GetParametrString(layoutElement, AttrLayoutVersion, QStringLiteral("0.0.0")); + return GetParametrString(layoutElement, AttrLayoutVersion, "0.0.0"_L1); } } - return QStringLiteral("0.0.0"); + return "0.0.0"_L1; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/ifc/xml/vpatternimage.cpp b/src/libs/ifc/xml/vpatternimage.cpp index 2318f719c..86c50fef8 100644 --- a/src/libs/ifc/xml/vpatternimage.cpp +++ b/src/libs/ifc/xml/vpatternimage.cpp @@ -209,3 +209,15 @@ auto VPatternImage::Size() const -> QSize return QImageReader(&buffer).size(); } + +//--------------------------------------------------------------------------------------------------------------------- +auto VPatternImage::Title() const -> QString +{ + return m_title; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VPatternImage::SetTitle(const QString &newTitle) +{ + m_title = newTitle; +} diff --git a/src/libs/ifc/xml/vpatternimage.h b/src/libs/ifc/xml/vpatternimage.h index 6d37a19b2..c8d3ca79e 100644 --- a/src/libs/ifc/xml/vpatternimage.h +++ b/src/libs/ifc/xml/vpatternimage.h @@ -60,10 +60,14 @@ public: auto Size() const -> QSize; + auto Title() const -> QString; + void SetTitle(const QString &newTitle); + private: QString m_contentType{}; QByteArray m_contentData{}; mutable QString m_errorString{}; + QString m_title{}; }; #endif // VPATTERNIMAGE_H diff --git a/src/libs/ifc/xml/xml.pri b/src/libs/ifc/xml/xml.pri index 0b78e5809..5073a365d 100644 --- a/src/libs/ifc/xml/xml.pri +++ b/src/libs/ifc/xml/xml.pri @@ -16,7 +16,8 @@ HEADERS += \ $$PWD//vabstractmconverter.h \ $$PWD/vlabeltemplateconverter.h \ $$PWD/vwatermarkconverter.h \ - $$PWD/vparsererrorhandler.h + $$PWD/vparsererrorhandler.h \ + $$PWD/vknownmeasurementsconverter.h SOURCES += \ $$PWD/utils.cpp \ @@ -33,4 +34,6 @@ SOURCES += \ $$PWD//vabstractmconverter.cpp \ $$PWD/vlabeltemplateconverter.cpp \ $$PWD/vwatermarkconverter.cpp \ - $$PWD/vparsererrorhandler.cpp + $$PWD/vparsererrorhandler.cpp \ + $$PWD/vknownmeasurementsconverter.cpp + diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurement.h b/src/libs/vformat/knownmeasurements/vknownmeasurement.h new file mode 100644 index 000000000..6c6ae7202 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurement.h @@ -0,0 +1,45 @@ +/************************************************************************ + ** + ** @file vknownmeasurement.h + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENT_H +#define VKNOWNMEASUREMENT_H + +#include +#include + +struct VKnownMeasurement +{ + QString name{}; + QString fullName{}; + QString description{}; + QString formula{}; + bool specialUnits{false}; + QUuid diagram{}; + int index{0}; +}; + +#endif // VKNOWNMEASUREMENT_H diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurements.cpp b/src/libs/vformat/knownmeasurements/vknownmeasurements.cpp new file mode 100644 index 000000000..e9498de83 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurements.cpp @@ -0,0 +1,162 @@ +/************************************************************************ + ** + ** @file vknownmeasurements.cpp + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#include "vknownmeasurements.h" +#include "../vmisc/def.h" +#include "vknownmeasurements_p.h" + +//--------------------------------------------------------------------------------------------------------------------- +VKnownMeasurements::VKnownMeasurements() + : d(new VKnownMeasurementsData) +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +VKnownMeasurements::~VKnownMeasurements() +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +COPY_CONSTRUCTOR_IMPL(VKnownMeasurements) + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::operator=(const VKnownMeasurements &measurements) -> VKnownMeasurements & +{ + if (&measurements == this) + { + return *this; + } + d = measurements.d; + return *this; +} + +#ifdef Q_COMPILER_RVALUE_REFS +//--------------------------------------------------------------------------------------------------------------------- +VKnownMeasurements::VKnownMeasurements(VKnownMeasurements &&paper) noexcept + : d(std::move(paper.d)) +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::operator=(VKnownMeasurements &&paper) noexcept -> VKnownMeasurements & +{ + std::swap(d, paper.d); + return *this; +} +#endif + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::IsValid() const -> bool +{ + return !d->m_uid.isNull(); +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::GetUId() const -> QUuid +{ + return d->m_uid; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::SetUId(const QUuid &id) +{ + d->m_uid = id; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::Name() const -> QString +{ + return d->m_name; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::SetName(const QString &name) +{ + d->m_name = name; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::Description() const -> QString +{ + return d->m_description; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::SetDescription(const QString &desc) +{ + d->m_description = desc; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::IsReadOnly() const -> bool +{ + return d->m_readOnly; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::SetReadOnly(bool ro) +{ + d->m_readOnly = ro; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::Measurments() const -> QHash +{ + return d->m_measurements; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::OrderedMeasurments() const -> QMap +{ + QMap ordered; + auto i = d->m_measurements.constBegin(); + while (i != d->m_measurements.constEnd()) + { + ordered.insert(i.value().index, i.value()); + ++i; + } + + return ordered; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurements::Images() const -> QHash +{ + return d->m_images; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::AddMeasurement(const VKnownMeasurement &m) +{ + d->m_measurements.insert(m.name, m); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurements::AddImage(const QUuid &id, const VPatternImage &image) +{ + d->m_images.insert(id, image); +} diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurements.h b/src/libs/vformat/knownmeasurements/vknownmeasurements.h new file mode 100644 index 000000000..c94e5b9e3 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurements.h @@ -0,0 +1,80 @@ +/************************************************************************ + ** + ** @file vknownmeasurements.h + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENTS_H +#define VKNOWNMEASUREMENTS_H + +#include "xml/vpatternimage.h" +#include +#include + +class VKnownMeasurementsData; +class QUuid; +struct VKnownMeasurement; + +class VKnownMeasurements +{ +public: + VKnownMeasurements(); + ~VKnownMeasurements(); + + VKnownMeasurements(const VKnownMeasurements &measurements); + + auto operator=(const VKnownMeasurements &paper) -> VKnownMeasurements &; +#ifdef Q_COMPILER_RVALUE_REFS + VKnownMeasurements(VKnownMeasurements &&paper) noexcept; + auto operator=(VKnownMeasurements &&paper) noexcept -> VKnownMeasurements &; +#endif + + auto IsValid() const -> bool; + + auto GetUId() const -> QUuid; + void SetUId(const QUuid &id); + + auto Name() const -> QString; + void SetName(const QString &name); + + auto Description() const -> QString; + void SetDescription(const QString &desc); + + auto IsReadOnly() const -> bool; + void SetReadOnly(bool ro); + + auto Measurments() const -> QHash; + auto OrderedMeasurments() const -> QMap; + auto Images() const -> QHash; + + void AddMeasurement(const VKnownMeasurement &m); + void AddImage(const QUuid &id, const VPatternImage &image); + +private: + QSharedDataPointer d; +}; + +Q_DECLARE_TYPEINFO(VKnownMeasurements, Q_MOVABLE_TYPE); // NOLINT + +#endif // VKNOWNMEASUREMENTS_H diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurements_p.h b/src/libs/vformat/knownmeasurements/vknownmeasurements_p.h new file mode 100644 index 000000000..35d384fb8 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurements_p.h @@ -0,0 +1,62 @@ +/************************************************************************ + ** + ** @file vknownmeasurements_p.h + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENTS_P_H +#define VKNOWNMEASUREMENTS_P_H + +#include "../ifc/xml/vpatternimage.h" +#include "../vmisc/defglobal.h" +#include "vknownmeasurement.h" +#include +#include + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Weffc++") +QT_WARNING_DISABLE_GCC("-Wnon-virtual-dtor") + +class VKnownMeasurementsData : public QSharedData +{ +public: + VKnownMeasurementsData() = default; + VKnownMeasurementsData(const VKnownMeasurementsData &measurements) = default; + ~VKnownMeasurementsData() = default; + + QUuid m_uid{}; // NOLINT (misc-non-private-member-variables-in-classes) + QString m_name{}; // NOLINT (misc-non-private-member-variables-in-classes) + QString m_description{}; // NOLINT (misc-non-private-member-variables-in-classes) + bool m_readOnly{false}; // NOLINT (misc-non-private-member-variables-in-classes) + + QHash m_images{}; // NOLINT (misc-non-private-member-variables-in-classes) + QHash m_measurements{}; // NOLINT (misc-non-private-member-variables-in-classes) + +private: + Q_DISABLE_ASSIGN_MOVE(VKnownMeasurementsData) // NOLINT +}; + +QT_WARNING_POP + +#endif // VKNOWNMEASUREMENTS_P_H diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.cpp b/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.cpp new file mode 100644 index 000000000..d76f70604 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.cpp @@ -0,0 +1,156 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsdatabase.cpp + ** @author Roman Telezhynskyi + ** @date 26 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#include "vknownmeasurementsdatabase.h" +#include "../ifc/exception/vexception.h" +#include "../ifc/xml/vknownmeasurementsconverter.h" +#include "../vformat/knownmeasurements/vknownmeasurements.h" +#include "../vformat/knownmeasurements/vknownmeasurementsdocument.h" +#include "../vmisc/vabstractapplication.h" +#include "../vmisc/vcommonsettings.h" + +#include +#include +#include +#include + +namespace +{ +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wunused-member-function") + +Q_GLOBAL_STATIC(QMutex, knownMeasurementsDatabaseMutex) // NOLINT + +QT_WARNING_POP +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDatabase::PopulateMeasurementsDatabase() +{ + QMutexLocker locker(knownMeasurementsDatabaseMutex()); + + m_measurementsCache.clear(); + + VCommonSettings *settings = VAbstractApplication::VApp()->Settings(); + + m_measurementsDB.clear(); + m_populated = false; + + ParseDirectory(settings->GetPathKnownMeasurements()); + + UpdateIndexes(); + m_populated = true; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDatabase::IsPopulated() const -> bool +{ + QMutexLocker locker(knownMeasurementsDatabaseMutex()); + return m_populated; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDatabase::AllKnownMeasurements() const -> QHash +{ + return m_measurementsDB; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDatabase::KnownMeasurements(const QUuid &id) const -> VKnownMeasurements +{ + if (m_measurementsCache.contains(id)) + { + return {*m_measurementsCache.object(id)}; + } + + QString measurementsFilePath = m_indexMeasurementsPath.value(id); + if (measurementsFilePath.isEmpty()) + { + return {}; + } + + try + { + VKnownMeasurementsConverter converter(measurementsFilePath); + VKnownMeasurementsDocument measurements; + measurements.setXMLContent(converter.Convert()); + + VKnownMeasurements known = measurements.KnownMeasurements(); + m_measurementsCache.insert(id, new VKnownMeasurements(known)); + return known; + } + catch (VException &e) + { + qDebug("%s\n\n%s\n\n%s", qUtf8Printable("File error."), qUtf8Printable(e.ErrorMessage()), + qUtf8Printable(e.DetailedInformation())); + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDatabase::UpdateIndexes() +{ + m_indexMeasurementsPath.clear(); + + auto i = m_measurementsDB.constBegin(); + while (i != m_measurementsDB.constEnd()) + { + m_indexMeasurementsPath.insert(i.key(), i.value().path); + ++i; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDatabase::ParseDirectory(const QString &path) +{ + QDirIterator it(path, {"*.vkm"}, QDir::Files, QDirIterator::Subdirectories); + while (it.hasNext()) + { + QString measurementsFilePath = it.next(); + + try + { + VKnownMeasurementsConverter converter(measurementsFilePath); + VKnownMeasurementsDocument measurements; + measurements.setXMLContent(converter.Convert()); + + VKnownMeasurementsHeader header; + header.uid = measurements.GetUId(); + header.name = measurements.Name(); + header.description = measurements.Description(); + header.path = measurementsFilePath; + + m_measurementsDB.insert(header.uid, header); + } + catch (VException &e) + { + qDebug("%s\n\n%s\n\n%s", qUtf8Printable("File error."), qUtf8Printable(e.ErrorMessage()), + qUtf8Printable(e.DetailedInformation())); + } + } +} diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.h b/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.h new file mode 100644 index 000000000..b226ec89d --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurementsdatabase.h @@ -0,0 +1,70 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsdatabase.h + ** @author Roman Telezhynskyi + ** @date 26 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENTSDATABASE_H +#define VKNOWNMEASUREMENTSDATABASE_H + +#include +#include +#include +#include + +class VKnownMeasurements; + +struct VKnownMeasurementsHeader +{ + QUuid uid{}; + QString name{}; + QString description{}; + QString path{}; +}; + +class VKnownMeasurementsDatabase +{ +public: + VKnownMeasurementsDatabase() = default; + + void PopulateMeasurementsDatabase(); + + auto IsPopulated() const -> bool; + + auto AllKnownMeasurements() const -> QHash; + + auto KnownMeasurements(const QUuid &id) const -> VKnownMeasurements; + +private: + bool m_populated{false}; + QHash m_measurementsDB{}; + QHash m_indexMeasurementsPath{}; + mutable QCache m_measurementsCache{15}; + + void UpdateIndexes(); + + void ParseDirectory(const QString &path); +}; + +#endif // VKNOWNMEASUREMENTSDATABASE_H diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.cpp b/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.cpp new file mode 100644 index 000000000..f53310537 --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.cpp @@ -0,0 +1,601 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsdocument.cpp + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#include "vknownmeasurementsdocument.h" +#include "../ifc/xml/vknownmeasurementsconverter.h" +#include "../ifc/xml/vpatternimage.h" +#include "../vmisc/projectversion.h" +#include "ifcdef.h" +#include "literals.h" +#include "quuid.h" +#include "vformat/knownmeasurements/vknownmeasurement.h" +#include "vknownmeasurements.h" + +#include + +#if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) +#include "../vmisc/compatibility.h" +#endif + +using namespace Qt::Literals::StringLiterals; + +namespace +{ +QT_WARNING_PUSH +QT_WARNING_DISABLE_CLANG("-Wunused-member-function") + +// The list of all string we use for conversion +// Better to use global variables because repeating QStringLiteral blows up code size +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagKnownMeasurements, ("known-measurements"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagMeasurements, ("measurements"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagMeasurement, ("m"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagDiagrams, ("diagrams"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagImage, ("tagImage"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagName, ("name"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagDescription, ("description"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, tagInfo, ("info"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrFormula, ("formula"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrSpecialUnits, ("specialUnits"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrName, ("name"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrContentType, ("contentType"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrUId, ("uid"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrTitle, ("title"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrReadOnly, ("read-only"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrDescription, ("description"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrFullName, ("full_name"_L1)) // NOLINT +Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrDiagram, ("diagram"_L1)) // NOLINT + +QT_WARNING_POP + +//--------------------------------------------------------------------------------------------------------------------- +auto FileComment() -> QString +{ + return u"Known measurements created with Valentina v%1 (https://smart-pattern.com.ua/)."_s.arg(AppVersionStr()); +} +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- +VKnownMeasurementsDocument::VKnownMeasurementsDocument(QObject *parent) + : VDomDocument(parent) +{ +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDocument::SaveDocument(const QString &fileName, QString &error) -> bool +{ + // Update comment with Valentina version + QDomNode commentNode = documentElement().firstChild(); + if (commentNode.isComment()) + { + QDomComment comment = commentNode.toComment(); + comment.setData(FileComment()); + } + + return VDomDocument::SaveDocument(fileName, error); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::CreateEmptyFile() +{ + clear(); + QDomElement kmElement = this->createElement(*tagKnownMeasurements); + + kmElement.appendChild(createComment(FileComment())); + kmElement.setAttribute(AttrKMVersion, VKnownMeasurementsConverter::KnownMeasurementsMaxVerStr); + kmElement.setAttribute(*attrUId, QUuid::createUuid().toString()); + + QDomElement info = createElement(*tagInfo); + info.appendChild(createElement(*tagName)); + info.appendChild(createElement(*tagDescription)); + kmElement.appendChild(info); + + kmElement.appendChild(createElement(*tagDiagrams)); + kmElement.appendChild(createElement(*tagMeasurements)); + + appendChild(kmElement); + insertBefore( + createProcessingInstruction(QStringLiteral("xml"), QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"")), + firstChild()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::AddEmptyMeasurement(const QString &name) +{ + const QDomElement element = MakeEmptyMeasurement(name); + + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).appendChild(element); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::AddEmptyMeasurementAfter(const QString &after, const QString &name) +{ + const QDomElement element = MakeEmptyMeasurement(name); + const QDomElement sibling = FindM(after); + + const QDomNodeList list = elementsByTagName(*tagMeasurements); + + if (sibling.isNull()) + { + list.at(0).appendChild(element); + } + else + { + list.at(0).insertAfter(element, sibling); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::AddImage(const VPatternImage &image) +{ + const QDomElement element = MakeEmptyImage(image); + + const QDomNodeList list = elementsByTagName(*tagDiagrams); + list.at(0).appendChild(element); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::RemoveMeasurement(const QString &name) +{ + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).removeChild(FindM(name)); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::RemoveImage(const QUuid &id) +{ + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).removeChild(FindImage(id)); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::MoveTop(const QString &name) +{ + const QDomElement node = FindM(name); + if (node.isNull()) + { + return; + } + + const QDomNodeList mList = elementsByTagName(*tagMeasurement); + if (mList.size() >= 2) + { + const QDomNode top = mList.at(0); + if (not top.isNull()) + { + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).insertBefore(node, top); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::MoveUp(const QString &name) +{ + const QDomElement node = FindM(name); + if (node.isNull()) + { + return; + } + + const QDomElement prSibling = node.previousSiblingElement(*tagMeasurement); + if (not prSibling.isNull()) + { + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).insertBefore(node, prSibling); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::MoveDown(const QString &name) +{ + const QDomElement node = FindM(name); + if (node.isNull()) + { + return; + } + + const QDomElement nextSibling = node.nextSiblingElement(*tagMeasurement); + if (not nextSibling.isNull()) + { + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).insertAfter(node, nextSibling); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::MoveBottom(const QString &name) +{ + const QDomElement node = FindM(name); + if (node.isNull()) + { + return; + } + + const QDomNodeList mList = elementsByTagName(*tagMeasurement); + if (mList.size() >= 2) + { + const QDomNode bottom = mList.at(mList.size() - 1); + if (not bottom.isNull()) + { + const QDomNodeList list = elementsByTagName(*tagMeasurements); + list.at(0).insertAfter(node, bottom); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QUuid VKnownMeasurementsDocument::GetUId() const +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + const QDomElement rootElement = root.toElement(); + if (not rootElement.isNull()) + { + return QUuid(GetParametrEmptyString(rootElement, AttrKMVersion)); + } + } + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetUId(const QUuid &id) +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + QDomElement rootElement = root.toElement(); + if (not rootElement.isNull()) + { + SetAttribute(rootElement, *attrUId, id.toString()); + } + } + else + { + qDebug() << "Can't save known measurements uid " << Q_FUNC_INFO; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VKnownMeasurementsDocument::Name() const +{ + return UniqueTagText(*tagName, QString()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetName(const QString &name) +{ + setTagText(*tagName, name); +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VKnownMeasurementsDocument::Description() const +{ + return UniqueTagText(*tagDescription, QString()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetDescription(const QString &desc) +{ + setTagText(*tagDescription, desc); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VKnownMeasurementsDocument::IsReadOnly() const +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + const QDomElement rootElement = root.toElement(); + if (not rootElement.isNull()) + { + return GetParametrBool(rootElement, *attrReadOnly, falseStr); + } + } + return false; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetReadOnly(bool ro) +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + QDomElement rootElement = root.toElement(); + if (not rootElement.isNull()) + { + SetAttributeOrRemoveIf(rootElement, *attrReadOnly, ro, [](bool ro) noexcept { return not ro; }); + } + } + else + { + qDebug() << "Can't save known measurements read only status " << Q_FUNC_INFO; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDocument::KnownMeasurements() const -> VKnownMeasurements +{ + VKnownMeasurements known; + + known.SetUId(GetUId()); + known.SetName(Name()); + known.SetDescription(Description()); + known.SetReadOnly(IsReadOnly()); + + ReadImages(known); + ReadMeasurements(known); + + return known; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMName(const QString &name, const QString &text) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttribute(node, *attrName, text); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMFormula(const QString &name, const QString &text) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttribute(node, *attrFormula, text); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMSpecialUnits(const QString &name, bool special) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttributeOrRemoveIf(node, *attrSpecialUnits, special, + [](bool special) noexcept { return not special; }); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMDescription(const QString &name, const QString &text) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttributeOrRemoveIf(node, *attrDescription, text, + [](const QString &text) noexcept { return text.isEmpty(); }); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMFullName(const QString &name, const QString &text) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttribute(node, *attrFullName, text); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetMImage(const QString &name, const QUuid &imageId) +{ + QDomElement node = FindM(name); + if (not node.isNull()) + { + SetAttributeOrRemoveIf(node, *attrDiagram, imageId, + [](const QUuid &imageId) noexcept { return imageId.isNull(); }); + } + else + { + qWarning() << tr("Can't find measurement '%1'").arg(name); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetImageContent(const QUuid &id, const VPatternImage &image) +{ + QDomElement node = FindImage(id); + if (not node.isNull()) + { + setTagText(node, image.ContentData()); + node.setAttribute(*attrContentType, image.ContentType()); + } + else + { + qWarning() << tr("Can't find image by id '%1'").arg(id.toString()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::SetImageTitle(const QUuid &id, const QString &text) +{ + QDomElement node = FindImage(id); + if (not node.isNull()) + { + SetAttributeOrRemoveIf(node, *attrTitle, text, + [](const QString &text) noexcept { return text.isEmpty(); }); + } + else + { + qWarning() << tr("Can't find image by id '%1'").arg(id.toString()); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QDomElement VKnownMeasurementsDocument::MakeEmptyMeasurement(const QString &name) +{ + QDomElement element = createElement(*tagMeasurement); + SetAttribute(element, *attrName, name); + return element; +} + +//--------------------------------------------------------------------------------------------------------------------- +auto VKnownMeasurementsDocument::FindM(const QString &name) const -> QDomElement +{ + if (name.isEmpty()) + { + qWarning() << tr("The measurement name is empty!"); + return {}; + } + + QDomNodeList list = elementsByTagName(*tagMeasurement); + + for (int i = 0; i < list.size(); ++i) + { + const QDomElement domElement = list.at(i).toElement(); + if (domElement.isNull()) + { + continue; + } + + const QString parameter = domElement.attribute(*attrName); + if (parameter == name) + { + return domElement; + } + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +QDomElement VKnownMeasurementsDocument::MakeEmptyImage(const VPatternImage &image) +{ + QDomElement element = createElement(*tagImage); + + SetAttribute(element, *attrContentType, image.ContentType()); + SetAttribute(element, *attrUId, QUuid::createUuid().toString()); + SetAttributeOrRemoveIf(element, *attrTitle, image.Title(), + [](const QString &text) noexcept { return text.isEmpty(); }); + setTagText(element, image.ContentData()); + + return element; +} + +//--------------------------------------------------------------------------------------------------------------------- +QDomElement VKnownMeasurementsDocument::FindImage(const QUuid &id) const +{ + if (id.isNull()) + { + qWarning() << tr("The image id is empty!"); + return {}; + } + + QDomNodeList list = elementsByTagName(*tagImage); + + QString idString = id.toString(); + + for (int i = 0; i < list.size(); ++i) + { + const QDomElement domElement = list.at(i).toElement(); + if (domElement.isNull()) + { + continue; + } + + const QString parameter = domElement.attribute(*attrUId); + if (parameter == idString) + { + return domElement; + } + } + + return {}; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::ReadImages(VKnownMeasurements &known) const +{ + QDomNodeList list = elementsByTagName(*tagImage); + + for (int i = 0; i < list.size(); ++i) + { + const QDomElement domElement = list.at(i).toElement(); + if (domElement.isNull()) + { + continue; + } + + VPatternImage image; + image.SetContentData(domElement.text().toLatin1(), domElement.attribute(*attrContentType)); + image.SetTitle(domElement.attribute(*attrTitle)); + + known.AddImage(QUuid(domElement.attribute(*attrUId)), image); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VKnownMeasurementsDocument::ReadMeasurements(VKnownMeasurements &known) const +{ + QDomNodeList list = elementsByTagName(*tagMeasurement); + + for (int i = 0; i < list.size(); ++i) + { + const QDomElement domElement = list.at(i).toElement(); + if (domElement.isNull()) + { + continue; + } + + VKnownMeasurement m; + m.name = domElement.attribute(*attrName); + m.fullName = domElement.attribute(*attrFullName); + m.description = domElement.attribute(*attrDescription); + m.formula = domElement.attribute(*attrFormula); + m.specialUnits = GetParametrBool(domElement, *attrSpecialUnits, falseStr); + m.diagram = QUuid(GetParametrEmptyString(domElement, *attrDiagram)); + m.index = i; + + known.AddMeasurement(m); + } +} diff --git a/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.h b/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.h new file mode 100644 index 000000000..1f42fda4e --- /dev/null +++ b/src/libs/vformat/knownmeasurements/vknownmeasurementsdocument.h @@ -0,0 +1,98 @@ +/************************************************************************ + ** + ** @file vknownmeasurementsdocument.h + ** @author Roman Telezhynskyi + ** @date 27 10, 2023 + ** + ** @brief + ** @copyright + ** This source code is part of the Valentina project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2023 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ +#ifndef VKNOWNMEASUREMENTSDOCUMENT_H +#define VKNOWNMEASUREMENTSDOCUMENT_H + +#include "../ifc/xml/vdomdocument.h" + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif + +class VKnownMeasurements; +class VPatternImage; + +class VKnownMeasurementsDocument : public VDomDocument +{ + Q_OBJECT // NOLINT + +public: + explicit VKnownMeasurementsDocument(QObject *parent = nullptr); + ~VKnownMeasurementsDocument() override = default; + + auto SaveDocument(const QString &fileName, QString &error) -> bool override; + + void CreateEmptyFile(); + + void AddEmptyMeasurement(const QString &name); + void AddEmptyMeasurementAfter(const QString &after, const QString &name); + void AddImage(const VPatternImage &image); + void RemoveMeasurement(const QString &name); + void RemoveImage(const QUuid &id); + void MoveTop(const QString &name); + void MoveUp(const QString &name); + void MoveDown(const QString &name); + void MoveBottom(const QString &name); + + auto GetUId() const -> QUuid; + void SetUId(const QUuid &id); + + auto Name() const -> QString; + void SetName(const QString &name); + + auto Description() const -> QString; + void SetDescription(const QString &desc); + + auto IsReadOnly() const -> bool; + void SetReadOnly(bool ro); + + auto KnownMeasurements() const -> VKnownMeasurements; + + void SetMName(const QString &name, const QString &text); + void SetMFormula(const QString &name, const QString &text); + void SetMSpecialUnits(const QString &name, bool special); + void SetMDescription(const QString &name, const QString &text); + void SetMFullName(const QString &name, const QString &text); + void SetMImage(const QString &name, const QUuid &imageId); + + void SetImageContent(const QUuid &id, const VPatternImage &image); + void SetImageTitle(const QUuid &id, const QString &text); + +private: + Q_DISABLE_COPY_MOVE(VKnownMeasurementsDocument) // NOLINT + + auto MakeEmptyMeasurement(const QString &name) -> QDomElement; + auto FindM(const QString &name) const -> QDomElement; + auto MakeEmptyImage(const VPatternImage &image) -> QDomElement; + auto FindImage(const QUuid &id) const -> QDomElement; + + void ReadImages(VKnownMeasurements &known) const; + void ReadMeasurements(VKnownMeasurements &known) const; +}; + +#endif // VKNOWNMEASUREMENTSDOCUMENT_H diff --git a/src/libs/vformat/vformat.pri b/src/libs/vformat/vformat.pri index 65077449f..3f9ec6036 100644 --- a/src/libs/vformat/vformat.pri +++ b/src/libs/vformat/vformat.pri @@ -7,7 +7,12 @@ SOURCES += \ $$PWD/vlabeltemplate.cpp \ $$PWD/vpatternrecipe.cpp \ $$PWD/vsinglelineoutlinechar.cpp \ - $$PWD/vwatermark.cpp + $$PWD/vwatermark.cpp \ + $$PWD/knownmeasurements/vknownmeasurements.cpp \ + $$PWD/knownmeasurements/vknownmeasurementsdocument.cpp \ + $$PWD/knownmeasurements/vknownmeasurementsdatabase.cpp + + *msvc*:SOURCES += $$PWD/stable.cpp @@ -18,4 +23,9 @@ HEADERS += \ $$PWD/vlabeltemplate.h \ $$PWD/vpatternrecipe.h \ $$PWD/vsinglelineoutlinechar.h \ - $$PWD/vwatermark.h + $$PWD/vwatermark.h \ + $$PWD/knownmeasurements/vknownmeasurement.h \ + $$PWD/knownmeasurements/vknownmeasurements.h \ + $$PWD/knownmeasurements/vknownmeasurements_p.h \ + $$PWD/knownmeasurements/vknownmeasurementsdocument.h \ + $$PWD/knownmeasurements/vknownmeasurementsdatabase.h diff --git a/src/libs/vformat/vformat.qbs b/src/libs/vformat/vformat.qbs index ddfb3315e..f163341c1 100644 --- a/src/libs/vformat/vformat.qbs +++ b/src/libs/vformat/vformat.qbs @@ -4,7 +4,15 @@ VLib { name: "VFormatLib" files: [ + "knownmeasurements/vknownmeasurement.h", + "knownmeasurements/vknownmeasurements.cpp", + "knownmeasurements/vknownmeasurements.h", + "knownmeasurements/vknownmeasurements_p.h", + "knownmeasurements/vknownmeasurementsdocument.cpp", + "knownmeasurements/vknownmeasurementsdocument.h", "vdimensions.cpp", + "knownmeasurements/vknownmeasurementsdatabase.cpp", + "knownmeasurements/vknownmeasurementsdatabase.h", "vmeasurements.cpp", "vlabeltemplate.cpp", "vpatternrecipe.cpp", diff --git a/src/libs/vformat/vmeasurements.cpp b/src/libs/vformat/vmeasurements.cpp index b462d5662..80914e52d 100644 --- a/src/libs/vformat/vmeasurements.cpp +++ b/src/libs/vformat/vmeasurements.cpp @@ -132,13 +132,18 @@ auto FileComment() -> QString } // namespace //--------------------------------------------------------------------------------------------------------------------- -VMeasurements::VMeasurements(VContainer *data) - : data(data), - type(MeasurementsType::Unknown){SCASSERT(data != nullptr)} +VMeasurements::VMeasurements(VContainer *data, QObject *parent) + : VDomDocument(parent), + data(data), + type(MeasurementsType::Unknown) +{ + SCASSERT(data != nullptr); +} - //--------------------------------------------------------------------------------------------------------------------- - VMeasurements::VMeasurements(Unit unit, VContainer * data) - : data(data), +//--------------------------------------------------------------------------------------------------------------------- +VMeasurements::VMeasurements(Unit unit, VContainer *data, QObject *parent) + : VDomDocument(parent), + data(data), type(MeasurementsType::Individual) { SCASSERT(data != nullptr) @@ -147,8 +152,10 @@ VMeasurements::VMeasurements(VContainer *data) } //--------------------------------------------------------------------------------------------------------------------- -VMeasurements::VMeasurements(Unit unit, const QVector &dimensions, VContainer *data) - : data(data), +VMeasurements::VMeasurements(Unit unit, const QVector &dimensions, VContainer *data, + QObject *parent) + : VDomDocument(parent), + data(data), type(MeasurementsType::Multisize) { SCASSERT(data != nullptr) @@ -249,17 +256,19 @@ void VMeasurements::Remove(const QString &name) void VMeasurements::MoveTop(const QString &name) { const QDomElement node = FindM(name); - if (not node.isNull()) + if (node.isNull()) { - const QDomNodeList mList = elementsByTagName(TagMeasurement); - if (mList.size() >= 2) + return; + } + + const QDomNodeList mList = elementsByTagName(TagMeasurement); + if (mList.size() >= 2) + { + const QDomNode top = mList.at(0); + if (not top.isNull()) { - const QDomNode top = mList.at(0); - if (not top.isNull()) - { - const QDomNodeList list = elementsByTagName(TagBodyMeasurements); - list.at(0).insertBefore(node, top); - } + const QDomNodeList list = elementsByTagName(TagBodyMeasurements); + list.at(0).insertBefore(node, top); } } } @@ -268,14 +277,16 @@ void VMeasurements::MoveTop(const QString &name) void VMeasurements::MoveUp(const QString &name) { const QDomElement node = FindM(name); - if (not node.isNull()) + if (node.isNull()) { - const QDomElement prSibling = node.previousSiblingElement(TagMeasurement); - if (not prSibling.isNull()) - { - const QDomNodeList list = elementsByTagName(TagBodyMeasurements); - list.at(0).insertBefore(node, prSibling); - } + return; + } + + const QDomElement prSibling = node.previousSiblingElement(TagMeasurement); + if (not prSibling.isNull()) + { + const QDomNodeList list = elementsByTagName(TagBodyMeasurements); + list.at(0).insertBefore(node, prSibling); } } @@ -283,14 +294,16 @@ void VMeasurements::MoveUp(const QString &name) void VMeasurements::MoveDown(const QString &name) { const QDomElement node = FindM(name); - if (not node.isNull()) + if (node.isNull()) { - const QDomElement nextSibling = node.nextSiblingElement(TagMeasurement); - if (not nextSibling.isNull()) - { - const QDomNodeList list = elementsByTagName(TagBodyMeasurements); - list.at(0).insertAfter(node, nextSibling); - } + return; + } + + const QDomElement nextSibling = node.nextSiblingElement(TagMeasurement); + if (not nextSibling.isNull()) + { + const QDomNodeList list = elementsByTagName(TagBodyMeasurements); + list.at(0).insertAfter(node, nextSibling); } } @@ -298,17 +311,19 @@ void VMeasurements::MoveDown(const QString &name) void VMeasurements::MoveBottom(const QString &name) { const QDomElement node = FindM(name); - if (not node.isNull()) + if (node.isNull()) { - const QDomNodeList mList = elementsByTagName(TagMeasurement); - if (mList.size() >= 2) + return; + } + + const QDomNodeList mList = elementsByTagName(TagMeasurement); + if (mList.size() >= 2) + { + const QDomNode bottom = mList.at(mList.size() - 1); + if (not bottom.isNull()) { - const QDomNode bottom = mList.at(mList.size() - 1); - if (not bottom.isNull()) - { - const QDomNodeList list = elementsByTagName(TagBodyMeasurements); - list.at(0).insertAfter(node, bottom); - } + const QDomNodeList list = elementsByTagName(TagBodyMeasurements); + list.at(0).insertAfter(node, bottom); } } } @@ -771,7 +786,8 @@ void VMeasurements::SetMDescription(const QString &name, const QString &text) QDomElement node = FindM(name); if (not node.isNull()) { - SetAttribute(node, AttrDescription, text); + SetAttributeOrRemoveIf(node, AttrDescription, text, + [](const QString &text) noexcept { return text.isEmpty(); }); } else { @@ -1276,7 +1292,7 @@ auto VMeasurements::FindM(const QString &name) const -> QDomElement if (name.isEmpty()) { qWarning() << tr("The measurement name is empty!"); - return QDomElement(); + return {}; } QDomNodeList list = elementsByTagName(TagMeasurement); @@ -1284,17 +1300,19 @@ auto VMeasurements::FindM(const QString &name) const -> QDomElement for (int i = 0; i < list.size(); ++i) { const QDomElement domElement = list.at(i).toElement(); - if (domElement.isNull() == false) + if (domElement.isNull()) { - const QString parameter = domElement.attribute(AttrName); - if (parameter == name) - { - return domElement; - } + continue; + } + + const QString parameter = domElement.attribute(AttrName); + if (parameter == name) + { + return domElement; } } - return QDomElement(); + return {}; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/libs/vformat/vmeasurements.h b/src/libs/vformat/vmeasurements.h index 2f27603e7..1cca94b98 100644 --- a/src/libs/vformat/vmeasurements.h +++ b/src/libs/vformat/vmeasurements.h @@ -39,6 +39,10 @@ #include "../vmisc/def.h" #include "vdimensions.h" +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +#include "../vmisc/defglobal.h" +#endif + class VContainer; class VPatternImage; class VMeasurement; @@ -57,9 +61,10 @@ class VMeasurements : public VDomDocument Q_OBJECT // NOLINT public: - explicit VMeasurements(VContainer *data); - VMeasurements(Unit unit, VContainer *data); - VMeasurements(Unit unit, const QVector &dimensions, VContainer *data); + explicit VMeasurements(VContainer *data, QObject *parent = nullptr); + VMeasurements(Unit unit, VContainer *data, QObject *parent = nullptr); + VMeasurements(Unit unit, const QVector &dimensions, VContainer *data, + QObject *parent = nullptr); ~VMeasurements() override = default; void setXMLContent(const QString &fileName) override;