* ./vslsisapd/src/configuration:

- Change: Internal rewrite of the check function, now named _doChange()
        and shared by all mutators.
    - Change: Logs now contains entries with the last correct value and are
        able to restore that value.
    - Change: LogWidget simplificated, only one message label. But now two
        buttons (Continue/Cancel).
    - Change: In ConfigurationWidget, two steps validation "mustExist" then
        "needRestart".
This commit is contained in:
Jean-Paul Chaput 2010-10-13 21:44:50 +00:00
parent 3db947d302
commit 45f9dcc394
9 changed files with 262 additions and 160 deletions

View File

@ -164,7 +164,10 @@ namespace {
, _getAttributeValue("value")
);
} else {
_parameter->setString ( _getAttributeValue("value"), false );
_parameter->setString ( _getAttributeValue("value")
, (Parameter::AllRequirements | Parameter::FromString)
& ~Parameter::TypeCheck
);
}
if ( not attrRestart.empty() ) _parameter->setFlags ( Parameter::NeedRestart );
@ -389,11 +392,7 @@ namespace Cfg {
, _layout (this)
, _flags (0)
, _logSets ()
{
_logSets.reserve ( LogTypeSize );
for ( size_t ilog=0 ; ilog<LogTypeSize ; ++ilog )
_logSets.push_back ( set<string>() );
}
{ }
ConfigurationWidget* Configuration::buildWidget ( unsigned int flags )
@ -443,15 +442,31 @@ namespace Cfg {
}
void Configuration::addLog ( unsigned int type, const string& id )
const set<Configuration::LogEntry>& Configuration::getLogs ( unsigned int mask ) const
{
_logSets[ (type<LogTypeSize) ? type : 0 ].insert ( id );
static set<LogEntry> _failsafe;
map< unsigned int, set<LogEntry> >::const_iterator ilog = _logSets.find(mask);
if ( ilog != _logSets.end() ) return (*ilog).second;
return _failsafe;
}
void Configuration::addLog ( unsigned int mask, const string& id )
{
map< unsigned int, set<LogEntry> >::iterator ilog = _logSets.find(mask);
if ( ilog == _logSets.end() ) {
_logSets.insert ( make_pair(mask,set<LogEntry>()) );
ilog = _logSets.find(mask);
}
(*ilog).second.insert ( LogEntry(id) );
}
void Configuration::removeLog ( unsigned int type, const string& id )
void Configuration::removeLog ( unsigned int mask, const string& id )
{
_logSets[ (type<LogTypeSize) ? type : 0 ].erase ( id );
map< unsigned int, set<LogEntry> >::iterator ilog = _logSets.find(mask);
if ( ilog != _logSets.end() ) (*ilog).second.erase ( id );
}

View File

@ -194,21 +194,29 @@ namespace Cfg {
void ConfigurationWidget::applyClicked ()
{
emit updateParameters();
checkConfiguration ();
if ( checkConfiguration(Configuration::LogNeedExist) == QDialog::Accepted ) {
if ( checkConfiguration(Configuration::LogRestart) == QDialog::Accepted ) {
emit confOk();
} else {
Configuration* configuration = Configuration::get();
configuration->restoreFromLogs(Configuration::LogRestart);
configuration->clearLogs (Configuration::LogRestart);
}
}
}
void ConfigurationWidget::checkConfiguration ()
int ConfigurationWidget::checkConfiguration ( unsigned int mask )
{
Configuration* configuration = Configuration::get();
if ( configuration->hasLogs() ) {
if ( configuration->hasLogs(mask) ) {
if ( _log == NULL ) _log = new LogWidget(this);
_log->updateLogs ();
_log->exec ();
} else {
emit checkOk();
_log->updateLogs (mask);
return _log->exec ();
}
return QDialog::Accepted;
}

View File

@ -45,16 +45,17 @@ namespace Cfg {
LogWidget::LogWidget ( QWidget* parent )
: QDialog (parent)
, _restartMessage (new QLabel())
, _needExistMessage(new QLabel())
: QDialog (parent)
, _message (new QLabel())
, _contButton (new QPushButton())
, _cancelButton(new QPushButton())
{
setModal ( true );
setWindowTitle( tr("<Configuration Message>") );
setToolTip ( tr("You should better follow these instructions...") );
_restartMessage->setTextFormat ( Qt::RichText );
_restartMessage->setText ( "<b>Oups! I did it again!</b>" );
_message->setTextFormat ( Qt::RichText );
_message->setText ( "<b>Oups! I did it again!</b>" );
QLabel* ok = new QLabel ();
ok->setSizePolicy ( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding );
@ -62,20 +63,23 @@ namespace Cfg {
ok->setStyleSheet ( "QLabel { background-color: #FF9999;"
" padding: 5px }" );
QPushButton* okButton = new QPushButton ();
okButton->setSizePolicy ( QSizePolicy::Fixed, QSizePolicy::Fixed );
okButton->setText ( tr("Continue") );
_contButton->setSizePolicy ( QSizePolicy::Fixed, QSizePolicy::Fixed );
_contButton->setText ( tr("Continue") );
_cancelButton->setSizePolicy ( QSizePolicy::Fixed, QSizePolicy::Fixed );
_cancelButton->setText ( tr("Cancel") );
QHBoxLayout* hLayout2 = new QHBoxLayout ();
hLayout2->addStretch ( 1 );
hLayout2->addWidget ( okButton, Qt::AlignCenter );
hLayout2->addWidget ( _contButton, Qt::AlignCenter );
hLayout2->addStretch ( 1 );
hLayout2->addWidget ( _cancelButton, Qt::AlignCenter );
hLayout2->addStretch ( 1 );
QVBoxLayout* vLayout1 = new QVBoxLayout ();
vLayout1->setContentsMargins ( 10, 10, 10, 10 );
vLayout1->setSpacing ( 0 );
vLayout1->addWidget ( _restartMessage , Qt::AlignCenter );
vLayout1->addWidget ( _needExistMessage, Qt::AlignCenter );
vLayout1->addWidget ( _message, Qt::AlignCenter );
vLayout1->addSpacing ( 10 );
vLayout1->addLayout ( hLayout2, Qt::AlignCenter );
@ -87,7 +91,8 @@ namespace Cfg {
setLayout ( hLayout1 );
connect ( okButton, SIGNAL(clicked()), this, SLOT(accept()) );
connect ( _contButton , SIGNAL(clicked()), this, SLOT(accept()) );
connect ( _cancelButton, SIGNAL(clicked()), this, SLOT(reject()) );
}
@ -97,34 +102,41 @@ namespace Cfg {
}
void LogWidget::updateLogs ()
void LogWidget::updateLogs ( unsigned int mask )
{
Configuration* configuration = Configuration::get();
QString contents;
bool enableCont = true;
for ( size_t ilog=0 ; ilog<Configuration::LogTypeSize ; ++ilog ) {
const set<string>& logs = configuration->getLogs(ilog);
QLabel* messageLabel = NULL;
QString contents;
const char* header = NULL;
for ( size_t ibit=0 ; ibit < 32 ; ++ibit ) {
unsigned int bit = 1 << ibit;
const char* header = NULL;
switch ( ilog ) {
switch ( bit ) {
case Configuration::LogRestart:
messageLabel = _restartMessage;
header = "<b>Program needs restart for these parameters to take effect:</b><br>";
header = "<b>Program needs restart for these parameters to take effect:</b><br>";
break;
case Configuration::LogNeedExist:
messageLabel = _needExistMessage;
header = "<b>Those parameters needs file/path to exists:</b><br>";
header = "<b>Those parameters needs file/path to exists:</b><br>";
break;
}
if ( messageLabel == NULL ) continue;
if ( (header == NULL) or not (mask & bit) ) continue;
mask &= ~bit;
const set<Configuration::LogEntry>& logs = configuration->getLogs(bit);
if ( not logs.empty() ) {
switch ( bit ) {
case Configuration::LogRestart: break;
case Configuration::LogNeedExist: enableCont = false; break;
}
contents += header;
set<string>::const_iterator iid = logs.begin();
for ( ; iid != logs.end() ; ++iid ) {
Parameter* p = configuration->getParameter((*iid));
set<Configuration::LogEntry>::const_iterator ientry = logs.begin();
for ( ; ientry != logs.end() ; ++ientry ) {
Parameter* p = configuration->getParameter((*ientry).getId());
if ( p != NULL ) {
WidgetDescription* desc = configuration->getLayout().getWidget ( p->getId() );
@ -142,9 +154,9 @@ namespace Cfg {
}
}
}
messageLabel->setText ( contents );
}
_message->setText ( contents );
_contButton->setEnabled ( enableCont );
}

View File

@ -36,6 +36,9 @@ namespace Cfg {
using std::cerr;
using std::endl;
using std::string;
using std::ostringstream;
using std::boolalpha;
using std::hex;
string Parameter::typeToString ( Parameter::Type type )
@ -131,20 +134,14 @@ namespace Cfg {
}
bool Parameter::setString ( const std::string& s, bool check )
bool Parameter::setString ( const std::string& s, unsigned int flags )
{
if ( check and (_type != String) )
if ( (flags & TypeCheck) and (_type != String) )
cerr << "[ERROR] Parameter::setString(): Setting " << Parameter::typeToString(_type)
<< " parameter <" << _id
<< "> as " << Parameter::typeToString(String)<< " (type mismatch)." << endl;
if ( _value == s ) return true;
_value = s;
_onValueChanged();
_checkRequirements();
return true;
return _doChange ( flags, s, false, 0, 0.0 );
}
@ -155,14 +152,7 @@ namespace Cfg {
<< " parameter <" << _id
<< "> as " << Parameter::typeToString(Bool)<< " (type mismatch)." << endl;
std::ostringstream s; s << std::boolalpha << b;
if ( _value == s.str() ) return true;
_value = s.str();
_onValueChanged();
_checkRequirements();
return true;
return _doChange ( AllRequirements, "", b, 0, 0.0 );
}
@ -173,17 +163,7 @@ namespace Cfg {
<< " parameter <" << _id
<< "> as " << Parameter::typeToString(Int)<< " (type mismatch)." << endl;
bool success = checkValue(i);
if ( success ) {
std::ostringstream s; s << i;
if ( _value == s.str() ) return true;
_value = s.str();
_onValueChanged();
_checkRequirements();
}
return success;
return _doChange ( AllRequirements, "", false, i, 0.0 );
}
@ -194,17 +174,7 @@ namespace Cfg {
<< " parameter <" << _id
<< "> as " << Parameter::typeToString(Double)<< " (type mismatch)." << endl;
bool success = checkValue(d);
if ( success ) {
std::ostringstream s; s << d;
if ( _value == s.str() ) return true;
_value = s.str();
_onValueChanged();
_checkRequirements();
}
return success;
return _doChange ( AllRequirements, "", false, 0, d );
}
@ -215,37 +185,72 @@ namespace Cfg {
<< " parameter <" << _id
<< "> as " << Parameter::typeToString(Double)<< " (type mismatch)." << endl;
bool success = checkValue(d/100.0);
if ( success ) {
std::ostringstream s; s << (d/100.0);
if ( _value == s.str() ) return true;
_value = s.str();
_onValueChanged();
_checkRequirements();
}
return success;
return _doChange ( AllRequirements, "", false, 0, d );
}
void Parameter::_checkRequirements () const
bool Parameter::_doChange ( unsigned int flags, const string& s, bool b, int i, double d )
{
Configuration* configuration = Configuration::get();
//cerr << "_doChange: " << _id << ":" << _value << " -> \"" << s << "\"|" << b << "|" << i << "|" << d;
if ( hasFlags(NeedRestart) ) {
Configuration* configuration = Configuration::get();
ostringstream svalue;
bool success = true;
unsigned int type = (flags & FromString) ? String : _type;
switch ( type ) {
case Unknown:
break;
case String:
svalue << s;
break;
case Bool:
svalue << boolalpha << b;
break;
case Enumerate:
case Int:
svalue << i;
if ( flags & TypeCheck ) success = checkValue(i);
break;
case Double:
svalue << d;
if ( flags & TypeCheck ) success = checkValue(d);
break;
case Percentage:
svalue << (d/100.0);
if ( flags & TypeCheck ) success = checkValue(d/100.0);
break;
}
if ( not success ) {
//cerr << " (" << _flags << "," << _minInt << ") check failed." << endl;
return false;
}
if ( svalue.str() == _value ) {
//cerr << " no change." << endl;
return true;
}
if ( (flags & NeedRestart) and hasFlags(NeedRestart) ) {
configuration->addLog ( Configuration::LogRestart, _id );
}
if ( hasFlags(MustExist) ) {
if ( (flags & MustExist) and hasFlags(MustExist) ) {
if ( _type == String ) {
bfs::path filePath = ( asString() );
bfs::path filePath = ( svalue.str() );
if ( not bfs::exists(filePath) )
configuration->addLog ( Configuration::LogNeedExist, _id );
else
configuration->removeLog ( Configuration::LogNeedExist, _id );
}
}
//cerr << " updated" << endl;
_value = svalue.str();
_onValueChanged();
return true;
}

View File

@ -237,6 +237,8 @@ namespace Cfg {
void ParameterWidget::onUpdateValueCb ( Parameter* )
{
//cerr << "onUpdateValue: " << _parameter->getId() << " -> " << _parameter->asString() << endl;
if ( _parameter->getType() == Parameter::String )
{
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(_valueWidget);

View File

@ -43,41 +43,53 @@ namespace Cfg {
class Configuration {
public:
enum Flags { DriveValues=0x1, DriveLayout=0x2 };
enum LogType { LogRestart=0, LogNeedExist, LogTypeSize };
enum LogType { LogRestart=0x1, LogNeedExist=0x2, AllLogs=0xFFFF };
public:
static Configuration* get ();
class LogEntry {
public:
inline LogEntry ( const std::string& id );
inline const std::string& getId () const;
inline const std::string& getValid () const;
inline void restore () const;
private:
std::string _id;
std::string _valid;
};
public:
static Configuration* get ();
public:
// Methods.
ConfigurationWidget* buildWidget ( unsigned int flags );
ConfigurationDialog* buildDialog ();
ConfigurationWidget* buildWidget ( unsigned int flags );
ConfigurationDialog* buildDialog ();
inline const std::map<const std::string,Parameter*>&
getParameters () const;
inline const std::set<std::string>&
getLogs ( unsigned int type ) const;
inline unsigned int getFlags () const;
inline const LayoutDescription& getLayout () const;
inline LayoutDescription& getLayout ();
Parameter* getParameter ( const std::string& id
, Parameter::Type type=Parameter::Unknown ) const;
Parameter* addParameter ( const std::string& id
, Parameter::Type type
, const std::string& value );
inline void setFlags ( unsigned int mask );
inline bool hasLogs () const;
void addLog ( unsigned int type, const std::string& id );
void removeLog ( unsigned int type, const std::string& id );
inline void clearLogs ();
void print ( std::ostream& ) const;
bool readFromFile ( const std::string& );
bool writeToFile ( const std::string&, unsigned int flags, const std::string& tabs="" ) const;
void writeToStream ( std::ostream&, unsigned int flags, const std::string& tabs="" ) const;
getParameters () const;
const std::set<LogEntry>& getLogs ( unsigned int ilog ) const;
inline unsigned int getFlags () const;
inline const LayoutDescription& getLayout () const;
inline LayoutDescription& getLayout ();
Parameter* getParameter ( const std::string& id
, Parameter::Type type=Parameter::Unknown ) const;
Parameter* addParameter ( const std::string& id
, Parameter::Type type
, const std::string& value );
inline void setFlags ( unsigned int mask );
inline bool hasLogs ( unsigned int mask ) const;
void addLog ( unsigned int mask, const std::string& id );
void removeLog ( unsigned int mask, const std::string& id );
inline void restoreFromLogs ( unsigned int mask );
inline void clearLogs ( unsigned int mask );
void print ( std::ostream& ) const;
bool readFromFile ( const std::string& );
bool writeToFile ( const std::string&, unsigned int flags, const std::string& tabs="" ) const;
void writeToStream ( std::ostream&, unsigned int flags, const std::string& tabs="" ) const;
private:
// Attributes.
static Configuration* _singleton;
std::map<const std::string,Parameter*> _parameters;
LayoutDescription _layout;
unsigned int _flags;
std::vector< std::set<std::string> > _logSets;
static Configuration* _singleton;
std::map<const std::string,Parameter*> _parameters;
LayoutDescription _layout;
unsigned int _flags;
std::map< unsigned int, std::set<LogEntry> > _logSets;
private:
Configuration ();
};
@ -87,25 +99,42 @@ namespace Cfg {
inline const std::map<const std::string,Parameter*>& Configuration::getParameters () const
{ return _parameters; }
inline const std::set<std::string>& Configuration::getLogs ( unsigned int type ) const
{ return _logSets[(type<LogTypeSize) ? type : 0]; }
inline const LayoutDescription& Configuration::getLayout () const { return _layout; }
inline LayoutDescription& Configuration::getLayout () { return _layout; }
inline unsigned int Configuration::getFlags () const { return _flags; }
inline void Configuration::setFlags ( unsigned int mask ) { _flags |= mask; }
inline bool Configuration::hasLogs () const
inline bool Configuration::hasLogs ( unsigned int mask ) const
{
for ( size_t ilog=0 ; ilog<_logSets.size() ; ++ilog )
if ( not _logSets[ilog].empty () ) return true;
std::map< unsigned int, std::set<LogEntry> >::const_iterator ilog = _logSets.begin();
for ( ; ilog != _logSets.end() ; ++ilog )
if ( (mask & (*ilog).first) and not (*ilog).second.empty () ) return true;
return false;
}
inline void Configuration::clearLogs ()
inline void Configuration::restoreFromLogs ( unsigned int mask )
{
for ( size_t ilog=0 ; ilog<_logSets.size() ; ++ilog )
_logSets[ilog].clear ();
std::map< unsigned int, std::set<LogEntry> >::iterator ilog = _logSets.begin();
for ( ; ilog != _logSets.end() ; ++ilog ) {
if ( mask & (*ilog).first ) {
std::set<LogEntry>::iterator ientry = (*ilog).second.begin();
for ( ; ientry != (*ilog).second.end() ; ++ientry ) {
//std::cerr << "Restoring " << (*ientry).getId() << " -> " << (*ientry).getValid() << std::endl;
(*ientry).restore ();
}
}
}
}
inline void Configuration::clearLogs ( unsigned int mask )
{
std::map< unsigned int, std::set<LogEntry> >::iterator ilog = _logSets.begin();
for ( ; ilog != _logSets.end() ; ++ilog ) {
if ( mask & (*ilog).first ) (*ilog).second.clear();
}
}
@ -174,6 +203,29 @@ namespace Cfg {
}
inline Configuration::LogEntry::LogEntry ( const std::string& id )
: _id (id)
, _valid("")
{
Parameter* parameter = Configuration::get()->getParameter(id);
if ( parameter != NULL ) _valid = parameter->asString();
}
inline const std::string& Configuration::LogEntry::getId () const { return _id; }
inline const std::string& Configuration::LogEntry::getValid () const { return _valid; }
inline void Configuration::LogEntry::restore () const
{
Parameter* parameter = Configuration::get()->getParameter(_id);
if ( parameter != NULL ) parameter->setString(_valid,false);
}
inline bool operator< ( const Configuration::LogEntry& lhs, const Configuration::LogEntry& rhs )
{ return lhs.getId() < rhs.getId(); }
} // End of Cfg namespace.

View File

@ -73,13 +73,13 @@ namespace Cfg {
, int span =1
, int flags =0 );
void syncSlaves ();
void checkConfiguration ();
int checkConfiguration ( unsigned int mask );
void selectTab ( const std::string& );
public slots:
void applyClicked ();
signals:
void updateParameters ();
void checkOk ();
void confOk ();
private:
unsigned int _flags;
QFont _boldFont;

View File

@ -29,6 +29,7 @@
#include <QDialog>
class QLabel;
class QPushButton;
namespace Cfg {
@ -38,12 +39,13 @@ namespace Cfg {
Q_OBJECT;
public:
LogWidget ( QWidget* parent=NULL);
void updateLogs ();
void updateLogs ( unsigned int mask );
private:
QLabel* _restartMessage;
QLabel* _needExistMessage;
protected:
virtual void closeEvent ( QCloseEvent* );
private:
QLabel* _message;
QPushButton* _contButton;
QPushButton* _cancelButton;
};

View File

@ -38,20 +38,23 @@ namespace Cfg {
class Parameter {
public:
enum Type { Unknown = 0
, String = 1
, Bool = 2
, Int = 3
, Enumerate = 4
, Double = 5
, Percentage = 6
enum Type { Unknown = 0
, String = 1
, Bool = 2
, Int = 3
, Enumerate = 4
, Double = 5
, Percentage = 6
};
enum Flags { HasMin = 0x01
, HasMax = 0x02
, IsFile = 0x04
, IsPath = 0x08
, NeedRestart = 0x10
, MustExist = 0x20
enum Flags { HasMin = 0x01
, HasMax = 0x02
, IsFile = 0x04
, IsPath = 0x08
, NeedRestart = 0x10
, MustExist = 0x20
, TypeCheck = 0x40
, FromString = 0x80
, AllRequirements = HasMin|HasMax|IsFile|IsPath|NeedRestart|MustExist|TypeCheck
};
typedef boost::function< void(Parameter*) > ParameterChangedCb_t;
public:
@ -98,7 +101,7 @@ namespace Cfg {
inline void addSlave ( const std::string& );
inline void setFlags ( int mask );
inline void unsetFlags ( int mask );
bool setString ( const std::string&, bool check=true );
bool setString ( const std::string&, unsigned int flags=AllRequirements );
bool setBool ( bool );
bool setInt ( int );
bool setDouble ( double );
@ -110,7 +113,7 @@ namespace Cfg {
inline void registerCb ( ParameterChangedCb_t );
private:
inline void _onValueChanged ();
void _checkRequirements () const;
bool _doChange ( unsigned int flags, const std::string&, bool, int, double );
private:
// Attributes.
std::string _id;
@ -150,12 +153,15 @@ namespace Cfg {
// std::cerr << "flags:" << _flags << " "
// << _minInt << " < " << value << " < " << _maxInt
// << " : " << std::boolalpha << ok << std::endl;
// std::cerr << " " << std::boolalpha << ok;
return ok;
}
inline bool Parameter::checkValue ( double value ) const {
// std::cerr << " (double) " << _minDouble << "<" << value << "<" << _maxDouble;
bool ok = not ( ( (_flags&HasMin) and (value < _minDouble) )
or ( (_flags&HasMax) and (value > _maxDouble) ) );
// std::cerr << " " << std::boolalpha << ok;
return ok;
}