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