table-item: Remove barely used parameters from table_item_create().
[pspp] / src / output / pivot-output.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2018 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include "output/pivot-table.h"
22
23 #include "data/settings.h"
24 #include "libpspp/assertion.h"
25 #include "libpspp/pool.h"
26 #include "output/table.h"
27 #include "output/page-eject-item.h"
28 #include "output/table-item.h"
29 #include "output/text-item.h"
30 #include "output/table-provider.h"
31
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34
35 #define H TABLE_HORZ
36 #define V TABLE_VERT
37
38 static const struct pivot_category *
39 find_category (const struct pivot_dimension *d, int dim_index,
40                const size_t *indexes, int row_ofs)
41 {
42   size_t index = indexes[dim_index];
43   assert (index < d->n_leaves);
44   for (const struct pivot_category *c = d->presentation_leaves[index];
45        c; c = c->parent)
46     {
47       /* A category can covert multiple rows.  Only return the category for its
48          top row. */
49       if (row_ofs == c->extra_depth)
50         return c;
51
52       row_ofs -= 1 + c->extra_depth;
53       if (row_ofs < 0)
54         return NULL;
55     }
56   return NULL;
57 }
58
59 static struct table_area_style *
60 table_area_style_override (struct pool *pool,
61                            const struct table_area_style *in,
62                            const struct cell_style *cell_,
63                            const struct font_style *font_,
64                            bool rotate_label)
65 {
66   const struct cell_style *cell = cell_ ? cell_ : &in->cell_style;
67   const struct font_style *font = font_ ? font_ : &in->font_style;
68
69   struct table_area_style *out = (pool
70                             ? pool_alloc (pool, sizeof *out)
71                             : xmalloc (sizeof *out));
72   *out = (struct table_area_style) {
73     .cell_style.halign = rotate_label ? TABLE_HALIGN_CENTER : cell->halign,
74     .cell_style.valign = rotate_label ? TABLE_VALIGN_CENTER : cell->valign,
75     .cell_style.decimal_offset = cell->decimal_offset,
76     .cell_style.margin[H][0] = cell->margin[H][0],
77     .cell_style.margin[H][1] = cell->margin[H][1],
78     .cell_style.margin[V][0] = cell->margin[V][0],
79     .cell_style.margin[V][1] = cell->margin[V][1],
80     .font_style.fg[0] = font->fg[0],
81     .font_style.fg[1] = font->fg[1],
82     .font_style.bg[0] = font->bg[0],
83     .font_style.bg[1] = font->bg[1],
84     .font_style.typeface = (font->typeface
85                             ? pool_strdup (pool, font->typeface)
86                             : NULL),
87     .font_style.size = font->size,
88     .font_style.bold = font->bold,
89     .font_style.italic = font->italic,
90     .font_style.underline = font->underline,
91     .font_style.markup = font->markup,
92   };
93   return out;
94 }
95
96 static void
97 fill_cell (struct table *t, int x1, int y1, int x2, int y2,
98            const struct table_area_style *style, int style_idx,
99            const struct pivot_value *value, struct footnote **footnotes,
100            enum settings_value_show show_values,
101            enum settings_value_show show_variables,
102            bool rotate_label)
103 {
104
105   struct string s = DS_EMPTY_INITIALIZER;
106   int opts = style_idx << TAB_STYLE_SHIFT;
107   if (value)
108     {
109       bool numeric = pivot_value_format_body (value, show_values,
110                                               show_variables, &s);
111       if (numeric)
112         opts |= TAB_NUMERIC;
113       if (value->font_style && value->font_style->markup)
114         opts |= TAB_MARKUP;
115       if (rotate_label)
116         opts |= TAB_ROTATE;
117     }
118   table_joint_text (t, x1, y1, x2, y2, opts, ds_cstr (&s));
119   ds_destroy (&s);
120
121   if (value)
122     {
123       if (value->cell_style || value->font_style || rotate_label)
124         table_add_style (t, x1, y1,
125                          table_area_style_override (t->container, style,
126                                                     value->cell_style,
127                                                     value->font_style,
128                                                     rotate_label));
129
130       for (size_t i = 0; i < value->n_footnotes; i++)
131         {
132           struct footnote *f = footnotes[value->footnotes[i]->idx];
133           if (f)
134             table_add_footnote (t, x1, y1, f);
135         }
136
137       if (value->n_subscripts)
138         table_add_subscripts (t, x1, y1,
139                               value->subscripts, value->n_subscripts);
140     }
141 }
142
143 static struct table_item_text *
144 pivot_value_to_table_item_text (const struct pivot_value *value,
145                                 const struct table_area_style *area,
146                                 struct footnote **footnotes,
147                                 enum settings_value_show show_values,
148                                 enum settings_value_show show_variables)
149 {
150   if (!value)
151     return NULL;
152
153   struct string s = DS_EMPTY_INITIALIZER;
154   pivot_value_format_body (value, show_values, show_variables, &s);
155
156   struct table_item_text *text = xmalloc (sizeof *text);
157   *text = (struct table_item_text) {
158     .content = ds_steal_cstr (&s),
159     .footnotes = xnmalloc (value->n_footnotes, sizeof *text->footnotes),
160     .style = table_area_style_override (
161       NULL, area, value->cell_style, value->font_style, false),
162   };
163
164   for (size_t i = 0; i < value->n_footnotes; i++)
165     {
166       struct footnote *f = footnotes[value->footnotes[i]->idx];
167       if (f)
168         text->footnotes[text->n_footnotes++] = f;
169     }
170
171   return text;
172 }
173
174 static int
175 get_table_rule (const struct table_border_style *styles,
176                 enum pivot_border style_idx)
177 {
178   return styles[style_idx].stroke | (style_idx << TAB_RULE_STYLE_SHIFT);
179 }
180
181 static void
182 draw_line (struct table *t, const struct table_border_style *styles,
183            enum pivot_border style_idx,
184            enum table_axis axis, int a, int b0, int b1)
185 {
186   int rule = get_table_rule (styles, style_idx);
187   if (axis == H)
188     table_hline (t, rule, b0, b1, a);
189   else
190     table_vline (t, rule, a, b0, b1);
191 }
192
193 /* Fills row or column headings into T.
194
195    This function uses terminology and variable names for column headings, but
196    it also applies to row headings because it uses variables for the
197    differences, e.g. when for column headings it would use the H axis, it
198    instead uses 'h', which is set to H for column headings and V for row
199    headings.  */
200 static void
201 compose_headings (struct table *t,
202                   const struct pivot_axis *a_axis, enum table_axis a,
203                   const struct pivot_axis *b_axis,
204                   const struct table_border_style *borders,
205                   enum pivot_border dim_col_horz,
206                   enum pivot_border dim_col_vert,
207                   enum pivot_border cat_col_horz,
208                   enum pivot_border cat_col_vert,
209                   const size_t *column_enumeration, size_t n_columns,
210                   const struct table_area_style *label_style,
211                   int label_style_idx,
212                   const struct table_area_style *corner_style,
213                   struct footnote **footnotes,
214                   enum settings_value_show show_values,
215                   enum settings_value_show show_variables,
216                   bool rotate_inner_labels, bool rotate_outer_labels)
217 {
218   enum table_axis b = !a;
219   int b_size = a_axis->label_depth;
220   int a_ofs = b_axis->label_depth;
221
222   if (!a_axis->n_dimensions || !n_columns || !b_size)
223     return;
224
225   const int stride = MAX (1, a_axis->n_dimensions);
226
227   /* Below, we're going to iterate through the dimensions.  Each dimension
228      occupies one or more rows in the heading.  'top_row' is the top row of
229      these (and 'top_row + d->label_depth - 1' is the bottom row). */
230   int top_row = 0;
231
232   /* We're going to iterate through dimensions and the rows that label them
233      from top to bottom (from outer to inner dimensions).  As we move downward,
234      we start drawing vertical rules to separate categories and groups.  After
235      we start drawing a vertical rule in a particular horizontal position, it
236      continues until the bottom of the heading.  vrules[pos] indicates whether,
237      in our current row, we have already started drawing a vertical rule in
238      horizontal position 'pos'.  (There are n_columns + 1 horizontal positions.
239      We allocate all of them for convenience below but only the inner n_columns
240      - 1 of them really matter.)
241
242      Here's an example that shows how vertical rules continue all the way
243      downward:
244
245      +-----------------------------------------------------+ __
246      |                         bbbb                        |  |
247      +-----------------+-----------------+-----------------+  |dimension "bbbb"
248      |      bbbb1      |      bbbb2      |      bbbb3      | _|
249      +-----------------+-----------------+-----------------+ __
250      |       aaaa      |       aaaa      |       aaaa      |  |
251      +-----+-----+-----+-----+-----+-----+-----+-----+-----+  |dimension "aaaa"
252      |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3| _|
253      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
254
255      ^     ^     ^     ^     ^     ^     ^     ^     ^     ^
256      |     |     |     |     |     |     |     |     |     |
257      0     1     2     3     4     5     6     7     8     9
258      |___________________vrules[] indexes__________________|
259
260      Our data structures are more naturally iterated from bottom to top (inner
261      to outer dimensions).  A previous version of this code actually worked
262      like that, but it didn't draw all of the vertical lines correctly as shown
263      above.  It ended up rendering the above heading much like shown below,
264      which isn't what users expect.  The "aaaa" label really needs to be shown
265      three times for clarity:
266
267      +-----------------------------------------------------+
268      |                         bbbb                        |
269      +-----------------+-----------------+-----------------+
270      |      bbbb1      |      bbbb2      |      bbbb3      |
271      +-----------------+-----------------+-----------------+
272      |                 |       aaaa      |                 |
273      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
274      |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|
275      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
276   */
277   bool *vrules = xzalloc (n_columns + 1);
278   vrules[0] = vrules[n_columns] = true;
279   for (int dim_index = a_axis->n_dimensions; --dim_index >= 0; )
280     {
281       const struct pivot_dimension *d = a_axis->dimensions[dim_index];
282       if (d->hide_all_labels)
283         continue;
284
285       for (int row_ofs = 0; row_ofs < d->label_depth; row_ofs++)
286         {
287           for (size_t x1 = 0; x1 < n_columns;)
288             {
289               const struct pivot_category *c = find_category (
290                 d, dim_index, column_enumeration + x1 * stride,
291                 d->label_depth - row_ofs - 1);
292               if (!c)
293                 {
294                   x1++;
295                   continue;
296                 }
297
298               size_t x2;
299               for (x2 = x1 + 1; x2 < n_columns; x2++)
300                 {
301                   if (vrules[x2])
302                     break;
303                   const struct pivot_category *c2 = find_category (
304                     d, dim_index, column_enumeration + x2 * stride,
305                     d->label_depth - row_ofs - 1);
306                   if (c != c2)
307                     break;
308                 }
309
310               int y1 = top_row + row_ofs;
311               int y2 = top_row + row_ofs + c->extra_depth + 1;
312               bool is_outer_row = y1 == 0;
313               bool is_inner_row = y2 == b_size;
314               if (pivot_category_is_leaf (c) || c->show_label)
315                 {
316                   int bb[TABLE_N_AXES][2];
317                   bb[a][0] = x1 + a_ofs;
318                   bb[a][1] = x2 + a_ofs - 1;
319                   bb[b][0] = y1;
320                   bb[b][1] = y2 - 1;
321                   bool rotate = ((rotate_inner_labels && is_inner_row)
322                                  || (rotate_outer_labels && is_outer_row));
323                   fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
324                              label_style, label_style_idx, c->name, footnotes,
325                              show_values, show_variables, rotate);
326
327                   /* Draw all the vertical lines in our running example, other
328                      than the far left and far right ones.  Only the ones that
329                      start in the last row of the heading are drawn with the
330                      "category" style, the rest with the "dimension" style,
331                      e.g. only the # below are category style:
332
333                      +-----------------------------------------------------+
334                      |                         bbbb                        |
335                      +-----------------+-----------------+-----------------+
336                      |      bbbb1      |      bbbb2      |      bbbb3      |
337                      +-----------------+-----------------+-----------------+
338                      |       aaaa      |       aaaa      |       aaaa      |
339                      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
340                      |aaaa1#aaaa2#aaaa3|aaaa1#aaaa2#aaaa3|aaaa1#aaaa2#aaaa3|
341                      +-----+-----+-----+-----+-----+-----+-----+-----+-----+
342                   */
343                   enum pivot_border style
344                     = (y1 == b_size - 1 ? cat_col_vert : dim_col_vert);
345                   if (!vrules[x2])
346                     {
347                       draw_line (t, borders, style, b, x2 + a_ofs, y1,
348                                  t->n[b] - 1);
349                       vrules[x2] = true;
350                     }
351                   if (!vrules[x1])
352                     {
353                       draw_line (t, borders, style, b, x1 + a_ofs, y1,
354                                  t->n[b] - 1);
355                       vrules[x1] = true;
356                     }
357                 }
358
359               /* Draws the horizontal lines within a dimension, that is, those
360                  that separate a separating a category (or group) from its
361                  parent group or dimension's label.  Our running example
362                  doesn't have groups but the ==== lines below show the
363                  separators between categories and their dimension label:
364
365                  +-----------------------------------------------------+
366                  |                         bbbb                        |
367                  +=================+=================+=================+
368                  |      bbbb1      |      bbbb2      |      bbbb3      |
369                  +-----------------+-----------------+-----------------+
370                  |       aaaa      |       aaaa      |       aaaa      |
371                  +=====+=====+=====+=====+=====+=====+=====+=====+=====+
372                  |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|
373                  +-----+-----+-----+-----+-----+-----+-----+-----+-----+
374               */
375               if (c->parent && c->parent->show_label)
376                 draw_line (t, borders, cat_col_horz, a, y1,
377                            x1 + a_ofs, x2 + a_ofs - 1);
378               x1 = x2;
379             }
380         }
381
382       if (d->root->show_label_in_corner && a_ofs > 0)
383         {
384           int bb[TABLE_N_AXES][2];
385           bb[a][0] = 0;
386           bb[a][1] = a_ofs - 1;
387           bb[b][0] = top_row;
388           bb[b][1] = top_row + d->label_depth - 1;
389           fill_cell (t, bb[H][0], bb[V][0], bb[H][1], bb[V][1],
390                      corner_style, PIVOT_AREA_CORNER, d->root->name, footnotes,
391                      show_values, show_variables, false);
392         }
393
394       /* Draw the horizontal line between dimensions, e.g. the ===== line here:
395
396          +-----------------------------------------------------+ __
397          |                         bbbb                        |  |
398          +-----------------+-----------------+-----------------+  |dim "bbbb"
399          |      bbbb1      |      bbbb2      |      bbbb3      | _|
400          +=================+=================+=================+ __
401          |       aaaa      |       aaaa      |       aaaa      |  |
402          +-----+-----+-----+-----+-----+-----+-----+-----+-----+  |dim "aaaa"
403          |aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3|aaaa1|aaaa2|aaaa3| _|
404          +-----+-----+-----+-----+-----+-----+-----+-----+-----+
405       */
406       if (dim_index != a_axis->n_dimensions - 1)
407         draw_line (t, borders, dim_col_horz, a, top_row, a_ofs,
408                    t->n[a] - 1);
409       top_row += d->label_depth;
410     }
411   free (vrules);
412 }
413
414 static void
415 pivot_table_submit_layer (const struct pivot_table *pt,
416                           const size_t *layer_indexes)
417 {
418   const size_t *pindexes[PIVOT_N_AXES]
419     = { [PIVOT_AXIS_LAYER] = layer_indexes };
420
421   size_t body[TABLE_N_AXES];
422   size_t *column_enumeration = pivot_table_enumerate_axis (
423     pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &body[H]);
424   size_t *row_enumeration = pivot_table_enumerate_axis (
425     pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &body[V]);
426
427   int stub[TABLE_N_AXES] = {
428     [H] = pt->axes[PIVOT_AXIS_ROW].label_depth,
429     [V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth,
430   };
431   struct table *table = table_create (body[H] + stub[H],
432                                       body[V] + stub[V],
433                                       stub[H], 0, stub[V], 0);
434
435   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
436     table->styles[i] = table_area_style_override (
437       table->container, &pt->look->areas[i], NULL, NULL, false);
438
439   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
440     {
441       const struct table_border_style *in = &pt->look->borders[i];
442       table->rule_colors[i] = pool_alloc (table->container,
443                                           sizeof *table->rule_colors[i]);
444       struct cell_color *out = table->rule_colors[i];
445       out->alpha = in->color.alpha;
446       out->r = in->color.r;
447       out->g = in->color.g;
448       out->b = in->color.b;
449     }
450
451   struct footnote **footnotes = XCALLOC (pt->n_footnotes,  struct footnote *);
452   for (size_t i = 0; i < pt->n_footnotes; i++)
453     {
454       const struct pivot_footnote *pf = pt->footnotes[i];
455
456       if (!pf->show)
457         continue;
458
459       char *content = pivot_value_to_string (pf->content, pt->show_values,
460                                              pt->show_variables);
461       char *marker = pivot_value_to_string (pf->marker, pt->show_values,
462                                             pt->show_variables);
463       footnotes[i] = table_create_footnote (
464         table, i, content, marker,
465         table_area_style_override (table->container,
466                                    &pt->look->areas[PIVOT_AREA_FOOTER],
467                                    pf->content->cell_style,
468                                    pf->content->font_style,
469                                    false));
470       free (marker);
471       free (content);
472     }
473
474   compose_headings (table,
475                     &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
476                     pt->look->borders,
477                     PIVOT_BORDER_DIM_COL_HORZ,
478                     PIVOT_BORDER_DIM_COL_VERT,
479                     PIVOT_BORDER_CAT_COL_HORZ,
480                     PIVOT_BORDER_CAT_COL_VERT,
481                     column_enumeration, body[H],
482                     &pt->look->areas[PIVOT_AREA_COLUMN_LABELS],
483                     PIVOT_AREA_COLUMN_LABELS,
484                     &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
485                     pt->show_values, pt->show_variables,
486                     pt->rotate_outer_row_labels, false);
487
488   compose_headings (table,
489                     &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
490                     pt->look->borders,
491                     PIVOT_BORDER_DIM_ROW_VERT,
492                     PIVOT_BORDER_DIM_ROW_HORZ,
493                     PIVOT_BORDER_CAT_ROW_VERT,
494                     PIVOT_BORDER_CAT_ROW_HORZ,
495                     row_enumeration, body[V],
496                     &pt->look->areas[PIVOT_AREA_ROW_LABELS],
497                     PIVOT_AREA_ROW_LABELS,
498                     &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
499                     pt->show_values, pt->show_variables,
500                     false, pt->rotate_inner_column_labels);
501
502   size_t *dindexes = XCALLOC (pt->n_dimensions, size_t);
503   size_t y = 0;
504   PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_ROW], row_enumeration,
505                               &pt->axes[PIVOT_AXIS_ROW])
506     {
507       size_t x = 0;
508       PIVOT_ENUMERATION_FOR_EACH (pindexes[PIVOT_AXIS_COLUMN],
509                                   column_enumeration,
510                                   &pt->axes[PIVOT_AXIS_COLUMN])
511         {
512           pivot_table_convert_indexes_ptod (pt, pindexes, dindexes);
513           const struct pivot_value *value = pivot_table_get (pt, dindexes);
514           fill_cell (table,
515                      x + stub[H], y + stub[V],
516                      x + stub[H], y + stub[V],
517                      &pt->look->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA,
518                      value, footnotes,
519                      pt->show_values, pt->show_variables, false);
520
521           x++;
522         }
523
524       y++;
525     }
526   free (dindexes);
527
528   if ((pt->corner_text || !pt->look->row_labels_in_corner)
529       && stub[H] && stub[V])
530     fill_cell (table, 0, 0, stub[H] - 1, stub[V] - 1,
531                &pt->look->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER,
532                pt->corner_text, footnotes,
533                pt->show_values, pt->show_variables, false);
534
535   if (table->n[H] && table->n[V])
536     {
537       table_hline (
538         table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP),
539         0, table->n[H] - 1, 0);
540       table_hline (
541         table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM),
542         0, table->n[H] - 1, table->n[V]);
543       table_vline (
544         table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT),
545         0, 0, table->n[V] - 1);
546       table_vline (
547         table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT),
548         table->n[H], 0, table->n[V] - 1);
549
550       if (stub[V])
551         table_hline (
552           table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP),
553           0, table->n[H] - 1, stub[V]);
554       if (stub[H])
555         table_vline (
556           table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT),
557           stub[H], 0, table->n[V] - 1);
558
559     }
560   free (column_enumeration);
561   free (row_enumeration);
562
563   struct table_item *ti = table_item_create (table);
564
565   if (pt->notes)
566     table_item_set_notes (ti, pt->notes);
567
568   if (pt->title && pt->show_title)
569     {
570       struct table_item_text *title = pivot_value_to_table_item_text (
571         pt->title, &pt->look->areas[PIVOT_AREA_TITLE], footnotes,
572         pt->show_values, pt->show_variables);
573       table_item_set_title (ti, title);
574       table_item_text_destroy (title);
575     }
576
577   const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
578   struct table_item_layers *layers = NULL;
579   for (size_t i = 0; i < layer_axis->n_dimensions; i++)
580     {
581       const struct pivot_dimension *d = layer_axis->dimensions[i];
582       if (d->n_leaves)
583         {
584           if (!layers)
585             {
586               layers = xzalloc (sizeof *layers);
587               layers->style = table_area_style_override (
588                 NULL, &pt->look->areas[PIVOT_AREA_LAYERS], NULL, NULL, false);
589               layers->layers = xnmalloc (layer_axis->n_dimensions,
590                                          sizeof *layers->layers);
591             }
592
593           const struct pivot_value *name
594             = d->data_leaves[layer_indexes[i]]->name;
595           struct table_item_layer *layer = &layers->layers[layers->n_layers++];
596           struct string s = DS_EMPTY_INITIALIZER;
597           pivot_value_format_body (name, pt->show_values, pt->show_variables,
598                                    &s);
599           layer->content = ds_steal_cstr (&s);
600           layer->n_footnotes = 0;
601           layer->footnotes = xnmalloc (name->n_footnotes,
602                                        sizeof *layer->footnotes);
603           for (size_t i = 0; i < name->n_footnotes; i++)
604             {
605               struct footnote *f = footnotes[name->footnotes[i]->idx];
606               if (f)
607                 layer->footnotes[layer->n_footnotes++] = f;
608             }
609         }
610     }
611   if (layers)
612     {
613       table_item_set_layers (ti, layers);
614       table_item_layers_destroy (layers);
615     }
616
617   if (pt->caption && pt->show_caption)
618     {
619       struct table_item_text *caption = pivot_value_to_table_item_text (
620         pt->caption, &pt->look->areas[PIVOT_AREA_CAPTION], footnotes,
621         pt->show_values, pt->show_variables);
622       table_item_set_caption (ti, caption);
623       table_item_text_destroy (caption);
624     }
625
626   free (footnotes);
627   ti->pt = pivot_table_ref (pt);
628
629   table_item_submit (ti);
630 }
631
632 void
633 pivot_table_submit (struct pivot_table *pt)
634 {
635   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, pt));
636
637   int old_decimal = settings_get_decimal_char (FMT_COMMA);
638   if (pt->decimal == '.' || pt->decimal == ',')
639     settings_set_decimal_char (pt->decimal);
640
641   if (pt->look->print_all_layers)
642     {
643       size_t *layer_indexes;
644
645       PIVOT_AXIS_FOR_EACH (layer_indexes, &pt->axes[PIVOT_AXIS_LAYER])
646         {
647           if (pt->look->paginate_layers)
648             page_eject_item_submit (page_eject_item_create ());
649           pivot_table_submit_layer (pt, layer_indexes);
650         }
651     }
652   else
653     pivot_table_submit_layer (pt, pt->current_layer);
654
655   settings_set_decimal_char (old_decimal);
656
657   pivot_table_unref (pt);
658 }