src/3rdparty/libgq/gconf/gconfitem.cpp
changeset 37 758a864f9613
equal deleted inserted replaced
36:ef0373b55136 37:758a864f9613
       
     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 }