/*************************************************************************** * This file is part of the Lime Report project * * Copyright (C) 2021 by Alexander Arin * * arin_a@bk.ru * * * ** GNU General Public License Usage ** * * * This library 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. * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ** GNU Lesser General Public License ** * * * This library is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public * * License along with this library. * * If not, see . * * * * This library 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. * ****************************************************************************/ #include "lrxmlwriter.h" #include "lrbasedesignintf.h" #include "lrcollection.h" #include "lrreporttranslation.h" #include "serializators/lrxmlserializatorsfactory.h" #include namespace LimeReport { XMLWriter::XMLWriter(): m_doc(new QDomDocument) { init(); } XMLWriter::XMLWriter(QSharedPointer doc): m_doc(doc) { init(); } void XMLWriter::init() { m_rootElement = m_doc->createElement("Report"); QDomNode xmlNode = m_doc->createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF8\""); m_doc->insertBefore(xmlNode, m_doc->firstChild()); m_doc->appendChild(m_rootElement); } void XMLWriter::putItem(QObject* item) { QDomElement node = putQObjectItem(item->metaObject()->className(), item); if (!replaceNode(node, item)) m_rootElement.appendChild(node); } QString XMLWriter::extractClassName(QObject* item) { BaseDesignIntf* baseItem = dynamic_cast(item); if (baseItem) return baseItem->storageTypeName(); else return item->metaObject()->className(); } void XMLWriter::putChildQObjectItem(QString name, QObject* item, QDomElement* parentNode) { QDomElement itemNode = m_doc->createElement(name); itemNode.setAttribute("ClassName", extractClassName(item)); itemNode.setAttribute("Type", "Object"); if (parentNode) parentNode->appendChild(itemNode); saveProperties(item, &itemNode); } bool XMLWriter::setContent(QString fileName) { QFile xmlFile(fileName); if (xmlFile.open(QFile::ReadOnly)) { m_doc->setContent(&xmlFile); return true; } return false; } bool XMLWriter::saveToFile(QString fileName) { if ((m_doc->childNodes().count() == 0) || fileName.isEmpty()) return false; QFile xmlFile(fileName); if (xmlFile.open(QFile::WriteOnly)) { QTextStream buffer(&xmlFile); m_doc->save(buffer, 2); xmlFile.close(); return true; } return false; } QString XMLWriter::saveToString() { QString res; QTextStream buffer(&res); m_doc->save(buffer, 2); return res; } QByteArray XMLWriter::saveToByteArray() { QByteArray res; QTextStream buffer(&res); m_doc->save(buffer, 2); return res; } void XMLWriter::setPassPhrase(const QString& passPhrase) { m_passPhrase = passPhrase; } QDomElement XMLWriter::putQObjectItem(QString name, QObject* item) { Q_UNUSED(name) QDomElement itemNode = m_doc->createElement("object"); itemNode.setAttribute("ClassName", extractClassName(item)); itemNode.setAttribute("Type", "Object"); saveProperties(item, &itemNode); return itemNode; } void XMLWriter::saveProperty(QString name, QObject* item, QDomElement* node) { QString typeName; if (name.compare("itemIndexMethod") == 0) typeName = item->metaObject() ->property(item->metaObject()->indexOfProperty(name.toLatin1())) .typeName(); else typeName = item->property(name.toLatin1()).typeName(); CreateSerializator creator = 0; if (isCollection(name, item)) { saveCollection(name, item, node); return; } if (isTranslation(name, item)) { saveTranslation(name, item, node); return; } if (isQObject(name, item)) { if (qvariant_cast(item->property(name.toLatin1()))) putQObjectProperty(name, qvariant_cast(item->property(name.toLatin1())), node); else { qDebug() << "Warnig property can`t be casted to QObject" << name; } return; } if (enumOrFlag(name, item)) creator = XMLAbstractSerializatorFactory::instance().objectCreator("enumAndFlags"); else try { creator = XMLAbstractSerializatorFactory::instance().objectCreator(typeName); } catch (LimeReport::ReportError& exception) { qDebug() << "class name =" << item->metaObject()->className() << "property name=" << name << " property type=" << typeName << exception.what(); } if (creator) { QScopedPointer serializator(creator(m_doc.data(), node)); CryptedSerializator* cs = dynamic_cast(serializator.data()); if (cs) { cs->setPassPhrase(m_passPhrase); } serializator->save(item->property(name.toLatin1()), name); } } void XMLWriter::saveProperties(QObject* item, QDomElement* node) { for (int i = 0; i < item->metaObject()->propertyCount(); i++) { saveProperty(item->metaObject()->property(i).name(), item, node); } } bool XMLWriter::enumOrFlag(QString name, QObject* item) { return item->metaObject() ->property(item->metaObject()->indexOfProperty(name.toLatin1())) .isFlagType() || item->metaObject() ->property(item->metaObject()->indexOfProperty(name.toLatin1())) .isEnumType(); } bool XMLWriter::isCollection(QString propertyName, QObject* item) { QMetaProperty prop = item->metaObject()->property( item->metaObject()->indexOfProperty(propertyName.toLatin1())); // TODO: Migrate to QMetaType #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return QMetaType::fromName(prop.typeName()).id() == COLLECTION_TYPE_ID; #else return QMetaType::type(prop.typeName()) == COLLECTION_TYPE_ID; #endif } bool XMLWriter::isTranslation(QString propertyName, QObject* item) { QMetaProperty prop = item->metaObject()->property( item->metaObject()->indexOfProperty(propertyName.toLatin1())); // TODO: Migrate to QMetaType #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return QMetaType::fromName(prop.typeName()).id() == TRANSLATION_TYPE_ID; #else return QMetaType::type(prop.typeName()) == TRANSLATION_TYPE_ID; #endif } void XMLWriter::saveCollection(QString propertyName, QObject* item, QDomElement* node) { ICollectionContainer* collection = dynamic_cast(item); QDomElement collectionNode = m_doc->createElement(propertyName); collectionNode.setAttribute("Type", "Collection"); for (int i = 0; i < collection->elementsCount(propertyName); i++) { putCollectionItem(collection->elementAt(propertyName, i), &collectionNode); } node->appendChild(collectionNode); } void XMLWriter::saveTranslation(QString propertyName, QObject* item, QDomElement* node) { ITranslationContainer* translationsContainer = dynamic_cast(item); if (translationsContainer) { QDomElement translationsNode = m_doc->createElement(propertyName); translationsNode.setAttribute("Type", "Translation"); Translations* translations = translationsContainer->translations(); foreach (QLocale::Language language, translations->keys()) { QDomElement languageNode = m_doc->createElement(QLocale::languageToString(language).replace(' ', '_')); languageNode.setAttribute("Value", QString::number(language)); translationsNode.appendChild(languageNode); ReportTranslation* curTranslation = translations->value(language); foreach (PageTranslation* page, curTranslation->pagesTranslation()) { QDomElement pageNode = m_doc->createElement(page->pageName); languageNode.appendChild(pageNode); foreach (ItemTranslation* item, page->itemsTranslation) { QDomElement itemNode = m_doc->createElement(item->itemName); foreach (PropertyTranslation* property, item->propertyesTranslation) { if (property->sourceValue.compare(property->value) != 0) { QDomElement propertyNode = m_doc->createElement(property->propertyName); propertyNode.setAttribute("Value", property->value); propertyNode.setAttribute("SourceValue", property->sourceValue); propertyNode.setAttribute("Checked", property->checked ? "Y" : "N"); itemNode.appendChild(propertyNode); } } if (!itemNode.childNodes().isEmpty()) pageNode.appendChild(itemNode); } } } node->appendChild(translationsNode); } } bool XMLWriter::isQObject(QString propertyName, QObject* item) { QMetaProperty prop = item->metaObject()->property( item->metaObject()->indexOfProperty(propertyName.toLatin1())); // TODO: Migrate to QMetaType #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return QMetaType::fromName(prop.typeName()).id() == QMetaType::QObjectStar; #else return QMetaType::type(prop.typeName()) == QMetaType::QObjectStar; #endif } bool XMLWriter::replaceNode(QDomElement node, QObject* item) { QDomElement element = m_rootElement.firstChildElement(item->metaObject()->className()); while (!element.isNull()) { QDomElement objectName = element.firstChildElement(QLatin1String("objectName")); if (!objectName.isNull() && (objectName.text() == item->objectName())) { QDomElement removeElement = element; element = element.nextSiblingElement(item->metaObject()->className()); m_rootElement.replaceChild(node, removeElement); return true; } else element = element.nextSiblingElement(item->metaObject()->className()); } return false; } void XMLWriter::putCollectionItem(QObject* item, QDomElement* parentNode) { putChildQObjectItem("item", item, parentNode); } void XMLWriter::putQObjectProperty(QString propertyName, QObject* item, QDomElement* parentNode) { putChildQObjectItem(propertyName, item, parentNode); } } // namespace LimeReport