diff --git a/src/mvvmcore/settings.xsd b/src/mvvmcore/settings.xsd
deleted file mode 100644
index 6e3bb0e..0000000
--- a/src/mvvmcore/settings.xsd
+++ /dev/null
@@ -1,145 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/settingsgenerator/qpmx.json b/tools/settingsgenerator/qpmx.json
index 5f052db..8de0c3d 100644
--- a/tools/settingsgenerator/qpmx.json
+++ b/tools/settingsgenerator/qpmx.json
@@ -3,7 +3,7 @@
{
"package": "de.skycoder42.qxmlcodegen",
"provider": "qpm",
- "version": "1.0.0"
+ "version": "1.1.0"
}
],
"license": {
diff --git a/tools/settingsgenerator/qsettingsgenerator.qrc b/tools/settingsgenerator/qsettingsgenerator.qrc
index c1b6869..b2a73cd 100644
--- a/tools/settingsgenerator/qsettingsgenerator.qrc
+++ b/tools/settingsgenerator/qsettingsgenerator.qrc
@@ -1,5 +1,6 @@
qsettingsgenerator.xsd
+ settingsconfig.xsd
diff --git a/tools/settingsgenerator/settingsconfig.xsd b/tools/settingsgenerator/settingsconfig.xsd
new file mode 100644
index 0000000..e65e245
--- /dev/null
+++ b/tools/settingsgenerator/settingsconfig.xsd
@@ -0,0 +1,144 @@
+
+
+
+
+ QtCore/QHash
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/settingsgenerator/settingsgenerator.cpp b/tools/settingsgenerator/settingsgenerator.cpp
index 9a1946e..f1c418f 100644
--- a/tools/settingsgenerator/settingsgenerator.cpp
+++ b/tools/settingsgenerator/settingsgenerator.cpp
@@ -50,7 +50,25 @@ void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContent
// read the document
try {
- auto settings = readDocument(import.importPath);
+ 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")) {
+ SettingsTranslator 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)) {
@@ -59,8 +77,8 @@ void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContent
return;
}
}
- data = *cGrp;
- } catch(QException &e) {
+ data = std::move(*cGrp);
+ } catch(FileException &e) {
if(import.required)
throw;
else {
@@ -70,17 +88,131 @@ void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContent
}
}
-SettingsGeneratorBase::NodeContentGroup *SettingsGenerator::findContentGroup(SettingsGeneratorBase::NodeContentGroup *cGrp, const QString &key)
+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 = &(std::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 = &(std::get(cGrp->contentNodes.last()));
+ } else if(!isEntry) {
+ EntryType nEntry;
+ nEntry.key = entryKey;
+ nEntry.contentNodes = std::move(eGrp->contentNodes);
+ eGrp = replaceNodeByEntry(cGrp, eGrp, std::move(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 = std::move(entry.trdefault);
+}
+
+SettingsGeneratorBase::NodeContentGroup *SettingsGenerator::findContentGroup(SettingsGeneratorBase::NodeContentGroup *cGrp, const QString &key, bool *isEntry)
{
- for(const auto &cNode : cGrp->contentNodes) {
+ if(isEntry)
+ *isEntry = false;
+ for(auto &cNode : cGrp->contentNodes) {
if(nonstd::holds_alternative(cNode)) {
if(std::get(cNode).key == key)
- return const_cast(&(std::get(cNode)));
+ return &(std::get(cNode));
} else if(nonstd::holds_alternative(cNode)) {
- if(std::get(cNode).key == key)
- return const_cast(&(std::get(cNode)));
+ if(std::get(cNode).key == key) {
+ if(isEntry)
+ *isEntry = true;
+ return &(std::get(cNode));
+ }
+ } else if(nonstd::holds_alternative(cNode)) {
+ auto res = findContentGroup(&(std::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(&std::get(cNode) == node) {
+ cNode = std::move(entry);
+ return &(std::get(cNode));
+ }
} else if(nonstd::holds_alternative(cNode)) {
- auto res = findContentGroup(const_cast(&(std::get(cNode))), key);
+ auto res = replaceNodeByEntry(&(std::get(cNode)), node, std::move(entry));
if(res)
return res;
}
diff --git a/tools/settingsgenerator/settingsgenerator.h b/tools/settingsgenerator/settingsgenerator.h
index 9d897b5..6a83354 100644
--- a/tools/settingsgenerator/settingsgenerator.h
+++ b/tools/settingsgenerator/settingsgenerator.h
@@ -5,6 +5,7 @@
#include
#include "qsettingsgenerator.h"
+#include "settingstranslator.h"
class SettingsGenerator : public SettingsGeneratorBase
{
@@ -25,7 +26,14 @@ private:
QTextStream _hdr;
QTextStream _src;
- NodeContentGroup *findContentGroup(NodeContentGroup *cGrp, const QString &key);
+ 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 writeHeader(const SettingsType &settings);
void writeNodeElements(const NodeContentGroup &node, int intendent = 1);
diff --git a/tools/settingsgenerator/settingsgenerator.pro b/tools/settingsgenerator/settingsgenerator.pro
index 15f6e77..513f000 100644
--- a/tools/settingsgenerator/settingsgenerator.pro
+++ b/tools/settingsgenerator/settingsgenerator.pro
@@ -15,14 +15,17 @@ DEFINES += "COMPANY=\\\"$$COMPANY\\\""
DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\""
HEADERS += \
- settingsgenerator.h
+ settingsgenerator.h \
+ settingstranslator.h
SOURCES += \
main.cpp \
- settingsgenerator.cpp
+ settingsgenerator.cpp \
+ settingstranslator.cpp
XML_SCHEMA_DEFINITIONS += \
- qsettingsgenerator.xsd
+ qsettingsgenerator.xsd \
+ settingsconfig.xsd
contains(QT, xmlpatterns):RESOURCES += qsettingsgenerator.qrc
diff --git a/tools/settingsgenerator/settingstranslator.cpp b/tools/settingsgenerator/settingstranslator.cpp
new file mode 100644
index 0000000..df63f4e
--- /dev/null
+++ b/tools/settingsgenerator/settingstranslator.cpp
@@ -0,0 +1,108 @@
+#include "settingstranslator.h"
+
+#include
+#include
+#include
+
+namespace {
+
+using SourceType = SettingsConfigBase::variant;
+
+template
+void convertElement(QXmlStreamReader &reader, TVariantTarget &, SourceType &&)
+{
+ throw SettingsConfigBase::XmlException{reader, QStringLiteral("Unexpected root element in included file")};
+}
+
+template
+void convertElement(QXmlStreamReader &reader, TVariantTarget &target, SourceType &&source)
+{
+ if(nonstd::holds_alternative(source))
+ target = nonstd::get(std::move(source));
+ else
+ convertElement(reader, target, std::move(source));
+}
+
+template
+struct VariantInfo {};
+
+template
+struct VariantInfo>>
+{
+ using TargetType = SettingsConfigBase::variant;
+ static void convert(QXmlStreamReader &reader, TargetType &target, SourceType &&source) {
+ convertElement(reader, target, std::move(source));
+ }
+};
+
+}
+
+bool SettingsTranslator::finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext)
+{
+ hasNext = read_GroupContentGroup(reader, data, hasNext);
+ finishContents(reader, data.content);
+ return hasNext;
+}
+
+bool SettingsTranslator::finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext)
+{
+ hasNext = read_SectionContentGroup(reader, data, hasNext);
+ finishContents(reader, data.content);
+ return hasNext;
+}
+
+bool SettingsTranslator::finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext)
+{
+ hasNext = read_CategoryContentGroup(reader, data, hasNext);
+ finishContents(reader, data.content);
+ return hasNext;
+}
+
+bool SettingsTranslator::finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext)
+{
+ hasNext = read_SettingsConfigContentGroup(reader, data, hasNext);
+ finishContents(reader, data.content);
+ return hasNext;
+}
+
+template
+void SettingsTranslator::finishContents(QXmlStreamReader &reader, TGroup &group)
+{
+ optional index;
+ for(auto it = group.begin(); it != group.end();) {
+ // convert includes to the actual data
+ if(nonstd::holds_alternative(*it)) {
+ if(!readGeneralInclude(reader, nonstd::get(*it), it, group))
+ continue;
+ }
+ // verify that the contents are all of the same type
+ if(index) {
+ if(index.value() != it->index())
+ throw XmlException{reader, QStringLiteral("Detected mixture of different child elements. Only includes and a single other type are allowed")};
+ } else
+ index = it->index();
+ ++it;
+ }
+}
+
+template
+bool SettingsTranslator::readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list)
+{
+ try {
+ //make the path relative if possbile
+ if(dynamic_cast(reader.device())) {
+ QFileInfo docInfo{static_cast(reader.device())->fileName()};
+ include.includePath = docInfo.dir().absoluteFilePath(include.includePath);
+ }
+ // read the document
+ VariantInfo::convert(reader, *it, readDocument(include.includePath));
+ return true;
+ } catch(FileException &e) {
+ if(include.optional) {
+ qWarning() << e.what();
+ it = list.erase(it);
+ return false;
+ } else
+ throw;
+ }
+}
diff --git a/tools/settingsgenerator/settingstranslator.h b/tools/settingsgenerator/settingstranslator.h
new file mode 100644
index 0000000..dd832ea
--- /dev/null
+++ b/tools/settingsgenerator/settingstranslator.h
@@ -0,0 +1,21 @@
+#ifndef SETTINGSTRANSLATOR_H
+#define SETTINGSTRANSLATOR_H
+
+#include "settingsconfig.h"
+
+class SettingsTranslator : public SettingsConfigBase
+{
+protected:
+ bool finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) override;
+ bool finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) override;
+ bool finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) override;
+ bool finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext) override;
+
+private:
+ template
+ void finishContents(QXmlStreamReader &reader, TGroup &group);
+ template
+ bool readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list);
+};
+
+#endif // SETTINGSTRANSLATOR_H