You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Framework/AzQtComponents/AzQtComponents/Components/ConfigHelpers.h

136 lines
4.8 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <QFile>
#include <QFileSystemWatcher>
#include <QSettings>
#include <QString>
#include <functional>
namespace AzQtComponents
{
namespace ConfigHelpers
{
/* The aim of the *Config.ini files is to provide a human read/writable file which allows
* developers and designers to tweak UI settings without having to rebuild the application.
* Types that QVariant can convert to QString are stored as one might expect:
*
* MyBool=true
* MyInt=5
* MyDecimal=3.14
* MyString=A stored string
*
* QColor is not normally stored by QSettings as a human readable string, it is encoded as a
* QVariant, but the following syntax works with the QVariant::value<QColor> call:
*
* MyColor=#ffffff
*
* Many types that QVariant cannot convert to QString, such as QPoint, QRect and QSize, can
* be specified as follows:
*
* MyPoint=@Point(12 16)
* MyRect=@Rect(0 0 16 16)
* MySize=@Size(4 4)
*
* However there are some types which QVariant does not store in a human readable manner, or
* cannot store at all. For these we provide template specialisations. For example, QPixmap
* can be read as follows:
*
* QPixmap pixmap;
* ConfigHelpers::read<QPixmap>(settings, QStringLiteral("MyPixmap"), pixmap);
*
* QPixmap is specified like this:
*
* MyPixmap=path/to/image.png
*/
template <class T>
void read(QSettings& settings, const QString& key, T& configValue)
{
// Sets configValue to the value of key in settings. If key does not exist, configValue
// is unchanged.
configValue = settings.value(key, QVariant::fromValue(configValue)).template value<T>();
}
template <>
void read(QSettings& settings, const QString& key, QPixmap& configValue);
template <>
void read(QSettings& settings, const QString& key, QCursor& configValue);
/* ConfigHelpers::loadConfig loads the ConfigType from a QSettings IniFormat file and
* watches that file for further changes. When changes occur, the notify function is called.
* Note that in Qt terminology, the notify function can be either a signal or a slot.
*
* Note that in case it does not go without saying, the config pointer must be valid as long
* as the watcher is, otherwise a file change on disk will result in a memory access
* violation.
*
* ConfigType is simply a struct containing the configuration options:
*
* struct Config
* {
* int height = -1;
* };
*
* This function expects WidgetType to have the following static functions:
*
* static Config loadConfig(QSettings& settings);
* static Config defaultConfig();
*/
template <typename ConfigType, typename WidgetType>
void loadConfig(QFileSystemWatcher* watcher, ConfigType* config, const QString& path, const QObject* context, const std::function<void()>& notify)
{
if (QFile::exists(path))
{
// add to the file watcher
watcher->addPath(path);
// connect the relead slot()
QObject::connect(watcher, &QFileSystemWatcher::fileChanged, context, [path, config, notify](const QString& changedPath) {
if (changedPath == path)
{
QSettings settings(path, QSettings::IniFormat);
*config = WidgetType::loadConfig(settings);
Q_EMIT notify();
}
});
QSettings settings(path, QSettings::IniFormat);
*config = WidgetType::loadConfig(settings);
}
else
{
*config = WidgetType::defaultConfig();
}
}
/* GroupGuard ensures that QSettings::endGroup is called when it is destroyed.
*/
class GroupGuard
{
public:
GroupGuard(QSettings* settings, const QString& prefix)
: m_settings(settings)
{
m_settings->beginGroup(prefix);
}
~GroupGuard()
{
m_settings->endGroup();
}
private:
QSettings* m_settings;
};
} // namespace ConfigHelpers
} // namespace AzQtComponents