Browse Source

implemented xml imports, ready for first tests

pull/2/head
Skycoder42 7 years ago
parent
commit
2596f8280f
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 145
      src/mvvmcore/settings.xsd
  2. 2
      tools/settingsgenerator/qpmx.json
  3. 1
      tools/settingsgenerator/qsettingsgenerator.qrc
  4. 144
      tools/settingsgenerator/settingsconfig.xsd
  5. 150
      tools/settingsgenerator/settingsgenerator.cpp
  6. 10
      tools/settingsgenerator/settingsgenerator.h
  7. 9
      tools/settingsgenerator/settingsgenerator.pro
  8. 108
      tools/settingsgenerator/settingstranslator.cpp
  9. 21
      tools/settingsgenerator/settingstranslator.h

145
src/mvvmcore/settings.xsd

@ -1,145 +0,0 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Type definitions -->
<xs:complexType name="IncludeType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:boolean" name="optional" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="ElementType" mixed="true">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="PropertyType" name="Property"/>
<xs:element type="ElementType" name="Element"/>
</xs:choice>
</xs:sequence>
<xs:attribute type="xs:string" name="type" use="required"/>
<xs:attribute type="xs:boolean" name="tr" use="optional" default="false"/>
<xs:attribute type="xs:boolean" name="ztr" use="optional" default="false"/>
</xs:complexType>
<xs:complexType name="PropertyType" mixed="true">
<xs:complexContent>
<xs:extension base="ElementType">
<xs:attribute type="xs:string" name="key" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="EntryType">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="xs:string" name="SearchKey"/>
<xs:element type="PropertyType" name="Property"/>
</xs:choice>
</xs:sequence>
<xs:attribute type="xs:string" name="key" use="required"/>
<xs:attribute type="xs:string" name="type" use="required"/>
<xs:attribute type="xs:string" name="title" use="required"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="default" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
<xs:attribute type="xs:boolean" name="trdefault" use="optional" default="false"/>
<xs:attribute type="xs:boolean" name="ztrdefault" use="optional" default="false"/>
</xs:complexType>
<xs:complexType name="GroupType">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
<xs:attribute type="xs:string" name="title" use="required"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:complexType>
<xs:complexType name="SectionType">
<xs:choice>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="GroupType" name="Group"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:choice>
<xs:attribute type="xs:string" name="title" use="required"/>
<xs:attribute type="xs:string" name="icon" use="optional"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:complexType>
<xs:complexType name="CategoryType">
<xs:choice>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="SectionType" name="Section"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="GroupType" name="Group"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:choice>
<xs:attribute type="xs:string" name="title" use="required"/>
<xs:attribute type="xs:string" name="icon" use="optional"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:complexType>
<xs:complexType name="SettingsConfigType">
<xs:choice>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="CategoryType" name="Category"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="SectionType" name="Section"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="GroupType" name="Group"/>
</xs:choice>
</xs:sequence>
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:choice>
<xs:attribute type="xs:boolean" name="allowSearch" use="optional"/>
<xs:attribute type="xs:boolean" name="allowRestore" use="optional"/>
</xs:complexType>
<!-- root elements-->
<xs:element name="SettingsConfig" type="SettingsConfigType"/>
</xs:schema>

2
tools/settingsgenerator/qpmx.json

@ -3,7 +3,7 @@
{ {
"package": "de.skycoder42.qxmlcodegen", "package": "de.skycoder42.qxmlcodegen",
"provider": "qpm", "provider": "qpm",
"version": "1.0.0" "version": "1.1.0"
} }
], ],
"license": { "license": {

1
tools/settingsgenerator/qsettingsgenerator.qrc

@ -1,5 +1,6 @@
<RCC> <RCC>
<qresource prefix="/schemas"> <qresource prefix="/schemas">
<file>qsettingsgenerator.xsd</file> <file>qsettingsgenerator.xsd</file>
<file>settingsconfig.xsd</file>
</qresource> </qresource>
</RCC> </RCC>

144
tools/settingsgenerator/settingsconfig.xsd

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:qxg="https://skycoder42.de/xml/schemas/QXmlCodeGen">
<!-- QXG Definitions -->
<qxg:config class="SettingsConfigBase"
stdcompat="true"
schemaUrl="qrc:/schemas/settingsconfig.xsd"
visibility="public">
<qxg:include>QtCore/QHash</qxg:include>
</qxg:config>
<qxg:method name="finish_group_content" type="GroupContentGroup" asGroup="true"/>
<qxg:method name="finish_section_content" type="SectionContentGroup" asGroup="true"/>
<qxg:method name="finish_category_content" type="CategoryContentGroup" asGroup="true"/>
<qxg:method name="finish_settings_config_content" type="SettingsConfigContentGroup" asGroup="true"/>
<!-- Basic property-like elements definitions -->
<xs:complexType name="IncludeType">
<xs:simpleContent>
<xs:extension base="xs:string" qxg:member="includePath">
<xs:attribute type="xs:boolean" name="optional" default="false" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="ElementType" mixed="true" qxg:declare="true" qxg:member="content">
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" type="PropertyType" name="Property" qxg:member="properties"/>
<xs:element maxOccurs="unbounded" minOccurs="0" type="ElementType" name="Element" qxg:member="elements"/>
</xs:sequence>
<xs:attribute type="xs:string" name="type" use="required"/>
<xs:attribute type="xs:boolean" name="tr" use="optional" default="false"/>
<xs:attribute type="xs:boolean" name="ztr" use="optional" default="false"/>
</xs:complexType>
<xs:complexType name="PropertyType" qxg:declare="true">
<xs:complexContent>
<xs:extension base="ElementType">
<xs:attribute type="xs:string" name="key" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Group Definitions to build the elements from -->
<xs:attributeGroup name="BasicContainerInfo">
<xs:attribute type="xs:string" name="title" use="optional"/>
<xs:attribute type="xs:string" name="tooltip" use="optional"/>
<xs:attribute type="xs:string" name="frontends" use="optional"/>
<xs:attribute type="xs:string" name="selectors" use="optional"/>
</xs:attributeGroup>
<xs:attributeGroup name="ExtendedContainerInfo">
<xs:attributeGroup ref="BasicContainerInfo" qxg:inherit="true"/>
<xs:attribute type="xs:string" name="icon" use="optional"/>
</xs:attributeGroup>
<xs:group name="GroupContentGroup">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="content">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="SectionContentGroup">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="content">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="GroupType" name="Group"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="CategoryContentGroup">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="content">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="SectionType" name="Section"/>
<xs:element type="GroupType" name="Group"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="SettingsConfigContentGroup">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:member="content">
<xs:element type="IncludeType" name="Include"/>
<xs:element type="CategoryType" name="Category"/>
<xs:element type="SectionType" name="Section"/>
<xs:element type="GroupType" name="Group"/>
<xs:element type="EntryType" name="Entry"/>
</xs:choice>
</xs:sequence>
</xs:group>
<!-- Element definitions -->
<xs:complexType name="EntryType" qxg:declare="true">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0" qxg:unordered="true">
<xs:element type="xs:string" name="SearchKey" qxg:member="searchKeys"/>
<xs:element type="PropertyType" name="Property" qxg:member="properties"/>
</xs:choice>
</xs:sequence>
<xs:attributeGroup ref="BasicContainerInfo" qxg:inherit="true"/>
<xs:attribute type="xs:string" name="key" use="required"/>
<xs:attribute type="xs:string" name="type" use="required"/>
<xs:attribute type="xs:string" name="default" use="optional" qxg:member="defaultValue"/>
<xs:attribute type="xs:boolean" name="trdefault" use="optional" default="false"/>
</xs:complexType>
<xs:complexType name="GroupType" qxg:declare="true">
<xs:group ref="GroupContentGroup" qxg:inherit="true" qxg:method="finish_group_content"/>
<xs:attributeGroup ref="BasicContainerInfo" qxg:inherit="true"/>
</xs:complexType>
<xs:complexType name="SectionType" qxg:declare="true">
<xs:group ref="SectionContentGroup" qxg:inherit="true" qxg:method="finish_section_content"/>
<xs:attributeGroup ref="ExtendedContainerInfo" qxg:inherit="true"/>
</xs:complexType>
<xs:complexType name="CategoryType" qxg:declare="true">
<xs:group ref="CategoryContentGroup" qxg:inherit="true" qxg:method="finish_category_content"/>
<xs:attributeGroup ref="ExtendedContainerInfo" qxg:inherit="true"/>
</xs:complexType>
<xs:complexType name="SettingsConfigType" qxg:declare="true">
<xs:group ref="SettingsConfigContentGroup" qxg:inherit="true" qxg:method="finish_settings_config_content"/>
<xs:attribute type="xs:boolean" name="allowSearch" use="optional" default="true"/>
<xs:attribute type="xs:boolean" name="allowRestore" use="optional" default="true"/>
</xs:complexType>
<!-- root elements-->
<xs:element name="SettingsConfig" type="SettingsConfigType"/>
<xs:element name="Category" type="CategoryType"/>
<xs:element name="Section" type="SectionType"/>
<xs:element name="Group" type="GroupType"/>
<xs:element name="Entry" type="EntryType"/>
</xs:schema>

150
tools/settingsgenerator/settingsgenerator.cpp

@ -50,7 +50,25 @@ void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContent
// read the document // read the document
try { 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; NodeContentGroup *cGrp = &settings;
if(import.rootNode) { if(import.rootNode) {
for(const auto &key : import.rootNode.value().split(QLatin1Char('/'), QString::SkipEmptyParts)) { for(const auto &key : import.rootNode.value().split(QLatin1Char('/'), QString::SkipEmptyParts)) {
@ -59,8 +77,8 @@ void SettingsGenerator::read_included_file(QXmlStreamReader &reader, NodeContent
return; return;
} }
} }
data = *cGrp; data = std::move(*cGrp);
} catch(QException &e) { } catch(FileException &e) {
if(import.required) if(import.required)
throw; throw;
else { 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<SettingsConfigBase::CategoryType>(element))
readCategory(reader, nonstd::get<SettingsConfigBase::CategoryType>(element), data);
else if(nonstd::holds_alternative<SettingsConfigBase::SectionType>(element))
readSection(reader, nonstd::get<SettingsConfigBase::SectionType>(element), data);
else if(nonstd::holds_alternative<SettingsConfigBase::GroupType>(element))
readGroup(reader, nonstd::get<SettingsConfigBase::GroupType>(element), data);
else if(nonstd::holds_alternative<SettingsConfigBase::EntryType>(element))
readEntry(reader, nonstd::get<SettingsConfigBase::EntryType>(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<SettingsConfigBase::SectionType>(element))
readSection(reader, nonstd::get<SettingsConfigBase::SectionType>(element), targetRootNode);
else if(nonstd::holds_alternative<SettingsConfigBase::GroupType>(element))
readGroup(reader, nonstd::get<SettingsConfigBase::GroupType>(element), targetRootNode);
else if(nonstd::holds_alternative<SettingsConfigBase::EntryType>(element))
readEntry(reader, nonstd::get<SettingsConfigBase::EntryType>(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<SettingsConfigBase::GroupType>(element))
readGroup(reader, nonstd::get<SettingsConfigBase::GroupType>(element), targetRootNode);
else if(nonstd::holds_alternative<SettingsConfigBase::EntryType>(element))
readEntry(reader, nonstd::get<SettingsConfigBase::EntryType>(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<SettingsConfigBase::EntryType>(element))
readEntry(reader, nonstd::get<SettingsConfigBase::EntryType>(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<NodeType>(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<EntryType>(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<EntryType*>(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<NodeType>(cNode)) { if(nonstd::holds_alternative<NodeType>(cNode)) {
if(std::get<NodeType>(cNode).key == key) if(std::get<NodeType>(cNode).key == key)
return const_cast<NodeType*>(&(std::get<NodeType>(cNode))); return &(std::get<NodeType>(cNode));
} else if(nonstd::holds_alternative<EntryType>(cNode)) { } else if(nonstd::holds_alternative<EntryType>(cNode)) {
if(std::get<EntryType>(cNode).key == key) if(std::get<EntryType>(cNode).key == key) {
return const_cast<EntryType*>(&(std::get<EntryType>(cNode))); if(isEntry)
*isEntry = true;
return &(std::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = findContentGroup(&(std::get<NodeContentGroup>(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<NodeType>(cNode)) {
if(&std::get<NodeType>(cNode) == node) {
cNode = std::move(entry);
return &(std::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) { } else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = findContentGroup(const_cast<NodeContentGroup*>(&(std::get<NodeContentGroup>(cNode))), key); auto res = replaceNodeByEntry(&(std::get<NodeContentGroup>(cNode)), node, std::move(entry));
if(res) if(res)
return res; return res;
} }

10
tools/settingsgenerator/settingsgenerator.h

@ -5,6 +5,7 @@
#include <QTextStream> #include <QTextStream>
#include "qsettingsgenerator.h" #include "qsettingsgenerator.h"
#include "settingstranslator.h"
class SettingsGenerator : public SettingsGeneratorBase class SettingsGenerator : public SettingsGeneratorBase
{ {
@ -25,7 +26,14 @@ private:
QTextStream _hdr; QTextStream _hdr;
QTextStream _src; 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 writeHeader(const SettingsType &settings);
void writeNodeElements(const NodeContentGroup &node, int intendent = 1); void writeNodeElements(const NodeContentGroup &node, int intendent = 1);

9
tools/settingsgenerator/settingsgenerator.pro

@ -15,14 +15,17 @@ DEFINES += "COMPANY=\\\"$$COMPANY\\\""
DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\"" DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\""
HEADERS += \ HEADERS += \
settingsgenerator.h settingsgenerator.h \
settingstranslator.h
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
settingsgenerator.cpp settingsgenerator.cpp \
settingstranslator.cpp
XML_SCHEMA_DEFINITIONS += \ XML_SCHEMA_DEFINITIONS += \
qsettingsgenerator.xsd qsettingsgenerator.xsd \
settingsconfig.xsd
contains(QT, xmlpatterns):RESOURCES += qsettingsgenerator.qrc contains(QT, xmlpatterns):RESOURCES += qsettingsgenerator.qrc

108
tools/settingsgenerator/settingstranslator.cpp

@ -0,0 +1,108 @@
#include "settingstranslator.h"
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDebug>
namespace {
using SourceType = SettingsConfigBase::variant<SettingsConfigBase::SettingsConfigType, SettingsConfigBase::CategoryType, SettingsConfigBase::SectionType, SettingsConfigBase::GroupType, SettingsConfigBase::EntryType>;
template <typename TVariantTarget>
void convertElement(QXmlStreamReader &reader, TVariantTarget &, SourceType &&)
{
throw SettingsConfigBase::XmlException{reader, QStringLiteral("Unexpected root element in included file")};
}
template <typename TVariantTarget, typename TType, typename... TArgs>
void convertElement(QXmlStreamReader &reader, TVariantTarget &target, SourceType &&source)
{
if(nonstd::holds_alternative<TType>(source))
target = nonstd::get<TType>(std::move(source));
else
convertElement<TVariantTarget, TArgs...>(reader, target, std::move(source));
}
template <typename T>
struct VariantInfo {};
template <typename... TArgs>
struct VariantInfo<QList<SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>>>
{
using TargetType = SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>;
static void convert(QXmlStreamReader &reader, TargetType &target, SourceType &&source) {
convertElement<TargetType, TArgs...>(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<typename TGroup>
void SettingsTranslator::finishContents(QXmlStreamReader &reader, TGroup &group)
{
optional<std::size_t> index;
for(auto it = group.begin(); it != group.end();) {
// convert includes to the actual data
if(nonstd::holds_alternative<IncludeType>(*it)) {
if(!readGeneralInclude(reader, nonstd::get<IncludeType>(*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<typename TIter, typename TList>
bool SettingsTranslator::readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list)
{
try {
//make the path relative if possbile
if(dynamic_cast<QFileDevice*>(reader.device())) {
QFileInfo docInfo{static_cast<QFileDevice*>(reader.device())->fileName()};
include.includePath = docInfo.dir().absoluteFilePath(include.includePath);
}
// read the document
VariantInfo<TList>::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;
}
}

21
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 <typename TGroup>
void finishContents(QXmlStreamReader &reader, TGroup &group);
template <typename TIter, typename TList>
bool readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list);
};
#endif // SETTINGSTRANSLATOR_H
Loading…
Cancel
Save