Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qqmlsettings.cpp
Go to the documentation of this file.
1
// Copyright (C) 2022 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qqmlsettings_p.h"
6
7
#
include
<
QtQml
/
qjsvalue
.
h
>
8
#
include
<
QtQml
/
qqmlfile
.
h
>
9
#
include
<
QtQml
/
qqmlinfo
.
h
>
10
11
#
include
<
QtCore
/
qbasictimer
.
h
>
12
#
include
<
QtCore
/
qcoreapplication
.
h
>
13
#
include
<
QtCore
/
qcoreevent
.
h
>
14
#
include
<
QtCore
/
qdebug
.
h
>
15
#
include
<
QtCore
/
qhash
.
h
>
16
#
include
<
QtCore
/
qloggingcategory
.
h
>
17
#
include
<
QtCore
/
qpointer
.
h
>
18
#
include
<
QtCore
/
qsettings
.
h
>
19
20
using
namespace
Qt::StringLiterals;
21
using
namespace
std::chrono_literals;
22
23
QT_BEGIN_NAMESPACE
24
25
/*!
26
\qmltype Settings
27
//! \nativetype QQmlSettings
28
\inherits QtObject
29
\inqmlmodule QtCore
30
\since 6.5
31
\brief Provides persistent platform-independent application settings.
32
33
The Settings type provides persistent platform-independent application settings.
34
35
Users normally expect an application to remember its settings (window sizes
36
and positions, options, etc.) across sessions. The Settings type enables you
37
to save and restore such application settings with the minimum of effort.
38
39
Individual setting values are specified by declaring properties within a
40
Settings element. Only value types recognized by QSettings are supported.
41
The recommended approach is to use property aliases in order
42
to get automatic property updates both ways. The following example shows
43
how to use Settings to store and restore the geometry of a window.
44
45
\qml
46
import QtCore
47
import QtQuick
48
49
Window {
50
id: window
51
52
width: 800
53
height: 600
54
55
Settings {
56
property alias x: window.x
57
property alias y: window.y
58
property alias width: window.width
59
property alias height: window.height
60
}
61
}
62
\endqml
63
64
At first application startup, the window gets default dimensions specified
65
as 800x600. Notice that no default position is specified - we let the window
66
manager handle that. Later when the window geometry changes, new values will
67
be automatically stored to the persistent settings. The second application
68
run will get initial values from the persistent settings, bringing the window
69
back to the previous position and size.
70
71
A fully declarative syntax, achieved by using property aliases, comes at the
72
cost of storing persistent settings whenever the values of aliased properties
73
change. Normal properties can be used to gain more fine-grained control over
74
storing the persistent settings. The following example illustrates how to save
75
a setting on component destruction.
76
77
\qml
78
import QtCore
79
import QtQuick
80
81
Item {
82
id: page
83
84
state: settings.state
85
86
states: [
87
State {
88
name: "active"
89
// ...
90
},
91
State {
92
name: "inactive"
93
// ...
94
}
95
]
96
97
Settings {
98
id: settings
99
property string state: "active"
100
}
101
102
Component.onDestruction: {
103
settings.state = page.state
104
}
105
}
106
\endqml
107
108
Notice how the default value is now specified in the persistent setting property,
109
and the actual property is bound to the setting in order to get the initial value
110
from the persistent settings.
111
112
\section1 Application Identifiers
113
114
Application specific settings are identified by providing application
115
\l {QCoreApplication::applicationName}{name},
116
\l {QCoreApplication::organizationName}{organization} and
117
\l {QCoreApplication::organizationDomain}{domain}, or by specifying
118
\l location.
119
120
\code
121
#include <QGuiApplication>
122
#include <QQmlApplicationEngine>
123
124
int main(int argc, char *argv[])
125
{
126
QGuiApplication app(argc, argv);
127
app.setOrganizationName("Some Company");
128
app.setOrganizationDomain("somecompany.com");
129
app.setApplicationName("Amazing Application");
130
131
QQmlApplicationEngine engine("main.qml");
132
return app.exec();
133
}
134
\endcode
135
136
These are typically specified in C++ in the beginning of \c main(),
137
but can also be controlled in QML via the following properties:
138
\list
139
\li \l {Qt::application}{Qt.application.name},
140
\li \l {Qt::application}{Qt.application.organization} and
141
\li \l {Qt::application}{Qt.application.domain}.
142
\endlist
143
144
\section1 Categories
145
146
Application settings may be divided into logical categories by specifying
147
a category name via the \l category property. Using logical categories not
148
only provides a cleaner settings structure, but also prevents possible
149
conflicts between setting keys.
150
151
If several categories are required, use several Settings objects, each with
152
their own category:
153
154
\qml
155
Item {
156
id: panel
157
158
visible: true
159
160
Settings {
161
category: "OutputPanel"
162
property alias visible: panel.visible
163
// ...
164
}
165
166
Settings {
167
category: "General"
168
property alias fontSize: fontSizeSpinBox.value
169
// ...
170
}
171
}
172
\endqml
173
174
Instead of ensuring that all settings in the application have unique names,
175
the settings can be divided into unique categories that may then contain
176
settings using the same names that are used in other categories - without
177
a conflict.
178
179
\section1 Settings singleton
180
181
It's often useful to have settings available to every QML file as a
182
singleton. For an example of this, see the
183
\l {Qt Quick Controls - To Do List}{To Do List example}. Specifically,
184
\l {https://code.qt.io/cgit/qt/qtdeclarative.git/tree/examples/quickcontrols/ios/todolist/AppSettings.qml}
185
{AppSettings.qml} is the singleton, and in the
186
\l {https://code.qt.io/cgit/qt/qtdeclarative.git/tree/examples/quickcontrols/ios/todolist/CMakeLists.txt}
187
{CMakeLists.txt file},
188
the \c QT_QML_SINGLETON_TYPE property is set to \c TRUE for that file via
189
\c set_source_files_properties.
190
191
\section1 Notes
192
193
The current implementation is based on \l QSettings. This imposes certain
194
limitations, such as missing change notifications. Writing a setting value
195
using one instance of Settings does not update the value in another Settings
196
instance, even if they are referring to the same setting in the same category.
197
198
The information is stored in the system registry on Windows, and in XML
199
preferences files on \macos. On other Unix systems, in the absence of a
200
standard, INI text files are used. See \l QSettings documentation for
201
more details.
202
203
\sa QSettings
204
*/
205
206
using
namespace
Qt::StringLiterals;
207
208
Q_STATIC_LOGGING_CATEGORY
(lcQmlSettings,
"qt.core.settings"
)
209
210
static
constexpr
auto
settingsWriteDelay
= 500ms;
211
212
class
QQmlSettingsPrivate
213
{
214
Q_DISABLE_COPY_MOVE
(
QQmlSettingsPrivate
)
215
Q_DECLARE_PUBLIC
(
QQmlSettings
)
216
217
public
:
218
QQmlSettingsPrivate
() =
default
;
219
~
QQmlSettingsPrivate
() =
default
;
220
221
QSettings
*
instance
()
const
;
222
223
void
init
();
224
void
reset
();
225
226
void
load
();
227
void
store
();
228
229
void
_q_propertyChanged
();
230
QVariant
readProperty
(
const
QMetaProperty &property)
const
;
231
232
QQmlSettings
*
q_ptr
=
nullptr
;
233
QBasicTimer
timer
;
234
bool
initialized
=
false
;
235
QString
category
= {};
236
QUrl
location
= {};
237
mutable
QPointer
<
QSettings
>
settings
=
nullptr
;
238
QHash
<
const
char
*,
QVariant
>
changedProperties
= {};
239
};
240
241
QSettings
*
QQmlSettingsPrivate
::
instance
()
const
242
{
243
if
(settings)
244
return
settings;
245
246
QQmlSettings *q =
const_cast
<QQmlSettings *>(q_func());
247
settings = QQmlFile::isLocalFile(location)
248
?
new
QSettings(QQmlFile::urlToLocalFileOrQrc(location), QSettings::IniFormat, q)
249
:
new
QSettings(q);
250
251
if
(settings->status() != QSettings::NoError) {
252
// TODO: can't print out the enum due to the following error:
253
// error: C2666: 'QQmlInfo::operator <<': 15 overloads have similar conversions
254
qmlWarning(q) <<
"Failed to initialize QSettings instance. Status code is: "
<<
int
(settings->status());
255
256
if
(settings->status() == QSettings::AccessError) {
257
QStringList missingIdentifiers = {};
258
if
(QCoreApplication::organizationName().isEmpty())
259
missingIdentifiers.append(u"organizationName"_s);
260
if
(QCoreApplication::organizationDomain().isEmpty())
261
missingIdentifiers.append(u"organizationDomain"_s);
262
if
(QCoreApplication::applicationName().isEmpty())
263
missingIdentifiers.append(u"applicationName"_s);
264
265
if
(!missingIdentifiers.isEmpty()) {
266
#
ifdef
Q_CC_MSVC
267
QString formattedList = QStringLiteral(
"QList(\""
)
268
+ missingIdentifiers.join(QStringLiteral(
"\", \""
)) + QStringLiteral(
"\")"
);
269
qmlWarning(q) <<
"The following application identifiers have not been set: "
<< formattedList;
270
#
else
271
qmlWarning(q) <<
"The following application identifiers have not been set: "
272
<< missingIdentifiers;
273
#
endif
274
}
275
}
276
277
return
settings;
278
}
279
280
if
(!category.isEmpty())
281
settings->beginGroup(category);
282
283
if
(initialized)
284
q->d_func()->load();
285
286
return
settings;
287
}
288
289
void
QQmlSettingsPrivate
::
init
()
290
{
291
if
(
initialized
)
292
return
;
293
load
(
)
;
294
initialized
=
true
;
295
qCDebug(lcQmlSettings) <<
"QQmlSettings: stored at"
<< instance()->fileName();
296
}
297
298
void
QQmlSettingsPrivate
::
reset
()
299
{
300
if
(initialized && settings && !changedProperties.isEmpty())
301
store
(
)
;
302
delete
settings;
303
}
304
305
void
QQmlSettingsPrivate
::
load
()
306
{
307
Q_Q(QQmlSettings);
308
const
QMetaObject *mo = q->metaObject();
309
const
int
offset = QQmlSettings::staticMetaObject.propertyCount();
310
const
int
count = mo->propertyCount();
311
312
for
(
int
i = offset; i < count; ++i) {
313
QMetaProperty property = mo->property(i);
314
const
QString propertyName = QString::fromUtf8(property.name());
315
316
const
QVariant previousValue = readProperty(property);
317
const
QVariant currentValue = instance()->value(propertyName,
318
previousValue);
319
320
if
(!currentValue.isNull() && (!previousValue.isValid()
321
|| (currentValue.canConvert(previousValue.metaType())
322
&& previousValue != currentValue))) {
323
property.write(q, currentValue);
324
qCDebug(lcQmlSettings) <<
"QQmlSettings: load"
<< property.name() <<
"setting:"
<< currentValue <<
"default:"
<< previousValue;
325
}
326
327
// ensure that a non-existent setting gets written
328
// even if the property wouldn't change later
329
if
(!instance()->contains(propertyName))
330
_q_propertyChanged
(
)
;
331
332
// setup change notifications on first load
333
if
(!
initialized
&& property.hasNotifySignal()) {
334
static
const
int
propertyChangedIndex = mo->indexOfSlot(
"_q_propertyChanged()"
);
335
QMetaObject::connect(q, property.notifySignalIndex(), q, propertyChangedIndex);
336
}
337
}
338
}
339
340
void
QQmlSettingsPrivate
::
store
()
341
{
342
QHash<
const
char
*, QVariant>::const_iterator it = changedProperties.constBegin();
343
while
(it != changedProperties.constEnd()) {
344
instance()->setValue(QString::fromUtf8(it.key()), it.value());
345
qCDebug(lcQmlSettings) <<
"QQmlSettings: store"
<< it.key() <<
":"
<< it.value();
346
++it;
347
}
348
changedProperties.clear();
349
}
350
351
void
QQmlSettingsPrivate
::
_q_propertyChanged
()
352
{
353
Q_Q(QQmlSettings);
354
const
QMetaObject *mo = q->metaObject();
355
const
int
offset = QQmlSettings::staticMetaObject.propertyCount() ;
356
const
int
count = mo->propertyCount();
357
for
(
int
i = offset; i < count; ++i) {
358
const
QMetaProperty &property = mo->property(i);
359
const
QVariant value = readProperty(property);
360
changedProperties.insert(property.name(), value);
361
qCDebug(lcQmlSettings) <<
"QQmlSettings: cache"
<< property.name() <<
":"
<< value;
362
}
363
timer.start(settingsWriteDelay, q);
364
}
365
366
QVariant
QQmlSettingsPrivate
::
readProperty
(
const
QMetaProperty &property)
const
367
{
368
Q_Q(
const
QQmlSettings);
369
QVariant var = property.read(q);
370
if
(var.metaType() == QMetaType::fromType<QJSValue>())
371
var = var.value<QJSValue>().toVariant();
372
return
var;
373
}
374
375
QQmlSettings::QQmlSettings(QObject *parent)
376
: QObject(parent), d_ptr(
new
QQmlSettingsPrivate)
377
{
378
Q_D(QQmlSettings);
379
d->q_ptr =
this
;
380
}
381
382
QQmlSettings::~QQmlSettings()
383
{
384
Q_D(QQmlSettings);
385
d->reset();
// flush pending changes
386
}
387
388
/*!
389
\qmlproperty string Settings::category
390
391
This property holds the name of the settings category.
392
393
Categories can be used to group related settings together.
394
395
\sa QSettings::group
396
*/
397
QString QQmlSettings::category()
const
398
{
399
Q_D(
const
QQmlSettings);
400
return
d->category;
401
}
402
403
void
QQmlSettings::setCategory(
const
QString &category)
404
{
405
Q_D(QQmlSettings);
406
if
(d->category == category)
407
return
;
408
d->reset();
409
d->category = category;
410
if
(d->initialized)
411
d->load();
412
Q_EMIT categoryChanged(category);
413
}
414
415
/*!
416
\qmlproperty url Settings::location
417
418
This property holds the path to the settings file. If the file doesn't
419
already exist, it will be created.
420
421
If this property is empty (the default), then QSettings::defaultFormat()
422
will be used. Otherwise, QSettings::IniFormat will be used.
423
424
\sa QSettings::fileName, QSettings::defaultFormat, QSettings::IniFormat
425
*/
426
QUrl QQmlSettings::location()
const
427
{
428
Q_D(
const
QQmlSettings);
429
return
d->location;
430
}
431
432
void
QQmlSettings::setLocation(
const
QUrl &location)
433
{
434
Q_D(QQmlSettings);
435
if
(d->location == location)
436
return
;
437
d->reset();
438
d->location = location;
439
if
(d->initialized)
440
d->load();
441
Q_EMIT locationChanged(location);
442
}
443
444
/*!
445
\qmlmethod var Settings::value(string key, var defaultValue)
446
447
Returns the value for setting \a key. If the setting doesn't exist,
448
returns \a defaultValue.
449
450
\sa QSettings::value
451
*/
452
QVariant QQmlSettings::value(
const
QString &key,
const
QVariant &defaultValue)
const
453
{
454
Q_D(
const
QQmlSettings);
455
return
d->instance()->value(key, defaultValue);
456
}
457
458
/*!
459
\qmlmethod void Settings::setValue(string key, var value)
460
461
Sets the value of setting \a key to \a value. If the key already exists,
462
the previous value is overwritten.
463
464
\sa QSettings::setValue
465
*/
466
void
QQmlSettings::setValue(
const
QString &key,
const
QVariant &value)
467
{
468
Q_D(
const
QQmlSettings);
469
d->instance()->setValue(key, value);
470
qCDebug(lcQmlSettings) <<
"QQmlSettings: setValue"
<< key <<
":"
<< value;
471
}
472
473
/*!
474
\qmlmethod void Settings::sync()
475
476
Writes any unsaved changes to permanent storage, and reloads any
477
settings that have been changed in the meantime by another
478
application.
479
480
This function is called automatically from QSettings's destructor and
481
by the event loop at regular intervals, so you normally don't need to
482
call it yourself.
483
484
\sa QSettings::sync
485
*/
486
void
QQmlSettings::sync()
487
{
488
Q_D(QQmlSettings);
489
d->instance()->sync();
490
}
491
492
void
QQmlSettings::classBegin()
493
{
494
}
495
496
void
QQmlSettings::componentComplete()
497
{
498
Q_D(QQmlSettings);
499
d->init();
500
}
501
502
void
QQmlSettings::timerEvent(QTimerEvent *event)
503
{
504
Q_D(QQmlSettings);
505
QObject::timerEvent(event);
506
if
(!event->matches(d->timer))
507
return
;
508
d->timer.stop();
509
d->store();
510
}
511
512
QT_END_NAMESPACE
513
514
#
include
"moc_qqmlsettings_p.cpp"
QQmlSettingsPrivate
Definition
qqmlsettings.cpp:213
QQmlSettingsPrivate::location
QUrl location
Definition
qqmlsettings.cpp:236
QQmlSettingsPrivate::category
QString category
Definition
qqmlsettings.cpp:235
QQmlSettingsPrivate::settings
QPointer< QSettings > settings
Definition
qqmlsettings.cpp:237
QQmlSettingsPrivate::changedProperties
QHash< const char *, QVariant > changedProperties
Definition
qqmlsettings.cpp:238
QQmlSettingsPrivate::initialized
bool initialized
Definition
qqmlsettings.cpp:234
QQmlSettingsPrivate::reset
void reset()
Definition
qqmlsettings.cpp:298
QQmlSettingsPrivate::timer
QBasicTimer timer
Definition
qqmlsettings.cpp:233
QQmlSettingsPrivate::q_ptr
QQmlSettings * q_ptr
Definition
qqmlsettings.cpp:232
QQmlSettingsPrivate::readProperty
QVariant readProperty(const QMetaProperty &property) const
Definition
qqmlsettings.cpp:366
QQmlSettingsPrivate::~QQmlSettingsPrivate
~QQmlSettingsPrivate()=default
QQmlSettingsPrivate::_q_propertyChanged
void _q_propertyChanged()
Definition
qqmlsettings.cpp:351
QQmlSettingsPrivate::load
void load()
Definition
qqmlsettings.cpp:305
QQmlSettingsPrivate::store
void store()
Definition
qqmlsettings.cpp:340
QQmlSettingsPrivate::instance
QSettings * instance() const
Definition
qqmlsettings.cpp:241
QQmlSettingsPrivate::init
void init()
Definition
qqmlsettings.cpp:289
settingsWriteDelay
static constexpr auto settingsWriteDelay
Definition
qqmlsettings.cpp:210
Q_STATIC_LOGGING_CATEGORY
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
qtdeclarative
src
core
qqmlsettings.cpp
Generated on
for Qt by
1.18.0