8 changed files with 181 additions and 124 deletions
			
			
		@ -0,0 +1,109 @@ | 
				
			|||||
 | 
					#include "settingsconfigimpl.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include <QtCore/QFileInfo> | 
				
			||||
 | 
					#include <QtCore/QDir> | 
				
			||||
 | 
					#include <QtCore/QDebug> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					namespace { | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					using SourceType = SettingsConfigBase::variant<SettingsConfigBase::SettingsConfigType, SettingsConfigBase::CategoryType, SettingsConfigBase::SectionType, SettingsConfigBase::GroupType, SettingsConfigBase::EntryType>; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template <typename TVariantTarget> | 
				
			||||
 | 
					void convertElement(QXmlStreamReader &reader, TVariantTarget &, SourceType &&) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						throw SettingsConfigBase::XmlException{reader, QStringLiteral("Unexpected root element in included file")}; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template <typename TVariantTarget, typename TType, typename... TArgs> | 
				
			||||
 | 
					void convertElement(QXmlStreamReader &reader, TVariantTarget &target, SourceType &&source) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						if(nonstd::holds_alternative<TType>(source)) | 
				
			||||
 | 
							target = nonstd::get<TType>(std::move(source)); | 
				
			||||
 | 
						else | 
				
			||||
 | 
							convertElement<TVariantTarget, TArgs...>(reader, target, std::move(source)); | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template <typename T> | 
				
			||||
 | 
					struct VariantInfo {}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template <typename... TArgs> | 
				
			||||
 | 
					struct VariantInfo<QList<SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>>> | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						using TargetType = SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>; | 
				
			||||
 | 
						static void convert(QXmlStreamReader &reader, TargetType &target, SourceType &&source) { | 
				
			||||
 | 
							convertElement<TargetType, TArgs...>(reader, target, std::move(source)); | 
				
			||||
 | 
						} | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool SettingsConfigImpl::finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						hasNext = read_GroupContentGroup(reader, data, hasNext); | 
				
			||||
 | 
						finishContents(reader, data.content); | 
				
			||||
 | 
						return hasNext; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool SettingsConfigImpl::finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						hasNext = read_SectionContentGroup(reader, data, hasNext); | 
				
			||||
 | 
						finishContents(reader, data.content); | 
				
			||||
 | 
						return hasNext; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool SettingsConfigImpl::finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						hasNext = read_CategoryContentGroup(reader, data, hasNext); | 
				
			||||
 | 
						finishContents(reader, data.content); | 
				
			||||
 | 
						return hasNext; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					bool SettingsConfigImpl::finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						hasNext = read_SettingsConfigContentGroup(reader, data, hasNext); | 
				
			||||
 | 
						finishContents(reader, data.content); | 
				
			||||
 | 
						return hasNext; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template<typename TGroup> | 
				
			||||
 | 
					void SettingsConfigImpl::finishContents(QXmlStreamReader &reader, TGroup &group) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						optional<std::size_t> index; | 
				
			||||
 | 
						for(auto it = group.begin(); it != group.end();) { | 
				
			||||
 | 
							// convert includes to the actual data
 | 
				
			||||
 | 
							if(nonstd::holds_alternative<IncludeType>(*it)) { | 
				
			||||
 | 
								if(!readGeneralInclude(reader, nonstd::get<IncludeType>(*it), it, group)) | 
				
			||||
 | 
									continue; | 
				
			||||
 | 
							} | 
				
			||||
 | 
							// verify that the contents are all of the same type
 | 
				
			||||
 | 
							if(index) { | 
				
			||||
 | 
								if(index.value() != it->index()) | 
				
			||||
 | 
									throw XmlException{reader, QStringLiteral("Detected mixture of different child elements. Only includes and a single other type are allowed")}; | 
				
			||||
 | 
							} else | 
				
			||||
 | 
								index = it->index(); | 
				
			||||
 | 
							++it; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					template<typename TIter, typename TList> | 
				
			||||
 | 
					bool SettingsConfigImpl::readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list) | 
				
			||||
 | 
					{ | 
				
			||||
 | 
						try { | 
				
			||||
 | 
							//make the path relative if possbile
 | 
				
			||||
 | 
							if(dynamic_cast<QFileDevice*>(reader.device())) { | 
				
			||||
 | 
								QFileInfo docInfo{static_cast<QFileDevice*>(reader.device())->fileName()}; | 
				
			||||
 | 
								include.includePath = docInfo.dir().absoluteFilePath(include.includePath); | 
				
			||||
 | 
							} | 
				
			||||
 | 
							// read the document
 | 
				
			||||
 | 
							VariantInfo<TList>::convert(reader, *it, readDocument(include.includePath)); | 
				
			||||
 | 
							return true; | 
				
			||||
 | 
						} catch(FileException &e) { | 
				
			||||
 | 
							if(include.optional) { | 
				
			||||
 | 
								qWarning() << e.what(); | 
				
			||||
 | 
								it = list.erase(it); | 
				
			||||
 | 
								return false; | 
				
			||||
 | 
							} else | 
				
			||||
 | 
								throw; | 
				
			||||
 | 
						} | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
@ -0,0 +1,21 @@ | 
				
			|||||
 | 
					#ifndef SETTINGSCONFIGIMPL_H | 
				
			||||
 | 
					#define SETTINGSCONFIGIMPL_H | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#include "settingsconfig.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class SettingsConfigImpl : public SettingsConfigBase | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					protected: | 
				
			||||
 | 
						bool finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) override; | 
				
			||||
 | 
						bool finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) override; | 
				
			||||
 | 
						bool finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) override; | 
				
			||||
 | 
						bool finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext) override; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					private: | 
				
			||||
 | 
						template <typename TGroup> | 
				
			||||
 | 
						void finishContents(QXmlStreamReader &reader, TGroup &group); | 
				
			||||
 | 
						template <typename TIter, typename TList> | 
				
			||||
 | 
						bool readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list); | 
				
			||||
 | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#endif // SETTINGSCONFIGIMPL_H
 | 
				
			||||
@ -1,108 +1,19 @@ | 
				
			|||||
#include "settingstranslator.h" | 
					#include "settingstranslator.h" | 
				
			||||
 | 
					
 | 
				
			||||
#include <QtCore/QFileInfo> | 
					SettingsTranslator::SettingsTranslator(const QString &srcPath) : | 
				
			||||
#include <QtCore/QDir> | 
						_srcFile{srcPath}, | 
				
			||||
#include <QtCore/QDebug> | 
						_src{&_srcFile} | 
				
			||||
 | 
					{} | 
				
			||||
 | 
					
 | 
				
			||||
namespace { | 
					void SettingsTranslator::process(const QString &inPath) | 
				
			||||
 | 
					 | 
				
			||||
using SourceType = SettingsConfigBase::variant<SettingsConfigBase::SettingsConfigType, SettingsConfigBase::CategoryType, SettingsConfigBase::SectionType, SettingsConfigBase::GroupType, SettingsConfigBase::EntryType>; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template <typename TVariantTarget> | 
					 | 
				
			||||
void convertElement(QXmlStreamReader &reader, TVariantTarget &, SourceType &&) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	throw SettingsConfigBase::XmlException{reader, QStringLiteral("Unexpected root element in included file")}; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template <typename TVariantTarget, typename TType, typename... TArgs> | 
					 | 
				
			||||
void convertElement(QXmlStreamReader &reader, TVariantTarget &target, SourceType &&source) | 
					 | 
				
			||||
{ | 
					{ | 
				
			||||
	if(nonstd::holds_alternative<TType>(source)) | 
						auto settings = readDocument(inPath); | 
				
			||||
		target = nonstd::get<TType>(std::move(source)); | 
						if(!nonstd::holds_alternative<SettingsConfigType>(settings)) | 
				
			||||
	else | 
							throw XmlException{inPath, 0, 0, QStringLiteral("Expected the root element to be a SettingsConfig element")}; | 
				
			||||
		convertElement<TVariantTarget, TArgs...>(reader, target, std::move(source)); | 
						writeTranslations(nonstd::get<SettingsConfigType>(settings)); | 
				
			||||
} | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
template <typename T> | 
					void SettingsTranslator::writeTranslations(const SettingsConfigBase::SettingsConfigType &settings) | 
				
			||||
struct VariantInfo {}; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template <typename... TArgs> | 
					 | 
				
			||||
struct VariantInfo<QList<SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>>> | 
					 | 
				
			||||
{ | 
					{ | 
				
			||||
	using TargetType = SettingsConfigBase::variant<SettingsConfigBase::IncludeType, TArgs...>; | 
					 | 
				
			||||
	static void convert(QXmlStreamReader &reader, TargetType &target, SourceType &&source) { | 
					 | 
				
			||||
		convertElement<TargetType, TArgs...>(reader, target, std::move(source)); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
}; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsTranslator::finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	hasNext = read_GroupContentGroup(reader, data, hasNext); | 
					 | 
				
			||||
	finishContents(reader, data.content); | 
					 | 
				
			||||
	return hasNext; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsTranslator::finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	hasNext = read_SectionContentGroup(reader, data, hasNext); | 
					 | 
				
			||||
	finishContents(reader, data.content); | 
					 | 
				
			||||
	return hasNext; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
bool SettingsTranslator::finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	hasNext = read_CategoryContentGroup(reader, data, hasNext); | 
					 | 
				
			||||
	finishContents(reader, data.content); | 
					 | 
				
			||||
	return hasNext; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsTranslator::finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	hasNext = read_SettingsConfigContentGroup(reader, data, hasNext); | 
					 | 
				
			||||
	finishContents(reader, data.content); | 
					 | 
				
			||||
	return hasNext; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template<typename TGroup> | 
					 | 
				
			||||
void SettingsTranslator::finishContents(QXmlStreamReader &reader, TGroup &group) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	optional<std::size_t> index; | 
					 | 
				
			||||
	for(auto it = group.begin(); it != group.end();) { | 
					 | 
				
			||||
		// convert includes to the actual data
 | 
					 | 
				
			||||
		if(nonstd::holds_alternative<IncludeType>(*it)) { | 
					 | 
				
			||||
			if(!readGeneralInclude(reader, nonstd::get<IncludeType>(*it), it, group)) | 
					 | 
				
			||||
				continue; | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
		// verify that the contents are all of the same type
 | 
					 | 
				
			||||
		if(index) { | 
					 | 
				
			||||
			if(index.value() != it->index()) | 
					 | 
				
			||||
				throw XmlException{reader, QStringLiteral("Detected mixture of different child elements. Only includes and a single other type are allowed")}; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			index = it->index(); | 
					 | 
				
			||||
		++it; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template<typename TIter, typename TList> | 
					 | 
				
			||||
bool SettingsTranslator::readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	try { | 
					 | 
				
			||||
		//make the path relative if possbile
 | 
					 | 
				
			||||
		if(dynamic_cast<QFileDevice*>(reader.device())) { | 
					 | 
				
			||||
			QFileInfo docInfo{static_cast<QFileDevice*>(reader.device())->fileName()}; | 
					 | 
				
			||||
			include.includePath = docInfo.dir().absoluteFilePath(include.includePath); | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
		// read the document
 | 
					 | 
				
			||||
		VariantInfo<TList>::convert(reader, *it, readDocument(include.includePath)); | 
					 | 
				
			||||
		return true; | 
					 | 
				
			||||
	} catch(FileException &e) { | 
					 | 
				
			||||
		if(include.optional) { | 
					 | 
				
			||||
			qWarning() << e.what(); | 
					 | 
				
			||||
			it = list.erase(it); | 
					 | 
				
			||||
			return false; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			throw; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					} | 
				
			||||
 | 
				
			|||||
@ -1,21 +1,23 @@ | 
				
			|||||
#ifndef SETTINGSTRANSLATOR_H | 
					#ifndef SETTINGSTRANSLATOR_H | 
				
			||||
#define SETTINGSTRANSLATOR_H | 
					#define SETTINGSTRANSLATOR_H | 
				
			||||
 | 
					
 | 
				
			||||
#include "settingsconfig.h" | 
					#include <QFile> | 
				
			||||
 | 
					#include <QTextStream> | 
				
			||||
 | 
					
 | 
				
			||||
class SettingsTranslator : public SettingsConfigBase | 
					#include "settingsconfigimpl.h" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class SettingsTranslator : public SettingsConfigImpl | 
				
			||||
{ | 
					{ | 
				
			||||
protected: | 
					public: | 
				
			||||
	bool finish_group_content(QXmlStreamReader &reader, GroupContentGroup &data, bool hasNext) override; | 
						SettingsTranslator(const QString &srcPath); | 
				
			||||
	bool finish_section_content(QXmlStreamReader &reader, SectionContentGroup &data, bool hasNext) override; | 
					
 | 
				
			||||
	bool finish_category_content(QXmlStreamReader &reader, CategoryContentGroup &data, bool hasNext) override; | 
						void process(const QString &inPath); | 
				
			||||
	bool finish_settings_config_content(QXmlStreamReader &reader, SettingsConfigContentGroup &data, bool hasNext) override; | 
					 | 
				
			||||
 | 
					
 | 
				
			||||
private: | 
					private: | 
				
			||||
	template <typename TGroup> | 
						QFile _srcFile; | 
				
			||||
	void finishContents(QXmlStreamReader &reader, TGroup &group); | 
						QTextStream _src; | 
				
			||||
	template <typename TIter, typename TList> | 
					
 | 
				
			||||
	bool readGeneralInclude(QXmlStreamReader &reader, IncludeType include, TIter &it, TList &list); | 
						void writeTranslations(const SettingsConfigType &settings); | 
				
			||||
}; | 
					}; | 
				
			||||
 | 
					
 | 
				
			||||
#endif // SETTINGSTRANSLATOR_H
 | 
					#endif // SETTINGSTRANSLATOR_H
 | 
				
			||||
 | 
				
			|||||
					Loading…
					
					
				
		Reference in new issue