64bc46209286c020cf5913934f990c14d1d5b10f
[quassel.git] / src / common / settings.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #pragma once
22
23 #include "common-export.h"
24
25 #include <memory>
26 #include <type_traits>
27
28 #include <QCoreApplication>
29 #include <QHash>
30 #include <QSettings>
31 #include <QString>
32 #include <QVariant>
33 #include <utility>
34
35 #include "quassel.h"
36
37 class COMMON_EXPORT SettingsChangeNotifier : public QObject
38 {
39     Q_OBJECT
40
41 signals:
42     void valueChanged(const QVariant &newValue);
43
44 private:
45     friend class Settings;
46 };
47
48
49 class COMMON_EXPORT Settings
50 {
51 public:
52     enum Mode { Default, Custom };
53
54 public:
55     //! Calls the given slot on change of the given key
56     template<typename Receiver, typename Slot>
57     void notify(const QString &key, const Receiver *receiver, Slot slot) const
58     {
59         static_assert(!std::is_same<Slot, const char*>::value, "Old-style slots not supported");
60         QObject::connect(notifier(normalizedKey(_group, keyForNotify(key))), &SettingsChangeNotifier::valueChanged, receiver, slot);
61     }
62
63     //! Sets up notification and calls the given slot to set the initial value
64     template<typename Receiver, typename Slot>
65     void initAndNotify(const QString &key, const Receiver *receiver, Slot slot, const QVariant &defaultValue = {}) const
66     {
67         notify(key, receiver, std::move(slot));
68         auto notifyKey = keyForNotify(key);
69         emit notifier(normalizedKey(_group, notifyKey))->valueChanged(localValue(notifyKey, defaultValue));
70     }
71
72     /**
73      * Get the major configuration version
74      *
75      * This indicates the backwards/forwards incompatible version of configuration.
76      *
77      * @return Major configuration version (the X in XX.YY)
78      */
79     virtual uint version() const;
80
81     /**
82      * Get the minor configuration version
83      *
84      * This indicates the backwards/forwards compatible version of configuration.
85      *
86      * @see Settings::setVersionMinor()
87      * @return Minor configuration version (the Y in XX.YY)
88      */
89     virtual uint versionMinor() const;
90
91     /**
92      * Set the minor configuration version
93      *
94      * When making backwards/forwards compatible changes, call this with the new version number.
95      * This does not implement any upgrade logic; implement that when checking Settings::version(),
96      * e.g. in Core::Core() and QtUiApplication::init().
97      *
98      * @param[in] versionMinor New minor version number
99      */
100     virtual void setVersionMinor(const uint versionMinor);
101
102     /**
103      * Persist unsaved changes to permanent storage
104      *
105      * @return true if succeeded, false otherwise
106      */
107     bool sync();
108
109     /**
110      * Check if the configuration storage is writable.
111      *
112      * @return true if writable, false otherwise
113      */
114     bool isWritable() const;
115
116 protected:
117     Settings(QString group, QString appName);
118     virtual ~Settings() = default;
119
120     void setGroup(QString group);
121
122     /**
123      * Allows subclasses to transform the key given to notify().
124      *
125      * Default implementation just returns the given key.
126      *
127      * @param key Key given to notify()
128      * @returns Key that should be used for notfication
129      */
130     virtual QString keyForNotify(const QString &key) const;
131
132     virtual QStringList allLocalKeys() const;
133     virtual QStringList localChildKeys(const QString &rootkey = QString()) const;
134     virtual QStringList localChildGroups(const QString &rootkey = QString()) const;
135
136     virtual void setLocalValue(const QString &key, const QVariant &data);
137     virtual QVariant localValue(const QString &key, const QVariant &def = QVariant()) const;
138
139     /**
140      * Gets if a key exists in settings
141      *
142      * @param[in] key ID of local settings key
143      * @returns True if key exists in settings, otherwise false
144      */
145     virtual bool localKeyExists(const QString &key) const;
146
147     virtual void removeLocalKey(const QString &key);
148
149     QString _group;
150     QString _appName;
151
152 private:
153     QSettings::Format format() const;
154
155     QString fileName() const;
156
157     QString normalizedKey(const QString &group, const QString &key) const;
158
159     /**
160      * Update the cache of whether or not a given settings key persists on disk
161      *
162      * @param normKey Normalized settings key ID
163      * @param exists  True if key exists, otherwise false
164      */
165     void setCacheKeyPersisted(const QString &normKey, bool exists) const;
166
167     /**
168      * Check if the given settings key ID persists on disk (rather than being a default value)
169      *
170      * @see Settings::localKeyExists()
171      *
172      * @param normKey Normalized settings key ID
173      * @return True if key exists and persistence has been cached, otherwise false
174      */
175     bool cacheKeyPersisted(const QString &normKey) const;
176
177     /**
178      * Check if the persistence of the given settings key ID has been cached
179      *
180      * @param normKey Normalized settings key ID
181      * @return True if key persistence has been cached, otherwise false
182      */
183     bool isKeyPersistedCached(const QString &normKey) const;
184
185     void setCacheValue(const QString &normKey, const QVariant &data) const;
186
187     QVariant cacheValue(const QString &normKey) const;
188
189     bool isCached(const QString &normKey) const;
190
191     SettingsChangeNotifier *notifier(const QString &normKey) const;
192
193     bool hasNotifier(const QString &normKey) const;
194
195 private:
196     static QHash<QString, QVariant> _settingsCache;         ///< Cached settings values
197     static QHash<QString, bool> _settingsKeyPersistedCache; ///< Cached settings key exists on disk
198     static QHash<QString, std::shared_ptr<SettingsChangeNotifier>> _settingsChangeNotifier;
199 };