aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/qml/CMakeLists.txt39
-rw-r--r--src/qml/kconfigpropertymap.cpp148
-rw-r--r--src/qml/kconfigpropertymap.h69
5 files changed, 260 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 326912b7..64e24647 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ option(KCONFIG_USE_GUI "Build components using Qt5Gui" ON)
if(KCONFIG_USE_GUI)
find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Gui)
endif()
+find_package(Qt5 ${REQUIRED_QT_VERSION} OPTIONAL_COMPONENTS Qml)
if (NOT ANDROID)
option(KCONFIG_USE_DBUS "Build components using Qt5DBus" ON)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e6bac82a..89fe7284 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,9 @@ add_subdirectory(core)
if(TARGET Qt5::Gui)
add_subdirectory(gui)
endif()
+if(TARGET Qt5::Qml)
+ add_subdirectory(qml)
+endif()
add_subdirectory(kconfig_compiler)
add_subdirectory(kconf_update)
add_subdirectory(kreadconfig)
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
new file mode 100644
index 00000000..1cdae88a
--- /dev/null
+++ b/src/qml/CMakeLists.txt
@@ -0,0 +1,39 @@
+add_library(KF5ConfigQml)
+add_library(KF5::ConfigQml ALIAS KF5ConfigQml)
+
+target_sources(KF5ConfigQml PRIVATE
+ kconfigpropertymap.cpp
+)
+
+ecm_generate_export_header(KF5ConfigQml
+ BASE_NAME KConfigQml
+ GROUP_BASE_NAME KF
+ VERSION ${KF_VERSION}
+ DEPRECATED_BASE_VERSION 0
+ EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
+)
+
+target_link_libraries(KF5ConfigQml
+ PUBLIC
+ KF5::ConfigCore # KCoreConfigSkeleton, in ConfigPropertyMap
+ Qt5::Qml
+)
+set_target_properties(KF5ConfigQml PROPERTIES VERSION ${KCONFIG_VERSION}
+ SOVERSION ${KCONFIG_SOVERSION}
+ EXPORT_NAME ConfigQml
+)
+
+ecm_generate_headers(KConfigQml_HEADERS
+ HEADER_NAMES
+ KConfigPropertyMap
+
+ REQUIRED_HEADERS KConfigQml_HEADERS
+)
+target_include_directories(KF5ConfigQml INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KConfigQml>")
+
+install(TARGETS KF5ConfigQml EXPORT KF5ConfigTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/kconfigqml_export.h
+ ${KConfigQml_HEADERS}
+ DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KConfigQml COMPONENT Devel
+)
diff --git a/src/qml/kconfigpropertymap.cpp b/src/qml/kconfigpropertymap.cpp
new file mode 100644
index 00000000..55b2991d
--- /dev/null
+++ b/src/qml/kconfigpropertymap.cpp
@@ -0,0 +1,148 @@
+/*
+ SPDX-FileCopyrightText: 2013 Marco Martin <notmart@gmail.com>
+ SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
+ SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
+
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#include "kconfigpropertymap.h"
+
+#include <KCoreConfigSkeleton>
+#include <QJSValue>
+#include <QPointer>
+
+#include <functional>
+
+class KConfigPropertyMapPrivate
+{
+public:
+ KConfigPropertyMapPrivate(KConfigPropertyMap *map)
+ : q(map)
+ {
+ }
+
+ enum LoadConfigOption {
+ DontEmitValueChanged,
+ EmitValueChanged,
+ };
+
+ void loadConfig(LoadConfigOption option);
+ void writeConfig();
+ void writeConfigValue(const QString &key, const QVariant &value);
+
+ KConfigPropertyMap *q;
+ QPointer<KCoreConfigSkeleton> config;
+ bool updatingConfigValue = false;
+ bool autosave = true;
+ bool notify = false;
+};
+
+KConfigPropertyMap::KConfigPropertyMap(KCoreConfigSkeleton *config, QObject *parent)
+ : QQmlPropertyMap(this, parent)
+ , d(new KConfigPropertyMapPrivate(this))
+{
+ Q_ASSERT(config);
+ d->config = config;
+
+ // Reload the config only if the change signal has *not* been emitted by ourselves updating the config
+ connect(config, &KCoreConfigSkeleton::configChanged, this, [this]() {
+ if (!d->updatingConfigValue) {
+ d->loadConfig(KConfigPropertyMapPrivate::EmitValueChanged);
+ }
+ });
+ connect(this, &KConfigPropertyMap::valueChanged, this, [this](const QString &key, const QVariant &value) {
+ d->writeConfigValue(key, value);
+ });
+
+ d->loadConfig(KConfigPropertyMapPrivate::DontEmitValueChanged);
+}
+
+KConfigPropertyMap::~KConfigPropertyMap() = default;
+
+bool KConfigPropertyMap::isNotify() const
+{
+ return d->notify;
+}
+
+void KConfigPropertyMap::setNotify(bool notify)
+{
+ d->notify = notify;
+}
+
+void KConfigPropertyMap::writeConfig()
+{
+ d->writeConfig();
+}
+
+QVariant KConfigPropertyMap::updateValue(const QString &key, const QVariant &input)
+{
+ Q_UNUSED(key);
+ if (input.userType() == qMetaTypeId<QJSValue>()) {
+ return input.value<QJSValue>().toVariant();
+ }
+ return input;
+}
+
+bool KConfigPropertyMap::isImmutable(const QString &key) const
+{
+ KConfigSkeletonItem *item = d->config.data()->findItem(key);
+ if (item) {
+ return item->isImmutable();
+ }
+
+ return false;
+}
+
+void KConfigPropertyMapPrivate::loadConfig(KConfigPropertyMapPrivate::LoadConfigOption option)
+{
+ if (!config) {
+ return;
+ }
+
+ const auto &items = config.data()->items();
+ for (KConfigSkeletonItem *item : items) {
+ q->insert(item->key() + QStringLiteral("Default"), item->getDefault());
+ q->insert(item->key(), item->property());
+ if (option == EmitValueChanged) {
+ Q_EMIT q->valueChanged(item->key(), item->property());
+ }
+ }
+}
+
+void KConfigPropertyMapPrivate::writeConfig()
+{
+ if (!config) {
+ return;
+ }
+
+ const auto lstItems = config.data()->items();
+ for (KConfigSkeletonItem *item : lstItems) {
+ item->setWriteFlags(notify ? KConfigBase::Notify : KConfigBase::Normal);
+ item->setProperty(q->value(item->key()));
+ }
+
+ if (autosave) {
+ updatingConfigValue = true;
+ config.data()->save();
+ updatingConfigValue = false;
+ }
+}
+
+void KConfigPropertyMapPrivate::writeConfigValue(const QString &key, const QVariant &value)
+{
+ KConfigSkeletonItem *item = config.data()->findItem(key);
+ if (item) {
+ updatingConfigValue = true;
+ item->setWriteFlags(notify ? KConfigBase::Notify : KConfigBase::Normal);
+ item->setProperty(value);
+ if (autosave) {
+ config.data()->save();
+ // why read? read will update KConfigSkeletonItem::mLoadedValue,
+ // allowing a write operation to be performed next time
+ config.data()->read();
+ }
+ updatingConfigValue = false;
+ }
+}
+
diff --git a/src/qml/kconfigpropertymap.h b/src/qml/kconfigpropertymap.h
new file mode 100644
index 00000000..3795e099
--- /dev/null
+++ b/src/qml/kconfigpropertymap.h
@@ -0,0 +1,69 @@
+/*
+ SPDX-FileCopyrightText: 2013 Marco Martin <notmart@gmail.com>
+ SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
+ SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
+
+ SPDX-License-Identifier: LGPL-2.0-or-later
+*/
+
+#ifndef KCONFIGPROPERTYMAP_H
+#define KCONFIGPROPERTYMAP_H
+
+#include <QQmlPropertyMap>
+#include <memory>
+
+class KCoreConfigSkeleton;
+
+#include <kconfigqml_export.h>
+
+class KConfigPropertyMapPrivate;
+
+/**
+ * @class KConfigPropertyMap configpropertymap.h ConfigPropertyMap
+ *
+ * An object that (optionally) automatically saves changes in a
+ * property map to a configuration object (e.g. a KConfig file).
+ * @since 5.89
+ */
+class KCONFIGQML_EXPORT KConfigPropertyMap : public QQmlPropertyMap
+{
+ Q_OBJECT
+
+public:
+ KConfigPropertyMap(KCoreConfigSkeleton *config, QObject *parent = nullptr);
+ ~KConfigPropertyMap() override;
+
+ /**
+ * Whether notifications on config changes are enabled. Disabled by default.
+ * @see KConfigBase::Notify
+ * @return true if writes send (dbus) notifications
+ */
+ bool isNotify() const;
+
+ /**
+ * Enable or disable notifications on config changes.
+ * @see KConfigBase::Notify
+ * @param notify whether to send notifications
+ */
+ void setNotify(bool notify);
+
+ /**
+ * @brief Whether the value at the given key is immutable
+ *
+ * @return true if the value is immutable, false if it isn't or it doesn't exist
+ */
+ Q_INVOKABLE bool isImmutable(const QString &key) const;
+
+ /**
+ * Saves the state of the property map on disk.
+ */
+ void writeConfig();
+
+protected:
+ QVariant updateValue(const QString &key, const QVariant &input) override;
+
+private:
+ std::unique_ptr<KConfigPropertyMapPrivate> const d;
+};
+
+#endif