1/*
2 SPDX-FileCopyrightText: 2013 Marco Martin <notmart@gmail.com>
3 SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
4 SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "kconfigpropertymap.h"
10
11#include <KCoreConfigSkeleton>
12#include <QJSValue>
13#include <QPointer>
14
15#include <functional>
16
17class KConfigPropertyMapPrivate
18{
19public:
20 KConfigPropertyMapPrivate(KConfigPropertyMap *map)
21 : q(map)
22 {
23 }
24
25 enum LoadConfigOption {
26 DontEmitValueChanged,
27 EmitValueChanged,
28 };
29
30 void loadConfig(LoadConfigOption option);
31 void writeConfig();
32 void writeConfigValue(const QString &key, const QVariant &value);
33
34 KConfigPropertyMap *q;
35 QPointer<KCoreConfigSkeleton> config;
36 bool updatingConfigValue = false;
37 bool notify = false;
38};
39
40KConfigPropertyMap::KConfigPropertyMap(KCoreConfigSkeleton *config, QObject *parent)
41 : QQmlPropertyMap(this, parent)
42 , d(new KConfigPropertyMapPrivate(this))
43{
44 Q_ASSERT(config);
45 d->config = config;
46
47 // Reload the config only if the change signal has *not* been emitted by ourselves updating the config
48 connect(sender: config, signal: &KCoreConfigSkeleton::configChanged, context: this, slot: [this]() {
49 if (!d->updatingConfigValue) {
50 d->loadConfig(option: KConfigPropertyMapPrivate::EmitValueChanged);
51 }
52 });
53 connect(sender: this, signal: &KConfigPropertyMap::valueChanged, context: this, slot: [this](const QString &key, const QVariant &value) {
54 d->writeConfigValue(key, value);
55 });
56
57 d->loadConfig(option: KConfigPropertyMapPrivate::DontEmitValueChanged);
58}
59
60KConfigPropertyMap::~KConfigPropertyMap() = default;
61
62bool KConfigPropertyMap::isNotify() const
63{
64 return d->notify;
65}
66
67void KConfigPropertyMap::setNotify(bool notify)
68{
69 d->notify = notify;
70}
71
72void KConfigPropertyMap::writeConfig()
73{
74 d->writeConfig();
75}
76
77QVariant KConfigPropertyMap::updateValue(const QString &key, const QVariant &input)
78{
79 Q_UNUSED(key);
80 if (input.userType() == qMetaTypeId<QJSValue>()) {
81 return input.value<QJSValue>().toVariant();
82 }
83 return input;
84}
85
86bool KConfigPropertyMap::isImmutable(const QString &key) const
87{
88 KConfigSkeletonItem *item = d->config.data()->findItem(name: key);
89 if (item) {
90 return item->isImmutable();
91 }
92
93 return false;
94}
95
96void KConfigPropertyMapPrivate::loadConfig(KConfigPropertyMapPrivate::LoadConfigOption option)
97{
98 if (!config) {
99 return;
100 }
101
102 const auto &items = config.data()->items();
103 for (KConfigSkeletonItem *item : items) {
104 q->insert(key: item->key() + QStringLiteral("Default"), value: item->getDefault());
105 q->insert(key: item->key(), value: item->property());
106 if (option == EmitValueChanged) {
107 Q_EMIT q->valueChanged(key: item->key(), value: item->property());
108 }
109 }
110}
111
112void KConfigPropertyMapPrivate::writeConfig()
113{
114 if (!config) {
115 return;
116 }
117
118 const auto lstItems = config.data()->items();
119 for (KConfigSkeletonItem *item : lstItems) {
120 item->setWriteFlags(notify ? KConfigBase::Notify : KConfigBase::Normal);
121 item->setProperty(q->value(key: item->key()));
122 }
123 // Internally sync the config. This way we ensure the config file is written, even if the process crashed
124 config.data()->save();
125}
126
127void KConfigPropertyMapPrivate::writeConfigValue(const QString &key, const QVariant &value)
128{
129 KConfigSkeletonItem *item = config.data()->findItem(name: key);
130 if (item) {
131 updatingConfigValue = true;
132 item->setWriteFlags(notify ? KConfigBase::Notify : KConfigBase::Normal);
133 item->setProperty(value);
134 updatingConfigValue = false;
135 }
136}
137
138#include "moc_kconfigpropertymap.cpp"
139

source code of kconfig/src/qml/kconfigpropertymap.cpp