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