/* PSPP - a program for statistical analysis.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010 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
#include <libpspp/assertion.h>
#include <libpspp/cast.h>
+#include <libpspp/message.h>
#include <libpspp/start-date.h>
#include <libpspp/str.h>
#include <libpspp/string-map.h>
#include <output/charts/roc-chart.h>
#include <output/charts/scree.h>
#include <output/driver-provider.h>
+#include <output/message-item.h>
#include <output/options.h>
#include <output/render.h>
#include <output/tab.h>
/* Internal state. */
struct render_params *params;
+ char *command_name;
char *title;
char *subtitle;
cairo_t *cairo;
int y;
};
+static const struct output_driver_class cairo_driver_class;
+
static void xr_show_page (struct xr_driver *);
static void draw_headers (struct xr_driver *);
static struct xr_driver *
xr_driver_cast (struct output_driver *driver)
{
- assert (driver->class == &cairo_class);
+ assert (driver->class == &cairo_driver_class);
return UP_CAST (driver, struct xr_driver, driver);
}
xr = xzalloc (sizeof *xr);
d = &xr->driver;
- output_driver_init (d, &cairo_class, name, device_type);
+ output_driver_init (d, &cairo_driver_class, name, device_type);
xr->headers = true;
xr->font_height = XR_POINT * 10;
xr->fonts[XR_FONT_FIXED].string
}
static struct output_driver *
-xr_create (const char *name, enum output_device_type device_type,
- struct string_map *o)
+xr_create (const char *file_name, enum settings_output_devices device_type,
+ struct string_map *o, enum xr_output_type file_type)
{
- enum { MIN_LENGTH = 3 };
+ enum { MIN_WIDTH = 3, MIN_LENGTH = 3 };
struct output_driver *d;
struct xr_driver *xr;
cairo_surface_t *surface;
cairo_status_t status;
double width_pt, length_pt;
int paper_width, paper_length;
- char *file_name;
- xr = xr_allocate (name, device_type, o);
+ xr = xr_allocate (file_name, device_type, o);
d = &xr->driver;
xr->headers = parse_boolean (opt (d, o, "headers", "true"));
- xr->file_type = parse_enum (opt (d, o, "output-type", "pdf"),
- "pdf", XR_PDF,
- "ps", XR_PS,
- "svg", XR_SVG,
- (char *) NULL);
- file_name = parse_string (opt (d, o, "output-file",
- (xr->file_type == XR_PDF ? "pspp.pdf"
- : xr->file_type == XR_PS ? "pspp.ps"
- : "pspp.svg")));
+ xr->file_type = file_type;
parse_paper_size (opt (d, o, "paper-size", ""), &paper_width, &paper_length);
xr->left_margin = parse_dimension (opt (d, o, "left-margin", ".5in"));
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
{
- error (0, 0, _("opening output file \"%s\": %s"),
+ error (0, 0, _("error opening output file \"%s\": %s"),
file_name, cairo_status_to_string (status));
cairo_surface_destroy (surface);
goto error;
if (!xr_set_cairo (xr, xr->cairo))
goto error;
+ if (xr->width / (xr->font_height / 2) < MIN_WIDTH)
+ {
+ error (0, 0, _("The defined page is not wide enough to hold at least %d "
+ "characters in the default font. In fact, there's only "
+ "room for %d characters."),
+ MIN_WIDTH,
+ xr->width / (xr->font_height / 2));
+ goto error;
+ }
+
if (xr->length / xr->font_height < MIN_LENGTH)
{
error (0, 0, _("The defined page is not long "
goto error;
}
- free (file_name);
return &xr->driver;
error:
return NULL;
}
+static struct output_driver *
+xr_pdf_create (const char *file_name, enum settings_output_devices device_type,
+ struct string_map *o)
+{
+ return xr_create (file_name, device_type, o, XR_PDF);
+}
+
+static struct output_driver *
+xr_ps_create (const char *file_name, enum settings_output_devices device_type,
+ struct string_map *o)
+{
+ return xr_create (file_name, device_type, o, XR_PS);
+}
+
+static struct output_driver *
+xr_svg_create (const char *file_name, enum settings_output_devices device_type,
+ struct string_map *o)
+{
+ return xr_create (file_name, device_type, o, XR_SVG);
+}
+
static void
xr_destroy (struct output_driver *driver)
{
cairo_destroy (xr->cairo);
}
+ free (xr->command_name);
for (i = 0; i < XR_N_FONTS; i++)
free_font (&xr->fonts[i]);
free (xr->params);
}
static void
-xr_submit (struct output_driver *driver, const struct output_item *output_item)
+xr_output_table_item (struct xr_driver *xr,
+ const struct table_item *table_item)
{
- struct xr_driver *xr = xr_driver_cast (driver);
- if (is_table_item (output_item))
- {
- struct table_item *table_item = to_table_item (output_item);
- struct render_break x_break;
- struct render_page *page;
- int caption_height;
+ struct render_break x_break;
+ struct render_page *page;
+ int caption_height;
- if (xr->y > 0)
- xr->y += xr->font_height;
+ if (xr->y > 0)
+ xr->y += xr->font_height;
+
+ page = xr_render_table_item (xr, table_item, &caption_height);
+ xr->params->size[V] = xr->length - caption_height;
+ for (render_break_init (&x_break, page, H);
+ render_break_has_next (&x_break); )
+ {
+ struct render_page *x_slice;
+ struct render_break y_break;
- page = xr_render_table_item (xr, table_item, &caption_height);
- xr->params->size[V] = xr->length - caption_height;
- for (render_break_init (&x_break, page, H);
- render_break_has_next (&x_break); )
+ x_slice = render_break_next (&x_break, xr->width);
+ for (render_break_init (&y_break, x_slice, V);
+ render_break_has_next (&y_break); )
{
- struct render_page *x_slice;
- struct render_break y_break;
+ int space = xr->length - xr->y;
+ struct render_page *y_slice;
- x_slice = render_break_next (&x_break, xr->width);
- for (render_break_init (&y_break, x_slice, V);
- render_break_has_next (&y_break); )
+ /* XXX doesn't allow for caption or space between segments */
+ if (render_break_next_size (&y_break) > space)
{
- int space = xr->length - xr->y;
- struct render_page *y_slice;
-
- /* XXX doesn't allow for caption or space between segments */
- if (render_break_next_size (&y_break) > space)
- {
- assert (xr->y > 0);
- xr_show_page (xr);
- continue;
- }
-
- y_slice = render_break_next (&y_break, space);
- if (caption_height)
- {
- struct table_cell cell;
- int bb[TABLE_N_AXES][2];
-
- xr_init_caption_cell (table_item_get_caption (table_item),
- &cell);
- bb[H][0] = 0;
- bb[H][1] = xr->width;
- bb[V][0] = 0;
- bb[V][1] = caption_height;
- xr_draw_cell (xr, &cell, bb, bb);
- xr->y += caption_height;
- caption_height = 0;
- }
-
- render_page_draw (y_slice);
- xr->y += render_page_get_size (y_slice, V);
- render_page_unref (y_slice);
+ assert (xr->y > 0);
+ xr_show_page (xr);
+ continue;
}
- render_break_destroy (&y_break);
+
+ y_slice = render_break_next (&y_break, space);
+ if (caption_height)
+ {
+ struct table_cell cell;
+ int bb[TABLE_N_AXES][2];
+
+ xr_init_caption_cell (table_item_get_caption (table_item),
+ &cell);
+ bb[H][0] = 0;
+ bb[H][1] = xr->width;
+ bb[V][0] = 0;
+ bb[V][1] = caption_height;
+ xr_draw_cell (xr, &cell, bb, bb);
+ xr->y += caption_height;
+ caption_height = 0;
+ }
+
+ render_page_draw (y_slice);
+ xr->y += render_page_get_size (y_slice, V);
+ render_page_unref (y_slice);
}
- render_break_destroy (&x_break);
+ render_break_destroy (&y_break);
}
+ render_break_destroy (&x_break);
+}
+
+static void
+xr_output_text (struct xr_driver *xr, const char *text)
+{
+ struct table_item *table_item;
+
+ table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+ xr_output_table_item (xr, table_item);
+ table_item_unref (table_item);
+}
+
+static void
+xr_submit (struct output_driver *driver, const struct output_item *output_item)
+{
+ struct xr_driver *xr = xr_driver_cast (driver);
+ if (is_table_item (output_item))
+ xr_output_table_item (xr, to_table_item (output_item));
else if (is_chart_item (output_item))
{
if (xr->y > 0)
break;
default:
- {
- struct table_item *item;
-
- item = table_item_create (table_from_string (0, text), NULL);
- xr_submit (&xr->driver, &item->output_item);
- table_item_unref (item);
- }
+ xr_output_text (xr, text);
break;
}
-
+ }
+ else if (is_message_item (output_item))
+ {
+ const struct message_item *message_item = to_message_item (output_item);
+ const struct msg *msg = message_item_get_msg (message_item);
+ char *s = msg_to_string (msg, xr->command_name);
+ xr_output_text (xr, s);
+ free (s);
}
}
if (font->desc != NULL)
pango_font_description_free (font->desc);
pango_font_metrics_unref (font->metrics);
- g_object_unref (font->layout);
+ if (font->layout != NULL)
+ g_object_unref (font->layout);
}
-/* Cairo driver class. */
-const struct output_driver_class cairo_class =
+struct output_driver_factory pdf_driver_factory = { "pdf", xr_pdf_create };
+struct output_driver_factory ps_driver_factory = { "ps", xr_ps_create };
+struct output_driver_factory svg_driver_factory = { "svg", xr_svg_create };
+
+static const struct output_driver_class cairo_driver_class =
{
"cairo",
- xr_create,
xr_destroy,
xr_submit,
xr_flush,
#define CHART_HEIGHT 375
struct xr_driver *
-xr_create_driver (cairo_t *cairo)
+xr_create_driver (cairo_t *cairo, struct string_map *options)
{
- struct xr_driver *xr;
- struct string_map map;
-
- string_map_init (&map);
- xr = xr_allocate ("cairo", 0, &map);
- string_map_destroy (&map);
-
+ struct xr_driver *xr = xr_allocate ("cairo", 0, options);
xr->width = INT_MAX / 8;
xr->length = INT_MAX / 8;
if (!xr_set_cairo (xr, cairo))
return xr;
}
+static struct xr_rendering *
+xr_rendering_create_text (struct xr_driver *xr, const char *text, cairo_t *cr)
+{
+ struct table_item *table_item;
+ struct xr_rendering *r;
+
+ table_item = table_item_create (table_from_string (0, text), NULL);
+ r = xr_rendering_create (xr, &table_item->output_item, cr);
+ table_item_unref (table_item);
+
+ return r;
+}
+
struct xr_rendering *
xr_rendering_create (struct xr_driver *xr, const struct output_item *item,
cairo_t *cr)
struct xr_rendering *r = NULL;
if (is_text_item (item))
+ r = xr_rendering_create_text (xr, text_item_get_text (to_text_item (item)),
+ cr);
+ else if (is_message_item (item))
{
- const struct text_item *text_item = to_text_item (item);
- const char *text = text_item_get_text (text_item);
- struct table_item *table_item;
-
- table_item = table_item_create (table_from_string (0, text), NULL);
- r = xr_rendering_create (xr, &table_item->output_item, cr);
- table_item_unref (table_item);
+ const struct message_item *message_item = to_message_item (item);
+ const struct msg *msg = message_item_get_msg (message_item);
+ char *s = msg_to_string (msg, NULL);
+ r = xr_rendering_create_text (xr, s, cr);
+ free (s);
}
else if (is_table_item (item))
{
status = cairo_surface_write_to_png (surface, file_name);
if (status != CAIRO_STATUS_SUCCESS)
- error (0, 0, _("writing output file \"%s\": %s"),
+ error (0, 0, _("error writing output file \"%s\": %s"),
file_name, cairo_status_to_string (status));
cairo_destroy (cr);