From 44c74e5e9d5baa0d8856ac601eae4d492b0555a3 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Sun, 30 Jun 2013 07:42:28 -0400 Subject: Add e_table_state_parse_context_push/pop(). New parser implementation that uses GMarkupParser instead of libxml2. --- e-util/e-table-state.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++ e-util/e-table-state.h | 4 + 2 files changed, 234 insertions(+) (limited to 'e-util') diff --git a/e-util/e-table-state.c b/e-util/e-table-state.c index 54416a42ba..2c097c7996 100644 --- a/e-util/e-table-state.c +++ b/e-util/e-table-state.c @@ -35,6 +35,8 @@ #define STATE_VERSION 0.1 +typedef struct _ParseData ParseData; + struct _ETableStatePrivate { GWeakRef specification; }; @@ -44,8 +46,146 @@ enum { PROP_SPECIFICATION }; +struct _ParseData { + ETableState *state; + GVariantBuilder *column_info; +}; + G_DEFINE_TYPE (ETableState, e_table_state, G_TYPE_OBJECT) +static ParseData * +parse_data_new (ETableSpecification *specification) +{ + ParseData *parse_data; + const GVariantType *type; + + type = G_VARIANT_TYPE ("a(xd)"); + + parse_data = g_slice_new0 (ParseData); + parse_data->state = e_table_state_new (specification); + parse_data->column_info = g_variant_builder_new (type); + + return parse_data; +} + +static void +parse_data_free (ParseData *parse_data) +{ + g_object_unref (parse_data->state); + g_variant_builder_unref (parse_data->column_info); + g_slice_free (ParseData, parse_data); +} + +static void +table_state_parser_start_column (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + GVariantBuilder *column_info, + GError **error) +{ + const gchar *index_str; + const gchar *expansion_str; + gboolean success; + + success = g_markup_collect_attributes ( + element_name, + attribute_names, + attribute_values, + error, + + G_MARKUP_COLLECT_STRING, + "source", + &index_str, + + G_MARKUP_COLLECT_STRING | + G_MARKUP_COLLECT_OPTIONAL, + "expansion", + &expansion_str, + + G_MARKUP_COLLECT_INVALID); + + if (success) { + gint64 index; + gdouble expansion = 1.0; + + g_return_if_fail (index_str != NULL); + index = g_ascii_strtoll (index_str, NULL, 10); + + if (expansion_str != NULL) + expansion = g_ascii_strtod (expansion_str, NULL); + + g_variant_builder_add ( + column_info, "(xd)", index, expansion); + } +} + +static void +table_state_parser_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseData *parse_data = user_data; + ETableSpecification *specification; + + specification = e_table_state_ref_specification (parse_data->state); + + if (g_str_equal (element_name, "column")) + table_state_parser_start_column ( + context, + element_name, + attribute_names, + attribute_values, + parse_data->column_info, + error); + + if (g_str_equal (element_name, "grouping")) + e_table_sort_info_parse_context_push ( + context, specification); + + g_object_unref (specification); +} + +static void +table_state_parser_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseData *parse_data = user_data; + + if (g_str_equal (element_name, "grouping")) { + ETableSortInfo *sort_info; + + sort_info = e_table_sort_info_parse_context_pop (context); + g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info)); + + g_clear_object (&parse_data->state->sort_info); + parse_data->state->sort_info = g_object_ref (sort_info); + + g_object_unref (sort_info); + } +} + +static void +table_state_parser_error (GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + parse_data_free ((ParseData *) user_data); +} + +static const GMarkupParser table_state_parser = { + table_state_parser_start_element, + table_state_parser_end_element, + NULL, + NULL, + table_state_parser_error +}; + static void table_state_set_specification (ETableState *state, ETableSpecification *specification) @@ -206,6 +346,96 @@ e_table_state_vanilla (ETableSpecification *specification) return state; } +/** + * e_table_state_parse_context_push: + * @context: a #GMarkupParseContext + * @specification: an #ETableSpecification + * + * Creates a new #ETableState from a segment of XML data being fed to + * @context. Call this function for the appropriate opening tag from the + * start_element callback of a #GMarkupParser, + * then call e_table_state_parse_context_pop() for the corresponding + * closing tag from the end_element callback. + **/ +void +e_table_state_parse_context_push (GMarkupParseContext *context, + ETableSpecification *specification) +{ + g_return_if_fail (context != NULL); + g_return_if_fail (E_IS_TABLE_SPECIFICATION (specification)); + + g_markup_parse_context_push ( + context, &table_state_parser, + parse_data_new (specification)); +} + +/** + * e_table_state_parse_context_pop: + * @context: a #GMarkupParseContext + * + * Creates a new #ETableState from a segment of XML data being fed to + * @context. Call e_table_state_parse_context_push() for the appropriate + * opening tag from the start_element callback of + * a #GMarkupParser, then call this function for the corresponding closing + * tag from the end_element callback. + * + * Unreference the newly-created #ETableState with g_object_unref() when + * finished with it. + * + * Returns: an #ETableState + **/ +ETableState * +e_table_state_parse_context_pop (GMarkupParseContext *context) +{ + ETableSpecification *specification; + ParseData *parse_data; + GPtrArray *columns; + ETableState *state; + GVariant *variant; + GVariantIter iter; + gint64 index; + gdouble expansion; + gsize length, ii = 0; + + g_return_val_if_fail (context != NULL, NULL); + + parse_data = g_markup_parse_context_pop (context); + g_return_val_if_fail (parse_data != NULL, NULL); + + state = g_object_ref (parse_data->state); + + specification = e_table_state_ref_specification (state); + columns = e_table_specification_ref_columns (specification); + + variant = g_variant_builder_end (parse_data->column_info); + length = g_variant_iter_init (&iter, variant); + + state->column_specs = g_new0 (ETableColumnSpecification *, length); + state->expansions = g_new0 (gdouble, length); + state->col_count = length; + + while (g_variant_iter_next (&iter, "(xd)", &index, &expansion)) { + if (index < columns->len) { + ETableColumnSpecification *column_spec; + + column_spec = g_ptr_array_index (columns, index); + state->column_specs[ii] = g_object_ref (column_spec); + state->expansions[ii] = expansion; + + ii++; + } + } + + g_variant_unref (variant); + + g_object_unref (specification); + g_ptr_array_unref (columns); + + parse_data_free (parse_data); + + return state; +} + /** * e_table_state_ref_specification: * @state: an #ETableState diff --git a/e-util/e-table-state.h b/e-util/e-table-state.h index be7800163b..c0f88e7183 100644 --- a/e-util/e-table-state.h +++ b/e-util/e-table-state.h @@ -73,6 +73,10 @@ struct _ETableStateClass { GType e_table_state_get_type (void) G_GNUC_CONST; ETableState * e_table_state_new (struct _ETableSpecification *specification); ETableState * e_table_state_vanilla (struct _ETableSpecification *specification); +void e_table_state_parse_context_push + (GMarkupParseContext *context, + struct _ETableSpecification *specification); +ETableState * e_table_state_parse_context_pop (GMarkupParseContext *context); struct _ETableSpecification * e_table_state_ref_specification (ETableState *state); gboolean e_table_state_load_from_file (ETableState *state, -- cgit v1.2.3