1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2017, 2018, 2020 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "output/spv/spv-table-look.h"
22 #include <libxml/xmlreader.h>
25 #include "output/spv/structure-xml-parser.h"
27 #include "gl/read-file.h"
28 #include "gl/xalloc.h"
30 static struct cell_color
31 optional_color (int color, struct cell_color default_color)
34 ? (struct cell_color) CELL_COLOR (color >> 16, color >> 8, color)
39 optional_length (const char *s, int default_length)
41 /* There is usually a "pt" suffix. We ignore it. */
43 return s && sscanf (s, "%d", &length) == 1 ? length : default_length;
47 optional_px (double inches, int default_px)
49 return inches != DBL_MAX ? inches * 96.0 : default_px;
53 optional_int (int x, int default_value)
55 return x != INT_MIN ? x : default_value;
59 optional_pt (double inches, int default_pt)
61 return inches != DBL_MAX ? inches * 72.0 + .5 : default_pt;
64 static enum pivot_area
65 pivot_area_from_name (const char *name)
67 static const char *area_names[PIVOT_N_AREAS] = {
68 [PIVOT_AREA_TITLE] = "title",
69 [PIVOT_AREA_CAPTION] = "caption",
70 [PIVOT_AREA_FOOTER] = "footnotes",
71 [PIVOT_AREA_CORNER] = "cornerLabels",
72 [PIVOT_AREA_COLUMN_LABELS] = "columnLabels",
73 [PIVOT_AREA_ROW_LABELS] = "rowLabels",
74 [PIVOT_AREA_DATA] = "data",
75 [PIVOT_AREA_LAYERS] = "layers",
79 for (area = 0; area < PIVOT_N_AREAS; area++)
80 if (!strcmp (name, area_names[area]))
85 static enum pivot_border
86 pivot_border_from_name (const char *name)
88 static const char *border_names[PIVOT_N_BORDERS] = {
89 [PIVOT_BORDER_TITLE] = "titleLayerSeparator",
90 [PIVOT_BORDER_OUTER_LEFT] = "leftOuterFrame",
91 [PIVOT_BORDER_OUTER_TOP] = "topOuterFrame",
92 [PIVOT_BORDER_OUTER_RIGHT] = "rightOuterFrame",
93 [PIVOT_BORDER_OUTER_BOTTOM] = "bottomOuterFrame",
94 [PIVOT_BORDER_INNER_LEFT] = "leftInnerFrame",
95 [PIVOT_BORDER_INNER_TOP] = "topInnerFrame",
96 [PIVOT_BORDER_INNER_RIGHT] = "rightInnerFrame",
97 [PIVOT_BORDER_INNER_BOTTOM] = "bottomInnerFrame",
98 [PIVOT_BORDER_DATA_LEFT] = "dataAreaLeft",
99 [PIVOT_BORDER_DATA_TOP] = "dataAreaTop",
100 [PIVOT_BORDER_DIM_ROW_HORZ] = "horizontalDimensionBorderRows",
101 [PIVOT_BORDER_DIM_ROW_VERT] = "verticalDimensionBorderRows",
102 [PIVOT_BORDER_DIM_COL_HORZ] = "horizontalDimensionBorderColumns",
103 [PIVOT_BORDER_DIM_COL_VERT] = "verticalDimensionBorderColumns",
104 [PIVOT_BORDER_CAT_ROW_HORZ] = "horizontalCategoryBorderRows",
105 [PIVOT_BORDER_CAT_ROW_VERT] = "verticalCategoryBorderRows",
106 [PIVOT_BORDER_CAT_COL_HORZ] = "horizontalCategoryBorderColumns",
107 [PIVOT_BORDER_CAT_COL_VERT] = "verticalCategoryBorderColumns",
110 enum pivot_border border;
111 for (border = 0; border < PIVOT_N_BORDERS; border++)
112 if (!strcmp (name, border_names[border]))
117 char * WARN_UNUSED_RESULT
118 spv_table_look_decode (const struct spvsx_table_properties *in,
119 struct spv_table_look **outp)
121 struct spv_table_look *out = xzalloc (sizeof *out);
124 const struct spvsx_general_properties *g = in->general_properties;
125 out->omit_empty = g->hide_empty_rows != 0;
126 out->width_ranges[TABLE_HORZ][0] = optional_pt (g->minimum_column_width, -1);
127 out->width_ranges[TABLE_HORZ][1] = optional_pt (g->maximum_column_width, -1);
128 out->width_ranges[TABLE_VERT][0] = optional_pt (g->minimum_row_width, -1);
129 out->width_ranges[TABLE_VERT][1] = optional_pt (g->maximum_row_width, -1);
130 out->row_labels_in_corner
131 = g->row_dimension_labels != SPVSX_ROW_DIMENSION_LABELS_NESTED;
133 const struct spvsx_footnote_properties *f = in->footnote_properties;
134 out->footnote_marker_superscripts
135 = (f->marker_position != SPVSX_MARKER_POSITION_SUBSCRIPT);
136 out->show_numeric_markers
137 = (f->number_format == SPVSX_NUMBER_FORMAT_NUMERIC);
139 for (int i = 0; i < PIVOT_N_AREAS; i++)
140 area_style_copy (NULL, &out->areas[i], pivot_area_get_default_style (i));
142 const struct spvsx_cell_format_properties *cfp = in->cell_format_properties;
143 for (size_t i = 0; i < cfp->n_cell_style; i++)
145 const struct spvsx_cell_style *c = cfp->cell_style[i];
146 const char *name = CHAR_CAST (const char *, c->node_.raw->name);
147 enum pivot_area area = pivot_area_from_name (name);
148 if (area == PIVOT_N_AREAS)
150 error = xasprintf ("unknown area \"%s\" in cellFormatProperties",
155 struct area_style *a = &out->areas[area];
156 const struct spvsx_style *s = c->style;
158 a->font_style.bold = s->font_weight == SPVSX_FONT_WEIGHT_BOLD;
160 a->font_style.italic = s->font_style == SPVSX_FONT_STYLE_ITALIC;
161 if (s->font_underline)
162 a->font_style.underline
163 = s->font_underline == SPVSX_FONT_UNDERLINE_UNDERLINE;
165 a->font_style.fg[0] = optional_color (
166 s->color, (struct cell_color) CELL_COLOR_BLACK);
167 if (c->alternating_text_color >= 0 || s->color >= 0)
168 a->font_style.fg[1] = optional_color (c->alternating_text_color,
169 a->font_style.fg[0]);
171 a->font_style.bg[0] = optional_color (
172 s->color2, (struct cell_color) CELL_COLOR_WHITE);
173 if (c->alternating_color >= 0 || s->color2 >= 0)
174 a->font_style.bg[1] = optional_color (c->alternating_color,
175 a->font_style.bg[0]);
178 free (a->font_style.typeface);
179 a->font_style.typeface = xstrdup (s->font_family);
183 a->font_style.size = optional_length (s->font_size, 0);
185 if (s->text_alignment)
187 = (s->text_alignment == SPVSX_TEXT_ALIGNMENT_LEFT
189 : s->text_alignment == SPVSX_TEXT_ALIGNMENT_RIGHT
191 : s->text_alignment == SPVSX_TEXT_ALIGNMENT_CENTER
192 ? TABLE_HALIGN_CENTER
193 : s->text_alignment == SPVSX_TEXT_ALIGNMENT_DECIMAL
194 ? TABLE_HALIGN_DECIMAL
195 : TABLE_HALIGN_MIXED);
196 if (s->label_location_vertical)
198 = (s->label_location_vertical == SPVSX_LABEL_LOCATION_VERTICAL_NEGATIVE
199 ? TABLE_VALIGN_BOTTOM
200 : s->label_location_vertical == SPVSX_LABEL_LOCATION_VERTICAL_POSITIVE
202 : TABLE_VALIGN_CENTER);
204 if (s->decimal_offset != DBL_MAX)
205 a->cell_style.decimal_offset = optional_px (s->decimal_offset, 0);
207 if (s->margin_left != DBL_MAX)
208 a->cell_style.margin[TABLE_HORZ][0] = optional_px (s->margin_left, 8);
209 if (s->margin_right != DBL_MAX)
210 a->cell_style.margin[TABLE_HORZ][1] = optional_px (s->margin_right,
212 if (s->margin_top != DBL_MAX)
213 a->cell_style.margin[TABLE_VERT][0] = optional_px (s->margin_top, 1);
214 if (s->margin_bottom != DBL_MAX)
215 a->cell_style.margin[TABLE_VERT][1] = optional_px (s->margin_bottom,
219 for (int i = 0; i < PIVOT_N_BORDERS; i++)
220 pivot_border_get_default_style (i, &out->borders[i]);
222 const struct spvsx_border_properties *bp = in->border_properties;
223 for (size_t i = 0; i < bp->n_border_style; i++)
225 const struct spvsx_border_style *bin = bp->border_style[i];
226 const char *name = CHAR_CAST (const char *, bin->node_.raw->name);
227 enum pivot_border border = pivot_border_from_name (name);
228 if (border == PIVOT_N_BORDERS)
230 error = xasprintf ("unknown border \"%s\" parsing borderProperties",
235 struct table_border_style *bout = &out->borders[border];
237 = (bin->border_style_type == SPVSX_BORDER_STYLE_TYPE_NONE
239 : bin->border_style_type == SPVSX_BORDER_STYLE_TYPE_DASHED
240 ? TABLE_STROKE_DASHED
241 : bin->border_style_type == SPVSX_BORDER_STYLE_TYPE_THICK
243 : bin->border_style_type == SPVSX_BORDER_STYLE_TYPE_THIN
245 : bin->border_style_type == SPVSX_BORDER_STYLE_TYPE_DOUBLE
246 ? TABLE_STROKE_DOUBLE
247 : TABLE_STROKE_SOLID);
248 bout->color = optional_color (bin->color,
249 (struct cell_color) CELL_COLOR_BLACK);
252 const struct spvsx_printing_properties *pp = in->printing_properties;
253 out->print_all_layers = pp->print_all_layers > 0;
254 out->paginate_layers = pp->print_each_layer_on_separate_page > 0;
255 out->shrink_to_width = pp->rescale_wide_table_to_fit_page > 0;
256 out->shrink_to_length = pp->rescale_long_table_to_fit_page > 0;
257 out->top_continuation = pp->continuation_text_at_top > 0;
258 out->bottom_continuation = pp->continuation_text_at_bottom > 0;
259 out->continuation = xstrdup (pp->continuation_text
260 ? pp->continuation_text : "(cont.)");
261 out->n_orphan_lines = optional_int (pp->window_orphan_lines, 2);
267 spv_table_look_destroy (out);
272 char * WARN_UNUSED_RESULT
273 spv_table_look_read (const char *filename, struct spv_table_look **outp)
278 char *file = read_file (filename, 0, &length);
280 return xasprintf ("%s: failed to read file (%s)",
281 filename, strerror (errno));
283 xmlDoc *doc = xmlReadMemory (file, length, NULL, NULL, XML_PARSE_NOBLANKS);
286 return xasprintf ("%s: failed to parse XML", filename);
288 struct spvxml_context ctx = SPVXML_CONTEXT_INIT (ctx);
289 struct spvsx_table_properties *tp;
290 spvsx_parse_table_properties (&ctx, xmlDocGetRootElement (doc), &tp);
291 char *error = spvxml_context_finish (&ctx, &tp->node_);
294 error = spv_table_look_decode (tp, outp);
296 spvsx_free_table_properties (tp);
303 spv_table_look_destroy (struct spv_table_look *look)
307 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
308 area_style_uninit (&look->areas[i]);
309 free (look->continuation);
315 spv_table_look_install (const struct spv_table_look *look,
316 struct pivot_table *table)
318 table->omit_empty = look->omit_empty;
320 for (enum table_axis axis = 0; axis < TABLE_N_AXES; axis++)
321 for (int i = 0; i < 2; i++)
322 if (look->width_ranges[axis][i] > 0)
323 table->sizing[axis].range[i] = look->width_ranges[axis][i];
324 table->row_labels_in_corner = look->row_labels_in_corner;
326 table->footnote_marker_superscripts = look->footnote_marker_superscripts;
327 table->show_numeric_markers = look->show_numeric_markers;
329 for (size_t i = 0; i < PIVOT_N_AREAS; i++)
331 area_style_uninit (&table->areas[i]);
332 area_style_copy (NULL, &table->areas[i], &look->areas[i]);
334 for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
335 table->borders[i] = look->borders[i];
337 table->print_all_layers = look->print_all_layers;
338 table->paginate_layers = look->paginate_layers;
339 table->shrink_to_fit[TABLE_HORZ] = look->shrink_to_width;
340 table->shrink_to_fit[TABLE_VERT] = look->shrink_to_length;
341 table->top_continuation = look->top_continuation;
342 table->bottom_continuation = look->bottom_continuation;
343 table->continuation = xstrdup (look->continuation);
344 table->n_orphan_lines = look->n_orphan_lines;