From 9d38d0a2076da190df90757efdfc53efe4c68417 Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Sun, 22 Jul 2018 21:24:28 +0200 Subject: [PATCH] split generator in 2 --- .../cppsettingsgenerator.cpp | 231 +++++++++ .../settingsgenerator/cppsettingsgenerator.h | 33 ++ tools/settingsgenerator/main.cpp | 24 +- .../qmlsettingsgenerator.cpp | 74 +++ .../settingsgenerator/qmlsettingsgenerator.h | 25 + .../settingsgenerator/qsettingsgenerator.xsd | 1 + tools/settingsgenerator/settingsgenerator.cpp | 458 ------------------ tools/settingsgenerator/settingsgenerator.h | 53 -- tools/settingsgenerator/settingsgenerator.pro | 12 +- .../settingsgeneratorimpl.cpp | 225 +++++++++ .../settingsgenerator/settingsgeneratorimpl.h | 28 ++ 11 files changed, 642 insertions(+), 522 deletions(-) create mode 100644 tools/settingsgenerator/cppsettingsgenerator.cpp create mode 100644 tools/settingsgenerator/cppsettingsgenerator.h create mode 100644 tools/settingsgenerator/qmlsettingsgenerator.cpp create mode 100644 tools/settingsgenerator/qmlsettingsgenerator.h delete mode 100644 tools/settingsgenerator/settingsgenerator.cpp delete mode 100644 tools/settingsgenerator/settingsgenerator.h create mode 100644 tools/settingsgenerator/settingsgeneratorimpl.cpp create mode 100644 tools/settingsgenerator/settingsgeneratorimpl.h diff --git a/tools/settingsgenerator/cppsettingsgenerator.cpp b/tools/settingsgenerator/cppsettingsgenerator.cpp new file mode 100644 index 0000000..a3d0adf --- /dev/null +++ b/tools/settingsgenerator/cppsettingsgenerator.cpp @@ -0,0 +1,231 @@ +#include "cppsettingsgenerator.h" +#include + +#define TABS QString{QLatin1Char('\t')}.repeated(intendent) + +CppSettingsGenerator::CppSettingsGenerator(const QString &hdrPath, const QString &srcPath) : + _hdrFile{hdrPath}, + _srcFile{srcPath}, + _hdr{&_hdrFile}, + _src{&_srcFile} +{} + +void CppSettingsGenerator::process(const QString &inPath) +{ + // read settings and adjust defaults + auto settings = readDocument(inPath); + if(!settings.name) + settings.name = QFileInfo{inPath}.baseName(); + fixTrContext(settings, QFileInfo{inPath}.fileName()); + + if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) + throw FileException{_hdrFile}; + writeHeader(settings); + _hdrFile.close(); + + if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) + throw FileException{_srcFile}; + writeSource(settings); + _srcFile.close(); +} + +void CppSettingsGenerator::writeHeader(const SettingsType &settings) +{ + QString incGuard = QFileInfo{_hdrFile.fileName()} + .completeBaseName() + .replace(QLatin1Char('.'), QLatin1Char('_')) + .toUpper() + QStringLiteral("_H"); + _hdr << "#ifndef " << incGuard << '\n' + << "#define " << incGuard << "\n\n"; + + // write the includes + auto includes = QList { + {false, QStringLiteral("QtCore/QObject")}, + {false, QStringLiteral("QtMvvmCore/ISettingsAccessor")}, + {false, QStringLiteral("QtMvvmCore/SettingsEntry")} + } + settings.includes; + for(const auto &inc : includes) { + if(inc.local) + _hdr << "#include \"" << inc.includePath << "\"\n"; + else + _hdr << "#include <" << inc.includePath << ">\n"; + } + _hdr << "\n"; + + // create the class + _hdr << "class " << QString{settings.prefix ? settings.prefix.value() + QLatin1Char(' ') + settings.name.value() : settings.name.value()} << " : public QObject\n" + << "{\n" + << "\tQ_OBJECT\n\n" + << "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n" + << "public:\n" + << "\tQ_INVOKABLE explicit " << settings.name.value() << "(QObject *parent = nullptr);\n" + << "\texplicit " << settings.name.value() << "(QtMvvm::ISettingsAccessor *accessor, QObject *parent);\n\n" + << "\tstatic " << settings.name.value() << " *instance();\n\n" + << "\tQtMvvm::ISettingsAccessor *accessor() const;\n\n"; + + writeNodeElementDeclarations(settings, settings.typeMappings); + + _hdr << "\nprivate:\n" + << "\tQtMvvm::ISettingsAccessor *_accessor;\n" + << "};\n\n" + << "#endif //" << incGuard << '\n'; +} + +void CppSettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent) +{ + for(const auto &cNode : node.contentNodes) { + if(nonstd::holds_alternative(cNode)) + writeNodeDeclaration(nonstd::get(cNode), typeMappings, intendent); + else if(nonstd::holds_alternative(cNode)) + writeEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); + else if(nonstd::holds_alternative(cNode)) + writeListEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); + else if(nonstd::holds_alternative(cNode)) + writeNodeElementDeclarations(nonstd::get(cNode), typeMappings, intendent); + } +} + +void CppSettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent) +{ + _hdr << TABS << "struct { //" << node.key << "\n"; + writeNodeElementDeclarations(node, typeMappings, intendent + 1); + _hdr << TABS << "} " << node.key << ";\n"; +} + +void CppSettingsGenerator::writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent) +{ + if(entry.contentNodes.isEmpty()) + _hdr << TABS << "QtMvvm::SettingsEntry<" << typeMappings.value(entry.type, entry.type) << "> " << entry.key << ";\n"; + else { + const auto &mType = typeMappings.value(entry.type, entry.type); + _hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n"; + writeNodeElementDeclarations(entry, typeMappings, intendent + 1); + _hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n"; + _hdr << TABS << "} " << entry.key << ";\n"; + } +} + +void CppSettingsGenerator::writeListEntryDeclaration(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, int intendent) +{ + if(entry.contentNodes.isEmpty()) + _hdr << TABS << "QtMvvm::SettingsEntry> " << entry.key << ";\n"; + else { + const QString mType = QStringLiteral("QList<") + typeMappings.value(entry.type, entry.type) + QLatin1Char('>'); + _hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n"; + writeNodeElementDeclarations(entry, typeMappings, intendent + 1); + _hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n"; + _hdr << TABS << "\tinline auto &operator+=(const " << typeMappings.value(entry.type, entry.type) << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n"; + _hdr << TABS << "\tinline auto &operator+=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n"; + _hdr << TABS << "} " << entry.key << ";\n"; + } +} + +void CppSettingsGenerator::writeSource(const SettingsType &settings) +{ + _src << "#include \"" << _hdrFile.fileName() << "\"\n"; + _src << "#include \n"; + _src << "#include \n"; + if(!settings.backend) + _src << "#include \n"; + _src << "\n"; + + auto backend = settings.backend.value_or(BackendType{QStringLiteral("QtMvvm::QSettingsAccessor"), {}, {}}); + + _src << "namespace {\n\n" + << "void __generated_settings_setup()\n" + << "{\n" + << "\tQtMvvm::ServiceRegistry::instance()->registerObject<" << settings.name.value() << ">("; + if(backend.scope) + _src << "QtMvvm::ServiceRegistry::" << backend.scope.value(); + _src << ");\n" + << "}\n\n" + << "}\n" + << "Q_COREAPP_STARTUP_FUNCTION(__generated_settings_setup)\n\n"; + + _src << settings.name.value() << "::" << settings.name.value() << "(QObject *parent) : \n" + << "\t" << settings.name.value() << "{new " << backend.className << "{"; + if(!backend.param.isEmpty()) { + _src << "\n"; + auto first = true; + for(const auto ¶m : qAsConst(backend.param)) { + if(first) + first = false; + else + _src << ",\n"; + _src << "\t\tQVariant{"; + if(param.asStr) + _src << "QStringLiteral(\"" << param.value << "\")"; + else + _src << param.value; + _src << "}.value<" << param.type << ">()"; + } + _src << "\n\t"; + } + _src << "}, parent}\n" + << "{\n" + << "\t_accessor->setParent(this);\n" + << "}\n\n"; + + _src << settings.name.value() << "::" << settings.name.value() << "(QtMvvm::ISettingsAccessor *accessor, QObject *parent) : \n" + << "\tQObject{parent},\n" + << "\t_accessor{accessor}\n" + << "{\n"; + writeNodeElementDefinitions(settings, settings.typeMappings, settings.baseKey); + _src << "}\n\n"; + + _src << settings.name.value() << " *" << settings.name.value() << "::instance()\n" + << "{\n" + << "\treturn QtMvvm::ServiceRegistry::instance()->service<" << settings.name.value() << ">();\n" + << "}\n\n"; + + _src << "QtMvvm::ISettingsAccessor *" << settings.name.value() << "::accessor() const\n" + << "{\n" + << "\treturn _accessor;\n" + << "}\n\n"; +} + +void CppSettingsGenerator::writeNodeElementDefinitions(const SettingsGeneratorBase::NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain) +{ + for(const auto &cNode : node.contentNodes) { + if(nonstd::holds_alternative(cNode)) { + const auto &xNode = nonstd::get(cNode); + writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key); + } else if(nonstd::holds_alternative(cNode)) + writeEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); + else if(nonstd::holds_alternative(cNode)) + writeListEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); + else if(nonstd::holds_alternative(cNode)) + writeNodeElementDefinitions(nonstd::get(cNode), typeMappings, baseKey, keyChain); + } +} + +void CppSettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren) +{ + keyChain.append(entry.key); + _src << "\t" << keyChain.join(QLatin1Char('.')) + << ".setup(QStringLiteral(\"" << (baseKey ? QStringList{baseKey.value()} + keyChain : keyChain).join(QLatin1Char('/')) << "\"), _accessor"; + if(entry.code) + _src << ", QVariant::fromValue<" << typeMappings.value(entry.type, entry.type) << ">(" << entry.code.value().trimmed() << ")"; + else if(entry.defaultValue) { + _src << ", QVariant{"; + if(entry.tr) + _src << "QCoreApplication::translate(\"" << entry.trContext.value() << "\", \"" << entry.defaultValue.value() << "\")"; + else + _src << "QStringLiteral(\"" << entry.defaultValue.value() << "\")"; + _src << "}.value<" << typeMappings.value(entry.type, entry.type) << ">()"; + } + _src << ");\n"; + if(!skipChildren) + writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); +} + +void CppSettingsGenerator::writeListEntryDefinition(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain) +{ + writeEntryDefinition(entry, typeMappings, baseKey, keyChain, entry.init.has_value()); + if(entry.init) { + keyChain.append(entry.key); + _src << "\t" << keyChain.join(QLatin1Char('.')) << ".setupInit(" << entry.init.value().trimmed() << ");\n"; + writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); + } +} + diff --git a/tools/settingsgenerator/cppsettingsgenerator.h b/tools/settingsgenerator/cppsettingsgenerator.h new file mode 100644 index 0000000..9e39e8b --- /dev/null +++ b/tools/settingsgenerator/cppsettingsgenerator.h @@ -0,0 +1,33 @@ +#ifndef CPPSETTINGSGENERATOR_H +#define CPPSETTINGSGENERATOR_H + +#include "settingsgeneratorimpl.h" + +class CppSettingsGenerator : public SettingsGeneratorImpl +{ +public: + CppSettingsGenerator(const QString &hdrPath, + const QString &srcPath); + + void process(const QString &inPath); + +private: + QFile _hdrFile; + QFile _srcFile; + + QTextStream _hdr; + QTextStream _src; + + void writeHeader(const SettingsType &settings); + void writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent = 1); + void writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent = 1); + void writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent = 1); + void writeListEntryDeclaration(const ListEntryType &entry, const QHash &typeMappings, int intendent = 1); + + void writeSource(const SettingsType &settings); + void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain = {}); + void writeEntryDefinition(const EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren = false); + void writeListEntryDefinition(const ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain); +}; + +#endif // CPPSETTINGSGENERATOR_H diff --git a/tools/settingsgenerator/main.cpp b/tools/settingsgenerator/main.cpp index 37ec030..e0d45ea 100644 --- a/tools/settingsgenerator/main.cpp +++ b/tools/settingsgenerator/main.cpp @@ -4,7 +4,8 @@ #include #include -#include "settingsgenerator.h" +#include "cppsettingsgenerator.h" +#include "qmlsettingsgenerator.h" #include "settingstranslator.h" int main(int argc, char *argv[]) @@ -57,18 +58,27 @@ int main(int argc, char *argv[]) qCritical() << e.what(); return EXIT_FAILURE; } + } else if(parser.isSet(QStringLiteral("qml"))) { + try { + QmlSettingsGenerator generator { + parser.value(QStringLiteral("header")), + parser.value(QStringLiteral("impl")) + }; + generator.process(parser.value(QStringLiteral("in"))); + return EXIT_SUCCESS; + } catch (SettingsGeneratorImpl::Exception &e) { + qCritical() << e.what(); + return EXIT_FAILURE; + } } else { try { - SettingsGenerator generator { + CppSettingsGenerator generator { parser.value(QStringLiteral("header")), parser.value(QStringLiteral("impl")) }; - if(parser.isSet(QStringLiteral("qml"))) - generator.processQml(parser.value(QStringLiteral("in"))); - else - generator.process(parser.value(QStringLiteral("in"))); + generator.process(parser.value(QStringLiteral("in"))); return EXIT_SUCCESS; - } catch (SettingsGenerator::Exception &e) { + } catch (SettingsGeneratorImpl::Exception &e) { qCritical() << e.what(); return EXIT_FAILURE; } diff --git a/tools/settingsgenerator/qmlsettingsgenerator.cpp b/tools/settingsgenerator/qmlsettingsgenerator.cpp new file mode 100644 index 0000000..bd973eb --- /dev/null +++ b/tools/settingsgenerator/qmlsettingsgenerator.cpp @@ -0,0 +1,74 @@ +#include "qmlsettingsgenerator.h" +#include + +QmlSettingsGenerator::QmlSettingsGenerator(const QString &hdrPath, const QString &srcPath) : + _hdrFile{hdrPath}, + _srcFile{srcPath}, + _hdr{&_hdrFile}, + _src{&_srcFile} +{} + +void QmlSettingsGenerator::process(const QString &inPath) +{ + // read settings and adjust defaults + auto settings = readDocument(inPath); + if(!settings.name) + settings.name = QFileInfo{inPath}.baseName(); + settings.name.value().prepend(QStringLiteral("QMLTYPE_")); + fixTrContext(settings, QFileInfo{inPath}.fileName()); + + if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) + throw FileException{_hdrFile}; + writeHeader(settings); + _hdrFile.close(); + + if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) + throw FileException{_srcFile}; + writeSource(settings); + _srcFile.close(); +} + +void QmlSettingsGenerator::writeHeader(const SettingsGeneratorBase::SettingsType &settings) +{ + QString incGuard = QFileInfo{_hdrFile.fileName()} + .completeBaseName() + .replace(QLatin1Char('.'), QLatin1Char('_')) + .toUpper() + QStringLiteral("_H"); + _hdr << "#ifndef " << incGuard << '\n' + << "#define " << incGuard << "\n\n"; + + // write the includes + auto includes = QList { + {false, QStringLiteral("QtCore/QObject")}, + {false, QStringLiteral("QtQml/QQmlListProperty")}, + {false, QStringLiteral("QtMvvmCore/ISettingsAccessor")} + } + settings.includes; + for(const auto &inc : includes) { + if(inc.local) + _hdr << "#include \"" << inc.includePath << "\"\n"; + else + _hdr << "#include <" << inc.includePath << ">\n"; + } + _hdr << "\n"; + + // create the class + _hdr << "class " << QString{settings.prefix ? settings.prefix.value() + QLatin1Char(' ') + settings.name.value() : settings.name.value()} << " : public QObject\n" + << "{\n" + << "\tQ_OBJECT\n\n" + << "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n" + << "public:\n" + << "\texplicit " << settings.name.value() << "(QObject *parent = nullptr);\n" + << "\tQtMvvm::ISettingsAccessor *accessor() const;\n\n"; + + + + _hdr << "\nprivate:\n" + << "\tQtMvvm::ISettingsAccessor *_accessor;\n" + << "};\n\n" + << "#endif //" << incGuard << '\n'; +} + +void QmlSettingsGenerator::writeSource(const SettingsGeneratorBase::SettingsType &settings) +{ + +} diff --git a/tools/settingsgenerator/qmlsettingsgenerator.h b/tools/settingsgenerator/qmlsettingsgenerator.h new file mode 100644 index 0000000..15dae40 --- /dev/null +++ b/tools/settingsgenerator/qmlsettingsgenerator.h @@ -0,0 +1,25 @@ +#ifndef QMLSETTINGSGENERATOR_H +#define QMLSETTINGSGENERATOR_H + +#include "settingsgeneratorimpl.h" + +class QmlSettingsGenerator : public SettingsGeneratorImpl +{ +public: + QmlSettingsGenerator(const QString &hdrPath, + const QString &srcPath); + + void process(const QString &inPath); + + void writeHeader(const SettingsType &settings); + void writeSource(const SettingsType &settings); + +private: + QFile _hdrFile; + QFile _srcFile; + + QTextStream _hdr; + QTextStream _src; +}; + +#endif // QMLSETTINGSGENERATOR_H diff --git a/tools/settingsgenerator/qsettingsgenerator.xsd b/tools/settingsgenerator/qsettingsgenerator.xsd index 147a1d4..e638652 100644 --- a/tools/settingsgenerator/qsettingsgenerator.xsd +++ b/tools/settingsgenerator/qsettingsgenerator.xsd @@ -93,6 +93,7 @@ + diff --git a/tools/settingsgenerator/settingsgenerator.cpp b/tools/settingsgenerator/settingsgenerator.cpp deleted file mode 100644 index 0d315d5..0000000 --- a/tools/settingsgenerator/settingsgenerator.cpp +++ /dev/null @@ -1,458 +0,0 @@ -#include "settingsgenerator.h" -#include -#include -#include - -#define TABS QString{QLatin1Char('\t')}.repeated(intendent) - -SettingsGenerator::SettingsGenerator(const QString &hdrPath, const QString &srcPath) : - _hdrFile{hdrPath}, - _srcFile{srcPath}, - _hdr{&_hdrFile}, - _src{&_srcFile} -{} - -void SettingsGenerator::process(const QString &inPath) -{ - // read settings and adjust defaults - auto settings = readDocument(inPath); - if(!settings.name) - settings.name = QFileInfo{inPath}.baseName(); - fixTrContext(settings, QFileInfo{inPath}.fileName()); - - if(!_hdrFile.open(QIODevice::WriteOnly | QIODevice::Text)) - throw FileException{_hdrFile}; - writeHeader(settings); - _hdrFile.close(); - - if(!_srcFile.open(QIODevice::WriteOnly | QIODevice::Text)) - throw FileException{_srcFile}; - writeSource(settings); - _srcFile.close(); -} - -void SettingsGenerator::processQml(const QString &inPath) -{ - -} - -bool SettingsGenerator::read_type_mapping(QXmlStreamReader &reader, QHash &data, bool hasNext) -{ - TypeMappingGroup grp; - hasNext = read_TypeMappingGroup(reader, grp, hasNext); - for(const auto &mapping : qAsConst(grp.typeMapping)) - data.insert(mapping.key, mapping.type); - return hasNext; -} - -void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContentGroup &data) -{ - ImportType import; - read_ImportType(reader, import); - - //make the path relative if possbile - if(dynamic_cast(reader.device())) { - QFileInfo docInfo{static_cast(reader.device())->fileName()}; - import.importPath = docInfo.dir().absoluteFilePath(import.importPath); - } - - // read the document - try { - QFile xmlFile{import.importPath}; - if(!xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) - throw FileException{xmlFile}; - - QXmlStreamReader subReader{&xmlFile}; - if(!subReader.readNextStartElement()) - throw XmlException{subReader}; - - SettingsType settings; - if(subReader.name() == QStringLiteral("Settings")) { - read_SettingsType(subReader, settings); - } else if(subReader.name() == QStringLiteral("SettingsConfig")) { - SettingsConfigImpl confReader; - SettingsConfigBase::SettingsConfigType settingsConf; - confReader.read_SettingsConfigType(subReader, settingsConf); - convertFromConf(reader, settingsConf, settings); - } else - throwChild(subReader); - - NodeContentGroup *cGrp = &settings; - if(import.rootNode) { - for(const auto &key : import.rootNode.value().split(QLatin1Char('/'), QString::SkipEmptyParts)) { - cGrp = findContentGroup(cGrp, key); - if(!cGrp) - return; - } - } - - data = std::move(*cGrp); - fixTrContext(data, QFileInfo{import.importPath}.fileName()); - } catch(FileException &e) { - if(import.required) - throw; - else { - qWarning() << e.what(); - return; - } - } -} - -void SettingsGenerator::convertFromConf(QXmlStreamReader &reader, SettingsConfigBase::SettingsConfigType &conf, SettingsType &data) -{ - for(auto &element : conf.content) { - if(nonstd::holds_alternative(element)) - readCategory(reader, nonstd::get(element), data); - else if(nonstd::holds_alternative(element)) - readSection(reader, nonstd::get(element), data); - else if(nonstd::holds_alternative(element)) - readGroup(reader, nonstd::get(element), data); - else if(nonstd::holds_alternative(element)) - readEntry(reader, nonstd::get(element), data); - else - throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf")}; - } -} - -void SettingsGenerator::readCategory(QXmlStreamReader &reader, SettingsConfigBase::CategoryContentGroup &content, NodeContentGroup &targetRootNode) -{ - for(auto &element : content.content) { - if(nonstd::holds_alternative(element)) - readSection(reader, nonstd::get(element), targetRootNode); - else if(nonstd::holds_alternative(element)) - readGroup(reader, nonstd::get(element), targetRootNode); - else if(nonstd::holds_alternative(element)) - readEntry(reader, nonstd::get(element), targetRootNode); - else - throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Categoy")}; - } -} - -void SettingsGenerator::readSection(QXmlStreamReader &reader, SettingsConfigBase::SectionContentGroup &content, NodeContentGroup &targetRootNode) -{ - for(auto &element : content.content) { - if(nonstd::holds_alternative(element)) - readGroup(reader, nonstd::get(element), targetRootNode); - else if(nonstd::holds_alternative(element)) - readEntry(reader, nonstd::get(element), targetRootNode); - else - throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Section")}; - } -} - -void SettingsGenerator::readGroup(QXmlStreamReader &reader, SettingsConfigBase::GroupContentGroup &content, NodeContentGroup &targetRootNode) -{ - for(auto &element : content.content) { - if(nonstd::holds_alternative(element)) - readEntry(reader, nonstd::get(element), targetRootNode); - else - throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Group")}; - } -} - -void SettingsGenerator::readEntry(QXmlStreamReader &reader, SettingsConfigBase::EntryType &entry, NodeContentGroup &targetRootNode) -{ - auto keyChain = entry.key.split(QLatin1Char('/'), QString::SkipEmptyParts); - auto entryKey = keyChain.takeLast(); - - auto cGrp = &targetRootNode; - for(const auto &key : keyChain) { - auto nGrp = findContentGroup(cGrp, key); - if(!nGrp) { - NodeType nNode; - nNode.key = key; - cGrp->contentNodes.append(std::move(nNode)); - nGrp = &(nonstd::get(cGrp->contentNodes.last())); - } - cGrp = nGrp; - } - - auto isEntry = false; - auto eGrp = findContentGroup(cGrp, entryKey, &isEntry); - if(!eGrp) { - EntryType nEntry; - nEntry.key = entryKey; - cGrp->contentNodes.append(std::move(nEntry)); - eGrp = &(nonstd::get(cGrp->contentNodes.last())); - } else if(!isEntry) { - EntryType nEntry; - nEntry.key = entryKey; - nEntry.contentNodes = std::move(eGrp->contentNodes); - eGrp = replaceNodeByEntry(cGrp, eGrp, nEntry); - Q_ASSERT(eGrp); - } else - throw XmlException{reader, QStringLiteral("Found duplicated entry with key: %1").arg(entry.key)}; - - auto nEntry = static_cast(eGrp); - nEntry->type = std::move(entry.type); - nEntry->defaultValue = std::move(entry.defaultValue); - nEntry->tr = entry.trdefault; -} - -SettingsGeneratorBase::NodeContentGroup *SettingsGenerator::findContentGroup(SettingsGeneratorBase::NodeContentGroup *cGrp, const QString &key, bool *isEntry) -{ - if(isEntry) - *isEntry = false; - for(auto &cNode : cGrp->contentNodes) { - if(nonstd::holds_alternative(cNode)) { - if(nonstd::get(cNode).key == key) - return &(nonstd::get(cNode)); - } else if(nonstd::holds_alternative(cNode)) { - if(nonstd::get(cNode).key == key) { - if(isEntry) - *isEntry = true; - return &(nonstd::get(cNode)); - } - } else if(nonstd::holds_alternative(cNode)) { - if(nonstd::get(cNode).key == key) { - if(isEntry) - *isEntry = true; - return &(nonstd::get(cNode)); - } - } else if(nonstd::holds_alternative(cNode)) { - auto res = findContentGroup(&(nonstd::get(cNode)), key); - if(res) - return res; - } - } - - return nullptr; -} - -SettingsGeneratorBase::NodeContentGroup *SettingsGenerator::replaceNodeByEntry(SettingsGeneratorBase::NodeContentGroup *cGrp, NodeContentGroup *node, SettingsGeneratorBase::EntryType &entry) -{ - for(auto &cNode : cGrp->contentNodes) { - if(nonstd::holds_alternative(cNode)) { - if(&nonstd::get(cNode) == node) { - cNode = std::move(entry); - return &(nonstd::get(cNode)); - } - } else if(nonstd::holds_alternative(cNode)) { - auto res = replaceNodeByEntry(&(nonstd::get(cNode)), node, entry); - if(res) - return res; - } - } - - return nullptr; -} - -void SettingsGenerator::fixTrContext(NodeContentGroup &group, const QString &context) -{ - for(auto &node : group.contentNodes) { - if(nonstd::holds_alternative(node)) - fixTrContext(nonstd::get(node), context); - else if(nonstd::holds_alternative(node)) { - auto &entry = nonstd::get(node); - if(!entry.trContext) - entry.trContext = context; - fixTrContext(entry, context); - } else if(nonstd::holds_alternative(node)) { - auto &entry = nonstd::get(node); - if(!entry.trContext) - entry.trContext = context; - fixTrContext(entry, context); - } else if(nonstd::holds_alternative(node)) - fixTrContext(nonstd::get(node), context); - } -} - -void SettingsGenerator::writeHeader(const SettingsType &settings) -{ - QString incGuard = QFileInfo{_hdrFile.fileName()} - .completeBaseName() - .replace(QLatin1Char('.'), QLatin1Char('_')) - .toUpper() + QStringLiteral("_H"); - _hdr << "#ifndef " << incGuard << '\n' - << "#define " << incGuard << "\n\n"; - - // write the includes - auto includes = QList { - {false, QStringLiteral("QtCore/QObject")}, - {false, QStringLiteral("QtMvvmCore/ISettingsAccessor")}, - {false, QStringLiteral("QtMvvmCore/SettingsEntry")} - } + settings.includes; - for(const auto &inc : includes) { - if(inc.local) - _hdr << "#include \"" << inc.includePath << "\"\n"; - else - _hdr << "#include <" << inc.includePath << ">\n"; - } - _hdr << "\n"; - - // create the class - _hdr << "class " << QString{settings.prefix ? settings.prefix.value() + QLatin1Char(' ') + settings.name.value() : settings.name.value()} << " : public QObject\n" - << "{\n" - << "\tQ_OBJECT\n\n" - << "\tQ_PROPERTY(QtMvvm::ISettingsAccessor *accessor READ accessor CONSTANT FINAL)\n\n" - << "public:\n" - << "\tQ_INVOKABLE explicit " << settings.name.value() << "(QObject *parent = nullptr);\n" - << "\texplicit " << settings.name.value() << "(QtMvvm::ISettingsAccessor *accessor, QObject *parent);\n\n" - << "\tstatic " << settings.name.value() << " *instance();\n\n" - << "\tQtMvvm::ISettingsAccessor *accessor() const;\n\n"; - - writeNodeElementDeclarations(settings, settings.typeMappings); - - _hdr << "\nprivate:\n" - << "\tQtMvvm::ISettingsAccessor *_accessor;\n" - << "};\n\n" - << "#endif //" << incGuard << '\n'; -} - -void SettingsGenerator::writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent) -{ - for(const auto &cNode : node.contentNodes) { - if(nonstd::holds_alternative(cNode)) - writeNodeDeclaration(nonstd::get(cNode), typeMappings, intendent); - else if(nonstd::holds_alternative(cNode)) - writeEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); - else if(nonstd::holds_alternative(cNode)) - writeListEntryDeclaration(nonstd::get(cNode), typeMappings, intendent); - else if(nonstd::holds_alternative(cNode)) - writeNodeElementDeclarations(nonstd::get(cNode), typeMappings, intendent); - } -} - -void SettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent) -{ - _hdr << TABS << "struct { //" << node.key << "\n"; - writeNodeElementDeclarations(node, typeMappings, intendent + 1); - _hdr << TABS << "} " << node.key << ";\n"; -} - -void SettingsGenerator::writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent) -{ - if(entry.contentNodes.isEmpty()) - _hdr << TABS << "QtMvvm::SettingsEntry<" << typeMappings.value(entry.type, entry.type) << "> " << entry.key << ";\n"; - else { - const auto &mType = typeMappings.value(entry.type, entry.type); - _hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n"; - writeNodeElementDeclarations(entry, typeMappings, intendent + 1); - _hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n"; - _hdr << TABS << "} " << entry.key << ";\n"; - } -} - -void SettingsGenerator::writeListEntryDeclaration(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, int intendent) -{ - if(entry.contentNodes.isEmpty()) - _hdr << TABS << "QtMvvm::SettingsEntry> " << entry.key << ";\n"; - else { - const QString mType = QStringLiteral("QList<") + typeMappings.value(entry.type, entry.type) + QLatin1Char('>'); - _hdr << TABS << "struct : QtMvvm::SettingsEntry<" << mType << "> { //" << entry.key << "\n"; - writeNodeElementDeclarations(entry, typeMappings, intendent + 1); - _hdr << TABS << "\tinline auto &operator=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator=(__value); return *this; }\n"; - _hdr << TABS << "\tinline auto &operator+=(const " << typeMappings.value(entry.type, entry.type) << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n"; - _hdr << TABS << "\tinline auto &operator+=(const " << mType << " &__value) { SettingsEntry<" << mType << ">::operator+=(__value); return *this; }\n"; - _hdr << TABS << "} " << entry.key << ";\n"; - } -} - -void SettingsGenerator::writeSource(const SettingsType &settings) -{ - _src << "#include \"" << _hdrFile.fileName() << "\"\n"; - _src << "#include \n"; - _src << "#include \n"; - if(!settings.backend) - _src << "#include \n"; - _src << "\n"; - - auto backend = settings.backend.value_or(BackendType{QStringLiteral("QtMvvm::QSettingsAccessor"), {}, {}}); - - _src << "namespace {\n\n" - << "void __generated_settings_setup()\n" - << "{\n" - << "\tQtMvvm::ServiceRegistry::instance()->registerObject<" << settings.name.value() << ">("; - if(backend.scope) - _src << "QtMvvm::ServiceRegistry::" << backend.scope.value(); - _src << ");\n" - << "}\n\n" - << "}\n" - << "Q_COREAPP_STARTUP_FUNCTION(__generated_settings_setup)\n\n"; - - _src << settings.name.value() << "::" << settings.name.value() << "(QObject *parent) : \n" - << "\t" << settings.name.value() << "{new " << backend.className << "{"; - if(!backend.param.isEmpty()) { - _src << "\n"; - auto first = true; - for(const auto ¶m : qAsConst(backend.param)) { - if(first) - first = false; - else - _src << ",\n"; - _src << "\t\tQVariant{"; - if(param.asStr) - _src << "QStringLiteral(\"" << param.value << "\")"; - else - _src << param.value; - _src << "}.value<" << param.type << ">()"; - } - _src << "\n\t"; - } - _src << "}, parent}\n" - << "{\n" - << "\t_accessor->setParent(this);\n" - << "}\n\n"; - - _src << settings.name.value() << "::" << settings.name.value() << "(QtMvvm::ISettingsAccessor *accessor, QObject *parent) : \n" - << "\tQObject{parent},\n" - << "\t_accessor{accessor}\n" - << "{\n"; - writeNodeElementDefinitions(settings, settings.typeMappings, settings.baseKey); - _src << "}\n\n"; - - _src << settings.name.value() << " *" << settings.name.value() << "::instance()\n" - << "{\n" - << "\treturn QtMvvm::ServiceRegistry::instance()->service<" << settings.name.value() << ">();\n" - << "}\n\n"; - - _src << "QtMvvm::ISettingsAccessor *" << settings.name.value() << "::accessor() const\n" - << "{\n" - << "\treturn _accessor;\n" - << "}\n\n"; -} - -void SettingsGenerator::writeNodeElementDefinitions(const SettingsGeneratorBase::NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain) -{ - for(const auto &cNode : node.contentNodes) { - if(nonstd::holds_alternative(cNode)) { - const auto &xNode = nonstd::get(cNode); - writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key); - } else if(nonstd::holds_alternative(cNode)) - writeEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); - else if(nonstd::holds_alternative(cNode)) - writeListEntryDefinition(nonstd::get(cNode), typeMappings, baseKey, keyChain); - else if(nonstd::holds_alternative(cNode)) - writeNodeElementDefinitions(nonstd::get(cNode), typeMappings, baseKey, keyChain); - } -} - -void SettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren) -{ - keyChain.append(entry.key); - _src << "\t" << keyChain.join(QLatin1Char('.')) - << ".setup(QStringLiteral(\"" << (baseKey ? QStringList{baseKey.value()} + keyChain : keyChain).join(QLatin1Char('/')) << "\"), _accessor"; - if(entry.code) - _src << ", QVariant::fromValue<" << typeMappings.value(entry.type, entry.type) << ">(" << entry.code.value().trimmed() << ")"; - else if(entry.defaultValue) { - _src << ", QVariant{"; - if(entry.tr) - _src << "QCoreApplication::translate(\"" << entry.trContext.value() << "\", \"" << entry.defaultValue.value() << "\")"; - else - _src << "QStringLiteral(\"" << entry.defaultValue.value() << "\")"; - _src << "}.value<" << typeMappings.value(entry.type, entry.type) << ">()"; - } - _src << ");\n"; - if(!skipChildren) - writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); -} - -void SettingsGenerator::writeListEntryDefinition(const SettingsGeneratorBase::ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain) -{ - writeEntryDefinition(entry, typeMappings, baseKey, keyChain, entry.init.has_value()); - if(entry.init) { - keyChain.append(entry.key); - _src << "\t" << keyChain.join(QLatin1Char('.')) << ".setupInit(" << entry.init.value().trimmed() << ");\n"; - writeNodeElementDefinitions(entry, typeMappings, baseKey, keyChain); - } -} diff --git a/tools/settingsgenerator/settingsgenerator.h b/tools/settingsgenerator/settingsgenerator.h deleted file mode 100644 index dcd0fcc..0000000 --- a/tools/settingsgenerator/settingsgenerator.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef SETTINGSGENERATOR_H -#define SETTINGSGENERATOR_H - -#include -#include - -#include "qsettingsgenerator.h" -#include "settingsconfigimpl.h" - -class SettingsGenerator : public SettingsGeneratorBase -{ -public: - SettingsGenerator(const QString &hdrPath, - const QString &srcPath); - - void process(const QString &inPath); - void processQml(const QString &inPath); - -protected: - bool read_type_mapping(QXmlStreamReader &reader, QHash &data, bool hasNext) override; - void read_included_file(QXmlStreamReader &reader, NodeContentGroup &data) override; - -private: - QFile _hdrFile; - QFile _srcFile; - - QTextStream _hdr; - QTextStream _src; - - void convertFromConf(QXmlStreamReader &reader, SettingsConfigBase::SettingsConfigType &conf, SettingsType &data); - void readCategory(QXmlStreamReader &reader, SettingsConfigBase::CategoryContentGroup &content, NodeContentGroup &targetRootNode); - void readSection(QXmlStreamReader &reader, SettingsConfigBase::SectionContentGroup &content, NodeContentGroup &targetRootNode); - void readGroup(QXmlStreamReader &reader, SettingsConfigBase::GroupContentGroup &content, NodeContentGroup &targetRootNode); - void readEntry(QXmlStreamReader &reader, SettingsConfigBase::EntryType &entry, NodeContentGroup &targetRootNode); - - NodeContentGroup *findContentGroup(NodeContentGroup *cGrp, const QString &key, bool *isEntry = nullptr); - NodeContentGroup *replaceNodeByEntry(NodeContentGroup *cGrp, NodeContentGroup *node, EntryType &entry); - - void fixTrContext(NodeContentGroup &group, const QString &context); - - void writeHeader(const SettingsType &settings); - void writeNodeElementDeclarations(const NodeContentGroup &node, const QHash &typeMappings, int intendent = 1); - void writeNodeDeclaration(const NodeType &node, const QHash &typeMappings, int intendent = 1); - void writeEntryDeclaration(const EntryType &entry, const QHash &typeMappings, int intendent = 1); - void writeListEntryDeclaration(const ListEntryType &entry, const QHash &typeMappings, int intendent = 1); - - void writeSource(const SettingsType &settings); - void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash &typeMappings, const optional &baseKey, const QStringList &keyChain = {}); - void writeEntryDefinition(const EntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain, bool skipChildren = false); - void writeListEntryDefinition(const ListEntryType &entry, const QHash &typeMappings, const optional &baseKey, QStringList keyChain); -}; - -#endif // SETTINGSGENERATOR_H diff --git a/tools/settingsgenerator/settingsgenerator.pro b/tools/settingsgenerator/settingsgenerator.pro index 4dafe7e..5d5f41c 100644 --- a/tools/settingsgenerator/settingsgenerator.pro +++ b/tools/settingsgenerator/settingsgenerator.pro @@ -15,15 +15,19 @@ DEFINES += "COMPANY=\\\"$$COMPANY\\\"" DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\"" HEADERS += \ - settingsgenerator.h \ settingstranslator.h \ - settingsconfigimpl.h + settingsconfigimpl.h \ + cppsettingsgenerator.h \ + settingsgeneratorimpl.h \ + qmlsettingsgenerator.h SOURCES += \ main.cpp \ - settingsgenerator.cpp \ settingstranslator.cpp \ - settingsconfigimpl.cpp + settingsconfigimpl.cpp \ + cppsettingsgenerator.cpp \ + settingsgeneratorimpl.cpp \ + qmlsettingsgenerator.cpp XML_SCHEMA_DEFINITIONS += \ qsettingsgenerator.xsd \ diff --git a/tools/settingsgenerator/settingsgeneratorimpl.cpp b/tools/settingsgenerator/settingsgeneratorimpl.cpp new file mode 100644 index 0000000..d5f1b5b --- /dev/null +++ b/tools/settingsgenerator/settingsgeneratorimpl.cpp @@ -0,0 +1,225 @@ +#include "settingsgeneratorimpl.h" +#include +#include +#include + +bool SettingsGeneratorImpl::read_type_mapping(QXmlStreamReader &reader, QHash &data, bool hasNext) +{ + TypeMappingGroup grp; + hasNext = read_TypeMappingGroup(reader, grp, hasNext); + for(const auto &mapping : qAsConst(grp.typeMapping)) + data.insert(mapping.key, mapping.type); + return hasNext; +} + +void SettingsGeneratorImpl::read_included_file(QXmlStreamReader &reader, NodeContentGroup &data) +{ + ImportType import; + read_ImportType(reader, import); + + //make the path relative if possbile + if(dynamic_cast(reader.device())) { + QFileInfo docInfo{static_cast(reader.device())->fileName()}; + import.importPath = docInfo.dir().absoluteFilePath(import.importPath); + } + + // read the document + try { + QFile xmlFile{import.importPath}; + if(!xmlFile.open(QIODevice::ReadOnly | QIODevice::Text)) + throw FileException{xmlFile}; + + QXmlStreamReader subReader{&xmlFile}; + if(!subReader.readNextStartElement()) + throw XmlException{subReader}; + + SettingsType settings; + if(subReader.name() == QStringLiteral("Settings")) { + read_SettingsType(subReader, settings); + } else if(subReader.name() == QStringLiteral("SettingsConfig")) { + SettingsConfigImpl confReader; + SettingsConfigBase::SettingsConfigType settingsConf; + confReader.read_SettingsConfigType(subReader, settingsConf); + convertFromConf(reader, settingsConf, settings); + } else + throwChild(subReader); + + NodeContentGroup *cGrp = &settings; + if(import.rootNode) { + for(const auto &key : import.rootNode.value().split(QLatin1Char('/'), QString::SkipEmptyParts)) { + cGrp = findContentGroup(cGrp, key); + if(!cGrp) + return; + } + } + + data = std::move(*cGrp); + fixTrContext(data, QFileInfo{import.importPath}.fileName()); + } catch(FileException &e) { + if(import.required) + throw; + else { + qWarning() << e.what(); + return; + } + } +} + +void SettingsGeneratorImpl::convertFromConf(QXmlStreamReader &reader, SettingsConfigBase::SettingsConfigType &conf, SettingsType &data) +{ + for(auto &element : conf.content) { + if(nonstd::holds_alternative(element)) + readCategory(reader, nonstd::get(element), data); + else if(nonstd::holds_alternative(element)) + readSection(reader, nonstd::get(element), data); + else if(nonstd::holds_alternative(element)) + readGroup(reader, nonstd::get(element), data); + else if(nonstd::holds_alternative(element)) + readEntry(reader, nonstd::get(element), data); + else + throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf")}; + } +} + +void SettingsGeneratorImpl::readCategory(QXmlStreamReader &reader, SettingsConfigBase::CategoryContentGroup &content, NodeContentGroup &targetRootNode) +{ + for(auto &element : content.content) { + if(nonstd::holds_alternative(element)) + readSection(reader, nonstd::get(element), targetRootNode); + else if(nonstd::holds_alternative(element)) + readGroup(reader, nonstd::get(element), targetRootNode); + else if(nonstd::holds_alternative(element)) + readEntry(reader, nonstd::get(element), targetRootNode); + else + throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Categoy")}; + } +} + +void SettingsGeneratorImpl::readSection(QXmlStreamReader &reader, SettingsConfigBase::SectionContentGroup &content, NodeContentGroup &targetRootNode) +{ + for(auto &element : content.content) { + if(nonstd::holds_alternative(element)) + readGroup(reader, nonstd::get(element), targetRootNode); + else if(nonstd::holds_alternative(element)) + readEntry(reader, nonstd::get(element), targetRootNode); + else + throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Section")}; + } +} + +void SettingsGeneratorImpl::readGroup(QXmlStreamReader &reader, SettingsConfigBase::GroupContentGroup &content, NodeContentGroup &targetRootNode) +{ + for(auto &element : content.content) { + if(nonstd::holds_alternative(element)) + readEntry(reader, nonstd::get(element), targetRootNode); + else + throw XmlException{reader, QStringLiteral("Unexpected child element in included SettingsConf Group")}; + } +} + +void SettingsGeneratorImpl::readEntry(QXmlStreamReader &reader, SettingsConfigBase::EntryType &entry, NodeContentGroup &targetRootNode) +{ + auto keyChain = entry.key.split(QLatin1Char('/'), QString::SkipEmptyParts); + auto entryKey = keyChain.takeLast(); + + auto cGrp = &targetRootNode; + for(const auto &key : keyChain) { + auto nGrp = findContentGroup(cGrp, key); + if(!nGrp) { + NodeType nNode; + nNode.key = key; + cGrp->contentNodes.append(std::move(nNode)); + nGrp = &(nonstd::get(cGrp->contentNodes.last())); + } + cGrp = nGrp; + } + + auto isEntry = false; + auto eGrp = findContentGroup(cGrp, entryKey, &isEntry); + if(!eGrp) { + EntryType nEntry; + nEntry.key = entryKey; + cGrp->contentNodes.append(std::move(nEntry)); + eGrp = &(nonstd::get(cGrp->contentNodes.last())); + } else if(!isEntry) { + EntryType nEntry; + nEntry.key = entryKey; + nEntry.contentNodes = std::move(eGrp->contentNodes); + eGrp = replaceNodeByEntry(cGrp, eGrp, nEntry); + Q_ASSERT(eGrp); + } else + throw XmlException{reader, QStringLiteral("Found duplicated entry with key: %1").arg(entry.key)}; + + auto nEntry = static_cast(eGrp); + nEntry->type = std::move(entry.type); + nEntry->defaultValue = std::move(entry.defaultValue); + nEntry->tr = entry.trdefault; +} + +SettingsGeneratorBase::NodeContentGroup *SettingsGeneratorImpl::findContentGroup(SettingsGeneratorBase::NodeContentGroup *cGrp, const QString &key, bool *isEntry) +{ + if(isEntry) + *isEntry = false; + for(auto &cNode : cGrp->contentNodes) { + if(nonstd::holds_alternative(cNode)) { + if(nonstd::get(cNode).key == key) + return &(nonstd::get(cNode)); + } else if(nonstd::holds_alternative(cNode)) { + if(nonstd::get(cNode).key == key) { + if(isEntry) + *isEntry = true; + return &(nonstd::get(cNode)); + } + } else if(nonstd::holds_alternative(cNode)) { + if(nonstd::get(cNode).key == key) { + if(isEntry) + *isEntry = true; + return &(nonstd::get(cNode)); + } + } else if(nonstd::holds_alternative(cNode)) { + auto res = findContentGroup(&(nonstd::get(cNode)), key); + if(res) + return res; + } + } + + return nullptr; +} + +SettingsGeneratorBase::NodeContentGroup *SettingsGeneratorImpl::replaceNodeByEntry(SettingsGeneratorBase::NodeContentGroup *cGrp, NodeContentGroup *node, SettingsGeneratorBase::EntryType &entry) +{ + for(auto &cNode : cGrp->contentNodes) { + if(nonstd::holds_alternative(cNode)) { + if(&nonstd::get(cNode) == node) { + cNode = std::move(entry); + return &(nonstd::get(cNode)); + } + } else if(nonstd::holds_alternative(cNode)) { + auto res = replaceNodeByEntry(&(nonstd::get(cNode)), node, entry); + if(res) + return res; + } + } + + return nullptr; +} + +void SettingsGeneratorImpl::fixTrContext(NodeContentGroup &group, const QString &context) +{ + for(auto &node : group.contentNodes) { + if(nonstd::holds_alternative(node)) + fixTrContext(nonstd::get(node), context); + else if(nonstd::holds_alternative(node)) { + auto &entry = nonstd::get(node); + if(!entry.trContext) + entry.trContext = context; + fixTrContext(entry, context); + } else if(nonstd::holds_alternative(node)) { + auto &entry = nonstd::get(node); + if(!entry.trContext) + entry.trContext = context; + fixTrContext(entry, context); + } else if(nonstd::holds_alternative(node)) + fixTrContext(nonstd::get(node), context); + } +} diff --git a/tools/settingsgenerator/settingsgeneratorimpl.h b/tools/settingsgenerator/settingsgeneratorimpl.h new file mode 100644 index 0000000..c347eba --- /dev/null +++ b/tools/settingsgenerator/settingsgeneratorimpl.h @@ -0,0 +1,28 @@ +#ifndef SETTINGSGENERATOR_H +#define SETTINGSGENERATOR_H + +#include +#include + +#include "qsettingsgenerator.h" +#include "settingsconfigimpl.h" + +class SettingsGeneratorImpl : public SettingsGeneratorBase +{ +protected: + bool read_type_mapping(QXmlStreamReader &reader, QHash &data, bool hasNext) override; + void read_included_file(QXmlStreamReader &reader, NodeContentGroup &data) override; + + void convertFromConf(QXmlStreamReader &reader, SettingsConfigBase::SettingsConfigType &conf, SettingsType &data); + void readCategory(QXmlStreamReader &reader, SettingsConfigBase::CategoryContentGroup &content, NodeContentGroup &targetRootNode); + void readSection(QXmlStreamReader &reader, SettingsConfigBase::SectionContentGroup &content, NodeContentGroup &targetRootNode); + void readGroup(QXmlStreamReader &reader, SettingsConfigBase::GroupContentGroup &content, NodeContentGroup &targetRootNode); + void readEntry(QXmlStreamReader &reader, SettingsConfigBase::EntryType &entry, NodeContentGroup &targetRootNode); + + NodeContentGroup *findContentGroup(NodeContentGroup *cGrp, const QString &key, bool *isEntry = nullptr); + NodeContentGroup *replaceNodeByEntry(NodeContentGroup *cGrp, NodeContentGroup *node, EntryType &entry); + + void fixTrContext(NodeContentGroup &group, const QString &context); +}; + +#endif // SETTINGSGENERATOR_H