}
}
+void
+pivot_area_get_default_style (enum pivot_area area, struct area_style *style)
+{
+#define STYLE(BOLD, H, V, L, R, T, B) { \
+ .cell_style = { \
+ .halign = TABLE_HALIGN_##H, \
+ .valign = TABLE_VALIGN_##V, \
+ .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
+ [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
+ }, \
+ .font_style = { \
+ .bold = BOLD, \
+ .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
+ .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
+ .size = 9, \
+ }, \
+ }
+ static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
+ [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
+ [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
+ [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
+ [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
+ [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
+ [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
+ [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
+ [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
+ };
+#undef STYLE
+
+ *style = default_area_styles[area];
+ style->font_style.typeface = xstrdup ("SansSerif");
+}
+
+void
+pivot_border_get_default_style (enum pivot_border border,
+ struct table_border_style *style)
+{
+ static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
+ [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
+ };
+ *style = (struct table_border_style) {
+ .stroke = default_strokes[border],
+ .color = CELL_COLOR_BLACK,
+ };
+}
+
/* Returns the name of BORDER. */
const char *
pivot_border_to_string (enum pivot_border border)
axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
axis->dimensions[axis->n_dimensions++] = d;
- /* XXX extent and label_depth need to be calculated later. */
+ /* axis->extent and axis->label_depth will be calculated later. */
return d;
}
return rc != NULL;
}
\f
-/* One piece of data within a pivot table. */
-struct pivot_cell
- {
- struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
- struct pivot_value *value;
- unsigned int idx[]; /* One index per table dimension. */
- };
-
/* Pivot tables. */
/* Creates and returns a new pivot table with the given TITLE. TITLE should be
pivot_table_create__ (struct pivot_value *title)
{
struct pivot_table *table = xzalloc (sizeof *table);
+ table->ref_cnt = 1;
table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
table->title = title;
- /* Set default area styles. */
-#define STYLE(BOLD, H, V, L, R, T, B) { \
- .cell_style = { \
- .halign = TABLE_HALIGN_##H, \
- .valign = TABLE_VALIGN_##V, \
- .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
- [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
- }, \
- .font_style = { \
- .bold = BOLD, \
- .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
- .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
- }, \
- }
- static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
- [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
- [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
- [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
- [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
- [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
- [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
- [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
- [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
- };
-#undef STYLE
+ table->sizing[TABLE_HORZ].range[0] = 50;
+ table->sizing[TABLE_HORZ].range[1] = 72;
+ table->sizing[TABLE_VERT].range[0] = 36;
+ table->sizing[TABLE_VERT].range[1] = 120;
+
for (size_t i = 0; i < PIVOT_N_AREAS; i++)
- table->areas[i] = default_area_styles[i];
+ pivot_area_get_default_style (i, &table->areas[i]);
/* Set default border styles. */
static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
return table;
}
-/* Destroys TABLE and frees everything it points to. */
+/* Increases TABLE's reference count, indicating that it has an additional
+ owner. A pivot table that is shared among multiple owners must not be
+ modified. */
+struct pivot_table *
+pivot_table_ref (const struct pivot_table *table_)
+{
+ struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
+ table->ref_cnt++;
+ return table;
+}
+
+/* Decreases TABLE's reference count, indicating that it has one fewer owner.
+ If TABLE no longer has any owners, it is freed. */
void
-pivot_table_destroy (struct pivot_table *table)
+pivot_table_unref (struct pivot_table *table)
{
if (!table)
return;
+ assert (table->ref_cnt > 0);
+ if (--table->ref_cnt)
+ return;
free (table->current_layer);
free (table->table_look);
free (table);
}
+/* Returns true if TABLE has more than one owner. A pivot table that is shared
+ among multiple owners must not be modified. */
+bool
+pivot_table_is_shared (const struct pivot_table *table)
+{
+ return table->ref_cnt > 1;
+}
+
/* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
WV, which should be the weight variable for the dictionary whose data or
statistics are being put into TABLE.
return pivot_value_new_user_text (text, -1);
}
-/* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
- is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
- footnote's content. */
+/* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
+ all lower indexes as a side effect). If MARKER is nonnull, sets the
+ footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
struct pivot_footnote *
pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
struct pivot_value *marker,
return headings;
}
+static void
+free_headings (const struct pivot_axis *axis, char ***headings)
+{
+ for (size_t i = 0; i < axis->label_depth; i++)
+ {
+ for (size_t j = 0; j < axis->extent; j++)
+ free (headings[i][j]);
+ free (headings[i]);
+ }
+ free (headings);
+}
+
+static void
+pivot_table_sizing_dump (const char *name, const struct pivot_table_sizing *s,
+ int indentation)
+{
+ indent (indentation);
+ printf ("%ss: min=%d, max=%d\n", name, s->range[0], s->range[1]);
+ if (s->n_widths)
+ {
+ indent (indentation + 1);
+ printf ("%s widths:", name);
+ for (size_t i = 0; i < s->n_widths; i++)
+ printf (" %d", s->widths[i]);
+ printf ("\n");
+ }
+ if (s->n_breaks)
+ {
+ indent (indentation + 1);
+ printf ("break after %ss:", name);
+ for (size_t i = 0; i < s->n_breaks; i++)
+ printf (" %zu", s->breaks[i]);
+ printf ("\n");
+ }
+ if (s->n_keeps)
+ {
+ indent (indentation + 1);
+ printf ("keep %ss together:", name);
+ for (size_t i = 0; i < s->n_keeps; i++)
+ printf (" [%zu,%zu]",
+ s->keeps[i].ofs,
+ s->keeps[i].ofs + s->keeps[i].n - 1);
+ printf ("\n");
+ }
+}
+
void
pivot_table_dump (const struct pivot_table *table, int indentation)
{
if (table->date)
{
indent (indentation);
- printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
+ char buf[26];
+ printf ("date: %s", ctime_r (&table->date, buf));
}
+ indent (indentation);
+ printf ("sizing:\n");
+ pivot_table_sizing_dump ("column", &table->sizing[TABLE_HORZ],
+ indentation + 1);
+ pivot_table_sizing_dump ("row", &table->sizing[TABLE_VERT],
+ indentation + 1);
+
indent (indentation);
printf ("areas:\n");
for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
fputs (" =", stdout);
struct pivot_value **names = xnmalloc (layer_axis->label_depth,
- sizeof *names);
+ sizeof *names);
size_t n_names = 0;
for (const struct pivot_category *c
= d->presentation_leaves[layer_indexes[i]];
}
putchar ('\n');
}
+ free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
indent (indentation + 1);
printf ("-----------------------------------------------\n");
free (column_enumeration);
free (row_enumeration);
+ free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
}
pivot_table_dump_value (table->caption, "caption", indentation);
putchar ('\n');
}
+ free (dindexes);
settings_set_decimal_char (old_decimal);
}
\f
break;
case PIVOT_VALUE_TEMPLATE:
- pivot_format_template (out, value->template.s, value->template.args,
+ pivot_format_template (out, value->template.local, value->template.args,
value->template.n_args, show_values,
show_variables);
break;
/* Do not free the elements of footnotes because VALUE does not own
them. */
free (value->footnotes);
+ free (value->subscript);
switch (value->type)
{
break;
case PIVOT_VALUE_TEMPLATE:
- free (value->template.s);
+ free (value->template.local);
+ if (value->template.id != value->template.local)
+ free (value->template.id);
for (size_t i = 0; i < value->template.n_args; i++)
pivot_argument_uninit (&value->template.args[i]);
free (value->template.args);
DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
void
pivot_value_get_style (struct pivot_value *value,
- const struct area_style *default_style,
+ const struct font_style *base_font_style,
+ const struct cell_style *base_cell_style,
struct area_style *area)
{
font_style_copy (&area->font_style, (value->font_style
? value->font_style
- : &default_style->font_style));
- area->cell_style = (value->cell_style
- ? *value->cell_style
- : default_style->cell_style);
+ : base_font_style));
+ area->cell_style = *(value->cell_style
+ ? value->cell_style
+ : base_cell_style);
}
/* Copies AREA into VALUE's style. */
pivot_value_add_footnote (struct pivot_value *v,
struct pivot_footnote *footnote)
{
+ /* Some legacy tables include numerous duplicate footnotes. Suppress
+ them. */
+ for (size_t i = 0; i < v->n_footnotes; i++)
+ if (v->footnotes[i] == footnote)
+ return;
+
v->footnotes = xrealloc (v->footnotes,
(v->n_footnotes + 1) * sizeof *v->footnotes);
v->footnotes[v->n_footnotes++] = footnote;