Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Native Development

Reply
Developer
pfluger
Posts: 100
Registered: ‎02-10-2009
My Device: Q10, Z10
My Carrier: T-Mobile
Accepted Solution

Bool changes to QString when QSettings load

[ Edited ]

I have run into a problem when storing bool values in QSettings. It looks like a bug to me, but maybe I am missing something?

 

I have this short piece of code:

 

QSettings* settings = new QSettings();
qDebug() << "test setting is of type " << settings->value("test", false).typeName();
settings->setValue("test", true);
qDebug() << "now test setting is of type " << settings->value("test", false).typeName();

 

On the first run it will print

 

test setting is of type bool

now test setting is of type bool

 

After that it will print

 

test setting is of type QString

now test setting is of type bool

 

On the first run there is no stored setting, so it takes the passed default value, but after the setting has been set once, it seems like it is stored as a QString and loaded as a QString on the next app run.

 

This is messing a lot of things up especially when passing the QVariant to QML.

 

My ugly workaround right now is to do a 

 

settings->setValue('test', settings->value('test', false).toBool())

 

on launch for every bool setting that I have.

 

Anyone else seeing this?

 

 

 

Please use plain text.
Developer
Zmey
Posts: 1,512
Registered: ‎12-18-2012
My Device: PlayBook, Z10, DAC

Re: Bool changes to QString when QSettings load

[ Edited ]

This is expected behavior although not very intuitive. :smileyhappy:
QSettings doesn't store type information in ini files. Always request the specific type when accessing QSetting using .toBool(), toInt(), toString() etc.

I think it's more correct than using the workaround above as there's no guarantee on how QSettings stores the data internally.


Andrey Fidrya, @zmeyc on twitter
Please use plain text.
Developer
pfluger
Posts: 100
Registered: ‎02-10-2009
My Device: Q10, Z10
My Carrier: T-Mobile

Re: Bool changes to QString when QSettings load

Thanks Zmey. I wasn't aware that the settings are being stored in .ini files, but in this case it makes sense. I probably was secretly hoping QSettings are serialized like PersistentStore on BB7 ;-)

 

I am exposing the QSettings object as a context property to QML. In QML I do not have a way to request a specific type by using toBool etc. Or is there a way?

Please use plain text.
Developer
Zmey
Posts: 1,512
Registered: ‎12-18-2012
My Device: PlayBook, Z10, DAC

Re: Bool changes to QString when QSettings load

[ Edited ]

It depends on OS. It uses text files on Unix, registry on Windows, but can be switched to ini files and so on.

 

For QML I'd create a wrapper class with getters/setters:

Q_INVOKABLE bool soundEnabled();

Q_INVOKABLE void setSoundEnabled(bool enabled);

etc

 

Instantiate QSettings as a member variable. Call sync() in setters to write changes to disk:

 

int Settings::numericPrecision()
{
        QVariant v = settings_.value(numericPrecisionKey);
        if (v.isNull())
                return 8; // default value
        return v.toInt();
}

void Settings::setNumericPrecision(int precision)
{
        settings_.setValue(numericPrecisionKey, QVariant(precision));
        settings_.sync();
        emit numericFormatChanged();
}

Also it might be a good idea to make Settings class a singleton so every page which uses these settings can subscribe to changes.

 


Andrey Fidrya, @zmeyc on twitter
Please use plain text.
Developer
pfluger
Posts: 100
Registered: ‎02-10-2009
My Device: Q10, Z10
My Carrier: T-Mobile

Re: Bool changes to QString when QSettings load

Thanks again Zmey.

 

I was trying to avoid using accessor methods for every single setting. What I have done now is to use a subclassed version of QSettings that introduces a boolValue, intValue etc. that I can use from QML.

 

class Settings : public QSettings {
  Q_OBJECT
public:
  Settings(QObject *parent = 0);
  virtual ~Settings();

  Q_INVOKABLE
  void setValue(const QString &key, const QVariant &value);

  Q_INVOKABLE
  void setValueIfNotSet(const QString &key, const QVariant &value);

  Q_INVOKABLE
  QVariant value(const QString &key, const QVariant &defaultValue);

  Q_INVOKABLE
  bool boolValue(const QString &key, const bool defaultValue);

  Q_INVOKABLE
  void initToDefaults();

signals:
  void settingChanged(const QString& key);
};

 

Settings::Settings(QObject* parent) :
  QSettings(parent) {
}

Settings::~Settings() {
}

QVariant Settings::value(const QString &key, const QVariant &defaultValue = QVariant()) {
  return QSettings::value(key, defaultValue);
}

bool Settings::boolValue(const QString &key, bool defaultValue) {
  return QSettings::value(key, defaultValue).toBool();
}

void Settings::setValue(const QString &key, const QVariant &value) {

  // change the setting and emit a changed signal
  // (we are not checking if the value really changed before emitting for simplicity)
  QSettings::setValue(key, value);
  emit settingChanged(key);
}

void Settings::setValueIfNotSet(const QString &key, const QVariant &value) {

  // change the setting and emit a changed signal
  if( !QSettings::contains(key) ) {
    QSettings::setValue(key, value);
    // (we are not checking if the value really changed before emitting for simplicity)
    emit settingChanged(key);
  }
}

void Settings::initToDefaults() {
  setValueIfNotSet("test", true);
}

 

Please use plain text.