Browse Source

added first settingsloader code

pull/2/head
Skycoder42 7 years ago
parent
commit
18d18771e1
  1. 14
      examples/mvvmcore/SampleCore/SampleCore.pro
  2. 12
      examples/mvvmwidgets/SampleWidgets/SampleWidgets.pro
  3. 2
      src/mvvmcore/ipresenter.h
  4. 1
      src/mvvmcore/mvvmcore.pro
  5. 10
      src/mvvmcore/qtmvvm_logging_p.h
  6. 4
      src/mvvmcore/qtmvvmcore_global.cpp
  7. 37
      src/mvvmcore/serviceregistry.cpp
  8. 42
      src/mvvmcore/serviceregistry.h
  9. 9
      src/mvvmcore/serviceregistry_p.h
  10. 1
      src/mvvmquick/mvvmquick.pro
  11. 40
      src/mvvmsettingscore/mvvmsettingscore.pro
  12. 14
      src/mvvmsettingscore/qpmx.json
  13. 23
      src/mvvmsettingscore/qtmvvmsettingscore_global.cpp
  14. 12
      src/mvvmsettingscore/qtmvvmsettingscore_global.h
  15. 83
      src/mvvmsettingscore/settingssetup.h
  16. 400
      src/mvvmsettingscore/settingssetuploader.cpp
  17. 81
      src/mvvmsettingscore/settingssetuploader_p.h
  18. 54
      src/mvvmsettingscore/settingsviewmodel.cpp
  19. 52
      src/mvvmsettingscore/settingsviewmodel.h
  20. 17
      src/mvvmsettingscore/settingsviewmodel_p.h
  21. 1
      src/mvvmwidgets/mvvmwidgets.pro
  22. 3
      src/src.pro
  23. 3
      sync.profile

14
examples/mvvmcore/SampleCore/SampleCore.pro

@ -1,6 +1,6 @@
TEMPLATE = lib
QT = core gui mvvmcore
QT = core gui mvvmcore mvvmsettingscore
CONFIG += static
TARGET = SampleCore
@ -10,17 +10,17 @@ HEADERS += \
sampleviewmodel.h \
ieventservice.h \
echoservice.h \
resultviewmodel.h \
drawerviewmodel.h \
tabviewmodel.h
resultviewmodel.h \
drawerviewmodel.h \
tabviewmodel.h
SOURCES += \
samplecoreapp.cpp \
sampleviewmodel.cpp \
echoservice.cpp \
resultviewmodel.cpp \
drawerviewmodel.cpp \
tabviewmodel.cpp
resultviewmodel.cpp \
drawerviewmodel.cpp \
tabviewmodel.cpp
target.path = $$[QT_INSTALL_EXAMPLES]/mvvmcore/$$TARGET
INSTALLS += target

12
examples/mvvmwidgets/SampleWidgets/SampleWidgets.pro

@ -8,22 +8,22 @@ HEADERS += \
widgetseventservice.h \
sampleview.h \
resultdialog.h \
tabview.h \
tabitemview.h
tabview.h \
tabitemview.h
SOURCES += \
main.cpp \
widgetseventservice.cpp \
sampleview.cpp \
resultdialog.cpp \
tabview.cpp \
tabitemview.cpp
tabview.cpp \
tabitemview.cpp
FORMS += \
sampleview.ui \
resultdialog.ui \
tabview.ui \
tabitemview.ui
tabview.ui \
tabitemview.ui
target.path = $$[QT_INSTALL_EXAMPLES]/mvvmwidgets/$$TARGET
INSTALLS += target

2
src/mvvmcore/ipresenter.h

@ -25,7 +25,7 @@ protected:
const QByteArray _what;
};
class Q_MVVMCORE_EXPORT IPresenter
class Q_MVVMCORE_EXPORT IPresenter //TODO use via service registry EVERYWHERE
{
public:
inline virtual ~IPresenter() = default;

1
src/mvvmcore/mvvmcore.pro

@ -35,7 +35,6 @@ DISTFILES += $$TRANSLATIONS
qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS]
qpmx_ts_target.depends += lrelease
!mingw: INSTALLS += qpmx_ts_target
load(qt_module)

10
src/mvvmcore/qtmvvm_logging_p.h

@ -7,13 +7,13 @@
namespace QtMvvm {
Q_MVVMCORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(mvvmcore)
Q_MVVMCORE_EXPORT Q_DECLARE_LOGGING_CATEGORY(mvvmLoggingCat)
}
#define logDebug(...) qCDebug(mvvmcore, __VA_ARGS__)
#define logInfo(...) qCInfo(mvvmcore, __VA_ARGS__)
#define logWarning(...) qCWarning(mvvmcore, __VA_ARGS__)
#define logCritical(...) qCCritical(mvvmcore, __VA_ARGS__)
#define logDebug(...) qCDebug(mvvmLoggingCat, __VA_ARGS__)
#define logInfo(...) qCInfo(mvvmLoggingCat, __VA_ARGS__)
#define logWarning(...) qCWarning(mvvmLoggingCat, __VA_ARGS__)
#define logCritical(...) qCCritical(mvvmLoggingCat, __VA_ARGS__)
#endif // QTMVVM_LOGGING_P_H

4
src/mvvmcore/qtmvvmcore_global.cpp

@ -4,9 +4,9 @@
namespace QtMvvm {
#ifdef QT_NO_DEBUG
Q_LOGGING_CATEGORY(mvvmcore, "qtmvvm", QtInfoMsg)
Q_LOGGING_CATEGORY(mvvmLoggingCat, "qtmvvm", QtInfoMsg)
#else
Q_LOGGING_CATEGORY(mvvmcore, "qtmvvm", QtDebugMsg)
Q_LOGGING_CATEGORY(mvvmLoggingCat, "qtmvvm", QtDebugMsg)
#endif
}

37
src/mvvmcore/serviceregistry.cpp

@ -20,20 +20,20 @@ ServiceRegistry *ServiceRegistry::instance()
return _instance;
}
void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject)
void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak)
{
QMutexLocker _(&d->serviceMutex);
if(d->services.contains(iid))
if(d->serviceBlocked(iid))
throw ServiceExistsException(iid);
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::MetaServiceInfo>::create(metaObject));
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::MetaServiceInfo>::create(metaObject, weak));
}
void ServiceRegistry::registerService(const QByteArray &iid, const std::function<QObject*(const QObjectList &)> &fn, QByteArrayList injectables)
void ServiceRegistry::registerService(const QByteArray &iid, const std::function<QObject*(const QObjectList &)> &fn, QByteArrayList injectables, bool weak)
{
QMutexLocker _(&d->serviceMutex);
if(d->services.contains(iid))
if(d->serviceBlocked(iid))
throw ServiceExistsException(iid);
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::FnServiceInfo>::create(fn, injectables));
d->services.insert(iid, QSharedPointer<ServiceRegistryPrivate::FnServiceInfo>::create(fn, injectables, weak));
}
QObject *ServiceRegistry::serviceObj(const QByteArray &iid)
@ -53,6 +53,15 @@ ServiceRegistryPrivate::ServiceRegistryPrivate() :
services()
{}
bool ServiceRegistryPrivate::serviceBlocked(const QByteArray &iid) const
{
auto svc = services.value(iid);
if(svc)
return !svc->replaceable();
else
return false;
}
QObject *ServiceRegistryPrivate::constructInjected(const QMetaObject *metaObject)
{
auto &d = ServiceRegistry::instance()->d;
@ -111,14 +120,20 @@ QObject *ServiceRegistryPrivate::constructInjectedLocked(const QMetaObject *meta
ServiceRegistryPrivate::ServiceInfo::ServiceInfo() :
ServiceRegistryPrivate::ServiceInfo::ServiceInfo(bool weak) :
_weak(weak),
_instance(nullptr)
{}
ServiceRegistryPrivate::ServiceInfo::~ServiceInfo()
{
if(_instance)
QMetaObject::invokeMethod(_instance, "deleteLater");
QMetaObject::invokeMethod(_instance, "deleteLater"); //TODO doesnt work out of eventloop, maybe test first?
}
bool ServiceRegistryPrivate::ServiceInfo::replaceable() const
{
return _weak && !_instance;
}
QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d, const QByteArray &iid)
@ -136,7 +151,8 @@ QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d
ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(const std::function<QObject*(QObjectList)> &creator, const QByteArrayList &injectables) :
ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(const std::function<QObject*(QObjectList)> &creator, const QByteArrayList &injectables, bool weak) :
ServiceInfo(weak),
creator(creator),
injectables(injectables)
{}
@ -155,7 +171,8 @@ QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate
ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject) :
ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject, bool weak) :
ServiceInfo(weak),
metaObject(metaObject)
{}

42
src/mvvmcore/serviceregistry.h

@ -20,23 +20,25 @@ public:
static ServiceRegistry* instance();
template <typename TInterface, typename TService>
void registerInterface();
void registerInterface(bool weak = false);
template <typename TInterface, typename TService, typename TFunc>
void registerInterface(const TFunc &fn);
void registerInterface(const TFunc &fn, bool weak = false);
template <typename TInterface, typename TService>
void registerInterface(TService *service);
void registerInterface(TService *service, bool weak = false);
template <typename TService>
void registerObject();
void registerObject(bool weak = false);
template <typename TService, typename TFunc>
void registerObject(const TFunc &fn);
void registerObject(const TFunc &fn, bool weak = false);
template <typename TService>
void registerObject(TService *service);
void registerObject(TService *service, bool weak = false);
void registerService(const QByteArray &iid,
const QMetaObject *metaObject);
const QMetaObject *metaObject,
bool weak = false);
void registerService(const QByteArray &iid,
const std::function<QObject*(const QObjectList &)> &fn,
QByteArrayList injectables);
QByteArrayList injectables,
bool weak = false);
template <typename TInterface>
TInterface *service();
@ -98,29 +100,29 @@ protected:
Q_ASSERT_X(qobject_interface_iid<TInterface*>(), Q_FUNC_INFO, "TInterface must be registered with Q_DECLARE_INTERFACE");
template<typename TInterface, typename TService>
void ServiceRegistry::registerInterface()
void ServiceRegistry::registerInterface(bool weak)
{
QTMVVM_SERVICE_ASSERT(TInterface, TService)
registerService(qobject_interface_iid<TInterface*>(), &TService::staticMetaObject);
registerService(qobject_interface_iid<TInterface*>(), &TService::staticMetaObject, weak);
}
template <typename TInterface, typename TService, typename TFunc>
void ServiceRegistry::registerInterface(const TFunc &fn)
void ServiceRegistry::registerInterface(const TFunc &fn, bool weak)
{
QTMVVM_SERVICE_ASSERT(TInterface, TService)
QByteArrayList injectables;
auto packed_fn = __helpertypes::pack_function(fn, injectables);
registerService(qobject_interface_iid<TInterface*>(), packed_fn, injectables);
registerService(qobject_interface_iid<TInterface*>(), packed_fn, injectables, weak);
}
template<typename TInterface, typename TService>
void ServiceRegistry::registerInterface(TService *service)
void ServiceRegistry::registerInterface(TService *service, bool weak)
{
QTMVVM_SERVICE_ASSERT(TInterface, TService)
registerService(qobject_interface_iid<TInterface*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params);
return service;
}, QByteArrayList());
}, QByteArrayList(), weak);
}
#undef QTMVVM_SERVICE_ASSERT
@ -128,29 +130,29 @@ void ServiceRegistry::registerInterface(TService *service)
static_assert(__helpertypes::is_qobj<tsvc>::value, "TService must be a qobject class");
template<typename TService>
void ServiceRegistry::registerObject()
void ServiceRegistry::registerObject(bool weak)
{
QTMVVM_SERVICE_ASSERT(TService)
registerService(__helpertypes::qobject_iid<TService*>(), &TService::staticMetaObject);
registerService(__helpertypes::qobject_iid<TService*>(), &TService::staticMetaObject, weak);
}
template<typename TService, typename TFunc>
void ServiceRegistry::registerObject(const TFunc &fn)
void ServiceRegistry::registerObject(const TFunc &fn, bool weak)
{
QTMVVM_SERVICE_ASSERT(TService)
QByteArrayList injectables;
auto packed_fn = __helpertypes::pack_function(fn, injectables);
registerService(__helpertypes::qobject_iid<TService*>(), packed_fn, injectables);
registerService(__helpertypes::qobject_iid<TService*>(), packed_fn, injectables, weak);
}
template<typename TService>
void ServiceRegistry::registerObject(TService *service)
void ServiceRegistry::registerObject(TService *service, bool weak)
{
QTMVVM_SERVICE_ASSERT(TService)
registerService(__helpertypes::qobject_iid<TService*>(), [service](const QObjectList &params) -> QObject* {
Q_UNUSED(params);
return service;
}, QByteArrayList());
}, QByteArrayList(), weak);
}
#undef QTMVVM_SERVICE_ASSERT

9
src/mvvmcore/serviceregistry_p.h

@ -14,21 +14,23 @@ class ServiceRegistryPrivate
public:
class ServiceInfo {
public:
ServiceInfo();
ServiceInfo(bool weak);
virtual ~ServiceInfo();
bool replaceable() const;
QObject *instance(ServiceRegistryPrivate *d, const QByteArray &iid);
protected:
virtual QObject *construct(ServiceRegistryPrivate *d) const = 0;
private:
const bool _weak;
QObject *_instance;
};
class FnServiceInfo : public ServiceInfo {
public:
FnServiceInfo(const std::function<QObject*(QObjectList)> &creator, const QByteArrayList &injectables);
FnServiceInfo(const std::function<QObject*(QObjectList)> &creator, const QByteArrayList &injectables, bool weak);
protected:
QObject *construct(ServiceRegistryPrivate *d) const final;
@ -40,7 +42,7 @@ public:
class MetaServiceInfo : public ServiceInfo {
public:
MetaServiceInfo(const QMetaObject *metaObject);
MetaServiceInfo(const QMetaObject *metaObject, bool weak);
protected:
QObject *construct(ServiceRegistryPrivate *d) const final;
@ -54,6 +56,7 @@ public:
ServiceRegistryPrivate();
bool serviceBlocked(const QByteArray &iid) const;
static QObject *constructInjected(const QMetaObject *metaObject);
QObject *constructInjectedLocked(const QMetaObject *metaObject);
};

1
src/mvvmquick/mvvmquick.pro

@ -24,7 +24,6 @@ DISTFILES += $$TRANSLATIONS
qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS]
qpmx_ts_target.depends += lrelease
!mingw: INSTALLS += qpmx_ts_target
load(qt_module)

40
src/mvvmsettingscore/mvvmsettingscore.pro

@ -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

14
src/mvvmsettingscore/qpmx.json

@ -0,0 +1,14 @@
{
"dependencies": [],
"license": {
"file": "",
"name": ""
},
"prcFile": "",
"priFile": "",
"priIncludes": [
],
"publishers": {
},
"source": false
}

23
src/mvvmsettingscore/qtmvvmsettingscore_global.cpp

@ -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)

12
src/mvvmsettingscore/qtmvvmsettingscore_global.h

@ -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

83
src/mvvmsettingscore/settingssetup.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

400
src/mvvmsettingscore/settingssetuploader.cpp

@ -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 &section, 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);
}

81
src/mvvmsettingscore/settingssetuploader_p.h

@ -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 &section, 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

54
src/mvvmsettingscore/settingsviewmodel.cpp

@ -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 &params)
{
}

52
src/mvvmsettingscore/settingsviewmodel.h

@ -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 &params) override;
private:
QScopedPointer<SettingsViewModelPrivate> d;
};
}
#endif // QTMVVM_SETTINGSVIEWMODEL_H

17
src/mvvmsettingscore/settingsviewmodel_p.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

1
src/mvvmwidgets/mvvmwidgets.pro

@ -26,7 +26,6 @@ DISTFILES += $$TRANSLATIONS
qpmx_ts_target.path = $$[QT_INSTALL_TRANSLATIONS]
qpmx_ts_target.depends += lrelease
!mingw: INSTALLS += qpmx_ts_target
load(qt_module)

3
src/src.pro

@ -4,7 +4,8 @@ CONFIG += ordered
SUBDIRS += mvvmcore \
mvvmwidgets \
mvvmquick \
imports
imports \
mvvmsettingscore
prepareRecursiveTarget(lrelease)
QMAKE_EXTRA_TARGETS += lrelease

3
sync.profile

@ -1,7 +1,8 @@
%modules = (
"QtMvvmCore" => "$basedir/src/mvvmcore",
"QtMvvmWidgets" => "$basedir/src/mvvmwidgets",
"QtMvvmQuick" => "$basedir/src/mvvmquick"
"QtMvvmQuick" => "$basedir/src/mvvmquick",
"QtMvvmSettingsCore" => "$basedir/src/mvvmsettingscore"
);
# Force generation of camel case headers for classes inside QtDataSync namespaces

Loading…
Cancel
Save