1// SPDX-FileCopyrightText: 2016 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
6#include "quotient_export.h"
7#include "util.h"
8
9#include <QtCore/QSettings>
10#include <QtCore/QUrl>
11#include <QtCore/QVector>
12
13class QVariant;
14
15namespace Quotient {
16
17class QUOTIENT_API Settings : public QSettings {
18 Q_OBJECT
19public:
20 /// Add a legacy organisation/application name to migrate settings from
21 /*!
22 * Use this function before creating any Settings objects in order
23 * to set a legacy location where configuration has previously been stored.
24 * This will provide an additional fallback in case of renaming
25 * the organisation/application. Values in legacy locations are _removed_
26 * when setValue() or remove() is called.
27 */
28 static void setLegacyNames(const QString& organizationName,
29 const QString& applicationName = {});
30
31 explicit Settings(QObject* parent = nullptr);
32
33 /// Set the value for a given key
34 /*! If the key exists in the legacy location, it is removed. */
35 Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
36
37 /// Remove the value from both the primary and legacy locations
38 Q_INVOKABLE void remove(const QString& key);
39
40 /// Obtain a value for a given key
41 /*!
42 * If the key doesn't exist in the primary settings location, the legacy
43 * location is checked. If neither location has the key,
44 * \p defaultValue is returned.
45 *
46 * This function returns a QVariant; use get<>() to get the unwrapped
47 * value if you know the type upfront.
48 *
49 * \sa setLegacyNames, get
50 */
51 Q_INVOKABLE QVariant value(const QString& key,
52 const QVariant& defaultValue = {}) const;
53
54 /// Obtain a value for a given key, coerced to the given type
55 /*!
56 * On top of value(), this function unwraps the QVariant and returns
57 * its contents assuming the type passed as the template parameter.
58 * If the type is different from the one stored inside the QVariant,
59 * \p defaultValue is returned. In presence of legacy settings,
60 * only the first found value is checked; if its type does not match,
61 * further checks through legacy settings are not performed and
62 * \p defaultValue is returned.
63 */
64 template <typename T>
65 T get(const QString& key, const T& defaultValue = {}) const
66 {
67 const auto qv = value(key, defaultValue: QVariant());
68 return qv.isValid() && qv.canConvert<T>() ? qv.value<T>() : defaultValue;
69 }
70
71 Q_INVOKABLE bool contains(const QString& key) const;
72 Q_INVOKABLE QStringList childGroups() const;
73
74private:
75 static QString legacyOrganizationName;
76 static QString legacyApplicationName;
77
78protected:
79 QSettings legacySettings { legacyOrganizationName, legacyApplicationName };
80};
81
82class QUOTIENT_API SettingsGroup : public Settings {
83public:
84 explicit SettingsGroup(QString path, QObject* parent = nullptr)
85 : Settings(parent)
86 , groupPath(std::move(path))
87 {}
88
89 Q_INVOKABLE bool contains(const QString& key) const;
90 Q_INVOKABLE QVariant value(const QString& key,
91 const QVariant& defaultValue = {}) const;
92
93 template <typename T>
94 T get(const QString& key, const T& defaultValue = {}) const
95 {
96 const auto qv = value(key, defaultValue: QVariant());
97 return qv.isValid() && qv.canConvert<T>() ? qv.value<T>() : defaultValue;
98 }
99
100 Q_INVOKABLE QString group() const;
101 Q_INVOKABLE QStringList childGroups() const;
102 Q_INVOKABLE void setValue(const QString& key, const QVariant& value);
103
104 Q_INVOKABLE void remove(const QString& key);
105
106private:
107 QString groupPath;
108};
109
110#define QUO_DECLARE_SETTING(type, propname, setter) \
111 Q_PROPERTY(type propname READ propname WRITE setter) \
112public: \
113 type propname() const; \
114 void setter(type newValue); \
115 \
116private:
117
118#define QUO_DEFINE_SETTING(classname, type, propname, qsettingname, \
119 defaultValue, setter) \
120 type classname::propname() const \
121 { \
122 return get<type>(QStringLiteral(qsettingname), defaultValue); \
123 } \
124 \
125 void classname::setter(type newValue) \
126 { \
127 setValue(QStringLiteral(qsettingname), std::move(newValue)); \
128 }
129
130class QUOTIENT_API AccountSettings : public SettingsGroup {
131 Q_OBJECT
132 Q_PROPERTY(QString userId READ userId CONSTANT)
133 QUO_DECLARE_SETTING(QString, deviceId, setDeviceId)
134 QUO_DECLARE_SETTING(QString, deviceName, setDeviceName)
135 QUO_DECLARE_SETTING(bool, keepLoggedIn, setKeepLoggedIn)
136 Q_PROPERTY(QByteArray encryptionAccountPickle READ encryptionAccountPickle
137 WRITE setEncryptionAccountPickle)
138public:
139 explicit AccountSettings(const QString& accountId, QObject* parent = nullptr)
140 : SettingsGroup("Accounts/"_ls + accountId, parent)
141 {}
142
143 QString userId() const;
144
145 QUrl homeserver() const;
146 void setHomeserver(const QUrl& url);
147
148 Q_DECL_DEPRECATED_X("Access tokens are not stored in QSettings any more")
149 Q_INVOKABLE void clearAccessToken();
150
151 QByteArray encryptionAccountPickle();
152 void setEncryptionAccountPickle(const QByteArray& encryptionAccountPickle);
153 Q_INVOKABLE void clearEncryptionAccountPickle();
154};
155} // namespace Quotient
156