Implement IRCv3 Server-Time
[quassel.git] / src / common / settings.h
1 /***************************************************************************
2  *   Copyright (C) 2005-2019 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 #include <utility>
28
29 #include <QCoreApplication>
30 #include <QHash>
31 #include <QSettings>
32 #include <QString>
33 #include <QVariant>
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 class COMMON_EXPORT Settings
49 {
50 public:
51     enum Mode
52     {
53         Default,
54         Custom
55     };
56
57 public:
58     //! Calls the given slot on change of the given key
59     template<typename Receiver, typename Slot>
60     void notify(const QString& key, const Receiver* receiver, Slot slot) const
61     {
62         static_assert(!std::is_same<Slot, const char*>::value, "Old-style slots not supported");
63         QObject::connect(notifier(normalizedKey(_group, keyForNotify(key))), &SettingsChangeNotifier::valueChanged, receiver, slot);
64     }
65
66     //! Sets up notification and calls the given slot to set the initial value
67     template<typename Receiver, typename Slot>
68     void initAndNotify(const QString& key, const Receiver* receiver, Slot slot, const QVariant& defaultValue = {}) const
69     {
70         notify(key, receiver, std::move(slot));
71         auto notifyKey = keyForNotify(key);
72         emit notifier(normalizedKey(_group, notifyKey))->valueChanged(localValue(notifyKey, defaultValue));
73     }
74
75     /**
76      * Get the major configuration version
77      *
78      * This indicates the backwards/forwards incompatible version of configuration.
79      *
80      * @return Major configuration version (the X in XX.YY)
81      */
82     virtual uint version() const;
83
84     /**
85      * Get the minor configuration version
86      *
87      * This indicates the backwards/forwards compatible version of configuration.
88      *
89      * @see Settings::setVersionMinor()
90      * @return Minor configuration version (the Y in XX.YY)
91      */
92     virtual uint versionMinor() const;
93
94     /**
95      * Set the minor configuration version
96      *
97      * When making backwards/forwards compatible changes, call this with the new version number.
98      * This does not implement any upgrade logic; implement that when checking Settings::version(),
99      * e.g. in Core::Core() and QtUiApplication::init().
100      *
101      * @param[in] versionMinor New minor version number
102      */
103     virtual void setVersionMinor(const uint versionMinor);
104
105     /**
106      * Persist unsaved changes to permanent storage
107      *
108      * @return true if succeeded, false otherwise
109      */
110     bool sync();
111
112     /**
113      * Check if the configuration storage is writable.
114      *
115      * @return true if writable, false otherwise
116      */
117     bool isWritable() const;
118
119 protected:
120     Settings(QString group, QString appName);
121     virtual ~Settings() = default;
122
123     void setGroup(QString group);
124
125     /**
126      * Allows subclasses to transform the key given to notify().
127      *
128      * Default implementation just returns the given key.
129      *
130      * @param key Key given to notify()
131      * @returns Key that should be used for notfication
132      */
133     virtual QString keyForNotify(const QString& key) const;
134
135     virtual QStringList allLocalKeys() const;
136     virtual QStringList localChildKeys(const QString& rootkey = QString()) const;
137     virtual QStringList localChildGroups(const QString& rootkey = QString()) const;
138
139     virtual void setLocalValue(const QString& key, const QVariant& data);
140     virtual QVariant localValue(const QString& key, const QVariant& def = QVariant()) const;
141
142     /**
143      * Gets if a key exists in settings
144      *
145      * @param[in] key ID of local settings key
146      * @returns True if key exists in settings, otherwise false
147      */
148     virtual bool localKeyExists(const QString& key) const;
149
150     virtual void removeLocalKey(const QString& key);
151
152     QString _group;
153     QString _appName;
154
155 private:
156     QSettings::Format format() const;
157
158     QString fileName() const;
159
160     QString normalizedKey(const QString& group, const QString& key) const;
161
162     /**
163      * Update the cache of whether or not a given settings key persists on disk
164      *
165      * @param normKey Normalized settings key ID
166      * @param exists  True if key exists, otherwise false
167      */
168     void setCacheKeyPersisted(const QString& normKey, bool exists) const;
169
170     /**
171      * Check if the given settings key ID persists on disk (rather than being a default value)
172      *
173      * @see Settings::localKeyExists()
174      *
175      * @param normKey Normalized settings key ID
176      * @return True if key exists and persistence has been cached, otherwise false
177      */
178     bool cacheKeyPersisted(const QString& normKey) const;
179
180     /**
181      * Check if the persistence of the given settings key ID has been cached
182      *
183      * @param normKey Normalized settings key ID
184      * @return True if key persistence has been cached, otherwise false
185      */
186     bool isKeyPersistedCached(const QString& normKey) const;
187
188     void setCacheValue(const QString& normKey, const QVariant& data) const;
189
190     QVariant cacheValue(const QString& normKey) const;
191
192     bool isCached(const QString& normKey) const;
193
194     SettingsChangeNotifier* notifier(const QString& normKey) const;
195
196     bool hasNotifier(const QString& normKey) const;
197
198 private:
199     static QHash<QString, QVariant> _settingsCache;          ///< Cached settings values
200     static QHash<QString, bool> _settingsKeyPersistedCache;  ///< Cached settings key exists on disk
201     static QHash<QString, std::shared_ptr<SettingsChangeNotifier>> _settingsChangeNotifier;
202 };