diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/qml/CMakeLists.txt | 39 | ||||
| -rw-r--r-- | src/qml/kconfigpropertymap.cpp | 148 | ||||
| -rw-r--r-- | src/qml/kconfigpropertymap.h | 69 | 
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 | 
