Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgssettings.h
3 : : --------------------------------------
4 : : Date : January 2017
5 : : Copyright : (C) 2017 by Alessandro Pasotti
6 : : Email : apasotti at boundlessgeo dot com
7 : : ***************************************************************************
8 : : * *
9 : : * This program is free software; you can redistribute it and/or modify *
10 : : * it under the terms of the GNU General Public License as published by *
11 : : * the Free Software Foundation; either version 2 of the License, or *
12 : : * (at your option) any later version. *
13 : : * *
14 : : ***************************************************************************/
15 : :
16 : :
17 : : #ifndef QGSSETTINGS_H
18 : : #define QGSSETTINGS_H
19 : :
20 : : #include <QSettings>
21 : : #include <QMetaEnum>
22 : :
23 : : #include "qgis_core.h"
24 : : #include "qgis_sip.h"
25 : : #include "qgslogger.h"
26 : :
27 : : /**
28 : : * \ingroup core
29 : : * \class QgsSettings
30 : : *
31 : : * \brief This class is a composition of two QSettings instances:
32 : : *
33 : : * - the main QSettings instance is the standard User Settings and
34 : : * - the second one (Global Settings) is meant to provide read-only
35 : : * pre-configuration and defaults to the first one.
36 : : *
37 : : * For a given settings key, the function call to value(key, default) will return
38 : : * the first existing setting in the order specified below:
39 : : *
40 : : * - User Settings
41 : : * - Global Settings
42 : : * - Default Value
43 : : *
44 : : * The path to the Global Settings storage can be set before constructing the QgsSettings
45 : : * objects, with a static call to:
46 : : * static bool setGlobalSettingsPath( QString path );
47 : : *
48 : : * QgsSettings provides some shortcuts to get/set namespaced settings from/to a specific section:
49 : : *
50 : : * - Core
51 : : * - Gui
52 : : * - Server
53 : : * - Plugins
54 : : * - Auth
55 : : * - App
56 : : * - Providers
57 : : * - Misc
58 : : *
59 : : * \since QGIS 3.0
60 : : */
61 : : class CORE_EXPORT QgsSettings : public QObject
62 : : {
63 : : Q_OBJECT
64 : : public:
65 : :
66 : : //! Sections for namespaced settings
67 : : enum Section
68 : : {
69 : : NoSection,
70 : : Core,
71 : : Gui,
72 : : Server,
73 : : Plugins,
74 : : Auth,
75 : : App,
76 : : Providers,
77 : : Expressions,
78 : : Misc
79 : : };
80 : :
81 : : /**
82 : : * Constructs a QgsSettings object for accessing settings of the application
83 : : * called application from the organization called organization, and with parent parent.
84 : : */
85 : : explicit QgsSettings( const QString &organization,
86 : : const QString &application = QString(), QObject *parent = nullptr );
87 : :
88 : : /**
89 : : * Constructs a QgsSettings object for accessing settings of the application called application
90 : : * from the organization called organization, and with parent parent.
91 : : *
92 : : * If scope is QSettings::UserScope, the QSettings object searches user-specific settings first,
93 : : * before it searches system-wide settings as a fallback. If scope is QSettings::SystemScope,
94 : : * the QSettings object ignores user-specific settings and provides access to system-wide settings.
95 : : *
96 : : * The storage format is set to QSettings::NativeFormat (i.e. calling setDefaultFormat() before
97 : : * calling this constructor has no effect).
98 : : *
99 : : * If no application name is given, the QSettings object will only access the organization-wide
100 : : * locations.
101 : : */
102 : : QgsSettings( QSettings::Scope scope, const QString &organization,
103 : : const QString &application = QString(), QObject *parent = nullptr );
104 : :
105 : : /**
106 : : * Constructs a QgsSettings object for accessing settings of the application called application
107 : : * from the organization called organization, and with parent parent.
108 : : *
109 : : * If scope is QSettings::UserScope, the QSettings object searches user-specific settings first,
110 : : * before it searches system-wide settings as a fallback. If scope is QSettings::SystemScope,
111 : : * the QSettings object ignores user-specific settings and provides access to system-wide settings.
112 : : *
113 : : * If format is QSettings::NativeFormat, the native API is used for storing settings. If format
114 : : * is QSettings::IniFormat, the INI format is used.
115 : : *
116 : : * If no application name is given, the QSettings object will only access the organization-wide
117 : : * locations.
118 : : */
119 : : QgsSettings( QSettings::Format format, QSettings::Scope scope, const QString &organization,
120 : : const QString &application = QString(), QObject *parent = nullptr );
121 : :
122 : : /**
123 : : * Constructs a QgsSettings object for accessing the settings stored in the file called fileName,
124 : : * with parent parent. If the file doesn't already exist, it is created.
125 : : *
126 : : * If format is QSettings::NativeFormat, the meaning of fileName depends on the platform. On Unix,
127 : : * fileName is the name of an INI file. On macOS and iOS, fileName is the name of a .plist file.
128 : : * On Windows, fileName is a path in the system registry.
129 : : *
130 : : * If format is QSettings::IniFormat, fileName is the name of an INI file.
131 : : *
132 : : * \warning This function is provided for convenience. It works well for accessing INI or .plist
133 : : * files generated by Qt, but might fail on some syntaxes found in such files originated by
134 : : * other programs. In particular, be aware of the following limitations:
135 : : *
136 : : * - QgsSettings provides no way of reading INI "path" entries, i.e., entries with unescaped slash characters.
137 : : * (This is because these entries are ambiguous and cannot be resolved automatically.)
138 : : * - In INI files, QSettings uses the @ character as a metacharacter in some contexts, to encode
139 : : * Qt-specific data types (e.g., \@Rect), and might therefore misinterpret it when it occurs
140 : : * in pure INI files.
141 : : */
142 : : QgsSettings( const QString &fileName, QSettings::Format format, QObject *parent = nullptr );
143 : :
144 : : /**
145 : : * Constructs a QgsSettings object for accessing settings of the application and organization
146 : : * set previously with a call to QCoreApplication::setOrganizationName(),
147 : : * QCoreApplication::setOrganizationDomain(), and QCoreApplication::setApplicationName().
148 : : *
149 : : * The scope is QSettings::UserScope and the format is defaultFormat() (QSettings::NativeFormat
150 : : * by default). Use setDefaultFormat() before calling this constructor to change the default
151 : : * format used by this constructor.
152 : : */
153 : : explicit QgsSettings( QObject *parent = nullptr );
154 : : ~QgsSettings() override;
155 : :
156 : : /**
157 : : * Appends prefix to the current group.
158 : : * The current group is automatically prepended to all keys specified to QSettings.
159 : : * In addition, query functions such as childGroups(), childKeys(), and allKeys()
160 : : * are based on the group. By default, no group is set.
161 : : */
162 : : void beginGroup( const QString &prefix, QgsSettings::Section section = QgsSettings::NoSection );
163 : : //! Resets the group to what it was before the corresponding beginGroup() call.
164 : : void endGroup();
165 : :
166 : : /**
167 : : * Returns the current group.
168 : : * \see beginGroup()
169 : : * \see endGroup()
170 : : * \since QGIS 3.6
171 : : */
172 : : QString group() const;
173 : :
174 : : //! Returns a list of all keys, including subkeys, that can be read using the QSettings object.
175 : : QStringList allKeys() const;
176 : : //! Returns a list of all top-level keys that can be read using the QSettings object.
177 : : QStringList childKeys() const;
178 : : //! Returns a list of all key top-level groups that contain keys that can be read using the QSettings object.
179 : : QStringList childGroups() const;
180 : : //! Returns a list of all key top-level groups (same as childGroups) but only for groups defined in global settings.
181 : : QStringList globalChildGroups() const;
182 : : //! Returns the path to the Global Settings QSettings storage file
183 : : static QString globalSettingsPath();
184 : : //! Sets the Global Settings QSettings storage file
185 : : static bool setGlobalSettingsPath( const QString &path );
186 : : //! Adds prefix to the current group and starts reading from an array. Returns the size of the array.
187 : : int beginReadArray( const QString &prefix );
188 : :
189 : : /**
190 : : * Adds prefix to the current group and starts writing an array of size size.
191 : : * If size is -1 (the default), it is automatically determined based on the indexes of the entries written.
192 : : * \note This will completely shadow any existing array with the same name in the global settings
193 : : */
194 : : void beginWriteArray( const QString &prefix, int size = -1 );
195 : : //! Closes the array that was started using beginReadArray() or beginWriteArray().
196 : : void endArray();
197 : :
198 : : /**
199 : : * Sets the current array index to i. Calls to functions such as setValue(), value(),
200 : : * remove(), and contains() will operate on the array entry at that index.
201 : : */
202 : : void setArrayIndex( int i );
203 : :
204 : : /**
205 : : * Sets the value of setting key to value. If the key already exists, the previous value is overwritten.
206 : : * An optional Section argument can be used to set a value to a specific Section.
207 : : */
208 : : void setValue( const QString &key, const QVariant &value, QgsSettings::Section section = QgsSettings::NoSection );
209 : :
210 : : /**
211 : : * Returns the value for setting key. If the setting doesn't exist, it will be
212 : : * searched in the Global Settings and if not found, returns defaultValue.
213 : : * If no default value is specified, a default QVariant is returned.
214 : : * An optional Section argument can be used to get a value from a specific Section.
215 : : */
216 : : #ifndef SIP_RUN
217 : : QVariant value( const QString &key, const QVariant &defaultValue = QVariant(),
218 : : Section section = NoSection ) const;
219 : : #else
220 : : SIP_PYOBJECT value( const QString &key, const QVariant &defaultValue = QVariant(),
221 : : SIP_PYOBJECT type = 0,
222 : : QgsSettings::Section section = QgsSettings::NoSection ) const / ReleaseGIL /;
223 : : % MethodCode
224 : : typedef PyObject *( *pyqt5_from_qvariant_by_type )( QVariant &value, PyObject *type );
225 : : QVariant value;
226 : :
227 : : // QSettings has an internal mutex so release the GIL to avoid the possibility of deadlocks.
228 : : Py_BEGIN_ALLOW_THREADS
229 : : value = sipCpp->value( *a0, *a1, a3 );
230 : : Py_END_ALLOW_THREADS
231 : :
232 : : pyqt5_from_qvariant_by_type f = ( pyqt5_from_qvariant_by_type ) sipImportSymbol( "pyqt5_from_qvariant_by_type" );
233 : : sipRes = f( value, a2 );
234 : :
235 : : sipIsErr = !sipRes;
236 : : % End
237 : : #endif
238 : :
239 : : #ifndef SIP_RUN
240 : :
241 : : /**
242 : : * Returns the setting value for a setting based on an enum.
243 : : * This forces the output to be a valid and existing entry of the enum.
244 : : * Hence if the setting value is incorrect, the given default value is returned.
245 : : * This tries first with setting as a string (as the enum) and then as an integer value.
246 : : * \note The enum needs to be declared with Q_ENUM, and flags with Q_FLAG (not Q_FLAGS).
247 : : * \note for Python bindings, a custom implementation is achieved in Python directly
248 : : * \see setEnumValue
249 : : * \see flagValue
250 : : */
251 : : template <class T>
252 : 106 : T enumValue( const QString &key, const T &defaultValue,
253 : : const Section section = NoSection )
254 : : {
255 : 106 : QMetaEnum metaEnum = QMetaEnum::fromType<T>();
256 : : Q_ASSERT( metaEnum.isValid() );
257 : 106 : if ( !metaEnum.isValid() )
258 : : {
259 : 0 : QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
260 : 0 : }
261 : :
262 : : T v;
263 : 106 : bool ok = false;
264 : :
265 : 106 : if ( metaEnum.isValid() )
266 : : {
267 : : // read as string
268 : 106 : QByteArray ba = value( key, metaEnum.valueToKey( static_cast<int>( defaultValue ) ), section ).toString().toUtf8();
269 : 106 : const char *vs = ba.data();
270 : 106 : v = static_cast<T>( metaEnum.keyToValue( vs, &ok ) );
271 : 106 : if ( ok )
272 : 106 : return v;
273 : 106 : }
274 : :
275 : : // if failed, try to read as int (old behavior)
276 : : // this code shall be removed later (probably after QGIS 3.4 LTR for 3.6)
277 : : // then the method could be marked as const
278 : 0 : v = static_cast<T>( value( key, static_cast<int>( defaultValue ), section ).toInt( &ok ) );
279 : 0 : if ( metaEnum.isValid() )
280 : : {
281 : 0 : if ( !ok || !metaEnum.valueToKey( static_cast<int>( v ) ) )
282 : : {
283 : 0 : v = defaultValue;
284 : 0 : }
285 : : else
286 : : {
287 : : // found setting as an integer
288 : : // convert the setting to the new form (string)
289 : 0 : setEnumValue( key, v, section );
290 : : }
291 : 0 : }
292 : :
293 : 0 : return v;
294 : 106 : }
295 : :
296 : : /**
297 : : * Set the value of a setting based on an enum.
298 : : * The setting will be saved as string.
299 : : * \note The enum needs to be declared with Q_ENUM, and flags with Q_FLAG (not Q_FLAGS).
300 : : * \see enumValue
301 : : * \see setFlagValue
302 : : */
303 : : template <class T>
304 : 0 : void setEnumValue( const QString &key, const T &value,
305 : : const Section section = NoSection )
306 : : {
307 : 0 : QMetaEnum metaEnum = QMetaEnum::fromType<T>();
308 : : Q_ASSERT( metaEnum.isValid() );
309 : 0 : if ( metaEnum.isValid() )
310 : : {
311 : 0 : setValue( key, metaEnum.valueToKey( static_cast<int>( value ) ), section );
312 : 0 : }
313 : : else
314 : : {
315 : 0 : QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
316 : : }
317 : 0 : }
318 : :
319 : : /**
320 : : * Returns the setting value for a setting based on a flag.
321 : : * This forces the output to be a valid and existing entry of the flag.
322 : : * Hence if the setting value is incorrect, the given default value is returned.
323 : : * This tries first with setting as a string (using a byte array) and then as an integer value.
324 : : * \note The flag needs to be declared with Q_FLAG (not Q_FLAGS).
325 : : * \note for Python bindings, a custom implementation is achieved in Python directly.
326 : : * \see setFlagValue
327 : : * \see enumValue
328 : : */
329 : : template <class T>
330 : 91 : T flagValue( const QString &key, const T &defaultValue,
331 : : const Section section = NoSection )
332 : : {
333 : 91 : QMetaEnum metaEnum = QMetaEnum::fromType<T>();
334 : : Q_ASSERT( metaEnum.isValid() );
335 : 91 : if ( !metaEnum.isValid() )
336 : : {
337 : 0 : QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
338 : 0 : }
339 : :
340 : 91 : T v = defaultValue;
341 : 91 : bool ok = false;
342 : :
343 : 91 : if ( metaEnum.isValid() )
344 : : {
345 : : // read as string
346 : 91 : QByteArray ba = value( key, metaEnum.valueToKeys( defaultValue ) ).toString().toUtf8();
347 : 91 : const char *vs = ba.data();
348 : 91 : v = static_cast<T>( metaEnum.keysToValue( vs, &ok ) );
349 : 91 : }
350 : 91 : if ( !ok )
351 : : {
352 : : // if failed, try to read as int (old behavior)
353 : : // this code shall be removed later (probably after QGIS 3.4 LTR for 3.6)
354 : : // then the method could be marked as const
355 : 0 : v = T( value( key, static_cast<int>( defaultValue ), section ).toInt( &ok ) );
356 : 0 : if ( metaEnum.isValid() )
357 : : {
358 : 0 : if ( !ok || metaEnum.valueToKeys( static_cast<int>( v ) ).isEmpty() )
359 : : {
360 : 0 : v = defaultValue;
361 : 0 : }
362 : : else
363 : : {
364 : : // found setting as an integer
365 : : // convert the setting to the new form (string)
366 : 0 : setFlagValue( key, v, section );
367 : : }
368 : 0 : }
369 : 0 : }
370 : :
371 : 91 : return v;
372 : 0 : }
373 : :
374 : : /**
375 : : * Set the value of a setting based on a flaf.
376 : : * The setting will be saved as string.
377 : : * \note The flag needs to be declared with Q_FLAG (not Q_FLAGS).
378 : : * \see flagValue
379 : : * \see setEnumValue
380 : : */
381 : : template <class T>
382 : 0 : void setFlagValue( const QString &key, const T &value,
383 : : const Section section = NoSection )
384 : : {
385 : 0 : QMetaEnum metaEnum = QMetaEnum::fromType<T>();
386 : : Q_ASSERT( metaEnum.isValid() );
387 : 0 : if ( metaEnum.isValid() )
388 : : {
389 : 0 : setValue( key, metaEnum.valueToKeys( value ), section );
390 : 0 : }
391 : : else
392 : : {
393 : 0 : QgsDebugMsg( QStringLiteral( "Invalid metaenum. Enum probably misses Q_ENUM or Q_FLAG declaration." ) );
394 : : }
395 : 0 : }
396 : : #endif
397 : :
398 : : /**
399 : : * Returns TRUE if there exists a setting called key; returns FALSE otherwise.
400 : : * If a group is set using beginGroup(), key is taken to be relative to that group.
401 : : */
402 : : bool contains( const QString &key, QgsSettings::Section section = QgsSettings::NoSection ) const;
403 : : //! Returns the path where settings written using this QSettings object are stored.
404 : : QString fileName() const;
405 : :
406 : : /**
407 : : * Writes any unsaved changes to permanent storage, and reloads any settings that have been
408 : : * changed in the meantime by another application.
409 : : * This function is called automatically from QSettings's destructor and by the event
410 : : * loop at regular intervals, so you normally don't need to call it yourself.
411 : : */
412 : : void sync();
413 : : //! Removes the setting key and any sub-settings of key in a section.
414 : : void remove( const QString &key, QgsSettings::Section section = QgsSettings::NoSection );
415 : : //! Returns the sanitized and prefixed key
416 : : QString prefixedKey( const QString &key, QgsSettings::Section section ) const;
417 : : //! Removes all entries in the user settings
418 : : void clear();
419 : :
420 : : private:
421 : : void init();
422 : : QString sanitizeKey( const QString &key ) const;
423 : : QSettings *mUserSettings = nullptr;
424 : : QSettings *mGlobalSettings = nullptr;
425 : : bool mUsingGlobalArray = false;
426 : : Q_DISABLE_COPY( QgsSettings )
427 : :
428 : : };
429 : :
430 : : #endif // QGSSETTINGS_H
|