qa: Avoid deprecation warnings for QList/QSet conversions
[quassel.git] / src / common / settings.cpp
index 2d79ffe..1fbe04a 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   Copyright (C) 2005-2019 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#include <QStringList>
-
 #include "settings.h"
 
-const int VERSION = 1;              /// Settings version for backwords/forwards incompatible changes
+#include <QStringList>
+
+const int VERSION = 1;  /// Settings version for backwords/forwards incompatible changes
 
 // This is used if no VersionMinor key exists, e.g. upgrading from a Quassel version before this
 // change.  This shouldn't be increased from 1; instead, change the logic in Core::Core() and
 // QtUiApplication::init() to handle upgrading and downgrading.
-const int VERSION_MINOR_INITIAL = 1; /// Initial settings version for compatible changes
+const int VERSION_MINOR_INITIAL = 1;  /// Initial settings version for compatible changes
 
-QHash<QString, QVariant> Settings::settingsCache;
-QHash<QString, SettingsChangeNotifier *> Settings::settingsChangeNotifier;
+QHash<QString, QVariant> Settings::_settingsCache;
+QHash<QString, bool> Settings::_settingsKeyPersistedCache;
+QHash<QString, std::shared_ptr<SettingsChangeNotifier>> Settings::_settingsChangeNotifier;
 
 #ifdef Q_OS_MAC
-#  define create_qsettings QSettings s(QCoreApplication::organizationDomain(), appName)
+#    define create_qsettings QSettings s(QCoreApplication::organizationDomain(), _appName)
 #else
-#  define create_qsettings QSettings s(fileName(), format())
+#    define create_qsettings QSettings s(fileName(), format())
 #endif
 
-// Settings::Settings(QString group_, QString appName_)
-//   : group(group_),
-//     appName(appName_)
-// {
+Settings::Settings(QString group, QString appName)
+    : _group(std::move(group))
+    , _appName(std::move(appName))
+{}
 
-// /* we need to call the constructor immediately in order to set the path...
-// #ifndef Q_WS_QWS
-//   QSettings(QCoreApplication::organizationName(), applicationName);
-// #else
-//   // FIXME sandboxDir() is not currently working correctly...
-//   //if(Qtopia::sandboxDir().isEmpty()) QSettings();
-//   //else QSettings(Qtopia::sandboxDir() + "/etc/QuasselIRC.conf", QSettings::NativeFormat);
-//   // ...so we have to use a workaround:
-//   QString appPath = QCoreApplication::applicationFilePath();
-//   if(appPath.startsWith(Qtopia::packagePath())) {
-//     QString sandboxPath = appPath.left(Qtopia::packagePath().length() + 32);
-//     QSettings(sandboxPath + "/etc/QuasselIRC.conf", QSettings::IniFormat);
-//     qDebug() << sandboxPath + "/etc/QuasselIRC.conf";
-//   } else {
-//     QSettings(QCoreApplication::organizationName(), applicationName);
-//   }
-// #endif
-// */
-// }
-
-void Settings::notify(const QString &key, QObject *receiver, const char *slot)
+void Settings::setGroup(QString group)
 {
-    QObject::connect(notifier(normalizedKey(group, key)), SIGNAL(valueChanged(const QVariant &)),
-        receiver, slot);
+    _group = std::move(group);
 }
 
-
-void Settings::initAndNotify(const QString &key, QObject *receiver, const char *slot, const QVariant &defaultValue)
+QString Settings::keyForNotify(const QString& key) const
 {
-    notify(key, receiver, slot);
-    emit notifier(normalizedKey(group, key))->valueChanged(localValue(key, defaultValue));
+    return key;
 }
 
-
-uint Settings::version()
+uint Settings::version() const
 {
     // we don't cache this value, and we ignore the group
     create_qsettings;
@@ -90,8 +67,7 @@ uint Settings::version()
     return ver;
 }
 
-
-uint Settings::versionMinor()
+uint Settings::versionMinor() const
 {
     // Don't cache this value; ignore the group
     create_qsettings;
@@ -104,14 +80,15 @@ uint Settings::versionMinor()
     // than Config/Version exist.  If so, assume it's version 1.
     if (verMinor == 0 && s.allKeys().count() > 1) {
         // More than 1 key exists, but version's never been set.  Assume and set version 1.
-        setVersionMinor(VERSION_MINOR_INITIAL);
+        // const_cast is ok, because setVersionMinor() doesn't actually change this instance
+        const_cast<Settings*>(this)->setVersionMinor(VERSION_MINOR_INITIAL);
         return VERSION_MINOR_INITIAL;
-    } else {
+    }
+    else {
         return verMinor;
     }
 }
 
-
 void Settings::setVersionMinor(const uint versionMinor)
 {
     // Don't cache this value; ignore the group
@@ -120,42 +97,49 @@ void Settings::setVersionMinor(const uint versionMinor)
     s.setValue("Config/VersionMinor", versionMinor);
 }
 
+QSettings::Format Settings::format() const
+{
+#ifdef Q_OS_WIN
+    return QSettings::IniFormat;
+#else
+    return QSettings::NativeFormat;
+#endif
+}
 
-bool Settings::sync() {
+bool Settings::sync()
+{
     create_qsettings;
     s.sync();
     switch (s.status()) {
-        case QSettings::NoError:
-            return true;
-        default:
-            return false;
+    case QSettings::NoError:
+        return true;
+    default:
+        return false;
     }
 }
 
-
-bool Settings::isWritable() {
+bool Settings::isWritable() const
+{
     create_qsettings;
     return s.isWritable();
 }
 
-
-QStringList Settings::allLocalKeys()
+QStringList Settings::allLocalKeys() const
 {
     create_qsettings;
-    s.beginGroup(group);
+    s.beginGroup(_group);
     QStringList res = s.allKeys();
     s.endGroup();
     return res;
 }
 
-
-QStringList Settings::localChildKeys(const QString &rootkey)
+QStringList Settings::localChildKeys(const QString& rootkey) const
 {
     QString g;
     if (rootkey.isEmpty())
-        g = group;
+        g = _group;
     else
-        g = QString("%1/%2").arg(group, rootkey);
+        g = QString("%1/%2").arg(_group, rootkey);
 
     create_qsettings;
     s.beginGroup(g);
@@ -164,14 +148,13 @@ QStringList Settings::localChildKeys(const QString &rootkey)
     return res;
 }
 
-
-QStringList Settings::localChildGroups(const QString &rootkey)
+QStringList Settings::localChildGroups(const QString& rootkey) const
 {
     QString g;
     if (rootkey.isEmpty())
-        g = group;
+        g = _group;
     else
-        g = QString("%1/%2").arg(group, rootkey);
+        g = QString("%1/%2").arg(_group, rootkey);
 
     create_qsettings;
     s.beginGroup(g);
@@ -180,52 +163,117 @@ QStringList Settings::localChildGroups(const QString &rootkey)
     return res;
 }
 
-
-void Settings::setLocalValue(const QString &key, const QVariant &data)
+void Settings::setLocalValue(const QString& key, const QVariant& data)
 {
-    QString normKey = normalizedKey(group, key);
+    QString normKey = normalizedKey(_group, key);
     create_qsettings;
     s.setValue(normKey, data);
+    setCacheKeyPersisted(normKey, true);
     setCacheValue(normKey, data);
     if (hasNotifier(normKey)) {
         emit notifier(normKey)->valueChanged(data);
     }
 }
 
-
-const QVariant &Settings::localValue(const QString &key, const QVariant &def)
+QVariant Settings::localValue(const QString& key, const QVariant& def) const
 {
-    QString normKey = normalizedKey(group, key);
+    QString normKey = normalizedKey(_group, key);
     if (!isCached(normKey)) {
         create_qsettings;
+        // Since we're loading from settings anyways, cache whether or not the key exists on disk
+        setCacheKeyPersisted(normKey, s.contains(normKey));
+        // Cache key value
         setCacheValue(normKey, s.value(normKey, def));
     }
-    return cacheValue(normKey);
+    if (cacheKeyPersisted(normKey)) {
+        return cacheValue(normKey);
+    }
+    // Don't return possibly wrong cached values
+    // A key gets cached with the first default value requested and never changes afterwards
+    return def;
 }
 
-
-bool Settings::localKeyExists(const QString &key)
+bool Settings::localKeyExists(const QString& key) const
 {
-    QString normKey = normalizedKey(group, key);
-    if (isCached(normKey))
-        return true;
+    QString normKey = normalizedKey(_group, key);
+    if (!isKeyPersistedCached(normKey)) {
+        create_qsettings;
+        // Cache whether or not key exists on disk
+        // We can't cache key value as we don't know the default
+        setCacheKeyPersisted(normKey, s.contains(normKey));
+    }
 
-    create_qsettings;
-    return s.contains(normKey);
+    return cacheKeyPersisted(normKey);
 }
 
-
-void Settings::removeLocalKey(const QString &key)
+void Settings::removeLocalKey(const QString& key)
 {
     create_qsettings;
-    s.beginGroup(group);
+    s.beginGroup(_group);
     s.remove(key);
     s.endGroup();
-    QString normKey = normalizedKey(group, key);
+    QString normKey = normalizedKey(_group, key);
     if (isCached(normKey)) {
-        settingsCache.remove(normKey);
+        _settingsCache.remove(normKey);
+    }
+    if (isKeyPersistedCached(normKey)) {
+        _settingsKeyPersistedCache.remove(normKey);
     }
     if (hasNotifier(normKey)) {
         emit notifier(normKey)->valueChanged({});
     }
 }
+
+QString Settings::fileName() const
+{
+    return Quassel::configDirPath() + _appName + ((format() == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini"));
+}
+
+QString Settings::normalizedKey(const QString& group, const QString& key) const
+{
+    if (group.isEmpty())
+        return key;
+    return group + '/' + key;
+}
+
+void Settings::setCacheKeyPersisted(const QString& normKey, bool exists) const
+{
+    _settingsKeyPersistedCache[normKey] = exists;
+}
+
+bool Settings::cacheKeyPersisted(const QString& normKey) const
+{
+    return _settingsKeyPersistedCache[normKey];
+}
+
+bool Settings::isKeyPersistedCached(const QString& normKey) const
+{
+    return _settingsKeyPersistedCache.contains(normKey);
+}
+
+void Settings::setCacheValue(const QString& normKey, const QVariant& data) const
+{
+    _settingsCache[normKey] = data;
+}
+
+QVariant Settings::cacheValue(const QString& normKey) const
+{
+    return _settingsCache[normKey];
+}
+
+bool Settings::isCached(const QString& normKey) const
+{
+    return _settingsCache.contains(normKey);
+}
+
+SettingsChangeNotifier* Settings::notifier(const QString& normKey) const
+{
+    if (!hasNotifier(normKey))
+        _settingsChangeNotifier[normKey] = std::make_shared<SettingsChangeNotifier>();
+    return _settingsChangeNotifier[normKey].get();
+}
+
+bool Settings::hasNotifier(const QString& normKey) const
+{
+    return _settingsChangeNotifier.contains(normKey);
+}