From c2403fdcf7885d7da1efa2c0dfb3e294f760ca9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 27 Jan 2011 19:35:54 +0100 Subject: Extend LdDiagramObject. * Add generic methods for data storage, making it able to store data in a hierarchy. * Reimplement ld_diagram_{get,set}_data_for_param on top of the generic methods. * Add a "data-changed" signal. --- liblogdiag/ld-diagram-object.c | 339 +++++++++++++++++++++++++++++++++++------ liblogdiag/ld-diagram-object.h | 16 ++ liblogdiag/ld-diagram-symbol.c | 8 +- liblogdiag/ld-marshal.list | 1 + 4 files changed, 319 insertions(+), 45 deletions(-) diff --git a/liblogdiag/ld-diagram-object.c b/liblogdiag/ld-diagram-object.c index 9dd9815..754ab1d 100644 --- a/liblogdiag/ld-diagram-object.c +++ b/liblogdiag/ld-diagram-object.c @@ -45,6 +45,8 @@ static void ld_diagram_object_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void ld_diagram_object_dispose (GObject *gobject); +static const gchar **args_to_strv (const gchar *first_arg, va_list args); + G_DEFINE_TYPE (LdDiagramObject, ld_diagram_object, G_TYPE_OBJECT); @@ -89,6 +91,21 @@ ld_diagram_object_class_init (LdDiagramObjectClass *klass) -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE); g_object_class_install_property (object_class, PROP_Y, pspec); +/** + * LdDiagramObject::data-changed: + * @self: An #LdDiagramObject object. + * @path: Path to the data. + * @old_value: (allow-none): The old value of data. + * @new_value: (allow-none): The new value of data. + * + * Some data have been changed in internal storage. + */ + klass->data_changed_signal = g_signal_new + ("data-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, + ld_marshal_VOID__BOXED_BOXED_BOXED, G_TYPE_NONE, 3, + G_TYPE_STRV, G_TYPE_VALUE, G_TYPE_VALUE); + g_type_class_add_private (klass, sizeof (LdDiagramObjectPrivate)); } @@ -104,6 +121,7 @@ ld_diagram_object_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { LdDiagramObject *self; + GValue tmp_value; self = LD_DIAGRAM_OBJECT (object); switch (property_id) @@ -113,7 +131,10 @@ ld_diagram_object_get_property (GObject *object, guint property_id, break; case PROP_X: case PROP_Y: - ld_diagram_object_get_data_for_param (self, value, pspec); + memset (&tmp_value, 0, sizeof (GValue)); + ld_diagram_object_get_data_for_param (self, &tmp_value, pspec); + g_value_copy (&tmp_value, value); + g_value_unset (&tmp_value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -212,51 +233,288 @@ ld_diagram_object_set_storage (LdDiagramObject *self, JsonObject *storage) } /** - * ld_diagram_object_get_data_for_param: + * ld_diagram_object_get_data: + * @self: An #LdDiagramObject object. + * @data: (out): An uninitialized storage for the data. + * @type: Requested type of data. %G_TYPE_NONE for any. + * @first_element: The first element of path to the data. + * @...: Optional remaining elements, followed by %NULL. + * + * Retrieve data from internal storage. + * + * Return value: %TRUE if successful. + */ +gboolean +ld_diagram_object_get_data (LdDiagramObject *self, + GValue *data, GType type, const gchar *first_element, ...) +{ + va_list args; + gboolean result; + + va_start (args, first_element); + result = ld_diagram_object_get_data_valist (self, + data, type, first_element, args); + va_end (args); + return result; +} + +/** + * ld_diagram_object_set_data: * @self: An #LdDiagramObject object. - * @data: (out): Where the data will be stored. - * @pspec: The parameter to read data for. + * @data: (allow-none): The data. %NULL just removes the current data. + * @first_element: The first element of path where the data will be stored. + * @...: Optional remaining elements, followed by %NULL. * - * Retrieve data for a parameter from internal storage. + * Put data into internal storage. */ void -ld_diagram_object_get_data_for_param (LdDiagramObject *self, - GValue *data, GParamSpec *pspec) +ld_diagram_object_set_data (LdDiagramObject *self, + const GValue *data, const gchar *first_element, ...) { - JsonObject *storage; - JsonNode *node; - const gchar *name; - GValue json_value; + va_list args; + + va_start (args, first_element); + ld_diagram_object_set_data_valist (self, data, first_element, args); + va_end (args); +} + +/** + * ld_diagram_object_get_data_valist: + * @self: An #LdDiagramObject object. + * @data: (out): An uninitialized storage for the data. + * @type: Requested type of data. %G_TYPE_NONE for any. + * @first_element: The first element of path to the data. + * @var_args: Optional remaining elements, followed by %NULL. + * + * Retrieve data from internal storage. + * + * Return value: %TRUE if successful. + */ +gboolean +ld_diagram_object_get_data_valist (LdDiagramObject *self, + GValue *data, GType type, const gchar *first_element, va_list var_args) +{ + const gchar **elements; gboolean result; - g_return_if_fail (LD_IS_DIAGRAM_OBJECT (self)); - g_return_if_fail (G_IS_VALUE (data)); - g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + elements = args_to_strv (first_element, var_args); + result = ld_diagram_object_get_datav (self, data, type, elements); + g_free (elements); + return result; +} + +/** + * ld_diagram_object_set_data_valist: + * @self: An #LdDiagramObject object. + * @data: (allow-none): The data. %NULL just removes the current data. + * @first_element: The first element of path where the data will be stored. + * @var_args: Optional remaining elements, followed by %NULL. + * + * Put data into internal storage. + */ +void +ld_diagram_object_set_data_valist (LdDiagramObject *self, + const GValue *data, const gchar *first_element, va_list var_args) +{ + const gchar **elements; - storage = ld_diagram_object_get_storage (self); - name = g_param_spec_get_name (pspec); - node = json_object_get_member (storage, name); - if (!node || json_node_is_null (node)) - goto ld_diagram_object_get_data_default; + elements = args_to_strv (first_element, var_args); + ld_diagram_object_set_datav (self, data, elements); + g_free (elements); +} + +static const gchar ** +args_to_strv (const gchar *first_arg, va_list args) +{ + const gchar **strv, *arg; + size_t strv_len = 0, strv_size = 8; + + strv = g_malloc (strv_size * sizeof (gchar *)); + for (arg = first_arg; ; arg = va_arg (args, const gchar *)) + { + if (strv_len == strv_size) + strv = g_realloc (strv, (strv_size <<= 1) * sizeof (gchar *)); + strv[strv_len++] = arg; + + if (!arg) + break; + } + return strv; +} + +/** + * ld_diagram_object_get_datav: + * @self: An #LdDiagramObject object. + * @data: (out): An uninitialized storage for the data. + * @type: Requested type of data. %G_TYPE_NONE for any. + * @elements: An array of elements of path to the data, terminated by %NULL. + * + * Retrieve data from internal storage. + * + * Return value: %TRUE if successful. + */ +gboolean +ld_diagram_object_get_datav (LdDiagramObject *self, + GValue *data, GType type, const gchar **elements) +{ + JsonObject *object; + JsonNode *node; + guint i; + + g_return_val_if_fail (LD_IS_DIAGRAM_OBJECT (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (elements != NULL && *elements, FALSE); + + object = ld_diagram_object_get_storage (self); + node = json_object_get_member (object, elements[0]); + for (i = 1; elements[i]; i++) + { + if (!node) + return FALSE; + if (!JSON_NODE_HOLDS_OBJECT (node)) + { + g_warning ("%s: unable to get a member of a non-object node", + G_STRFUNC); + return FALSE; + } + object = json_node_get_object (node); + node = json_object_get_member (object, elements[i]); + } + if (!node) + return FALSE; if (!JSON_NODE_HOLDS_VALUE (node)) - goto ld_diagram_object_get_data_warn; + { + g_warning ("%s: unable to read from a non-value node", G_STRFUNC); + return FALSE; + } + + if (type == G_TYPE_NONE) + { + json_node_get_value (node, data); + return TRUE; + } + if (g_value_type_transformable (json_node_get_value_type (node), type)) + { + GValue json_value; + + memset (&json_value, 0, sizeof (GValue)); + json_node_get_value (node, &json_value); + g_value_init (data, type); + g_value_transform (&json_value, data); + g_value_unset (&json_value); + return TRUE; + } + g_warning ("%s: unable to get value of type `%s' from node of type `%s'", + G_STRFUNC, g_type_name (type), json_node_type_name (node)); + return FALSE; +} - memset (&json_value, 0, sizeof (json_value)); - json_node_get_value (node, &json_value); - result = g_param_value_convert (pspec, &json_value, data, FALSE); - g_value_unset (&json_value); - if (result) +/** + * ld_diagram_object_set_datav: + * @self: An #LdDiagramObject object. + * @data: (allow-none): The data. %NULL just removes the current data. + * @elements: An array of elements of path where the data will be stored, + * terminated by %NULL. + * + * Put data into internal storage. + */ +void ld_diagram_object_set_datav (LdDiagramObject *self, + const GValue *data, const gchar **elements) +{ + GValue tmp_value, *old_value; + JsonObject *object, *new_object; + JsonNode *node, *new_node; + const gchar *last_element; + guint i; + + g_return_if_fail (LD_IS_DIAGRAM_OBJECT (self)); + g_return_if_fail (!data || G_IS_VALUE (data)); + g_return_if_fail (elements != NULL && *elements); + + object = ld_diagram_object_get_storage (self); + node = json_object_get_member (object, elements[0]); + last_element = elements[0]; + for (i = 1; elements[i]; i++) + { + if (!node || JSON_NODE_HOLDS_NULL (node)) + { + new_object = json_object_new (); + json_object_set_object_member (object, last_element, new_object); + object = new_object; + node = NULL; + } + else if (!JSON_NODE_HOLDS_OBJECT (node)) + { + g_warning ("%s: unable to get a member of a non-object node", + G_STRFUNC); + return; + } + else + { + object = json_node_get_object (node); + node = json_object_get_member (object, elements[i]); + } + last_element = elements[i]; + } + + if (!node || JSON_NODE_HOLDS_NULL (node)) + old_value = NULL; + else if (!JSON_NODE_HOLDS_VALUE (node)) + { + g_warning ("%s: unable to replace a non-value node", G_STRFUNC); return; + } + else + { + memset (&tmp_value, 0, sizeof (GValue)); + json_node_get_value (node, &tmp_value); + old_value = &tmp_value; + } -ld_diagram_object_get_data_warn: - g_warning ("%s: unable to get parameter `%s' of type `%s'" - " from node of type `%s'; setting the parameter to it's default value", - G_STRFUNC, name, G_PARAM_SPEC_TYPE_NAME (pspec), - json_node_type_name (node)); + /* We have to remove it first due to a bug in json-glib. */ + json_object_remove_member (object, last_element); + if (data) + { + new_node = json_node_new (JSON_NODE_VALUE); + json_node_set_value (new_node, data); + json_object_set_member (object, last_element, new_node); + } -ld_diagram_object_get_data_default: - g_param_value_set_default (pspec, data); - g_object_set_property (G_OBJECT (self), name, data); + if (old_value || data) + g_signal_emit (self, LD_DIAGRAM_OBJECT_GET_CLASS (self) + ->data_changed_signal, 0, old_value, data); + if (old_value) + g_value_unset (old_value); +} + +/** + * ld_diagram_object_get_data_for_param: + * @self: An #LdDiagramObject object. + * @data: (out): An uninitialized storage for the data. + * @pspec: The parameter to read data for. This must be a property of @self. + * + * Retrieve data for a parameter from internal storage. If there's no data + * corresponding to this parameter, the value is set to the default. + */ +void +ld_diagram_object_get_data_for_param (LdDiagramObject *self, + GValue *data, GParamSpec *pspec) +{ + const gchar *elements[2]; + + g_return_if_fail (LD_IS_DIAGRAM_OBJECT (self)); + g_return_if_fail (data != NULL); + g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + g_return_if_fail (g_type_is_a (pspec->owner_type, LD_TYPE_DIAGRAM_OBJECT)); + + elements[0] = g_param_spec_get_name (pspec); + elements[1] = NULL; + if (!ld_diagram_object_get_datav (self, data, pspec->value_type, elements)) + { + g_value_init (data, pspec->value_type); + g_param_value_set_default (pspec, data); + g_object_set_property (G_OBJECT (self), elements[0], data); + } } /** @@ -271,22 +529,15 @@ void ld_diagram_object_set_data_for_param (LdDiagramObject *self, const GValue *data, GParamSpec *pspec) { - JsonObject *storage; - const gchar *name; - JsonNode *node; + const gchar *elements[2]; g_return_if_fail (LD_IS_DIAGRAM_OBJECT (self)); g_return_if_fail (G_IS_VALUE (data)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); - storage = ld_diagram_object_get_storage (self); - name = g_param_spec_get_name (pspec); - - node = json_node_new (JSON_NODE_VALUE); - json_node_set_value (node, data); - /* We have to remove it first due to a bug in json-glib. */ - json_object_remove_member (storage, name); - json_object_set_member (storage, name, node); + elements[0] = g_param_spec_get_name (pspec); + elements[1] = NULL; + ld_diagram_object_set_datav (self, data, elements); } /** diff --git a/liblogdiag/ld-diagram-object.h b/liblogdiag/ld-diagram-object.h index 8ab8791..5c82f9c 100644 --- a/liblogdiag/ld-diagram-object.h +++ b/liblogdiag/ld-diagram-object.h @@ -48,6 +48,8 @@ struct _LdDiagramObjectClass { /*< private >*/ GObjectClass parent_class; + + guint data_changed_signal; }; @@ -56,6 +58,20 @@ GType ld_diagram_object_get_type (void) G_GNUC_CONST; LdDiagramObject *ld_diagram_object_new (JsonObject *storage); JsonObject *ld_diagram_object_get_storage (LdDiagramObject *self); void ld_diagram_object_set_storage (LdDiagramObject *self, JsonObject *storage); + +gboolean ld_diagram_object_get_data (LdDiagramObject *self, + GValue *data, GType type, const gchar *first_element, ...); +gboolean ld_diagram_object_get_data_valist (LdDiagramObject *self, + GValue *data, GType type, const gchar *first_element, va_list var_args); +gboolean ld_diagram_object_get_datav (LdDiagramObject *self, + GValue *data, GType type, const gchar **elements); +void ld_diagram_object_set_data (LdDiagramObject *self, + const GValue *data, const gchar *first_element, ...); +void ld_diagram_object_set_data_valist (LdDiagramObject *self, + const GValue *data, const gchar *first_element, va_list var_args); +void ld_diagram_object_set_datav (LdDiagramObject *self, + const GValue *data, const gchar **elements); + void ld_diagram_object_get_data_for_param (LdDiagramObject *self, GValue *data, GParamSpec *pspec); void ld_diagram_object_set_data_for_param (LdDiagramObject *self, diff --git a/liblogdiag/ld-diagram-symbol.c b/liblogdiag/ld-diagram-symbol.c index 070befd..9007938 100644 --- a/liblogdiag/ld-diagram-symbol.c +++ b/liblogdiag/ld-diagram-symbol.c @@ -8,6 +8,8 @@ * */ +#include + #include "liblogdiag.h" #include "config.h" @@ -65,12 +67,16 @@ ld_diagram_symbol_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { LdDiagramObject *self; + GValue tmp_value; self = LD_DIAGRAM_OBJECT (object); switch (property_id) { case PROP_CLASS: - ld_diagram_object_get_data_for_param (self, value, pspec); + memset (&tmp_value, 0, sizeof (GValue)); + ld_diagram_object_get_data_for_param (self, &tmp_value, pspec); + g_value_copy (&tmp_value, value); + g_value_unset (&tmp_value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); diff --git a/liblogdiag/ld-marshal.list b/liblogdiag/ld-marshal.list index 20c67c0..01a0328 100644 --- a/liblogdiag/ld-marshal.list +++ b/liblogdiag/ld-marshal.list @@ -1,2 +1,3 @@ VOID:OBJECT,OBJECT VOID:OBJECT,STRING +VOID:BOXED,BOXED,BOXED -- cgit v1.2.3