feat: create gsettingsbackend
authorIceyer <me@iceyer.net>
Mon, 23 Oct 2017 12:21:29 +0000 (20:21 +0800)
committerDeepin Code Review <gerrit@deepin.com>
Tue, 24 Oct 2017 02:19:05 +0000 (10:19 +0800)
Change-Id: I6ed1ef01205c31814f53a427e84b8b24fe96a7a6

src/settings/backend/gsettingsbackend.cpp [new file with mode: 0644]
src/settings/backend/gsettingsbackend.h [new file with mode: 0644]
src/settings/backend/qsettingbackend.cpp
src/settings/dsettings.cpp
src/settings/dsettings.h
src/settings/dsettingsbackend.h
src/settings/settings.pri
src/src.pro
tests/tests.pro
tool/settings/main.cpp
tool/settings/settings.pro

diff --git a/src/settings/backend/gsettingsbackend.cpp b/src/settings/backend/gsettingsbackend.cpp
new file mode 100644 (file)
index 0000000..71278ba
--- /dev/null
@@ -0,0 +1,101 @@
+#include "gsettingsbackend.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QVariant>
+#include <QGSettings/QGSettings>
+
+#include <DSettings>
+
+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<QString, QString> 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 (file)
index 0000000..5fd92f7
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <QObject>
+#include <QScopedPointer>
+
+#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<GSettingsBackendPrivate> d_ptr;
+    Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), GSettingsBackend)
+};
+
+DCORE_END_NAMESPACE
index 6893c47f19ee4031fa5175c2e6a7da5419cc6d13..fec9e4bca767730e69066bae5eea45da84e4fc7e 100644 (file)
@@ -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
index 9ce4c1d127a80b23dc03ab27f60e1f8321819c98..fd906d451dcea02b7f4dbf7c286c86feccc89aaf 100644 (file)
@@ -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 <QString, OptionPtr>   options;
 
     QMap<QString, GroupPtr>     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> 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()) {
index 4353106ec61580b93e63b87da9fa96a840b9df31..60bf05f1094c6017dc7b4580831695b8e32ad78a 100644 (file)
@@ -40,6 +40,7 @@ public:
 
     static QPointer<DSettings> fromJson(const QByteArray &json);
     static QPointer<DSettings> fromJsonFile(const QString &filepath);
+    QJsonObject meta() const;
 
     QStringList keys() const;
     QList<QPointer<DSettingsOption>> options() const;
index 19b5552664625f7b06e7042a2992abb576e09d64..9c08ab532ad31e147a2b768125f16e9822e60d02 100644 (file)
@@ -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
index ecfa071a881cd8dab50e5436ea48c725c7c2cab3..b32595af5e81f0ba9a75986772ccf77e157efe60 100644 (file)
@@ -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
index f9af1736282a0644366dfa641b65307d27665c24..00a8f6b3d746351f6949c8b9a547f30d41ad31aa 100644 (file)
@@ -2,6 +2,8 @@ include($$PWD/lib.pri)
 
 QT -= gui
 QT += dbus
+CONFIG += link_pkgconfig
+PKGCONFIG += gsettings-qt
 
 TARGET = dtkcore
 
index f89c59954938014fa599b40227b0cfcd6cdc6d6c..ac6396235b11173287e94707bf5bb52d88227c46 100644 (file)
@@ -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 \
index b84b4179348e5e81e65ff927350442deeae9b02d..ff0f49821ed38a94b07d52c6f2b886591177a1e7 100644 (file)
 #include "settings/dsettingsgroup.h"
 #include "settings/dsettingsoption.h"
 
+#include <QFile>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <QDomDocument>
 
 static QString CppTemplate =
     "#include <DSettings>\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;
 }
 
index fb6e4cd94ded7531a35ae5f51e4a3b922e23206b..8dcb34c6c70cf9505d43814afe3a7e1dc2d59563 100644 (file)
@@ -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