1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include <output/manager.h>
24 #include <libpspp/assertion.h>
25 #include <output/output.h>
27 #include "gl/xalloc.h"
30 static int table_num = 1;
31 static int subtable_num;
33 /* Name of PSPP's current command, or NULL if outside a command. */
34 static char *command_name;
37 som_entity_clone (struct som_entity *entity)
39 struct som_entity *copy = xmemdup (entity, sizeof *entity);
40 copy->command_name = xstrdup (entity->command_name);
45 som_entity_destroy (struct som_entity *entity)
49 free (entity->command_name);
54 /* Increments table_num so different procedures' output can be
59 if (subtable_num != 0)
66 /* Sets COMMAND_NAME as the name of the current command,
67 for embedding in output. */
69 som_set_command_name (const char *command_name_)
72 command_name = command_name_ ? xstrdup (command_name_) : NULL;
75 /* Ejects the paper for all active devices. */
79 struct outp_driver *d;
81 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
85 /* Flushes output on all active devices. */
89 struct outp_driver *d;
91 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
95 /* Skip down a single line on all active devices. */
99 struct outp_driver *d;
101 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
102 if (d->page_open && d->cp_y != 0)
103 d->cp_y += d->font_height;
106 static void render_columns (void *r, struct outp_driver *, struct som_entity *,
108 int hl, int hr, int ht, int hb);
109 static void render_simple (void *r, struct outp_driver *, struct som_entity *,
111 int hl, int hr, int ht, int hb);
112 static void render_segments (void *r, struct outp_driver *,
115 int hl, int hr, int ht, int hb);
117 static void output_entity (struct outp_driver *, struct som_entity *);
119 /* Output table T to appropriate output devices. */
121 som_submit (struct som_entity *t)
123 struct outp_driver *d;
129 assert (entry++ == 0);
132 t->class->flags (t, &flags);
133 if (!(flags & SOMF_NO_TITLE))
135 t->table_num = table_num;
136 t->subtable_num = subtable_num;
137 t->command_name = command_name ? xstrdup (command_name) : NULL;
139 if (t->type == SOM_TABLE)
144 t->class->count (t, &nc, &nr);
145 t->class->headers (t, &hl, &hr, &ht, &hb);
146 if (hl + hr > nc || ht + hb > nr)
148 fprintf (stderr, "headers: (l,r)=(%d,%d), (t,b)=(%d,%d) "
149 "in table size (%d,%d)\n",
150 hl, hr, ht, hb, nc, nr);
153 else if (hl + hr == nc)
154 fprintf (stderr, "warning: headers (l,r)=(%d,%d) in table width %d\n",
156 else if (ht + hb == nr)
157 fprintf (stderr, "warning: headers (t,b)=(%d,%d) in table height %d\n",
161 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
162 output_entity (d, t);
165 assert (--entry == 0);
170 check_fits_width (struct som_entity *t, const struct outp_driver *d, void *r)
176 t->class->headers (t, &hl, &hr, &ht, &hb);
177 t->class->count (t, &nc, &nr);
178 for (i = hl; i < nc - hr; i++)
181 t->class->cumulate (r, SOM_COLUMNS, i, &end, d->width, &actual);
190 check_fits_length (struct som_entity *t, const struct outp_driver *d, void *r)
196 t->class->headers (t, &hl, &hr, &ht, &hb);
197 t->class->count (t, &nc, &nr);
198 for (i = ht; i < nr - hb; i++)
201 t->class->cumulate (r, SOM_ROWS, i, &end, d->length, &actual);
209 /* Output entity T to driver D. */
211 output_entity (struct outp_driver *d, struct som_entity *t)
213 bool fits_width, fits_length;
222 if (d->class->special)
224 d->class->submit (d, t);
228 t->class->headers (t, &hl, &hr, &ht, &hb);
229 t->class->count (t, &nc, &nr);
230 t->class->columns (t, &cs);
231 t->class->flags (t, &flags);
233 r = t->class->render_init (t, d, hl, hr, ht, hb);
235 fits_width = check_fits_width (t, d, r);
236 fits_length = check_fits_length (t, d, r);
237 if (!fits_width || !fits_length)
239 t->class->render_free (r);
246 r = t->class->render_init (t, d, hl, hr, ht, hb);
248 t->class->area (r, &tw, &th);
250 if (!(flags & SOMF_NO_SPACING) && d->cp_y != 0)
251 d->cp_y += d->font_height;
253 if (cs != SOM_COL_NONE
254 && 2 * (tw + d->prop_em_width) <= d->width
255 && nr - (ht + hb) > 5)
256 render_columns (r, d, t, tw, th, hl, hr, ht, hb);
257 else if (tw < d->width && th + d->cp_y < d->length)
258 render_simple (r, d, t, tw, th, hl, hr, ht, hb);
260 render_segments (r, d, t, tw, th, hl, hr, ht, hb);
262 t->class->render_free (r);
265 /* Render the table into multiple columns. */
267 render_columns (void *r, struct outp_driver *d, struct som_entity *t,
268 int tw, int th UNUSED,
269 int hl UNUSED, int hr UNUSED, int ht, int hb)
277 t->class->count (t, &nc, &nr);
278 t->class->columns (t, &cs);
280 assert (cs == SOM_COL_DOWN);
281 assert (d->cp_x == 0);
283 for (y0 = ht; y0 < nr - hb; y0 = y1)
287 t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
299 t->class->title (r, index++, 0, t->table_num, t->subtable_num,
301 t->class->render (r, 0, y0, nc, y1);
303 d->cp_x += tw + 2 * d->prop_em_width;
304 if (d->cp_x + tw > d->width)
320 /* Render the table by itself on the current page. */
322 render_simple (void *r, struct outp_driver *d, struct som_entity *t,
324 int hl, int hr, int ht, int hb)
328 t->class->count (t, &nc, &nr);
330 assert (d->cp_x == 0);
331 assert (tw < d->width && th + d->cp_y < d->length);
333 t->class->title (r, 0, 0, t->table_num, t->subtable_num, t->command_name);
334 t->class->render (r, hl, ht, nc - hr, nr - hb);
338 /* General table breaking routine. */
340 render_segments (void *r, struct outp_driver *d, struct som_entity *t,
341 int tw UNUSED, int th UNUSED,
342 int hl, int hr, int ht, int hb)
351 assert (d->cp_x == 0);
353 t->class->count (t, &nc, &nr);
354 for (x_index = 0, x0 = hl; x0 < nc - hr; x0 = x1, x_index++)
359 t->class->cumulate (r, SOM_COLUMNS, x0, &x1, d->width, NULL);
360 if (x_index == 0 && x1 != nc - hr)
363 for (y_index = 0, y0 = ht; y0 < nr - hb; y0 = y1, y_index++)
367 if (count++ != 0 && d->cp_y != 0)
368 d->cp_y += d->font_height;
370 t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
371 if (y_index == 0 && y1 != nr - hb)
381 t->class->title (r, x_index ? x_index : y_index,
382 x_index ? y_index : 0,
383 t->table_num, t->subtable_num, t->command_name);
384 t->class->render (r, x0, y0, x1, y1);