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 | |
17 | class KConfigPropertyMapPrivate |
18 | { |
19 | public: |
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 | |
40 | KConfigPropertyMap::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 | |
60 | KConfigPropertyMap::~KConfigPropertyMap() = default; |
61 | |
62 | bool KConfigPropertyMap::isNotify() const |
63 | { |
64 | return d->notify; |
65 | } |
66 | |
67 | void KConfigPropertyMap::setNotify(bool notify) |
68 | { |
69 | d->notify = notify; |
70 | } |
71 | |
72 | void KConfigPropertyMap::writeConfig() |
73 | { |
74 | d->writeConfig(); |
75 | } |
76 | |
77 | QVariant 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 | |
86 | bool 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 | |
96 | void 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 | |
112 | void 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 | |
127 | void 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 | |