12 changed files with 120 additions and 649 deletions
			
			
		@ -1,530 +0,0 @@ | 
				
			|||||
#include "settingssetuploader_p.h" | 
					 | 
				
			||||
#include "qtmvvm_logging_p.h" | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include <QtCore/QCoreApplication> | 
					 | 
				
			||||
#include <QtCore/QDir> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
using namespace QtMvvm; | 
					 | 
				
			||||
using namespace QtMvvm::SettingsElements; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define throwXmlError(...) throw SettingsXmlException(__VA_ARGS__) | 
					 | 
				
			||||
#define throwAttrib(reader, attrib) throwXmlError(reader, "Attribute \"" attrib "\" is required, but was not set!") | 
					 | 
				
			||||
#define throwElement(reader, element) throwXmlError(reader, "Expected element of type <" element ">") | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define testXmlValid(reader) if(reader.hasError()) throwXmlError(reader) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define hasValue(key) attributes().hasAttribute(QStringLiteral(key)) | 
					 | 
				
			||||
#define stringValue(key) attributes().value(QStringLiteral(key)).toString() | 
					 | 
				
			||||
#define boolValue(key) attributes().value(QStringLiteral(key)) == QStringLiteral("true") | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#define trctx(x) QCoreApplication::translate("qtmvvm_settings_xml", qUtf8Printable(x)) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
SettingsSetupLoader::SettingsSetupLoader(QObject *parent) : | 
					 | 
				
			||||
	QObject{parent} | 
					 | 
				
			||||
{} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::changeDefaultIcon(const QUrl &defaultIcon) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	_defaultIcon = defaultIcon; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Setup SettingsSetupLoader::loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	Setup setup; | 
					 | 
				
			||||
	if(!_cache.contains(filePath)) { | 
					 | 
				
			||||
		QFile file(QDir::cleanPath(selector->select(filePath))); | 
					 | 
				
			||||
		if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) | 
					 | 
				
			||||
			throw SettingsXmlException(file); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		QXmlStreamReader reader(&file); | 
					 | 
				
			||||
		testXmlValid(reader); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		if(!reader.readNextStartElement() || reader.name() != QStringLiteral("SettingsConfig")) | 
					 | 
				
			||||
			throwElement(reader, "SettingsConfig"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		if(reader.hasValue("allowSearch")) | 
					 | 
				
			||||
			setup.allowSearch = reader.boolValue("allowSearch"); | 
					 | 
				
			||||
		if(reader.hasValue("allowRestore")) | 
					 | 
				
			||||
			setup.allowRestore = reader.boolValue("allowRestore"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		if(reader.readNextStartElement()) { | 
					 | 
				
			||||
			if(reader.name() == QStringLiteral("Category") || | 
					 | 
				
			||||
			   reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
				do { | 
					 | 
				
			||||
					if(reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
						Category category; | 
					 | 
				
			||||
						if(readCategoryInclude(reader, category, selector)) | 
					 | 
				
			||||
							setup.categories.append(category); | 
					 | 
				
			||||
					} else | 
					 | 
				
			||||
						setup.categories.append(readCategory(reader, selector)); | 
					 | 
				
			||||
				} while(reader.readNextStartElement()); | 
					 | 
				
			||||
			} else | 
					 | 
				
			||||
				setup.categories.append(readDefaultCategory(reader, selector)); | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
		testXmlValid(reader); | 
					 | 
				
			||||
		file.close(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		_cache.insert(filePath, new Setup(setup)); | 
					 | 
				
			||||
	} else | 
					 | 
				
			||||
		setup = *(_cache.object(filePath)); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	clearSetup(setup, frontend, selector->allSelectors()); | 
					 | 
				
			||||
	return setup; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::event(QEvent *event) | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	//reset the loaded cache on language changes
 | 
					 | 
				
			||||
	switch(event->type()) { | 
					 | 
				
			||||
	case QEvent::LanguageChange: | 
					 | 
				
			||||
	case QEvent::LocaleChange: | 
					 | 
				
			||||
		_cache.clear(); | 
					 | 
				
			||||
		break; | 
					 | 
				
			||||
	default: | 
					 | 
				
			||||
		break; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return QObject::event(event); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Category SettingsSetupLoader::readCategory(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.name() != QStringLiteral("Category")) | 
					 | 
				
			||||
		throwElement(reader, "Category"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	auto category = createDefaultCategory(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(reader.hasValue("title")) | 
					 | 
				
			||||
		category.title = trctx(reader.stringValue("title")); | 
					 | 
				
			||||
	if(reader.hasValue("icon")) | 
					 | 
				
			||||
		category.icon = reader.stringValue("icon"); | 
					 | 
				
			||||
	if(reader.hasValue("tooltip")) | 
					 | 
				
			||||
		category.tooltip = trctx(reader.stringValue("tooltip")); | 
					 | 
				
			||||
	category.frontends = reader.stringValue("frontends"); | 
					 | 
				
			||||
	category.selectors = reader.stringValue("selectors"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(reader.readNextStartElement()) | 
					 | 
				
			||||
		readCategoryChildren(reader, category, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return category; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Category SettingsSetupLoader::readDefaultCategory(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	auto category = createDefaultCategory(); | 
					 | 
				
			||||
	readCategoryChildren(reader, category, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	return category; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::readCategoryChildren(QXmlStreamReader &reader, Category &category, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	if(reader.name() == QStringLiteral("Section") || | 
					 | 
				
			||||
	   reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
		do { | 
					 | 
				
			||||
			if(reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
				Section section; | 
					 | 
				
			||||
				if(readSectionInclude(reader, section, selector)) | 
					 | 
				
			||||
					category.sections.append(section); | 
					 | 
				
			||||
			} else | 
					 | 
				
			||||
				category.sections.append(readSection(reader, selector)); | 
					 | 
				
			||||
		} while(reader.readNextStartElement()); | 
					 | 
				
			||||
	} else | 
					 | 
				
			||||
		category.sections.append(readDefaultSection(reader, selector)); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Section SettingsSetupLoader::readSection(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.name() != QStringLiteral("Section")) | 
					 | 
				
			||||
		throwElement(reader, "Section"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	auto section = createDefaultSection(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(reader.hasValue("title")) | 
					 | 
				
			||||
		section.title = trctx(reader.stringValue("title")); | 
					 | 
				
			||||
	if(reader.hasValue("icon")) | 
					 | 
				
			||||
		section.icon = reader.stringValue("icon"); | 
					 | 
				
			||||
	if(reader.hasValue("tooltip")) | 
					 | 
				
			||||
		section.tooltip = trctx(reader.stringValue("tooltip")); | 
					 | 
				
			||||
	section.frontends = reader.stringValue("frontends"); | 
					 | 
				
			||||
	section.selectors = reader.stringValue("selectors"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(reader.readNextStartElement()) | 
					 | 
				
			||||
		readSectionChildren(reader, section, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return section; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Section SettingsSetupLoader::readDefaultSection(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	auto section = createDefaultSection(); | 
					 | 
				
			||||
	readSectionChildren(reader, section, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	return section; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::readSectionChildren(QXmlStreamReader &reader, Section §ion, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	if(reader.name() == QStringLiteral("Group") || | 
					 | 
				
			||||
	   reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
		do { | 
					 | 
				
			||||
			if(reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
				Group group; | 
					 | 
				
			||||
				if(readGroupInclude(reader, group, selector)) | 
					 | 
				
			||||
					section.groups.append(group); | 
					 | 
				
			||||
			} else | 
					 | 
				
			||||
				section.groups.append(readGroup(reader, selector)); | 
					 | 
				
			||||
		} while(reader.readNextStartElement()); | 
					 | 
				
			||||
	} else | 
					 | 
				
			||||
		section.groups.append(readDefaultGroup(reader, selector)); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Group SettingsSetupLoader::readGroup(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.name() != QStringLiteral("Group")) | 
					 | 
				
			||||
		throwElement(reader, "Group"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	Group group; | 
					 | 
				
			||||
	if(reader.hasValue("title")) | 
					 | 
				
			||||
		group.title = trctx(reader.stringValue("title")); | 
					 | 
				
			||||
	if(reader.hasValue("tooltip")) | 
					 | 
				
			||||
		group.tooltip = trctx(reader.stringValue("tooltip")); | 
					 | 
				
			||||
	group.frontends = reader.stringValue("frontends"); | 
					 | 
				
			||||
	group.selectors = reader.stringValue("selectors"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(reader.readNextStartElement()) | 
					 | 
				
			||||
		readGroupChildren(reader, group, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return group; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Group SettingsSetupLoader::readDefaultGroup(QXmlStreamReader &reader, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	Group group; | 
					 | 
				
			||||
	readGroupChildren(reader, group, selector); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	return group; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::readGroupChildren(QXmlStreamReader &reader, Group &group, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	if(reader.name() == QStringLiteral("Entry") || | 
					 | 
				
			||||
	   reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
		do { | 
					 | 
				
			||||
			if(reader.name() == QStringLiteral("Include")) { | 
					 | 
				
			||||
				Entry entry; | 
					 | 
				
			||||
				if(readEntryInclude(reader, entry, selector)) | 
					 | 
				
			||||
					group.entries.append(entry); | 
					 | 
				
			||||
			} else | 
					 | 
				
			||||
				group.entries.append(readEntry(reader)); | 
					 | 
				
			||||
		} while(reader.readNextStartElement()); | 
					 | 
				
			||||
	} else | 
					 | 
				
			||||
		throwXmlError(reader, QStringLiteral("Unexpected element type <%1>").arg(reader.name()).toUtf8()); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Entry SettingsSetupLoader::readEntry(QXmlStreamReader &reader) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.name() != QStringLiteral("Entry")) | 
					 | 
				
			||||
		throwElement(reader, "Entry"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	Entry entry; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	if(!reader.hasValue("key")) | 
					 | 
				
			||||
		throwAttrib(reader, "key"); | 
					 | 
				
			||||
	entry.key = reader.stringValue("key"); | 
					 | 
				
			||||
	if(!reader.hasValue("type")) | 
					 | 
				
			||||
		throwAttrib(reader, "type"); | 
					 | 
				
			||||
	entry.type = reader.stringValue("type").toLatin1(); | 
					 | 
				
			||||
	if(!reader.hasValue("title")) | 
					 | 
				
			||||
		throwAttrib(reader, "title"); | 
					 | 
				
			||||
	entry.title = trctx(reader.stringValue("title")); | 
					 | 
				
			||||
	entry.tooltip = trctx(reader.stringValue("tooltip")); | 
					 | 
				
			||||
	if(reader.boolValue("trdefault") || reader.boolValue("tsdefault")) //MAJOR remove ts variant
 | 
					 | 
				
			||||
		entry.defaultValue = trctx(reader.stringValue("default")); | 
					 | 
				
			||||
	else | 
					 | 
				
			||||
		entry.defaultValue = reader.stringValue("default"); | 
					 | 
				
			||||
	entry.frontends = reader.stringValue("frontends"); | 
					 | 
				
			||||
	entry.selectors = reader.stringValue("selectors"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	while(reader.readNextStartElement()) { | 
					 | 
				
			||||
		if(reader.name() == QStringLiteral("SearchKey")) { | 
					 | 
				
			||||
			entry.searchKeys.append(trctx(reader.readElementText())); | 
					 | 
				
			||||
			testXmlValid(reader); | 
					 | 
				
			||||
		} else if(reader.name() == QStringLiteral("Property")) { | 
					 | 
				
			||||
			auto prop = readProperty(reader); | 
					 | 
				
			||||
			entry.properties.insert(std::get<0>(prop), std::get<1>(prop)); | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			throwXmlError(reader, "Expected element of type <SearchKey> or <Property>"); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return entry; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Category SettingsSetupLoader::createDefaultCategory() const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	Category category; | 
					 | 
				
			||||
	category.title = tr("General Settings"); | 
					 | 
				
			||||
	category.icon = _defaultIcon; | 
					 | 
				
			||||
	return category; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
Section SettingsSetupLoader::createDefaultSection() const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	Section section; | 
					 | 
				
			||||
	section.title = tr("General"); | 
					 | 
				
			||||
	return section; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
std::tuple<QString, QVariant> SettingsSetupLoader::readProperty(QXmlStreamReader &reader) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	if(!reader.hasValue("key")) | 
					 | 
				
			||||
		throwAttrib(reader, "key"); | 
					 | 
				
			||||
	auto key = reader.stringValue("key"); | 
					 | 
				
			||||
	return std::make_tuple(key, readElement(reader)); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
QVariant SettingsSetupLoader::readElement(QXmlStreamReader &reader) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	if(!reader.hasValue("type")) | 
					 | 
				
			||||
		throwAttrib(reader, "type"); | 
					 | 
				
			||||
	auto type = reader.stringValue("type"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//special type mappings
 | 
					 | 
				
			||||
	if(type == QStringLiteral("string")) | 
					 | 
				
			||||
		type = QString::fromUtf8(QMetaType::typeName(QMetaType::QString)); | 
					 | 
				
			||||
	else if(type == QStringLiteral("number")) | 
					 | 
				
			||||
		type = QString::fromUtf8(QMetaType::typeName(QMetaType::Int)); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//special types
 | 
					 | 
				
			||||
	if(type == QStringLiteral("list")) { | 
					 | 
				
			||||
		QVariantList list; | 
					 | 
				
			||||
		while (reader.readNextStartElement()) { | 
					 | 
				
			||||
			if(reader.name() != QStringLiteral("Element")) | 
					 | 
				
			||||
				throwElement(reader, "Element"); | 
					 | 
				
			||||
			list.append(readElement(reader)); | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
		testXmlValid(reader); | 
					 | 
				
			||||
		return list; | 
					 | 
				
			||||
	} else if(type == QStringLiteral("object")) { | 
					 | 
				
			||||
		QVariantMap map; | 
					 | 
				
			||||
		while (reader.readNextStartElement()) { | 
					 | 
				
			||||
			if(reader.name() != QStringLiteral("Property")) | 
					 | 
				
			||||
				throwElement(reader, "Property"); | 
					 | 
				
			||||
			auto property = readProperty(reader); | 
					 | 
				
			||||
			map.insert(std::get<0>(property), std::get<1>(property)); | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
		testXmlValid(reader); | 
					 | 
				
			||||
		return map; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//common types
 | 
					 | 
				
			||||
	auto typeId = QMetaType::type(qUtf8Printable(type)); | 
					 | 
				
			||||
	if(typeId == QMetaType::UnknownType) | 
					 | 
				
			||||
		throwXmlError(reader, "Unknown type: " + type.toUtf8()); | 
					 | 
				
			||||
	QVariant mVariant; | 
					 | 
				
			||||
	if(reader.boolValue("tr") || reader.boolValue("ts")) //MAJOR remove ts variant
 | 
					 | 
				
			||||
		mVariant = trctx(reader.readElementText()); | 
					 | 
				
			||||
	else | 
					 | 
				
			||||
		mVariant = reader.readElementText(); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(!mVariant.convert(typeId)) | 
					 | 
				
			||||
		throwXmlError(reader, "Failed to convert element data to type: " + type.toUtf8()); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return mVariant; | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::readCategoryInclude(QXmlStreamReader &reader, Category &category, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return readInclude(reader, [this, &category, selector](QXmlStreamReader &mReader){ | 
					 | 
				
			||||
		category = readCategory(mReader, selector); | 
					 | 
				
			||||
	}, QStringLiteral("Category"), selector); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::readSectionInclude(QXmlStreamReader &reader, Section §ion, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return readInclude(reader, [this, §ion, selector](QXmlStreamReader &mReader){ | 
					 | 
				
			||||
		section = readSection(mReader, selector); | 
					 | 
				
			||||
	}, QStringLiteral("Section"), selector); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::readGroupInclude(QXmlStreamReader &reader, Group &group, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return readInclude(reader, [this, &group, selector](QXmlStreamReader &mReader){ | 
					 | 
				
			||||
		group = readGroup(mReader, selector); | 
					 | 
				
			||||
	}, QStringLiteral("Group"), selector); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::readEntryInclude(QXmlStreamReader &reader, Entry &entry, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return readInclude(reader, [this, &entry](QXmlStreamReader &mReader){ | 
					 | 
				
			||||
		entry = readEntry(mReader); | 
					 | 
				
			||||
	}, QStringLiteral("Entry"), selector); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
bool SettingsSetupLoader::readInclude(QXmlStreamReader &reader, const std::function<void(QXmlStreamReader &)> &readFn, const QString &typeName, const QFileSelector *selector) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.name() != QStringLiteral("Include")) | 
					 | 
				
			||||
		throwElement(reader, "Include"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	auto optional = reader.boolValue("optional"); | 
					 | 
				
			||||
	auto fileName = reader.readElementText(); | 
					 | 
				
			||||
	testXmlValid(reader); | 
					 | 
				
			||||
	if(reader.readNextStartElement()) | 
					 | 
				
			||||
		throwXmlError(reader, "The <Include> Element must not have any child elements"); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	try { | 
					 | 
				
			||||
		auto dir = QDir::current(); | 
					 | 
				
			||||
		auto dev = qobject_cast<QFileDevice*>(reader.device()); | 
					 | 
				
			||||
		if(dev) | 
					 | 
				
			||||
			dir = QFileInfo(dev->fileName()).dir(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		QFile incFile(QDir::cleanPath(selector->select(dir.absoluteFilePath(fileName)))); | 
					 | 
				
			||||
		if(!incFile.open(QIODevice::ReadOnly | QIODevice::Text)) | 
					 | 
				
			||||
			throw SettingsXmlException(incFile); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		QXmlStreamReader incReader(&incFile); | 
					 | 
				
			||||
		if(!incReader.readNextStartElement() || incReader.name() != typeName) | 
					 | 
				
			||||
			throwXmlError(reader, QStringLiteral("Expected element of type <%1>").arg(typeName).toUtf8()); | 
					 | 
				
			||||
		readFn(incReader); | 
					 | 
				
			||||
		testXmlValid(reader); | 
					 | 
				
			||||
		incFile.close(); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		return true; | 
					 | 
				
			||||
	} catch(SettingsXmlException &e) { | 
					 | 
				
			||||
		if(optional) { | 
					 | 
				
			||||
			logInfo() << "Skipped include file:" << e.what(); | 
					 | 
				
			||||
			return false; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			throw; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::clearSetup(Setup &setup, const QString &frontend, const QStringList &selectors) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	for(auto it = setup.categories.begin(); it != setup.categories.end();) { | 
					 | 
				
			||||
		if(isUsable(*it, frontend, selectors)) { | 
					 | 
				
			||||
			clearCategory(*it, frontend, selectors); | 
					 | 
				
			||||
			it++; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			it = setup.categories.erase(it); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::clearCategory(Category &category, const QString &frontend, const QStringList &selectors) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	for(auto it = category.sections.begin(); it != category.sections.end();) { | 
					 | 
				
			||||
		if(isUsable(*it, frontend, selectors)) { | 
					 | 
				
			||||
			clearSection(*it, frontend, selectors); | 
					 | 
				
			||||
			it++; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			it = category.sections.erase(it); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::clearSection(Section §ion, const QString &frontend, const QStringList &selectors) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	for(auto it = section.groups.begin(); it != section.groups.end();) { | 
					 | 
				
			||||
		if(isUsable(*it, frontend, selectors)) { | 
					 | 
				
			||||
			clearGroup(*it, frontend, selectors); | 
					 | 
				
			||||
			it++; | 
					 | 
				
			||||
		} else | 
					 | 
				
			||||
			it = section.groups.erase(it); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsSetupLoader::clearGroup(Group &group, const QString &frontend, const QStringList &selectors) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	for(auto it = group.entries.begin(); it != group.entries.end();) { | 
					 | 
				
			||||
		if(isUsable(*it, frontend, selectors)) | 
					 | 
				
			||||
			it++; | 
					 | 
				
			||||
		else | 
					 | 
				
			||||
			it = group.entries.erase(it); | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
template<typename T> | 
					 | 
				
			||||
bool SettingsSetupLoader::isUsable(const T &configElement, const QString &frontend, const QStringList &selectors) const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	auto fronts = configElement.frontends.split(QLatin1Char('|'), QString::SkipEmptyParts); | 
					 | 
				
			||||
	if(!fronts.isEmpty() && !fronts.contains(frontend)) | 
					 | 
				
			||||
		return false; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	auto selects = configElement.selectors.split(QLatin1Char('|'), QString::SkipEmptyParts); | 
					 | 
				
			||||
	for(const auto &select : selects) { | 
					 | 
				
			||||
		auto sels = select.split(QLatin1Char('&'), QString::SkipEmptyParts); | 
					 | 
				
			||||
		auto allSelected = true; | 
					 | 
				
			||||
		for(const auto &sel : sels) { | 
					 | 
				
			||||
			if(!selectors.contains(sel)) { | 
					 | 
				
			||||
				allSelected = false; | 
					 | 
				
			||||
				break; | 
					 | 
				
			||||
			} | 
					 | 
				
			||||
		} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
		if(allSelected) | 
					 | 
				
			||||
			return true; | 
					 | 
				
			||||
	} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	return selects.isEmpty(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
 | 
					 | 
				
			||||
SettingsXmlException::SettingsXmlException(const QXmlStreamReader &reader) : | 
					 | 
				
			||||
	SettingsLoaderException(), | 
					 | 
				
			||||
	_what(QStringLiteral("XML Error in file \"%1\", line %2, column %3. Error: %4") | 
					 | 
				
			||||
		  .arg([&](){ | 
					 | 
				
			||||
			  auto dev = qobject_cast<QFileDevice*>(reader.device()); | 
					 | 
				
			||||
			  return dev ? dev->fileName() : QStringLiteral("<unknown>"); | 
					 | 
				
			||||
		  }()) | 
					 | 
				
			||||
		  .arg(reader.lineNumber()) | 
					 | 
				
			||||
		  .arg(reader.columnNumber()) | 
					 | 
				
			||||
		  .arg(reader.errorString()) | 
					 | 
				
			||||
		  .toUtf8()) | 
					 | 
				
			||||
{} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
SettingsXmlException::SettingsXmlException(QXmlStreamReader &reader, const QByteArray &customError, bool forceOverwrite) : | 
					 | 
				
			||||
	SettingsXmlException([&]() -> QXmlStreamReader & { | 
					 | 
				
			||||
		if(forceOverwrite || !reader.hasError()) | 
					 | 
				
			||||
			reader.raiseError(QString::fromUtf8(customError)); | 
					 | 
				
			||||
		return reader; | 
					 | 
				
			||||
	}()) | 
					 | 
				
			||||
{} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
SettingsXmlException::SettingsXmlException(const QFile &fileError) : | 
					 | 
				
			||||
	SettingsLoaderException(), | 
					 | 
				
			||||
	_what(QStringLiteral("Failed to open file \"%1\" with error: %2") | 
					 | 
				
			||||
		  .arg(fileError.fileName(), fileError.errorString()) | 
					 | 
				
			||||
		  .toUtf8()) | 
					 | 
				
			||||
{} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
SettingsXmlException::SettingsXmlException(const SettingsXmlException * const other) : | 
					 | 
				
			||||
	SettingsLoaderException(), | 
					 | 
				
			||||
	_what(other->_what) | 
					 | 
				
			||||
{} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
const char *SettingsXmlException::what() const noexcept | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return _what.constData(); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
void SettingsXmlException::raise() const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	throw (*this); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
QException *SettingsXmlException::clone() const | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	return new SettingsXmlException(this); | 
					 | 
				
			||||
} | 
					 | 
				
			||||
@ -1,92 +0,0 @@ | 
				
			|||||
#ifndef QTMVVM_SETTINGSSETUPLOADER_P_H | 
					 | 
				
			||||
#define QTMVVM_SETTINGSSETUPLOADER_P_H | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include <tuple> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include <QtCore/QObject> | 
					 | 
				
			||||
#include <QtCore/QIODevice> | 
					 | 
				
			||||
#include <QtCore/QCache> | 
					 | 
				
			||||
#include <QtCore/QXmlStreamReader> | 
					 | 
				
			||||
#include <QtCore/QFile> | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#include "qtmvvmcore_global.h" | 
					 | 
				
			||||
#include "settingssetup.h" | 
					 | 
				
			||||
 | 
					 | 
				
			||||
namespace QtMvvm { | 
					 | 
				
			||||
 | 
					 | 
				
			||||
class Q_MVVMCORE_EXPORT Q_DECL_DEPRECATED SettingsSetupLoader : public QObject, public ISettingsSetupLoader | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
	Q_OBJECT | 
					 | 
				
			||||
	Q_INTERFACES(QtMvvm::ISettingsSetupLoader) | 
					 | 
				
			||||
 | 
					 | 
				
			||||
public: | 
					 | 
				
			||||
	Q_INVOKABLE SettingsSetupLoader(QObject *parent = nullptr); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	void changeDefaultIcon(const QUrl &defaultIcon) override; | 
					 | 
				
			||||
	SettingsElements::Setup loadSetup(const QString &filePath, const QString &frontend, const QFileSelector *selector) const final; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	bool event(QEvent *event) override; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
private: | 
					 | 
				
			||||
	QUrl _defaultIcon{QStringLiteral("qrc:/de/skycoder42/qtmvvm/icons/settings.svg")}; | 
					 | 
				
			||||
	mutable QCache<QString, SettingsElements::Setup> _cache; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//Functions to read the settings XML
 | 
					 | 
				
			||||
	SettingsElements::Category readCategory(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	SettingsElements::Category readDefaultCategory(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	void readCategoryChildren(QXmlStreamReader &reader, SettingsElements::Category &category, const QFileSelector *selector) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	SettingsElements::Section readSection(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	SettingsElements::Section readDefaultSection(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	void readSectionChildren(QXmlStreamReader &reader, SettingsElements::Section §ion, const QFileSelector *selector) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	SettingsElements::Group readGroup(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	SettingsElements::Group readDefaultGroup(QXmlStreamReader &reader, const QFileSelector *selector) const; | 
					 | 
				
			||||
	void readGroupChildren(QXmlStreamReader &reader, SettingsElements::Group &group, const QFileSelector *selector) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	SettingsElements::Entry readEntry(QXmlStreamReader &reader) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	SettingsElements::Category createDefaultCategory() const; | 
					 | 
				
			||||
	SettingsElements::Section createDefaultSection() const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	std::tuple<QString, QVariant> readProperty(QXmlStreamReader &reader) const; | 
					 | 
				
			||||
	QVariant readElement(QXmlStreamReader &reader) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//Functions to read included files
 | 
					 | 
				
			||||
	bool readCategoryInclude(QXmlStreamReader &reader, SettingsElements::Category &category, const QFileSelector *selector) const; | 
					 | 
				
			||||
	bool readSectionInclude(QXmlStreamReader &reader, SettingsElements::Section §ion, const QFileSelector *selector) const; | 
					 | 
				
			||||
	bool readGroupInclude(QXmlStreamReader &reader, SettingsElements::Group &group, const QFileSelector *selector) const; | 
					 | 
				
			||||
	bool readEntryInclude(QXmlStreamReader &reader, SettingsElements::Entry &entry, const QFileSelector *selector) const; | 
					 | 
				
			||||
	bool readInclude(QXmlStreamReader &reader, const std::function<void(QXmlStreamReader&)> &readFn, const QString &typeName, const QFileSelector *selector) const; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	//Functions to filter the elements
 | 
					 | 
				
			||||
	void clearSetup(SettingsElements::Setup &setup, const QString &frontend, const QStringList &selectors) const; | 
					 | 
				
			||||
	void clearCategory(SettingsElements::Category &category, const QString &frontend, const QStringList &selectors) const; | 
					 | 
				
			||||
	void clearSection(SettingsElements::Section §ion, const QString &frontend, const QStringList &selectors) const; | 
					 | 
				
			||||
	void clearGroup(SettingsElements::Group &group, const QString &frontend, const QStringList &selectors) const; | 
					 | 
				
			||||
	template <typename T> | 
					 | 
				
			||||
	bool isUsable(const T &configElement, const QString &frontend, const QStringList &selectors) const; | 
					 | 
				
			||||
}; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
class Q_MVVMCORE_EXPORT SettingsXmlException : public SettingsLoaderException | 
					 | 
				
			||||
{ | 
					 | 
				
			||||
public: | 
					 | 
				
			||||
	SettingsXmlException(const QXmlStreamReader &reader); | 
					 | 
				
			||||
	SettingsXmlException(QXmlStreamReader &reader, const QByteArray &customError, bool forceOverwrite = false); | 
					 | 
				
			||||
	SettingsXmlException(const QFile &fileError); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	const char *what() const noexcept override; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
	void raise() const override; | 
					 | 
				
			||||
	QException *clone() const override; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
protected: | 
					 | 
				
			||||
	SettingsXmlException(const SettingsXmlException * const other); | 
					 | 
				
			||||
 | 
					 | 
				
			||||
private: | 
					 | 
				
			||||
	const QByteArray _what; | 
					 | 
				
			||||
}; | 
					 | 
				
			||||
 | 
					 | 
				
			||||
} | 
					 | 
				
			||||
 | 
					 | 
				
			||||
#endif // QTMVVM_SETTINGSSETUPLOADER_P_H
 | 
					 | 
				
			||||
@ -0,0 +1,20 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<SettingsConfig allowSearch="false" allowRestore="false"> | 
				
			||||
 | 
						<Include>includeDocument_category.xml</Include> | 
				
			||||
 | 
						<Category> | 
				
			||||
 | 
							<Include>includeDocument_section.xml</Include> | 
				
			||||
 | 
							<Section> | 
				
			||||
 | 
								<Group/> | 
				
			||||
 | 
								<Include>includeDocument_group.xml</Include> | 
				
			||||
 | 
								<Group> | 
				
			||||
 | 
									<Include>includeDocument_entry.xml</Include> | 
				
			||||
 | 
								</Group> | 
				
			||||
 | 
							</Section> | 
				
			||||
 | 
						</Category> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						<Category> | 
				
			||||
 | 
							<Include frontends="console">includeDocument_section.xml</Include> | 
				
			||||
 | 
							<Include optional="true">includeDocument_invalid.xml</Include> | 
				
			||||
 | 
							<Include>includeDocument_filtered.xml</Include> | 
				
			||||
 | 
						</Category> | 
				
			||||
 | 
					</SettingsConfig> | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<Category> | 
				
			||||
 | 
						<Include>includeDocument_section.xml</Include> | 
				
			||||
 | 
					</Category> | 
				
			||||
@ -0,0 +1,2 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<Entry key="incEntry" type="bool" /> | 
				
			||||
@ -0,0 +1,3 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<Section frontends="console"> | 
				
			||||
 | 
					</Section> | 
				
			||||
@ -0,0 +1,2 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<Group title="incGroup"/> | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<Section> | 
				
			||||
 | 
						<Entry key="included" type="url"/> | 
				
			||||
 | 
					</Section> | 
				
			||||
					Loading…
					
					
				
		Reference in new issue