/************************************************************************ ** ** @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/ifcdef.h" #include "../ifc/xml/vknownmeasurementsconverter.h" #include "../ifc/xml/vpatternimage.h" #include "../vmisc/literals.h" #include "../vmisc/projectversion.h" #include "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, ("image"_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 Q_GLOBAL_STATIC_WITH_ARGS(const QString, attrGroup, ("group"_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(*tagDiagrams); list.at(0).removeChild(FindImage(id)); UpdateDiagramId(id, QUuid()); } //--------------------------------------------------------------------------------------------------------------------- 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); } } } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::GetUId() const -> QUuid { QDomNode root = documentElement(); if (not root.isNull() && root.isElement()) { const QDomElement rootElement = root.toElement(); if (not rootElement.isNull()) { return QUuid(GetParametrEmptyString(rootElement, *attrUId)); } } 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; } } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::Name() const -> QString { return UniqueTagText(*tagName, QString()); } //--------------------------------------------------------------------------------------------------------------------- void VKnownMeasurementsDocument::SetName(const QString &name) { setTagText(*tagName, name); } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::Description() const -> QString { return UniqueTagText(*tagDescription, QString()); } //--------------------------------------------------------------------------------------------------------------------- void VKnownMeasurementsDocument::SetDescription(const QString &desc) { setTagText(*tagDescription, desc); } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::IsReadOnly() const -> bool { 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::SetMGroup(const QString &name, const QString &text) { QDomElement node = FindM(name); if (not node.isNull()) { SetAttribute(node, *attrGroup, text); } else { qWarning() << tr("Can't find measurement '%1'").arg(name); } } //--------------------------------------------------------------------------------------------------------------------- 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()); } } //--------------------------------------------------------------------------------------------------------------------- void VKnownMeasurementsDocument::SetImageId(const QUuid &id, const QUuid &newId) { QDomElement node = FindImage(id); if (not node.isNull()) { SetAttribute(node, *attrUId, newId); UpdateDiagramId(id, newId); } else { qWarning() << tr("Can't find image by id '%1'").arg(id.toString()); } } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::MakeEmptyMeasurement(const QString &name) -> QDomElement { 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 {}; } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::MakeEmptyImage(const VPatternImage &image) -> QDomElement { 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; } //--------------------------------------------------------------------------------------------------------------------- auto VKnownMeasurementsDocument::FindImage(const QUuid &id) const -> QDomElement { 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; m.group = GetParametrEmptyString(domElement, *attrGroup); known.AddMeasurement(m); } } //--------------------------------------------------------------------------------------------------------------------- void VKnownMeasurementsDocument::UpdateDiagramId(const QUuid &oldId, const QUuid &newId) { QDomNodeList list = elementsByTagName(*tagMeasurement); for (int i = 0; i < list.size(); ++i) { QDomElement domElement = list.at(i).toElement(); if (domElement.isNull()) { continue; } if (QUuid(GetParametrEmptyString(domElement, *attrDiagram)) == oldId) { SetAttribute(domElement, *attrDiagram, newId); } } }