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