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 <QtCore/QFileInfo> | 
				
			|||
#include <QtCore/QDir> | 
				
			|||
#include <QtCore/QDebug> | 
				
			|||
SettingsTranslator::SettingsTranslator(const QString &srcPath) : | 
				
			|||
	_srcFile{srcPath}, | 
				
			|||
	_src{&_srcFile} | 
				
			|||
{} | 
				
			|||
 | 
				
			|||
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 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) | 
				
			|||
void SettingsTranslator::process(const QString &inPath) | 
				
			|||
{ | 
				
			|||
	hasNext = read_SettingsConfigContentGroup(reader, data, hasNext); | 
				
			|||
	finishContents(reader, data.content); | 
				
			|||
	return hasNext; | 
				
			|||
	auto settings = readDocument(inPath); | 
				
			|||
	if(!nonstd::holds_alternative<SettingsConfigType>(settings)) | 
				
			|||
		throw XmlException{inPath, 0, 0, QStringLiteral("Expected the root element to be a SettingsConfig element")}; | 
				
			|||
	writeTranslations(nonstd::get<SettingsConfigType>(settings)); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
template<typename TGroup> | 
				
			|||
void SettingsTranslator::finishContents(QXmlStreamReader &reader, TGroup &group) | 
				
			|||
void SettingsTranslator::writeTranslations(const SettingsConfigBase::SettingsConfigType &settings) | 
				
			|||
{ | 
				
			|||
	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 | 
				
			|||
#define SETTINGSTRANSLATOR_H | 
				
			|||
 | 
				
			|||
#include "settingsconfig.h" | 
				
			|||
#include <QFile> | 
				
			|||
#include <QTextStream> | 
				
			|||
 | 
				
			|||
class SettingsTranslator : public SettingsConfigBase | 
				
			|||
#include "settingsconfigimpl.h" | 
				
			|||
 | 
				
			|||
class SettingsTranslator : public SettingsConfigImpl | 
				
			|||
{ | 
				
			|||
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; | 
				
			|||
public: | 
				
			|||
	SettingsTranslator(const QString &srcPath); | 
				
			|||
 | 
				
			|||
	void process(const QString &inPath); | 
				
			|||
 | 
				
			|||
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); | 
				
			|||
	QFile _srcFile; | 
				
			|||
	QTextStream _src; | 
				
			|||
 | 
				
			|||
	void writeTranslations(const SettingsConfigType &settings); | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
#endif // SETTINGSTRANSLATOR_H
 | 
				
			|||
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue