overte/libraries/shared/src/SettingManager.cpp
Dale Glass 32b9cc123c Fix resetting the settings
Also minor documentation improvements
2023-06-04 14:50:03 +02:00

227 lines
6.5 KiB
C++

//
// SettingManager.cpp
//
//
// Created by Clement on 2/2/15.
// Copyright 2015 High Fidelity, Inc.
// Copyright 2022 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SettingManager.h"
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QUuid>
#include "SettingInterface.h"
Q_LOGGING_CATEGORY(settings_manager, "settings.manager")
Q_LOGGING_CATEGORY(settings_writer, "settings.manager.writer")
namespace Setting {
void WriteWorker::start() {
// QSettings seems to have some issues with moving to a new thread.
// Make sure the object is only created once the thread is already up and running.
init();
}
void WriteWorker::setValue(const QString key, const QVariant value) {
//qCDebug(settings_writer) << "Setting config " << key << "to" << value;
init();
if (!_qSettings->contains(key) || _qSettings->value(key) != value) {
_qSettings->setValue(key, value);
}
}
void WriteWorker::removeKey(const QString key) {
init();
_qSettings->remove(key);
}
void WriteWorker::clearAllSettings() {
init();
_qSettings->clear();
sync();
}
void WriteWorker::sync() {
//qCDebug(settings_writer) << "Forcing settings sync";
init();
_qSettings->sync();
}
void WriteWorker::threadFinished() {
qCDebug(settings_writer) << "Settings write worker syncing and terminating";
sync();
this->deleteLater();
}
void WriteWorker::terminate() {
qCDebug(settings_writer) << "Settings write worker being asked to terminate. Syncing and terminating.";
sync();
this->deleteLater();
QThread::currentThread()->exit(0);
}
Manager::Manager(QObject *parent) {
WriteWorker *worker = new WriteWorker();
// We operate purely from memory, and forward all changes to a thread that has writing the
// settings as its only job.
qCDebug(settings_manager) << "Initializing settings write thread";
_workerThread.setObjectName("Settings Writer");
worker->moveToThread(&_workerThread);
// connect(&_workerThread, &QThread::started, worker, &WriteWorker::start, Qt::QueuedConnection);
// All normal connections are queued, so that we're sure they happen asynchronously.
connect(&_workerThread, &QThread::finished, worker, &WriteWorker::threadFinished, Qt::QueuedConnection);
connect(this, &Manager::valueChanged, worker, &WriteWorker::setValue, Qt::QueuedConnection);
connect(this, &Manager::keyRemoved, worker, &WriteWorker::removeKey, Qt::QueuedConnection);
connect(this, &Manager::syncRequested, worker, &WriteWorker::sync, Qt::QueuedConnection);
connect(this, &Manager::clearAllSettingsRequested, worker, &WriteWorker::clearAllSettings, Qt::QueuedConnection);
// This one is blocking because we want to wait until it's actually processed.
connect(this, &Manager::terminationRequested, worker, &WriteWorker::terminate, Qt::BlockingQueuedConnection);
_workerThread.start();
// Load all current settings
QSettings settings;
_fileName = settings.fileName();
for(QString key : settings.allKeys()) {
//qCDebug(settings_manager) << "Loaded key" << key << "with value" << settings.value(key);
_settings[key] = settings.value(key);
}
}
Manager::~Manager() {
}
// Custom deleter does nothing, because we need to shutdown later than the dependency manager
void Manager::customDeleter() { }
void Manager::registerHandle(Interface* handle) {
const QString& key = handle->getKey();
withWriteLock([&] {
if (_handles.contains(key)) {
qCWarning(settings_manager) << "Setting::Manager::registerHandle(): Key registered more than once, overriding: " << key;
}
_handles.insert(key, handle);
});
}
void Manager::removeHandle(const QString& key) {
withWriteLock([&] {
_handles.remove(key);
});
}
void Manager::loadSetting(Interface* handle) {
const auto& key = handle->getKey();
withWriteLock([&] {
QVariant loadedValue = _settings[key];
if (loadedValue.isValid()) {
handle->setVariant(loadedValue);
}
});
}
void Manager::saveSetting(Interface* handle) {
const auto& key = handle->getKey();
if (handle->isSet()) {
QVariant handleValue = handle->getVariant();
withWriteLock([&] {
_settings[key] = handleValue;
});
emit valueChanged(key, handleValue);
} else {
withWriteLock([&] {
_settings.remove(key);
});
emit keyRemoved(key);
}
}
void Manager::forceSave() {
emit syncRequested();
}
void Manager::terminateThread() {
qCDebug(settings_manager) << "Terminating settings writer thread";
emit terminationRequested(); // This blocks
_workerThread.exit();
_workerThread.wait(THREAD_TERMINATION_TIMEOUT);
qCDebug(settings_manager) << "Settings writer terminated";
}
QString Manager::fileName() const {
return resultWithReadLock<QString>([&] {
return _fileName;
});
}
void Manager::remove(const QString &key) {
withWriteLock([&] {
_settings.remove(key);
});
emit keyRemoved(key);
}
QStringList Manager::allKeys() const {
return resultWithReadLock<QStringList>([&] {
return _settings.keys();
});
}
bool Manager::contains(const QString &key) const {
return resultWithReadLock<bool>([&] {
return _settings.contains(key);
});
}
void Manager::setValue(const QString &key, const QVariant &value) {
withWriteLock([&] {
_settings[key] = value;
});
emit valueChanged(key, value);
}
QVariant Manager::value(const QString &key, const QVariant &defaultValue) const {
return resultWithReadLock<QVariant>([&] {
return _settings.value(key, defaultValue);
});
}
void Manager::clearAllSettings() {
withWriteLock([&] {
_settings.clear();
});
emit clearAllSettingsRequested();
}
}