New settings api

This commit is contained in:
Atlante45 2015-02-02 15:56:03 -08:00
parent 1cfd98b2d7
commit 633ec9807d
2 changed files with 166 additions and 115 deletions

View file

@ -9,35 +9,125 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QCoreApplication>
#include <QDebug>
#include <QHash>
#include <QSettings> #include <QSettings>
#include <QThread> #include <QThread>
#include <QThreadStorage> #include <QVector>
#include "PathUtils.h"
#include "Settings.h" #include "Settings.h"
namespace SettingHandles { namespace Setting {
class Manager : public QSettings {
public:
~Manager();
void registerHandle(Interface* handle);
void removeHandle(const QString& key);
void loadSetting(Interface* handle);
void saveSetting(Interface* handle);
void saveAll();
private:
QHash<QString, Interface*> _handles;
};
Manager* privateInstance = nullptr;
static QThreadStorage<QSettings*> storage; // cleans up the settings private instance. Should only be run once at closing down.
void cleanupPrivateInstance() {
QSettings* getSettings() { delete privateInstance;
if (!storage.hasLocalData()) { privateInstance = nullptr;
storage.setLocalData(new QSettings());
QObject::connect(QThread::currentThread(), &QThread::destroyed,
storage.localData(), &QSettings::deleteLater);
} }
return storage.localData();
}
QVariant SettingsBridge::getFromSettings(const QString& key, const QVariant& defaultValue) { // Sets up the settings private instance. Should only be run once at startup
return getSettings()->value(key, defaultValue); void setupPrivateInstance() {
} // read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings::setDefaultFormat(QSettings::IniFormat);
void SettingsBridge::setInSettings(const QString& key, const QVariant& value) { QSettings applicationInfo(PathUtils::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
getSettings()->setValue(key, value); // set the associated application properties
} applicationInfo.beginGroup("INFO");
QCoreApplication::setApplicationName(applicationInfo.value("name").toString());
QCoreApplication::setOrganizationName(applicationInfo.value("organizationName").toString());
QCoreApplication::setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
// Let's set up the settings Private instance on it's own thread
QThread* thread = new QThread();
Q_CHECK_PTR(thread);
privateInstance = new Manager();
Q_CHECK_PTR(privateInstance);
thread->setObjectName("Settings Thread");
QObject::connect(privateInstance, SIGNAL(destroyed()), thread, SLOT(quit()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
privateInstance->moveToThread(thread);
thread->start();
qDebug() << "Settings thread started.";
// Register cleanupPrivateInstance to run inside QCoreApplication's destructor.
qAddPostRoutine(cleanupPrivateInstance);
}
// Register setupPrivateInstance to run after QCoreApplication's constructor.
Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance)
void SettingsBridge::removeFromSettings(const QString& key) { Interface::~Interface() {
getSettings()->remove(key); if (privateInstance) {
} privateInstance->removeHandle(_key);
}
} }
void Interface::init() {
if (privateInstance) {
// Register Handle
privateInstance->registerHandle(this);
_isInitialized = true;
// Load value from disk
privateInstance->loadSetting(this);
} else {
qWarning() << "Setting::Interface::init(): Manager not yet created";
}
}
void Interface::maybeInit() {
if (!_isInitialized) {
init();
}
}
Manager::~Manager() {
saveAll();
sync();
}
void Manager::registerHandle(Setting::Interface* handle) {
QString key = handle->getKey();
if (_handles.contains(key)) {
qWarning() << "Setting::Manager::registerHandle(): Key registered more than once, overriding: " << key;
}
_handles.insert(key, handle);
}
void Manager::removeHandle(const QString& key) {
_handles.remove(key);
}
void Manager::loadSetting(Interface* handle) {
handle->setVariant(value(handle->getKey()));
}
void Manager::saveSetting(Interface* handle) {
if (handle->isSet()) {
setValue(handle->getKey(), handle->getVariant());
} else {
remove(handle->getKey());
}
}
void Manager::saveAll() {
for (auto handle : _handles) {
saveSetting(handle);
}
}
}

View file

@ -21,101 +21,62 @@ class Settings : public QSettings {
}; };
namespace SettingHandles { namespace Setting {
class Interface {
template <typename T> protected:
class SettingHandle { Interface(const QString& key) : _key(key) {}
public: virtual ~Interface();
SettingHandle(const QString& key); void init();
SettingHandle(const QStringList& path); void maybeInit();
SettingHandle(const QString& key, const T& defaultValue);
SettingHandle(const QStringList& path, const T& defaultValue);
T get() const; // Returns setting value, returns its default value if not found
T get(const T& other) const; // Returns setting value, returns other if not found
T getDefault() const;
void set(const T& value) const;
void reset() const;
void remove() const;
private:
const QString _key;
const QVariant _defaultValue;
};
class SettingsBridge {
private:
static QVariant getFromSettings(const QString& key, const QVariant& defaultValue);
static void setInSettings(const QString& key, const QVariant& value);
static void removeFromSettings(const QString& key);
template<typename T>
friend class SettingHandle;
};
template <typename T>
SettingHandle<T>::SettingHandle(const QString& key) : _key(key) {
}
template <typename T>
SettingHandle<T>::SettingHandle(const QStringList& path) : _key(path.join("/")) {
}
template <typename T>
SettingHandle<T>::SettingHandle(const QString& key, const T& defaultValue) :
_key(key),
_defaultValue(defaultValue) {
}
template <typename T>
SettingHandle<T>::SettingHandle(const QStringList& path, const T& defaultValue) :
_key(path.join("/")),
_defaultValue(defaultValue) {
} QString getKey() const { return _key; }
bool isSet() const { return _isSet; }
template <typename T>
T SettingHandle<T>::get() const { virtual void setVariant(const QVariant& variant) = 0;
QVariant variant = SettingsBridge::getFromSettings(_key, _defaultValue); virtual QVariant getVariant() = 0;
if (variant.canConvert<T>()) {
return variant.value<T>(); bool _isInitialized = false;
} bool _isSet = false;
return _defaultValue.value<T>(); const QString _key;
}
friend class Manager;
template <typename T> };
T SettingHandle<T>::get(const T& other) const {
QVariant variant = SettingsBridge::getFromSettings(_key, QVariant(other));
if (variant.canConvert<T>()) {
return variant.value<T>();
}
return other;
}
template <typename T> inline
T SettingHandle<T>::getDefault() const {
return _defaultValue.value<T>();
}
template <typename T> inline
void SettingHandle<T>::set(const T& value) const {
if (value != get()) {
SettingsBridge::setInSettings(_key, QVariant(value));
}
}
template <typename T> inline
void SettingHandle<T>::reset() const {
SettingsBridge::setInSettings(_key, _defaultValue);
}
template <typename T> inline template <typename T>
void SettingHandle<T>::remove() const { class Handle : public Interface {
SettingsBridge::removeFromSettings(_key); public:
} Handle(const QString& key) : Interface(key) {}
Handle(const QStringList& path) : Interface(path.join("/")) {}
Handle(const QString& key, const T& defaultValue) : Interface(key), _defaultValue(defaultValue) {}
Handle(const QStringList& path, const T& defaultValue) : Handle(path.join("/"), defaultValue) {}
// Returns setting value, returns its default value if not found
T get() { return get(_defaultValue); }
// Returns setting value, returns other if not found
T get(const T& other) { maybeInit(); return (_isSet) ? _value : other; }
T getDefault() const { return _defaultValue; }
void set(const T& value) { maybeInit(); _value = value; _isSet = true; }
void reset() { set(_defaultValue); }
void remove() { maybeInit(); _isSet = false; }
protected:
virtual void setVariant(const QVariant& variant);
virtual QVariant getVariant() { return QVariant::fromValue(get()); }
private:
T _value;
const T _defaultValue;
};
template <typename T>
void Handle<T>::setVariant(const QVariant& variant) {
if (variant.canConvert<T>()) {
set(variant.value<T>());
}
}
} }
#endif // hifi_Settings_h #endif // hifi_Settings_h