putc ('\n', csv->file);
}
+static void
+csv_output_table_cell (struct csv_driver *csv,
+ const struct table_cell *cell,
+ const char *leader)
+{
+ if (!cell)
+ return;
+
+ if (!(cell->options & TAB_MARKUP) && !cell->n_footnotes
+ && !cell->n_subscripts && !leader)
+ csv_output_field (csv, cell->text);
+ else
+ {
+ struct string s = DS_EMPTY_INITIALIZER;
+
+ if (leader)
+ ds_put_format (&s, "%s: ", leader);
+
+ if (cell->options & TAB_MARKUP)
+ {
+ char *t = output_get_text_from_markup (cell->text);
+ ds_put_cstr (&s, t);
+ free (t);
+ }
+ else
+ ds_put_cstr (&s, cell->text);
+
+ if (cell->n_subscripts)
+ for (size_t i = 0; i < cell->n_subscripts; i++)
+ ds_put_format (&s, "%c%s",
+ i ? ',' : '_', cell->subscripts[i]);
+ csv_format_footnotes (cell->footnotes, cell->n_footnotes, &s);
+ csv_output_field (csv, ds_cstr (&s));
+ ds_destroy (&s);
+
+ if (leader)
+ putc ('\n', csv->file);
+ }
+}
+
static void
csv_submit (struct output_driver *driver,
const struct output_item *output_item)
csv_put_separator (csv);
if (csv->titles)
- csv_output_table_item_text (csv, table_item_get_title (table_item),
- "Table");
+ csv_output_table_cell (csv, table_item_get_title (table_item), "Table");
for (y = 0; y < t->n[TABLE_VERT]; y++)
{
if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
csv_output_field (csv, "");
- else if (!(cell.options & TAB_MARKUP) && !cell.n_footnotes
- && !cell.n_subscripts)
- csv_output_field (csv, cell.text);
else
- {
- struct string s = DS_EMPTY_INITIALIZER;
-
- if (cell.options & TAB_MARKUP)
- {
- char *t = output_get_text_from_markup (cell.text);
- ds_put_cstr (&s, t);
- free (t);
- }
- else
- ds_put_cstr (&s, cell.text);
-
- if (cell.n_subscripts)
- for (size_t i = 0; i < cell.n_subscripts; i++)
- ds_put_format (&s, "%c%s",
- i ? ',' : '_', cell.subscripts[i]);
- csv_format_footnotes (cell.footnotes, cell.n_footnotes, &s);
- csv_output_field (csv, ds_cstr (&s));
- ds_destroy (&s);
- }
+ csv_output_table_cell (csv, &cell, NULL);
}
putc ('\n', csv->file);
}
}
static void
-put_style (struct css_style *st, const char *name, const char *value)
+next_style (struct css_style *st)
{
bool first = !st->n_styles++;
- fprintf (st->file, "%s%s: %s", first ? " style='" : "; ", name, value);
+ fputs (first ? " style='" : "; ", st->file);
+}
+
+static void
+put_style (struct css_style *st, const char *name, const char *value)
+{
+ next_style (st);
+ fprintf (st->file, "%s: %s", name, value);
}
static bool
}
static void
-put_border (struct css_style *st, int style, const struct cell_color *color,
+put_border (const struct table *table, const struct table_cell *cell,
+ struct css_style *style,
+ enum table_axis axis, int h, int v,
const char *border_name)
{
- const char *css = border_to_css (style);
+ struct cell_color color;
+ const char *css = border_to_css (
+ table_get_rule (table, axis, cell->d[H][h], cell->d[V][v], &color));
if (css)
{
- if (st->n_styles++ > 0)
- fputs ("; ", st->file);
- fprintf (st->file, "border-%s: %s", border_name, css);
+ next_style (style);
+ fprintf (style->file, "border-%s: %s", border_name, css);
char buf[32];
- if (format_color (*color, (struct cell_color) CELL_COLOR_BLACK,
+ if (format_color (color, (struct cell_color) CELL_COLOR_BLACK,
buf, sizeof buf))
- fprintf (st->file, " %s", buf);
+ fprintf (style->file, " %s", buf);
}
}
}
}
+static void
+html_put_table_cell (struct html_driver *html, const struct table *t,
+ const struct table_cell *cell, const char *tag,
+ bool border)
+{
+ fprintf (html->file, "<%s", tag);
+
+ struct css_style style;
+ style_start (&style, html->file);
+ enum table_halign halign = table_halign_interpret (
+ cell->style->cell_style.halign, cell->options & TAB_NUMERIC);
+
+ switch (halign)
+ {
+ case TABLE_HALIGN_RIGHT:
+ put_style (&style, "text-align", "right");
+ break;
+ case TABLE_HALIGN_CENTER:
+ put_style (&style, "text-align", "center");
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ if (cell->options & TAB_ROTATE)
+ put_style (&style, "writing-mode", "sideways-lr");
+
+ if (cell->style->cell_style.valign != TABLE_VALIGN_TOP)
+ {
+ put_style (&style, "vertical-align",
+ (cell->style->cell_style.valign == TABLE_VALIGN_BOTTOM
+ ? "bottom" : "middle"));
+ }
+
+ const struct font_style *fs = &cell->style->font_style;
+ char bgcolor[32];
+ if (format_color (fs->bg[cell->d[V][0] % 2],
+ (struct cell_color) CELL_COLOR_WHITE,
+ bgcolor, sizeof bgcolor))
+ put_style (&style, "background", bgcolor);
+
+ char fgcolor[32];
+ if (format_color (fs->fg[cell->d[V][0] % 2],
+ (struct cell_color) CELL_COLOR_BLACK,
+ fgcolor, sizeof fgcolor))
+ put_style (&style, "color", fgcolor);
+
+ if (fs->typeface)
+ {
+ put_style (&style, "font-family", "\"");
+ escape_string (html->file, fs->typeface, " ", "\n");
+ putc ('"', html->file);
+ }
+ if (fs->bold)
+ put_style (&style, "font-weight", "bold");
+ if (fs->italic)
+ put_style (&style, "font-style", "italic");
+ if (fs->underline)
+ put_style (&style, "text-decoration", "underline");
+ if (fs->size)
+ {
+ char buf[32];
+ snprintf (buf, sizeof buf, "%dpt", fs->size);
+ put_style (&style, "font-size", buf);
+ }
+
+ if (border)
+ {
+ put_border (t, cell, &style, V, 0, 0, "top");
+ put_border (t, cell, &style, H, 0, 0, "left");
+
+ if (cell->d[V][1] == t->n[V])
+ put_border (t, cell, &style, V, 0, 1, "bottom");
+ if (cell->d[H][1] == t->n[H])
+ put_border (t, cell, &style, H, 1, 0, "right");
+ }
+ style_end (&style);
+
+ int colspan = table_cell_colspan (cell);
+ if (colspan > 1)
+ fprintf (html->file, " colspan=\"%d\"", colspan);
+
+ int rowspan = table_cell_rowspan (cell);
+ if (rowspan > 1)
+ fprintf (html->file, " rowspan=\"%d\"", rowspan);
+
+ putc ('>', html->file);
+
+ html_put_table_cell_text (html, cell);
+
+ /* output </th> or </td>. */
+ fprintf (html->file, "</%s>\n", tag);
+}
+
static void
html_output_table (struct html_driver *html, const struct table_item *item)
{
const struct table *t = table_item_get_table (item);
bool tfoot = false;
- int y;
fputs ("<table", html->file);
if (item->notes)
fputs ("</tfoot>\n", html->file);
}
- const struct table_item_text *title = table_item_get_title (item);
+ const struct table_cell *title = table_item_get_title (item);
const struct table_item_layers *layers = table_item_get_layers (item);
if (title || layers)
{
fputs ("<caption>", html->file);
if (title)
- html_put_table_item_text (html, title);
+ html_put_table_cell (html, t, title, "span", false);
if (title && layers)
fputs ("<br>\n", html->file);
if (layers)
fputs ("<tbody>\n", html->file);
- for (y = 0; y < t->n[V]; y++)
+ for (int y = 0; y < t->n[V]; y++)
{
- int x;
-
fputs ("<tr>\n", html->file);
- for (x = 0; x < t->n[H];)
+ for (int x = 0; x < t->n[H]; )
{
struct table_cell cell;
- const char *tag;
-
table_get_cell (t, x, y, &cell);
- if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
- goto next_1;
-
- /* output <td> or <th> tag. */
- bool is_header = (y < t->h[V][0]
- || y >= t->n[V] - t->h[V][1]
- || x < t->h[H][0]
- || x >= t->n[H] - t->h[H][1]);
- tag = is_header ? "th" : "td";
- fprintf (html->file, "<%s", tag);
-
- struct css_style style;
- style_start (&style, html->file);
- enum table_halign halign = table_halign_interpret (
- cell.style->cell_style.halign, cell.options & TAB_NUMERIC);
-
- switch (halign)
- {
- case TABLE_HALIGN_RIGHT:
- put_style (&style, "text-align", "right");
- break;
- case TABLE_HALIGN_CENTER:
- put_style (&style, "text-align", "center");
- break;
- default:
- /* Do nothing */
- break;
- }
-
- if (cell.options & TAB_ROTATE)
- put_style (&style, "writing-mode", "sideways-lr");
-
- if (cell.style->cell_style.valign != TABLE_VALIGN_TOP)
- {
- put_style (&style, "vertical-align",
- (cell.style->cell_style.valign == TABLE_VALIGN_BOTTOM
- ? "bottom" : "middle"));
- }
-
- const struct font_style *fs = &cell.style->font_style;
- char bgcolor[32];
- if (format_color (fs->bg[y % 2],
- (struct cell_color) CELL_COLOR_WHITE,
- bgcolor, sizeof bgcolor))
- put_style (&style, "background", bgcolor);
-
- char fgcolor[32];
- if (format_color (fs->fg[y % 2],
- (struct cell_color) CELL_COLOR_BLACK,
- fgcolor, sizeof fgcolor))
- put_style (&style, "color", fgcolor);
-
- if (fs->typeface)
- {
- put_style (&style, "font-family", "\"");
- escape_string (html->file, fs->typeface, " ", "\n");
- putc ('"', html->file);
- }
- if (fs->bold)
- put_style (&style, "font-weight", "bold");
- if (fs->italic)
- put_style (&style, "font-style", "italic");
- if (fs->underline)
- put_style (&style, "text-decoration", "underline");
- if (fs->size)
+ if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
{
- char buf[32];
- snprintf (buf, sizeof buf, "%dpt", fs->size);
- put_style (&style, "font-size", buf);
+ bool is_header = (y < t->h[V][0]
+ || y >= t->n[V] - t->h[V][1]
+ || x < t->h[H][0]
+ || x >= t->n[H] - t->h[H][1]);
+ const char *tag = is_header ? "th" : "td";
+ html_put_table_cell (html, t, &cell, tag, html->borders);
}
- int colspan = table_cell_colspan (&cell);
- int rowspan = table_cell_rowspan (&cell);
-
- if (html->borders)
- {
- /* Cell borders. */
- struct cell_color color;
-
- int top = table_get_rule (t, TABLE_VERT, x, y, &color);
- put_border (&style, top, &color, "top");
-
- if (y + rowspan == t->n[V])
- {
- int bottom = table_get_rule (t, TABLE_VERT, x, y + rowspan,
- &color);
- put_border (&style, bottom, &color, "bottom");
- }
-
- int left = table_get_rule (t, TABLE_HORZ, x, y, &color);
- put_border (&style, left, &color, "left");
-
- if (x + colspan == t->n[H])
- {
- int right = table_get_rule (t, TABLE_HORZ, x + colspan, y,
- &color);
- put_border (&style, right, &color, "right");
- }
- }
- style_end (&style);
-
- if (colspan > 1)
- fprintf (html->file, " colspan=\"%d\"", colspan);
-
- if (rowspan > 1)
- fprintf (html->file, " rowspan=\"%d\"", rowspan);
-
- putc ('>', html->file);
-
- html_put_table_cell_text (html, &cell);
-
- /* output </th> or </td>. */
- fprintf (html->file, "</%s>\n", tag);
-
- next_1:
x = cell.d[TABLE_HORZ][1];
}
fputs ("</tr>\n", html->file);
xmlTextWriterEndElement (odt->content_wtr);
}
+static void
+write_table_item_cell (struct odt_driver *odt,
+ const struct table_cell *cell)
+{
+ if (!cell)
+ return;
+
+ xmlTextWriterStartElement (odt->content_wtr, _xml("text:h"));
+ xmlTextWriterWriteFormatAttribute (odt->content_wtr,
+ _xml("text:outline-level"), "%d", 2);
+ xmlTextWriterWriteString (odt->content_wtr, _xml (cell->text));
+ for (size_t i = 0; i < cell->n_footnotes; i++)
+ write_footnote (odt, cell->footnotes[i]);
+ xmlTextWriterEndElement (odt->content_wtr);
+}
+
static void
write_table_item_layers (struct odt_driver *odt,
const struct table_item_layers *layers)
int r, c;
/* Write a heading for the table */
- write_table_item_text (odt, table_item_get_title (item));
+ write_table_item_cell (odt, table_item_get_title (item));
write_table_item_layers (odt, table_item_get_layers (item));
/* Start table */
return out;
}
+static int
+format_cell (const struct pivot_value *value, int style_idx,
+ enum settings_value_show show_values,
+ enum settings_value_show show_variables,
+ bool rotate_label, struct string *s)
+{
+ int options = style_idx << TAB_STYLE_SHIFT;
+ if (value)
+ {
+ bool numeric = pivot_value_format_body (value, show_values,
+ show_variables, s);
+ if (numeric)
+ options |= TAB_NUMERIC;
+ if (value->font_style && value->font_style->markup)
+ options |= TAB_MARKUP;
+ if (rotate_label)
+ options |= TAB_ROTATE;
+ }
+ return options;
+}
+
static void
fill_cell (struct table *t, int x1, int y1, int x2, int y2,
const struct table_area_style *style, int style_idx,
enum settings_value_show show_variables,
bool rotate_label)
{
-
struct string s = DS_EMPTY_INITIALIZER;
- int opts = style_idx << TAB_STYLE_SHIFT;
- if (value)
- {
- bool numeric = pivot_value_format_body (value, show_values,
- show_variables, &s);
- if (numeric)
- opts |= TAB_NUMERIC;
- if (value->font_style && value->font_style->markup)
- opts |= TAB_MARKUP;
- if (rotate_label)
- opts |= TAB_ROTATE;
- }
- table_joint_text (t, x1, y1, x2, y2, opts, ds_cstr (&s));
+ int options = format_cell (value, style_idx,
+ show_values, show_variables, rotate_label, &s);
+ table_joint_text (t, x1, y1, x2, y2, options, ds_cstr (&s));
ds_destroy (&s);
if (value)
}
}
+static struct table_cell *
+pivot_value_to_table_cell (const struct pivot_value *value,
+ const struct table_area_style *style, int style_idx,
+ struct footnote **footnotes,
+ enum settings_value_show show_values,
+ enum settings_value_show show_variables)
+{
+ if (!value)
+ return NULL;
+
+ struct string s = DS_EMPTY_INITIALIZER;
+ int options = format_cell (value, style_idx,
+ show_values, show_variables, false, &s);
+
+ struct table_cell *cell = xmalloc (sizeof *cell);
+ *cell = (struct table_cell) {
+ .options = options,
+ .text = ds_steal_cstr (&s),
+ .style = table_area_style_override (
+ NULL, style, value->cell_style, value->font_style, false),
+ };
+
+ if (value->n_subscripts)
+ {
+ cell->subscripts = xnmalloc (value->n_subscripts,
+ sizeof *cell->subscripts);
+ cell->n_subscripts = value->n_subscripts;
+ for (size_t i = 0; i < value->n_subscripts; i++)
+ cell->subscripts[i] = xstrdup (value->subscripts[i]);
+ }
+
+ if (value->n_footnotes)
+ {
+ cell->footnotes = xnmalloc (value->n_footnotes, sizeof *cell->footnotes);
+ for (size_t i = 0; i < value->n_footnotes; i++)
+ {
+ struct footnote *f = footnotes[value->footnotes[i]->idx];
+ if (f)
+ cell->footnotes[cell->n_footnotes++] = f;
+ }
+ }
+
+ return cell;
+}
+
static struct table_item_text *
pivot_value_to_table_item_text (const struct pivot_value *value,
const struct table_area_style *area,
if (pt->title)
{
- struct table_item_text *title = pivot_value_to_table_item_text (
- pt->title, &pt->look->areas[PIVOT_AREA_TITLE], footnotes,
- pt->show_values, pt->show_variables);
+ struct table_cell *title = pivot_value_to_table_cell (
+ pt->title, &pt->look->areas[PIVOT_AREA_TITLE], PIVOT_AREA_TITLE,
+ footnotes, pt->show_values, pt->show_variables);
table_item_set_title (ti, title);
- table_item_text_destroy (title);
+ table_cell_destroy (title);
}
const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
/* Appends a text representation of the body of VALUE to OUT. SHOW_VALUES and
SHOW_VARIABLES control whether variable and value labels are included.
- The "body" omits subscripts and superscripts and footnotes. */
+ The "body" omits subscripts and superscripts and footnotes.
+
+ Returns true if OUT is a number (or a number plus a value label), false
+ otherwise. */
bool
pivot_value_format_body (const struct pivot_value *value,
enum settings_value_show show_values,
free (f);
}
+static void
+add_table_cell_page (struct render_pager *p, const struct table_cell *cell,
+ int min_width)
+{
+ if (!cell)
+ return;
+
+ struct table *tab = table_create (1, 1, 0, 0, 0, 0);
+ table_text (tab, 0, 0, 0, cell->text);
+ for (size_t i = 0; i < cell->n_footnotes; i++)
+ table_add_footnote (tab, 0, 0, cell->footnotes[i]);
+ if (cell->style)
+ tab->styles[0] = table_area_style_clone (tab->container, cell->style);
+ render_pager_add_table (p, tab, min_width);
+}
+
static void
add_text_page (struct render_pager *p, const struct table_item_text *t,
int min_width)
/* Create the pager. */
struct render_pager *p = xmalloc (sizeof *p);
*p = (struct render_pager) { .params = params, .scale = scale };
- add_text_page (p, table_item_get_title (table_item), body_width);
+ add_table_cell_page (p, table_item_get_title (table_item), body_width);
add_layers_page (p, table_item_get_layers (table_item), body_width);
render_pager_add_table (p, table_ref (table_item_get_table (table_item)), 0);
add_text_page (p, table_item_get_caption (table_item), 0);
#include "output/output-item-provider.h"
#include "output/pivot-table.h"
#include "output/table-item.h"
+#include "output/table-provider.h"
#include "gl/xalloc.h"
/* Returns ITEM's title, which is a null pointer if no title has been
set. */
-const struct table_item_text *
+const struct table_cell *
table_item_get_title (const struct table_item *item)
{
return item->title;
This function may only be used on a table_item that is unshared. */
void
-table_item_set_title (struct table_item *item,
- const struct table_item_text *title)
+table_item_set_title (struct table_item *item, const struct table_cell *title)
{
assert (!table_item_is_shared (item));
- table_item_text_destroy (item->title);
- item->title = table_item_text_clone (title);
+ table_cell_destroy (item->title);
+ item->title = table_cell_clone (title);
}
/* Returns ITEM's layers, which will be a null pointer if no layers have been
table_item_get_label (const struct output_item *output_item)
{
const struct table_item *item = to_table_item (output_item);
- return (item->title && item->title->content
- ? item->title->content
+ return (item->title && item->title->text
+ ? item->title->text
: _("Table"));
}
table_item_destroy (struct output_item *output_item)
{
struct table_item *item = to_table_item (output_item);
- table_item_text_destroy (item->title);
+ table_cell_destroy (item->title);
table_item_text_destroy (item->caption);
table_item_layers_destroy (item->layers);
free (item->notes);
{
struct output_item output_item; /* Superclass. */
struct table *table; /* The table to be rendered. */
- struct table_item_text *title; /* Null if there is no title. */
+ struct table_cell *title; /* Null if there is no title. */
struct table_item_text *caption; /* Null if there is no caption. */
struct table_item_layers *layers; /* Null if there is no layer info. */
char *notes; /* Shown as tooltip. */
const struct table *table_item_get_table (const struct table_item *);
-const struct table_item_text *table_item_get_title (const struct table_item *);
-void table_item_set_title (struct table_item *,
- const struct table_item_text *);
+const struct table_cell *table_item_get_title (const struct table_item *);
+void table_item_set_title (struct table_item *, const struct table_cell *);
const struct table_item_layers *table_item_get_layers (
const struct table_item *);
struct table_area_style *style;
};
+struct footnote *footnote_clone (const struct footnote *);
+void footnote_destroy (struct footnote *);
+
/* A cell in a table. */
struct table_cell
{
}
}
+struct footnote *
+footnote_clone (const struct footnote *old)
+{
+ struct footnote *new = xmalloc (sizeof *new);
+ *new = (struct footnote) {
+ .idx = old->idx,
+ .content = old->content ? xstrdup (old->content) : NULL,
+ .marker = old->marker ? xstrdup (old->marker) : NULL,
+ .style = old->style ? table_area_style_clone (NULL, old->style) : NULL,
+ };
+ return new;
+}
+
+void
+footnote_destroy (struct footnote *f)
+{
+ if (f)
+ {
+ free (f->content);
+ free (f->marker);
+ if (f->style)
+ {
+ table_area_style_uninit (f->style);
+ free (f->style);
+ }
+ free (f);
+ }
+}
+
+struct table_cell *
+table_cell_clone (const struct table_cell *old)
+{
+ struct table_cell *new = xmalloc (sizeof *new);
+ *new = *old;
+ new->text = xstrdup (new->text);
+
+ if (old->n_subscripts)
+ {
+ new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
+ for (size_t i = 0; i < old->n_subscripts; i++)
+ new->subscripts[i] = xstrdup (old->subscripts[i]);
+ }
+ else
+ new->subscripts = NULL;
+
+ if (old->n_footnotes)
+ {
+ new->footnotes = xnmalloc (old->n_footnotes, sizeof *new->footnotes);
+ for (size_t i = 0; i < old->n_footnotes; i++)
+ new->footnotes[i] = footnote_clone (old->footnotes[i]);
+ }
+ else
+ new->footnotes = NULL;
+
+ if (old->style)
+ new->style = table_area_style_clone (NULL, old->style);
+
+ return new;
+}
+
+void
+table_cell_destroy (struct table_cell *cell)
+{
+ if (!cell)
+ return;
+
+ free (cell->text);
+ for (size_t i = 0; i < cell->n_subscripts; i++)
+ free (cell->subscripts[i]);
+ free (cell->subscripts);
+ for (size_t i = 0; i < cell->n_footnotes; i++)
+ footnote_destroy (cell->footnotes[i]);
+ free (cell->footnotes);
+ if (cell->style)
+ {
+ table_area_style_uninit (cell->style);
+ free (cell->style);
+ }
+ free (cell);
+}
+
void
table_cell_format_footnote_markers (const struct table_cell *cell,
struct string *s)
}
}
- const struct table_item_text *title = table_item_get_title (item);
+ const struct table_cell *title = table_item_get_title (item);
if (title)
footnotes = add_footnotes (title->footnotes, title->n_footnotes,
footnotes, &allocated, &n);
}
static void
-tex_put_table_item_text (struct tex_driver *tex,
- const struct table_item_text *text)
+tex_put_table_cell (struct tex_driver *tex, const struct table_cell *cell)
{
- tex_escape_string (tex, text->content, false);
- tex_put_footnote_markers (tex, text->footnotes, text->n_footnotes);
+ tex_escape_string (tex, cell->text, false);
+ tex_put_footnote_markers (tex, cell->footnotes, cell->n_footnotes);
}
static void
struct footnote **f;
size_t n_footnotes = table_collect_footnotes (item, &f);
- const struct table_item_text *title = table_item_get_title (item);
+ const struct table_cell *title = table_item_get_title (item);
const struct table_item_layers *layers = table_item_get_layers (item);
if (title || layers)
{
if (title)
{
shipout (&tex->token_list, "{\\bf ");
- tex_put_table_item_text (tex, title);
+ tex_put_table_cell (tex, title);
shipout (&tex->token_list, "}");
}
if (layers)