2015-12-10 05:06:13 +02:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
2019-12-29 23:21:34 +00:00
|
|
|
** Copyright (C) 2016-2020 Ivailo Monev
|
2015-12-10 05:06:13 +02:00
|
|
|
**
|
2019-07-02 18:13:44 +00:00
|
|
|
** This file is part of the QtCore module of the Katie Toolkit.
|
2015-12-10 05:06:13 +02:00
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
2019-12-29 23:21:34 +00:00
|
|
|
**
|
2015-12-10 05:06:13 +02:00
|
|
|
** GNU Lesser General Public License Usage
|
2019-12-29 23:21:34 +00:00
|
|
|
** This file may be used under the terms of the GNU Lesser
|
|
|
|
** General Public License version 2.1 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 2.1 requirements
|
|
|
|
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2015-12-10 05:06:13 +02:00
|
|
|
**
|
|
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3.0 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2019-07-15 20:10:49 +00:00
|
|
|
#include "qdebug.h"
|
2015-12-10 05:06:13 +02:00
|
|
|
#include "qplatformdefs.h"
|
|
|
|
#include "qsettings.h"
|
2019-12-23 21:05:10 +00:00
|
|
|
#include "qjsondocument.h"
|
|
|
|
#include "qjsonobject.h"
|
|
|
|
#include "qstandardpaths.h"
|
|
|
|
#include "qmutex.h"
|
|
|
|
#include "qcoreapplication.h"
|
|
|
|
#include "qlibraryinfo.h"
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
#ifndef QT_NO_SETTINGS
|
|
|
|
|
|
|
|
#include "qsettings_p.h"
|
|
|
|
#include "qfile.h"
|
|
|
|
#include "qdir.h"
|
|
|
|
|
|
|
|
#ifndef QT_NO_GEOM_VARIANT
|
|
|
|
#include "qsize.h"
|
|
|
|
#include "qpoint.h"
|
|
|
|
#include "qrect.h"
|
|
|
|
#endif // !QT_NO_GEOM_VARIANT
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
struct QSettingsCustomFormat
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::Format format;
|
2015-12-10 05:06:13 +02:00
|
|
|
QString extension;
|
|
|
|
QSettings::ReadFunc readFunc;
|
|
|
|
QSettings::WriteFunc writeFunc;
|
|
|
|
};
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
typedef QVector<QSettingsCustomFormat> CustomFormatVector;
|
|
|
|
typedef QVector<QSettings*> QSettingsVector;
|
|
|
|
Q_GLOBAL_STATIC(QSettingsVector, qGlobalSettings)
|
2015-12-10 05:06:13 +02:00
|
|
|
Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
|
2019-12-23 21:05:10 +00:00
|
|
|
Q_GLOBAL_STATIC(QMutex, qSettingsMutex)
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
// ************************************************************************
|
|
|
|
// Native format
|
|
|
|
static bool json_settings_read(QIODevice &device, QSettings::SettingsMap &map)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QByteArray data = device.readAll();
|
|
|
|
if (Q_UNLIKELY(data.isEmpty())) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2020-01-01 18:09:02 +00:00
|
|
|
QJsonParseError error;
|
|
|
|
QJsonDocument jsondoc = QJsonDocument::fromJson(data, &error);
|
2019-12-23 21:05:10 +00:00
|
|
|
if (Q_UNLIKELY(jsondoc.isNull())) {
|
2020-01-01 18:09:02 +00:00
|
|
|
qWarning("json_settings_read: %s", error.errorString().toUtf8().constData());
|
2019-12-23 21:05:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
map = jsondoc.object().toVariantMap();
|
|
|
|
|
|
|
|
// qDebug() << "json_settings_read" << jsondoc.toJson();
|
|
|
|
return true;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
static bool json_settings_write(QIODevice &device, const QSettings::SettingsMap &map)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QJsonDocument jsondoc = QJsonDocument(QJsonObject::fromVariantMap(map));
|
|
|
|
QByteArray jsondata = jsondoc.toJson();
|
|
|
|
if (Q_UNLIKELY(jsondoc.isNull() || jsondata.isNull())) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
// qDebug() << "json_settings_write" << jsondata;
|
|
|
|
return device.write(jsondata);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
// ************************************************************************
|
|
|
|
// INI format
|
|
|
|
static bool ini_settings_read(QIODevice &device, QSettings::SettingsMap &map)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QByteArray section; // keys without section are allowed
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
bool parsedsomething = false;
|
|
|
|
while (!device.atEnd()) {
|
|
|
|
const QByteArray line = device.readLine().trimmed();
|
|
|
|
if (line.isEmpty() || line.startsWith(';')) {
|
|
|
|
continue;
|
2019-12-25 21:23:17 +00:00
|
|
|
// extract section
|
2019-12-23 21:05:10 +00:00
|
|
|
} else if (line.startsWith('[') && line.endsWith(']')) {
|
|
|
|
section = line.mid(1, line.size() - 2);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-12-24 18:18:09 +00:00
|
|
|
// extract key/value
|
|
|
|
const int separatorpos = line.indexOf('=');
|
|
|
|
if (separatorpos < 1) {
|
2019-12-23 21:05:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-12-24 18:18:09 +00:00
|
|
|
const QByteArray key = line.left(separatorpos).trimmed();
|
|
|
|
const QByteArray value = line.mid(separatorpos + 1).trimmed();
|
2019-12-23 21:05:10 +00:00
|
|
|
const QVariant variantvalue = QSettingsPrivate::stringToVariant(value);
|
|
|
|
if (section.isEmpty()) {
|
|
|
|
map.insert(key, variantvalue);
|
|
|
|
} else {
|
2019-12-24 18:18:09 +00:00
|
|
|
map.insert(section + '/' + key, variantvalue);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
parsedsomething = true;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
2019-12-23 21:05:10 +00:00
|
|
|
|
|
|
|
// qDebug() << "ini_settings_read" << map;
|
|
|
|
return parsedsomething;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
static bool ini_settings_write(QIODevice &device, const QSettings::SettingsMap &map)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QString lastsection;
|
|
|
|
foreach (const QString &key, map.keys()) {
|
|
|
|
QString section;
|
2019-12-24 18:18:09 +00:00
|
|
|
QString actualkey = key;
|
|
|
|
// extract section from the key
|
|
|
|
const int separatorpos = key.indexOf(QLatin1Char('/'));
|
|
|
|
if (separatorpos > 1) {
|
|
|
|
section = QLatin1Char('[') + key.left(separatorpos) + QLatin1String("]\n");
|
|
|
|
actualkey = key.mid(separatorpos + 1, key.size() - separatorpos - 1);
|
2019-12-23 21:05:10 +00:00
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
if (section != lastsection) {
|
|
|
|
// separate each section with two line separators, do only for
|
|
|
|
// sections after the first one
|
|
|
|
if (!lastsection.isEmpty() && !device.write("\n")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!section.isEmpty() && !device.write(section.toAscii())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lastsection = section;
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-24 18:18:09 +00:00
|
|
|
if (!device.write(actualkey.toAscii())) {
|
2019-12-23 21:05:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
const QString stringvalue = QSettingsPrivate::variantToString(map.value(key));
|
|
|
|
const QString datavalue = QLatin1Char('=') + stringvalue + QLatin1Char('\n');
|
|
|
|
if (!device.write(datavalue.toAscii())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-24 18:18:09 +00:00
|
|
|
// qDebug() << "ini_settings_write" << section << actualkey << stringvalue;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
return true;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ************************************************************************
|
|
|
|
// QSettingsPrivate
|
2019-12-23 21:05:10 +00:00
|
|
|
static QSettingsCustomFormat getSettingsFormat(QSettings::Format format)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsCustomFormat result;
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
if (format == QSettings::NativeFormat) {
|
|
|
|
result.extension = QLatin1String(".json");
|
|
|
|
result.readFunc = json_settings_read;
|
|
|
|
result.writeFunc = json_settings_write;
|
|
|
|
return result;
|
|
|
|
} else if (format == QSettings::IniFormat) {
|
|
|
|
result.extension = QLatin1String(".ini");
|
|
|
|
result.readFunc = ini_settings_read;
|
|
|
|
result.writeFunc = ini_settings_write;
|
|
|
|
return result;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
const CustomFormatVector *customFormatVector = customFormatVectorFunc();
|
|
|
|
for (int i = 0; i < customFormatVector->size(); i++) {
|
|
|
|
const QSettingsCustomFormat &custom = customFormatVector->at(i);
|
|
|
|
if (custom.format == format) {
|
|
|
|
result.extension = custom.extension;
|
|
|
|
result.readFunc = custom.readFunc;
|
|
|
|
result.writeFunc = custom.writeFunc;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qWarning("QSettingsPrivate::getSettingsFormat: format not found %d", format);
|
|
|
|
result.extension = QLatin1String(".json");
|
|
|
|
result.readFunc = json_settings_read;
|
|
|
|
result.writeFunc = json_settings_write;
|
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2020-02-16 14:30:02 +00:00
|
|
|
static inline QString createLeadingDir(const QString &filename)
|
|
|
|
{
|
|
|
|
QFileInfo info(filename);
|
|
|
|
QDir().mkpath(info.absolutePath());
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
2019-12-28 04:19:47 +00:00
|
|
|
static QString getSettingsPath(QSettings::Scope scope, const QString &filename, const QString &extension)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QFileInfo info(filename);
|
|
|
|
if (info.isAbsolute()) {
|
2020-02-16 14:30:02 +00:00
|
|
|
return createLeadingDir(filename);
|
2019-12-23 21:05:10 +00:00
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QString nameandext = filename;
|
|
|
|
if (!filename.endsWith(extension)) {
|
|
|
|
nameandext += extension;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QStringList locations = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation);
|
|
|
|
if (scope == QSettings::UserScope) {
|
|
|
|
locations = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
foreach (const QString &location, locations) {
|
2020-11-08 06:22:49 +02:00
|
|
|
QFileInfo info(location);
|
|
|
|
if (info.isWritable()) {
|
2020-02-16 14:30:02 +00:00
|
|
|
return createLeadingDir(location + QDir::separator() + nameandext);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-08 04:24:25 +02:00
|
|
|
return createLeadingDir(locations.first() + QDir::separator() + nameandext);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope)
|
2020-01-25 18:05:53 +00:00
|
|
|
: format(format), scope(scope), status(QSettings::NoError)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsCustomFormat handler = getSettingsFormat(format);
|
|
|
|
filename = getSettingsPath(scope, QCoreApplication::applicationName(), handler.extension);
|
|
|
|
readFunc = handler.readFunc;
|
|
|
|
writeFunc = handler.writeFunc;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsPrivate::QSettingsPrivate(const QString &fileName, QSettings::Format format)
|
2020-01-25 18:05:53 +00:00
|
|
|
: format(format), scope(QSettings::UserScope), status(QSettings::NoError)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsCustomFormat handler = getSettingsFormat(format);
|
|
|
|
filename = getSettingsPath(scope, fileName, handler.extension);
|
|
|
|
readFunc = handler.readFunc;
|
|
|
|
writeFunc = handler.writeFunc;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsPrivate::~QSettingsPrivate()
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
void QSettingsPrivate::read()
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QFileInfo info(filename);
|
|
|
|
if (!info.isReadable() || info.size() == 0) {
|
|
|
|
status = QSettings::AccessError;
|
|
|
|
// no warning, info.exists() may return false if not readable
|
|
|
|
return;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QFile file(filename);
|
|
|
|
if (Q_UNLIKELY(!file.open(QFile::ReadOnly))) {
|
|
|
|
status = QSettings::AccessError;
|
|
|
|
qWarning("QSettingsPrivate::read: failed to open %s", filename.toLocal8Bit().constData());
|
|
|
|
return;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2020-01-25 18:05:53 +00:00
|
|
|
if (Q_UNLIKELY(!readFunc(file, map))) {
|
2019-12-23 21:05:10 +00:00
|
|
|
status = QSettings::FormatError;
|
|
|
|
qWarning("QSettingsPrivate::read: could not read %s", filename.toLocal8Bit().constData());
|
|
|
|
return;
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
timestamp = info.lastModified();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
void QSettingsPrivate::write()
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2020-01-25 18:05:53 +00:00
|
|
|
if (pending.isEmpty()) {
|
2019-12-24 19:19:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QFileInfo info(filename);
|
|
|
|
const QDateTime newstamp = info.lastModified();
|
|
|
|
if (timestamp < newstamp || !newstamp.isValid()) {
|
|
|
|
QSettingsPrivate::read();
|
|
|
|
}
|
|
|
|
|
2020-01-25 18:05:53 +00:00
|
|
|
|
|
|
|
foreach (const QString &key, map.keys()) {
|
|
|
|
if (!pending.contains(key)) {
|
|
|
|
pending.insert(key, map.value(key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 07:29:08 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
2019-12-23 21:05:10 +00:00
|
|
|
QFile file(filename);
|
|
|
|
if (Q_UNLIKELY(!file.open(QFile::WriteOnly))) {
|
|
|
|
status = QSettings::AccessError;
|
|
|
|
qWarning("QSettingsPrivate::write: failed to open %s", filename.toLocal8Bit().constData());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-25 18:05:53 +00:00
|
|
|
if (Q_UNLIKELY(!writeFunc(file, pending))) {
|
2019-12-23 21:05:10 +00:00
|
|
|
status = QSettings::FormatError;
|
|
|
|
qWarning("QSettingsPrivate::write: could not write %s", filename.toLocal8Bit().constData());
|
2020-01-06 17:14:41 +00:00
|
|
|
return;
|
2019-12-23 21:05:10 +00:00
|
|
|
}
|
2019-12-24 19:19:32 +00:00
|
|
|
|
2020-01-25 18:05:53 +00:00
|
|
|
pending.clear();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
void QSettingsPrivate::notify()
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
Q_Q(QSettings);
|
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
for (int i = 0; i < qGlobalSettings()->size(); i++) {
|
|
|
|
QSettings *setting = qGlobalSettings()->at(i);
|
|
|
|
if (setting != q && setting->fileName() == q->fileName()) {
|
|
|
|
setting->d_func()->map = map;
|
2020-01-25 18:05:53 +00:00
|
|
|
setting->d_func()->pending = pending;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 17:24:17 +00:00
|
|
|
QString QSettingsPrivate::toGroupKey(const QString &key) const
|
|
|
|
{
|
|
|
|
if (group.isEmpty()) {
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
return group + QLatin1Char('/') + key;
|
|
|
|
}
|
|
|
|
|
2015-12-10 05:06:13 +02:00
|
|
|
QString QSettingsPrivate::variantToString(const QVariant &v)
|
|
|
|
{
|
|
|
|
switch (v.type()) {
|
2019-12-25 21:51:08 +00:00
|
|
|
case QVariant::Invalid: {
|
|
|
|
return QLatin1String("@Invalid()");
|
|
|
|
}
|
2015-12-10 05:06:13 +02:00
|
|
|
case QVariant::ByteArray: {
|
|
|
|
QByteArray a = v.toByteArray();
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = QLatin1String("@ByteArray(");
|
2019-12-25 21:50:08 +00:00
|
|
|
result += QString::fromAscii(a.constData(), a.size());
|
2015-12-10 05:06:13 +02:00
|
|
|
result += QLatin1Char(')');
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
case QVariant::String:
|
|
|
|
case QVariant::LongLong:
|
|
|
|
case QVariant::ULongLong:
|
|
|
|
case QVariant::Int:
|
|
|
|
case QVariant::UInt:
|
|
|
|
case QVariant::Bool:
|
|
|
|
case QVariant::Double:
|
|
|
|
case QVariant::KeySequence: {
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = v.toString();
|
2015-12-10 05:06:13 +02:00
|
|
|
if (result.startsWith(QLatin1Char('@')))
|
|
|
|
result.prepend(QLatin1Char('@'));
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
#ifndef QT_NO_GEOM_VARIANT
|
|
|
|
case QVariant::Rect: {
|
|
|
|
QRect r = qvariant_cast<QRect>(v);
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = QLatin1String("@Rect(");
|
2015-12-10 05:06:13 +02:00
|
|
|
result += QString::number(r.x());
|
|
|
|
result += QLatin1Char(' ');
|
|
|
|
result += QString::number(r.y());
|
|
|
|
result += QLatin1Char(' ');
|
|
|
|
result += QString::number(r.width());
|
|
|
|
result += QLatin1Char(' ');
|
|
|
|
result += QString::number(r.height());
|
|
|
|
result += QLatin1Char(')');
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
case QVariant::Size: {
|
|
|
|
QSize s = qvariant_cast<QSize>(v);
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = QLatin1String("@Size(");
|
2015-12-10 05:06:13 +02:00
|
|
|
result += QString::number(s.width());
|
|
|
|
result += QLatin1Char(' ');
|
|
|
|
result += QString::number(s.height());
|
|
|
|
result += QLatin1Char(')');
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
case QVariant::Point: {
|
|
|
|
QPoint p = qvariant_cast<QPoint>(v);
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = QLatin1String("@Point(");
|
2015-12-10 05:06:13 +02:00
|
|
|
result += QString::number(p.x());
|
|
|
|
result += QLatin1Char(' ');
|
|
|
|
result += QString::number(p.y());
|
|
|
|
result += QLatin1Char(')');
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
#endif // !QT_NO_GEOM_VARIANT
|
|
|
|
|
|
|
|
default: {
|
|
|
|
#ifndef QT_NO_DATASTREAM
|
|
|
|
QByteArray a;
|
|
|
|
{
|
|
|
|
QDataStream s(&a, QIODevice::WriteOnly);
|
|
|
|
s << v;
|
|
|
|
}
|
|
|
|
|
2019-12-25 21:51:08 +00:00
|
|
|
QString result = QLatin1String("@Variant(");
|
2019-12-25 21:50:08 +00:00
|
|
|
result += QString::fromAscii(a.constData(), a.size());
|
2015-12-10 05:06:13 +02:00
|
|
|
result += QLatin1Char(')');
|
2019-12-25 21:51:08 +00:00
|
|
|
return result;
|
2015-12-10 05:06:13 +02:00
|
|
|
#else
|
|
|
|
Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
|
2019-12-25 21:51:08 +00:00
|
|
|
return QString();
|
2015-12-10 05:06:13 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2019-12-25 21:51:08 +00:00
|
|
|
return QString();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QVariant QSettingsPrivate::stringToVariant(const QString &s)
|
|
|
|
{
|
|
|
|
if (s.startsWith(QLatin1Char('@'))) {
|
|
|
|
if (s.endsWith(QLatin1Char(')'))) {
|
|
|
|
if (s.startsWith(QLatin1String("@ByteArray("))) {
|
2019-12-25 21:52:02 +00:00
|
|
|
return QVariant(s.toAscii().mid(11, s.size() - 12));
|
2015-12-10 05:06:13 +02:00
|
|
|
} else if (s.startsWith(QLatin1String("@Variant("))) {
|
|
|
|
#ifndef QT_NO_DATASTREAM
|
2019-12-25 21:52:02 +00:00
|
|
|
QByteArray a(s.toAscii().mid(9));
|
2015-12-10 05:06:13 +02:00
|
|
|
QDataStream stream(&a, QIODevice::ReadOnly);
|
|
|
|
QVariant result;
|
|
|
|
stream >> result;
|
|
|
|
return result;
|
|
|
|
#else
|
|
|
|
Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
|
|
|
|
#endif
|
|
|
|
#ifndef QT_NO_GEOM_VARIANT
|
|
|
|
} else if (s.startsWith(QLatin1String("@Rect("))) {
|
|
|
|
QStringList args = QSettingsPrivate::splitArgs(s, 5);
|
|
|
|
if (args.size() == 4)
|
|
|
|
return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
|
|
|
|
} else if (s.startsWith(QLatin1String("@Size("))) {
|
|
|
|
QStringList args = QSettingsPrivate::splitArgs(s, 5);
|
|
|
|
if (args.size() == 2)
|
|
|
|
return QVariant(QSize(args[0].toInt(), args[1].toInt()));
|
|
|
|
} else if (s.startsWith(QLatin1String("@Point("))) {
|
|
|
|
QStringList args = QSettingsPrivate::splitArgs(s, 6);
|
|
|
|
if (args.size() == 2)
|
|
|
|
return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
|
|
|
|
#endif
|
|
|
|
} else if (s == QLatin1String("@Invalid()")) {
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if (s.startsWith(QLatin1String("@@")))
|
|
|
|
return QVariant(s.mid(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
return QVariant(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
|
|
|
|
{
|
|
|
|
int l = s.length();
|
|
|
|
Q_ASSERT(l > 0);
|
|
|
|
Q_ASSERT(s.at(idx) == QLatin1Char('('));
|
|
|
|
Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
|
|
|
|
|
|
|
|
QStringList result;
|
|
|
|
QString item;
|
|
|
|
|
|
|
|
for (++idx; idx < l; ++idx) {
|
|
|
|
QChar c = s.at(idx);
|
|
|
|
if (c == QLatin1Char(')')) {
|
|
|
|
Q_ASSERT(idx == l - 1);
|
|
|
|
result.append(item);
|
|
|
|
} else if (c == QLatin1Char(' ')) {
|
|
|
|
result.append(item);
|
|
|
|
item.clear();
|
|
|
|
} else {
|
|
|
|
item.append(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
/*!
|
|
|
|
\class QSettings
|
|
|
|
\brief The QSettings class provides persistent platform-independent application settings.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\ingroup io
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\reentrant
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
Users normally expect an application to remember its settings
|
|
|
|
(window sizes and positions, options, etc.) across sessions.
|
|
|
|
On Unix systems, in the absence of a standard, many applications
|
|
|
|
(including the KDE applications) use INI text files.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings is an abstraction around these technologies, enabling
|
|
|
|
you to save and restore application settings in a portable
|
|
|
|
manner. It also supports \l{registerFormat()}{custom storage
|
|
|
|
formats}.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings's API is based on QVariant, allowing you to save
|
|
|
|
most value-based types, such as QString, QRect, and QImage,
|
|
|
|
with the minimum of effort.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
If all you need is a non-persistent memory-based structure,
|
|
|
|
consider using QMap<QString, QVariant> instead.
|
2016-09-16 00:16:22 +00:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\tableofcontents section1
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\section1 Basic Usage
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
If you use QSettings from many places in your application, you
|
|
|
|
might want to specify the application name using
|
|
|
|
QCoreApplication::setApplicationName() and then use the default
|
|
|
|
QSettings constructor:
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings stores settings. Each setting consists of a QString
|
|
|
|
that specifies the setting's name (the \e key) and a QVariant
|
|
|
|
that stores the data associated with the key. To write a setting,
|
|
|
|
use setValue().
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
If there already exists a setting with the same key, the existing
|
|
|
|
value is overwritten by the new value. For efficiency, the
|
|
|
|
changes may not be saved to permanent storage immediately. (You
|
|
|
|
can always call sync() to commit your changes.)
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
You can get a setting's value back using value(). If there is no
|
|
|
|
setting with the specified name, QSettings returns a null QVariant
|
|
|
|
(which can be converted to the integer 0). You can specify
|
|
|
|
another default value by passing a second argument to value():
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
To test whether a given key exists, call contains(). To remove
|
|
|
|
the setting associated with a key, call remove(). To obtain the
|
|
|
|
list of all keys, call keys(). To get a map of all settings, call
|
|
|
|
map(). To remove all keys, call clear().
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\section1 QVariant and GUI Types
|
|
|
|
|
|
|
|
Because QVariant is part of the \l QtCore library, it cannot provide
|
|
|
|
conversion functions to data types such as QColor, QImage, and
|
|
|
|
QPixmap, which are part of \l QtGui. In other words, there is no
|
|
|
|
\c toColor(), \c toImage(), or \c toPixmap() functions in QVariant.
|
|
|
|
Instead, you can use the QVariant::value() or the qVariantValue()
|
2019-12-23 21:05:10 +00:00
|
|
|
template function.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
The inverse conversion (e.g., from QColor to QVariant) is
|
|
|
|
automatic for all data types supported by QVariant, including
|
2019-12-23 21:05:10 +00:00
|
|
|
GUI-related types.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
Custom types registered using qRegisterMetaType() and
|
|
|
|
qRegisterMetaTypeStreamOperators() can be stored using QSettings.
|
|
|
|
|
|
|
|
\section1 Section and Key Syntax
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
Setting keys can contain any Unicode characters. To avoid portability
|
|
|
|
problems, follow these simple rules:
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\list 1
|
|
|
|
\o Always refer to the same key using the same case. For example,
|
|
|
|
if you refer to a key as "text fonts" in one place in your
|
|
|
|
code, don't refer to it as "Text Fonts" somewhere else.
|
|
|
|
|
|
|
|
\o Avoid key names that are identical except for the case. For
|
|
|
|
example, if you have a key called "MainWindow", don't try to
|
|
|
|
save another key as "mainwindow".
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\o Do not use slashes ('/' and '\\') in key names. The backslash
|
2019-12-25 21:23:17 +00:00
|
|
|
character is used to separate sub keys (see below).
|
2015-12-10 05:06:13 +02:00
|
|
|
\endlist
|
|
|
|
|
|
|
|
You can form hierarchical keys using the '/' character as a
|
2019-12-23 21:05:10 +00:00
|
|
|
separator, similar to Unix file paths.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
If you want to use specific format instead of the native, you
|
|
|
|
can pass QSettings::IniFormat as the first argument to the
|
|
|
|
QSettings constructor, followed by the scope.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\section1 Restoring the State of a GUI Application
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings is often used to store the state of a GUI application.
|
2015-12-10 05:06:13 +02:00
|
|
|
See \l{Window Geometry} for a discussion on why it is better to
|
2019-12-23 21:05:10 +00:00
|
|
|
call QWidget::resize() and QWidget::move() rather than
|
|
|
|
QWidget::setGeometry() to restore a window's geometry.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
The \c readSettings() and \c writeSettings() functions must be
|
2019-12-23 21:05:10 +00:00
|
|
|
called from the main window's constructor and close event handler.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\section1 Accessing Settings from Multiple Threads or Processes Simultaneously
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings is \l{reentrant}. This means that you can use distinct
|
|
|
|
QSettings object in different threads simultaneously. This
|
|
|
|
guarantee stands even when the QSettings objects refer to the
|
|
|
|
same files on disk. If a setting is modified through one
|
2015-12-10 05:06:13 +02:00
|
|
|
QSettings object, the change will immediately be visible in
|
|
|
|
any other QSettings objects that operate on the same location
|
|
|
|
and that live in the same process.
|
|
|
|
|
|
|
|
QSettings can safely be used from different processes (which can
|
|
|
|
be different instances of your application running at the same
|
|
|
|
time or different applications altogether) to read and write to
|
2019-12-25 05:08:38 +00:00
|
|
|
the same system locations. Note that sync() imports changes made
|
|
|
|
by other processes (in addition to writing the changes from this
|
|
|
|
QSettings).
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\section1 Platform-Specific Notes
|
|
|
|
|
|
|
|
\section2 Locations Where Application Settings Are Stored
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings stores settings for an application in two locations,
|
2015-12-10 05:06:13 +02:00
|
|
|
depending on whether the settings are user-specific or
|
2019-12-23 21:05:10 +00:00
|
|
|
system-wide. For simplicity, we're assuming the application is
|
|
|
|
called MySoft.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
On Unix systems, if the file format is NativeFormat, the
|
|
|
|
following files are used by default:
|
|
|
|
|
|
|
|
\list 1
|
2019-12-23 21:05:10 +00:00
|
|
|
\o \c{$HOME/.config/MySoft.json}
|
|
|
|
\o \c{/etc/xdg/MySoft.json}
|
2015-12-10 05:06:13 +02:00
|
|
|
\endlist
|
|
|
|
|
|
|
|
If the file format is IniFormat, the following files are
|
2016-09-13 19:50:38 +00:00
|
|
|
used on Unix:
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\list 1
|
2019-12-23 21:05:10 +00:00
|
|
|
\o \c{$HOME/.config/MySoft.ini}
|
2015-12-10 05:06:13 +02:00
|
|
|
\o \c{/etc/xdg/MySoft.ini}
|
|
|
|
\endlist
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
The paths for the \c .ini and \c .json files can be changed by the
|
|
|
|
user by setting the \c XDG_CONFIG_HOME environment variable.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\section2 Accessing Files Directly
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
Sometimes you do want to access settings stored in a specific file.
|
|
|
|
If you want to read an INI file directly, you can use the QSettings
|
|
|
|
constructor that takes a file name as first argument and pass
|
|
|
|
QSettings::IniFormat as second argument. You can then use the
|
|
|
|
QSettings object to read and write settingsin the file.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-25 03:36:14 +00:00
|
|
|
\warning No attempt is made to lock the file thus if you want to use
|
|
|
|
QSettings to access settings file used by applications that do not use
|
2019-12-25 05:08:38 +00:00
|
|
|
QSettings you will have to do file locking yourself. As is with QFile
|
|
|
|
or any other disk I/O related class, QSettings guarantees only internal
|
|
|
|
state integrity.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa QVariant, QSessionManager
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
|
2017-08-09 11:51:23 +00:00
|
|
|
/*! \enum QSettings::SettingsStatus
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
The following status values are possible:
|
|
|
|
|
|
|
|
\value NoError No error occurred.
|
|
|
|
\value AccessError An access error occurred (e.g. trying to write to a read-only file).
|
|
|
|
\value FormatError A format error occurred (e.g. loading a malformed INI file).
|
|
|
|
|
|
|
|
\sa status()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \enum QSettings::Format
|
|
|
|
|
|
|
|
This enum type specifies the storage format used by QSettings.
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\value NativeFormat Store the settings in JSON files.
|
2015-12-10 05:06:13 +02:00
|
|
|
\value IniFormat Store the settings in INI files.
|
|
|
|
\value InvalidFormat Special value returned by registerFormat().
|
|
|
|
\omitvalue CustomFormat1
|
|
|
|
\omitvalue CustomFormat2
|
|
|
|
\omitvalue CustomFormat3
|
|
|
|
\omitvalue CustomFormat4
|
|
|
|
\omitvalue CustomFormat5
|
|
|
|
\omitvalue CustomFormat6
|
|
|
|
\omitvalue CustomFormat7
|
|
|
|
\omitvalue CustomFormat8
|
|
|
|
\omitvalue CustomFormat9
|
|
|
|
\omitvalue CustomFormat10
|
|
|
|
\omitvalue CustomFormat11
|
|
|
|
\omitvalue CustomFormat12
|
|
|
|
\omitvalue CustomFormat13
|
|
|
|
\omitvalue CustomFormat14
|
|
|
|
\omitvalue CustomFormat15
|
|
|
|
\omitvalue CustomFormat16
|
|
|
|
|
|
|
|
The INI file format is a Windows file format that Qt supports on
|
|
|
|
all platforms. In the absence of an INI standard, we try to
|
|
|
|
follow what Microsoft does, with the following exceptions:
|
|
|
|
|
|
|
|
\list
|
|
|
|
\o If you store types that QVariant can't convert to QString
|
2019-12-25 21:23:17 +00:00
|
|
|
(e.g., QPoint, QRect, and QSize),an \c{@}-based syntax to
|
|
|
|
encode the type is used. For example:
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 8
|
|
|
|
|
|
|
|
To minimize compatibility issues, any \c @ that doesn't
|
|
|
|
appear at the first position in the value or that isn't
|
2019-12-25 21:23:17 +00:00
|
|
|
followed by a type (\c Point, \c Rect, \c Size, etc.) is
|
2015-12-10 05:06:13 +02:00
|
|
|
treated as a normal character.
|
|
|
|
|
|
|
|
\o Although backslash is a special character in INI files, most
|
|
|
|
Windows applications don't escape backslashes (\c{\}) in file
|
|
|
|
paths:
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 9
|
|
|
|
|
|
|
|
QSettings always treats backslash as a special character and
|
|
|
|
provides no API for reading or writing such entries.
|
|
|
|
|
|
|
|
\o The INI file format has severe restrictions on the syntax of
|
2019-12-25 21:23:17 +00:00
|
|
|
a key. If you save a top-level setting (a key with no slashes
|
|
|
|
in it, e.g., "someKey"), it will appear in the INI file without
|
|
|
|
section.
|
|
|
|
|
|
|
|
\o The codec used to read and write the settings files is the
|
|
|
|
same codec used for C-strings, UTF-8 by default.
|
2015-12-10 05:06:13 +02:00
|
|
|
\endlist
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa registerFormat()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \enum QSettings::Scope
|
|
|
|
|
|
|
|
This enum specifies whether settings are user-specific or shared
|
|
|
|
by all users of the same system.
|
|
|
|
|
|
|
|
\value UserScope Store settings in a location specific to the
|
|
|
|
current user (e.g., in the user's home
|
|
|
|
directory).
|
|
|
|
\value SystemScope Store settings in a global location, so that
|
|
|
|
all users on the same machine access the same
|
|
|
|
set of settings.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a QSettings object for accessing settings of the
|
|
|
|
application called \a application from the organization called \a
|
|
|
|
organization, and with parent \a parent.
|
|
|
|
|
|
|
|
If \a scope is QSettings::UserScope, the QSettings object searches
|
2019-12-23 21:05:10 +00:00
|
|
|
user-specific settings only. If \a scope is QSettings::SystemScope,
|
|
|
|
the QSettings object ignores user-specific settings and provides
|
2015-12-10 05:06:13 +02:00
|
|
|
access to system-wide settings.
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
The storage format is set to QSettings::NativeFormat.
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::QSettings(Scope scope, QObject *parent)
|
|
|
|
: QObject(*new QSettingsPrivate(NativeFormat, scope), parent)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
qGlobalSettings()->append(this);
|
|
|
|
Q_D(QSettings);
|
|
|
|
d->read();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a QSettings object for accessing settings of the
|
|
|
|
application called \a application from the organization called
|
|
|
|
\a organization, and with parent \a parent.
|
|
|
|
|
|
|
|
If \a scope is QSettings::UserScope, the QSettings object searches
|
2019-12-23 21:05:10 +00:00
|
|
|
user-specific settings only. If \a scope is QSettings::SystemScope,
|
|
|
|
the QSettings object ignores user-specific settings and provides
|
|
|
|
access to system-wide settings.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
If \a format is QSettings::NativeFormat, the native JSON API is used
|
|
|
|
for storing settings. If \a format is QSettings::IniFormat, the INI
|
|
|
|
format is used.
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::QSettings(Format format, Scope scope, QObject *parent)
|
|
|
|
: QObject(*new QSettingsPrivate(format, scope), parent)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
qGlobalSettings()->append(this);
|
|
|
|
Q_D(QSettings);
|
|
|
|
d->read();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a QSettings object for accessing the settings
|
|
|
|
stored in the file called \a fileName, with parent \a parent. If
|
|
|
|
the file doesn't already exist, it is created.
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
The meaning of \a fileName depends on the format. If \a format is
|
|
|
|
QSettings::NativeFormat, the filename will end with end with .json
|
|
|
|
suffix, if it is QSettings::IniFormat it will be suffixed with .ini.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
If \a format is QSettings::IniFormat, \a fileName is the name of an INI
|
|
|
|
file.
|
|
|
|
|
|
|
|
\list
|
|
|
|
\o In INI files, QSettings uses the \c @ character as a metacharacter in some
|
2019-12-25 21:23:17 +00:00
|
|
|
contexts, to encode Katie-specific data types (e.g., \c @Rect), and might
|
2015-12-10 05:06:13 +02:00
|
|
|
therefore misinterpret it when it occurs in pure INI files.
|
|
|
|
\endlist
|
|
|
|
|
|
|
|
\sa fileName()
|
|
|
|
*/
|
|
|
|
QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
|
2019-12-23 21:05:10 +00:00
|
|
|
: QObject(*new QSettingsPrivate(fileName, format), parent)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
qGlobalSettings()->append(this);
|
|
|
|
Q_D(QSettings);
|
|
|
|
d->read();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Constructs a QSettings object for accessing settings of the
|
2019-12-23 21:05:10 +00:00
|
|
|
application set previously with a call to
|
2015-12-10 05:06:13 +02:00
|
|
|
QCoreApplication::setApplicationName().
|
|
|
|
|
|
|
|
The scope is QSettings::UserScope and the format is
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::NativeFormat.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa QCoreApplication::setApplicationName()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
QSettings::QSettings(QObject *parent)
|
2019-12-23 21:05:10 +00:00
|
|
|
: QObject(*new QSettingsPrivate(QSettings::NativeFormat, UserScope), parent)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
qGlobalSettings()->append(this);
|
|
|
|
Q_D(QSettings);
|
|
|
|
d->read();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Destroys the QSettings object.
|
|
|
|
|
|
|
|
Any unsaved changes will eventually be written to permanent
|
|
|
|
storage.
|
|
|
|
|
|
|
|
\sa sync()
|
|
|
|
*/
|
|
|
|
QSettings::~QSettings()
|
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::sync();
|
|
|
|
QMutexLocker locker(qSettingsMutex());
|
|
|
|
const int index = qGlobalSettings()->indexOf(this);
|
|
|
|
qGlobalSettings()->remove(index);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2019-12-25 21:23:17 +00:00
|
|
|
Removes all entries in the file associated to this QSettings object.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa remove()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
void QSettings::clear()
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
2019-12-23 21:05:10 +00:00
|
|
|
d->map.clear();
|
2020-01-25 18:05:53 +00:00
|
|
|
d->pending.clear();
|
2019-12-23 21:05:10 +00:00
|
|
|
d->notify();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Writes any unsaved changes to permanent storage, and reloads any
|
|
|
|
settings that have been changed in the meantime by another
|
|
|
|
application.
|
|
|
|
|
2019-12-25 21:23:17 +00:00
|
|
|
This function is called automatically from QSettings's destructor,
|
|
|
|
so you normally don't need to call it yourself.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\sa status()
|
|
|
|
*/
|
|
|
|
void QSettings::sync()
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
2019-12-23 21:05:10 +00:00
|
|
|
d->write();
|
|
|
|
d->notify();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the path where settings written using this QSettings
|
|
|
|
object are stored.
|
|
|
|
|
|
|
|
\sa isWritable(), format()
|
|
|
|
*/
|
|
|
|
QString QSettings::fileName() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2019-12-23 21:05:10 +00:00
|
|
|
return d->filename;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\since 4.4
|
|
|
|
|
|
|
|
Returns the format used for storing the settings.
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa fileName(), scope()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
QSettings::Format QSettings::format() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
|
|
|
return d->format;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\since 4.4
|
|
|
|
|
|
|
|
Returns the scope used for storing the settings.
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa format()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
|
|
|
QSettings::Scope QSettings::scope() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
|
|
|
return d->scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns a status code indicating the first error that was met by
|
|
|
|
QSettings, or QSettings::NoError if no error occurred.
|
|
|
|
|
|
|
|
Be aware that QSettings delays performing some operations. For this
|
|
|
|
reason, you might want to call sync() to ensure that the data stored
|
|
|
|
in QSettings is written to disk before calling status().
|
|
|
|
|
|
|
|
\sa sync()
|
|
|
|
*/
|
2017-08-09 11:51:23 +00:00
|
|
|
QSettings::SettingsStatus QSettings::status() const
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
|
|
|
return d->status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2019-12-23 21:05:10 +00:00
|
|
|
Returns a map of all keys, with their values, that the QSettings
|
|
|
|
object holds.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
\sa keys()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettings::SettingsMap QSettings::map() const
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2019-12-23 21:05:10 +00:00
|
|
|
return d->map;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns a list of all key top-level groups that contain keys that
|
|
|
|
can be read using the QSettings object.
|
|
|
|
|
|
|
|
You can navigate through the entire setting hierarchy using
|
2019-12-23 21:05:10 +00:00
|
|
|
keys() and map().
|
2015-12-10 05:06:13 +02:00
|
|
|
|
2020-02-01 17:24:17 +00:00
|
|
|
\sa map(), groupKeys()
|
2015-12-10 05:06:13 +02:00
|
|
|
*/
|
2019-12-23 21:05:10 +00:00
|
|
|
QStringList QSettings::keys() const
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2020-01-25 18:05:53 +00:00
|
|
|
if (!d->pending.isEmpty()) {
|
|
|
|
QStringList mapkeys = d->map.keys();
|
|
|
|
foreach(const QString &key, d->pending.keys()) {
|
|
|
|
mapkeys.append(key);
|
|
|
|
}
|
|
|
|
return mapkeys;
|
|
|
|
}
|
2019-12-23 21:05:10 +00:00
|
|
|
return d->map.keys();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
2020-02-01 17:24:17 +00:00
|
|
|
/*!
|
|
|
|
Returns the current group.
|
|
|
|
|
|
|
|
\sa beginGroup(), endGroup()
|
|
|
|
*/
|
|
|
|
QString QSettings::group() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
|
|
|
return d->group;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2020-02-11 01:02:13 +00:00
|
|
|
Sets the group prefix to \a group.
|
2020-02-01 17:24:17 +00:00
|
|
|
|
|
|
|
The current group is automatically prepended to all keys
|
|
|
|
specified to QSettings. In addition, query functions such as
|
|
|
|
groupKeys() are based on the group. By default, no group is set.
|
|
|
|
|
|
|
|
Call endGroup() to reset the current group to what it was before
|
|
|
|
the corresponding beginGroup() call. Groups cannot be nested.
|
|
|
|
|
|
|
|
\sa endGroup(), group()
|
|
|
|
*/
|
|
|
|
void QSettings::beginGroup(const QString &group)
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
|
|
|
|
|
|
|
if (!d->group.isEmpty()) {
|
|
|
|
qWarning("QSettings::beginGroup: sub-groups are not supported");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->group = group;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Resets the group to what it was before the corresponding
|
|
|
|
beginGroup() call.
|
|
|
|
|
|
|
|
\sa beginGroup(), group()
|
|
|
|
*/
|
|
|
|
void QSettings::endGroup()
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
|
|
|
if (d->group.isEmpty()) {
|
|
|
|
qWarning("QSettings::endGroup: No matching beginGroup()");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->group.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2020-02-11 01:02:13 +00:00
|
|
|
Returns a list of group-level keys without the group prefix
|
|
|
|
that can be read using the QSettings object.
|
2020-02-01 17:24:17 +00:00
|
|
|
|
2020-02-11 01:02:13 +00:00
|
|
|
If a group is not set using beginGroup(), empty list is
|
|
|
|
returned.
|
2020-02-01 17:24:17 +00:00
|
|
|
|
|
|
|
You can navigate through the entire setting hierarchy using
|
2020-02-11 01:02:13 +00:00
|
|
|
keys(), beginGroup(), groupKeys() and endGroup() recursively.
|
2020-02-01 17:24:17 +00:00
|
|
|
|
|
|
|
\sa keys()
|
|
|
|
*/
|
|
|
|
QStringList QSettings::groupKeys() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
|
|
|
if (d->group.isEmpty()) {
|
|
|
|
return QStringList();
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList result;
|
|
|
|
foreach(const QString &key, keys()) {
|
|
|
|
if (!key.startsWith(d->group + QLatin1Char('/'))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const int groupsize = d->group.size() + 1;
|
|
|
|
QString groupkey = key.mid(groupsize, key.size() - groupsize);
|
|
|
|
const int slashindex = groupkey.indexOf("/");
|
|
|
|
if (slashindex) {
|
|
|
|
groupkey = groupkey.mid(0, slashindex);
|
|
|
|
}
|
|
|
|
if (result.contains(groupkey)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
result.append(groupkey);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-12-10 05:06:13 +02:00
|
|
|
/*!
|
|
|
|
Returns true if settings can be written using this QSettings
|
|
|
|
object; returns false otherwise.
|
|
|
|
|
|
|
|
One reason why isWritable() might return false is if
|
|
|
|
QSettings operates on a read-only file.
|
|
|
|
|
|
|
|
\warning This function is not perfectly reliable, because the
|
|
|
|
file permissions can change at any time.
|
|
|
|
|
|
|
|
\sa fileName(), status(), sync()
|
|
|
|
*/
|
|
|
|
bool QSettings::isWritable() const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2019-12-23 21:05:10 +00:00
|
|
|
QFileInfo info(d->filename);
|
2019-12-25 22:26:14 +00:00
|
|
|
if (info.isWritable()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// if the file does not exist, check if it can be created
|
|
|
|
QFileInfo dirinfo(info.absolutePath());
|
|
|
|
return dirinfo.isWritable();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
|
|
|
Sets the value of setting \a key to \a value. If the \a key already
|
|
|
|
exists, the previous value is overwritten.
|
|
|
|
|
|
|
|
\sa value(), remove(), contains()
|
|
|
|
*/
|
|
|
|
void QSettings::setValue(const QString &key, const QVariant &value)
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
2020-02-01 17:24:17 +00:00
|
|
|
d->pending.insert(d->toGroupKey(key), value);
|
2019-12-23 21:05:10 +00:00
|
|
|
d->notify();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2019-12-23 21:05:10 +00:00
|
|
|
Removes the setting \a key.
|
2015-12-10 05:06:13 +02:00
|
|
|
|
|
|
|
\sa setValue(), value(), contains()
|
|
|
|
*/
|
|
|
|
void QSettings::remove(const QString &key)
|
|
|
|
{
|
|
|
|
Q_D(QSettings);
|
2020-02-01 17:24:17 +00:00
|
|
|
const QString groupkey = d->toGroupKey(key);
|
|
|
|
foreach(const QString &key, d->map.keys()) {
|
|
|
|
if (key.startsWith(groupkey)) {
|
|
|
|
d->map.remove(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach(const QString &key, d->pending.keys()) {
|
|
|
|
if (key.startsWith(groupkey)) {
|
|
|
|
d->pending.remove(key);
|
|
|
|
}
|
|
|
|
}
|
2019-12-23 21:05:10 +00:00
|
|
|
d->notify();
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns true if there exists a setting called \a key; returns
|
|
|
|
false otherwise.
|
|
|
|
|
|
|
|
\sa value(), setValue()
|
|
|
|
*/
|
|
|
|
bool QSettings::contains(const QString &key) const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2020-02-01 17:24:17 +00:00
|
|
|
const QString groupkey = d->toGroupKey(key);
|
|
|
|
return (d->map.contains(groupkey) || d->pending.contains(groupkey));
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
Returns the value for setting \a key. If the setting doesn't
|
|
|
|
exist, returns \a defaultValue.
|
|
|
|
|
|
|
|
If no default value is specified, a default QVariant is
|
|
|
|
returned.
|
|
|
|
|
|
|
|
\sa setValue(), contains(), remove()
|
|
|
|
*/
|
|
|
|
QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
|
|
|
|
{
|
|
|
|
Q_D(const QSettings);
|
2020-02-01 17:24:17 +00:00
|
|
|
const QString groupkey = d->toGroupKey(key);
|
|
|
|
if (d->pending.contains(groupkey)) {
|
|
|
|
return d->pending.value(groupkey);
|
2020-01-25 18:05:53 +00:00
|
|
|
}
|
2020-02-01 17:24:17 +00:00
|
|
|
return d->map.value(groupkey, defaultValue);
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\typedef QSettings::SettingsMap
|
|
|
|
|
|
|
|
Typedef for QMap<QString, QVariant>.
|
2020-01-22 15:39:06 +00:00
|
|
|
|
2015-12-10 05:06:13 +02:00
|
|
|
\sa registerFormat()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\typedef QSettings::ReadFunc
|
|
|
|
|
|
|
|
Typedef for a pointer to a function with the following signature:
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 27
|
|
|
|
|
|
|
|
\c ReadFunc is used in \c registerFormat() as a pointer to a function
|
|
|
|
that reads a set of key/value pairs. \c ReadFunc should read all the
|
|
|
|
options in one pass, and return all the settings in the \c SettingsMap
|
|
|
|
container, which is initially empty.
|
|
|
|
|
|
|
|
\sa WriteFunc, registerFormat()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\typedef QSettings::WriteFunc
|
|
|
|
|
|
|
|
Typedef for a pointer to a function with the following signature:
|
|
|
|
|
|
|
|
\snippet doc/src/snippets/code/src_corelib_io_qsettings.cpp 28
|
|
|
|
|
|
|
|
\c WriteFunc is used in \c registerFormat() as a pointer to a function
|
|
|
|
that writes a set of key/value pairs. \c WriteFunc is only called once,
|
|
|
|
so you need to output the settings in one go.
|
|
|
|
|
|
|
|
\sa ReadFunc, registerFormat()
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\since 4.1
|
|
|
|
\threadsafe
|
|
|
|
|
|
|
|
Registers a custom storage format. On success, returns a special
|
|
|
|
Format value that can then be passed to the QSettings constructor.
|
|
|
|
On failure, returns InvalidFormat.
|
|
|
|
|
|
|
|
The \a extension is the file
|
|
|
|
extension associated to the format (without the '.').
|
|
|
|
|
|
|
|
The \a readFunc and \a writeFunc parameters are pointers to
|
|
|
|
functions that read and write a set of key/value pairs. The
|
|
|
|
QIODevice parameter to the read and write functions is always
|
|
|
|
opened in binary mode (i.e., without the QIODevice::Text flag).
|
|
|
|
*/
|
|
|
|
QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
|
2019-12-23 21:05:10 +00:00
|
|
|
WriteFunc writeFunc)
|
2015-12-10 05:06:13 +02:00
|
|
|
{
|
2019-12-23 21:05:10 +00:00
|
|
|
QMutexLocker locker(qSettingsMutex());
|
2015-12-10 05:06:13 +02:00
|
|
|
CustomFormatVector *customFormatVector = customFormatVectorFunc();
|
|
|
|
int index = customFormatVector->size();
|
|
|
|
if (index == 16) // the QSettings::Format enum has room for 16 custom formats
|
|
|
|
return QSettings::InvalidFormat;
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
QSettingsCustomFormat info;
|
|
|
|
info.format = static_cast<QSettings::Format>(QSettings::CustomFormat1 + index);
|
2015-12-10 05:06:13 +02:00
|
|
|
info.extension = QLatin1Char('.');
|
|
|
|
info.extension += extension;
|
|
|
|
info.readFunc = readFunc;
|
|
|
|
info.writeFunc = writeFunc;
|
|
|
|
customFormatVector->append(info);
|
|
|
|
|
2019-12-23 21:05:10 +00:00
|
|
|
return info.format;
|
2015-12-10 05:06:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#include "moc_qsettings.h"
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
|
|
|
#endif // QT_NO_SETTINGS
|