11 changed files with 642 additions and 522 deletions
@ -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 ¶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<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); |
|||
} |
|||
} |
|||
|
@ -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
|
@ -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) |
|||
{ |
|||
|
|||
} |
@ -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,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 ¶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<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); |
|||
} |
|||
} |
@ -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
|
@ -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); |
|||
} |
|||
} |
@ -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…
Reference in new issue