output: Improve comments.
[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, NULL, NULL, pt->notes);
564
565   if (pt->title && pt->show_title)
566     {
567       struct table_item_text *title = pivot_value_to_table_item_text (
568         pt->title, &pt->look->areas[PIVOT_AREA_TITLE], footnotes,
569         pt->show_values, pt->show_variables);
570       table_item_set_title (ti, title);
571       table_item_text_destroy (title);
572     }
573
574   const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
575   struct table_item_layers *layers = NULL;
576   for (size_t i = 0; i < layer_axis->n_dimensions; i++)
577     {
578       const struct pivot_dimension *d = layer_axis->dimensions[i];
579       if (d->n_leaves)
580         {
581           if (!layers)
582             {
583               layers = xzalloc (sizeof *layers);
584               layers->style = table_area_style_override (
585                 NULL, &pt->look->areas[PIVOT_AREA_LAYERS], NULL, NULL, false);
586               layers->layers = xnmalloc (layer_axis->n_dimensions,
587                                          sizeof *layers->layers);
588             }
589
590           const struct pivot_value *name
591             = d->data_leaves[layer_indexes[i]]->name;
592           struct table_item_layer *layer = &layers->layers[layers->n_layers++];
593           struct string s = DS_EMPTY_INITIALIZER;
594           pivot_value_format_body (name, pt->show_values, pt->show_variables,
595                                    &s);
596           layer->content = ds_steal_cstr (&s);
597           layer->n_footnotes = 0;
598           layer->footnotes = xnmalloc (name->n_footnotes,
599                                        sizeof *layer->footnotes);
600           for (size_t i = 0; i < name->n_footnotes; i++)
601             {
602               struct footnote *f = footnotes[name->footnotes[i]->idx];
603               if (f)
604                 layer->footnotes[layer->n_footnotes++] = f;
605             }
606         }
607     }
608   if (layers)
609     {
610       table_item_set_layers (ti, layers);
611       table_item_layers_destroy (layers);
612     }
613
614   if (pt->caption && pt->show_caption)
615     {
616       struct table_item_text *caption = pivot_value_to_table_item_text (
617         pt->caption, &pt->look->areas[PIVOT_AREA_CAPTION], footnotes,
618         pt->show_values, pt->show_variables);
619       table_item_set_caption (ti, caption);
620       table_item_text_destroy (caption);
621     }
622
623   free (footnotes);
624   ti->pt = pivot_table_ref (pt);
625
626   table_item_submit (ti);
627 }
628
629 void
630 pivot_table_submit (struct pivot_table *pt)
631 {
632   pivot_table_assign_label_depth (CONST_CAST (struct pivot_table *, pt));
633
634   int old_decimal = settings_get_decimal_char (FMT_COMMA);
635   if (pt->decimal == '.' || pt->decimal == ',')
636     settings_set_decimal_char (pt->decimal);
637
638   if (pt->look->print_all_layers)
639     {
640       size_t *layer_indexes;
641
642       PIVOT_AXIS_FOR_EACH (layer_indexes, &pt->axes[PIVOT_AXIS_LAYER])
643         {
644           if (pt->look->paginate_layers)
645             page_eject_item_submit (page_eject_item_create ());
646           pivot_table_submit_layer (pt, layer_indexes);
647         }
648     }
649   else
650     pivot_table_submit_layer (pt, pt->current_layer);
651
652   settings_set_decimal_char (old_decimal);
653
654   pivot_table_unref (pt);
655 }