File indexing completed on 2024-12-08 10:59:34
0001 /* 0002 * SPDX-FileCopyrightText: 2009 Nokia Corporation and/or its subsidiary(-ies). 0003 * SPDX-FileCopyrightText: 2016 David Edmundson <davidedmundson@kde.org> 0004 * SPDX-FileContributor: Marius Vollmer <marius.vollmer@nokia.com> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.1-only 0007 */ 0008 0009 #include <QByteArray> 0010 #include <QDebug> 0011 #include <QString> 0012 #include <QVariant> 0013 0014 #include "gconfitem.h" 0015 0016 #include <gconf/gconf-client.h> 0017 #include <gconf/gconf-value.h> 0018 #include <glib.h> 0019 0020 struct GConfItemPrivate { 0021 QString root; 0022 QVariant value; 0023 guint notify_id; 0024 0025 static void notify_trampoline(GConfClient *, guint, GConfEntry *, gpointer); 0026 }; 0027 0028 #define withClient(c) for (GConfClient *c = (gconf_client_get_default()); c; g_object_unref(c), c = NULL) 0029 0030 static QByteArray convertKey(QString key) 0031 { 0032 if (key.startsWith('/')) { 0033 return key.toUtf8(); 0034 } else { 0035 qWarning() << "Using dot-separated key names with GConfItem is deprecated."; 0036 qWarning() << "Please use" << '/' + key.replace('.', '/') << "instead of" << key; 0037 return '/' + key.replace('.', '/').toUtf8(); 0038 } 0039 } 0040 0041 static QString convertKey(const char *key) 0042 { 0043 return QString::fromUtf8(key); 0044 } 0045 0046 static QVariant convertValue(GConfValue *src) 0047 { 0048 if (!src) { 0049 return QVariant(); 0050 } else { 0051 switch (src->type) { 0052 case GCONF_VALUE_INVALID: 0053 return QVariant(QVariant::Invalid); 0054 case GCONF_VALUE_BOOL: 0055 return QVariant((bool)gconf_value_get_bool(src)); 0056 case GCONF_VALUE_INT: 0057 return QVariant(gconf_value_get_int(src)); 0058 case GCONF_VALUE_FLOAT: 0059 return QVariant(gconf_value_get_float(src)); 0060 case GCONF_VALUE_STRING: 0061 return QVariant(QString::fromUtf8(gconf_value_get_string(src))); 0062 case GCONF_VALUE_LIST: 0063 switch (gconf_value_get_list_type(src)) { 0064 case GCONF_VALUE_STRING: { 0065 QStringList result; 0066 for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) 0067 result.append(QString::fromUtf8(gconf_value_get_string((GConfValue *)elts->data))); 0068 return QVariant(result); 0069 } 0070 default: { 0071 QList<QVariant> result; 0072 for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next) 0073 result.append(convertValue((GConfValue *)elts->data)); 0074 return QVariant(result); 0075 } 0076 } 0077 case GCONF_VALUE_SCHEMA: 0078 default: 0079 return QVariant(); 0080 } 0081 } 0082 } 0083 0084 static GConfValue *convertString(const QString &str) 0085 { 0086 GConfValue *v = gconf_value_new(GCONF_VALUE_STRING); 0087 gconf_value_set_string(v, str.toUtf8().data()); 0088 return v; 0089 } 0090 0091 static GConfValueType primitiveType(const QVariant &elt) 0092 { 0093 switch (elt.type()) { 0094 case QVariant::String: 0095 return GCONF_VALUE_STRING; 0096 case QVariant::Int: 0097 return GCONF_VALUE_INT; 0098 case QVariant::Double: 0099 return GCONF_VALUE_FLOAT; 0100 case QVariant::Bool: 0101 return GCONF_VALUE_BOOL; 0102 default: 0103 return GCONF_VALUE_INVALID; 0104 } 0105 } 0106 0107 static GConfValueType uniformType(const QList<QVariant> &list) 0108 { 0109 GConfValueType result = GCONF_VALUE_INVALID; 0110 0111 Q_FOREACH (const QVariant &elt, list) { 0112 GConfValueType elt_type = primitiveType(elt); 0113 0114 if (elt_type == GCONF_VALUE_INVALID) 0115 return GCONF_VALUE_INVALID; 0116 0117 if (result == GCONF_VALUE_INVALID) 0118 result = elt_type; 0119 else if (result != elt_type) 0120 return GCONF_VALUE_INVALID; 0121 } 0122 0123 if (result == GCONF_VALUE_INVALID) 0124 return GCONF_VALUE_STRING; // empty list. 0125 else 0126 return result; 0127 } 0128 0129 static int convertValue(const QVariant &src, GConfValue **valp) 0130 { 0131 GConfValue *v; 0132 0133 switch (src.type()) { 0134 case QVariant::Invalid: 0135 v = nullptr; 0136 break; 0137 case QVariant::Bool: 0138 v = gconf_value_new(GCONF_VALUE_BOOL); 0139 gconf_value_set_bool(v, src.toBool()); 0140 break; 0141 case QVariant::Int: 0142 v = gconf_value_new(GCONF_VALUE_INT); 0143 gconf_value_set_int(v, src.toInt()); 0144 break; 0145 case QVariant::Double: 0146 v = gconf_value_new(GCONF_VALUE_FLOAT); 0147 gconf_value_set_float(v, src.toDouble()); 0148 break; 0149 case QVariant::String: 0150 v = convertString(src.toString()); 0151 break; 0152 case QVariant::StringList: { 0153 GSList *elts = nullptr; 0154 v = gconf_value_new(GCONF_VALUE_LIST); 0155 gconf_value_set_list_type(v, GCONF_VALUE_STRING); 0156 Q_FOREACH (const QString &str, src.toStringList()) 0157 elts = g_slist_prepend(elts, convertString(str)); 0158 gconf_value_set_list_nocopy(v, g_slist_reverse(elts)); 0159 break; 0160 } 0161 case QVariant::List: { 0162 GConfValueType elt_type = uniformType(src.toList()); 0163 if (elt_type == GCONF_VALUE_INVALID) 0164 v = nullptr; 0165 else { 0166 GSList *elts = nullptr; 0167 v = gconf_value_new(GCONF_VALUE_LIST); 0168 gconf_value_set_list_type(v, elt_type); 0169 Q_FOREACH (const QVariant &elt, src.toList()) { 0170 GConfValue *val = nullptr; 0171 convertValue(elt, &val); // guaranteed to succeed. 0172 elts = g_slist_prepend(elts, val); 0173 } 0174 gconf_value_set_list_nocopy(v, g_slist_reverse(elts)); 0175 } 0176 break; 0177 } 0178 default: 0179 return 0; 0180 } 0181 0182 *valp = v; 0183 return 1; 0184 } 0185 0186 void GConfItemPrivate::notify_trampoline(GConfClient *, guint, GConfEntry *entry, gpointer data) 0187 { 0188 GConfItem *item = (GConfItem *)data; 0189 0190 item->update_value(true, entry->key, convertValue(entry->value)); 0191 } 0192 0193 void GConfItem::update_value(bool emit_signal, const QString &key, const QVariant &value) 0194 { 0195 QVariant new_value; 0196 0197 if (emit_signal) { 0198 subtreeChanged(key, value); 0199 } 0200 } 0201 0202 QString GConfItem::root() const 0203 { 0204 return priv->root; 0205 } 0206 0207 QVariant GConfItem::value(const QString &subKey) const 0208 { 0209 QVariant new_value; 0210 withClient(client) 0211 { 0212 GError *error = nullptr; 0213 QByteArray k = convertKey(priv->root + '/' + subKey); 0214 GConfValue *v = gconf_client_get(client, k.data(), &error); 0215 0216 if (error) { 0217 qWarning() << error->message; 0218 g_error_free(error); 0219 new_value = QVariant(); 0220 } else { 0221 new_value = convertValue(v); 0222 if (v) 0223 gconf_value_free(v); 0224 } 0225 } 0226 return new_value; 0227 } 0228 0229 void GConfItem::set(const QString &subKey, const QVariant &val) 0230 { 0231 withClient(client) 0232 { 0233 QByteArray k = convertKey(priv->root + '/' + subKey); 0234 GConfValue *v; 0235 if (convertValue(val, &v)) { 0236 GError *error = nullptr; 0237 0238 if (v) { 0239 gconf_client_set(client, k.data(), v, &error); 0240 gconf_value_free(v); 0241 } else { 0242 gconf_client_unset(client, k.data(), &error); 0243 } 0244 0245 if (error) { 0246 qWarning() << error->message; 0247 g_error_free(error); 0248 } 0249 } else { 0250 qWarning() << "Can't store a" << val.typeName(); 0251 } 0252 } 0253 } 0254 0255 QList<QString> GConfItem::listDirs() const 0256 { 0257 QList<QString> children; 0258 0259 withClient(client) 0260 { 0261 QByteArray k = convertKey(priv->root); 0262 GSList *dirs = gconf_client_all_dirs(client, k.data(), nullptr); 0263 for (GSList *d = dirs; d; d = d->next) { 0264 children.append(convertKey((char *)d->data)); 0265 g_free(d->data); 0266 } 0267 g_slist_free(dirs); 0268 } 0269 0270 return children; 0271 } 0272 0273 QList<QString> GConfItem::listEntries() const 0274 { 0275 QList<QString> children; 0276 0277 withClient(client) 0278 { 0279 QByteArray k = convertKey(priv->root); 0280 GSList *entries = gconf_client_all_entries(client, k.data(), nullptr); 0281 for (GSList *e = entries; e; e = e->next) { 0282 children.append(convertKey(((GConfEntry *)e->data)->key)); 0283 gconf_entry_free((GConfEntry *)e->data); 0284 } 0285 g_slist_free(entries); 0286 } 0287 0288 return children; 0289 } 0290 0291 GConfItem::GConfItem(const QString &key, QObject *parent) 0292 : QObject(parent) 0293 , priv(new GConfItemPrivate) 0294 { 0295 priv->root = key; 0296 withClient(client) 0297 { 0298 QByteArray k = convertKey(priv->root); 0299 gconf_client_add_dir(client, k.data(), GCONF_CLIENT_PRELOAD_ONELEVEL, nullptr); 0300 priv->notify_id = gconf_client_notify_add(client, k.data(), GConfItemPrivate::notify_trampoline, this, nullptr, nullptr); 0301 } 0302 } 0303 0304 GConfItem::~GConfItem() 0305 { 0306 withClient(client) 0307 { 0308 QByteArray k = convertKey(priv->root); 0309 gconf_client_notify_remove(client, priv->notify_id); 0310 gconf_client_remove_dir(client, k.data(), nullptr); 0311 } 0312 delete priv; 0313 }