--- /dev/null
+#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
--- /dev/null
+#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
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();
d->settings->sync();
}
+
DCORE_END_NAMESPACE
#include "dsettingsgroup.h"
#include "dsettingsbackend.h"
-#include "backend/qsettingbackend.h"
-
DCORE_BEGIN_NAMESPACE
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;
}
d->backend = backend;
+
+
auto backendWriteThread = new QThread;
d->backend->moveToThread(backendWriteThread);
+
+ connect(d->backend, &DSettingsBackend::optionChanged,
+ this, &DSettings::valueChanged);
+
backendWriteThread->start();
// load form backend
return DSettings::fromJson(jsonData);
}
+QJsonObject DSettings::meta() const
+{
+ Q_D(const DSettings);
+ return d->meta;
+}
+
QStringList DSettings::keys() const
{
Q_D(const DSettings);
void DSettings::setOption(const QString &key, const QVariant &value)
{
-// Q_D(Settings);
-// qDebug() << "set" << key << value;
option(key)->setValue(value);
}
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();
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);
});
}
}
{
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()) {
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;
DCORE_BEGIN_NAMESPACE
+class DSettings;
class DSettingsBackend : public QObject
{
Q_OBJECT
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
$$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
QT -= gui
QT += dbus
+CONFIG += link_pkgconfig
+PKGCONFIG += gsettings-qt
TARGET = dtkcore
TEMPLATE = app
QT += testlib
QT -= gui
-CONFIG += testcase c++11
+CONFIG += testcase c++11 link_pkgconfig
TARGET = tests
+PKGCONFIG += gsettings-qt
SOURCES += \
main.cpp \
#include "settings/dsettingsgroup.h"
#include "settings/dsettingsoption.h"
+#include <QFile>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <QDomDocument>
static QString CppTemplate =
"#include <DSettings>\n"
"%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);
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);
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!";
}
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;
}
-QT += core
+QT += core xml
QT -= gui
CONFIG += c++11
TARGET = dtk-settings-tool
CONFIG += console link_pkgconfig
CONFIG -= app_bundle
+PKGCONFIG += gsettings-qt
TEMPLATE = app