1 | /* * This file is part of libgq *
|
---|
2 | *
|
---|
3 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | * All rights reserved.
|
---|
5 | *
|
---|
6 | * Contact: Marius Vollmer <marius.vollmer@nokia.com>
|
---|
7 | *
|
---|
8 | * This library is free software; you can redistribute it and/or
|
---|
9 | * modify it under the terms of the GNU Lesser General Public License
|
---|
10 | * version 2.1 as published by the Free Software Foundation.
|
---|
11 | *
|
---|
12 | * This library is distributed in the hope that it will be useful, but
|
---|
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
15 | * Lesser General Public License for more details.
|
---|
16 | *
|
---|
17 | * You should have received a copy of the GNU Lesser General Public
|
---|
18 | * License along with this library; if not, write to the Free Software
|
---|
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
---|
20 | * 02110-1301 USA
|
---|
21 | *
|
---|
22 | */
|
---|
23 |
|
---|
24 | #include <QString>
|
---|
25 | #include <QStringList>
|
---|
26 | #include <QByteArray>
|
---|
27 | #include <QVariant>
|
---|
28 | #include <QtDebug>
|
---|
29 |
|
---|
30 | #include "gconfitem.h"
|
---|
31 |
|
---|
32 | #include <glib.h>
|
---|
33 | #include <gconf/gconf-value.h>
|
---|
34 | #include <gconf/gconf-client.h>
|
---|
35 |
|
---|
36 | struct GConfItemPrivate {
|
---|
37 | QString key;
|
---|
38 | QVariant value;
|
---|
39 | guint notify_id;
|
---|
40 |
|
---|
41 | static void notify_trampoline(GConfClient*, guint, GConfEntry *, gpointer);
|
---|
42 | };
|
---|
43 |
|
---|
44 | /* We get the default client and never release it, on purpose, to
|
---|
45 | avoid disconnecting from the GConf daemon when a program happens to
|
---|
46 | not have any GConfItems for short periods of time.
|
---|
47 | */
|
---|
48 | static GConfClient *
|
---|
49 | get_gconf_client ()
|
---|
50 | {
|
---|
51 | static bool initialized = false;
|
---|
52 | static GConfClient *client;
|
---|
53 |
|
---|
54 | if (initialized)
|
---|
55 | return client;
|
---|
56 |
|
---|
57 | g_type_init ();
|
---|
58 | client = gconf_client_get_default();
|
---|
59 | initialized = true;
|
---|
60 |
|
---|
61 | return client;
|
---|
62 | }
|
---|
63 |
|
---|
64 | /* Sometimes I like being too clever...
|
---|
65 | */
|
---|
66 | #define withClient(c) for (GConfClient *c = get_gconf_client (); c; c = NULL)
|
---|
67 |
|
---|
68 | static QByteArray convertKey (QString key)
|
---|
69 | {
|
---|
70 | if (key.startsWith('/'))
|
---|
71 | return key.toUtf8();
|
---|
72 | else
|
---|
73 | {
|
---|
74 | qWarning() << "Using dot-separated key names with GConfItem is deprecated.";
|
---|
75 | qWarning() << "Please use" << '/' + key.replace('.', '/') << "instead of" << key;
|
---|
76 | return '/' + key.replace('.', '/').toUtf8();
|
---|
77 | }
|
---|
78 | }
|
---|
79 |
|
---|
80 | static QString convertKey(const char *key)
|
---|
81 | {
|
---|
82 | return QString::fromUtf8(key);
|
---|
83 | }
|
---|
84 |
|
---|
85 | static QVariant convertValue(GConfValue *src)
|
---|
86 | {
|
---|
87 | if (!src) {
|
---|
88 | return QVariant();
|
---|
89 | } else {
|
---|
90 | switch (src->type) {
|
---|
91 | case GCONF_VALUE_INVALID:
|
---|
92 | return QVariant(QVariant::Invalid);
|
---|
93 | case GCONF_VALUE_BOOL:
|
---|
94 | return QVariant((bool)gconf_value_get_bool(src));
|
---|
95 | case GCONF_VALUE_INT:
|
---|
96 | return QVariant(gconf_value_get_int(src));
|
---|
97 | case GCONF_VALUE_FLOAT:
|
---|
98 | return QVariant(gconf_value_get_float(src));
|
---|
99 | case GCONF_VALUE_STRING:
|
---|
100 | return QVariant(QString::fromUtf8(gconf_value_get_string(src)));
|
---|
101 | case GCONF_VALUE_LIST:
|
---|
102 | switch (gconf_value_get_list_type(src)) {
|
---|
103 | case GCONF_VALUE_STRING:
|
---|
104 | {
|
---|
105 | QStringList result;
|
---|
106 | for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next)
|
---|
107 | result.append(QString::fromUtf8(gconf_value_get_string((GConfValue *)elts->data)));
|
---|
108 | return QVariant(result);
|
---|
109 | }
|
---|
110 | default:
|
---|
111 | {
|
---|
112 | QList<QVariant> result;
|
---|
113 | for (GSList *elts = gconf_value_get_list(src); elts; elts = elts->next)
|
---|
114 | result.append(convertValue((GConfValue *)elts->data));
|
---|
115 | return QVariant(result);
|
---|
116 | }
|
---|
117 | }
|
---|
118 | case GCONF_VALUE_SCHEMA:
|
---|
119 | default:
|
---|
120 | return QVariant();
|
---|
121 | }
|
---|
122 | }
|
---|
123 | }
|
---|
124 |
|
---|
125 | static GConfValue *convertString(const QString &str)
|
---|
126 | {
|
---|
127 | GConfValue *v = gconf_value_new (GCONF_VALUE_STRING);
|
---|
128 | gconf_value_set_string (v, str.toUtf8().data());
|
---|
129 | return v;
|
---|
130 | }
|
---|
131 |
|
---|
132 | static GConfValueType primitiveType (const QVariant &elt)
|
---|
133 | {
|
---|
134 | switch(elt.type()) {
|
---|
135 | case QVariant::String:
|
---|
136 | return GCONF_VALUE_STRING;
|
---|
137 | case QVariant::Int:
|
---|
138 | return GCONF_VALUE_INT;
|
---|
139 | case QVariant::Double:
|
---|
140 | return GCONF_VALUE_FLOAT;
|
---|
141 | case QVariant::Bool:
|
---|
142 | return GCONF_VALUE_BOOL;
|
---|
143 | default:
|
---|
144 | return GCONF_VALUE_INVALID;
|
---|
145 | }
|
---|
146 | }
|
---|
147 |
|
---|
148 | static GConfValueType uniformType(const QList<QVariant> &list)
|
---|
149 | {
|
---|
150 | GConfValueType result = GCONF_VALUE_INVALID;
|
---|
151 |
|
---|
152 | foreach (const QVariant &elt, list) {
|
---|
153 | GConfValueType elt_type = primitiveType (elt);
|
---|
154 |
|
---|
155 | if (elt_type == GCONF_VALUE_INVALID)
|
---|
156 | return GCONF_VALUE_INVALID;
|
---|
157 |
|
---|
158 | if (result == GCONF_VALUE_INVALID)
|
---|
159 | result = elt_type;
|
---|
160 | else if (result != elt_type)
|
---|
161 | return GCONF_VALUE_INVALID;
|
---|
162 | }
|
---|
163 |
|
---|
164 | if (result == GCONF_VALUE_INVALID)
|
---|
165 | return GCONF_VALUE_STRING; // empty list.
|
---|
166 | else
|
---|
167 | return result;
|
---|
168 | }
|
---|
169 |
|
---|
170 | static int convertValue(const QVariant &src, GConfValue **valp)
|
---|
171 | {
|
---|
172 | GConfValue *v;
|
---|
173 |
|
---|
174 | switch(src.type()) {
|
---|
175 | case QVariant::Invalid:
|
---|
176 | v = NULL;
|
---|
177 | break;
|
---|
178 | case QVariant::Bool:
|
---|
179 | v = gconf_value_new (GCONF_VALUE_BOOL);
|
---|
180 | gconf_value_set_bool (v, src.toBool());
|
---|
181 | break;
|
---|
182 | case QVariant::Int:
|
---|
183 | v = gconf_value_new (GCONF_VALUE_INT);
|
---|
184 | gconf_value_set_int (v, src.toInt());
|
---|
185 | break;
|
---|
186 | case QVariant::Double:
|
---|
187 | v = gconf_value_new (GCONF_VALUE_FLOAT);
|
---|
188 | gconf_value_set_float (v, src.toDouble());
|
---|
189 | break;
|
---|
190 | case QVariant::String:
|
---|
191 | v = convertString(src.toString());
|
---|
192 | break;
|
---|
193 | case QVariant::StringList:
|
---|
194 | {
|
---|
195 | GSList *elts = NULL;
|
---|
196 | v = gconf_value_new(GCONF_VALUE_LIST);
|
---|
197 | gconf_value_set_list_type(v, GCONF_VALUE_STRING);
|
---|
198 | foreach (const QString &str, src.toStringList())
|
---|
199 | elts = g_slist_prepend(elts, convertString(str));
|
---|
200 | gconf_value_set_list_nocopy(v, g_slist_reverse(elts));
|
---|
201 | break;
|
---|
202 | }
|
---|
203 | case QVariant::List:
|
---|
204 | {
|
---|
205 | GConfValueType elt_type = uniformType(src.toList());
|
---|
206 | if (elt_type == GCONF_VALUE_INVALID)
|
---|
207 | v = NULL;
|
---|
208 | else
|
---|
209 | {
|
---|
210 | GSList *elts = NULL;
|
---|
211 | v = gconf_value_new(GCONF_VALUE_LIST);
|
---|
212 | gconf_value_set_list_type(v, elt_type);
|
---|
213 | foreach (const QVariant &elt, src.toList())
|
---|
214 | {
|
---|
215 | GConfValue *val = NULL;
|
---|
216 | convertValue(elt, &val); // guaranteed to succeed.
|
---|
217 | elts = g_slist_prepend(elts, val);
|
---|
218 | }
|
---|
219 | gconf_value_set_list_nocopy(v, g_slist_reverse(elts));
|
---|
220 | }
|
---|
221 | break;
|
---|
222 | }
|
---|
223 | default:
|
---|
224 | return 0;
|
---|
225 | }
|
---|
226 |
|
---|
227 | *valp = v;
|
---|
228 | return 1;
|
---|
229 | }
|
---|
230 |
|
---|
231 | void GConfItemPrivate::notify_trampoline (GConfClient*,
|
---|
232 | guint,
|
---|
233 | GConfEntry *,
|
---|
234 | gpointer data)
|
---|
235 | {
|
---|
236 | GConfItem *item = (GConfItem *)data;
|
---|
237 | item->update_value (true);
|
---|
238 | }
|
---|
239 |
|
---|
240 | void GConfItem::update_value (bool emit_signal)
|
---|
241 | {
|
---|
242 | QVariant new_value;
|
---|
243 |
|
---|
244 | withClient(client) {
|
---|
245 | GError *error = NULL;
|
---|
246 | QByteArray k = convertKey(priv->key);
|
---|
247 | GConfValue *v = gconf_client_get(client, k.data(), &error);
|
---|
248 |
|
---|
249 | if (error) {
|
---|
250 | qWarning() << error->message;
|
---|
251 | g_error_free (error);
|
---|
252 | new_value = priv->value;
|
---|
253 | } else {
|
---|
254 | new_value = convertValue(v);
|
---|
255 | if (v)
|
---|
256 | gconf_value_free(v);
|
---|
257 | }
|
---|
258 | }
|
---|
259 |
|
---|
260 | if (new_value != priv->value) {
|
---|
261 | priv->value = new_value;
|
---|
262 | if (emit_signal)
|
---|
263 | emit valueChanged();
|
---|
264 | }
|
---|
265 | }
|
---|
266 |
|
---|
267 | QString GConfItem::key() const
|
---|
268 | {
|
---|
269 | return priv->key;
|
---|
270 | }
|
---|
271 |
|
---|
272 | QVariant GConfItem::value() const
|
---|
273 | {
|
---|
274 | return priv->value;
|
---|
275 | }
|
---|
276 |
|
---|
277 | QVariant GConfItem::value(const QVariant &def) const
|
---|
278 | {
|
---|
279 | if (priv->value.isNull())
|
---|
280 | return def;
|
---|
281 | else
|
---|
282 | return priv->value;
|
---|
283 | }
|
---|
284 |
|
---|
285 | void GConfItem::set(const QVariant &val)
|
---|
286 | {
|
---|
287 | withClient(client) {
|
---|
288 | QByteArray k = convertKey(priv->key);
|
---|
289 | GConfValue *v;
|
---|
290 | if (convertValue(val, &v)) {
|
---|
291 | GError *error = NULL;
|
---|
292 |
|
---|
293 | if (v) {
|
---|
294 | gconf_client_set(client, k.data(), v, &error);
|
---|
295 | gconf_value_free(v);
|
---|
296 | } else {
|
---|
297 | gconf_client_unset(client, k.data(), &error);
|
---|
298 | }
|
---|
299 |
|
---|
300 | if (error) {
|
---|
301 | qWarning() << error->message;
|
---|
302 | g_error_free(error);
|
---|
303 | } else if (priv->value != val) {
|
---|
304 | priv->value = val;
|
---|
305 | emit valueChanged();
|
---|
306 | }
|
---|
307 |
|
---|
308 | } else
|
---|
309 | qWarning() << "Can't store a" << val.typeName();
|
---|
310 | }
|
---|
311 | }
|
---|
312 |
|
---|
313 | void GConfItem::unset() {
|
---|
314 | set(QVariant());
|
---|
315 | }
|
---|
316 |
|
---|
317 | QList<QString> GConfItem::listDirs() const
|
---|
318 | {
|
---|
319 | QList<QString> children;
|
---|
320 |
|
---|
321 | withClient(client) {
|
---|
322 | QByteArray k = convertKey(priv->key);
|
---|
323 | GSList *dirs = gconf_client_all_dirs(client, k.data(), NULL);
|
---|
324 | for (GSList *d = dirs; d; d = d->next) {
|
---|
325 | children.append(convertKey((char *)d->data));
|
---|
326 | g_free (d->data);
|
---|
327 | }
|
---|
328 | g_slist_free (dirs);
|
---|
329 | }
|
---|
330 |
|
---|
331 | return children;
|
---|
332 | }
|
---|
333 |
|
---|
334 | QList<QString> GConfItem::listEntries() const
|
---|
335 | {
|
---|
336 | QList<QString> children;
|
---|
337 |
|
---|
338 | withClient(client) {
|
---|
339 | QByteArray k = convertKey(priv->key);
|
---|
340 | GSList *entries = gconf_client_all_entries(client, k.data(), NULL);
|
---|
341 | for (GSList *e = entries; e; e = e->next) {
|
---|
342 | children.append(convertKey(((GConfEntry *)e->data)->key));
|
---|
343 | gconf_entry_free ((GConfEntry *)e->data);
|
---|
344 | }
|
---|
345 | g_slist_free (entries);
|
---|
346 | }
|
---|
347 |
|
---|
348 | return children;
|
---|
349 | }
|
---|
350 |
|
---|
351 | GConfItem::GConfItem(const QString &key, QObject *parent)
|
---|
352 | : QObject (parent)
|
---|
353 | {
|
---|
354 | priv = new GConfItemPrivate;
|
---|
355 | priv->key = key;
|
---|
356 | priv->notify_id = 0;
|
---|
357 | withClient(client) {
|
---|
358 | update_value (false);
|
---|
359 | QByteArray k = convertKey(priv->key);
|
---|
360 | gconf_client_add_dir (client, k.data(), GCONF_CLIENT_PRELOAD_ONELEVEL, NULL);
|
---|
361 | priv->notify_id = gconf_client_notify_add (client, k.data(),
|
---|
362 | GConfItemPrivate::notify_trampoline, this,
|
---|
363 | NULL, NULL);
|
---|
364 | }
|
---|
365 | }
|
---|
366 |
|
---|
367 | GConfItem::~GConfItem()
|
---|
368 | {
|
---|
369 | withClient(client) {
|
---|
370 | QByteArray k = convertKey(priv->key);
|
---|
371 | if (priv->notify_id)
|
---|
372 | gconf_client_notify_remove (client, priv->notify_id);
|
---|
373 | gconf_client_remove_dir (client, k.data(), NULL);
|
---|
374 | }
|
---|
375 | delete priv;
|
---|
376 | }
|
---|