Commit d7017b81 authored by Clement CHAVANCE's avatar Clement CHAVANCE Committed by Hugo Beauzee-Luyssen

Refactored the SettingsManager

Signed-off-by: default avatarHugo Beauzee-Luyssen <beauze.h@gmail.com>
parent eb6432c6
/*****************************************************************************
* SettingsManager.cpp * : Backend settings manager
* SettingsManager.cpp: Backend settings manager
*****************************************************************************
* Copyright (C) 2008-2010 VideoLAN
* Copyright (C) 2008-2009 the VLMC team
*
* Authors: Clement CHAVANCE <kinder@vlmc.org>
*
......@@ -22,209 +22,222 @@
#include "SettingsManager.h"
#include "VLMCSettingsDefault.h"
#include "ProjectSettingsDefault.h"
#include "SettingValue.h"
#include <QHash>
#include <QDomElement>
#include <QDomNamedNodeMap>
#include <QDomNodeList>
#include <QtDebug>
#include <QSettings>
#include <QDomDocument>
#include <QWriteLocker>
#include <QReadLocker>
#include <QTextStream>
#include <QXmlStreamWriter>
#include <QtDebug>
bool SettingsManager::m_defaultLoaded = false;
SettingsManager::SettingsManager( QObject* parent )
: QObject( parent )
void
SettingsManager::setValue( const QString &key,
const QVariant &value,
SettingsManager::Type type )
{
if ( type == XML )
m_tmpXmlSettings.insert( key, new SettingValue( value ) );
else if ( type == QSett )
m_tmpClassicSettings.insert( key, new SettingValue( value ) );
return ;
}
SettingsManager::~SettingsManager()
void
SettingsManager::setImmediateValue( const QString &key,
const QVariant &value,
SettingsManager::Type type )
{
QWriteLocker wlock( &m_rwLock );
SettingHash *settMap;
if ( type == XML )
settMap = &m_xmlSettings;
else if ( type == QSett )
{
QSettings sett;
sett.setValue( key, value );
sett.sync();
settMap = &m_classicSettings;
}
if ( settMap->contains( key ) )
settMap->value( key )->set( value );
else
settMap->insert( key, new SettingValue( value ) );
return ;
}
void SettingsManager::setValue( const QString& part , const QString& key, const QVariant& value )
QVariant
SettingsManager::value( const QString &key,
const QVariant &defaultValue,
SettingsManager::Type type )
{
m_globalLock.lockForRead();
if ( !m_tempData.contains( part ) )
qDebug() << "value :" << key << "default" << defaultValue;
QReadLocker rl( &m_rwLock );
if ( ( type == XML || type == All ) && m_xmlSettings.contains( key ) )
return m_xmlSettings.value( key )->get();
else if ( ( type == QSett || type == All ) )
{
m_globalLock.unlock();
addNewSettingsPart( part );
if ( m_classicSettings.contains( key ) )
return m_classicSettings.value( key )->get();
else
{
QSettings sett;
QVariant val = sett.value( key, defaultValue );
if ( val != defaultValue )
m_classicSettings.insert( key, new SettingValue( val ) );
return val;
}
}
else
m_globalLock.unlock();
QWriteLocker lock( &m_globalLock );
SettingsPart* tmp = m_tempData[part];
SettingsPart::ConfigPair::iterator it = tmp->m_data.find( key );
if ( it == tmp->m_data.end() )
tmp->m_data[key] = new SettingValue( value );
else
it.value()->set( value );
return ;
return defaultValue;
}
const SettingValue* SettingsManager::getValue( const QString& part, const QString& key ) const
QHash<QString, QVariant>
SettingsManager::group( const QString& groupName, SettingsManager::Type type )
{
if ( !m_data.contains( part ) )
return getValue( "default", key );
QReadLocker readLock( &m_globalLock );
QReadLocker rdLock( &m_data[part]->m_lock );
if ( m_data[part]->m_data.contains( key ) == true )
return m_data[part]->m_data[key];
return NULL;
}
void SettingsManager::saveSettings( const QString& part, QDomDocument& xmlfile, QDomElement& root )
bool
SettingsManager::watchValue( const QString &key,
QObject* receiver,
const char *method,
SettingsManager::Type type )
{
m_globalLock.lockForRead();
if ( !m_data.contains( part ) )
QReadLocker rl( &m_rwLock );
if ( ( type == XML || type == All ) && m_xmlSettings.contains( key ) )
{
m_globalLock.unlock();
return ;
connect( m_xmlSettings[key], SIGNAL( changed( const QVariant& ) ),
receiver, method );
return true;
}
SettingsPart* sett = m_data[part];
m_globalLock.unlock();
//SAVE SETTINGS TO DomDocument
QReadLocker lock( &sett->m_lock );
SettingsPart::ConfigPair::const_iterator it = sett->m_data.begin();
SettingsPart::ConfigPair::const_iterator end = sett->m_data.end();
QDomElement settingsNode = xmlfile.createElement( part );
for ( ; it != end; ++it )
else if ( ( type == QSett || type == All ) )
{
QDomElement elem = xmlfile.createElement( it.key() );
elem.setAttribute( "value", it.value()->get().toString() );
settingsNode.appendChild( elem );
if ( m_classicSettings.contains( key ) )
{
connect( m_classicSettings[key], SIGNAL( changed( const QVariant& ) ),
receiver, method );
return true;
}
}
root.appendChild( settingsNode );
return false;
}
void SettingsManager::loadSettings( const QString& part, const QDomElement& settings )
void
SettingsManager::save() const
{
if ( settings.isNull() == true || settings.tagName() != "project" )
{
qWarning() << "Invalid settings node";
return ;
}
m_globalLock.lockForRead();
if ( !m_data.contains( part ) )
QReadLocker rl( &m_rwLock );
QSettings sett;
SettingHash::const_iterator it = m_classicSettings.begin();
SettingHash::const_iterator ed = m_classicSettings.end();
for ( ; it != ed; ++it )
sett.setValue( it.key(), it.value()->get() );
sett.sync();
}
void
SettingsManager::save( QXmlStreamWriter &stream ) const
{
typedef QPair<QString, SettingValue*> settingPair;
QMultiHash<QString, settingPair> parts;
QReadLocker rl( &m_rwLock );
SettingHash::const_iterator it;
SettingHash::const_iterator ed = m_xmlSettings.end();
for ( it = m_xmlSettings.begin(); it != ed; ++it )
{
qWarning() << "These settings Does not exists";
return ;
QString key = it.key();
if ( key.count( "/" ) == 1 )
{
int idx = key.indexOf( "/" );
QString part = key.left( idx );
QString name = key.right( idx );
parts.insert( part, settingPair( name, it.value() ) );
}
}
SettingsPart* sett = m_data[part];
m_globalLock.unlock();
//Loading all the settings
m_globalLock.lockForWrite();
sett->m_lock.lockForWrite();
QDomNodeList list = settings.childNodes();
int nbChild = list.size();
for ( int idx = 0; idx < nbChild; ++idx )
QMultiHash<QString, settingPair>::const_iterator iter;
QMultiHash<QString, settingPair>::const_iterator end = parts.end();
stream.writeStartElement( "Settings" );
for ( iter = parts.begin(); iter != end; ++iter )
{
QDomNamedNodeMap attrMap = list.at( idx ).attributes();
if ( attrMap.count() > 1 )
stream.writeStartElement( iter.key() );
QList<settingPair> pairs = parts.values( iter.key() );
foreach( settingPair pair, pairs )
{
qWarning() << "Invalid number of attributes for" << list.at( idx ).nodeName();
return ;
stream.writeStartElement( pair.first );
stream.writeAttribute( "value", pair.second->get().toString() );
stream.writeEndElement();
}
sett->m_data.insert( list.at( idx ).toElement().tagName(),
new SettingValue( QVariant( attrMap.item( 0 ).nodeValue() ) ) );
stream.writeEndElement();
}
sett->m_lock.unlock();
m_globalLock.unlock();
emit settingsLoaded();
stream.writeEndElement();
}
void SettingsManager::addNewSettingsPart( const QString& name )
bool
SettingsManager::load( QDomElement &element )
{
QReadLocker rLock( &m_globalLock );
if ( !m_data.contains( name ) )
{
rLock.unlock();
QWriteLocker lock( &m_globalLock );
m_data.insert( name, new SettingsPart );
m_tempData.insert( name, new SettingsPart );
}
}
void SettingsManager::commit()
bool
SettingsManager::commit( SettingsManager::Type type )
{
{
QWriteLocker lock( &m_globalLock );
QHash<QString, SettingsPart*>::iterator it = m_tempData.begin();
QHash<QString, SettingsPart*>::iterator ed = m_tempData.end();
for ( ; it != ed; ++it )
QWriteLocker wlock( &m_rwLock );
if ( type == XML || type == All )
{
SettingsPart* sett = it.value();
QString part = it.key();
QReadLocker rLock( &sett->m_lock );
SettingsPart::ConfigPair::iterator iter = sett->m_data.begin();
SettingsPart::ConfigPair::iterator end = sett->m_data.end();
QWriteLocker wLock( &m_data[part]->m_lock );
for ( ; iter != end; ++iter )
SettingHash::iterator it;
SettingHash::iterator ed = m_tmpXmlSettings.end();
for ( it = m_tmpXmlSettings.begin() ; it != ed; ++it )
{
QString settingName = iter.key();
SettingsPart::ConfigPair::iterator insert_it = m_data[part]->m_data.find( settingName );
if ( insert_it == m_data[part]->m_data.end() )
m_data[part]->m_data.insert( settingName, new SettingValue( iter.value()->get() ) );
if ( m_xmlSettings.contains( it.key() ) )
m_xmlSettings[it.key()]->set( it.value()->get() );
else
m_xmlSettings.insert( it.key(), it.value() );
}
}
if ( type == QSett || type == All )
{
QSettings sett;
SettingHash::iterator it;
SettingHash::iterator ed = m_classicSettings.end();
for ( it = m_classicSettings.begin(); it != ed; ++it )
{
sett.setValue( it.key(), it.value()->get() );
if ( m_classicSettings.contains( it.key() ) )
m_classicSettings[it.key()]->set( it.value()->get() );
else
m_data[part]->m_data[ settingName ]->set( iter.value()->get() );
m_classicSettings.insert( it.key(), it.value() );
}
}
}
flush();
}
void SettingsManager::flush()
void
SettingsManager::flush()
{
QWriteLocker lock( &m_globalLock );
QHash<QString, SettingsPart*>::iterator it = m_tempData.begin();
QHash<QString, SettingsPart*>::iterator ed = m_tempData.end();
for ( ; it != ed; ++it )
{
QWriteLocker wLock( &it.value()->m_lock );
it.value()->m_data.clear();
}
}
void SettingsManager::loadDefaultsSettings()
{
if ( !SettingsManager::m_defaultLoaded )
{
SettingsManager::m_defaultLoaded = true;
VLMCSettingsDefault::load( "default" );
VLMCSettingsDefault::load( "VLMC" );
ProjectSettingsDefault::load( "default" );
ProjectSettingsDefault::load( "project" );
}
QWriteLocker wl( &m_rwLock );
m_tmpXmlSettings.clear();
m_tmpClassicSettings.clear();
}
SettingsManager* SettingsManager::getInstance()
SettingsManager::SettingsManager()
: m_classicSettings(),
m_xmlSettings(),
m_tmpClassicSettings(),
m_tmpXmlSettings(),
m_rwLock()
{
SettingsManager* ret = QSingleton<SettingsManager>::getInstance();
if ( !SettingsManager::m_defaultLoaded )
{
SettingsManager::loadDefaultsSettings();
}
return ret;
}
const SettingsPart* SettingsManager::getConfigPart( const QString& part ) const
SettingsManager::~SettingsManager()
{
QHash<QString, SettingsPart*>::const_iterator it = m_data.find( part );
if ( it == m_data.end() )
return NULL;
return it.value();
}
/*****************************************************************************
* SettingsManager.h: Backend settings manager
*****************************************************************************
* Copyright (C) 2008-2010 VideoLAN
* Copyright (C) 2008-2009 the VLMC team
*
* Authors: Clement CHAVANCE <kinder@vlmc.org>
* Authors: Clement CHAVANCE <chavance.c@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -23,207 +23,67 @@
#ifndef SETTINGSMANAGER_H
#define SETTINGSMANAGER_H
#include "SettingValue.h"
#include "QSingleton.hpp"
#include <Singleton.hpp>
#include <QObject>
#include <QString>
#include <QHash>
#include <QObject>
#include <QReadWriteLock>
#include <QVariant>
class QDomDocument;
class QDomElement;
class QString;
/**
* \struct SettingsPart
* \brief Represent a part of the Settings.
*
* This is used to group different settings, and to be able to easily
* save or load just a part of all the settings used by the application.
*/
class SettingValue;
class QXmlStreamWriter;
class QDomElement;
class SettingValue;
struct SettingsPart
{
typedef QHash<QString, SettingValue*> ConfigPair;
SettingsPart() {}
/**
* \brief the HashList containing the settings
*/
ConfigPair m_data;
/**
* \brief The ReadWriteLock used for when we need to read / write the settingsPart.
*/
QReadWriteLock m_lock;
/**
* \brief This flag is used when the SettingsPart is
* a readOnly Part.
*/
bool m_rdOnly;
private:
SettingsPart( const SettingsPart& );
SettingsPart& operator =( const SettingsPart& );
};
/**
* \class SettingsManager
* \brief Will manage everything related to the settings.
*/
class SettingsManager : public QObject, public QSingleton<SettingsManager>
class SettingsManager : public QObject, public Singleton<SettingsManager>
{
Q_OBJECT
Q_DISABLE_COPY( SettingsManager )
friend class QSingleton<SettingsManager>;
public:
/**
* \brief Set a value to an existing or a new SettingValue
*
* If the SettingsPart part does not exist, it will be created
* \sa commit()
* \param part the part in wich the value will be set
* \param key the key of the setting
* \param value the value of the setting
*/
void setValue( const QString& part, const QString& key, const QVariant& value );
/**
* \brief get a settings value for a given name
*
* if the settings is not in part, return the default value
* for this setting
* \param part the part where the settings is stored
* \param key the setting's name
* \return the settingPart named part
* \warning if part does not exist, return a NULL pointer
*/
const SettingValue* getValue( const QString& part, const QString& key ) const;
/**
* \brief getter for a settingsPart
* \param part the name of the part we wish to get
* \return The settingsPart named part
* \warning returns a NULL pointer if the SettingsPart part does not exist
*/
const SettingsPart* getConfigPart( const QString& part ) const;
/**
* \brief save a settingPart into a DomDocument
*
* This will only save one part, to save all the preferences, you have to call
* this method with all the name of the existing SettingsPart
* \param part The part to save
* \param xmlfile The QDomDocument used to create new QDomElements
* \param root The root Element of the xml file in wich the project will be saved.
*/
void saveSettings( const QString& part, QDomDocument& xmlfile, QDomElement& root );
/**
* \brief load a Settings part from a QDomElement
*
* after all settings contained in the donElement have been loaded, this method will emit the
* settingsLoaded() signal
* \param part the Settings part to Load. The settings part must exist in order to be loaded
* \param settings the QDomElement containing the settingPart to load.
*/
void loadSettings( const QString& part, const QDomElement& settings );
/**
* \brief add a new SettingsPart
* \param name the name of the SettingPart that need to be created
*
* The SettingsPart is not created if name is already used by another
* SettingsPart
*/
void addNewSettingsPart( const QString& name );
/**
* \brief commit all change made into the settingManager
*
* This will commit all the settings modified with the SetValue method
* that have been stored in a temporary Hashlist to the settingManager HashList.
* It allow us to discard all the modified settings that have been modified. like when the user
* press the cancel button wile configuring the project settings via the project wizard
* \sa flush()
*/
void commit();
/**
* \brief clean the temporary value stored in the SettingsManager
*
* this method allow the user to cancel all the modifications made to the settingsManager
* between two calls of the commit method.
* this method is also called at the end of the commit method
*/
void flush();
/**
* \brief Will load the default value of the application and the project settings
*
* the defaults are only loaded once
*/
static void loadDefaultsSettings();
/**
* \brief Return the only available instance of the settingsManager
*/
static SettingsManager* getInstance();
typedef QHash<QString, SettingValue*> SettingHash;
enum Type
{
XML,
QSett,
All
};
void setValue( const QString &key,
const QVariant &value,
SettingsManager::Type type = QSett);
void setImmediateValue( const QString &key,
const QVariant &value,
SettingsManager::Type = QSett);
QVariant value( const QString &key,
const QVariant &defaultValue = QVariant(),
SettingsManager::Type type = QSett );
QHash<QString, QVariant> group( const QString &groupName,
SettingsManager::Type type = QSett );
bool watchValue( const QString &key,
QObject* receiver,
const char *method,
SettingsManager::Type type );
void save() const;
void save( QXmlStreamWriter &stream ) const;
bool load( QDomElement &element );
bool commit( SettingsManager::Type type );
void flush();
private:
SettingsManager( QObject* parent = 0 );
friend class Singleton<SettingsManager>;
SettingsManager();
~SettingsManager();
/**
* \brief the HashList containing the SettingsPart available
*/
QHash<QString, SettingsPart*> m_data;
/**
* \brief the temporary HashList containing the SettingsPart that have been modified between two commits
*/
QHash<QString, SettingsPart*> m_tempData;
SettingHash m_classicSettings;
SettingHash m_xmlSettings;
/**
* \brief The ReadWriteLock used for when we need to read / write the settingsPart haslist.
*/
SettingHash m_tmpClassicSettings;
SettingHash m_tmpXmlSettings;
mutable QReadWriteLock m_globalLock;
/**
* \brief this boolean is used to check if the defaults dettings have already been loaded
*/
static bool m_defaultLoaded;
signals:
/**
* \brief This signal is emmited when the settings have been loaded from a domDocument
*/
void settingsLoaded();
mutable QReadWriteLock m_rwLock;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment