output: Add support for colors for rules.
[pspp] / src / output / table.c
index bd51f494033ad346d3377e3f25e00db9e536a559..44efa3abc34f1fc379356598742212dca7ed6b10 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2009, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011, 2014, 2016 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@
 
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
+#include "libpspp/str.h"
+#include "output/table-item.h"
 
 #include "gl/xalloc.h"
 
@@ -47,7 +49,7 @@ table_unref (struct table *table)
     {
       assert (table->ref_cnt > 0);
       if (--table->ref_cnt == 0)
-        table->class->destroy (table);
+        table->klass->destroy (table);
     }
 }
 
@@ -104,7 +106,7 @@ table_set_hb (struct table *table, int hb)
 void
 table_init (struct table *table, const struct table_class *class)
 {
-  table->class = class;
+  table->klass = class;
   table->n[TABLE_HORZ] = table->n[TABLE_VERT] = 0;
   table->h[TABLE_HORZ][0] = table->h[TABLE_HORZ][1] = 0;
   table->h[TABLE_VERT][0] = table->h[TABLE_VERT][1] = 0;
@@ -127,6 +129,26 @@ table_set_nr (struct table *table, int nr)
   table->n[TABLE_VERT] = nr;
 }
 \f
+struct cell_style *
+cell_style_clone (const struct cell_style *old)
+{
+  struct cell_style *new = xmalloc (sizeof *new);
+  *new = *old;
+  if (new->font)
+    new->font = strdup (new->font);
+  return new;
+}
+
+void
+cell_style_free (struct cell_style *style)
+{
+  if (style)
+    {
+      free (style->font);
+      free (style);
+    }
+}
+
 /* Initializes CELL with the contents of the table cell at column X and row Y
    within TABLE.  When CELL is no longer needed, the caller is responsible for
    freeing it by calling table_cell_free(CELL).
@@ -138,7 +160,11 @@ table_get_cell (const struct table *table, int x, int y,
 {
   assert (x >= 0 && x < table->n[TABLE_HORZ]);
   assert (y >= 0 && y < table->n[TABLE_VERT]);
-  table->class->get_cell (table, x, y, cell);
+
+  static const struct cell_style default_style = CELL_STYLE_INITIALIZER;
+  cell->style = &default_style;
+
+  table->klass->get_cell (table, x, y, cell);
 }
 
 /* Frees CELL, which should have been initialized by calling
@@ -188,11 +214,87 @@ table_cell_free (struct table_cell *cell)
    between that cell and cell (0,1); and so on, up to (0,NR), which runs
    horizontally below cell (0,NR-1). */
 int
-table_get_rule (const struct table *table, enum table_axis axis, int x, int y)
+table_get_rule (const struct table *table, enum table_axis axis, int x, int y,
+                struct cell_color *color)
 {
   assert (x >= 0 && x < table->n[TABLE_HORZ] + (axis == TABLE_HORZ));
   assert (y >= 0 && y < table->n[TABLE_VERT] + (axis == TABLE_VERT));
-  return table->class->get_rule (table, axis, x, y);
+  *color = CELL_COLOR_BLACK;
+  return table->klass->get_rule (table, axis, x, y, color);
+}
+
+void
+cell_contents_format_footnote_markers (const struct cell_contents *c,
+                                       struct string *s)
+{
+  for (size_t i = 0; i < c->n_footnotes; i++)
+    {
+      if (i)
+        ds_put_byte (s, ',');
+      ds_put_cstr (s, c->footnotes[i]->marker);
+    }
+}
+
+static const struct footnote **
+add_footnotes (const struct footnote **refs, size_t n_refs,
+               const struct footnote **footnotes, size_t *allocated, size_t *n)
+{
+  for (size_t i = 0; i < n_refs; i++)
+    {
+      const struct footnote *f = refs[i];
+      if (f->idx >= *allocated)
+        {
+          size_t new_allocated = (f->idx + 1) * 2;
+          footnotes = xrealloc (footnotes, new_allocated * sizeof *footnotes);
+          while (*allocated < new_allocated)
+            footnotes[(*allocated)++] = NULL;
+        }
+      footnotes[f->idx] = f;
+      if (f->idx >= *n)
+        *n = f->idx + 1;
+    }
+  return footnotes;
+}
+
+size_t
+table_collect_footnotes (const struct table_item *item,
+                         const struct footnote ***footnotesp)
+{
+  const struct footnote **footnotes = NULL;
+  size_t allocated = 0;
+  size_t n = 0;
+
+  struct table *t = item->table;
+  for (int y = 0; y < table_nr (t); y++)
+    {
+      struct table_cell cell;
+      for (int x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1])
+        {
+          table_get_cell (t, x, y, &cell);
+
+          if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
+            for (size_t i = 0; i < cell.n_contents; i++)
+              {
+                const struct cell_contents *c = &cell.contents[i];
+                footnotes = add_footnotes (c->footnotes, c->n_footnotes,
+                                           footnotes, &allocated, &n);
+              }
+          table_cell_free (&cell);
+        }
+    }
+
+  const struct table_item_text *title = table_item_get_title (item);
+  if (title)
+    footnotes = add_footnotes (title->footnotes, title->n_footnotes,
+                               footnotes, &allocated, &n);
+
+  const struct table_item_text *caption = table_item_get_caption (item);
+  if (caption)
+    footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
+                               footnotes, &allocated, &n);
+
+  *footnotesp = footnotes;
+  return n;
 }
 \f
 struct table_unshared
@@ -233,7 +335,7 @@ table_unshare (struct table *table)
 static struct table_unshared *
 table_unshared_cast (const struct table *table)
 {
-  assert (table->class == &table_unshared_class);
+  assert (table->klass == &table_unshared_class);
   return UP_CAST (table, struct table_unshared, table);
 }
 
@@ -255,10 +357,11 @@ table_unshared_get_cell (const struct table *tiu_, int x, int y,
 
 static int
 table_unshared_get_rule (const struct table *tiu_,
-                              enum table_axis axis, int x, int y)
+                         enum table_axis axis, int x, int y,
+                         struct cell_color *color)
 {
   struct table_unshared *tiu = table_unshared_cast (tiu_);
-  return table_get_rule (tiu->subtable, axis, x, y);
+  return table_get_rule (tiu->subtable, axis, x, y, color);
 }
 
 static const struct table_class table_unshared_class =
@@ -295,7 +398,7 @@ table_from_string (unsigned int options, const char *s)
 static struct table_string *
 table_string_cast (const struct table *table)
 {
-  assert (table->class == &table_string_class);
+  assert (table->klass == &table_string_class);
   return UP_CAST (table, struct table_string, table);
 }
 
@@ -316,15 +419,19 @@ table_string_get_cell (const struct table *ts_, int x UNUSED, int y UNUSED,
   cell->d[TABLE_HORZ][1] = 1;
   cell->d[TABLE_VERT][0] = 0;
   cell->d[TABLE_VERT][1] = 1;
-  cell->contents = ts->string;
-  cell->options = ts->options;
+  cell->contents = &cell->inline_contents;
+  cell->inline_contents.options = ts->options;
+  cell->inline_contents.text = ts->string;
+  cell->inline_contents.n_footnotes = 0;
+  cell->n_contents = 1;
   cell->destructor = NULL;
 }
 
 
 static int
 table_string_get_rule (const struct table *ts UNUSED,
-                       enum table_axis axis UNUSED, int x UNUSED, int y UNUSED)
+                       enum table_axis axis UNUSED, int x UNUSED, int y UNUSED,
+                       struct cell_color *color UNUSED)
 {
   return TAL_0;
 }