#include "output/spv/spv-table-look.h"
#include <errno.h>
+#include <inttypes.h>
#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
#include <string.h>
+#include "libpspp/i18n.h"
#include "output/spv/structure-xml-parser.h"
+#include "output/spv/tlo-parser.h"
+#include "output/pivot-table.h"
+#include "output/table.h"
#include "gl/read-file.h"
#include "gl/xalloc.h"
+#include "gl/xmemdup0.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
static struct cell_color
optional_color (int color, struct cell_color default_color)
return inches != DBL_MAX ? inches * 72.0 + .5 : default_pt;
}
+static const char *pivot_area_names[PIVOT_N_AREAS] = {
+ [PIVOT_AREA_TITLE] = "title",
+ [PIVOT_AREA_CAPTION] = "caption",
+ [PIVOT_AREA_FOOTER] = "footnotes",
+ [PIVOT_AREA_CORNER] = "cornerLabels",
+ [PIVOT_AREA_COLUMN_LABELS] = "columnLabels",
+ [PIVOT_AREA_ROW_LABELS] = "rowLabels",
+ [PIVOT_AREA_DATA] = "data",
+ [PIVOT_AREA_LAYERS] = "layers",
+};
+
static enum pivot_area
pivot_area_from_name (const char *name)
{
- static const char *area_names[PIVOT_N_AREAS] = {
- [PIVOT_AREA_TITLE] = "title",
- [PIVOT_AREA_CAPTION] = "caption",
- [PIVOT_AREA_FOOTER] = "footnotes",
- [PIVOT_AREA_CORNER] = "cornerLabels",
- [PIVOT_AREA_COLUMN_LABELS] = "columnLabels",
- [PIVOT_AREA_ROW_LABELS] = "rowLabels",
- [PIVOT_AREA_DATA] = "data",
- [PIVOT_AREA_LAYERS] = "layers",
- };
-
enum pivot_area area;
for (area = 0; area < PIVOT_N_AREAS; area++)
- if (!strcmp (name, area_names[area]))
+ if (!strcmp (name, pivot_area_names[area]))
break;
return area;
}
+static const char *pivot_border_names[PIVOT_N_BORDERS] = {
+ [PIVOT_BORDER_TITLE] = "titleLayerSeparator",
+ [PIVOT_BORDER_OUTER_LEFT] = "leftOuterFrame",
+ [PIVOT_BORDER_OUTER_TOP] = "topOuterFrame",
+ [PIVOT_BORDER_OUTER_RIGHT] = "rightOuterFrame",
+ [PIVOT_BORDER_OUTER_BOTTOM] = "bottomOuterFrame",
+ [PIVOT_BORDER_INNER_LEFT] = "leftInnerFrame",
+ [PIVOT_BORDER_INNER_TOP] = "topInnerFrame",
+ [PIVOT_BORDER_INNER_RIGHT] = "rightInnerFrame",
+ [PIVOT_BORDER_INNER_BOTTOM] = "bottomInnerFrame",
+ [PIVOT_BORDER_DATA_LEFT] = "dataAreaLeft",
+ [PIVOT_BORDER_DATA_TOP] = "dataAreaTop",
+ [PIVOT_BORDER_DIM_ROW_HORZ] = "horizontalDimensionBorderRows",
+ [PIVOT_BORDER_DIM_ROW_VERT] = "verticalDimensionBorderRows",
+ [PIVOT_BORDER_DIM_COL_HORZ] = "horizontalDimensionBorderColumns",
+ [PIVOT_BORDER_DIM_COL_VERT] = "verticalDimensionBorderColumns",
+ [PIVOT_BORDER_CAT_ROW_HORZ] = "horizontalCategoryBorderRows",
+ [PIVOT_BORDER_CAT_ROW_VERT] = "verticalCategoryBorderRows",
+ [PIVOT_BORDER_CAT_COL_HORZ] = "horizontalCategoryBorderColumns",
+ [PIVOT_BORDER_CAT_COL_VERT] = "verticalCategoryBorderColumns",
+};
+
static enum pivot_border
pivot_border_from_name (const char *name)
{
- static const char *border_names[PIVOT_N_BORDERS] = {
- [PIVOT_BORDER_TITLE] = "titleLayerSeparator",
- [PIVOT_BORDER_OUTER_LEFT] = "leftOuterFrame",
- [PIVOT_BORDER_OUTER_TOP] = "topOuterFrame",
- [PIVOT_BORDER_OUTER_RIGHT] = "rightOuterFrame",
- [PIVOT_BORDER_OUTER_BOTTOM] = "bottomOuterFrame",
- [PIVOT_BORDER_INNER_LEFT] = "leftInnerFrame",
- [PIVOT_BORDER_INNER_TOP] = "topInnerFrame",
- [PIVOT_BORDER_INNER_RIGHT] = "rightInnerFrame",
- [PIVOT_BORDER_INNER_BOTTOM] = "bottomInnerFrame",
- [PIVOT_BORDER_DATA_LEFT] = "dataAreaLeft",
- [PIVOT_BORDER_DATA_TOP] = "dataAreaTop",
- [PIVOT_BORDER_DIM_ROW_HORZ] = "horizontalDimensionBorderRows",
- [PIVOT_BORDER_DIM_ROW_VERT] = "verticalDimensionBorderRows",
- [PIVOT_BORDER_DIM_COL_HORZ] = "horizontalDimensionBorderColumns",
- [PIVOT_BORDER_DIM_COL_VERT] = "verticalDimensionBorderColumns",
- [PIVOT_BORDER_CAT_ROW_HORZ] = "horizontalCategoryBorderRows",
- [PIVOT_BORDER_CAT_ROW_VERT] = "verticalCategoryBorderRows",
- [PIVOT_BORDER_CAT_COL_HORZ] = "horizontalCategoryBorderColumns",
- [PIVOT_BORDER_CAT_COL_VERT] = "verticalCategoryBorderColumns",
- };
-
enum pivot_border border;
for (border = 0; border < PIVOT_N_BORDERS; border++)
- if (!strcmp (name, border_names[border]))
+ if (!strcmp (name, pivot_border_names[border]))
break;
return border;
}
char * WARN_UNUSED_RESULT
spv_table_look_decode (const struct spvsx_table_properties *in,
- struct spv_table_look **outp)
+ struct pivot_table_look **outp)
{
- struct spv_table_look *out = xzalloc (sizeof *out);
+ struct pivot_table_look *out = xzalloc (sizeof *out);
char *error = NULL;
+ out->name = in->name ? xstrdup (in->name) : NULL;
+
const struct spvsx_general_properties *g = in->general_properties;
out->omit_empty = g->hide_empty_rows != 0;
out->width_ranges[TABLE_HORZ][0] = optional_pt (g->minimum_column_width, -1);
= (f->number_format == SPVSX_NUMBER_FORMAT_NUMERIC);
for (int i = 0; i < PIVOT_N_AREAS; i++)
- area_style_copy (NULL, &out->areas[i], pivot_area_get_default_style (i));
+ table_area_style_copy (NULL, &out->areas[i],
+ pivot_area_get_default_style (i));
const struct spvsx_cell_format_properties *cfp = in->cell_format_properties;
for (size_t i = 0; i < cfp->n_cell_style; i++)
goto error;
}
- struct area_style *a = &out->areas[area];
+ struct table_area_style *a = &out->areas[area];
const struct spvsx_style *s = c->style;
if (s->font_weight)
a->font_style.bold = s->font_weight == SPVSX_FONT_WEIGHT_BOLD;
const struct spvsx_printing_properties *pp = in->printing_properties;
out->print_all_layers = pp->print_all_layers > 0;
out->paginate_layers = pp->print_each_layer_on_separate_page > 0;
- out->shrink_to_width = pp->rescale_wide_table_to_fit_page > 0;
- out->shrink_to_length = pp->rescale_long_table_to_fit_page > 0;
+ out->shrink_to_fit[TABLE_HORZ] = pp->rescale_wide_table_to_fit_page > 0;
+ out->shrink_to_fit[TABLE_VERT] = pp->rescale_long_table_to_fit_page > 0;
out->top_continuation = pp->continuation_text_at_top > 0;
out->bottom_continuation = pp->continuation_text_at_bottom > 0;
out->continuation = xstrdup (pp->continuation_text
return NULL;
error:
- spv_table_look_destroy (out);
+ pivot_table_look_uninit (out);
+ free (out);
*outp = NULL;
return error;
}
+\f
+static struct cell_color
+tlo_decode_color (uint32_t c)
+{
+ return (struct cell_color) CELL_COLOR (c, c >> 8, c >> 16);
+}
+
+static void
+tlo_decode_border (const struct tlo_separator *in,
+ struct table_border_style *out)
+{
+ if (in->type == 0)
+ {
+ out->stroke = TABLE_STROKE_NONE;
+ return;
+ }
+
+ out->color = tlo_decode_color (in->type_01.color);
+
+ switch (in->type_01.style)
+ {
+ case 0:
+ out->stroke = (in->type_01.width == 0 ? TABLE_STROKE_THIN
+ : in->type_01.width == 1 ? TABLE_STROKE_SOLID
+ : TABLE_STROKE_THICK);
+ break;
+
+ case 1:
+ out->stroke = TABLE_STROKE_DOUBLE;
+ break;
+
+ case 2:
+ out->stroke = TABLE_STROKE_DASHED;
+ break;
+ }
+}
+
+static struct cell_color
+interpolate_colors (struct cell_color c0, struct cell_color c1, int shading)
+{
+ if (shading <= 0)
+ return c0;
+ else if (shading >= 10)
+ return c1;
+ else
+ {
+ int x0 = 10 - shading;
+ int x1 = shading;
+
+ return (struct cell_color) CELL_COLOR ((c0.r * x0 + c1.r * x1) / 10,
+ (c0.g * x0 + c1.g * x1) / 10,
+ (c0.b * x0 + c1.b * x1) / 10);
+ }
+}
+
+static void
+tlo_decode_area (const struct tlo_area_color *color,
+ const struct tlo_area_style *style,
+ struct table_area_style *out)
+{
+ out->cell_style.halign = (style->halign == 0 ? TABLE_HALIGN_LEFT
+ : style->halign == 1 ? TABLE_HALIGN_RIGHT
+ : style->halign == 2 ? TABLE_HALIGN_CENTER
+ : style->halign == 4 ? TABLE_HALIGN_DECIMAL
+ : TABLE_HALIGN_MIXED);
+ out->cell_style.valign = (style->valign == 0 ? TABLE_VALIGN_TOP
+ : style->valign == 1 ? TABLE_VALIGN_BOTTOM
+ : TABLE_VALIGN_CENTER);
+ out->cell_style.decimal_offset = style->decimal_offset / 20;
+ out->cell_style.decimal_char = '.'; /* XXX */
+ out->cell_style.margin[TABLE_HORZ][0] = style->left_margin / 20;
+ out->cell_style.margin[TABLE_HORZ][1] = style->right_margin / 20;
+ out->cell_style.margin[TABLE_VERT][0] = style->top_margin / 20;
+ out->cell_style.margin[TABLE_VERT][1] = style->bottom_margin / 20;
+
+ out->font_style.bold = style->weight > 400;
+ out->font_style.italic = style->italic;
+ out->font_style.underline = style->underline;
+ out->font_style.markup = false;
+
+ out->font_style.fg[0] = out->font_style.fg[1]
+ = tlo_decode_color (style->text_color);
+
+ struct cell_color c0 = tlo_decode_color (color->color0);
+ struct cell_color c10 = tlo_decode_color (color->color10);
+ struct cell_color bg = interpolate_colors (c0, c10, color->shading);
+ out->font_style.bg[0] = out->font_style.bg[1] = bg;
+
+ free (out->font_style.typeface);
+ out->font_style.typeface = recode_string (
+ "UTF-8", "ISO-8859-1",
+ CHAR_CAST (char *, style->font_name), style->font_name_len);
+ out->font_style.size = -style->font_size * 3 / 4;
+}
+
+static struct pivot_table_look *
+tlo_decode (const struct tlo_table_look *in)
+{
+ struct pivot_table_look *out = xmalloc (sizeof *out);
+ pivot_table_look_init (out);
+
+ const uint16_t flags = in->tl->flags;
+
+ out->omit_empty = (flags & 0x02) != 0;
+ out->row_labels_in_corner = !in->tl->nested_row_labels;
+ if (in->v2_styles)
+ {
+ out->width_ranges[TABLE_HORZ][0] = in->v2_styles->min_col_width;
+ out->width_ranges[TABLE_HORZ][1] = in->v2_styles->max_col_width;
+ out->width_ranges[TABLE_VERT][0] = in->v2_styles->min_row_height;
+ out->width_ranges[TABLE_VERT][1] = in->v2_styles->max_row_height;
+ }
+ else
+ {
+ out->width_ranges[TABLE_HORZ][0] = 36;
+ out->width_ranges[TABLE_HORZ][1] = 72;
+ out->width_ranges[TABLE_VERT][0] = 36;
+ out->width_ranges[TABLE_VERT][1] = 120;
+ }
+ out->show_numeric_markers = flags & 0x04;
+ out->footnote_marker_superscripts = !in->tl->footnote_marker_subscripts;
+
+ for (int i = 0; i < 4; i++)
+ {
+ static const enum pivot_border map[4] =
+ {
+ PIVOT_BORDER_DIM_ROW_HORZ,
+ PIVOT_BORDER_DIM_ROW_VERT,
+ PIVOT_BORDER_CAT_ROW_HORZ,
+ PIVOT_BORDER_CAT_ROW_VERT,
+ };
+ tlo_decode_border (in->ss->sep1[i], &out->borders[map[i]]);
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ static const enum pivot_border map[4] =
+ {
+ PIVOT_BORDER_DIM_COL_HORZ,
+ PIVOT_BORDER_DIM_COL_VERT,
+ PIVOT_BORDER_CAT_COL_HORZ,
+ PIVOT_BORDER_CAT_COL_VERT,
+ };
+ tlo_decode_border (in->ss->sep2[i], &out->borders[map[i]]);
+ }
+
+ if (in->v2_styles)
+ for (int i = 0; i < 11; i++)
+ {
+ static const enum pivot_border map[11] =
+ {
+ PIVOT_BORDER_TITLE,
+ PIVOT_BORDER_INNER_LEFT,
+ PIVOT_BORDER_INNER_RIGHT,
+ PIVOT_BORDER_INNER_TOP,
+ PIVOT_BORDER_INNER_BOTTOM,
+ PIVOT_BORDER_OUTER_LEFT,
+ PIVOT_BORDER_OUTER_RIGHT,
+ PIVOT_BORDER_OUTER_TOP,
+ PIVOT_BORDER_OUTER_BOTTOM,
+ PIVOT_BORDER_DATA_LEFT,
+ PIVOT_BORDER_DATA_TOP,
+ };
+ tlo_decode_border (in->v2_styles->sep3[i], &out->borders[map[i]]);
+ }
+ else
+ {
+ out->borders[PIVOT_BORDER_TITLE].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_INNER_LEFT].stroke = TABLE_STROKE_SOLID;
+ out->borders[PIVOT_BORDER_INNER_TOP].stroke = TABLE_STROKE_SOLID;
+ out->borders[PIVOT_BORDER_INNER_RIGHT].stroke = TABLE_STROKE_SOLID;
+ out->borders[PIVOT_BORDER_INNER_BOTTOM].stroke = TABLE_STROKE_SOLID;
+ out->borders[PIVOT_BORDER_OUTER_LEFT].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_OUTER_TOP].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_OUTER_RIGHT].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_OUTER_BOTTOM].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_DATA_LEFT].stroke = TABLE_STROKE_NONE;
+ out->borders[PIVOT_BORDER_DATA_TOP].stroke = TABLE_STROKE_NONE;
+ }
+
+ tlo_decode_area (in->cs->title_color, in->ts->title_style,
+ &out->areas[PIVOT_AREA_TITLE]);
+ for (int i = 0; i < 7; i++)
+ {
+ static const enum pivot_area map[7] = {
+ PIVOT_AREA_LAYERS,
+ PIVOT_AREA_CORNER,
+ PIVOT_AREA_ROW_LABELS,
+ PIVOT_AREA_COLUMN_LABELS,
+ PIVOT_AREA_DATA,
+ PIVOT_AREA_CAPTION,
+ PIVOT_AREA_FOOTER
+ };
+ tlo_decode_area (in->ts->most_areas[i]->color,
+ in->ts->most_areas[i]->style,
+ &out->areas[map[i]]);
+ }
+
+ out->print_all_layers = flags & 0x08;
+ out->paginate_layers = flags & 0x40;
+ out->shrink_to_fit[TABLE_HORZ] = flags & 0x10;
+ out->shrink_to_fit[TABLE_VERT] = flags & 0x20;
+ out->top_continuation = flags & 0x80;
+ out->bottom_continuation = flags & 0x100;
+ /* n_orphan_lines isn't in .tlo files AFAICT. */
+
+ return out;
+}
+\f
char * WARN_UNUSED_RESULT
-spv_table_look_read (const char *filename, struct spv_table_look **outp)
+spv_table_look_read (const char *filename, struct pivot_table_look **outp)
{
*outp = NULL;
return xasprintf ("%s: failed to read file (%s)",
filename, strerror (errno));
- xmlDoc *doc = xmlReadMemory (file, length, NULL, NULL, XML_PARSE_NOBLANKS);
- free (file);
- if (!doc)
- return xasprintf ("%s: failed to parse XML", filename);
+ if ((uint8_t) file[0] == 0xff)
+ {
+ struct spvbin_input input;
+ spvbin_input_init (&input, file, length);
+
+ struct tlo_table_look *look;
+ char *error = NULL;
+ if (!tlo_parse_table_look (&input, &look))
+ error = spvbin_input_to_error (&input, NULL);
+ else
+ {
+ *outp = tlo_decode (look);
+ tlo_free_table_look (look);
+ }
+ return error;
+ }
+ else
+ {
+ xmlDoc *doc = xmlReadMemory (file, length, NULL, NULL, XML_PARSE_NOBLANKS);
+ free (file);
+ if (!doc)
+ return xasprintf ("%s: failed to parse XML", filename);
- struct spvxml_context ctx = SPVXML_CONTEXT_INIT (ctx);
- struct spvsx_table_properties *tp;
- spvsx_parse_table_properties (&ctx, xmlDocGetRootElement (doc), &tp);
- char *error = spvxml_context_finish (&ctx, &tp->node_);
+ struct spvxml_context ctx = SPVXML_CONTEXT_INIT (ctx);
+ struct spvsx_table_properties *tp;
+ spvsx_parse_table_properties (&ctx, xmlDocGetRootElement (doc), &tp);
+ char *error = spvxml_context_finish (&ctx, &tp->node_);
- if (!error)
- error = spv_table_look_decode (tp, outp);
+ if (!error)
+ error = spv_table_look_decode (tp, outp);
- spvsx_free_table_properties (tp);
- xmlFreeDoc (doc);
+ spvsx_free_table_properties (tp);
+ xmlFreeDoc (doc);
- return error;
+ return error;
+ }
}
-void
-spv_table_look_destroy (struct spv_table_look *look)
+static void
+write_attr (xmlTextWriter *xml, const char *name, const char *value)
{
- if (look)
- {
- for (size_t i = 0; i < PIVOT_N_AREAS; i++)
- area_style_uninit (&look->areas[i]);
- free (look->continuation);
- free (look);
- }
+ xmlTextWriterWriteAttribute (xml,
+ CHAR_CAST (xmlChar *, name),
+ CHAR_CAST (xmlChar *, value));
}
-void
-spv_table_look_install (const struct spv_table_look *look,
- struct pivot_table *table)
+static void PRINTF_FORMAT (3, 4)
+write_attr_format (xmlTextWriter *xml, const char *name,
+ const char *format, ...)
{
- table->omit_empty = look->omit_empty;
+ va_list args;
+ va_start (args, format);
+ char *value = xvasprintf (format, args);
+ va_end (args);
- for (enum table_axis axis = 0; axis < TABLE_N_AXES; axis++)
- for (int i = 0; i < 2; i++)
- if (look->width_ranges[axis][i] > 0)
- table->sizing[axis].range[i] = look->width_ranges[axis][i];
- table->row_labels_in_corner = look->row_labels_in_corner;
+ write_attr (xml, name, value);
+ free (value);
+}
- table->footnote_marker_superscripts = look->footnote_marker_superscripts;
- table->show_numeric_markers = look->show_numeric_markers;
+static void
+write_attr_color (xmlTextWriter *xml, const char *name,
+ const struct cell_color *color)
+{
+ write_attr_format (xml, name, "#%02"PRIx8"%02"PRIx8"%02"PRIx8,
+ color->r, color->g, color->b);
+}
- for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+static void
+write_attr_dimension (xmlTextWriter *xml, const char *name, int px)
+{
+ int pt = px / 96.0 * 72.0;
+ write_attr_format (xml, name, "%dpt", pt);
+}
+
+static void
+write_attr_bool (xmlTextWriter *xml, const char *name, bool b)
+{
+ write_attr (xml, name, b ? "true" : "false");
+}
+
+static void
+start_elem (xmlTextWriter *xml, const char *name)
+{
+ xmlTextWriterStartElement (xml, CHAR_CAST (xmlChar *, name));
+}
+
+static void
+end_elem (xmlTextWriter *xml)
+{
+ xmlTextWriterEndElement (xml);
+}
+
+char * WARN_UNUSED_RESULT
+spv_table_look_write (const char *filename, const struct pivot_table_look *look)
+{
+ FILE *file = fopen (filename, "w");
+ if (!file)
+ return xasprintf (_("%s: create failed (%s)"), filename, strerror (errno));
+
+ xmlTextWriter *xml = xmlNewTextWriter (xmlOutputBufferCreateFile (
+ file, NULL));
+ if (!xml)
+ {
+ fclose (file);
+ return xasprintf (_("%s: failed to start writing XML"), filename);
+ }
+
+ xmlTextWriterSetIndent (xml, 1);
+ xmlTextWriterSetIndentString (xml, CHAR_CAST (xmlChar *, " "));
+
+ xmlTextWriterStartDocument (xml, NULL, "UTF-8", NULL);
+ start_elem (xml, "tableProperties");
+ if (look->name)
+ write_attr (xml, "name", look->name);
+ write_attr (xml, "xmlns", "http://www.ibm.com/software/analytics/spss/xml/table-looks");
+ write_attr (xml, "xmlns:vizml", "http://www.ibm.com/software/analytics/spss/xml/visualization");
+ write_attr (xml, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+ write_attr (xml, "xsi:schemaLocation", "http://www.ibm.com/software/analytics/spss/xml/table-looks http://www.ibm.com/software/analytics/spss/xml/table-looks/table-looks-1.4.xsd");
+
+ start_elem (xml, "generalProperties");
+ write_attr_bool (xml, "hideEmptyRows", look->omit_empty);
+ const int (*wr)[2] = look->width_ranges;
+ write_attr_format (xml, "maximumColumnWidth", "%d", wr[TABLE_HORZ][1]);
+ write_attr_format (xml, "maximumRowWidth", "%d", wr[TABLE_VERT][1]);
+ write_attr_format (xml, "minimumColumnWidth", "%d", wr[TABLE_HORZ][0]);
+ write_attr_format (xml, "minimumRowWidth", "%d", wr[TABLE_VERT][0]);
+ write_attr (xml, "rowDimensionLabels",
+ look->row_labels_in_corner ? "inCorner" : "nested");
+ end_elem (xml);
+
+ start_elem (xml, "footnoteProperties");
+ write_attr (xml, "markerPosition",
+ look->footnote_marker_superscripts ? "superscript" : "subscript");
+ write_attr (xml, "numberFormat",
+ look->show_numeric_markers ? "numeric" : "alphabetic");
+ end_elem (xml);
+
+ start_elem (xml, "cellFormatProperties");
+ for (enum pivot_area a = 0; a < PIVOT_N_AREAS; a++)
+ {
+ const struct table_area_style *area = &look->areas[a];
+ const struct font_style *font = &area->font_style;
+ const struct cell_style *cell = &area->cell_style;
+
+ start_elem (xml, pivot_area_names[a]);
+ if (a == PIVOT_AREA_DATA
+ && (!cell_color_equal (&font->fg[0], &font->fg[1])
+ || !cell_color_equal (&font->bg[0], &font->bg[1])))
+ {
+ write_attr_color (xml, "alternatingColor", &font->bg[1]);
+ write_attr_color (xml, "alternatingTextColor", &font->fg[1]);
+ }
+
+ start_elem (xml, "vizml:style");
+ write_attr_color (xml, "color", &font->fg[0]);
+ write_attr_color (xml, "color2", &font->bg[0]);
+ write_attr (xml, "font-family", font->typeface);
+ write_attr_format (xml, "font-size", "%dpt", font->size);
+ write_attr (xml, "font-weight", font->bold ? "bold" : "regular");
+ write_attr (xml, "font-underline",
+ font->underline ? "underline" : "none");
+ write_attr (xml, "labelLocationVertical",
+ cell->valign == TABLE_VALIGN_BOTTOM ? "negative"
+ : cell->valign == TABLE_VALIGN_TOP ? "positive"
+ : "center");
+ write_attr_dimension (xml, "margin-bottom", cell->margin[TABLE_VERT][1]);
+ write_attr_dimension (xml, "margin-left", cell->margin[TABLE_HORZ][0]);
+ write_attr_dimension (xml, "margin-right", cell->margin[TABLE_HORZ][1]);
+ write_attr_dimension (xml, "margin-top", cell->margin[TABLE_VERT][0]);
+ write_attr (xml, "textAlignment",
+ cell->halign == TABLE_HALIGN_LEFT ? "left"
+ : cell->halign == TABLE_HALIGN_RIGHT ? "right"
+ : cell->halign == TABLE_HALIGN_CENTER ? "center"
+ : cell->halign == TABLE_HALIGN_DECIMAL ? "decimal"
+ : "mixed");
+ if (cell->halign == TABLE_HALIGN_DECIMAL)
+ write_attr_dimension (xml, "decimal-offset", cell->decimal_offset);
+ end_elem (xml);
+
+ end_elem (xml);
+ }
+ end_elem (xml);
+
+ start_elem (xml, "borderProperties");
+ for (enum pivot_border b = 0; b < PIVOT_N_BORDERS; b++)
{
- area_style_uninit (&table->areas[i]);
- area_style_copy (NULL, &table->areas[i], &look->areas[i]);
+ const struct table_border_style *border = &look->borders[b];
+
+ start_elem (xml, pivot_border_names[b]);
+
+ static const char *table_stroke_names[TABLE_N_STROKES] =
+ {
+ [TABLE_STROKE_NONE] = "none",
+ [TABLE_STROKE_SOLID] = "solid",
+ [TABLE_STROKE_DASHED] = "dashed",
+ [TABLE_STROKE_THICK] = "thick",
+ [TABLE_STROKE_THIN] = "thin",
+ [TABLE_STROKE_DOUBLE] = "double",
+ };
+ write_attr (xml, "borderStyleType", table_stroke_names[border->stroke]);
+ write_attr_color (xml, "color", &border->color);
+ end_elem (xml);
}
- for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
- table->borders[i] = look->borders[i];
-
- table->print_all_layers = look->print_all_layers;
- table->paginate_layers = look->paginate_layers;
- table->shrink_to_fit[TABLE_HORZ] = look->shrink_to_width;
- table->shrink_to_fit[TABLE_VERT] = look->shrink_to_length;
- table->top_continuation = look->top_continuation;
- table->bottom_continuation = look->bottom_continuation;
- table->continuation = xstrdup (look->continuation);
- table->n_orphan_lines = look->n_orphan_lines;
+ end_elem (xml);
+
+ start_elem (xml, "printingProperties");
+ write_attr_bool (xml, "printAllLayers", look->print_all_layers);
+ write_attr_bool (xml, "rescaleLongTableToFitPage",
+ look->shrink_to_fit[TABLE_HORZ]);
+ write_attr_bool (xml, "rescaleWideTableToFitPage",
+ look->shrink_to_fit[TABLE_VERT]);
+ write_attr_format (xml, "windowOrphanLines", "%zu", look->n_orphan_lines);
+ if (look->continuation && look->continuation[0]
+ && (look->top_continuation || look->bottom_continuation))
+ {
+ write_attr (xml, "continuationText", look->continuation);
+ write_attr_bool (xml, "continuationTextAtTop", look->top_continuation);
+ write_attr_bool (xml, "continuationTextAtBottom",
+ look->bottom_continuation);
+ }
+ end_elem (xml);
+
+ xmlTextWriterEndDocument (xml);
+
+ xmlFreeTextWriter (xml);
+
+ fflush (file);
+ bool ok = !ferror (file);
+ if (fclose (file) == EOF)
+ ok = false;
+
+ if (!ok)
+ return xasprintf (_("%s: error writing file (%s)"),
+ filename, strerror (errno));
+
+ return NULL;
}