23 changed files with 856 additions and 59 deletions
			
			
		@ -0,0 +1,40 @@ | 
				
			|||
TARGET = QtMvvmSettingsCore | 
				
			|||
 | 
				
			|||
QT = core gui mvvmcore mvvmcore-private | 
				
			|||
 | 
				
			|||
HEADERS += qtmvvmsettingscore_global.h \ | 
				
			|||
	settingsviewmodel.h \ | 
				
			|||
	settingssetup.h \ | 
				
			|||
	settingssetuploader_p.h \ | 
				
			|||
    settingsviewmodel_p.h | 
				
			|||
 | 
				
			|||
SOURCES += \ | 
				
			|||
	settingsviewmodel.cpp \ | 
				
			|||
	settingssetuploader.cpp \ | 
				
			|||
    qtmvvmsettingscore_global.cpp | 
				
			|||
 | 
				
			|||
TRANSLATIONS += \ | 
				
			|||
	translations/qtmvvsettingsmcore_de.ts \ | 
				
			|||
	translations/qtmvvsettingsmcore_template.ts | 
				
			|||
 | 
				
			|||
DISTFILES += $$TRANSLATIONS | 
				
			|||
 | 
				
			|||
qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS] | 
				
			|||
qpmx_ts_target.depends += lrelease | 
				
			|||
 | 
				
			|||
load(qt_module) | 
				
			|||
 | 
				
			|||
win32 { | 
				
			|||
	QMAKE_TARGET_PRODUCT = "$$TARGET" | 
				
			|||
	QMAKE_TARGET_COMPANY = "Skycoder42" | 
				
			|||
	QMAKE_TARGET_COPYRIGHT = "Felix Barz" | 
				
			|||
} else:mac { | 
				
			|||
	QMAKE_TARGET_BUNDLE_PREFIX = "com.skycoder42." | 
				
			|||
} | 
				
			|||
 | 
				
			|||
!ReleaseBuild:!DebugBuild:!system(qpmx -d $$shell_quote($$_PRO_FILE_PWD_) --qmake-run init $$QPMX_EXTRA_OPTIONS $$shell_quote($$QMAKE_QMAKE) $$shell_quote($$OUT_PWD)): error(qpmx initialization failed. Check the compilation log for details.) | 
				
			|||
else: include($$OUT_PWD/qpmx_generated.pri) | 
				
			|||
 | 
				
			|||
qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvsettingsmcore_template.qm | 
				
			|||
qpmx_ts_target.files += translations/qtmvvsettingsmcore_template.ts | 
				
			|||
 | 
				
			|||
@ -0,0 +1,14 @@ | 
				
			|||
{ | 
				
			|||
    "dependencies": [], | 
				
			|||
    "license": { | 
				
			|||
        "file": "", | 
				
			|||
        "name": "" | 
				
			|||
    }, | 
				
			|||
    "prcFile": "", | 
				
			|||
    "priFile": "", | 
				
			|||
    "priIncludes": [ | 
				
			|||
    ], | 
				
			|||
    "publishers": { | 
				
			|||
    }, | 
				
			|||
    "source": false | 
				
			|||
} | 
				
			|||
@ -0,0 +1,23 @@ | 
				
			|||
#include "qtmvvmsettingscore_global.h" | 
				
			|||
#include <QtCore/QCoreApplication> | 
				
			|||
#include <QtMvvmCore/ServiceRegistry> | 
				
			|||
#include <QtMvvmCore/private/qtmvvm_logging_p.h> | 
				
			|||
 | 
				
			|||
#include "settingssetuploader_p.h" | 
				
			|||
 | 
				
			|||
using namespace QtMvvm; | 
				
			|||
 | 
				
			|||
namespace { | 
				
			|||
 | 
				
			|||
void qtMvvmSettingsCoreStartup() | 
				
			|||
{ | 
				
			|||
	try { | 
				
			|||
		ServiceRegistry::instance()->registerInterface<ISettingsSetupLoader, SettingsSetupLoader>(true); | 
				
			|||
	} catch(ServiceExistsException &e) { | 
				
			|||
		logDebug() << "Unable to register default ISettingsSetupLoader with error:" << e.what(); | 
				
			|||
	} | 
				
			|||
} | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
Q_COREAPP_STARTUP_FUNCTION(qtMvvmSettingsCoreStartup) | 
				
			|||
@ -0,0 +1,12 @@ | 
				
			|||
#ifndef QTMVVMSETTINGSCORE_GLOBAL_H | 
				
			|||
#define QTMVVMSETTINGSCORE_GLOBAL_H | 
				
			|||
 | 
				
			|||
#include <QtCore/qglobal.h> | 
				
			|||
 | 
				
			|||
#if defined(QT_BUILD_MVVMSETTINGSCORE_LIB) | 
				
			|||
#  define Q_MVVMSETTINGSCORE_EXPORT Q_DECL_EXPORT | 
				
			|||
#else | 
				
			|||
#  define Q_MVVMSETTINGSCORE_EXPORT Q_DECL_IMPORT | 
				
			|||
#endif | 
				
			|||
 | 
				
			|||
#endif // QTMVVMSETTINGSCORE_GLOBAL_H
 | 
				
			|||
@ -0,0 +1,83 @@ | 
				
			|||
#ifndef QTMVVM_SETTINGSSETUP_H | 
				
			|||
#define QTMVVM_SETTINGSSETUP_H | 
				
			|||
 | 
				
			|||
#include <QtCore/qstringlist.h> | 
				
			|||
#include <QtCore/qvariant.h> | 
				
			|||
#include <QtCore/qurl.h> | 
				
			|||
#include <QtCore/qobject.h> | 
				
			|||
#include <QtCore/qfileselector.h> | 
				
			|||
 | 
				
			|||
#include "QtMvvmSettingsCore/qtmvvmsettingscore_global.h" | 
				
			|||
 | 
				
			|||
namespace QtMvvm { | 
				
			|||
 | 
				
			|||
struct SettingsEntry | 
				
			|||
{ | 
				
			|||
	QString key; | 
				
			|||
	QByteArray type; | 
				
			|||
	QString title; | 
				
			|||
	QString tooltip; | 
				
			|||
	QVariant defaultValue; | 
				
			|||
	QStringList searchKeys; | 
				
			|||
	QVariantMap properties; | 
				
			|||
 | 
				
			|||
	QString frontends; | 
				
			|||
	QString selectors; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
struct SettingsGroup | 
				
			|||
{ | 
				
			|||
	QString title; | 
				
			|||
 | 
				
			|||
	QList<SettingsEntry> entries; | 
				
			|||
 | 
				
			|||
	QString frontends; | 
				
			|||
	QString selectors; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
struct SettingsSection | 
				
			|||
{ | 
				
			|||
	QString title; | 
				
			|||
	QUrl icon; | 
				
			|||
	QString tooltip; | 
				
			|||
 | 
				
			|||
	QList<SettingsGroup> groups; | 
				
			|||
 | 
				
			|||
	QString frontends; | 
				
			|||
	QString selectors; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
struct SettingsCategory | 
				
			|||
{ | 
				
			|||
	QString title; | 
				
			|||
	QUrl icon; | 
				
			|||
	QString tooltip; | 
				
			|||
 | 
				
			|||
	QList<SettingsSection> sections; | 
				
			|||
 | 
				
			|||
	QString frontends; | 
				
			|||
	QString selectors; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
struct SettingsSetup | 
				
			|||
{ | 
				
			|||
	bool allowSearch = false; | 
				
			|||
	bool allowRestore = false; | 
				
			|||
 | 
				
			|||
	QList<SettingsCategory> categories; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
class ISettingsSetupLoader | 
				
			|||
{ | 
				
			|||
public: | 
				
			|||
	virtual inline ~ISettingsSetupLoader() = default; | 
				
			|||
 | 
				
			|||
	virtual SettingsSetup loadSetup(const QString &platform, const QFileSelector *selector, const QString &filePath) const = 0; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
#define QtMvvm_ISettingsSetupLoaderIid "de.skycoder42.qtmvvm.settings.core.ISettingsSetupLoader" | 
				
			|||
Q_DECLARE_INTERFACE(QtMvvm::ISettingsSetupLoader, QtMvvm_ISettingsSetupLoaderIid) | 
				
			|||
 | 
				
			|||
#endif // QTMVVM_SETTINGSSETUP_H
 | 
				
			|||
@ -0,0 +1,400 @@ | 
				
			|||
#include "settingssetuploader_p.h" | 
				
			|||
using namespace QtMvvm; | 
				
			|||
 | 
				
			|||
#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") | 
				
			|||
 | 
				
			|||
QUrl SettingsSetupLoader::defaultIcon(QStringLiteral("qrc:/qtmvvm/icons/settings.svg")); | 
				
			|||
 | 
				
			|||
SettingsSetupLoader::SettingsSetupLoader(QObject *parent) : | 
				
			|||
	QObject(parent), | 
				
			|||
	_cache() | 
				
			|||
{} | 
				
			|||
 | 
				
			|||
SettingsSetup SettingsSetupLoader::loadSetup(const QString &platform, const QFileSelector *selector, const QString &filePath) const | 
				
			|||
{ | 
				
			|||
	SettingsSetup setup; | 
				
			|||
	if(!_cache.contains(filePath)) { | 
				
			|||
		QFile file(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"); | 
				
			|||
		setup.allowSearch = reader.boolValue("allowSearch"); | 
				
			|||
		setup.allowRestore = reader.boolValue("allowRestore"); | 
				
			|||
 | 
				
			|||
		if(reader.readNextStartElement()) { | 
				
			|||
			if(reader.name() == QStringLiteral("Category")) { | 
				
			|||
				do | 
				
			|||
					setup.categories.append(readCategory(reader)); | 
				
			|||
				while(reader.readNextStartElement()); | 
				
			|||
			} else | 
				
			|||
				setup.categories.append(readDefaultCategory(reader)); | 
				
			|||
		} | 
				
			|||
		testXmlValid(reader); | 
				
			|||
		file.close(); | 
				
			|||
 | 
				
			|||
		_cache.insert(filePath, new SettingsSetup(setup)); | 
				
			|||
	} else | 
				
			|||
		setup = *(_cache.object(filePath)); | 
				
			|||
 | 
				
			|||
	//todo platform/selector
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
	return setup; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsCategory SettingsSetupLoader::readCategory(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	if(reader.name() != QStringLiteral("Category")) | 
				
			|||
		throwElement(reader, "Category"); | 
				
			|||
 | 
				
			|||
	auto category = createDefaultCategory(); | 
				
			|||
 | 
				
			|||
	if(reader.hasValue("title")) | 
				
			|||
		category.title = reader.stringValue("title"); | 
				
			|||
	if(reader.hasValue("icon")) | 
				
			|||
		category.icon = reader.stringValue("icon"); | 
				
			|||
	if(reader.hasValue("tooltip")) | 
				
			|||
		category.tooltip = reader.stringValue("tooltip"); | 
				
			|||
	category.frontends = reader.stringValue("frontends"); | 
				
			|||
	category.selectors = reader.stringValue("selectors"); | 
				
			|||
 | 
				
			|||
	if(reader.readNextStartElement()) { | 
				
			|||
		if(reader.name() == QStringLiteral("Section")) { | 
				
			|||
			do | 
				
			|||
				category.sections.append(readSection(reader)); | 
				
			|||
			while(reader.readNextStartElement()); | 
				
			|||
		} else | 
				
			|||
			category.sections.append(readDefaultSection(reader)); | 
				
			|||
	} | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return category; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsCategory SettingsSetupLoader::readDefaultCategory(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	auto category = createDefaultCategory(); | 
				
			|||
	if(reader.name() == QStringLiteral("Section")) { | 
				
			|||
		do | 
				
			|||
			category.sections.append(readSection(reader)); | 
				
			|||
		while(reader.readNextStartElement()); | 
				
			|||
	} else | 
				
			|||
		category.sections.append(readDefaultSection(reader)); | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return category; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsSection SettingsSetupLoader::readSection(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	if(reader.name() != QStringLiteral("Section")) | 
				
			|||
		throwElement(reader, "Section"); | 
				
			|||
 | 
				
			|||
	auto section = createDefaultSection(); | 
				
			|||
 | 
				
			|||
	if(reader.hasValue("title")) | 
				
			|||
		section.title = reader.stringValue("title"); | 
				
			|||
	if(reader.hasValue("icon")) | 
				
			|||
		section.icon = reader.stringValue("icon"); | 
				
			|||
	if(reader.hasValue("tooltip")) | 
				
			|||
		section.tooltip = reader.stringValue("tooltip"); | 
				
			|||
	section.frontends = reader.stringValue("frontends"); | 
				
			|||
	section.selectors = reader.stringValue("selectors"); | 
				
			|||
 | 
				
			|||
	if(reader.readNextStartElement()) { | 
				
			|||
		if(reader.name() == QStringLiteral("Group")) { | 
				
			|||
			do | 
				
			|||
				section.groups.append(readGroup(reader)); | 
				
			|||
			while(reader.readNextStartElement()); | 
				
			|||
		} else | 
				
			|||
			section.groups.append(readDefaultGroup(reader)); | 
				
			|||
	} | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return section; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsSection SettingsSetupLoader::readDefaultSection(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	auto section = createDefaultSection(); | 
				
			|||
 | 
				
			|||
	if(reader.name() == QStringLiteral("Group")) { | 
				
			|||
		do | 
				
			|||
			section.groups.append(readGroup(reader)); | 
				
			|||
		while(reader.readNextStartElement()); | 
				
			|||
	} else | 
				
			|||
		section.groups.append(readDefaultGroup(reader)); | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return section; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsGroup SettingsSetupLoader::readGroup(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	if(reader.name() != QStringLiteral("Group")) | 
				
			|||
		throwElement(reader, "Group"); | 
				
			|||
 | 
				
			|||
	SettingsGroup group; | 
				
			|||
	if(reader.hasValue("title")) | 
				
			|||
		group.title = reader.stringValue("title"); | 
				
			|||
	group.frontends = reader.stringValue("frontends"); | 
				
			|||
	group.selectors = reader.stringValue("selectors"); | 
				
			|||
 | 
				
			|||
	if(reader.readNextStartElement()) { | 
				
			|||
		if(reader.name() == QStringLiteral("Entry")) { | 
				
			|||
			do | 
				
			|||
				group.entries.append(readEntry(reader)); | 
				
			|||
			while(reader.readNextStartElement()); | 
				
			|||
		} else | 
				
			|||
			throwElement(reader, "Entry"); | 
				
			|||
	} | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return group; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsGroup SettingsSetupLoader::readDefaultGroup(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	SettingsGroup group; | 
				
			|||
 | 
				
			|||
	if(reader.name() == QStringLiteral("Entry")) { | 
				
			|||
		do | 
				
			|||
			group.entries.append(readEntry(reader)); | 
				
			|||
		while(reader.readNextStartElement()); | 
				
			|||
	} else | 
				
			|||
		throwElement(reader, "Entry"); | 
				
			|||
	testXmlValid(reader); | 
				
			|||
 | 
				
			|||
	return group; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsEntry SettingsSetupLoader::readEntry(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	testXmlValid(reader); | 
				
			|||
	SettingsEntry 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 = reader.stringValue("title"); | 
				
			|||
	entry.tooltip = reader.stringValue("tooltip"); | 
				
			|||
	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(reader.readElementText()); | 
				
			|||
		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; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsCategory SettingsSetupLoader::createDefaultCategory() const | 
				
			|||
{ | 
				
			|||
	SettingsCategory category; | 
				
			|||
	category.title = tr("General Settings"); | 
				
			|||
	category.icon = defaultIcon; | 
				
			|||
	return category; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
SettingsSection SettingsSetupLoader::createDefaultSection() const | 
				
			|||
{ | 
				
			|||
	SettingsSection section; | 
				
			|||
	section.title = tr("General"); | 
				
			|||
	return section; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
std::tuple<QString, QVariant> SettingsSetupLoader::readProperty(QXmlStreamReader &reader) const | 
				
			|||
{ | 
				
			|||
	if(!reader.hasValue("key")) | 
				
			|||
		throwAttrib(reader, "key"); | 
				
			|||
	return std::make_tuple(reader.stringValue("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 = reader.readElementText(); | 
				
			|||
	if(!mVariant.convert(typeId)) | 
				
			|||
		throwXmlError(reader, "Failed to convert element data to type: " + type.toUtf8()); | 
				
			|||
 | 
				
			|||
	return mVariant; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void SettingsSetupLoader::clearSetup(SettingsSetup &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(SettingsCategory &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(SettingsSection §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(SettingsGroup &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(auto select : selects) { | 
				
			|||
		auto sels = select.split(QLatin1Char('&'), QString::SkipEmptyParts); | 
				
			|||
		auto allSelected = true; | 
				
			|||
		for(auto sel : sels) { | 
				
			|||
			if(!selectors.contains(sel)) { | 
				
			|||
				allSelected = false; | 
				
			|||
				break; | 
				
			|||
			} | 
				
			|||
		} | 
				
			|||
 | 
				
			|||
		if(allSelected) | 
				
			|||
			return true; | 
				
			|||
	} | 
				
			|||
 | 
				
			|||
	return selects.isEmpty(); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
SettingsXmlException::SettingsXmlException(const QXmlStreamReader &reader) : | 
				
			|||
	_what(QStringLiteral("XML Error at %1:%2. Error: %3") | 
				
			|||
		  .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) : | 
				
			|||
	_what(QStringLiteral("Failed to open file \"%1\" with error: %2") | 
				
			|||
		  .arg(fileError.fileName()) | 
				
			|||
		  .arg(fileError.errorString()) | 
				
			|||
		  .toUtf8()) | 
				
			|||
{} | 
				
			|||
 | 
				
			|||
SettingsXmlException::SettingsXmlException(const SettingsXmlException * const other) : | 
				
			|||
	_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); | 
				
			|||
} | 
				
			|||
@ -0,0 +1,81 @@ | 
				
			|||
#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/QException> | 
				
			|||
#include <QtCore/QFile> | 
				
			|||
 | 
				
			|||
#include "qtmvvmsettingscore_global.h" | 
				
			|||
#include "settingssetup.h" | 
				
			|||
 | 
				
			|||
namespace QtMvvm { | 
				
			|||
 | 
				
			|||
class SettingsSetupLoader : public QObject, public ISettingsSetupLoader | 
				
			|||
{ | 
				
			|||
	Q_OBJECT | 
				
			|||
	Q_INTERFACES(QtMvvm::ISettingsSetupLoader) | 
				
			|||
 | 
				
			|||
public: | 
				
			|||
	SettingsSetupLoader(QObject *parent = nullptr); | 
				
			|||
 | 
				
			|||
	SettingsSetup loadSetup(const QString &platform, const QFileSelector *selector, const QString &filePath) const override; | 
				
			|||
 | 
				
			|||
private: | 
				
			|||
	static QUrl defaultIcon; | 
				
			|||
 | 
				
			|||
	mutable QCache<QString, SettingsSetup> _cache; | 
				
			|||
 | 
				
			|||
	//functions to read the settings XML
 | 
				
			|||
	SettingsCategory readCategory(QXmlStreamReader &reader) const; | 
				
			|||
	SettingsCategory readDefaultCategory(QXmlStreamReader &reader) const; | 
				
			|||
 | 
				
			|||
	SettingsSection readSection(QXmlStreamReader &reader) const; | 
				
			|||
	SettingsSection readDefaultSection(QXmlStreamReader &reader) const; | 
				
			|||
 | 
				
			|||
	SettingsGroup readGroup(QXmlStreamReader &reader) const; | 
				
			|||
	SettingsGroup readDefaultGroup(QXmlStreamReader &reader) const; | 
				
			|||
 | 
				
			|||
	SettingsEntry readEntry(QXmlStreamReader &reader) const; | 
				
			|||
 | 
				
			|||
	SettingsCategory createDefaultCategory() const; | 
				
			|||
	SettingsSection createDefaultSection() const; | 
				
			|||
 | 
				
			|||
	std::tuple<QString, QVariant> readProperty(QXmlStreamReader &reader) const; | 
				
			|||
	QVariant readElement(QXmlStreamReader &reader) const; | 
				
			|||
 | 
				
			|||
	//Functions to filter the elements
 | 
				
			|||
	void clearSetup(SettingsSetup &setup, const QString &frontend, const QStringList &selectors) const; | 
				
			|||
	void clearCategory(SettingsCategory &category, const QString &frontend, const QStringList &selectors) const; | 
				
			|||
	void clearSection(SettingsSection §ion, const QString &frontend, const QStringList &selectors) const; | 
				
			|||
	void clearGroup(SettingsGroup &group, const QString &frontend, const QStringList &selectors) const; | 
				
			|||
	template <typename T> | 
				
			|||
	bool isUsable(const T &configElement, const QString &frontend, const QStringList &selectors) const; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
class SettingsXmlException : public QException | 
				
			|||
{ | 
				
			|||
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,54 @@ | 
				
			|||
#include "settingsviewmodel.h" | 
				
			|||
#include "settingsviewmodel_p.h" | 
				
			|||
#include <QtMvvmCore/CoreApp> | 
				
			|||
#include <QtMvvmCore/private/qtmvvm_logging_p.h> | 
				
			|||
 | 
				
			|||
#include "settingssetuploader_p.h" | 
				
			|||
 | 
				
			|||
using namespace QtMvvm; | 
				
			|||
 | 
				
			|||
SettingsViewModel::SettingsViewModel(QObject *parent) : | 
				
			|||
	ViewModel(parent), | 
				
			|||
	d(new SettingsViewModelPrivate()) | 
				
			|||
{} | 
				
			|||
 | 
				
			|||
SettingsViewModel::~SettingsViewModel() {} | 
				
			|||
 | 
				
			|||
void SettingsViewModel::showSettings(ViewModel *parent) | 
				
			|||
{ | 
				
			|||
	showSettings(nullptr, {}, parent); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void SettingsViewModel::showSettings(QSettings *settings, const QString &setupFile, ViewModel *parent) | 
				
			|||
{ | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
bool SettingsViewModel::canRestoreDefaults() const | 
				
			|||
{ | 
				
			|||
	return true; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
ISettingsSetupLoader *SettingsViewModel::settingsSetupLoader() const | 
				
			|||
{ | 
				
			|||
	return d->settingsSetupLoader; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void SettingsViewModel::callAction(const QString &entryId) | 
				
			|||
{ | 
				
			|||
	logWarning() << "Unknown action requested with entry id:" << entryId; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void SettingsViewModel::setSettingsSetupLoader(ISettingsSetupLoader *settingsSetupLoader) | 
				
			|||
{ | 
				
			|||
	if (d->settingsSetupLoader == settingsSetupLoader) | 
				
			|||
		return; | 
				
			|||
 | 
				
			|||
	d->settingsSetupLoader = settingsSetupLoader; | 
				
			|||
	emit settingsSetupLoaderChanged(d->settingsSetupLoader); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
void SettingsViewModel::onInit(const QVariantHash ¶ms) | 
				
			|||
{ | 
				
			|||
 | 
				
			|||
} | 
				
			|||
@ -0,0 +1,52 @@ | 
				
			|||
#ifndef QTMVVM_SETTINGSVIEWMODEL_H | 
				
			|||
#define QTMVVM_SETTINGSVIEWMODEL_H | 
				
			|||
 | 
				
			|||
#include <QtCore/qsettings.h> | 
				
			|||
#include <QtCore/qscopedpointer.h> | 
				
			|||
 | 
				
			|||
#include <QtMvvmCore/viewmodel.h> | 
				
			|||
 | 
				
			|||
#include "QtMvvmSettingsCore/qtmvvmsettingscore_global.h" | 
				
			|||
#include "QtMvvmSettingsCore/settingssetuploader.h" | 
				
			|||
 | 
				
			|||
namespace QtMvvm { | 
				
			|||
 | 
				
			|||
class SettingsViewModelPrivate; | 
				
			|||
class SettingsViewModel : public ViewModel | 
				
			|||
{ | 
				
			|||
	Q_OBJECT | 
				
			|||
 | 
				
			|||
	Q_PROPERTY(bool canRestoreDefaults READ canRestoreDefaults CONSTANT) | 
				
			|||
 | 
				
			|||
	Q_PROPERTY(QtMvvm::ISettingsSetupLoader* settingsSetupLoader READ settingsSetupLoader WRITE setSettingsSetupLoader NOTIFY settingsSetupLoaderChanged) | 
				
			|||
	QTMVVM_INJECT(QtMvvm::ISettingsSetupLoader*, settingsSetupLoader) | 
				
			|||
 | 
				
			|||
public: | 
				
			|||
	Q_INVOKABLE explicit SettingsViewModel(QObject *parent = nullptr); | 
				
			|||
	~SettingsViewModel(); | 
				
			|||
 | 
				
			|||
	static void showSettings(ViewModel *parent); | 
				
			|||
	static void showSettings(QSettings *settings = nullptr, const QString &setupFile = {}, ViewModel *parent = nullptr); | 
				
			|||
 | 
				
			|||
	virtual bool canRestoreDefaults() const; | 
				
			|||
 | 
				
			|||
	QtMvvm::ISettingsSetupLoader* settingsSetupLoader() const; | 
				
			|||
 | 
				
			|||
public Q_SLOTS: | 
				
			|||
	virtual void callAction(const QString &entryId); | 
				
			|||
 | 
				
			|||
	void setSettingsSetupLoader(QtMvvm::ISettingsSetupLoader* settingsSetupLoader); | 
				
			|||
 | 
				
			|||
Q_SIGNALS: | 
				
			|||
	void settingsSetupLoaderChanged(QtMvvm::ISettingsSetupLoader* settingsSetupLoader); | 
				
			|||
 | 
				
			|||
protected: | 
				
			|||
	void onInit(const QVariantHash ¶ms) override; | 
				
			|||
 | 
				
			|||
private: | 
				
			|||
	QScopedPointer<SettingsViewModelPrivate> d; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
#endif // QTMVVM_SETTINGSVIEWMODEL_H
 | 
				
			|||
@ -0,0 +1,17 @@ | 
				
			|||
#ifndef QTMVVM_SETTINGSVIEWMODEL_P_H | 
				
			|||
#define QTMVVM_SETTINGSVIEWMODEL_P_H | 
				
			|||
 | 
				
			|||
#include "qtmvvmsettingscore_global.h" | 
				
			|||
#include "settingsviewmodel.h" | 
				
			|||
 | 
				
			|||
namespace QtMvvm { | 
				
			|||
 | 
				
			|||
class SettingsViewModelPrivate | 
				
			|||
{ | 
				
			|||
public: | 
				
			|||
	ISettingsSetupLoader *settingsSetupLoader = nullptr; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
#endif // QTMVVM_SETTINGSVIEWMODEL_P_H
 | 
				
			|||
					Loading…
					
					
				
		Reference in new issue