more work toward making table_item just a pivot_Table
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 30 Dec 2020 01:20:59 +0000 (17:20 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Thu, 31 Dec 2020 03:58:11 +0000 (19:58 -0800)
21 files changed:
src/output/ascii.c
src/output/cairo-fsm.c
src/output/cairo-fsm.h
src/output/cairo-pager.c
src/output/cairo-pager.h
src/output/cairo.c
src/output/csv.c
src/output/html.c
src/output/odt.c
src/output/pivot-output.c
src/output/pivot-output.h
src/output/pivot-table.c
src/output/pivot-table.h
src/output/render.c
src/output/render.h
src/output/table-provider.h
src/output/table.c
src/output/table.h
src/output/tex.c
src/output/text-item.c
src/ui/gui/psppire-output-view.c

index c058f23f8a645068ce33de1ca4eda607c339242c..9a08a893317d656b588696e800ed5d179e001661 100644 (file)
@@ -54,6 +54,8 @@
 #include "output/driver-provider.h"
 #include "output/message-item.h"
 #include "output/options.h"
+#include "output/pivot-output.h"
+#include "output/pivot-table.h"
 #include "output/render.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
@@ -558,21 +560,22 @@ static void
 ascii_output_table_item (struct ascii_driver *a,
                          const struct table_item *table_item)
 {
-  struct render_pager *p;
-
   update_page_size (a, false);
 
-  if (a->object_cnt++)
-    putc ('\n', a->file);
-
-  p = render_pager_create (&a->params, table_item);
-  for (int i = 0; render_pager_has_next (p); i++)
+  size_t *layer_indexes;
+  PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, table_item->pt, true)
     {
-      if (i)
-        putc ('\n', a->file);
-      ascii_output_lines (a, render_pager_draw_next (p, INT_MAX));
+      struct render_pager *p = render_pager_create (&a->params, table_item,
+                                                    layer_indexes);
+      for (int i = 0; render_pager_has_next (p); i++)
+        {
+          if (a->object_cnt++)
+            putc ('\n', a->file);
+
+          ascii_output_lines (a, render_pager_draw_next (p, INT_MAX));
+        }
+      render_pager_destroy (p);
     }
-  render_pager_destroy (p);
 }
 
 static void
index 58bbf230d5aada148969733bd73eefe4ebdb66e5..5e6befc3d761093dc15e09b533135d31e6d18e14 100644 (file)
@@ -41,6 +41,8 @@
 #include "output/message-item.h"
 #include "output/page-eject-item.h"
 #include "output/page-setup-item.h"
+#include "output/pivot-output.h"
+#include "output/pivot-table.h"
 #include "output/render.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
@@ -105,6 +107,7 @@ xr_fsm_style_equals (const struct xr_fsm_style *a,
       || a->min_break[H] != b->min_break[H]
       || a->min_break[V] != b->min_break[V]
       || a->use_system_colors != b->use_system_colors
+      || a->object_spacing != b->object_spacing
       || a->font_resolution != b->font_resolution)
     return false;
 
@@ -134,14 +137,14 @@ struct xr_fsm
     struct output_item *item;
     bool print;
 
+    /* Print mode only. */
+    bool done;
+
     /* Table items only. */
     size_t *layer_indexes;
     struct render_params rp;
     struct render_pager *p;
     cairo_t *cairo;             /* XXX should this be here?! */
-
-    /* Chart and page-eject items only. */
-    bool done;
   };
 
 /* The unit used for internal measurements is inch/(72 * XR_POINT).
@@ -1020,7 +1023,8 @@ xr_fsm_create (const struct output_item *item_,
   size_t *layer_indexes = NULL;
   if (is_table_item (item))
     {
-      layer_indexes = pivot_table_next_layer (table_item->pt, NULL, print);
+      const struct table_item *table_item = to_table_item (item);
+      layer_indexes = pivot_output_next_layer (table_item->pt, NULL, print);
       if (!layer_indexes)
         return NULL;
     }
@@ -1045,10 +1049,6 @@ xr_fsm_create (const struct output_item *item_,
       [RENDER_LINE_DOUBLE] = 2 * LW + LS,
     };
 
-  size_t *layer_indexes = NULL;
-  if (is_table_item (item)
-  pivot_table_next_display_layer (
-
   struct xr_fsm *fsm = xmalloc (sizeof *fsm);
   *fsm = (struct xr_fsm) {
     .style = xr_fsm_style_ref (style),
@@ -1093,13 +1093,20 @@ xr_fsm_create (const struct output_item *item_,
       struct table_item *table_item = to_table_item (item);
 
       fsm->cairo = cr;
-      fsm->p = render_pager_create (&fsm->rp, table_item);
+      fsm->p = render_pager_create (&fsm->rp, table_item, fsm->layer_indexes);
       fsm->cairo = NULL;
     }
 
   return fsm;
 }
 
+struct xr_fsm *
+xr_fsm_create_for_printing (const struct output_item *item,
+                            const struct xr_fsm_style *style, cairo_t *cr)
+{
+  return xr_fsm_create (item, style, cr, true);
+}
+
 void
 xr_fsm_destroy (struct xr_fsm *fsm)
 {
@@ -1107,17 +1114,27 @@ xr_fsm_destroy (struct xr_fsm *fsm)
     {
       xr_fsm_style_unref (fsm->style);
       output_item_unref (fsm->item);
+      free (fsm->layer_indexes);
       render_pager_destroy (fsm->p);
       assert (!fsm->cairo);
       free (fsm);
     }
 }
+\f
+/* Scrolling API. */
+
+struct xr_fsm *
+xr_fsm_create_for_scrolling (const struct output_item *item,
+                             const struct xr_fsm_style *style, cairo_t *cr)
+{
+  return xr_fsm_create (item, style, cr, false);
+}
 
-/* This is primarily meant for use with screen rendering since the result is a
-   fixed value for charts. */
 void
 xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp)
 {
+  assert (!fsm->print);
+
   int w, h;
 
   if (is_table_item (fsm->item))
@@ -1141,38 +1158,10 @@ xr_fsm_measure (struct xr_fsm *fsm, cairo_t *cr, int *wp, int *hp)
     *hp = h;
 }
 
-static int
-xr_fsm_draw_table (struct xr_fsm *fsm, int space)
-{
-  return (render_pager_has_next (fsm->p)
-          ? render_pager_draw_next (fsm->p, space)
-          : 0);
-}
-
-static int
-xr_fsm_draw_chart (struct xr_fsm *fsm, int space)
-{
-  const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]);
-  if (space < chart_height)
-    return 0;
-
-  fsm->done = true;
-  xr_draw_chart (to_chart_item (fsm->item), fsm->cairo,
-                 xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height));
-  return chart_height;
-}
-
-static int
-xr_fsm_draw_eject (struct xr_fsm *fsm, int space)
-{
-  if (space >= fsm->rp.size[V])
-    fsm->done = true;
-  return 0;
-}
-
 void
 xr_fsm_draw_all (struct xr_fsm *fsm, cairo_t *cr)
 {
+  assert (!fsm->print);
   xr_fsm_draw_region (fsm, cr, 0, 0, INT_MAX, INT_MAX);
 }
 
@@ -1188,6 +1177,7 @@ void
 xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr,
                     int x, int y, int w, int h)
 {
+  assert (!fsm->print);
   if (is_table_item (fsm->item))
     {
       fsm->cairo = cr;
@@ -1204,11 +1194,65 @@ xr_fsm_draw_region (struct xr_fsm *fsm, cairo_t *cr,
   else
     NOT_REACHED ();
 }
+\f
+/* Printing API. */
+
+static int
+xr_fsm_draw_table (struct xr_fsm *fsm, int space)
+{
+  struct table_item *table_item = to_table_item (fsm->item);
+  int used = render_pager_draw_next (fsm->p, space);
+  if (!render_pager_has_next (fsm->p))
+    {
+      render_pager_destroy (fsm->p);
+
+      fsm->layer_indexes = pivot_output_next_layer (table_item->pt,
+                                                    fsm->layer_indexes, true);
+      if (fsm->layer_indexes)
+        {
+          fsm->p = render_pager_create (&fsm->rp, table_item,
+                                        fsm->layer_indexes);
+          if (table_item->pt->look->paginate_layers)
+            used = space;
+          else
+            used += fsm->style->object_spacing;
+        }
+      else
+        {
+          fsm->p = NULL;
+          fsm->done = true;
+        }
+    }
+  return MIN (used, space);
+}
+
+static int
+xr_fsm_draw_chart (struct xr_fsm *fsm, int space)
+{
+  const int chart_height = 0.8 * MIN (fsm->rp.size[H], fsm->rp.size[V]);
+  if (space < chart_height)
+    return 0;
+
+  fsm->done = true;
+  xr_draw_chart (to_chart_item (fsm->item), fsm->cairo,
+                 xr_to_pt (fsm->rp.size[H]), xr_to_pt (chart_height));
+  return chart_height;
+}
+
+static int
+xr_fsm_draw_eject (struct xr_fsm *fsm, int space)
+{
+  if (space >= fsm->rp.size[V])
+    fsm->done = true;
+  return 0;
+}
 
 int
 xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space)
 {
-  if (xr_fsm_is_empty (fsm))
+  assert (fsm->print);
+
+  if (fsm->done)
     return 0;
 
   cairo_save (cr);
@@ -1223,11 +1267,10 @@ xr_fsm_draw_slice (struct xr_fsm *fsm, cairo_t *cr, int space)
   return used;
 }
 
-
 bool
 xr_fsm_is_empty (const struct xr_fsm *fsm)
 {
-  return (is_table_item (fsm->item)
-          ? !render_pager_has_next (fsm->p)
-          : fsm->done);
+  assert (fsm->print);
+
+  return fsm->done;
 }
index 906ce12be3dc3a8deb3a03c63ed767ef28596747..8c8892378710ba5631fefdbedb01aebc03d2e99d 100644 (file)
@@ -49,6 +49,8 @@ struct xr_fsm_style
     struct cell_color fg;
     bool use_system_colors;
 
+    int object_spacing;
+
     /* Resolution, in units per inch, used for measuring font "points".  If
        this is 72.0, for example, then 1pt = 1 device unit, which is
        appropriate for rendering to a surface created by
index d096b0caceec08a783cdaf9f0d951ea51823681a..7243fad13c397eb79b6c174e04fe2f74356df9fb 100644 (file)
@@ -95,8 +95,7 @@ xr_page_style_equals (const struct xr_page_style *a,
     if (!page_heading_equals (&a->headings[i], &b->headings[i]))
       return false;
 
-  return (a->initial_page_number == b->initial_page_number
-          && a->object_spacing == b->object_spacing);
+  return a->initial_page_number == b->initial_page_number;
 }
 \f
 struct xr_pager
@@ -219,7 +218,7 @@ xr_measure_headings (const struct xr_page_style *ps,
                                    &ps->headings[i], -1, fs->size[H], 0,
                                    fs->font_resolution);
       if (*h)
-        *h += ps->object_spacing;
+        *h += fs->object_spacing;
     }
   cairo_destroy (cairo);
   cairo_surface_destroy (surface);
@@ -319,7 +318,7 @@ xr_pager_add_page (struct xr_pager *p, cairo_t *cr)
 
   if (p->heading_heights[1])
     xr_render_page_heading (cr, font, &ps->headings[1], page_number,
-                            fs->size[H], fs->size[V] + ps->object_spacing,
+                            fs->size[H], fs->size[V] + fs->object_spacing,
                             fs->font_resolution);
 
   cairo_surface_t *surface = cairo_get_target (cr);
@@ -418,7 +417,7 @@ xr_pager_run (struct xr_pager *p)
               free (attrs);
             }
 
-          int spacing = p->page_style->object_spacing;
+          int spacing = p->fsm_style->object_spacing;
           int chunk = xr_fsm_draw_slice (p->fsm, p->cr,
                                          p->fsm_style->size[V] - p->y);
           p->y += chunk + spacing;
index bd7fa55125115a0b5ab3377cd25af3d2990554cd..361c29798b549e4f5caf847eb0a2aa8a085bfd88 100644 (file)
@@ -38,7 +38,6 @@ struct xr_page_style
     struct page_heading headings[2]; /* Top and bottom headings. */
 
     int initial_page_number;
-    int object_spacing;
 
     /* Whether to include an outline in PDF output.  (The only reason I know to
        omit it is to avoid a Cairo bug that caused crashes in some cases.) */
index 313456c663e07290efb5a88f3104741c8df35d33..b099a8f609cec84a78d5841f05dd16d3187e1e07 100644 (file)
@@ -256,7 +256,6 @@ xr_allocate (const char *name, int device_type,
     },
 
     .initial_page_number = 1,
-    .object_spacing = object_spacing,
     .include_outline = include_outline,
   };
 
@@ -271,6 +270,7 @@ xr_allocate (const char *name, int device_type,
     },
     .fg = fg,
     .use_system_colors = systemcolors,
+    .object_spacing = object_spacing,
     .font_resolution = font_resolution,
   };
 
@@ -579,7 +579,6 @@ xr_update_page_setup (struct output_driver *driver,
     },
 
     .initial_page_number = setup->initial_page_number,
-    .object_spacing = setup->object_spacing * 72 * XR_POINT,
     .include_outline = old_ps->include_outline,
   };
   for (size_t i = 0; i < 2; i++)
@@ -597,6 +596,7 @@ xr_update_page_setup (struct output_driver *driver,
     },
     .fg = old_fs->fg,
     .use_system_colors = old_fs->use_system_colors,
+    .object_spacing = setup->object_spacing * 72 * XR_POINT,
     .font_resolution = old_fs->font_resolution,
   };
   for (size_t i = 0; i < XR_N_FONTS; i++)
index bde8711314f7384c44906c7cc4f05cb0fa4ea218..ab79e32a76c19bcdaa50c86ca5b379cf7d1711de 100644 (file)
@@ -31,6 +31,7 @@
 #include "output/options.h"
 #include "output/message-item.h"
 #include "output/page-eject-item.h"
+#include "output/pivot-output.h"
 #include "output/table-item.h"
 #include "output/table-provider.h"
 
@@ -221,61 +222,64 @@ csv_output_table_cell (struct csv_driver *csv, const struct table_cell *cell,
 }
 
 static void
-csv_submit (struct output_driver *driver,
-            const struct output_item *output_item)
+csv_output_table__ (struct csv_driver *csv, const struct table *t,
+                    const char *leader)
 {
-  struct csv_driver *csv = csv_driver_cast (driver);
-
-  if (is_table_item (output_item))
+  for (int y = 0; y < t->n[TABLE_VERT]; y++)
     {
-      struct table_item *table_item = to_table_item (output_item);
-      const struct table *t = table_item_get_table (table_item);
-      int x, y;
-
-      csv_put_separator (csv);
-
-      if (csv->titles)
-        csv_output_table_cell (csv, table_item_get_title (table_item), "Table");
-
-      for (y = 0; y < t->n[TABLE_VERT]; y++)
+      for (int x = 0; x < t->n[TABLE_HORZ]; x++)
         {
-          for (x = 0; x < t->n[TABLE_HORZ]; x++)
-            {
-              struct table_cell cell;
+          struct table_cell cell;
 
-              table_get_cell (t, x, y, &cell);
+          table_get_cell (t, x, y, &cell);
 
-              if (x > 0)
-                fputs (csv->separator, csv->file);
+          if (x > 0)
+            fputs (csv->separator, csv->file);
 
-              if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
-                csv_output_field (csv, "");
-              else
-                csv_output_table_cell (csv, &cell, NULL);
-            }
-          putc ('\n', csv->file);
+          if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
+            csv_output_field (csv, "");
+          else
+            csv_output_table_cell (csv, &cell, !x ? leader : NULL);
         }
+      putc ('\n', csv->file);
+    }
+}
 
-      if (csv->captions)
-        csv_output_table_cell (csv, table_item_get_caption (table_item),
-                               "Caption");
+static void
+csv_output_table_layer (struct csv_driver *csv, const struct pivot_table *pt,
+                        const size_t *layer_indexes)
+{
+  struct table *title, *layers, *body, *caption, *footnotes;
+  pivot_output (pt, layer_indexes, &title, &layers, &body,
+                &caption, &footnotes, NULL, NULL);
+
+  csv_put_separator (csv);
+  csv_output_table__ (csv, title, "Table");
+  csv_output_table__ (csv, layers, "Layer");
+  csv_output_table__ (csv, body, NULL);
+  csv_output_table__ (csv, caption, "Caption");
+  csv_output_table__ (csv, footnotes, "Footnote");
+
+  table_unref (title);
+  table_unref (layers);
+  table_unref (body);
+  table_unref (caption);
+  table_unref (footnotes);
+}
 
-      struct footnote **f;
-      size_t n_footnotes = table_collect_footnotes (table_item, &f);
-      if (n_footnotes)
-        {
-          fputs ("\nFootnotes:\n", csv->file);
+static void
+csv_submit (struct output_driver *driver,
+            const struct output_item *output_item)
+{
+  struct csv_driver *csv = csv_driver_cast (driver);
 
-          for (size_t i = 0; i < n_footnotes; i++)
-            {
-              csv_output_field (csv, f[i]->marker);
-              fputs (csv->separator, csv->file);
-              csv_output_field (csv, f[i]->content);
-              putc ('\n', csv->file);
-            }
+  if (is_table_item (output_item))
+    {
+      const struct pivot_table *pt = to_table_item (output_item)->pt;
 
-          free (f);
-        }
+      size_t *layer_indexes;
+      PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, pt, true)
+        csv_output_table_layer (csv, pt, layer_indexes);
     }
   else if (is_text_item (output_item))
     {
index 9f9fc2db89df9804650921c282ddb5a650f58978..f8213952e1294b0bfe9a359b991c78847c6d706a 100644 (file)
@@ -41,6 +41,8 @@
 #include "output/message-item.h"
 #include "output/options.h"
 #include "output/output-item-provider.h"
+#include "output/pivot-output.h"
+#include "output/pivot-table.h"
 #include "output/table-provider.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
@@ -159,7 +161,7 @@ put_header (struct html_driver *html)
             "  margin-bottom: 1em\n"
             "}\n"
             "caption {\n"
-            "  text-align: left\n"
+            "  text-align: left;\n"
             "}\n"
             "th { font-weight: normal }\n"
             "a:link {\n"
@@ -479,20 +481,6 @@ put_border (const struct table *table, const struct table_cell *cell,
     }
 }
 
-static void
-put_tfoot (struct html_driver *html, const struct table *t, bool *tfoot)
-{
-  if (!*tfoot)
-    {
-      fputs ("<tfoot>\n", html->file);
-      fputs ("<tr>\n", html->file);
-      fprintf (html->file, "<td colspan=%d>\n", t->n[H]);
-      *tfoot = true;
-    }
-  else
-    fputs ("\n<br>", html->file);
-}
-
 static void
 html_put_footnote_markers (struct html_driver *html,
                            struct footnote **footnotes,
@@ -542,24 +530,8 @@ html_put_table_cell_text (struct html_driver *html,
 }
 
 static void
-html_put_table_item_layers (struct html_driver *html,
-                            const struct table_item_layers *layers)
-{
-  for (size_t i = 0; i < layers->n_layers; i++)
-    {
-      if (i)
-        fputs ("<br>\n", html->file);
-
-      const struct table_item_layer *layer = &layers->layers[i];
-      escape_string (html->file, layer->content, " ", "<br>");
-      html_put_footnote_markers (html, layer->footnotes, layer->n_footnotes);
-    }
-}
-
-static void
-html_put_table_cell (struct html_driver *html, const struct table *t,
-                     const struct table_cell *cell, const char *tag,
-                     bool border)
+html_put_table_cell (struct html_driver *html, const struct table_cell *cell,
+                     const char *tag, const struct table *t)
 {
   fprintf (html->file, "<%s", tag);
 
@@ -623,7 +595,7 @@ html_put_table_cell (struct html_driver *html, const struct table *t,
       put_style (&style, "font-size", buf);
     }
 
-  if (border)
+  if (t && html->borders)
     {
       put_border (t, cell, &style, V, 0, 0, "top");
       put_border (t, cell, &style, H, 0, 0, "left");
@@ -652,83 +624,115 @@ html_put_table_cell (struct html_driver *html, const struct table *t,
 }
 
 static void
-html_output_table (struct html_driver *html, const struct table_item *item)
+html_output_table_layer (struct html_driver *html, const struct pivot_table *pt,
+                         const size_t *layer_indexes)
 {
-  const struct table *t = table_item_get_table (item);
-  bool tfoot = false;
+  struct table *title, *layers, *body, *caption, *footnotes;
+  pivot_output (pt, layer_indexes, &title, &layers, &body,
+                &caption, &footnotes, NULL, NULL);
 
   fputs ("<table", html->file);
-  if (item->notes)
+  if (pt->notes)
     {
       fputs (" title=\"", html->file);
-      escape_string (html->file, item->notes, " ", "\n");
+      escape_string (html->file, pt->notes, " ", "\n");
       putc ('"', html->file);
     }
   fputs (">\n", html->file);
 
-  const struct table_cell *caption = table_item_get_caption (item);
-  if (caption)
+  if (title)
     {
-      put_tfoot (html, t, &tfoot);
-      html_put_table_cell (html, t, caption, "span", false);
+      struct table_cell cell;
+      table_get_cell (title, 0, 0, &cell);
+      html_put_table_cell (html, &cell, "caption", NULL);
     }
-  struct footnote **f;
-  size_t n_footnotes = table_collect_footnotes (item, &f);
 
-  for (size_t i = 0; i < n_footnotes; i++)
+  if (layers)
     {
-      put_tfoot (html, t, &tfoot);
-      escape_tag (html->file, "sup", f[i]->marker, " ", "<br>");
-      escape_string (html->file, f[i]->content, " ", "<br>");
-    }
-  free (f);
-  if (tfoot)
-    {
-      fputs ("</td>\n", html->file);
-      fputs ("</tr>\n", html->file);
-      fputs ("</tfoot>\n", html->file);
-    }
+      fputs ("<thead>\n", html->file);
+      for (size_t y = 0; y < layers->n[V]; y++)
+        {
+          fputs ("<tr>\n", html->file);
 
-  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_cell (html, t, title, "span", false);
-      if (title && layers)
-        fputs ("<br>\n", html->file);
-      if (layers)
-        html_put_table_item_layers (html, layers);
-      fputs ("</caption>\n", html->file);
+          struct table_cell cell;
+          table_get_cell (layers, 0, y, &cell);
+          cell.d[H][1] = body->n[H];
+          html_put_table_cell (html, &cell, "td", NULL);
+
+          fputs ("</tr>\n", html->file);
+        }
+      fputs ("</thead>\n", html->file);
     }
 
   fputs ("<tbody>\n", html->file);
-
-  for (int y = 0; y < t->n[V]; y++)
+  for (int y = 0; y < body->n[V]; y++)
     {
       fputs ("<tr>\n", html->file);
-      for (int x = 0; x < t->n[H]; )
+      for (int x = 0; x < body->n[H]; )
         {
           struct table_cell cell;
-          table_get_cell (t, x, y, &cell);
+          table_get_cell (body, x, y, &cell);
           if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0])
             {
-              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]);
+              bool is_header = (y < body->h[V][0]
+                                || y >= body->n[V] - body->h[V][1]
+                                || x < body->h[H][0]
+                                || x >= body->n[H] - body->h[H][1]);
               const char *tag = is_header ? "th" : "td";
-              html_put_table_cell (html, t, &cell, tag, html->borders);
+              html_put_table_cell (html, &cell, tag, body);
             }
 
           x = cell.d[TABLE_HORZ][1];
         }
       fputs ("</tr>\n", html->file);
     }
-
   fputs ("</tbody>\n", html->file);
+
+  if (caption || footnotes)
+    {
+      fprintf (html->file, "<tfoot>\n");
+
+      if (caption)
+        {
+          fputs ("<tr>\n", html->file);
+
+          struct table_cell cell;
+          table_get_cell (caption, 0, 0, &cell);
+          cell.d[H][1] = body->n[H];
+          html_put_table_cell (html, &cell, "td", NULL);
+
+          fputs ("</tr>\n", html->file);
+        }
+
+      for (size_t y = 0; y < footnotes->n[V]; y++)
+        {
+          fputs ("<tr>\n", html->file);
+
+          struct table_cell cell;
+          table_get_cell (footnotes, 0, y, &cell);
+          cell.d[H][1] = body->n[H];
+          html_put_table_cell (html, &cell, "td", NULL);
+
+          fputs ("</tr>\n", html->file);
+        }
+      fputs ("</tfoot>\n", html->file);
+    }
+
   fputs ("</table>\n\n", html->file);
+
+  table_unref (title);
+  table_unref (layers);
+  table_unref (body);
+  table_unref (caption);
+  table_unref (footnotes);
+}
+
+static void
+html_output_table (struct html_driver *html, const struct table_item *item)
+{
+  size_t *layer_indexes;
+  PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true)
+    html_output_table_layer (html, item->pt, layer_indexes);
 }
 
 struct output_driver_factory html_driver_factory =
index 9397bf142574359aca5cd7439214c693a8de2ebe..4fdccd1424530a01d4257313914240744514b169 100644 (file)
@@ -40,6 +40,8 @@
 #include "output/driver-provider.h"
 #include "output/message-item.h"
 #include "output/options.h"
+#include "output/pivot-table.h"
+#include "output/pivot-output.h"
 #include "output/table-item.h"
 #include "output/table-provider.h"
 #include "output/text-item.h"
@@ -443,34 +445,30 @@ write_table_item_cell (struct odt_driver *odt,
 }
 
 static void
-write_table_item_layers (struct odt_driver *odt,
-                         const struct table_item_layers *layers)
+write_table__ (struct odt_driver *odt, const struct table *t)
 {
-  if (!layers)
-    return;
-
-  for (size_t i = 0; i < layers->n_layers; i++)
+  if (t)
     {
-      const struct table_item_layer *layer = &layers->layers[i];
-      xmlTextWriterStartElement (odt->content_wtr, _xml("text:h"));
-      xmlTextWriterWriteFormatAttribute (odt->content_wtr,
-                                         _xml("text:outline-level"), "%d", 2);
-      xmlTextWriterWriteString (odt->content_wtr, _xml (layer->content));
-      for (size_t i = 0; i < layer->n_footnotes; i++)
-        write_footnote (odt, layer->footnotes[i]);
-      xmlTextWriterEndElement (odt->content_wtr);
+      for (size_t y = 0; y < t->n[V]; y++)
+        {
+          struct table_cell cell;
+          table_get_cell (t, 0, y, &cell);
+          write_table_item_cell (odt, &cell);
+        }
     }
 }
 
 static void
-write_table (struct odt_driver *odt, const struct table_item *item)
+write_table_layer (struct odt_driver *odt, const struct pivot_table *pt,
+                   const size_t *layer_indexes)
 {
-  const struct table *tab = table_item_get_table (item);
-  int r, c;
+  struct table *title, *layers, *body, *caption, *footnotes;
+  pivot_output (pt, layer_indexes, &title, &layers, &body,
+                &caption, &footnotes, NULL, NULL);
 
   /* Write a heading for the table */
-  write_table_item_cell (odt, table_item_get_title (item));
-  write_table_item_layers (odt, table_item_get_layers (item));
+  write_table__ (odt, title);
+  write_table__ (odt, layers);
 
   /* Start table */
   xmlTextWriterStartElement (odt->content_wtr, _xml("table:table"));
@@ -480,27 +478,27 @@ write_table (struct odt_driver *odt, const struct table_item *item)
 
   /* Start column definitions */
   xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-column"));
-  xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:number-columns-repeated"), "%d", tab->n[H]);
+  xmlTextWriterWriteFormatAttribute (odt->content_wtr, _xml("table:number-columns-repeated"), "%d", body->n[H]);
   xmlTextWriterEndElement (odt->content_wtr);
 
 
   /* Deal with row headers */
-  if (tab->h[V][0] > 0)
+  if (body->h[V][0] > 0)
     xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-header-rows"));
 
 
   /* Write all the rows */
-  for (r = 0 ; r < tab->n[V]; ++r)
+  for (int r = 0 ; r < body->n[V]; ++r)
     {
       /* Start row definition */
       xmlTextWriterStartElement (odt->content_wtr, _xml("table:table-row"));
 
       /* Write all the columns */
-      for (c = 0 ; c < tab->n[H] ; ++c)
+      for (int c = 0 ; c < body->n[H] ; ++c)
        {
           struct table_cell cell;
 
-          table_get_cell (tab, c, r, &cell);
+          table_get_cell (body, c, r, &cell);
 
           if (c == cell.d[H][0] && r == cell.d[V][0])
             {
@@ -522,7 +520,7 @@ write_table (struct odt_driver *odt, const struct table_item *item)
 
               xmlTextWriterStartElement (odt->content_wtr, _xml("text:p"));
 
-              if (r < tab->h[V][0] || c < tab->h[H][0])
+              if (r < body->h[V][0] || c < body->h[H][0])
                 xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Heading"));
               else
                 xmlTextWriterWriteAttribute (odt->content_wtr, _xml("text:style-name"), _xml("Table_20_Contents"));
@@ -552,7 +550,7 @@ write_table (struct odt_driver *odt, const struct table_item *item)
 
       xmlTextWriterEndElement (odt->content_wtr); /* row */
 
-      int ht = tab->h[V][0];
+      int ht = body->h[V][0];
       if (ht > 0 && r == ht - 1)
        xmlTextWriterEndElement (odt->content_wtr); /* table-header-rows */
     }
@@ -560,7 +558,22 @@ write_table (struct odt_driver *odt, const struct table_item *item)
   xmlTextWriterEndElement (odt->content_wtr); /* table */
 
   /* Write a caption for the table */
-  write_table_item_cell (odt, table_item_get_caption (item));
+  write_table__ (odt, caption);
+  write_table__ (odt, footnotes);
+
+  table_unref (title);
+  table_unref (layers);
+  table_unref (body);
+  table_unref (caption);
+  table_unref (footnotes);
+}
+
+static void
+write_table (struct odt_driver *odt, const struct table_item *item)
+{
+  size_t *layer_indexes;
+  PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true)
+    write_table_layer (odt, item->pt, layer_indexes);
 }
 
 static void
index 4c0ac48a86b385e50599f1d23c9cfbe5df26636a..2d88610eae72db4ebe6b86cee146a21afa5d8dba 100644 (file)
 #define H TABLE_HORZ
 #define V TABLE_VERT
 
+size_t *
+pivot_output_next_layer (const struct pivot_table *pt, size_t *indexes,
+                         bool print)
+{
+  const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
+  if (print && pt->look->print_all_layers)
+    return pivot_axis_iterator_next (indexes, layer_axis);
+  else if (!indexes)
+    {
+      size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer;
+      return xmemdup (pt->current_layer, MAX (size, 1));
+    }
+  else
+    {
+      free (indexes);
+      return NULL;
+    }
+}
+
 static const struct pivot_category *
 find_category (const struct pivot_dimension *d, int dim_index,
                const size_t *indexes, int row_ofs)
@@ -149,51 +168,6 @@ fill_cell (struct table *t, int x1, int y1, int x2, int y2,
     }
 }
 
-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 int
 get_table_rule (const struct table_border_style *styles,
                 enum pivot_border style_idx)
@@ -331,41 +305,124 @@ compose_headings (struct table *t,
     }
 }
 
-struct table *
-pivot_table_to_table (const struct pivot_table *pt,
-                      const size_t *layer_indexes)
+static struct table *
+create_aux_table (const struct pivot_table *pt, int nc, int nr,
+                  int style_idx)
+{
+  struct table *table = table_create (nr, nc, 0, 0, 0, 0);
+  table->styles[style_idx] = table_area_style_override (
+      t->container, &pt->look->areas[style_idx], NULL, NULL, false);
+  return table;
+}
+
+
+static struct footnote **
+add_footnotes (struct footnote **refs, size_t n_refs,
+               struct footnote **footnotes, size_t *allocated, size_t *n)
+{
+  for (size_t i = 0; i < n_refs; i++)
+    {
+      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 *
+                         struct footnote ***footnotesp)
+{
+  struct footnote **footnotes = NULL;
+  size_t allocated = 0;
+  size_t n = 0;
+
+  struct table *t = item->table;
+  for (int y = 0; y < t->n[V]; y++)
+    {
+      struct table_cell cell;
+      for (int x = 0; x < t->n[H]; 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])
+            footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
+                                       footnotes, &allocated, &n);
+        }
+    }
+
+  const struct table_cell *title = table_item_get_title (item);
+  if (title)
+    footnotes = add_footnotes (title->footnotes, title->n_footnotes,
+                               footnotes, &allocated, &n);
+
+  const struct table_item_layers *layers = table_item_get_layers (item);
+  if (layers)
+    {
+      for (size_t i = 0; i < layers->n_layers; i++)
+        footnotes = add_footnotes (layers->layers[i].footnotes,
+                                   layers->layers[i].n_footnotes,
+                                   footnotes, &allocated, &n);
+    }
+
+  const struct table_cell *caption = table_item_get_caption (item);
+  if (caption)
+    footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
+                               footnotes, &allocated, &n);
+
+  size_t n_nonnull = 0;
+  for (size_t i = 0; i < n; i++)
+    if (footnotes[i])
+      footnotes[n_nonnull++] = footnotes[i];
+
+  *footnotesp = footnotes;
+  return n_nonnull;
+}
+
+void
+pivot_output (const struct pivot_table *pt,
+              const size_t *layer_indexes,
+              struct table **titlep,
+              struct table **layersp,
+              struct table **bodyp,
+              struct table **captionp,
+              struct table **footnotesp,
+              struct footnote ***fp, size_t *nfp)
 {
   const size_t *pindexes[PIVOT_N_AXES]
     = { [PIVOT_AXIS_LAYER] = layer_indexes };
 
-  size_t body[TABLE_N_AXES];
+  size_t data[TABLE_N_AXES];
   size_t *column_enumeration = pivot_table_enumerate_axis (
-    pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &body[H]);
+    pt, PIVOT_AXIS_COLUMN, layer_indexes, pt->look->omit_empty, &data[H]);
   size_t *row_enumeration = pivot_table_enumerate_axis (
-    pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &body[V]);
+    pt, PIVOT_AXIS_ROW, layer_indexes, pt->look->omit_empty, &data[V]);
 
   int stub[TABLE_N_AXES] = {
     [H] = pt->axes[PIVOT_AXIS_ROW].label_depth,
     [V] = pt->axes[PIVOT_AXIS_COLUMN].label_depth,
   };
-  struct table *table = table_create (body[H] + stub[H],
-                                      body[V] + stub[V],
-                                      stub[H], 0, stub[V], 0);
-
+  struct table *body = table_create (data[H] + stub[H],
+                                     data[V] + stub[V],
+                                     stub[H], 0, stub[V], 0);
   for (size_t i = 0; i < PIVOT_N_AREAS; i++)
-    table->styles[i] = table_area_style_override (
-      table->container, &pt->look->areas[i], NULL, NULL, false);
+    body->styles[i] = table_area_style_override (
+      body->container, &pt->look->areas[i], NULL, NULL, false);
 
   for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
     {
       const struct table_border_style *in = &pt->look->borders[i];
-      table->rule_colors[i] = pool_alloc (table->container,
-                                          sizeof *table->rule_colors[i]);
-      struct cell_color *out = table->rule_colors[i];
-      out->alpha = in->color.alpha;
-      out->r = in->color.r;
-      out->g = in->color.g;
-      out->b = in->color.b;
+      body->rule_colors[i] = pool_alloc (body->container,
+                                         sizeof *body->rule_colors[i]);
+      *body->rule_colors[i] = in->color;
     }
 
   struct footnote **footnotes = XCALLOC (pt->n_footnotes,  struct footnote *);
@@ -381,8 +438,8 @@ pivot_table_to_table (const struct pivot_table *pt,
       char *marker = pivot_value_to_string (pf->marker, pt->show_values,
                                             pt->show_variables);
       footnotes[i] = table_create_footnote (
-        table, i, content, marker,
-        table_area_style_override (table->container,
+        body, i, content, marker,
+        table_area_style_override (body->container,
                                    &pt->look->areas[PIVOT_AREA_FOOTER],
                                    pf->content->cell_style,
                                    pf->content->font_style,
@@ -391,28 +448,28 @@ pivot_table_to_table (const struct pivot_table *pt,
       free (content);
     }
 
-  compose_headings (table,
+  compose_headings (body,
                     &pt->axes[PIVOT_AXIS_COLUMN], H, &pt->axes[PIVOT_AXIS_ROW],
                     pt->look->borders,
                     PIVOT_BORDER_DIM_COL_HORZ,
                     PIVOT_BORDER_DIM_COL_VERT,
                     PIVOT_BORDER_CAT_COL_HORZ,
                     PIVOT_BORDER_CAT_COL_VERT,
-                    column_enumeration, body[H],
+                    column_enumeration, data[H],
                     &pt->look->areas[PIVOT_AREA_COLUMN_LABELS],
                     PIVOT_AREA_COLUMN_LABELS,
                     &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
                     pt->show_values, pt->show_variables,
                     pt->rotate_outer_row_labels, false);
 
-  compose_headings (table,
+  compose_headings (body,
                     &pt->axes[PIVOT_AXIS_ROW], V, &pt->axes[PIVOT_AXIS_COLUMN],
                     pt->look->borders,
                     PIVOT_BORDER_DIM_ROW_VERT,
                     PIVOT_BORDER_DIM_ROW_HORZ,
                     PIVOT_BORDER_CAT_ROW_VERT,
                     PIVOT_BORDER_CAT_ROW_HORZ,
-                    row_enumeration, body[V],
+                    row_enumeration, data[V],
                     &pt->look->areas[PIVOT_AREA_ROW_LABELS],
                     PIVOT_AREA_ROW_LABELS,
                     &pt->look->areas[PIVOT_AREA_CORNER], footnotes,
@@ -431,7 +488,7 @@ pivot_table_to_table (const struct pivot_table *pt,
         {
           pivot_table_convert_indexes_ptod (pt, pindexes, dindexes);
           const struct pivot_value *value = pivot_table_get (pt, dindexes);
-          fill_cell (table,
+          fill_cell (body,
                      x + stub[H], y + stub[V],
                      x + stub[H], y + stub[V],
                      &pt->look->areas[PIVOT_AREA_DATA], PIVOT_AREA_DATA,
@@ -447,42 +504,103 @@ pivot_table_to_table (const struct pivot_table *pt,
 
   if ((pt->corner_text || !pt->look->row_labels_in_corner)
       && stub[H] && stub[V])
-    fill_cell (table, 0, 0, stub[H] - 1, stub[V] - 1,
+    fill_cell (body, 0, 0, stub[H] - 1, stub[V] - 1,
                &pt->look->areas[PIVOT_AREA_CORNER], PIVOT_AREA_CORNER,
                pt->corner_text, footnotes,
                pt->show_values, pt->show_variables, false);
 
-  if (table->n[H] && table->n[V])
+  if (body->n[H] && body->n[V])
     {
       table_hline (
-        table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP),
-        0, table->n[H] - 1, 0);
+        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_TOP),
+        0, body->n[H] - 1, 0);
       table_hline (
-        table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM),
-        0, table->n[H] - 1, table->n[V]);
+        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_BOTTOM),
+        0, body->n[H] - 1, body->n[V]);
       table_vline (
-        table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT),
-        0, 0, table->n[V] - 1);
+        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_LEFT),
+        0, 0, body->n[V] - 1);
       table_vline (
-        table, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT),
-        table->n[H], 0, table->n[V] - 1);
+        body, get_table_rule (pt->look->borders, PIVOT_BORDER_INNER_RIGHT),
+        body->n[H], 0, body->n[V] - 1);
 
       if (stub[V])
         table_hline (
-          table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP),
-          0, table->n[H] - 1, stub[V]);
+          body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_TOP),
+          0, body->n[H] - 1, stub[V]);
       if (stub[H])
         table_vline (
-          table, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT),
-          stub[H], 0, table->n[V] - 1);
+          body, get_table_rule (pt->look->borders, PIVOT_BORDER_DATA_LEFT),
+          stub[H], 0, body->n[V] - 1);
 
     }
   free (column_enumeration);
   free (row_enumeration);
 
+  /* Title. */
+  struct table *title;
+  if (pt->title && titlep)
+    {
+      title = create_aux_table (pt, 1, 1, PIVOT_AREA_TITLE);
+      fill_cell (title, 0, 0, 1, 1,
+                 &pt->look->areas[PIVOT_AREA_TITLE], PIVOT_AREA_TITLE,
+                 pt->title, footnotes,
+                 pt->show_values, pt->show_variables, false);
+    }
+  else
+    title = NULL;
+
+  /* Layers. */
+  const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
+  int n_layers = 0;
+  if (layersp)
+    for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+      {
+        const struct pivot_dimension *d = layer_axis->dimensions[i];
+        if (d->n_leaves)
+          n_layers++;
+      }
+
+  struct table *layers;
+  if (n_layers > 0)
+    {
+      layers = create_aux_table (pt, 1, n_layers, PIVOT_AREA_LAYERS);
+      size_t y = 0;
+      for (size_t i = 0; i < layer_axis->n_dimensions; i++)
+        {
+          const struct pivot_dimension *d = layer_axis->dimensions[i];
+          if (!d->n_leaves)
+            continue;
+
+          /* XXX This puts in the layer values, but not the variable names. */
+          const struct pivot_value *name
+            = d->data_leaves[layer_indexes[i]]->name;
+          fill_cell (layers, 0, y, 1, y + 1,
+                     &pt->look->areas[PIVOT_AREA_LAYERS], PIVOT_AREA_LAYERS,
+                     name, footnotes,
+                     pt->show_values, pt->show_variables, false);
+          y++;
+        }
+    }
+  else
+    layers = NULL;
+
+  /* Caption. */
+  struct table *caption;
+  if (pt->caption && captionp)
+    {
+      caption = create_aux_table (pt, 1, 1, PIVOT_AREA_CAPTION);
+      fill_cell (caption, 0, 0, 1, 1,
+                 &pt->look->areas[PIVOT_AREA_CAPTION], PIVOT_AREA_CAPTION,
+                 pt->caption, footnotes,
+                 pt->show_values, pt->show_variables, false);
+    }
+  else
+    caption = NULL;
+
   free (footnotes);
 
-  return table;
+  *bodyp = body;
 }
 
 void
index 495a0a7e88d2c36635812601dc24fe9874664b62..38d595a8e051aaeb0e4f4b55ee300f56b35a32ed 100644 (file)
 #ifndef OUTPUT_PIVOT_OUTPUT_H
 #define OUTPUT_PIVOT_OUTPUT_H 1
 
+#include <stdbool.h>
 #include <stddef.h>
 
+struct footnote;
 struct pivot_table;
-
-struct table *pivot_table_to_table (const struct pivot_table *,
-                                    const size_t *layer_indexes);
+struct table;
+
+#define PIVOT_OUTPUT_FOR_EACH_LAYER(INDEXES, PT, PRINT)           \
+  for ((INDEXES) = NULL;                                                \
+       ((INDEXES) = pivot_output_next_layer (PT, INDEXES, PRINT)); )
+size_t *pivot_output_next_layer (const struct pivot_table *,
+                                 size_t *indexes, bool print);
+
+void pivot_output (const struct pivot_table *,
+                   const size_t *layer_indexes,
+                   struct table **titlep,
+                   struct table **layersp,
+                   struct table **bodyp,
+                   struct table **captionp,
+                   struct table **footnotesp,
+                   struct footnote ***fp, size_t *nfp);
 
 #endif /* output/pivot-output.h */
index 96dd9d2413abaac75fd58a251a2aa41ef46c8a96..d0588365a143529ba2812fcc31a0918f21bc86d9 100644 (file)
@@ -994,25 +994,6 @@ pivot_table_is_empty (const struct pivot_table *table)
   return hmap_is_empty (&table->cells);
 }
 
-size_t *
-pivot_table_next_display_layer (const struct pivot_table *pt, size_t *indexes,
-                                bool print)
-{
-  const struct pivot_axis *layer_axis = &pt->axes[PIVOT_AXIS_LAYER];
-  if (print && pt->look->print_all_layers)
-    return pivot_axis_iterator_next (indexes, layer_axis);
-  else if (!indexes)
-    {
-      size_t size = layer_axis->n_dimensions * sizeof *pt->current_layer;
-      return xmemdup (pt->current_layer, MAX (size, 1));
-    }
-  else
-    {
-      free (indexes);
-      return NULL;
-    }
-}
-
 static unsigned int
 pivot_cell_hash_indexes (const size_t *indexes, size_t n_idx)
 {
index a62c5b7bae34f0c2e9ba6080c77fe59168771bb7..7c36c43b2d61df2c1921bcee754975f99cf77858 100644 (file)
@@ -509,13 +509,6 @@ bool pivot_table_is_empty (const struct pivot_table *);
 /* Output. */
 void pivot_table_submit (struct pivot_table *);
 
-/* Layers. */
-#define PIVOT_TABLE_FOR_EACH_DISPLAY_LAYER(INDEXES, PT, PRINT)          \
-  for ((INDEXES) = NULL;                                                \
-       ((INDEXES) = pivot_table_next_display_layer (PT, INDEXES, PRINT)); )
-size_t *pivot_table_next_display_layer (const struct pivot_table *,
-                                        size_t *indexes, bool print);
-
 /* Data cells. */
 void pivot_table_put (struct pivot_table *, const size_t *dindexes, size_t n,
                       struct pivot_value *);
index 680beb38f86d69b18d8ddeb6812c8cf4d862bac4..00ef896105189045c129ff33215649a8a377576a 100644 (file)
@@ -26,6 +26,7 @@
 #include "libpspp/hash-functions.h"
 #include "libpspp/hmap.h"
 #include "libpspp/pool.h"
+#include "output/pivot-output.h"
 #include "output/pivot-table.h"
 #include "output/render.h"
 #include "output/table-item.h"
@@ -1483,12 +1484,11 @@ struct render_pager
     const struct render_params *params;
     double scale;
 
-    /* An array of "render_page"s to be rendered, in order, vertically.  From
-       the user's perspective, there's only one table per render_pager, but the
-       implementation treats the title, table body, caption, footnotes,
-       etc. each as a table, and that's why we have an array here. */
-    struct render_page **pages;
-    size_t n_pages, allocated_pages;
+    /* An array of "render_page"s to be rendered, in order, vertically.  There
+       may be up to 5 pages, for the pivot table's title, layers, body,
+       captions, and footnotes. */
+    struct render_page *pages[5];
+    size_t n_pages;
 
     size_t cur_page;
     struct render_break x_break;
@@ -1499,9 +1499,6 @@ static const struct render_page *
 render_pager_add_table (struct render_pager *p, struct table *table,
                         int min_width)
 {
-  if (p->n_pages >= p->allocated_pages)
-    p->pages = x2nrealloc (p->pages, &p->allocated_pages, sizeof *p->pages);
-
   struct render_page *page = render_page_create (p->params, table, min_width);
   p->pages[p->n_pages++] = page;
   return page;
@@ -1515,74 +1512,25 @@ render_pager_start_page (struct render_pager *p)
   render_break_init_empty (&p->y_break);
 }
 
-static void
-add_footnote_page (struct render_pager *p, const struct table_item *item)
-{
-  struct footnote **f;
-  size_t n_footnotes = table_collect_footnotes (item, &f);
-  if (!n_footnotes)
-    return;
-
-  struct table *t = table_create (1, n_footnotes, 0, 0, 0, 0);
-
-  for (size_t i = 0; i < n_footnotes; i++)
-    {
-      table_text_format (t, 0, i, 0, "%s. %s", f[i]->marker, f[i]->content);
-      table_add_style (t, 0, i, f[i]->style);
-    }
-  render_pager_add_table (p, t, 0);
-
-  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_layers_page (struct render_pager *p,
-                 const struct table_item_layers *layers, int min_width)
-{
-  if (!layers)
-    return;
-
-  struct table *tab = table_create (1, layers->n_layers, 0, 0, 0, 0);
-  for (size_t i = 0; i < layers->n_layers; i++)
-    {
-      const struct table_item_layer *layer = &layers->layers[i];
-      table_text (tab, 0, i, 0, layer->content);
-      for (size_t j = 0; j < layer->n_footnotes; j++)
-        table_add_footnote (tab, 0, i, layer->footnotes[j]);
-    }
-  if (layers->style)
-    tab->styles[0] = table_area_style_clone (tab->container, layers->style);
-  render_pager_add_table (p, tab, min_width);
-}
-
 /* Creates and returns a new render_pager for rendering TABLE_ITEM on the
    device with the given PARAMS. */
 struct render_pager *
 render_pager_create (const struct render_params *params,
-                     const struct table_item *table_item)
+                     const struct table_item *table_item,
+                     const size_t *layer_indexes)
 {
-  const struct table *table = table_item_get_table (table_item);
+  const struct pivot_table *pt = table_item->pt;
+  if (!layer_indexes)
+    layer_indexes = pt->current_layer;
+
+  struct table *title, *layers, *body, *caption, *footnotes;
+  pivot_output (pt, layer_indexes, &title, &layers, &body, &caption,
+                &footnotes, NULL, NULL);
 
   /* Figure out the width of the body of the table.  Use this to determine the
      base scale. */
-  struct render_page *page = render_page_create (params, table_ref (table), 0);
-  int body_width = table_width (page, H);
+  struct render_page *body_page = render_page_create (params, body, 0);
+  int body_width = table_width (body_page, H);
   double scale = 1.0;
   if (body_width > params->size[H])
     {
@@ -1593,7 +1541,7 @@ render_pager_create (const struct render_params *params,
       else
         {
           struct render_break b;
-          render_break_init (&b, page, H);
+          render_break_init (&b, render_page_ref (body_page), H);
           struct render_page *subpage
             = render_break_next (&b, params->size[H]);
           body_width = subpage ? subpage->cp[H][2 * subpage->n[H] + 1] : 0;
@@ -1605,11 +1553,12 @@ render_pager_create (const struct render_params *params,
   /* Create the pager. */
   struct render_pager *p = xmalloc (sizeof *p);
   *p = (struct render_pager) { .params = params, .scale = scale };
-  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_table_cell_page (p, table_item_get_caption (table_item), 0);
-  add_footnote_page (p, table_item);
+  render_pager_add_table (p, title, body_width);
+  render_pager_add_table (p, layers, body_width);
+  p->pages[p->n_pages++] = body_page;
+  render_pager_add_table (p, caption, 0);
+  render_pager_add_table (p, footnotes, 0);
+  assert (p->n_pages < sizeof p->pages / sizeof *p->pages);
 
   /* If we're shrinking tables to fit the page length, then adjust the scale
      factor.
@@ -1645,7 +1594,6 @@ render_pager_destroy (struct render_pager *p)
       render_break_destroy (&p->y_break);
       for (size_t i = 0; i < p->n_pages; i++)
         render_page_unref (p->pages[i]);
-      free (p->pages);
       free (p);
     }
 }
index 5df97a1b6718847ad42a955860b88b77510ee0fc..ff73c4e35af9896d0ad59ddf16a2694f7a1423ab 100644 (file)
@@ -148,7 +148,8 @@ struct render_ops
 
 /* An iterator for breaking render_pages into smaller chunks. */
 struct render_pager *render_pager_create (const struct render_params *,
-                                          const struct table_item *);
+                                          const struct table_item *,
+                                          const size_t *layer_indexes);
 void render_pager_destroy (struct render_pager *);
 
 bool render_pager_has_next (const struct render_pager *);
index 6aa59d86484d24bca72a6bfb5903a8bb2b393d26..30dcdff75f26dfd604b67f94a1428d608d17ed1a 100644 (file)
@@ -27,7 +27,7 @@ enum table_halign table_halign_interpret (enum table_halign, bool numeric);
 
 struct footnote
   {
-    size_t idx;
+    //size_t idx;
     char *content;
     char *marker;
     struct table_area_style *style;
index bd017f6b4f16ac518ad7ba826234c72b2ea2668c..925b707100cf78653650da1c2327e75ec36aae9d 100644 (file)
@@ -183,77 +183,6 @@ table_cell_format_footnote_markers (const struct table_cell *cell,
       ds_put_cstr (s, cell->footnotes[i]->marker);
     }
 }
-
-static struct footnote **
-add_footnotes (struct footnote **refs, size_t n_refs,
-               struct footnote **footnotes, size_t *allocated, size_t *n)
-{
-  for (size_t i = 0; i < n_refs; i++)
-    {
-      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,
-                         struct footnote ***footnotesp)
-{
-  struct footnote **footnotes = NULL;
-  size_t allocated = 0;
-  size_t n = 0;
-
-  struct table *t = item->table;
-  for (int y = 0; y < t->n[V]; y++)
-    {
-      struct table_cell cell;
-      for (int x = 0; x < t->n[H]; 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])
-            footnotes = add_footnotes (cell.footnotes, cell.n_footnotes,
-                                       footnotes, &allocated, &n);
-        }
-    }
-
-  const struct table_cell *title = table_item_get_title (item);
-  if (title)
-    footnotes = add_footnotes (title->footnotes, title->n_footnotes,
-                               footnotes, &allocated, &n);
-
-  const struct table_item_layers *layers = table_item_get_layers (item);
-  if (layers)
-    {
-      for (size_t i = 0; i < layers->n_layers; i++)
-        footnotes = add_footnotes (layers->layers[i].footnotes,
-                                   layers->layers[i].n_footnotes,
-                                   footnotes, &allocated, &n);
-    }
-
-  const struct table_cell *caption = table_item_get_caption (item);
-  if (caption)
-    footnotes = add_footnotes (caption->footnotes, caption->n_footnotes,
-                               footnotes, &allocated, &n);
-
-  size_t n_nonnull = 0;
-  for (size_t i = 0; i < n; i++)
-    if (footnotes[i])
-      footnotes[n_nonnull++] = footnotes[i];
-
-  *footnotesp = footnotes;
-  return n_nonnull;
-}
 \f
 const char *
 table_halign_to_string (enum table_halign halign)
@@ -789,10 +718,7 @@ table_cell_is_empty (const struct table *table, int c, int r)
 }
 \f
 /* 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).
-
-   The caller must ensure that CELL is destroyed before TABLE is unref'ed. */
+   within TABLE. */
 void
 table_get_cell (const struct table *t, int x, int y, struct table_cell *cell)
 {
index f43bd81fa217a1641cc1f23752ae1ac73439aeef..5c47ffe88c0c68e7a49ee0788c91d9b926af2f1a 100644 (file)
@@ -19,7 +19,7 @@
 
 /* Tables.
 
-.  A table is a rectangular grid of cells.  Cells can be joined to form larger
+   A table is a rectangular grid of cells.  Cells can be joined to form larger
    cells.  Rows and columns can be separated by rules of various types.  Rows
    at the top and bottom of a table and columns at the left and right edges of
    a table can be designated as headers, which means that if the table must be
index b6064097495b9006684f4e88764aeb4dc429bed0..cc46ee32272eca101e0f6b379d25ccf92b83367e 100644 (file)
@@ -44,6 +44,8 @@
 #include "output/message-item.h"
 #include "output/options.h"
 #include "output/output-item-provider.h"
+#include "output/pivot-output.h"
+#include "output/pivot-table.h"
 #include "output/table-provider.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
@@ -401,48 +403,60 @@ tex_put_table_cell (struct tex_driver *tex, const struct table_cell *cell)
 }
 
 static void
-tex_output_table (struct tex_driver *tex, const struct table_item *item)
+tex_output_table_layer (struct tex_driver *tex, const struct pivot_table *pt,
+                        const size_t *layer_indexes)
 {
   /* Tables are rendered in TeX with the \halign command.
      This is described in the TeXbook Ch. 22 */
-
-  const struct table *t = table_item_get_table (item);
+  struct table *title, *layers, *body, *caption;
+  struct footnote **footnotes;
+  size_t n_footnotes;
+  pivot_output (pt, layer_indexes, &title, &layers, &body,
+                &caption, NULL, &footnotes, &n_footnotes);
 
   shipout (&tex->token_list, "\n{\\parindent=0pt\n");
 
-  const struct table_cell *caption = table_item_get_caption (item);
   if (caption)
     {
       shipout (&tex->token_list, "{\\sl ");
-      tex_escape_string (tex, caption->text, false);
+      struct table_cell cell;
+      table_get_cell (caption, 0, 0, &cell);
+      tex_put_table_cell (tex, &cell);
       shipout (&tex->token_list, "}\n\n");
     }
-  struct footnote **f;
-  size_t n_footnotes = table_collect_footnotes (item, &f);
 
-  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_cell (tex, title);
-          shipout (&tex->token_list, "}");
+          struct table_cell cell;
+          table_get_cell (title, 0, 0, &cell);
+          tex_put_table_cell (tex, &cell);
+          shipout (&tex->token_list, "}\\par\n");
         }
+
       if (layers)
-        abort ();
-      shipout (&tex->token_list, "\\par\n");
+        {
+          for (size_t y = 0; y < layers->n[V]; y++)
+            {
+              shipout (&tex->token_list, "{");
+              struct table_cell cell;
+              table_get_cell (layers, 0, y, &cell);
+              tex_put_table_cell (tex, &cell);
+              shipout (&tex->token_list, "}\\par\n");
+            }
+        }
     }
 
   shipout (&tex->token_list, "\\offinterlineskip\\halign{\\strut%%\n");
 
   /* Generate the preamble */
-  for (int x = 0; x < t->n[H]; ++x)
+  for (int x = 0; x < body->n[H]; ++x)
     {
-      shipout (&tex->token_list, "{\\vbox{\\cell{%d}#}}", t->n[H]);
+      shipout (&tex->token_list, "{\\vbox{\\cell{%d}#}}", body->n[H]);
 
-      if (x < t->n[H] - 1)
+      if (x < body->n[H] - 1)
         {
           shipout (&tex->token_list, "\\hskip\\psppcolumnspace\\hfil");
           shipout (&tex->token_list, "&\\vrule\n");
@@ -452,17 +466,17 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item)
     }
 
   /* Emit the row data */
-  for (int y = 0; y < t->n[V]; y++)
+  for (int y = 0; y < body->n[V]; y++)
     {
       enum { H = TABLE_HORZ, V = TABLE_VERT };
-      bool is_column_header = y < t->h[V][0] || y >= t->n[V] - t->h[V][1];
+      bool is_column_header = y < body->h[V][0] || y >= body->n[V] - body->h[V][1];
       int prev_x = -1;
       int skipped = 0;
-      for (int x = 0; x < t->n[H];)
+      for (int x = 0; x < body->n[H];)
         {
           struct table_cell cell;
 
-          table_get_cell (t, x, y, &cell);
+          table_get_cell (body, x, y, &cell);
 
           int colspan = table_cell_colspan (&cell);
           if (x > 0)
@@ -475,10 +489,10 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item)
           if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
             goto next_1;
 
-          /* 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]); */
+          /* bool is_header = (y < body->h[V][0] */
+          /*                   || y >= body->n[V] - body->h[V][1] */
+          /*                   || x < body->h[H][0] */
+          /*                   || x >= body->n[H] - body->h[H][1]); */
 
           enum table_halign halign =
             table_halign_interpret (cell.style->cell_style.halign,
@@ -530,13 +544,26 @@ tex_output_table (struct tex_driver *tex, const struct table_item *item)
   for (int i = 0; i < n_footnotes; ++i)
     {
       shipout (&tex->token_list, "$^{");
-      tex_escape_string (tex, f[i]->marker, false);
+      tex_escape_string (tex, footnotes[i]->marker, false);
       shipout (&tex->token_list, "}$");
-      tex_escape_string (tex, f[i]->content, false);
+      tex_escape_string (tex, footnotes[i]->content, false);
     }
-  free (f);
 
   shipout (&tex->token_list, "}\n\\vskip 3ex\n\n");
+
+  table_unref (title);
+  table_unref (layers);
+  table_unref (body);
+  table_unref (caption);
+  free (footnotes);
+}
+
+static void
+tex_output_table (struct tex_driver *tex, const struct table_item *item)
+{
+  size_t *layer_indexes;
+  PIVOT_OUTPUT_FOR_EACH_LAYER (layer_indexes, item->pt, true)
+    tex_output_table_layer (tex, item->pt, layer_indexes);
 }
 
 struct output_driver_factory tex_driver_factory =
index ced77d2f64acd8598a3fa30813cfd234db685fa7..167c4caadf53133b27c477b6ca12fe1a95360fe6 100644 (file)
@@ -175,7 +175,7 @@ text_item_to_table_item (struct text_item *text_item)
   pivot_value_set_font_style (content, &text_item->style);
   pivot_table_put1 (table, 0, content);
 
-  return table;
+  return table_item_create (table);
 }
 \f
 static const char *
index 70b62b1c5a4af42efddf81526a836693daea5c0c..c6ee8c40bf993f18d116d1501711b11d7cf3cb9e 100644 (file)
@@ -33,6 +33,7 @@
 #include "output/message-item.h"
 #include "output/output-item.h"
 #include "output/output-item-provider.h"
+#include "output/pivot-table.h"
 #include "output/table-item.h"
 #include "output/text-item.h"
 
@@ -164,6 +165,7 @@ get_xr_fsm_style (struct psppire_output_view *view)
       [XR_FONT_FIXED] = ff,
     },
     .use_system_colors = true,
+    .object_spacing = XR_POINT * 12,
     .font_resolution = 96.0,
   };
 
@@ -364,7 +366,7 @@ rerender (struct psppire_output_view *view)
       if (is_table_item (item->item))
         {
           const struct table_item *ti = to_table_item (item->item);
-          gtk_widget_set_tooltip_text (item->drawing_area, ti->notes);
+          gtk_widget_set_tooltip_text (item->drawing_area, ti->pt->notes);
         }
 
       {
@@ -972,7 +974,6 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
       [V] = { margins[V][0], margins[V][1] },
     },
     .initial_page_number = 1,
-    .object_spacing = 12 * XR_POINT,
   };
 
   view->fsm_style = xmalloc (sizeof *view->fsm_style);
@@ -987,6 +988,7 @@ create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *vi
     },
     .fg = CELL_COLOR_BLACK,
     .use_system_colors = false,
+    .object_spacing = 12 * XR_POINT,
     .font_resolution = 72.0
   };