From f6abd96c772f189cf26bfbec702b025fca6ef76f Mon Sep 17 00:00:00 2001 From: justforlxz Date: Wed, 7 Aug 2019 16:09:12 +0800 Subject: [PATCH] feat(DGIOSettings): replace QGSettings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 和QGSettings接口基本一致,但是去掉了驼峰命名转换。 --- gio-qt/CMakeLists.txt | 2 + gio-qt/include/dgiosettings.h | 58 ++++++ gio-qt/private/dgiohelper.cpp | 10 + gio-qt/private/dgiohelper.h | 1 + gio-qt/source/dgiosettings.cpp | 325 +++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 2 + test/tst_dgiosettings.cpp | 38 ++++ 7 files changed, 436 insertions(+) create mode 100644 gio-qt/include/dgiosettings.h create mode 100644 gio-qt/source/dgiosettings.cpp create mode 100644 test/tst_dgiosettings.cpp diff --git a/gio-qt/CMakeLists.txt b/gio-qt/CMakeLists.txt index c2eb25a..5805d4f 100644 --- a/gio-qt/CMakeLists.txt +++ b/gio-qt/CMakeLists.txt @@ -13,6 +13,7 @@ set (QGIO_PUBLIC_HEADER_FILES include/dgiofileinfo.h include/dgiofileiterator.h include/dgiodrive.h + include/dgiosettings.h ) set (QGIO_PRIVATE_HEADER_FILES @@ -29,6 +30,7 @@ set (QGIO_PRIVATE_CPP_FILES source/dgiofileinfo.cpp source/dgiofileiterator.cpp source/dgiodrive.cpp + source/dgiosettings.cpp private/dgiohelper.cpp ) diff --git a/gio-qt/include/dgiosettings.h b/gio-qt/include/dgiosettings.h new file mode 100644 index 0000000..4bc9f8a --- /dev/null +++ b/gio-qt/include/dgiosettings.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: justforlxz + * + * Maintainer: justforlxz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DGIOSETTINGS_H +#define DGIOSETTINGS_H + +#include +#include + +class DGIOSettingsPrivate; +class DGIOSettings : public QObject +{ + Q_OBJECT +public: + explicit DGIOSettings(const QString& schemaId, QObject* parent = nullptr); + DGIOSettings(const QString& schemaId, const QString& path, QObject* parent = nullptr); + + ~DGIOSettings(); + + void sync(); + + bool setValue(const QString& key, const QVariant& value, bool sync = false); + QVariant value(const QString& key) const; + + Q_DECL_DEPRECATED QStringList keys() const; + + void reset(const QString& key); + + static bool isSchemaInstalled(const QString& schemaId); + +Q_SIGNALS: + void valueChanged(const QString& key, const QVariant& value); + +private: + QScopedPointer d_private; + + Q_DECLARE_PRIVATE_D(d_private, DGIOSettings) +}; + +#endif // DGIOSETTINGS_H diff --git a/gio-qt/private/dgiohelper.cpp b/gio-qt/private/dgiohelper.cpp index 1d7afb3..dacc161 100644 --- a/gio-qt/private/dgiohelper.cpp +++ b/gio-qt/private/dgiohelper.cpp @@ -73,5 +73,15 @@ QStringList getThemedIconNames(Glib::RefPtr icon) return iconNames; } +gchar *converToGChar(const QByteArray &array) { + GString *str = g_string_new(nullptr); + + for (const QChar c : array) { + g_string_append_c(str, c.toLower().toLatin1()); + } + + return g_string_free(str, FALSE); +} + } diff --git a/gio-qt/private/dgiohelper.h b/gio-qt/private/dgiohelper.h index 7b74b8e..73f0a37 100644 --- a/gio-qt/private/dgiohelper.h +++ b/gio-qt/private/dgiohelper.h @@ -27,6 +27,7 @@ namespace DGioPrivate { QStringList getThemedIconNames(Glib::RefPtr icon); + gchar * converToGChar(const QByteArray& array); } #endif // DGIOHELPER_H diff --git a/gio-qt/source/dgiosettings.cpp b/gio-qt/source/dgiosettings.cpp new file mode 100644 index 0000000..f3e5cbd --- /dev/null +++ b/gio-qt/source/dgiosettings.cpp @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2011 ~ 2019 Deepin Technology Co., Ltd. + * + * Author: justforlxz + * + * Maintainer: justforlxz + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dgiosettings.h" +#include "private/dgiohelper.h" + +#include +#include + +#include +#include + +static QVariant qconf_types_to_qvariant(GVariant* value) +{ + switch (g_variant_classify(value)) { + case G_VARIANT_CLASS_BOOLEAN: + return QVariant(static_cast(g_variant_get_boolean(value))); + + case G_VARIANT_CLASS_BYTE: + return QVariant(static_cast(g_variant_get_byte(value))); + + case G_VARIANT_CLASS_INT16: + return QVariant(static_cast(g_variant_get_int16(value))); + + case G_VARIANT_CLASS_UINT16: + return QVariant(static_cast(g_variant_get_uint16(value))); + + case G_VARIANT_CLASS_INT32: + return QVariant(static_cast(g_variant_get_int32(value))); + + case G_VARIANT_CLASS_UINT32: + return QVariant(static_cast(g_variant_get_uint32(value))); + + case G_VARIANT_CLASS_INT64: + return QVariant(static_cast(g_variant_get_int64(value))); + + case G_VARIANT_CLASS_UINT64: + return QVariant(static_cast(g_variant_get_uint64(value))); + + case G_VARIANT_CLASS_DOUBLE: + return QVariant(g_variant_get_double(value)); + + case G_VARIANT_CLASS_STRING: + return QVariant(g_variant_get_string(value, nullptr)); + + case G_VARIANT_CLASS_ARRAY: + if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) { + GVariantIter iter; + QStringList list; + const gchar *str; + + g_variant_iter_init (&iter, value); + while (g_variant_iter_next(&iter, "&s", &str)) { + list.append (str); + } + + return QVariant(list); + } + else if (g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING)) { + return QVariant(QByteArray(g_variant_get_bytestring(value))); + } + else if (g_variant_is_of_type(value, G_VARIANT_TYPE("a{ss}"))) { + GVariantIter iter; + QMap map; + const gchar* key; + const gchar* val; + + g_variant_iter_init (&iter, value); + while (g_variant_iter_next(&iter, "{&s&s}", &key, &val)) { + map.insert(key, QVariant(val)); + } + + return map; + } + } + + qWarning() << "No matching type! " << g_variant_classify(value); + return QVariant(); +} + +static GVariant *qconf_types_collect_from_variant(const GVariantType* gtype, const QVariant& v) +{ + switch (g_variant_type_peek_string(gtype)[0]) { + case G_VARIANT_CLASS_BOOLEAN: + return g_variant_new_boolean(v.toBool()); + + case G_VARIANT_CLASS_BYTE: + return g_variant_new_byte(v.toChar().cell()); + + case G_VARIANT_CLASS_INT16: + return g_variant_new_int16(v.toInt()); + + case G_VARIANT_CLASS_UINT16: + return g_variant_new_uint16(v.toUInt()); + + case G_VARIANT_CLASS_INT32: + return g_variant_new_int32(v.toInt()); + + case G_VARIANT_CLASS_UINT32: + return g_variant_new_uint32(v.toUInt()); + + case G_VARIANT_CLASS_INT64: + return g_variant_new_int64(v.toLongLong()); + + case G_VARIANT_CLASS_UINT64: + return g_variant_new_int64(v.toULongLong()); + + case G_VARIANT_CLASS_DOUBLE: + return g_variant_new_double(v.toDouble()); + + case G_VARIANT_CLASS_STRING: + return g_variant_new_string(v.toString().toUtf8()); + + case G_VARIANT_CLASS_ARRAY: + if (g_variant_type_equal(gtype, G_VARIANT_TYPE_STRING_ARRAY)) { + const QStringList list = v.toStringList(); + GVariantBuilder builder; + + g_variant_builder_init(&builder, G_VARIANT_TYPE_STRING_ARRAY); + + for (const QString& string : list) { + g_variant_builder_add(&builder, "s", string.toUtf8().constData()); + } + + return g_variant_builder_end(&builder); + } + else if (g_variant_type_equal(gtype, G_VARIANT_TYPE_BYTESTRING)) { + const QByteArray& array = v.toByteArray(); + gsize size = static_cast(array.size()); + gpointer data; + + data = g_memdup(array.data(), static_cast(size)); + + return g_variant_new_from_data(G_VARIANT_TYPE_BYTESTRING, + data, size, TRUE, g_free, data); + } + else if (g_variant_type_equal(gtype, G_VARIANT_TYPE("a{ss}"))) { + GVariantBuilder builder; + g_variant_builder_init(&builder, G_VARIANT_TYPE ("a{ss}")); + QMapIterator it(v.toMap()); + while (it.hasNext()) { + it.next(); + const QByteArray& key = it.key().toUtf8(); + const QByteArray& val = it.value().toByteArray(); + g_variant_builder_add (&builder, "{ss}", key.constData(), val.constData()); + } + return g_variant_builder_end (&builder); + } + } + + qWarning() << "No matching type! " << g_variant_type_peek_string(gtype)[0]; + return nullptr; +} + +class DGIOSettingsPrivate +{ +public: + DGIOSettingsPrivate(DGIOSettings* qq) + : ptr(qq) + { + } + + QString schemaId; + QString path; + DGIOSettings* ptr; + GSettings* settings; + GSettingsSchema* schema; + gulong signalHandlerId; + + QVariant value(GSettings* gsettings, const QString& key) const { + gchar* gkey = DGioPrivate::converToGChar(key.toUtf8()); + GVariant* variant = g_settings_get_value(gsettings, gkey); + QVariant qvalue = qconf_types_to_qvariant(variant); + g_variant_unref(variant); + g_free(gkey); + + return qvalue; + } + + bool trySet(const QString& key, const QVariant& value) + { + const gchar* gkey = key.toUtf8().constData(); + bool success = false; + + /* fetch current value to find out the exact type */ + GVariant* cur = g_settings_get_value(settings, gkey); + + GVariant* new_value = qconf_types_collect_from_variant(g_variant_get_type(cur), value); + + if (new_value) { + success = g_settings_set_value(settings, gkey, new_value); + } + + g_variant_unref(cur); + + return success; + } + + void sync() { + g_settings_sync(); + } + + static void onSettingChanged(GSettings* settings, const gchar* key, gpointer pointer) { + DGIOSettingsPrivate* self = static_cast(pointer); + Q_EMIT self->ptr->valueChanged(key, self->value(settings, key)); + } +}; + + +DGIOSettings::DGIOSettings(const QString& schemaId, QObject* parent) + : DGIOSettings(schemaId, QString(), parent) +{ +} + +DGIOSettings::DGIOSettings(const QString& schemaId, const QString& path, QObject* parent) + : QObject(parent) + , d_private(new DGIOSettingsPrivate(this)) +{ + d_private->schemaId = schemaId; + d_private->path = path; + + d_private->settings = path.isEmpty() + ? g_settings_new(d_private->schemaId.toUtf8().constData()) + : g_settings_new_with_path(d_private->schemaId.toUtf8().constData(), + path.toUtf8().constData()); + + g_object_get(d_private->settings, "settings-schema", &d_private->schema, nullptr); + d_private->signalHandlerId = g_signal_connect(d_private->settings, "changed", G_CALLBACK(DGIOSettingsPrivate::onSettingChanged), d_ptr.data()); +} + +DGIOSettings::~DGIOSettings() +{ + Q_D(DGIOSettings); + + if (d->schema) { + g_settings_sync (); + g_signal_handler_disconnect(d->settings, d->signalHandlerId); + g_object_unref (d->settings); + g_settings_schema_unref (d->schema); + } +} + +bool DGIOSettings::setValue(const QString& key, const QVariant& value, bool sync) +{ + Q_D(DGIOSettings); + + if (!d->trySet(key, value)) { + qWarning() << QString("unable to set key %1 to value %2").arg(key).arg(value.toString()); + return false; + } + + if (sync) { + d->sync(); + } + + return true; +} + +QVariant DGIOSettings::value(const QString& key) const +{ + Q_D(const DGIOSettings); + + return d->value(d->settings, key); +} + +QStringList DGIOSettings::keys() const +{ + Q_D(const DGIOSettings); + + QStringList list; + gchar** keys = g_settings_list_keys(d->settings); + + for (int i = 0; keys[i]; i++) { + list.append(keys[i]); + } + + g_strfreev(keys); + + return list; +} + +void DGIOSettings::reset(const QString& key) +{ + Q_D(DGIOSettings); + + g_settings_reset(d->settings, key.toUtf8().constData()); +} + +void DGIOSettings::sync() +{ + Q_D(DGIOSettings); + + d->sync(); +} + +bool DGIOSettings::isSchemaInstalled(const QString& schemaId) +{ + GSettingsSchemaSource* source = g_settings_schema_source_get_default(); + + if (GSettingsSchema* schema = g_settings_schema_source_lookup(source, schemaId.toUtf8().constData(), true)) { + g_settings_schema_unref (schema); + return true; + } + else { + return false; + } +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ab35845..20d7b19 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,3 +23,5 @@ dgio_create_test (tst_matchgioenum tst_matchgioenum.cpp YES) # Simple FileInfo dgio_create_test (tst_simplefileinfo tst_simplefileinfo.cpp NO) + +dgio_create_test (tst_dgiosettings tst_dgiosettings.cpp NO) diff --git a/test/tst_dgiosettings.cpp b/test/tst_dgiosettings.cpp new file mode 100644 index 0000000..85e7849 --- /dev/null +++ b/test/tst_dgiosettings.cpp @@ -0,0 +1,38 @@ +#include +#include + +#include +#include + +#include "dgiosettings.h" + +class DGioSettingsTest : public QObject { + Q_OBJECT +public: + DGioSettingsTest() {} + +private Q_SLOTS: + void testCase_Settings() { + if (DGIOSettings::isSchemaInstalled("com.deepin.dde.appearance") == false) { + qWarning() << "com.deepin.dde.appearance" << "invalid"; + return; + } + + DGIOSettings settings("com.deepin.dde.appearance", this); + QVERIFY(settings.value("background-uris").isValid()); + QVERIFY(settings.value("extra-picture-uris").isValid()); + const QStringList& tmpValue = settings.value("extra-picture-uris").toStringList(); + settings.setValue("extra-picture-uris", QStringList()); + settings.setValue("extra-picture-uris", QStringList() << "ddd"); + settings.sync(); + QVERIFY(settings.value("extra-picture-uris").toStringList() == QStringList() << "ddd"); + settings.setValue("extra-picture-uris", tmpValue, true); + QVERIFY(settings.value("extra-picture-uris").toStringList() == tmpValue); + + QVERIFY(settings.keys().contains("extra-picture-uris")); + } +}; + +QTEST_APPLESS_MAIN(DGioSettingsTest) + +#include "tst_dgiosettings.moc"