From 0d95a6ff1dff86f7d1578a8bf20a964c7a00b6c3 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 19 Oct 2019 05:20:02 +0000 Subject: [PATCH] table-item: Generalize support for layer info. This adds support for an arbitrary number of layer text items and allows the layer text items to have footnotes. --- src/output/html.c | 20 +++++++++++-- src/output/odt.c | 22 +++++++++++++- src/output/pivot-output.c | 58 ++++++++++++++++++++----------------- src/output/render.c | 22 +++++++++++++- src/output/table-item.c | 61 +++++++++++++++++++++++++++++++++++---- src/output/table-item.h | 28 ++++++++++++++++-- src/output/table.c | 9 ++++++ 7 files changed, 182 insertions(+), 38 deletions(-) diff --git a/src/output/html.c b/src/output/html.c index 806e632014..307f6c223d 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -419,6 +419,22 @@ html_put_table_item_text (struct html_driver *html, html_put_footnote_markers (html, text->footnotes, text->n_footnotes); } +static void +html_put_table_item_layers (struct html_driver *html, + const struct table_item_layers *layers) +{ + for (size_t i = 0; i < layers->n_layers; i++) + { + if (i) + fputs ("
\n", html->file); + + const struct table_item_layer *layer = &layers->layers[i]; + escape_string (html->file, layer->content, strlen (layer->content), + " ", "
"); + html_put_footnote_markers (html, layer->footnotes, layer->n_footnotes); + } +} + static void html_output_table (struct html_driver *html, const struct table_item *item) { @@ -454,7 +470,7 @@ html_output_table (struct html_driver *html, const struct table_item *item) fputs ("\n", html->file); const struct table_item_text *title = table_item_get_title (item); - const struct table_item_text *layers = table_item_get_layers (item); + const struct table_item_layers *layers = table_item_get_layers (item); if (title || layers) { fputs (" ", html->file); @@ -463,7 +479,7 @@ html_output_table (struct html_driver *html, const struct table_item *item) if (title && layers) fputs ("
\n", html->file); if (layers) - html_put_table_item_text (html, layers); + html_put_table_item_layers (html, layers); fputs ("\n", html->file); } diff --git a/src/output/odt.c b/src/output/odt.c index a3f945421f..104e57a933 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -438,6 +438,26 @@ write_table_item_text (struct odt_driver *odt, xmlTextWriterEndElement (odt->content_wtr); } +static void +write_table_item_layers (struct odt_driver *odt, + const struct table_item_layers *layers) +{ + if (!layers) + return; + + for (size_t i = 0; i < layers->n_layers; i++) + { + const struct table_item_layer *layer = &layers->layers[i]; + xmlTextWriterStartElement (odt->content_wtr, _xml("text:h")); + xmlTextWriterWriteFormatAttribute (odt->content_wtr, + _xml("text:outline-level"), "%d", 2); + xmlTextWriterWriteString (odt->content_wtr, _xml (layer->content) ); + for (size_t i = 0; i < layer->n_footnotes; i++) + write_footnote (odt, layer->footnotes[i]); + xmlTextWriterEndElement (odt->content_wtr); + } +} + static void write_table (struct odt_driver *odt, const struct table_item *item) { @@ -446,7 +466,7 @@ write_table (struct odt_driver *odt, const struct table_item *item) /* Write a heading for the table */ write_table_item_text (odt, table_item_get_title (item)); - write_table_item_text (odt, table_item_get_layers (item)); + write_table_item_layers (odt, table_item_get_layers (item)); /* Start table */ xmlTextWriterStartElement (odt->content_wtr, _xml("table:table")); diff --git a/src/output/pivot-output.c b/src/output/pivot-output.c index f9c22b7785..d805f42bb3 100644 --- a/src/output/pivot-output.c +++ b/src/output/pivot-output.c @@ -299,24 +299,6 @@ pivot_table_submit_layer (const struct pivot_table *pt, const size_t *pindexes[PIVOT_N_AXES] = { [PIVOT_AXIS_LAYER] = layer_indexes }; - struct string layer_label = DS_EMPTY_INITIALIZER; - const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; - for (size_t i = 0; i < layer_axis->n_dimensions; i++) - { - const struct pivot_dimension *d = layer_axis->dimensions[i]; - if (d->n_leaves) - { - if (!ds_is_empty (&layer_label)) - ds_put_byte (&layer_label, '\n'); - pivot_value_format (d->root->name, pt->show_values, - pt->show_variables, &layer_label); - ds_put_cstr (&layer_label, ": "); - pivot_value_format (d->data_leaves[layer_indexes[i]]->name, - pt->show_values, pt->show_variables, - &layer_label); - } - } - size_t body[TABLE_N_AXES]; size_t *column_enumeration = pivot_table_enumerate_axis ( pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->omit_empty, &body[H]); @@ -462,16 +444,40 @@ pivot_table_submit_layer (const struct pivot_table *pt, table_item_text_destroy (title); } - if (!ds_is_empty (&layer_label)) + const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; + struct table_item_layers *layers = NULL; + for (size_t i = 0; i < layer_axis->n_dimensions; i++) { - struct table_item_text *layers = table_item_text_create ( - ds_cstr (&layer_label)); - layers->style = area_style_override (NULL, &pt->areas[PIVOT_AREA_LAYERS], - NULL, NULL); - table_item_set_layers (ti, layers); - table_item_text_destroy (layers); + const struct pivot_dimension *d = layer_axis->dimensions[i]; + if (d->n_leaves) + { + if (!layers) + { + layers = xzalloc (sizeof *layers); + layers->style = area_style_override ( + NULL, &pt->areas[PIVOT_AREA_LAYERS], NULL, NULL); + layers->layers = xnmalloc (layer_axis->n_dimensions, + sizeof *layers->layers); + } - ds_destroy (&layer_label); + const struct pivot_value *name + = d->data_leaves[layer_indexes[i]]->name; + struct table_item_layer *layer = &layers->layers[layers->n_layers++]; + struct string s = DS_EMPTY_INITIALIZER; + pivot_value_format_body (name, pt->show_values, pt->show_variables, + &s); + layer->content = ds_steal_cstr (&s); + layer->n_footnotes = name->n_footnotes; + layer->footnotes = xnmalloc (layer->n_footnotes, + sizeof *layer->footnotes); + for (size_t i = 0; i < name->n_footnotes; i++) + layer->footnotes[i] = footnotes[name->footnotes[i]->idx]; + } + } + if (layers) + { + table_item_set_layers (ti, layers); + table_item_layers_destroy (layers); } if (pt->caption) diff --git a/src/output/render.c b/src/output/render.c index 636568f4ee..83641c2062 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -1547,6 +1547,26 @@ add_text_page (struct render_pager *p, const struct table_item_text *t, render_pager_add_table (p, &tab->table, min_width); } +static void +add_layers_page (struct render_pager *p, + const struct table_item_layers *layers, int min_width) +{ + if (!layers) + return; + + struct tab_table *tab = tab_create (1, layers->n_layers); + for (size_t i = 0; i < layers->n_layers; i++) + { + const struct table_item_layer *layer = &layers->layers[i]; + tab_text (tab, 0, i, 0, layer->content); + for (size_t j = 0; j < layer->n_footnotes; j++) + tab_add_footnote (tab, 0, i, layer->footnotes[j]); + } + if (layers->style) + tab->styles[0] = area_style_clone (tab->container, layers->style); + render_pager_add_table (p, &tab->table, min_width); +} + /* Creates and returns a new render_pager for rendering TABLE_ITEM on the device with the given PARAMS. */ struct render_pager * @@ -1570,7 +1590,7 @@ render_pager_create (const struct render_params *params, add_text_page (p, table_item_get_title (table_item), title_width); /* Layers. */ - add_text_page (p, table_item_get_layers (table_item), title_width); + add_layers_page (p, table_item_get_layers (table_item), title_width); /* Body. */ render_pager_add_table (p, table_ref (table_item_get_table (table_item)), 0); diff --git a/src/output/table-item.c b/src/output/table-item.c index e9b854040a..6243f03109 100644 --- a/src/output/table-item.c +++ b/src/output/table-item.c @@ -24,6 +24,7 @@ #include "libpspp/cast.h" #include "output/driver.h" #include "output/output-item-provider.h" +#include "output/pivot-table.h" #include "output/table-item.h" #include "gl/xalloc.h" @@ -68,6 +69,56 @@ table_item_text_destroy (struct table_item_text *text) } } +void +table_item_layer_copy (struct table_item_layer *dst, + const struct table_item_layer *src) +{ + dst->content = xstrdup (src->content); + dst->footnotes = xmemdup (src->footnotes, + src->n_footnotes * sizeof *src->footnotes); + dst->n_footnotes = src->n_footnotes; +} + +void +table_item_layer_uninit (struct table_item_layer *layer) +{ + if (layer) + { + free (layer->content); + free (layer->footnotes); + } +} + +struct table_item_layers * +table_item_layers_clone (const struct table_item_layers *old) +{ + if (!old) + return NULL; + + struct table_item_layers *new = xmalloc (sizeof *new); + *new = (struct table_item_layers) { + .layers = xnmalloc (old->n_layers, sizeof *new->layers), + .n_layers = old->n_layers, + .style = area_style_clone (NULL, old->style), + }; + for (size_t i = 0; i < new->n_layers; i++) + table_item_layer_copy (&new->layers[i], &old->layers[i]); + return new; +} + +void +table_item_layers_destroy (struct table_item_layers *layers) +{ + if (layers) + { + for (size_t i = 0; i < layers->n_layers; i++) + table_item_layer_uninit (&layers->layers[i]); + free (layers->layers); + area_style_free (layers->style); + free (layers); + } +} + /* Initializes ITEM as a table item for rendering TABLE. The new table item initially has the specified TITLE and CAPTION, which may each be NULL. The caller retains ownership of TITLE and CAPTION. */ @@ -114,7 +165,7 @@ table_item_set_title (struct table_item *item, /* Returns ITEM's layers, which will be a null pointer if no layers have been set. */ -const struct table_item_text * +const struct table_item_layers * table_item_get_layers (const struct table_item *item) { return item->layers; @@ -127,11 +178,11 @@ table_item_get_layers (const struct table_item *item) This function may only be used on a table_item that is unshared. */ void table_item_set_layers (struct table_item *item, - const struct table_item_text *layers) + const struct table_item_layers *layers) { assert (!table_item_is_shared (item)); - table_item_text_destroy (item->layers); - item->layers = table_item_text_clone (layers); + table_item_layers_destroy (item->layers); + item->layers = table_item_layers_clone (layers); } /* Returns ITEM's caption, which is a null pointer if no caption has been @@ -169,8 +220,8 @@ table_item_destroy (struct output_item *output_item) { struct table_item *item = to_table_item (output_item); table_item_text_destroy (item->title); - table_item_text_destroy (item->layers); table_item_text_destroy (item->caption); + table_item_layers_destroy (item->layers); table_unref (item->table); free (item); } diff --git a/src/output/table-item.h b/src/output/table-item.h index b7866a3c9b..24740f7eab 100644 --- a/src/output/table-item.h +++ b/src/output/table-item.h @@ -42,6 +42,28 @@ struct table_item_text *table_item_text_create (const char *); struct table_item_text *table_item_text_clone (const struct table_item_text *); void table_item_text_destroy (struct table_item_text *); +struct table_item_layer + { + char *content; + const struct footnote **footnotes; + size_t n_footnotes; + }; + +void table_item_layer_copy (struct table_item_layer *, + const struct table_item_layer *); +void table_item_layer_uninit (struct table_item_layer *); + +struct table_item_layers + { + struct table_item_layer *layers; + size_t n_layers; + struct area_style *style; + }; + +struct table_item_layers *table_item_layers_clone ( + const struct table_item_layers *); +void table_item_layers_destroy (struct table_item_layers *); + /* A table item. The members of struct table_item should not be accessed directly. Use one @@ -51,8 +73,8 @@ struct table_item struct output_item output_item; /* Superclass. */ struct table *table; /* The table to be rendered. */ struct table_item_text *title; /* Null if there is no title. */ - struct table_item_text *layers; /* Null if there is no layer info. */ struct table_item_text *caption; /* Null if there is no caption. */ + struct table_item_layers *layers; /* Null if there is no layer info. */ }; struct table_item *table_item_create (struct table *, const char *title, @@ -64,10 +86,10 @@ const struct table_item_text *table_item_get_title (const struct table_item *); void table_item_set_title (struct table_item *, const struct table_item_text *); -const struct table_item_text *table_item_get_layers ( +const struct table_item_layers *table_item_get_layers ( const struct table_item *); void table_item_set_layers (struct table_item *, - const struct table_item_text *); + const struct table_item_layers *); const struct table_item_text *table_item_get_caption ( const struct table_item *); diff --git a/src/output/table.c b/src/output/table.c index 86b7bc474f..7688d8c2fc 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -289,6 +289,15 @@ table_collect_footnotes (const struct table_item *item, footnotes = add_footnotes (title->footnotes, title->n_footnotes, footnotes, &allocated, &n); + const struct table_item_layers *layers = table_item_get_layers (item); + if (layers) + { + for (size_t i = 0; i < layers->n_layers; i++) + footnotes = add_footnotes (layers->layers[i].footnotes, + layers->layers[i].n_footnotes, + footnotes, &allocated, &n); + } + const struct table_item_text *caption = table_item_get_caption (item); if (caption) footnotes = add_footnotes (caption->footnotes, caption->n_footnotes, -- 2.30.2