Skip to content

Commit

Permalink
Provide for easily moving GValues to and from KVP
Browse files Browse the repository at this point in the history
So that all interaction with KVP is easily handled with properties.
Includes convenience functions for simplifying set/get property
functions.
  • Loading branch information
jralls committed Nov 4, 2013
1 parent c2d93cb commit 4a4b180
Show file tree
Hide file tree
Showing 5 changed files with 505 additions and 12 deletions.
188 changes: 188 additions & 0 deletions src/libqof/qof/kvp_frame.c
Expand Up @@ -1645,4 +1645,192 @@ kvp_frame_get_hash(const KvpFrame *frame)
return frame->hash;
}

static GValue *gvalue_from_kvp_value (KvpValue*);
static KvpValue *kvp_value_from_gvalue (const GValue*);

static void
gvalue_list_from_kvp_value (KvpValue *kval, gpointer pList)
{
GList **gvlist = NULL;
GValue *gval = gvalue_from_kvp_value (kval);
gvlist = (GList**)pList;
if (G_VALUE_TYPE (gval))
*gvlist = g_list_prepend (*gvlist, gval);
}

static void
kvp_value_list_from_gvalue (GValue *gval, gpointer pList)
{
GList **kvplist = (GList**)pList;
KvpValue *kvp;
if (!(gval && G_VALUE_TYPE (gval)))
return;
kvp = kvp_value_from_gvalue (gval);
*kvplist = g_list_prepend (*kvplist, kvp);
}

static GValue*
gvalue_from_kvp_value (KvpValue *kval)
{
GValue *val;
gnc_numeric num;
Timespec tm;
GDate gdate;

if (kval == NULL) return NULL;
val = g_slice_new0 (GValue);

switch (kval->type)
{
case KVP_TYPE_GINT64:
g_value_init (val, G_TYPE_INT64);
g_value_set_int64 (val, kvp_value_get_gint64 (kval));
break;
case KVP_TYPE_DOUBLE:
g_value_init (val, G_TYPE_DOUBLE);
g_value_set_double (val, kvp_value_get_double (kval));
break;
case KVP_TYPE_NUMERIC:
g_value_init (val, GNC_TYPE_NUMERIC);
num = kvp_value_get_numeric (kval);
g_value_set_boxed (val, &num);
break;
case KVP_TYPE_STRING:
g_value_init (val, G_TYPE_STRING);
g_value_set_string (val, kvp_value_get_string (kval));
break;
case KVP_TYPE_GUID:
g_value_init (val, GNC_TYPE_GUID);
g_value_set_boxed (val, kvp_value_get_guid (kval));
break;
case KVP_TYPE_TIMESPEC:
g_value_init (val, GNC_TYPE_TIMESPEC);
tm = kvp_value_get_timespec (kval);
g_value_set_boxed (val, &tm);
break;
case KVP_TYPE_BINARY:
PWARN ("Error! Don't use Kvp Binary!");
g_slice_free (GValue, val);
val = NULL;
break;
case KVP_TYPE_GDATE:
g_value_init (val, G_TYPE_DATE);
gdate = kvp_value_get_gdate (kval);
g_value_set_boxed (val, &gdate);
break;
case KVP_TYPE_GLIST:
{
GList *gvalue_list = NULL;
GList *kvp_list = kvp_value_get_glist (kval);
g_list_foreach (kvp_list, (GFunc)gvalue_list_from_kvp_value, &gvalue_list);
g_value_init (val, GNC_TYPE_VALUE_LIST);
gvalue_list = g_list_reverse (gvalue_list);
g_value_set_boxed (val, gvalue_list);
break;
}
/* No transfer of KVP frames outside of QofInstance-derived classes! */
case KVP_TYPE_FRAME:
PWARN ("Error! Attempt to transfer KvpFrame!");
default:
PWARN ("Error! Invalid KVP Transfer Request!");
g_slice_free (GValue, val);
val = NULL;
break;
}
return val;
}

KvpValue*
kvp_value_from_gvalue (const GValue *gval)
{
KvpValue *val = NULL;
GType type = G_VALUE_TYPE (gval);
g_return_val_if_fail (G_VALUE_TYPE (gval), NULL);

if (type == G_TYPE_INT64)
val = kvp_value_new_gint64 (g_value_get_int64 (gval));
else if (type == G_TYPE_DOUBLE)
val = kvp_value_new_double (g_value_get_double (gval));
else if (type == GNC_TYPE_NUMERIC)
val = kvp_value_new_numeric (*(gnc_numeric*)g_value_get_boxed (gval));
else if (type == G_TYPE_STRING)
val = kvp_value_new_string (g_value_get_string (gval));
else if (type == GNC_TYPE_GUID)
val = kvp_value_new_guid ((GncGUID*)g_value_get_boxed (gval));
else if (type == GNC_TYPE_TIMESPEC)
val = kvp_value_new_timespec (*(Timespec*)g_value_get_boxed (gval));
else if (type == G_TYPE_DATE)
val = kvp_value_new_gdate (*(GDate*)g_value_get_boxed (gval));
else if (type == GNC_TYPE_VALUE_LIST)
{
GList *gvalue_list = (GList*)g_value_get_boxed (gval);
GList *kvp_list = NULL;
g_list_foreach (gvalue_list, (GFunc)kvp_value_list_from_gvalue, &kvp_list);
kvp_list = g_list_reverse (kvp_list);
val = kvp_value_new_glist_nc (kvp_list);
// g_list_free_full (gvalue_list, (GDestroyNotify)g_value_unset);
// gvalue_list = NULL;
}
else
PWARN ("Error! Don't know how to make a KvpValue from a %s",
G_VALUE_TYPE_NAME (gval));

return val;
}

GValue*
kvp_frame_get_gvalue (KvpFrame *frame, const gchar *key)
{
KvpValue *kval = kvp_frame_get_value (frame, key);
GValue *value = gvalue_from_kvp_value (kval);
return value;
}

void
kvp_frame_set_gvalue (KvpFrame *frame, const gchar *key, const GValue *value)
{
kvp_frame_set_value_nc (frame, key, kvp_value_from_gvalue (value));
}

static GValue*
gnc_gvalue_copy (GValue *src, gpointer uData)
{
GValue *dest = g_value_init (g_slice_new0 (GValue), G_VALUE_TYPE (src));
g_value_copy (src, dest);
return dest;
}

void
gnc_gvalue_free (GValue *val)
{
if (val == NULL || ! G_IS_VALUE (val)) return;
g_value_unset (val);
g_slice_free (GValue, val);
}

static GList*
gnc_value_list_copy (GList *list)
{
return g_list_copy_deep (list, (GCopyFunc)gnc_gvalue_copy, NULL);
}

static void
gnc_value_list_free (GList *list)
{
g_list_free_full (list, (GDestroyNotify)gnc_gvalue_free);
}

GType
gnc_value_list_get_type (void)
{
static GType type = 0;
if (type == 0)
{
type = g_boxed_type_register_static ("gnc_value_list",
(GBoxedCopyFunc)gnc_value_list_copy,
(GBoxedFreeFunc)gnc_value_list_free);
}
return type;
}

/* ========================== END OF FILE ======================= */
53 changes: 53 additions & 0 deletions src/libqof/qof/kvp_frame.h
Expand Up @@ -588,5 +588,58 @@ gchar* kvp_frame_to_string(const KvpFrame *frame);
gchar* binary_to_string(const void *data, guint32 size);
GHashTable* kvp_frame_get_hash(const KvpFrame *frame);

/** KvpItem: GValue Exchange
* \brief Transfer of KVP to and from GValue, with the key
*
* Used to parameterize KVP <-> GValue exchanges.
*/
typedef struct
{
const gchar *key;
GValue *value;
}KvpItem;

/** Return a KvpItem containing the value of a KvpFrame
*
* Structure types (gnc_numeric, Timespec) are converted to pointers
* and must be extracted with g_value_get_boxed. A KVP_TYPE_GLIST will
* have all of its contents converted from KvpValues to GValues, so
* the return type will be a GValue containing a GList of GValue*, not
* GValue. Use gnc_value_list_free() to free such a list if you take
* it out of the GValue.
*
* \param frame: (transfer-none) The KvpFrame retrieved with kvp_get_frame_foo()
* \param key: (transfer-none) A slash-delimited string with the path to
* the stored value. Must not be NULL or empty.
* \return (transfer-full) A KvpItem* which must be freed with kvp_item_free().
*/
GValue *kvp_frame_get_gvalue (KvpFrame *frame, const gchar *key);

/** Replace or create a Kvp slot from a KvpItem
*
* Structure types (gnc_numeric, Timespec) should be stored as
* boxed-type pointers in the GValue with the appropriate type from
* qof.h. Lists should be stored as a GValue containing a GList of
* GValues of type convertable to KvpValues. Unsupported types will
* emit a warning message and will be skipped.
*
* \param frame: (transfer none) The KvpFrame into which the value
* will be added.
* \param key: (transfer none) The subkey of the frame at which to
* store the value
* \param value: GValue containing the paramter to store.
*/
void kvp_frame_set_gvalue (KvpFrame *frame, const gchar *key, const GValue *value);

/**
* \brief Convenience function to release the value in a GValue
* acquired by kvp_frame_get_gvalue and to free the GValue.
* \param value: A GValue* created by kvp_frame_get_gvalue
*/
void gnc_gvalue_free (GValue *value);

GType gnc_value_list_get_type (void);
#define GNC_TYPE_VALUE_LIST (gnc_value_list_get_type ())

/** @} */
#endif
5 changes: 5 additions & 0 deletions src/libqof/qof/qofinstance-p.h
Expand Up @@ -49,4 +49,9 @@ void qof_instance_set_last_update (QofInstance *inst, Timespec ts);
* collection flag at all. */
void qof_instance_set_dirty_flag (gconstpointer inst, gboolean flag);

/* Convenience functions to save some typing in property handlers */
void qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value);
void qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value);


#endif /* QOF_INSTANCE_P_H */
20 changes: 20 additions & 0 deletions src/libqof/qof/qofinstance.c
Expand Up @@ -1050,5 +1050,25 @@ qof_commit_edit_part2(QofInstance *inst,
return TRUE;
}

void
qof_instance_set_kvp (QofInstance *inst, const gchar *key, const GValue *value)
{
KvpFrame *frame = qof_instance_get_slots (inst);
kvp_frame_set_gvalue (frame, key, value);
}

void
qof_instance_get_kvp (QofInstance *inst, const gchar *key, GValue *value)
{
KvpFrame *frame = qof_instance_get_slots (inst);
GValue *temp = kvp_frame_get_gvalue (frame, key);
if (temp)
{
g_value_copy (temp, value);
gnc_gvalue_free (temp);
}
}


/* ========================== END OF FILE ======================= */

0 comments on commit 4a4b180

Please sign in to comment.