Browse Source

split generator in 2

pull/2/head
Skycoder42 7 years ago
parent
commit
9d38d0a207
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 231
      tools/settingsgenerator/cppsettingsgenerator.cpp
  2. 33
      tools/settingsgenerator/cppsettingsgenerator.h
  3. 24
      tools/settingsgenerator/main.cpp
  4. 74
      tools/settingsgenerator/qmlsettingsgenerator.cpp
  5. 25
      tools/settingsgenerator/qmlsettingsgenerator.h
  6. 1
      tools/settingsgenerator/qsettingsgenerator.xsd
  7. 458
      tools/settingsgenerator/settingsgenerator.cpp
  8. 53
      tools/settingsgenerator/settingsgenerator.h
  9. 12
      tools/settingsgenerator/settingsgenerator.pro
  10. 225
      tools/settingsgenerator/settingsgeneratorimpl.cpp
  11. 28
      tools/settingsgenerator/settingsgeneratorimpl.h

231
tools/settingsgenerator/cppsettingsgenerator.cpp

@ -0,0 +1,231 @@
#include "cppsettingsgenerator.h"
#include <QFileInfo>
#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<IncludeType> {
{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<QString, QString> &typeMappings, int intendent)
{
for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode))
writeNodeDeclaration(nonstd::get<NodeType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDeclaration(nonstd::get<EntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDeclaration(nonstd::get<ListEntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), typeMappings, intendent);
}
}
void CppSettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &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<QString, QString> &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<QString, QString> &typeMappings, int intendent)
{
if(entry.contentNodes.isEmpty())
_hdr << TABS << "QtMvvm::SettingsEntry<QList<" << typeMappings.value(entry.type, entry.type) << ">> " << 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 <QtCore/QCoreApplication>\n";
_src << "#include <QtMvvmCore/ServiceRegistry>\n";
if(!settings.backend)
_src << "#include <QtMvvmCore/QSettingsAccessor>\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 &param : 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<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain)
{
for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode)) {
const auto &xNode = nonstd::get<NodeType>(cNode);
writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key);
} else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDefinition(nonstd::get<EntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDefinition(nonstd::get<ListEntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), typeMappings, baseKey, keyChain);
}
}
void CppSettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &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<QString, QString> &typeMappings, const optional<QString> &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);
}
}

33
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<QString, QString> &typeMappings, int intendent = 1);
void writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeEntryDeclaration(const EntryType &entry, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeListEntryDeclaration(const ListEntryType &entry, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeSource(const SettingsType &settings);
void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain = {});
void writeEntryDefinition(const EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain, bool skipChildren = false);
void writeListEntryDefinition(const ListEntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain);
};
#endif // CPPSETTINGSGENERATOR_H

24
tools/settingsgenerator/main.cpp

@ -4,7 +4,8 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QDebug> #include <QDebug>
#include "settingsgenerator.h" #include "cppsettingsgenerator.h"
#include "qmlsettingsgenerator.h"
#include "settingstranslator.h" #include "settingstranslator.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -57,18 +58,27 @@ int main(int argc, char *argv[])
qCritical() << e.what(); qCritical() << e.what();
return EXIT_FAILURE; 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 { } else {
try { try {
SettingsGenerator generator { CppSettingsGenerator generator {
parser.value(QStringLiteral("header")), parser.value(QStringLiteral("header")),
parser.value(QStringLiteral("impl")) parser.value(QStringLiteral("impl"))
}; };
if(parser.isSet(QStringLiteral("qml"))) generator.process(parser.value(QStringLiteral("in")));
generator.processQml(parser.value(QStringLiteral("in")));
else
generator.process(parser.value(QStringLiteral("in")));
return EXIT_SUCCESS; return EXIT_SUCCESS;
} catch (SettingsGenerator::Exception &e) { } catch (SettingsGeneratorImpl::Exception &e) {
qCritical() << e.what(); qCritical() << e.what();
return EXIT_FAILURE; return EXIT_FAILURE;
} }

74
tools/settingsgenerator/qmlsettingsgenerator.cpp

@ -0,0 +1,74 @@
#include "qmlsettingsgenerator.h"
#include <QFileInfo>
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<IncludeType> {
{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)
{
}

25
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

1
tools/settingsgenerator/qsettingsgenerator.xsd

@ -93,6 +93,7 @@
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="1" minOccurs="0" name="Init" type="xs:string"/> <xs:element maxOccurs="1" minOccurs="0" name="Init" type="xs:string"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="qmllist" type="xs:boolean" use="optional" default="false"/>
</xs:extension> </xs:extension>
</xs:complexContent> </xs:complexContent>
</xs:complexType> </xs:complexType>

458
tools/settingsgenerator/settingsgenerator.cpp

@ -1,458 +0,0 @@
#include "settingsgenerator.h"
#include <QDebug>
#include <QFileInfo>
#include <QDir>
#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<QString, QString> &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<QFileDevice*>(reader.device())) {
QFileInfo docInfo{static_cast<QFileDevice*>(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<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 = &(nonstd::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 = &(nonstd::get<EntryType>(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<EntryType*>(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<NodeType>(cNode)) {
if(nonstd::get<NodeType>(cNode).key == key)
return &(nonstd::get<NodeType>(cNode));
} else if(nonstd::holds_alternative<EntryType>(cNode)) {
if(nonstd::get<EntryType>(cNode).key == key) {
if(isEntry)
*isEntry = true;
return &(nonstd::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<ListEntryType>(cNode)) {
if(nonstd::get<ListEntryType>(cNode).key == key) {
if(isEntry)
*isEntry = true;
return &(nonstd::get<ListEntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = findContentGroup(&(nonstd::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(&nonstd::get<NodeType>(cNode) == node) {
cNode = std::move(entry);
return &(nonstd::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = replaceNodeByEntry(&(nonstd::get<NodeContentGroup>(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<NodeType>(node))
fixTrContext(nonstd::get<NodeType>(node), context);
else if(nonstd::holds_alternative<EntryType>(node)) {
auto &entry = nonstd::get<EntryType>(node);
if(!entry.trContext)
entry.trContext = context;
fixTrContext(entry, context);
} else if(nonstd::holds_alternative<ListEntryType>(node)) {
auto &entry = nonstd::get<ListEntryType>(node);
if(!entry.trContext)
entry.trContext = context;
fixTrContext(entry, context);
} else if(nonstd::holds_alternative<NodeContentGroup>(node))
fixTrContext(nonstd::get<NodeContentGroup>(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<IncludeType> {
{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<QString, QString> &typeMappings, int intendent)
{
for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode))
writeNodeDeclaration(nonstd::get<NodeType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDeclaration(nonstd::get<EntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDeclaration(nonstd::get<ListEntryType>(cNode), typeMappings, intendent);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDeclarations(nonstd::get<NodeContentGroup>(cNode), typeMappings, intendent);
}
}
void SettingsGenerator::writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &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<QString, QString> &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<QString, QString> &typeMappings, int intendent)
{
if(entry.contentNodes.isEmpty())
_hdr << TABS << "QtMvvm::SettingsEntry<QList<" << typeMappings.value(entry.type, entry.type) << ">> " << 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 <QtCore/QCoreApplication>\n";
_src << "#include <QtMvvmCore/ServiceRegistry>\n";
if(!settings.backend)
_src << "#include <QtMvvmCore/QSettingsAccessor>\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 &param : 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<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain)
{
for(const auto &cNode : node.contentNodes) {
if(nonstd::holds_alternative<NodeType>(cNode)) {
const auto &xNode = nonstd::get<NodeType>(cNode);
writeNodeElementDefinitions(xNode, typeMappings, baseKey, QStringList{keyChain} << xNode.key);
} else if(nonstd::holds_alternative<EntryType>(cNode))
writeEntryDefinition(nonstd::get<EntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<ListEntryType>(cNode))
writeListEntryDefinition(nonstd::get<ListEntryType>(cNode), typeMappings, baseKey, keyChain);
else if(nonstd::holds_alternative<NodeContentGroup>(cNode))
writeNodeElementDefinitions(nonstd::get<NodeContentGroup>(cNode), typeMappings, baseKey, keyChain);
}
}
void SettingsGenerator::writeEntryDefinition(const SettingsGeneratorBase::EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &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<QString, QString> &typeMappings, const optional<QString> &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);
}
}

53
tools/settingsgenerator/settingsgenerator.h

@ -1,53 +0,0 @@
#ifndef SETTINGSGENERATOR_H
#define SETTINGSGENERATOR_H
#include <QFile>
#include <QTextStream>
#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<QString, QString> &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<QString, QString> &typeMappings, int intendent = 1);
void writeNodeDeclaration(const NodeType &node, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeEntryDeclaration(const EntryType &entry, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeListEntryDeclaration(const ListEntryType &entry, const QHash<QString, QString> &typeMappings, int intendent = 1);
void writeSource(const SettingsType &settings);
void writeNodeElementDefinitions(const NodeContentGroup &node, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, const QStringList &keyChain = {});
void writeEntryDefinition(const EntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain, bool skipChildren = false);
void writeListEntryDefinition(const ListEntryType &entry, const QHash<QString, QString> &typeMappings, const optional<QString> &baseKey, QStringList keyChain);
};
#endif // SETTINGSGENERATOR_H

12
tools/settingsgenerator/settingsgenerator.pro

@ -15,15 +15,19 @@ DEFINES += "COMPANY=\\\"$$COMPANY\\\""
DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\"" DEFINES += "BUNDLE_PREFIX=\\\"$$BUNDLE_PREFIX\\\""
HEADERS += \ HEADERS += \
settingsgenerator.h \
settingstranslator.h \ settingstranslator.h \
settingsconfigimpl.h settingsconfigimpl.h \
cppsettingsgenerator.h \
settingsgeneratorimpl.h \
qmlsettingsgenerator.h
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
settingsgenerator.cpp \
settingstranslator.cpp \ settingstranslator.cpp \
settingsconfigimpl.cpp settingsconfigimpl.cpp \
cppsettingsgenerator.cpp \
settingsgeneratorimpl.cpp \
qmlsettingsgenerator.cpp
XML_SCHEMA_DEFINITIONS += \ XML_SCHEMA_DEFINITIONS += \
qsettingsgenerator.xsd \ qsettingsgenerator.xsd \

225
tools/settingsgenerator/settingsgeneratorimpl.cpp

@ -0,0 +1,225 @@
#include "settingsgeneratorimpl.h"
#include <QFileInfo>
#include <QDir>
#include <QDebug>
bool SettingsGeneratorImpl::read_type_mapping(QXmlStreamReader &reader, QHash<QString, QString> &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<QFileDevice*>(reader.device())) {
QFileInfo docInfo{static_cast<QFileDevice*>(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<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 SettingsGeneratorImpl::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 SettingsGeneratorImpl::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 SettingsGeneratorImpl::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 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<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 = &(nonstd::get<EntryType>(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<EntryType*>(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<NodeType>(cNode)) {
if(nonstd::get<NodeType>(cNode).key == key)
return &(nonstd::get<NodeType>(cNode));
} else if(nonstd::holds_alternative<EntryType>(cNode)) {
if(nonstd::get<EntryType>(cNode).key == key) {
if(isEntry)
*isEntry = true;
return &(nonstd::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<ListEntryType>(cNode)) {
if(nonstd::get<ListEntryType>(cNode).key == key) {
if(isEntry)
*isEntry = true;
return &(nonstd::get<ListEntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = findContentGroup(&(nonstd::get<NodeContentGroup>(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<NodeType>(cNode)) {
if(&nonstd::get<NodeType>(cNode) == node) {
cNode = std::move(entry);
return &(nonstd::get<EntryType>(cNode));
}
} else if(nonstd::holds_alternative<NodeContentGroup>(cNode)) {
auto res = replaceNodeByEntry(&(nonstd::get<NodeContentGroup>(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<NodeType>(node))
fixTrContext(nonstd::get<NodeType>(node), context);
else if(nonstd::holds_alternative<EntryType>(node)) {
auto &entry = nonstd::get<EntryType>(node);
if(!entry.trContext)
entry.trContext = context;
fixTrContext(entry, context);
} else if(nonstd::holds_alternative<ListEntryType>(node)) {
auto &entry = nonstd::get<ListEntryType>(node);
if(!entry.trContext)
entry.trContext = context;
fixTrContext(entry, context);
} else if(nonstd::holds_alternative<NodeContentGroup>(node))
fixTrContext(nonstd::get<NodeContentGroup>(node), context);
}
}

28
tools/settingsgenerator/settingsgeneratorimpl.h

@ -0,0 +1,28 @@
#ifndef SETTINGSGENERATOR_H
#define SETTINGSGENERATOR_H
#include <QFile>
#include <QTextStream>
#include "qsettingsgenerator.h"
#include "settingsconfigimpl.h"
class SettingsGeneratorImpl : public SettingsGeneratorBase
{
protected:
bool read_type_mapping(QXmlStreamReader &reader, QHash<QString, QString> &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
Loading…
Cancel
Save