From b94b97b14586d7c39e0589cd664ad0f00ed08559 Mon Sep 17 00:00:00 2001 From: Iceyer Date: Mon, 23 Oct 2017 20:21:29 +0800 Subject: [PATCH] feat: create gsettingsbackend Change-Id: I6ed1ef01205c31814f53a427e84b8b24fe96a7a6 --- src/settings/backend/gsettingsbackend.cpp | 101 ++++++++++++++ src/settings/backend/gsettingsbackend.h | 30 +++++ src/settings/backend/qsettingbackend.cpp | 7 +- src/settings/dsettings.cpp | 28 ++-- src/settings/dsettings.h | 1 + src/settings/dsettingsbackend.h | 6 +- src/settings/settings.pri | 6 +- src/src.pro | 2 + tests/tests.pro | 3 +- tool/settings/main.cpp | 154 +++++++++++++++++++++- tool/settings/settings.pro | 3 +- 11 files changed, 320 insertions(+), 21 deletions(-) create mode 100644 src/settings/backend/gsettingsbackend.cpp create mode 100644 src/settings/backend/gsettingsbackend.h diff --git a/src/settings/backend/gsettingsbackend.cpp b/src/settings/backend/gsettingsbackend.cpp new file mode 100644 index 0000000..71278ba --- /dev/null +++ b/src/settings/backend/gsettingsbackend.cpp @@ -0,0 +1,101 @@ +#include "gsettingsbackend.h" + +#include +#include +#include +#include +#include +#include + +#include + +DCORE_BEGIN_NAMESPACE + + +QString unqtifyName(const QString &name) +{ + QString ret; + for (auto p : name) { + const QChar c(p); + if (c.isUpper()) { + ret.append("-"); + ret.append(c.toLower().toLatin1()); + } else { + ret.append(c); + } + } + return ret; +} + +QString qtifyName(const QString &key) +{ + return QString(key).replace(".", "-").replace("_", "-"); +} + + +class GSettingsBackendPrivate +{ +public: + GSettingsBackendPrivate(GSettingsBackend *parent) : q_ptr(parent) {} + + QGSettings *settings; + QMap keyMap; + + GSettingsBackend *q_ptr; + Q_DECLARE_PUBLIC(GSettingsBackend) +}; + +GSettingsBackend::GSettingsBackend(DSettings *settings, QObject *parent) : + DSettingsBackend(parent), d_ptr(new GSettingsBackendPrivate(this)) +{ + Q_D(GSettingsBackend); + + QJsonObject settingsMeta = settings->meta(); + auto gsettingsMeta = settingsMeta.value("gsettings").toObject(); + auto id = gsettingsMeta.value("id").toString(); + auto path = gsettingsMeta.value("path").toString(); + + for (QString key : settings->keys()) { + auto gsettingsKey = QString(key).replace(".", "-").replace("_", "-"); + d->keyMap.insert(gsettingsKey, key); + } + + d->settings = new QGSettings(id.toUtf8(), path.toUtf8(), this); + + connect(d->settings, &QGSettings::changed, this, [ = ](const QString & key) { + auto dk = d->keyMap.value(unqtifyName(key)); + Q_EMIT optionChanged(dk, d->settings->get(key)); + }); + +} + +GSettingsBackend::~GSettingsBackend() +{ + +} + +QStringList GSettingsBackend::keys() const +{ + Q_D(const GSettingsBackend); + return d->settings->keys(); +} + +QVariant GSettingsBackend::getOption(const QString &key) const +{ + Q_D(const GSettingsBackend); + return d->settings->get(qtifyName(key)); +} + +void GSettingsBackend::doSetOption(const QString &key, const QVariant &value) +{ + Q_D(GSettingsBackend); + d->settings->set(qtifyName(key), value); + Q_EMIT setOption(key, value); +} + +void GSettingsBackend::doSync() +{ + Q_EMIT sync(); +} + +DCORE_END_NAMESPACE diff --git a/src/settings/backend/gsettingsbackend.h b/src/settings/backend/gsettingsbackend.h new file mode 100644 index 0000000..5fd92f7 --- /dev/null +++ b/src/settings/backend/gsettingsbackend.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "dsettingsbackend.h" + +DCORE_BEGIN_NAMESPACE + +class GSettingsBackendPrivate; +class GSettingsBackend: public DSettingsBackend +{ + Q_OBJECT +public: + explicit GSettingsBackend(DSettings *settings, QObject *parent = 0); + ~GSettingsBackend(); + + virtual QStringList keys() const Q_DECL_OVERRIDE; + virtual QVariant getOption(const QString &key) const Q_DECL_OVERRIDE; + +protected Q_SLOTS: + virtual void doSetOption(const QString &key, const QVariant &value) Q_DECL_OVERRIDE; + virtual void doSync() Q_DECL_OVERRIDE; + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), GSettingsBackend) +}; + +DCORE_END_NAMESPACE diff --git a/src/settings/backend/qsettingbackend.cpp b/src/settings/backend/qsettingbackend.cpp index 6893c47..fec9e4b 100644 --- a/src/settings/backend/qsettingbackend.cpp +++ b/src/settings/backend/qsettingbackend.cpp @@ -69,7 +69,11 @@ void QSettingBackend::doSetOption(const QString &key, const QVariant &value) Q_D(QSettingBackend); d->writeLock.lock(); d->settings->beginGroup(key); - d->settings->setValue("value", value); + auto oldValue = d->settings->value("value"); + if (oldValue != value) { + d->settings->setValue("value", value); + Q_EMIT optionChanged(key, value); + } d->settings->endGroup(); d->settings->sync(); d->writeLock.unlock(); @@ -81,4 +85,5 @@ void QSettingBackend::doSync() d->settings->sync(); } + DCORE_END_NAMESPACE diff --git a/src/settings/dsettings.cpp b/src/settings/dsettings.cpp index 9ce4c1d..fd906d4 100644 --- a/src/settings/dsettings.cpp +++ b/src/settings/dsettings.cpp @@ -29,8 +29,6 @@ #include "dsettingsgroup.h" #include "dsettingsbackend.h" -#include "backend/qsettingbackend.h" - DCORE_BEGIN_NAMESPACE class DSettingsPrivate @@ -38,7 +36,8 @@ class DSettingsPrivate public: DSettingsPrivate(DSettings *parent) : q_ptr(parent) {} - DSettingsBackend *backend = nullptr; + DSettingsBackend *backend = nullptr; + QJsonObject meta; QMap options; QMap childGroups; @@ -71,8 +70,14 @@ void DSettings::setBackend(DSettingsBackend *backend) } d->backend = backend; + + auto backendWriteThread = new QThread; d->backend->moveToThread(backendWriteThread); + + connect(d->backend, &DSettingsBackend::optionChanged, + this, &DSettings::valueChanged); + backendWriteThread->start(); // load form backend @@ -96,6 +101,12 @@ QPointer DSettings::fromJsonFile(const QString &filepath) return DSettings::fromJson(jsonData); } +QJsonObject DSettings::meta() const +{ + Q_D(const DSettings); + return d->meta; +} + QStringList DSettings::keys() const { Q_D(const DSettings); @@ -150,8 +161,6 @@ QVariant DSettings::getOption(const QString &key) const void DSettings::setOption(const QString &key, const QVariant &value) { -// Q_D(Settings); -// qDebug() << "set" << key << value; option(key)->setValue(value); } @@ -178,11 +187,11 @@ void DSettings::parseJson(const QByteArray &json) Q_D(DSettings); auto jsonDoc = QJsonDocument::fromJson(json); - auto mainGroups = jsonDoc.object().value("groups"); + d->meta = jsonDoc.object(); + auto mainGroups = d->meta.value("groups"); for (auto groupJson : mainGroups.toArray()) { auto group = DSettingsGroup::fromJson("", groupJson.toObject()); for (auto option : group->options()) { -// qDebug() << "add option" << option->key(); d->options.insert(option->key(), option); } d->childGroupKeys << group->key(); @@ -191,12 +200,9 @@ void DSettings::parseJson(const QByteArray &json) for (auto option : d->options.values()) { d->options.insert(option->key(), option); - connect(option.data(), &DSettingsOption::valueChanged, this, [ = ](QVariant value) { Q_EMIT d->backend->setOption(option->key(), value); -// Q_EMIT d->backend->sync(); - Q_EMIT valueChanged(option->key(), value); }); } } @@ -205,9 +211,7 @@ void DSettings::loadValue() { Q_D(DSettings); -// qDebug() << d->backend; for (auto key : d->backend->keys()) { - //qDebug() << "load value for key" << key; auto value = d->backend->getOption(key); auto opt = option(key); if (!value.isValid() || opt.isNull()) { diff --git a/src/settings/dsettings.h b/src/settings/dsettings.h index 4353106..60bf05f 100644 --- a/src/settings/dsettings.h +++ b/src/settings/dsettings.h @@ -40,6 +40,7 @@ public: static QPointer fromJson(const QByteArray &json); static QPointer fromJsonFile(const QString &filepath); + QJsonObject meta() const; QStringList keys() const; QList> options() const; diff --git a/src/settings/dsettingsbackend.h b/src/settings/dsettingsbackend.h index 19b5552..9c08ab5 100644 --- a/src/settings/dsettingsbackend.h +++ b/src/settings/dsettingsbackend.h @@ -24,6 +24,7 @@ DCORE_BEGIN_NAMESPACE +class DSettings; class DSettingsBackend : public QObject { Q_OBJECT @@ -43,10 +44,13 @@ public: protected: virtual void doSetOption(const QString &key, const QVariant &value) = 0; +Q_SIGNALS: + void optionChanged(const QString &key, const QVariant &value); + + // private signals; Q_SIGNALS: void sync(); void setOption(const QString &key, const QVariant &value); - void optionChanged(const QString &key, const QVariant &value); }; DCORE_END_NAMESPACE diff --git a/src/settings/settings.pri b/src/settings/settings.pri index ecfa071..b32595a 100644 --- a/src/settings/settings.pri +++ b/src/settings/settings.pri @@ -4,14 +4,16 @@ SOURCES += \ $$PWD/backend/qsettingbackend.cpp \ $$PWD/dsettings.cpp \ $$PWD/dsettingsoption.cpp \ - $$PWD/dsettingsgroup.cpp + $$PWD/dsettingsgroup.cpp \ + $$PWD/backend/gsettingsbackend.cpp HEADERS +=\ $$PWD/backend/qsettingbackend.h \ $$PWD/dsettings.h \ $$PWD/dsettingsoption.h \ $$PWD/dsettingsgroup.h \ - $$PWD/dsettingsbackend.h + $$PWD/dsettingsbackend.h \ + $$PWD/backend/gsettingsbackend.h includes.files += $${PWD}/*.h includes.files += $${PWD}/backend/*.h diff --git a/src/src.pro b/src/src.pro index f9af173..00a8f6b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -2,6 +2,8 @@ include($$PWD/lib.pri) QT -= gui QT += dbus +CONFIG += link_pkgconfig +PKGCONFIG += gsettings-qt TARGET = dtkcore diff --git a/tests/tests.pro b/tests/tests.pro index f89c599..ac63962 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,8 +1,9 @@ TEMPLATE = app QT += testlib QT -= gui -CONFIG += testcase c++11 +CONFIG += testcase c++11 link_pkgconfig TARGET = tests +PKGCONFIG += gsettings-qt SOURCES += \ main.cpp \ diff --git a/tool/settings/main.cpp b/tool/settings/main.cpp index b84b417..ff0f498 100644 --- a/tool/settings/main.cpp +++ b/tool/settings/main.cpp @@ -27,6 +27,11 @@ #include "settings/dsettingsgroup.h" #include "settings/dsettingsoption.h" +#include +#include +#include + +#include static QString CppTemplate = "#include \n" @@ -36,6 +41,140 @@ static QString CppTemplate = "%1" "}\n"; +/* + * GVariant Type Name/Code C++ Type Name QVariant Type Name + * -------------------------------------------------------------------------- + * boolean b bool QVariant::Bool + * byte y char QVariant::Char + * int16 n int QVariant::Int + * uint16 q unsigned int QVariant::UInt + * int32 i int QVariant::Int + * uint32 u unsigned int QVariant::UInt + * int64 x long long QVariant::LongLong + * uint64 t unsigned long long QVariant::ULongLong + * double d double QVariant::Double + * string s QString QVariant::String + * string array* as QStringList QVariant::StringList + * byte array ay QByteArray QVariant::ByteArray + * dictionary a{ss} QVariantMap QVariant::Map +*/ + +QString gsettings_type_from_QVarint(const QVariant::Type qtype) +{ + switch (qtype) { + case QVariant::Bool: + return "b"; + case QVariant::Int: + return "i"; + case QVariant::UInt: + return "u"; + case QVariant::LongLong: + return "x"; + case QVariant::ULongLong: + return "t"; + case QVariant::Double: + return "d"; + case QVariant::String: + return "s"; + case QVariant::StringList: + return "as"; + case QVariant::ByteArray: + return "ay"; + case QVariant::Map: + return "a{ss}"; + default: + return ""; + } +} + +QString gsettings_value_from_QVarint(const QVariant value) +{ + switch (value.type()) { + case QVariant::Bool: + return value.toString(); + case QVariant::Int: + return value.toString(); + case QVariant::UInt: + return value.toString(); + case QVariant::LongLong: + return value.toString(); + case QVariant::ULongLong: + return value.toString(); + case QVariant::Double: + return value.toString(); + case QVariant::String: + return QString("\"%1\"").arg(value.toString()); + case QVariant::StringList: + return value.toString(); + case QVariant::ByteArray: + return value.toString(); + case QVariant::Map: + return value.toString(); + default: + return ""; + } +} + + +QJsonObject parseGSettingsMeta(const QString &jsonPath) +{ + QFile jsonFile(jsonPath); + jsonFile.open(QIODevice::ReadOnly); + auto jsonData = jsonFile.readAll(); + jsonFile.close(); + + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); + return jsonDoc.object().value("gsettings").toObject(); +} + +static bool writeGSettingXML(Dtk::Core::DSettings *settings, + QJsonObject gsettingsMeta, + const QString &xmlPath) +{ + QDomDocument document; + + QDomProcessingInstruction header = document.createProcessingInstruction("xml", + "version=\"1.0\" encoding=\"utf-8\""); + document.appendChild(header); + + QDomElement schemalist = document.createElement("schemalist"); + + auto id = gsettingsMeta.value("id").toString(); + auto path = gsettingsMeta.value("path").toString(); + QDomElement schema = document.createElement("schema"); + schema.setAttribute("id", id); + schema.setAttribute("path", path); + + for (QString key : settings->keys()) { + auto codeKey = QString(key).replace(".", "-").replace("_", "-"); + auto value = settings->option(key)->value(); + QDomElement keyXml = document.createElement("key"); + keyXml.setAttribute("dsetting-key", key); + keyXml.setAttribute("name", codeKey); + keyXml.setAttribute("type", gsettings_type_from_QVarint(value.type())); + + QString defaultData = gsettings_value_from_QVarint(value); + QDomElement defaultEle = document.createElement("default"); + QDomCharacterData data = document.createTextNode(defaultData); + defaultEle.appendChild(data); + keyXml.appendChild(defaultEle); + + schema.appendChild(keyXml); + } + + schemalist.appendChild(schema); + document.appendChild(schemalist); + + QFile file(xmlPath); + if (!file.open(QIODevice::WriteOnly)) { + return false; + } + QTextStream stream(&file); + stream << document.toString(); + file.close(); + return true; +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); @@ -48,9 +187,14 @@ int main(int argc, char *argv[]) parser.addHelpOption(); parser.addVersionOption(); + QCommandLineOption gsettingsArg(QStringList() << "g" << "gsettings", + QCoreApplication::tr("generate gsetting schema"), + "xml-file"); + QCommandLineOption outputFileArg(QStringList() << "o" << "output", QCoreApplication::tr("Output cpp file"), "cpp-file"); + parser.addOption(gsettingsArg); parser.addOption(outputFileArg); parser.addPositionalArgument("json-file", QCoreApplication::tr("Json file description config")); parser.process(app); @@ -116,9 +260,9 @@ int main(int argc, char *argv[]) cppCode.append(stringCode); } - QString outputCpp = CppTemplate.arg(cppCode); if (parser.isSet(outputFileArg)) { + QString outputCpp = CppTemplate.arg(cppCode); QFile outputFile(parser.value(outputFileArg)); if (!outputFile.open(QIODevice::WriteOnly)) { qCritical() << "can not open output file!"; @@ -126,9 +270,13 @@ int main(int argc, char *argv[]) } outputFile.write(outputCpp.toUtf8()); outputFile.close(); - } else { - std::cout << outputCpp.toStdString(); } + + if (parser.isSet(gsettingsArg)) { + QString outputXml = parser.value(gsettingsArg); + writeGSettingXML(settings, parseGSettingsMeta(jsonFile), outputXml); + } + return 0; } diff --git a/tool/settings/settings.pro b/tool/settings/settings.pro index fb6e4cd..8dcb34c 100644 --- a/tool/settings/settings.pro +++ b/tool/settings/settings.pro @@ -1,4 +1,4 @@ -QT += core +QT += core xml QT -= gui CONFIG += c++11 @@ -6,6 +6,7 @@ CONFIG += c++11 TARGET = dtk-settings-tool CONFIG += console link_pkgconfig CONFIG -= app_bundle +PKGCONFIG += gsettings-qt TEMPLATE = app -- 2.30.2