shared-libraries/ScStwLibraries/sources/scstwsettings.cpp

185 lines
6.8 KiB
C++

/****************************************************************************
** ScStw Libraries
** Copyright (C) 2020 Itsblue development
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "../headers/scstwsettings.h"
ScStwSettings::ScStwSettings(QObject *parent, bool overwriteFileOnErrors) : QObject(parent)
{
#ifdef RASPI
QString path = "/root/.config/ScStwBasestation";
#else
QString path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
#endif
QDir dir(path);
if(!dir.mkpath(path))
qFatal("[FATAL] Failed to create writable directory for settings at %s", qPrintable(path));
this->settingsFile = new QFile(path + "/settings.json");
this->fileIsReadonly = false;
if(!this->settingsFile->open(QFile::ReadWrite))
qFatal("[FATAL] Couldn't open settings file %s", qPrintable(path + "/settings.json"));
if(this->settingsFile->size() != 0 && !this->loadSettingsFromFile()) {
if(overwriteFileOnErrors) {
this->writeSettingsToFile();
qWarning("[WARNING] Settings file (%s) was of invalid format and therefore overwritten!", qPrintable(path + "/settings.json"));
}
else {
qWarning("[WARNING] Settings file (%s) was of invalid format!", qPrintable(path + "/settings.json"));
this->fileIsReadonly = true;
}
}
connect(this, &ScStwSettings::settingChanged, this, &ScStwSettings::writeSettingsToFile);
this->registerKeyLevelConverters(ScStwSettings::KeyLevel, &ScStwSettings::keyToString, &ScStwSettings::keyToType);
this->setDefaultSetting(ScStwSettings::BaseStationSetting::ReadySoundEnableSetting, false);
this->setDefaultSetting(ScStwSettings::BaseStationSetting::ReadySoundDelaySetting, 0);
this->setDefaultSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundEnableSetting, false);
this->setDefaultSetting(ScStwSettings::BaseStationSetting::AtYourMarksSoundDelaySetting, 0);
this->setDefaultSetting(ScStwSettings::SoundVolumeSetting, 1);
this->setDefaultSetting(ScStwSettings::CompetitionModeSetting, false);
}
QVariant ScStwSettings::readSetting(BaseStationSetting key) {
return this->readSetting(key, 0);
}
QVariant ScStwSettings::readSetting(int key, int keyLevel) {
if(this->keyToStringConverters.contains(keyLevel))
return this->readSetting(this->keyToStringConverters[keyLevel](key), key, keyLevel);
else
return QVariant();
}
bool ScStwSettings::writeSetting(BaseStationSetting key, QVariant value) {
return this->writeSetting(key, 0, value);
}
bool ScStwSettings::writeSetting(int key, int keyLevel, QVariant value) {
if(this->keyToStringConverters.contains(keyLevel))
return this->writeSetting(this->keyToStringConverters[keyLevel](key), value, key, keyLevel);
else
return false;
}
bool ScStwSettings::setDefaultSetting(BaseStationSetting key, QVariant defaultValue) {
return this->setDefaultSetting(key, 0, defaultValue);
}
bool ScStwSettings::setDefaultSetting(int key, int keyLevel, QVariant defaultValue) {
if(this->keyToStringConverters.contains(keyLevel))
return this->setDefaultSetting(this->keyToStringConverters[keyLevel](key), defaultValue, key, keyLevel);
else
return false;
}
QVariant ScStwSettings::readSetting(QString key, int keyInt, int keyLevel) {
Q_UNUSED(keyInt)
Q_UNUSED(keyLevel)
if(this->settingsCache.contains(key))
return this->settingsCache[key];
else
return QVariant();
}
bool ScStwSettings::writeSetting(QString key, QVariant value, int keyInt, int keyLevel) {
// check if the value type is valid
if(!this->keyToTypeConverters.contains(keyLevel) || !value.convert(this->keyToTypeConverters[keyLevel](keyInt)) || value.type() == QVariant::Invalid) {
return false;
}
// write the setting
if(!this->settingsCache.contains(key))
this->settingsCache.insert(key, value);
else if (this->settingsCache[key] == value)
return true;
else
this->settingsCache[key] = value;
emit this->settingChanged(keyInt, keyLevel, value);
return true;
}
bool ScStwSettings::setDefaultSetting(QString key, QVariant defaultValue, int keyInt, int keyLevel) {
if(!this->settingsCache.contains(key))
return this->writeSetting(key, defaultValue, keyInt, keyLevel);
return true;
}
ScStwSetting * ScStwSettings::getSetting(int key, int keyLevel) {
if(!this->internalSettingHandlers.contains(keyLevel))
this->internalSettingHandlers.insert(keyLevel, {});
if(!this->internalSettingHandlers[keyLevel].contains(key))
this->internalSettingHandlers[keyLevel].insert(key, new ScStwSetting(key, keyLevel, this, this));
return this->internalSettingHandlers[keyLevel][key];
}
bool ScStwSettings::registerKeyLevelConverters(int keyLevel, keyToStringConverter keyToStringConverterFunction, keyToTypeConverter keyToTypeConverterFunction) {
if(this->keyToStringConverters.contains(keyLevel))
return false;
this->keyToStringConverters.insert(keyLevel, keyToStringConverterFunction);
this->keyToTypeConverters.insert(keyLevel, keyToTypeConverterFunction);
return true;
}
/*
* File handling
*/
bool ScStwSettings::writeSettingsToFile() {
if(this->fileIsReadonly) {
qWarning() << "[WARNING][SETTINS] Cannot write changes to file! It has been marked readonly due to parse errors (see above).";
return false;
}
QJsonDocument doc = QJsonDocument::fromVariant(this->settingsCache);
// overwrite file
this->settingsFile->resize(0);
this->settingsFile->reset();
this->settingsFile->write(doc.toJson(QJsonDocument::Indented));
this->settingsFile->flush();
return true;
}
bool ScStwSettings::loadSettingsFromFile() {
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(this->settingsFile->readAll(), &error);
if(error.error != QJsonParseError::NoError) {
qWarning() << "[ERROR][SETTINGS] Error when parsing settings file: " << error.errorString() << " at offset " << error.offset;
return false;
}
if(doc.toVariant().type() != QVariant::Map)
return false;
this->settingsCache = doc.toVariant().toMap();
return true;
}