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/>. */
21 #include <libpspp/assertion.h>
28 /* Increments table_num so different procedures' output can be
33 if (subtable_num != 0)
40 /* Ejects the paper for all active devices. */
44 struct outp_driver *d;
46 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
50 /* Flushes output on all active devices. */
54 struct outp_driver *d;
56 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
60 /* Skip down a single line on all active devices. */
64 struct outp_driver *d;
66 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
67 if (d->page_open && d->cp_y != 0)
68 d->cp_y += d->font_height;
71 static void render_columns (void *r, struct outp_driver *, struct som_entity *,
73 int hl, int hr, int ht, int hb);
74 static void render_simple (void *r, struct outp_driver *, struct som_entity *,
76 int hl, int hr, int ht, int hb);
77 static void render_segments (void *r, struct outp_driver *,
80 int hl, int hr, int ht, int hb);
82 static void output_entity (struct outp_driver *, struct som_entity *);
84 /* Output table T to appropriate output devices. */
86 som_submit (struct som_entity *t)
88 struct outp_driver *d;
93 assert (entry++ == 0);
96 if (t->type == SOM_TABLE)
102 /* Set up to render the table. */
103 t->class->flags (t, &flags);
104 if (!(flags & SOMF_NO_TITLE))
107 /* Do some basic error checking. */
108 t->class->count (t, &nc, &nr);
109 t->class->headers (t, &hl, &hr, &ht, &hb);
110 if (hl + hr > nc || ht + hb > nr)
112 fprintf (stderr, "headers: (l,r)=(%d,%d), (t,b)=(%d,%d) "
113 "in table size (%d,%d)\n",
114 hl, hr, ht, hb, nc, nr);
117 else if (hl + hr == nc)
118 fprintf (stderr, "warning: headers (l,r)=(%d,%d) in table width %d\n",
120 else if (ht + hb == nr)
121 fprintf (stderr, "warning: headers (t,b)=(%d,%d) in table height %d\n",
125 for (d = outp_drivers (NULL); d; d = outp_drivers (d))
126 output_entity (d, t);
129 assert (--entry == 0);
134 check_fits_width (struct som_entity *t, const struct outp_driver *d, void *r)
140 t->class->headers (t, &hl, &hr, &ht, &hb);
141 t->class->count (t, &nc, &nr);
142 for (i = hl; i < nc - hr; i++)
145 t->class->cumulate (r, SOM_COLUMNS, i, &end, d->width, &actual);
154 check_fits_length (struct som_entity *t, const struct outp_driver *d, void *r)
160 t->class->headers (t, &hl, &hr, &ht, &hb);
161 t->class->count (t, &nc, &nr);
162 for (i = ht; i < nr - hb; i++)
165 t->class->cumulate (r, SOM_ROWS, i, &end, d->length, &actual);
173 /* Output entity T to driver D. */
175 output_entity (struct outp_driver *d, struct som_entity *t)
177 bool fits_width, fits_length;
186 if (d->class->special || t->type == SOM_CHART)
188 d->class->submit (d, t);
192 t->class->headers (t, &hl, &hr, &ht, &hb);
193 t->class->count (t, &nc, &nr);
194 t->class->columns (t, &cs);
195 t->class->flags (t, &flags);
197 r = t->class->render_init (t, d, hl, hr, ht, hb);
199 fits_width = check_fits_width (t, d, r);
200 fits_length = check_fits_length (t, d, r);
201 if (!fits_width || !fits_length)
203 t->class->render_free (r);
210 r = t->class->render_init (t, d, hl, hr, ht, hb);
212 t->class->area (r, &tw, &th);
214 if (!(flags & SOMF_NO_SPACING) && d->cp_y != 0)
215 d->cp_y += d->font_height;
217 if (cs != SOM_COL_NONE
218 && 2 * (tw + d->prop_em_width) <= d->width
219 && nr - (ht + hb) > 5)
220 render_columns (r, d, t, tw, th, hl, hr, ht, hb);
221 else if (tw < d->width && th + d->cp_y < d->length)
222 render_simple (r, d, t, tw, th, hl, hr, ht, hb);
224 render_segments (r, d, t, tw, th, hl, hr, ht, hb);
226 t->class->render_free (r);
229 /* Render the table into multiple columns. */
231 render_columns (void *r, struct outp_driver *d, struct som_entity *t,
232 int tw, int th UNUSED,
233 int hl UNUSED, int hr UNUSED, int ht, int hb)
241 t->class->count (t, &nc, &nr);
242 t->class->columns (t, &cs);
244 assert (cs == SOM_COL_DOWN);
245 assert (d->cp_x == 0);
247 for (y0 = ht; y0 < nr - hb; y0 = y1)
251 t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
263 t->class->title (r, index++, 0);
264 t->class->render (r, 0, y0, nc, y1);
266 d->cp_x += tw + 2 * d->prop_em_width;
267 if (d->cp_x + tw > d->width)
283 /* Render the table by itself on the current page. */
285 render_simple (void *r, struct outp_driver *d, struct som_entity *t,
287 int hl, int hr, int ht, int hb)
291 t->class->count (t, &nc, &nr);
293 assert (d->cp_x == 0);
294 assert (tw < d->width && th + d->cp_y < d->length);
296 t->class->title (r, 0, 0);
297 t->class->render (r, hl, ht, nc - hr, nr - hb);
301 /* General table breaking routine. */
303 render_segments (void *r, struct outp_driver *d, struct som_entity *t,
304 int tw UNUSED, int th UNUSED,
305 int hl, int hr, int ht, int hb)
314 assert (d->cp_x == 0);
316 t->class->count (t, &nc, &nr);
317 for (x_index = 0, x0 = hl; x0 < nc - hr; x0 = x1, x_index++)
322 t->class->cumulate (r, SOM_COLUMNS, x0, &x1, d->width, NULL);
323 if (x_index == 0 && x1 != nc - hr)
326 for (y_index = 0, y0 = ht; y0 < nr - hb; y0 = y1, y_index++)
330 if (count++ != 0 && d->cp_y != 0)
331 d->cp_y += d->font_height;
333 t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
334 if (y_index == 0 && y1 != nr - hb)
344 t->class->title (r, x_index ? x_index : y_index,
345 x_index ? y_index : 0);
346 t->class->render (r, x0, y0, x1, y1);