From 166eb5966a9a6908cfa60830a79d85b074eec53d Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 29 Dec 2020 17:20:59 -0800 Subject: [PATCH] more work toward making table_item just a pivot_Table --- src/output/ascii.c | 25 +-- src/output/cairo-fsm.c | 133 +++++++++----- src/output/cairo-fsm.h | 2 + src/output/cairo-pager.c | 9 +- src/output/cairo-pager.h | 1 - src/output/cairo.c | 4 +- src/output/csv.c | 92 +++++----- src/output/html.c | 162 ++++++++--------- src/output/odt.c | 67 ++++--- src/output/pivot-output.c | 290 ++++++++++++++++++++++--------- src/output/pivot-output.h | 21 ++- src/output/pivot-table.c | 19 -- src/output/pivot-table.h | 7 - src/output/render.c | 100 +++-------- src/output/render.h | 3 +- src/output/table-provider.h | 2 +- src/output/table.c | 76 +------- src/output/table.h | 2 +- src/output/tex.c | 81 ++++++--- src/output/text-item.c | 2 +- src/ui/gui/psppire-output-view.c | 6 +- 21 files changed, 591 insertions(+), 513 deletions(-) diff --git a/src/output/ascii.c b/src/output/ascii.c index c058f23f8a..9a08a89331 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -54,6 +54,8 @@ #include "output/driver-provider.h" #include "output/message-item.h" #include "output/options.h" +#include "output/pivot-output.h" +#include "output/pivot-table.h" #include "output/render.h" #include "output/table-item.h" #include "output/text-item.h" @@ -558,21 +560,22 @@ static void ascii_output_table_item (struct ascii_driver *a, const struct table_item *table_item) { - struct render_pager *p; - update_page_size (a, false); - if (a->object_cnt++) - putc ('\n', a->file); - - p = render_pager_create (&a->params, table_item); - for (int i = 0; render_pager_has_next (p); i++) + size_t *layer_indexes; + PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, table_item->pt, true) { - if (i) - putc ('\n', a->file); - ascii_output_lines (a, render_pager_draw_next (p, INT_MAX)); + struct render_pager *p = render_pager_create (&a->params, table_item, + layer_indexes); + for (int i = 0; render_pager_has_next (p); i++) + { + if (a->object_cnt++) + putc ('\n', a->file); + + ascii_output_lines (a, render_pager_draw_next (p, INT_MAX)); + } + render_pager_destroy (p); } - render_pager_destroy (p); } static void diff --git a/src/output/cairo-fsm.c b/src/output/cairo-fsm.c index 58bbf230d5..5e6befc3d7 100644 --- a/src/output/cairo-fsm.c +++ b/src/output/cairo-fsm.c @@ -41,6 +41,8 @@ #include "output/message-item.h" #include "output/page-eject-item.h" #include "output/page-setup-item.h" +#include "output/pivot-output.h" +#include "output/pivot-table.h" #include "output/render.h" #include "output/table-item.h" #include "output/text-item.h" @@ -105,6 +107,7 @@ xr_fsm_style_equals (const struct xr_fsm_style *a, || a->min_break[H] != b->min_break[H] || a->min_break[V] != b->min_break[V] || a->use_system_colors != b->use_system_colors + || a->object_spacing != b->object_spacing || a->font_resolution != b->font_resolution) return false; @@ -134,14 +137,14 @@ struct xr_fsm struct output_item *item; bool print; + /* Print mode only. */ + bool done; + /* Table items only. */ size_t *layer_indexes; struct render_params rp; struct render_pager *p; cairo_t *cairo; /* XXX should this be here?! */ - - /* Chart and page-eject items only. */ - bool done; }; /* The unit used for internal measurements is inch/(72 * XR_POINT). @@ -1020,7 +1023,8 @@ xr_fsm_create (const struct output_item *item_, size_t *layer_indexes = NULL; if (is_table_item (item)) { - layer_indexes = pivot_table_next_layer (table_item->pt, NULL, print); + const struct table_item *table_item = to_table_item (item); + layer_indexes = pivot_output_next_layer (table_item->pt, NULL, print); if (!layer_indexes) return NULL; } @@ -1045,10 +1049,6 @@ xr_fsm_create (const struct output_item *item_, [RENDER_LINE_DOUBLE] = 2 * LW + LS, }; - size_t *layer_indexes = NULL; - if (is_table_item (item) - pivot_table_next_display_layer ( - struct xr_fsm *fsm = xmalloc (sizeof *fsm); *fsm = (struct xr_fsm) { .style = xr_fsm_style_ref (style), @@ -1093,13 +1093,20 @@ xr_fsm_create (const struct output_item *item_, struct table_item *table_item = to_table_item (item); fsm->cairo = cr; - fsm->p = render_pager_create (&fsm->rp, table_item); + fsm->p = render_pager_create (&fsm->rp, table_item, fsm->layer_indexes); fsm->cairo = NULL; } return fsm; } +struct xr_fsm * +xr_fsm_create_for_printing (const struct output_item *item, + const struct xr_fsm_style *style, cairo_t *cr) +{ + return xr_fsm_create (item, style, cr, true); +} + void xr_fsm_destroy (struct xr_fsm *fsm) { @@ -1107,17 +1114,27 @@ xr_fsm_destroy (struct xr_fsm *fsm) { xr_fsm_style_unref (fsm->style); output_item_unref (fsm->item); + free (fsm->layer_indexes); render_pager_destroy (fsm->p); assert (!fsm->cairo); free (fsm); } } + +/* Scrolling API. */ + +struct xr_fsm * +xr_fsm_create_for_scrolling (const struct output_item *item, + const struct xr_fsm_style *style, cairo_t *cr) +{ + return xr_fsm_create (item, style, cr, false); +} -/* This is primarily meant for use with screen rendering since the result is a - fixed value for charts. */ void xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp) { + assert (!fsm->print); + int w, h; if (is_table_item (fsm->item)) @@ -1141,38 +1158,10 @@ xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp) *hp = h; } -static int -xr_fsm_draw_table (struct xr_fsm *fsm, int space) -{ - return (render_pager_has_next (fsm->p) - ? render_pager_draw_next (fsm->p, space) - : 0); -} - -static int -xr_fsm_draw_chart (struct xr_fsm *fsm, int space) -{ - const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]); - if (space < chart_height) - return 0; - - fsm->done = true; - xr_draw_chart (to_chart_item (fsm->item), fsm->cairo, - xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height)); - return chart_height; -} - -static int -xr_fsm_draw_eject (struct xr_fsm *fsm, int space) -{ - if (space >= fsm->rp.size[V]) - fsm->done = true; - return 0; -} - void xr_fsm_draw_all (struct xr_fsm *fsm, cairo_t *cr) { + assert (!fsm->print); xr_fsm_draw_region (fsm, cr, 0, 0, INT_MAX, INT_MAX); } @@ -1188,6 +1177,7 @@ void xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr, int x, int y, int w, int h) { + assert (!fsm->print); if (is_table_item (fsm->item)) { fsm->cairo = cr; @@ -1204,11 +1194,65 @@ xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr, else NOT_REACHED (); } + +/* Printing API. */ + +static int +xr_fsm_draw_table (struct xr_fsm *fsm, int space) +{ + struct table_item *table_item = to_table_item (fsm->item); + int used = render_pager_draw_next (fsm->p, space); + if (!render_pager_has_next (fsm->p)) + { + render_pager_destroy (fsm->p); + + fsm->layer_indexes = pivot_output_next_layer (table_item->pt, + fsm->layer_indexes, true); + if (fsm->layer_indexes) + { + fsm->p = render_pager_create (&fsm->rp, table_item, + fsm->layer_indexes); + if (table_item->pt->look->paginate_layers) + used = space; + else + used += fsm->style->object_spacing; + } + else + { + fsm->p = NULL; + fsm->done = true; + } + } + return MIN (used, space); +} + +static int +xr_fsm_draw_chart (struct xr_fsm *fsm, int space) +{ + const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]); + if (space < chart_height) + return 0; + + fsm->done = true; + xr_draw_chart (to_chart_item (fsm->item), fsm->cairo, + xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height)); + return chart_height; +} + +static int +xr_fsm_draw_eject (struct xr_fsm *fsm, int space) +{ + if (space >= fsm->rp.size[V]) + fsm->done = true; + return 0; +} int xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space) { - if (xr_fsm_is_empty (fsm)) + assert (fsm->print); + + if (fsm->done) return 0; cairo_save (cr); @@ -1223,11 +1267,10 @@ xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space) return used; } - bool xr_fsm_is_empty (const struct xr_fsm *fsm) { - return (is_table_item (fsm->item) - ? !render_pager_has_next (fsm->p) - : fsm->done); + assert (fsm->print); + + return fsm->done; } diff --git a/src/output/cairo-fsm.h b/src/output/cairo-fsm.h index 906ce12be3..8c88923787 100644 --- a/src/output/cairo-fsm.h +++ b/src/output/cairo-fsm.h @@ -49,6 +49,8 @@ struct xr_fsm_style struct cell_color fg; bool use_system_colors; + int object_spacing; + /* Resolution, in units per inch, used for measuring font "points". If this is 72.0, for example, then 1pt = 1 device unit, which is appropriate for rendering to a surface created by diff --git a/src/output/cairo-pager.c b/src/output/cairo-pager.c index d096b0cace..7243fad13c 100644 --- a/src/output/cairo-pager.c +++ b/src/output/cairo-pager.c @@ -95,8 +95,7 @@ xr_page_style_equals (const struct xr_page_style *a, if (!page_heading_equals (&a->headings[i], &b->headings[i])) return false; - return (a->initial_page_number == b->initial_page_number - && a->object_spacing == b->object_spacing); + return a->initial_page_number == b->initial_page_number; } struct xr_pager @@ -219,7 +218,7 @@ xr_measure_headings (const struct xr_page_style *ps, &ps->headings[i], -1, fs->size[H], 0, fs->font_resolution); if (*h) - *h += ps->object_spacing; + *h += fs->object_spacing; } cairo_destroy (cairo); cairo_surface_destroy (surface); @@ -319,7 +318,7 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr) if (p->heading_heights[1]) xr_render_page_heading (cr, font, &ps->headings[1], page_number, - fs->size[H], fs->size[V] + ps->object_spacing, + fs->size[H], fs->size[V] + fs->object_spacing, fs->font_resolution); cairo_surface_t *surface = cairo_get_target (cr); @@ -418,7 +417,7 @@ xr_pager_run (struct xr_pager *p) free (attrs); } - int spacing = p->page_style->object_spacing; + int spacing = p->fsm_style->object_spacing; int chunk = xr_fsm_draw_slice (p->fsm, p->cr, p->fsm_style->size[V] - p->y); p->y += chunk + spacing; diff --git a/src/output/cairo-pager.h b/src/output/cairo-pager.h index bd7fa55125..361c29798b 100644 --- a/src/output/cairo-pager.h +++ b/src/output/cairo-pager.h @@ -38,7 +38,6 @@ struct xr_page_style struct page_heading headings[2]; /* Top and bottom headings. */ int initial_page_number; - int object_spacing; /* Whether to include an outline in PDF output. (The only reason I know to omit it is to avoid a Cairo bug that caused crashes in some cases.) */ diff --git a/src/output/cairo.c b/src/output/cairo.c index 313456c663..b099a8f609 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -256,7 +256,6 @@ xr_allocate (const char *name, int device_type, }, .initial_page_number = 1, - .object_spacing = object_spacing, .include_outline = include_outline, }; @@ -271,6 +270,7 @@ xr_allocate (const char *name, int device_type, }, .fg = fg, .use_system_colors = systemcolors, + .object_spacing = object_spacing, .font_resolution = font_resolution, }; @@ -579,7 +579,6 @@ xr_update_page_setup (struct output_driver *driver, }, .initial_page_number = setup->initial_page_number, - .object_spacing = setup->object_spacing * 72 * XR_POINT, .include_outline = old_ps->include_outline, }; for (size_t i = 0; i < 2; i++) @@ -597,6 +596,7 @@ xr_update_page_setup (struct output_driver *driver, }, .fg = old_fs->fg, .use_system_colors = old_fs->use_system_colors, + .object_spacing = setup->object_spacing * 72 * XR_POINT, .font_resolution = old_fs->font_resolution, }; for (size_t i = 0; i < XR_N_FONTS; i++) diff --git a/src/output/csv.c b/src/output/csv.c index bde8711314..ab79e32a76 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -31,6 +31,7 @@ #include "output/options.h" #include "output/message-item.h" #include "output/page-eject-item.h" +#include "output/pivot-output.h" #include "output/table-item.h" #include "output/table-provider.h" @@ -221,61 +222,64 @@ csv_output_table_cell (struct csv_driver *csv, const struct table_cell *cell, } static void -csv_submit (struct output_driver *driver, - const struct output_item *output_item) +csv_output_table__ (struct csv_driver *csv, const struct table *t, + const char *leader) { - struct csv_driver *csv = csv_driver_cast (driver); - - if (is_table_item (output_item)) + for (int y = 0; y < t->n[TABLE_VERT]; y++) { - struct table_item *table_item = to_table_item (output_item); - const struct table *t = table_item_get_table (table_item); - int x, y; - - csv_put_separator (csv); - - if (csv->titles) - csv_output_table_cell (csv, table_item_get_title (table_item), "Table"); - - for (y = 0; y < t->n[TABLE_VERT]; y++) + for (int x = 0; x < t->n[TABLE_HORZ]; x++) { - for (x = 0; x < t->n[TABLE_HORZ]; x++) - { - struct table_cell cell; + struct table_cell cell; - table_get_cell (t, x, y, &cell); + table_get_cell (t, x, y, &cell); - if (x > 0) - fputs (csv->separator, csv->file); + if (x > 0) + fputs (csv->separator, csv->file); - if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0]) - csv_output_field (csv, ""); - else - csv_output_table_cell (csv, &cell, NULL); - } - putc ('\n', csv->file); + if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0]) + csv_output_field (csv, ""); + else + csv_output_table_cell (csv, &cell, !x ? leader : NULL); } + putc ('\n', csv->file); + } +} - if (csv->captions) - csv_output_table_cell (csv, table_item_get_caption (table_item), - "Caption"); +static void +csv_output_table_layer (struct csv_driver *csv, const struct pivot_table *pt, + const size_t *layer_indexes) +{ + struct table *title, *layers, *body, *caption, *footnotes; + pivot_output (pt, layer_indexes, &title, &layers, &body, + &caption, &footnotes, NULL, NULL); + + csv_put_separator (csv); + csv_output_table__ (csv, title, "Table"); + csv_output_table__ (csv, layers, "Layer"); + csv_output_table__ (csv, body, NULL); + csv_output_table__ (csv, caption, "Caption"); + csv_output_table__ (csv, footnotes, "Footnote"); + + table_unref (title); + table_unref (layers); + table_unref (body); + table_unref (caption); + table_unref (footnotes); +} - struct footnote **f; - size_t n_footnotes = table_collect_footnotes (table_item, &f); - if (n_footnotes) - { - fputs ("\nFootnotes:\n", csv->file); +static void +csv_submit (struct output_driver *driver, + const struct output_item *output_item) +{ + struct csv_driver *csv = csv_driver_cast (driver); - for (size_t i = 0; i < n_footnotes; i++) - { - csv_output_field (csv, f[i]->marker); - fputs (csv->separator, csv->file); - csv_output_field (csv, f[i]->content); - putc ('\n', csv->file); - } + if (is_table_item (output_item)) + { + const struct pivot_table *pt = to_table_item (output_item)->pt; - free (f); - } + size_t *layer_indexes; + PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, pt, true) + csv_output_table_layer (csv, pt, layer_indexes); } else if (is_text_item (output_item)) { diff --git a/src/output/html.c b/src/output/html.c index 9f9fc2db89..f8213952e1 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -41,6 +41,8 @@ #include "output/message-item.h" #include "output/options.h" #include "output/output-item-provider.h" +#include "output/pivot-output.h" +#include "output/pivot-table.h" #include "output/table-provider.h" #include "output/table-item.h" #include "output/text-item.h" @@ -159,7 +161,7 @@ put_header (struct html_driver *html) " margin-bottom: 1em\n" "}\n" "caption {\n" - " text-align: left\n" + " text-align: left;\n" "}\n" "th { font-weight: normal }\n" "a:link {\n" @@ -479,20 +481,6 @@ put_border (const struct table *table, const struct table_cell *cell, } } -static void -put_tfoot (struct html_driver *html, const struct table *t, bool *tfoot) -{ - if (!*tfoot) - { - fputs ("\n", html->file); - fputs ("\n", html->file); - fprintf (html->file, "\n", t->n[H]); - *tfoot = true; - } - else - fputs ("\n
", html->file); -} - static void html_put_footnote_markers (struct html_driver *html, struct footnote **footnotes, @@ -542,24 +530,8 @@ html_put_table_cell_text (struct html_driver *html, } 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, " ", "
"); - html_put_footnote_markers (html, layer->footnotes, layer->n_footnotes); - } -} - -static void -html_put_table_cell (struct html_driver *html, const struct table *t, - const struct table_cell *cell, const char *tag, - bool border) +html_put_table_cell (struct html_driver *html, const struct table_cell *cell, + const char *tag, const struct table *t) { fprintf (html->file, "<%s", tag); @@ -623,7 +595,7 @@ html_put_table_cell (struct html_driver *html, const struct table *t, put_style (&style, "font-size", buf); } - if (border) + if (t && html->borders) { put_border (t, cell, &style, V, 0, 0, "top"); put_border (t, cell, &style, H, 0, 0, "left"); @@ -652,83 +624,115 @@ html_put_table_cell (struct html_driver *html, const struct table *t, } static void -html_output_table (struct html_driver *html, const struct table_item *item) +html_output_table_layer (struct html_driver *html, const struct pivot_table *pt, + const size_t *layer_indexes) { - const struct table *t = table_item_get_table (item); - bool tfoot = false; + struct table *title, *layers, *body, *caption, *footnotes; + pivot_output (pt, layer_indexes, &title, &layers, &body, + &caption, &footnotes, NULL, NULL); fputs ("file); - if (item->notes) + if (pt->notes) { fputs (" title=\"", html->file); - escape_string (html->file, item->notes, " ", "\n"); + escape_string (html->file, pt->notes, " ", "\n"); putc ('"', html->file); } fputs (">\n", html->file); - const struct table_cell *caption = table_item_get_caption (item); - if (caption) + if (title) { - put_tfoot (html, t, &tfoot); - html_put_table_cell (html, t, caption, "span", false); + struct table_cell cell; + table_get_cell (title, 0, 0, &cell); + html_put_table_cell (html, &cell, "caption", NULL); } - struct footnote **f; - size_t n_footnotes = table_collect_footnotes (item, &f); - for (size_t i = 0; i < n_footnotes; i++) + if (layers) { - put_tfoot (html, t, &tfoot); - escape_tag (html->file, "sup", f[i]->marker, " ", "
"); - escape_string (html->file, f[i]->content, " ", "
"); - } - free (f); - if (tfoot) - { - fputs ("\n", html->file); - fputs ("\n", html->file); - fputs ("\n", html->file); - } + fputs ("\n", html->file); + for (size_t y = 0; y < layers->n[V]; y++) + { + fputs ("\n", html->file); - const struct table_cell *title = table_item_get_title (item); - const struct table_item_layers *layers = table_item_get_layers (item); - if (title || layers) - { - fputs ("", html->file); - if (title) - html_put_table_cell (html, t, title, "span", false); - if (title && layers) - fputs ("
\n", html->file); - if (layers) - html_put_table_item_layers (html, layers); - fputs ("\n", html->file); + struct table_cell cell; + table_get_cell (layers, 0, y, &cell); + cell.d[H][1] = body->n[H]; + html_put_table_cell (html, &cell, "td", NULL); + + fputs ("\n", html->file); + } + fputs ("\n", html->file); } fputs ("\n", html->file); - - for (int y = 0; y < t->n[V]; y++) + for (int y = 0; y < body->n[V]; y++) { fputs ("\n", html->file); - for (int x = 0; x < t->n[H]; ) + for (int x = 0; x < body->n[H]; ) { struct table_cell cell; - table_get_cell (t, x, y, &cell); + table_get_cell (body, x, y, &cell); if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0]) { - bool is_header = (y < t->h[V][0] - || y >= t->n[V] - t->h[V][1] - || x < t->h[H][0] - || x >= t->n[H] - t->h[H][1]); + bool is_header = (y < body->h[V][0] + || y >= body->n[V] - body->h[V][1] + || x < body->h[H][0] + || x >= body->n[H] - body->h[H][1]); const char *tag = is_header ? "th" : "td"; - html_put_table_cell (html, t, &cell, tag, html->borders); + html_put_table_cell (html, &cell, tag, body); } x = cell.d[TABLE_HORZ][1]; } fputs ("\n", html->file); } - fputs ("\n", html->file); + + if (caption || footnotes) + { + fprintf (html->file, "\n"); + + if (caption) + { + fputs ("\n", html->file); + + struct table_cell cell; + table_get_cell (caption, 0, 0, &cell); + cell.d[H][1] = body->n[H]; + html_put_table_cell (html, &cell, "td", NULL); + + fputs ("\n", html->file); + } + + for (size_t y = 0; y < footnotes->n[V]; y++) + { + fputs ("\n", html->file); + + struct table_cell cell; + table_get_cell (footnotes, 0, y, &cell); + cell.d[H][1] = body->n[H]; + html_put_table_cell (html, &cell, "td", NULL); + + fputs ("\n", html->file); + } + fputs ("\n", html->file); + } + fputs ("\n\n", html->file); + + table_unref (title); + table_unref (layers); + table_unref (body); + table_unref (caption); + table_unref (footnotes); +} + +static void +html_output_table (struct html_driver *html, const struct table_item *item) +{ + size_t *layer_indexes; + PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true) + html_output_table_layer (html, item->pt, layer_indexes); } struct output_driver_factory html_driver_factory = diff --git a/src/output/odt.c b/src/output/odt.c index 9397bf1425..4fdccd1424 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -40,6 +40,8 @@ #include "output/driver-provider.h" #include "output/message-item.h" #include "output/options.h" +#include "output/pivot-table.h" +#include "output/pivot-output.h" #include "output/table-item.h" #include "output/table-provider.h" #include "output/text-item.h" @@ -443,34 +445,30 @@ write_table_item_cell (struct odt_driver *odt, } static void -write_table_item_layers (struct odt_driver *odt, - const struct table_item_layers *layers) +write_table__ (struct odt_driver *odt, const struct table *t) { - if (!layers) - return; - - for (size_t i = 0; i < layers->n_layers; i++) + if (t) { - 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); + for (size_t y = 0; y < t->n[V]; y++) + { + struct table_cell cell; + table_get_cell (t, 0, y, &cell); + write_table_item_cell (odt, &cell); + } } } static void -write_table (struct odt_driver *odt, const struct table_item *item) +write_table_layer (struct odt_driver *odt, const struct pivot_table *pt, + const size_t *layer_indexes) { - const struct table *tab = table_item_get_table (item); - int r, c; + struct table *title, *layers, *body, *caption, *footnotes; + pivot_output (pt, layer_indexes, &title, &layers, &body, + &caption, &footnotes, NULL, NULL); /* Write a heading for the table */ - write_table_item_cell (odt, table_item_get_title (item)); - write_table_item_layers (odt, table_item_get_layers (item)); + write_table__ (odt, title); + write_table__ (odt, layers); /* Start table */ xmlTextWriterStartElement (odt->content_wtr, _xml("table:table")); @@ -480,27 +478,27 @@ write_table (struct odt_driver *odt, const struct table_item *item) /* Start column definitions */ xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-column")); - xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:number-columns-repeated"), "%d", tab->n[H]); + xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:number-columns-repeated"), "%d", body->n[H]); xmlTextWriterEndElement (odt->content_wtr); /* Deal with row headers */ - if (tab->h[V][0] > 0) + if (body->h[V][0] > 0) xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-header-rows")); /* Write all the rows */ - for (r = 0 ; r < tab->n[V]; ++r) + for (int r = 0 ; r < body->n[V]; ++r) { /* Start row definition */ xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-row")); /* Write all the columns */ - for (c = 0 ; c < tab->n[H] ; ++c) + for (int c = 0 ; c < body->n[H] ; ++c) { struct table_cell cell; - table_get_cell (tab, c, r, &cell); + table_get_cell (body, c, r, &cell); if (c == cell.d[H][0] && r == cell.d[V][0]) { @@ -522,7 +520,7 @@ write_table (struct odt_driver *odt, const struct table_item *item) xmlTextWriterStartElement (odt->content_wtr, _xml("text:p")); - if (r < tab->h[V][0] || c < tab->h[H][0]) + if (r < body->h[V][0] || c < body->h[H][0]) xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Heading")); else xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Contents")); @@ -552,7 +550,7 @@ write_table (struct odt_driver *odt, const struct table_item *item) xmlTextWriterEndElement (odt->content_wtr); /* row */ - int ht = tab->h[V][0]; + int ht = body->h[V][0]; if (ht > 0 && r == ht - 1) xmlTextWriterEndElement (odt->content_wtr); /* table-header-rows */ } @@ -560,7 +558,22 @@ write_table (struct odt_driver *odt, const struct table_item *item) xmlTextWriterEndElement (odt->content_wtr); /* table */ /* Write a caption for the table */ - write_table_item_cell (odt, table_item_get_caption (item)); + write_table__ (odt, caption); + write_table__ (odt, footnotes); + + table_unref (title); + table_unref (layers); + table_unref (body); + table_unref (caption); + table_unref (footnotes); +} + +static void +write_table (struct odt_driver *odt, const struct table_item *item) +{ + size_t *layer_indexes; + PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true) + write_table_layer (odt, item->pt, layer_indexes); } static void diff --git a/src/output/pivot-output.c b/src/output/pivot-output.c index 4c0ac48a86..2d88610eae 100644 --- a/src/output/pivot-output.c +++ b/src/output/pivot-output.c @@ -36,6 +36,25 @@ #define H TABLE_HORZ #define V TABLE_VERT +size_t * +pivot_output_next_layer (const struct pivot_table *pt, size_t *indexes, + bool print) +{ + const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; + if (print && pt->look->print_all_layers) + return pivot_axis_iterator_next (indexes, layer_axis); + else if (!indexes) + { + size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer; + return xmemdup (pt->current_layer, MAX (size, 1)); + } + else + { + free (indexes); + return NULL; + } +} + static const struct pivot_category * find_category (const struct pivot_dimension *d, int dim_index, const size_t *indexes, int row_ofs) @@ -149,51 +168,6 @@ fill_cell (struct table *t, int x1, int y1, int x2, int y2, } } -static struct table_cell * -pivot_value_to_table_cell (const struct pivot_value *value, - const struct table_area_style *style, int style_idx, - struct footnote **footnotes, - enum settings_value_show show_values, - enum settings_value_show show_variables) -{ - if (!value) - return NULL; - - struct string s = DS_EMPTY_INITIALIZER; - int options = format_cell (value, style_idx, - show_values, show_variables, false, &s); - - struct table_cell *cell = xmalloc (sizeof *cell); - *cell = (struct table_cell) { - .options = options, - .text = ds_steal_cstr (&s), - .style = table_area_style_override ( - NULL, style, value->cell_style, value->font_style, false), - }; - - if (value->n_subscripts) - { - cell->subscripts = xnmalloc (value->n_subscripts, - sizeof *cell->subscripts); - cell->n_subscripts = value->n_subscripts; - for (size_t i = 0; i < value->n_subscripts; i++) - cell->subscripts[i] = xstrdup (value->subscripts[i]); - } - - if (value->n_footnotes) - { - cell->footnotes = xnmalloc (value->n_footnotes, sizeof *cell->footnotes); - for (size_t i = 0; i < value->n_footnotes; i++) - { - struct footnote *f = footnotes[value->footnotes[i]->idx]; - if (f) - cell->footnotes[cell->n_footnotes++] = f; - } - } - - return cell; -} - static int get_table_rule (const struct table_border_style *styles, enum pivot_border style_idx) @@ -331,41 +305,124 @@ compose_headings (struct table *t, } } -struct table * -pivot_table_to_table (const struct pivot_table *pt, - const size_t *layer_indexes) +static struct table * +create_aux_table (const struct pivot_table *pt, int nc, int nr, + int style_idx) +{ + struct table *table = table_create (nr, nc, 0, 0, 0, 0); + table->styles[style_idx] = table_area_style_override ( + t->container, &pt->look->areas[style_idx], NULL, NULL, false); + return table; +} + + +static struct footnote ** +add_footnotes (struct footnote **refs, size_t n_refs, + struct footnote **footnotes, size_t *allocated, size_t *n) +{ + for (size_t i = 0; i < n_refs; i++) + { + struct footnote *f = refs[i]; + if (f->idx >= *allocated) + { + size_t new_allocated = (f->idx + 1) * 2; + footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes); + while (*allocated < new_allocated) + footnotes[(*allocated)++] = NULL; + } + footnotes[f->idx] = f; + if (f->idx >= *n) + *n = f->idx + 1; + } + return footnotes; +} + +size_t +table_collect_footnotes (const struct table * + struct footnote ***footnotesp) +{ + struct footnote **footnotes = NULL; + size_t allocated = 0; + size_t n = 0; + + struct table *t = item->table; + for (int y = 0; y < t->n[V]; y++) + { + struct table_cell cell; + for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1]) + { + table_get_cell (t, x, y, &cell); + + if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0]) + footnotes = add_footnotes (cell.footnotes, cell.n_footnotes, + footnotes, &allocated, &n); + } + } + + const struct table_cell *title = table_item_get_title (item); + if (title) + 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_cell *caption = table_item_get_caption (item); + if (caption) + footnotes = add_footnotes (caption->footnotes, caption->n_footnotes, + footnotes, &allocated, &n); + + size_t n_nonnull = 0; + for (size_t i = 0; i < n; i++) + if (footnotes[i]) + footnotes[n_nonnull++] = footnotes[i]; + + *footnotesp = footnotes; + return n_nonnull; +} + +void +pivot_output (const struct pivot_table *pt, + const size_t *layer_indexes, + struct table **titlep, + struct table **layersp, + struct table **bodyp, + struct table **captionp, + struct table **footnotesp, + struct footnote ***fp, size_t *nfp) { const size_t *pindexes[PIVOT_N_AXES] = { [PIVOT_AXIS_LAYER] = layer_indexes }; - size_t body[TABLE_N_AXES]; + size_t data[TABLE_N_AXES]; size_t *column_enumeration = pivot_table_enumerate_axis ( - pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &body[H]); + pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &data[H]); size_t *row_enumeration = pivot_table_enumerate_axis ( - pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &body[V]); + pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &data[V]); int stub[TABLE_N_AXES] = { [H] = pt->axes[PIVOT_AXIS_ROW].label_depth, [V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth, }; - struct table *table = table_create (body[H] + stub[H], - body[V] + stub[V], - stub[H], 0, stub[V], 0); - + struct table *body = table_create (data[H] + stub[H], + data[V] + stub[V], + stub[H], 0, stub[V], 0); for (size_t i = 0; i < PIVOT_N_AREAS; i++) - table->styles[i] = table_area_style_override ( - table->container, &pt->look->areas[i], NULL, NULL, false); + body->styles[i] = table_area_style_override ( + body->container, &pt->look->areas[i], NULL, NULL, false); for (size_t i = 0; i < PIVOT_N_BORDERS; i++) { const struct table_border_style *in = &pt->look->borders[i]; - table->rule_colors[i] = pool_alloc (table->container, - sizeof *table->rule_colors[i]); - struct cell_color *out = table->rule_colors[i]; - out->alpha = in->color.alpha; - out->r = in->color.r; - out->g = in->color.g; - out->b = in->color.b; + body->rule_colors[i] = pool_alloc (body->container, + sizeof *body->rule_colors[i]); + *body->rule_colors[i] = in->color; } struct footnote **footnotes = XCALLOC (pt->n_footnotes, struct footnote *); @@ -381,8 +438,8 @@ pivot_table_to_table (const struct pivot_table *pt, char *marker = pivot_value_to_string (pf->marker, pt->show_values, pt->show_variables); footnotes[i] = table_create_footnote ( - table, i, content, marker, - table_area_style_override (table->container, + body, i, content, marker, + table_area_style_override (body->container, &pt->look->areas[PIVOT_AREA_FOOTER], pf->content->cell_style, pf->content->font_style, @@ -391,28 +448,28 @@ pivot_table_to_table (const struct pivot_table *pt, free (content); } - compose_headings (table, + compose_headings (body, &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW], pt->look->borders, PIVOT_BORDER_DIM_COL_HORZ, PIVOT_BORDER_DIM_COL_VERT, PIVOT_BORDER_CAT_COL_HORZ, PIVOT_BORDER_CAT_COL_VERT, - column_enumeration, body[H], + column_enumeration, data[H], &pt->look->areas[PIVOT_AREA_COLUMN_LABELS], PIVOT_AREA_COLUMN_LABELS, &pt->look->areas[PIVOT_AREA_CORNER], footnotes, pt->show_values, pt->show_variables, pt->rotate_outer_row_labels, false); - compose_headings (table, + compose_headings (body, &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN], pt->look->borders, PIVOT_BORDER_DIM_ROW_VERT, PIVOT_BORDER_DIM_ROW_HORZ, PIVOT_BORDER_CAT_ROW_VERT, PIVOT_BORDER_CAT_ROW_HORZ, - row_enumeration, body[V], + row_enumeration, data[V], &pt->look->areas[PIVOT_AREA_ROW_LABELS], PIVOT_AREA_ROW_LABELS, &pt->look->areas[PIVOT_AREA_CORNER], footnotes, @@ -431,7 +488,7 @@ pivot_table_to_table (const struct pivot_table *pt, { pivot_table_convert_indexes_ptod (pt, pindexes, dindexes); const struct pivot_value *value = pivot_table_get (pt, dindexes); - fill_cell (table, + fill_cell (body, x + stub[H], y + stub[V], x + stub[H], y + stub[V], &pt->look->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA, @@ -447,42 +504,103 @@ pivot_table_to_table (const struct pivot_table *pt, if ((pt->corner_text || !pt->look->row_labels_in_corner) && stub[H] && stub[V]) - fill_cell (table, 0, 0, stub[H] - 1, stub[V] - 1, + fill_cell (body, 0, 0, stub[H] - 1, stub[V] - 1, &pt->look->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER, pt->corner_text, footnotes, pt->show_values, pt->show_variables, false); - if (table->n[H] && table->n[V]) + if (body->n[H] && body->n[V]) { table_hline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP), - 0, table->n[H] - 1, 0); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP), + 0, body->n[H] - 1, 0); table_hline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM), - 0, table->n[H] - 1, table->n[V]); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM), + 0, body->n[H] - 1, body->n[V]); table_vline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT), - 0, 0, table->n[V] - 1); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT), + 0, 0, body->n[V] - 1); table_vline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT), - table->n[H], 0, table->n[V] - 1); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT), + body->n[H], 0, body->n[V] - 1); if (stub[V]) table_hline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP), - 0, table->n[H] - 1, stub[V]); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP), + 0, body->n[H] - 1, stub[V]); if (stub[H]) table_vline ( - table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT), - stub[H], 0, table->n[V] - 1); + body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT), + stub[H], 0, body->n[V] - 1); } free (column_enumeration); free (row_enumeration); + /* Title. */ + struct table *title; + if (pt->title && titlep) + { + title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE); + fill_cell (title, 0, 0, 1, 1, + &pt->look->areas[PIVOT_AREA_TITLE], PIVOT_AREA_TITLE, + pt->title, footnotes, + pt->show_values, pt->show_variables, false); + } + else + title = NULL; + + /* Layers. */ + const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; + int n_layers = 0; + if (layersp) + for (size_t i = 0; i < layer_axis->n_dimensions; i++) + { + const struct pivot_dimension *d = layer_axis->dimensions[i]; + if (d->n_leaves) + n_layers++; + } + + struct table *layers; + if (n_layers > 0) + { + layers = create_aux_table (pt, 1, n_layers, PIVOT_AREA_LAYERS); + size_t y = 0; + for (size_t i = 0; i < layer_axis->n_dimensions; i++) + { + const struct pivot_dimension *d = layer_axis->dimensions[i]; + if (!d->n_leaves) + continue; + + /* XXX This puts in the layer values, but not the variable names. */ + const struct pivot_value *name + = d->data_leaves[layer_indexes[i]]->name; + fill_cell (layers, 0, y, 1, y + 1, + &pt->look->areas[PIVOT_AREA_LAYERS], PIVOT_AREA_LAYERS, + name, footnotes, + pt->show_values, pt->show_variables, false); + y++; + } + } + else + layers = NULL; + + /* Caption. */ + struct table *caption; + if (pt->caption && captionp) + { + caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION); + fill_cell (caption, 0, 0, 1, 1, + &pt->look->areas[PIVOT_AREA_CAPTION], PIVOT_AREA_CAPTION, + pt->caption, footnotes, + pt->show_values, pt->show_variables, false); + } + else + caption = NULL; + free (footnotes); - return table; + *bodyp = body; } void diff --git a/src/output/pivot-output.h b/src/output/pivot-output.h index 495a0a7e88..38d595a8e0 100644 --- a/src/output/pivot-output.h +++ b/src/output/pivot-output.h @@ -17,11 +17,26 @@ #ifndef OUTPUT_PIVOT_OUTPUT_H #define OUTPUT_PIVOT_OUTPUT_H 1 +#include #include +struct footnote; struct pivot_table; - -struct table *pivot_table_to_table (const struct pivot_table *, - const size_t *layer_indexes); +struct table; + +#define PIVOT_OUTPUT_FOR_EACH_LAYER(INDEXES, PT, PRINT) \ + for ((INDEXES) = NULL; \ + ((INDEXES) = pivot_output_next_layer (PT, INDEXES, PRINT)); ) +size_t *pivot_output_next_layer (const struct pivot_table *, + size_t *indexes, bool print); + +void pivot_output (const struct pivot_table *, + const size_t *layer_indexes, + struct table **titlep, + struct table **layersp, + struct table **bodyp, + struct table **captionp, + struct table **footnotesp, + struct footnote ***fp, size_t *nfp); #endif /* output/pivot-output.h */ diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c index 96dd9d2413..d0588365a1 100644 --- a/src/output/pivot-table.c +++ b/src/output/pivot-table.c @@ -994,25 +994,6 @@ pivot_table_is_empty (const struct pivot_table *table) return hmap_is_empty (&table->cells); } -size_t * -pivot_table_next_display_layer (const struct pivot_table *pt, size_t *indexes, - bool print) -{ - const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER]; - if (print && pt->look->print_all_layers) - return pivot_axis_iterator_next (indexes, layer_axis); - else if (!indexes) - { - size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer; - return xmemdup (pt->current_layer, MAX (size, 1)); - } - else - { - free (indexes); - return NULL; - } -} - static unsigned int pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx) { diff --git a/src/output/pivot-table.h b/src/output/pivot-table.h index a62c5b7bae..7c36c43b2d 100644 --- a/src/output/pivot-table.h +++ b/src/output/pivot-table.h @@ -509,13 +509,6 @@ bool pivot_table_is_empty (const struct pivot_table *); /* Output. */ void pivot_table_submit (struct pivot_table *); -/* Layers. */ -#define PIVOT_TABLE_FOR_EACH_DISPLAY_LAYER(INDEXES, PT, PRINT) \ - for ((INDEXES) = NULL; \ - ((INDEXES) = pivot_table_next_display_layer (PT, INDEXES, PRINT)); ) -size_t *pivot_table_next_display_layer (const struct pivot_table *, - size_t *indexes, bool print); - /* Data cells. */ void pivot_table_put (struct pivot_table *, const size_t *dindexes, size_t n, struct pivot_value *); diff --git a/src/output/render.c b/src/output/render.c index 680beb38f8..00ef896105 100644 --- a/src/output/render.c +++ b/src/output/render.c @@ -26,6 +26,7 @@ #include "libpspp/hash-functions.h" #include "libpspp/hmap.h" #include "libpspp/pool.h" +#include "output/pivot-output.h" #include "output/pivot-table.h" #include "output/render.h" #include "output/table-item.h" @@ -1483,12 +1484,11 @@ struct render_pager const struct render_params *params; double scale; - /* An array of "render_page"s to be rendered, in order, vertically. From - the user's perspective, there's only one table per render_pager, but the - implementation treats the title, table body, caption, footnotes, - etc. each as a table, and that's why we have an array here. */ - struct render_page **pages; - size_t n_pages, allocated_pages; + /* An array of "render_page"s to be rendered, in order, vertically. There + may be up to 5 pages, for the pivot table's title, layers, body, + captions, and footnotes. */ + struct render_page *pages[5]; + size_t n_pages; size_t cur_page; struct render_break x_break; @@ -1499,9 +1499,6 @@ static const struct render_page * render_pager_add_table (struct render_pager *p, struct table *table, int min_width) { - if (p->n_pages >= p->allocated_pages) - p->pages = x2nrealloc (p->pages, &p->allocated_pages, sizeof *p->pages); - struct render_page *page = render_page_create (p->params, table, min_width); p->pages[p->n_pages++] = page; return page; @@ -1515,74 +1512,25 @@ render_pager_start_page (struct render_pager *p) render_break_init_empty (&p->y_break); } -static void -add_footnote_page (struct render_pager *p, const struct table_item *item) -{ - struct footnote **f; - size_t n_footnotes = table_collect_footnotes (item, &f); - if (!n_footnotes) - return; - - struct table *t = table_create (1, n_footnotes, 0, 0, 0, 0); - - for (size_t i = 0; i < n_footnotes; i++) - { - table_text_format (t, 0, i, 0, "%s. %s", f[i]->marker, f[i]->content); - table_add_style (t, 0, i, f[i]->style); - } - render_pager_add_table (p, t, 0); - - free (f); -} - -static void -add_table_cell_page (struct render_pager *p, const struct table_cell *cell, - int min_width) -{ - if (!cell) - return; - - struct table *tab = table_create (1, 1, 0, 0, 0, 0); - table_text (tab, 0, 0, 0, cell->text); - for (size_t i = 0; i < cell->n_footnotes; i++) - table_add_footnote (tab, 0, 0, cell->footnotes[i]); - if (cell->style) - tab->styles[0] = table_area_style_clone (tab->container, cell->style); - render_pager_add_table (p, tab, min_width); -} - -static void -add_layers_page (struct render_pager *p, - const struct table_item_layers *layers, int min_width) -{ - if (!layers) - return; - - struct table *tab = table_create (1, layers->n_layers, 0, 0, 0, 0); - for (size_t i = 0; i < layers->n_layers; i++) - { - const struct table_item_layer *layer = &layers->layers[i]; - table_text (tab, 0, i, 0, layer->content); - for (size_t j = 0; j < layer->n_footnotes; j++) - table_add_footnote (tab, 0, i, layer->footnotes[j]); - } - if (layers->style) - tab->styles[0] = table_area_style_clone (tab->container, layers->style); - render_pager_add_table (p, tab, min_width); -} - /* Creates and returns a new render_pager for rendering TABLE_ITEM on the device with the given PARAMS. */ struct render_pager * render_pager_create (const struct render_params *params, - const struct table_item *table_item) + const struct table_item *table_item, + const size_t *layer_indexes) { - const struct table *table = table_item_get_table (table_item); + const struct pivot_table *pt = table_item->pt; + if (!layer_indexes) + layer_indexes = pt->current_layer; + + struct table *title, *layers, *body, *caption, *footnotes; + pivot_output (pt, layer_indexes, &title, &layers, &body, &caption, + &footnotes, NULL, NULL); /* Figure out the width of the body of the table. Use this to determine the base scale. */ - struct render_page *page = render_page_create (params, table_ref (table), 0); - int body_width = table_width (page, H); + struct render_page *body_page = render_page_create (params, body, 0); + int body_width = table_width (body_page, H); double scale = 1.0; if (body_width > params->size[H]) { @@ -1593,7 +1541,7 @@ render_pager_create (const struct render_params *params, else { struct render_break b; - render_break_init (&b, page, H); + render_break_init (&b, render_page_ref (body_page), H); struct render_page *subpage = render_break_next (&b, params->size[H]); body_width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0; @@ -1605,11 +1553,12 @@ render_pager_create (const struct render_params *params, /* Create the pager. */ struct render_pager *p = xmalloc (sizeof *p); *p = (struct render_pager) { .params = params, .scale = scale }; - add_table_cell_page (p, table_item_get_title (table_item), body_width); - add_layers_page (p, table_item_get_layers (table_item), body_width); - render_pager_add_table (p, table_ref (table_item_get_table (table_item)), 0); - add_table_cell_page (p, table_item_get_caption (table_item), 0); - add_footnote_page (p, table_item); + render_pager_add_table (p, title, body_width); + render_pager_add_table (p, layers, body_width); + p->pages[p->n_pages++] = body_page; + render_pager_add_table (p, caption, 0); + render_pager_add_table (p, footnotes, 0); + assert (p->n_pages < sizeof p->pages / sizeof *p->pages); /* If we're shrinking tables to fit the page length, then adjust the scale factor. @@ -1645,7 +1594,6 @@ render_pager_destroy (struct render_pager *p) render_break_destroy (&p->y_break); for (size_t i = 0; i < p->n_pages; i++) render_page_unref (p->pages[i]); - free (p->pages); free (p); } } diff --git a/src/output/render.h b/src/output/render.h index 5df97a1b67..ff73c4e35a 100644 --- a/src/output/render.h +++ b/src/output/render.h @@ -148,7 +148,8 @@ struct render_ops /* An iterator for breaking render_pages into smaller chunks. */ struct render_pager *render_pager_create (const struct render_params *, - const struct table_item *); + const struct table_item *, + const size_t *layer_indexes); void render_pager_destroy (struct render_pager *); bool render_pager_has_next (const struct render_pager *); diff --git a/src/output/table-provider.h b/src/output/table-provider.h index 6aa59d8648..30dcdff75f 100644 --- a/src/output/table-provider.h +++ b/src/output/table-provider.h @@ -27,7 +27,7 @@ enum table_halign table_halign_interpret (enum table_halign, bool numeric); struct footnote { - size_t idx; + //size_t idx; char *content; char *marker; struct table_area_style *style; diff --git a/src/output/table.c b/src/output/table.c index bd017f6b4f..925b707100 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -183,77 +183,6 @@ table_cell_format_footnote_markers (const struct table_cell *cell, ds_put_cstr (s, cell->footnotes[i]->marker); } } - -static struct footnote ** -add_footnotes (struct footnote **refs, size_t n_refs, - struct footnote **footnotes, size_t *allocated, size_t *n) -{ - for (size_t i = 0; i < n_refs; i++) - { - struct footnote *f = refs[i]; - if (f->idx >= *allocated) - { - size_t new_allocated = (f->idx + 1) * 2; - footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes); - while (*allocated < new_allocated) - footnotes[(*allocated)++] = NULL; - } - footnotes[f->idx] = f; - if (f->idx >= *n) - *n = f->idx + 1; - } - return footnotes; -} - -size_t -table_collect_footnotes (const struct table_item *item, - struct footnote ***footnotesp) -{ - struct footnote **footnotes = NULL; - size_t allocated = 0; - size_t n = 0; - - struct table *t = item->table; - for (int y = 0; y < t->n[V]; y++) - { - struct table_cell cell; - for (int x = 0; x < t->n[H]; x = cell.d[TABLE_HORZ][1]) - { - table_get_cell (t, x, y, &cell); - - if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0]) - footnotes = add_footnotes (cell.footnotes, cell.n_footnotes, - footnotes, &allocated, &n); - } - } - - const struct table_cell *title = table_item_get_title (item); - if (title) - 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_cell *caption = table_item_get_caption (item); - if (caption) - footnotes = add_footnotes (caption->footnotes, caption->n_footnotes, - footnotes, &allocated, &n); - - size_t n_nonnull = 0; - for (size_t i = 0; i < n; i++) - if (footnotes[i]) - footnotes[n_nonnull++] = footnotes[i]; - - *footnotesp = footnotes; - return n_nonnull; -} const char * table_halign_to_string (enum table_halign halign) @@ -789,10 +718,7 @@ table_cell_is_empty (const struct table *table, int c, int r) } /* Initializes CELL with the contents of the table cell at column X and row Y - within TABLE. When CELL is no longer needed, the caller is responsible for - freeing it by calling table_cell_free(CELL). - - The caller must ensure that CELL is destroyed before TABLE is unref'ed. */ + within TABLE. */ void table_get_cell (const struct table *t, int x, int y, struct table_cell *cell) { diff --git a/src/output/table.h b/src/output/table.h index f43bd81fa2..5c47ffe88c 100644 --- a/src/output/table.h +++ b/src/output/table.h @@ -19,7 +19,7 @@ /* Tables. -. A table is a rectangular grid of cells. Cells can be joined to form larger + A table is a rectangular grid of cells. Cells can be joined to form larger cells. Rows and columns can be separated by rules of various types. Rows at the top and bottom of a table and columns at the left and right edges of a table can be designated as headers, which means that if the table must be diff --git a/src/output/tex.c b/src/output/tex.c index b606409749..cc46ee3227 100644 --- a/src/output/tex.c +++ b/src/output/tex.c @@ -44,6 +44,8 @@ #include "output/message-item.h" #include "output/options.h" #include "output/output-item-provider.h" +#include "output/pivot-output.h" +#include "output/pivot-table.h" #include "output/table-provider.h" #include "output/table-item.h" #include "output/text-item.h" @@ -401,48 +403,60 @@ tex_put_table_cell (struct tex_driver *tex, const struct table_cell *cell) } static void -tex_output_table (struct tex_driver *tex, const struct table_item *item) +tex_output_table_layer (struct tex_driver *tex, const struct pivot_table *pt, + const size_t *layer_indexes) { /* Tables are rendered in TeX with the \halign command. This is described in the TeXbook Ch. 22 */ - - const struct table *t = table_item_get_table (item); + struct table *title, *layers, *body, *caption; + struct footnote **footnotes; + size_t n_footnotes; + pivot_output (pt, layer_indexes, &title, &layers, &body, + &caption, NULL, &footnotes, &n_footnotes); shipout (&tex->token_list, "\n{\\parindent=0pt\n"); - const struct table_cell *caption = table_item_get_caption (item); if (caption) { shipout (&tex->token_list, "{\\sl "); - tex_escape_string (tex, caption->text, false); + struct table_cell cell; + table_get_cell (caption, 0, 0, &cell); + tex_put_table_cell (tex, &cell); shipout (&tex->token_list, "}\n\n"); } - struct footnote **f; - size_t n_footnotes = table_collect_footnotes (item, &f); - const struct table_cell *title = table_item_get_title (item); - const struct table_item_layers *layers = table_item_get_layers (item); if (title || layers) { if (title) { shipout (&tex->token_list, "{\\bf "); - tex_put_table_cell (tex, title); - shipout (&tex->token_list, "}"); + struct table_cell cell; + table_get_cell (title, 0, 0, &cell); + tex_put_table_cell (tex, &cell); + shipout (&tex->token_list, "}\\par\n"); } + if (layers) - abort (); - shipout (&tex->token_list, "\\par\n"); + { + for (size_t y = 0; y < layers->n[V]; y++) + { + shipout (&tex->token_list, "{"); + struct table_cell cell; + table_get_cell (layers, 0, y, &cell); + tex_put_table_cell (tex, &cell); + shipout (&tex->token_list, "}\\par\n"); + } + } } shipout (&tex->token_list, "\\offinterlineskip\\halign{\\strut%%\n"); /* Generate the preamble */ - for (int x = 0; x < t->n[H]; ++x) + for (int x = 0; x < body->n[H]; ++x) { - shipout (&tex->token_list, "{\\vbox{\\cell{%d}#}}", t->n[H]); + shipout (&tex->token_list, "{\\vbox{\\cell{%d}#}}", body->n[H]); - if (x < t->n[H] - 1) + if (x < body->n[H] - 1) { shipout (&tex->token_list, "\\hskip\\psppcolumnspace\\hfil"); shipout (&tex->token_list, "&\\vrule\n"); @@ -452,17 +466,17 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item) } /* Emit the row data */ - for (int y = 0; y < t->n[V]; y++) + for (int y = 0; y < body->n[V]; y++) { enum { H = TABLE_HORZ, V = TABLE_VERT }; - bool is_column_header = y < t->h[V][0] || y >= t->n[V] - t->h[V][1]; + bool is_column_header = y < body->h[V][0] || y >= body->n[V] - body->h[V][1]; int prev_x = -1; int skipped = 0; - for (int x = 0; x < t->n[H];) + for (int x = 0; x < body->n[H];) { struct table_cell cell; - table_get_cell (t, x, y, &cell); + table_get_cell (body, x, y, &cell); int colspan = table_cell_colspan (&cell); if (x > 0) @@ -475,10 +489,10 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item) if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0]) goto next_1; - /* bool is_header = (y < t->h[V][0] */ - /* || y >= t->n[V] - t->h[V][1] */ - /* || x < t->h[H][0] */ - /* || x >= t->n[H] - t->h[H][1]); */ + /* bool is_header = (y < body->h[V][0] */ + /* || y >= body->n[V] - body->h[V][1] */ + /* || x < body->h[H][0] */ + /* || x >= body->n[H] - body->h[H][1]); */ enum table_halign halign = table_halign_interpret (cell.style->cell_style.halign, @@ -530,13 +544,26 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item) for (int i = 0; i < n_footnotes; ++i) { shipout (&tex->token_list, "$^{"); - tex_escape_string (tex, f[i]->marker, false); + tex_escape_string (tex, footnotes[i]->marker, false); shipout (&tex->token_list, "}$"); - tex_escape_string (tex, f[i]->content, false); + tex_escape_string (tex, footnotes[i]->content, false); } - free (f); shipout (&tex->token_list, "}\n\\vskip 3ex\n\n"); + + table_unref (title); + table_unref (layers); + table_unref (body); + table_unref (caption); + free (footnotes); +} + +static void +tex_output_table (struct tex_driver *tex, const struct table_item *item) +{ + size_t *layer_indexes; + PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true) + tex_output_table_layer (tex, item->pt, layer_indexes); } struct output_driver_factory tex_driver_factory = diff --git a/src/output/text-item.c b/src/output/text-item.c index ced77d2f64..167c4caadf 100644 --- a/src/output/text-item.c +++ b/src/output/text-item.c @@ -175,7 +175,7 @@ text_item_to_table_item (struct text_item *text_item) pivot_value_set_font_style (content, &text_item->style); pivot_table_put1 (table, 0, content); - return table; + return table_item_create (table); } static const char * diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index 70b62b1c5a..c6ee8c40bf 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -33,6 +33,7 @@ #include "output/message-item.h" #include "output/output-item.h" #include "output/output-item-provider.h" +#include "output/pivot-table.h" #include "output/table-item.h" #include "output/text-item.h" @@ -164,6 +165,7 @@ get_xr_fsm_style (struct psppire_output_view *view) [XR_FONT_FIXED] = ff, }, .use_system_colors = true, + .object_spacing = XR_POINT * 12, .font_resolution = 96.0, }; @@ -364,7 +366,7 @@ rerender (struct psppire_output_view *view) if (is_table_item (item->item)) { const struct table_item *ti = to_table_item (item->item); - gtk_widget_set_tooltip_text (item->drawing_area, ti->notes); + gtk_widget_set_tooltip_text (item->drawing_area, ti->pt->notes); } { @@ -972,7 +974,6 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi [V] = { margins[V][0], margins[V][1] }, }, .initial_page_number = 1, - .object_spacing = 12 * XR_POINT, }; view->fsm_style = xmalloc (sizeof *view->fsm_style); @@ -987,6 +988,7 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi }, .fg = CELL_COLOR_BLACK, .use_system_colors = false, + .object_spacing = 12 * XR_POINT, .font_resolution = 72.0 }; -- 2.30.2