html: Step toward better handling of text_items.
[pspp] / src / output / table-item.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2011, 2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "output/table-provider.h"
20
21 #include <assert.h>
22
23 #include "libpspp/assertion.h"
24 #include "libpspp/cast.h"
25 #include "output/driver.h"
26 #include "output/output-item-provider.h"
27 #include "output/pivot-table.h"
28 #include "output/table-item.h"
29
30 #include "gl/xalloc.h"
31
32 struct table_item_text *
33 table_item_text_create (const char *content)
34 {
35   if (!content)
36     return NULL;
37
38   struct table_item_text *text = xmalloc (sizeof *text);
39   *text = (struct table_item_text) { .content = xstrdup (content) };
40   return text;
41 }
42
43 struct table_item_text *
44 table_item_text_clone (const struct table_item_text *old)
45 {
46   if (!old)
47     return NULL;
48
49   struct table_item_text *new = xmalloc (sizeof *new);
50   *new = (struct table_item_text) {
51     .content = xstrdup (old->content),
52     .footnotes = xmemdup (old->footnotes,
53                           old->n_footnotes * sizeof *old->footnotes),
54     .n_footnotes = old->n_footnotes,
55     .style = table_area_style_clone (NULL, old->style),
56   };
57   return new;
58 }
59
60 void
61 table_item_text_destroy (struct table_item_text *text)
62 {
63   if (text)
64     {
65       free (text->content);
66       free (text->footnotes);
67       table_area_style_free (text->style);
68       free (text);
69     }
70 }
71
72 void
73 table_item_layer_copy (struct table_item_layer *dst,
74                        const struct table_item_layer *src)
75 {
76   dst->content = xstrdup (src->content);
77   dst->footnotes = xmemdup (src->footnotes,
78                             src->n_footnotes * sizeof *src->footnotes);
79   dst->n_footnotes = src->n_footnotes;
80 }
81
82 void
83 table_item_layer_uninit (struct table_item_layer *layer)
84 {
85   if (layer)
86     {
87       free (layer->content);
88       free (layer->footnotes);
89     }
90 }
91
92 struct table_item_layers *
93 table_item_layers_clone (const struct table_item_layers *old)
94 {
95   if (!old)
96     return NULL;
97
98   struct table_item_layers *new = xmalloc (sizeof *new);
99   *new = (struct table_item_layers) {
100     .layers = xnmalloc (old->n_layers, sizeof *new->layers),
101     .n_layers = old->n_layers,
102     .style = table_area_style_clone (NULL, old->style),
103   };
104   for (size_t i = 0; i < new->n_layers; i++)
105     table_item_layer_copy (&new->layers[i], &old->layers[i]);
106   return new;
107 }
108
109 void
110 table_item_layers_destroy (struct table_item_layers *layers)
111 {
112   if (layers)
113     {
114       for (size_t i = 0; i < layers->n_layers; i++)
115         table_item_layer_uninit (&layers->layers[i]);
116       free (layers->layers);
117       table_area_style_free (layers->style);
118       free (layers);
119     }
120 }
121
122 /* Initializes ITEM as a table item for rendering TABLE.  The new table item
123    initially has the specified TITLE, CAPTION, and NOTES, which may each be
124    NULL.  The caller retains ownership of TITLE, CAPTION, and NOTES. */
125 struct table_item *
126 table_item_create (struct table *table, const char *title, const char *caption,
127                    const char *notes)
128 {
129   struct table_item *item = xmalloc (sizeof *item);
130   output_item_init (&item->output_item, &table_item_class);
131   item->table = table;
132   item->title = table_item_text_create (title);
133   item->layers = NULL;
134   item->caption = table_item_text_create (caption);
135   item->notes = notes ? xstrdup (notes) : NULL;
136   item->pt = NULL;
137   return item;
138 }
139
140 /* Returns the table contained by TABLE_ITEM.  The caller must not modify or
141    unref the returned table. */
142 const struct table *
143 table_item_get_table (const struct table_item *table_item)
144 {
145   return table_item->table;
146 }
147
148 /* Returns ITEM's title, which is a null pointer if no title has been
149    set. */
150 const struct table_item_text *
151 table_item_get_title (const struct table_item *item)
152 {
153   return item->title;
154 }
155
156 /* Sets ITEM's title to TITLE, replacing any previous title.  Specify NULL for
157    TITLE to clear any title from ITEM.  The caller retains ownership of TITLE.
158
159    This function may only be used on a table_item that is unshared. */
160 void
161 table_item_set_title (struct table_item *item,
162                       const struct table_item_text *title)
163 {
164   assert (!table_item_is_shared (item));
165   table_item_text_destroy (item->title);
166   item->title = table_item_text_clone (title);
167 }
168
169 /* Returns ITEM's layers, which will be a null pointer if no layers have been
170    set. */
171 const struct table_item_layers *
172 table_item_get_layers (const struct table_item *item)
173 {
174   return item->layers;
175 }
176
177 /* Sets ITEM's layers to LAYERS, replacing any previous layers.  Specify NULL
178    for LAYERS to clear any layers from ITEM.  The caller retains ownership of
179    LAYERS.
180
181    This function may only be used on a table_item that is unshared. */
182 void
183 table_item_set_layers (struct table_item *item,
184                        const struct table_item_layers *layers)
185 {
186   assert (!table_item_is_shared (item));
187   table_item_layers_destroy (item->layers);
188   item->layers = table_item_layers_clone (layers);
189 }
190
191 /* Returns ITEM's caption, which is a null pointer if no caption has been
192    set. */
193 const struct table_item_text *
194 table_item_get_caption (const struct table_item *item)
195 {
196   return item->caption;
197 }
198
199 /* Sets ITEM's caption to CAPTION, replacing any previous caption.  Specify
200    NULL for CAPTION to clear any caption from ITEM.  The caller retains
201    ownership of CAPTION.
202
203    This function may only be used on a table_item that is unshared. */
204 void
205 table_item_set_caption (struct table_item *item,
206                         const struct table_item_text *caption)
207 {
208   assert (!table_item_is_shared (item));
209   table_item_text_destroy (item->caption);
210   item->caption = table_item_text_clone (caption);
211 }
212
213 /* Returns ITEM's notes, which is a null pointer if ITEM has no notes. */
214 const char *
215 table_item_get_notes (const struct table_item *item)
216 {
217   return item->notes;
218 }
219
220 /* Sets ITEM's notes to NOTES, replacing any previous notes.  Specify NULL for
221    NOTES to clear any notes from ITEM.  The caller retains ownership of
222    NOTES.
223
224    This function may only be used on a table_item that is unshared.*/
225 void
226 table_item_set_notes (struct table_item *item, const char *notes)
227 {
228   assert (!table_item_is_shared (item));
229   free (item->notes);
230   item->notes = notes ? xstrdup (notes) : NULL;
231 }
232
233 /* Submits TABLE_ITEM to the configured output drivers, and transfers ownership
234    to the output subsystem. */
235 void
236 table_item_submit (struct table_item *table_item)
237 {
238   output_submit (&table_item->output_item);
239 }
240 \f
241 static void
242 table_item_destroy (struct output_item *output_item)
243 {
244   struct table_item *item = to_table_item (output_item);
245   table_item_text_destroy (item->title);
246   table_item_text_destroy (item->caption);
247   table_item_layers_destroy (item->layers);
248   free (item->notes);
249   pivot_table_unref (item->pt);
250   table_unref (item->table);
251   free (item);
252 }
253
254 const struct output_item_class table_item_class =
255   {
256     "table",
257     table_item_destroy,
258   };