X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fui%2Fgui%2Fpsppire-output-view.c;h=2feaf90d62cc37135adb01d757f8c0d6bcd3c338;hb=17339b8ef2b6c9c403ceccb9f0ab534a943f92e1;hp=77fa537dce3a9004d8d859f245e116ff51cd5532;hpb=9021515cfa1489f9cd37e7440807bdd1d40de37a;p=pspp diff --git a/src/ui/gui/psppire-output-view.c b/src/ui/gui/psppire-output-view.c index 77fa537dce..2feaf90d62 100644 --- a/src/ui/gui/psppire-output-view.c +++ b/src/ui/gui/psppire-output-view.c @@ -1,5 +1,5 @@ /* PSPPIRE - a graphical user interface for PSPP. - Copyright (C) 2008-2014 Free Software Foundation. + Copyright (C) 2008-2015, 2016 Free Software Foundation. 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 @@ -33,20 +33,28 @@ #include "output/text-item.h" #include "gl/c-xvasprintf.h" +#include "gl/minmax.h" #include "gl/tmpdir.h" #include "gl/xalloc.h" #include #define _(msgid) gettext (msgid) +struct output_view_item + { + struct output_item *item; + GtkWidget *drawing_area; + }; + struct psppire_output_view { struct xr_driver *xr; int font_height; GtkLayout *output; + int render_width; int max_width; - int y; + glong y; struct string_map render_opts; GtkTreeView *overview; @@ -55,7 +63,7 @@ struct psppire_output_view GtkWidget *toplevel; - struct output_item **items; + struct output_view_item *items; size_t n_items, allocated_items; /* Variables pertaining to printing */ @@ -68,73 +76,221 @@ struct psppire_output_view enum { - COL_TITLE, /* Table title. */ + COL_NAME, /* Table name. */ COL_ADDR, /* Pointer to the table */ - COL_Y, /* Y position of top of title. */ + COL_Y, /* Y position of top of name. */ N_COLS }; -static void on_dwgarea_realize (GtkWidget *widget, gpointer data); - static gboolean -expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) +draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data) { - struct psppire_output_view *view = data; struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering"); - cairo_t *cr = gdk_cairo_create (widget->window); + xr_rendering_draw_all (r, cr); + return TRUE; +} - const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output)); +static void +free_rendering (gpointer rendering_) +{ + struct xr_rendering *rendering = rendering_; + xr_rendering_destroy (rendering); +} +static void +create_xr (struct psppire_output_view *view) +{ + struct text_item *text_item; PangoFontDescription *font_desc; + struct xr_rendering *r; char *font_name; + int font_width; + cairo_t *cr; + gchar *fgc; + + GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (view->output)); + GtkStateFlags state = gtk_widget_get_state_flags (GTK_WIDGET (view->output)); + GdkRGBA *fg_color; - gchar *fgc = - gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]); + gtk_style_context_get (context, state, + "font", &font_desc, "color", &fg_color, NULL); - string_map_replace (&view->render_opts, "foreground-color", fgc); + cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output))); - free (fgc); + /* Set the widget's text color as the foreground color for the output driver */ + /* gdk_rgba_to_string() would be perfect, but xr's parse_color does not */ + /* understand the rgb(255,128,33) format. Therefore we do it ourself. */ + fgc = xasprintf("#%4x%4x%4x",(int)(fg_color->red*0xffff), + (int)(fg_color->green*0xffff),(int)(fg_color->blue*0xffff)); + string_map_insert (&view->render_opts, "foreground-color", fgc); + g_free (fgc); + gdk_rgba_free (fg_color); /* Use GTK+ default font as proportional font. */ - font_name = pango_font_description_to_string (style->font_desc); - string_map_replace (&view->render_opts, "prop-font", font_name); + font_name = pango_font_description_to_string (font_desc); + string_map_insert (&view->render_opts, "prop-font", font_name); g_free (font_name); /* Derived emphasized font from proportional font. */ - font_desc = pango_font_description_copy (style->font_desc); pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC); font_name = pango_font_description_to_string (font_desc); - string_map_replace (&view->render_opts, "emph-font", font_name); + string_map_insert (&view->render_opts, "emph-font", font_name); g_free (font_name); pango_font_description_free (font_desc); - xr_rendering_apply_options (r, &view->render_opts); + /* Pretend that the "page" has a reasonable width and a very big length, + so that most tables can be conveniently viewed on-screen with vertical + scrolling only. (The length should not be increased very much because + it is already close enough to INT_MAX when expressed as thousands of a + point.) */ + string_map_insert_nocopy (&view->render_opts, xstrdup ("paper-size"), + xasprintf ("%dx1000000pt", view->render_width)); + string_map_insert (&view->render_opts, "left-margin", "0"); + string_map_insert (&view->render_opts, "right-margin", "0"); + string_map_insert (&view->render_opts, "top-margin", "0"); + string_map_insert (&view->render_opts, "bottom-margin", "0"); + + view->xr = xr_driver_create (cr, &view->render_opts); + + text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X"); + r = xr_rendering_create (view->xr, text_item_super (text_item), cr); + xr_rendering_measure (r, &font_width, &view->font_height); + text_item_unref (text_item); - xr_rendering_draw (r, cr, event->area.x, event->area.y, - event->area.width, event->area.height); cairo_destroy (cr); +} - return TRUE; +/* Return the horizontal position to place a widget whose + width is CHILD_WIDTH */ +static gint +get_xpos (const struct psppire_output_view *view, gint child_width) +{ + GdkWindow *gdkw = gtk_widget_get_window (GTK_WIDGET (view->output)); + guint w = gdk_window_get_width (gdkw); + int gutter = 0; + g_object_get (view->output, "border-width", &gutter, NULL); + return (gtk_widget_get_direction (GTK_WIDGET (view->output)) == GTK_TEXT_DIR_RTL) ? w - child_width - gutter: gutter; +} + +static void +create_drawing_area (struct psppire_output_view *view, + GtkWidget *drawing_area, struct xr_rendering *r, + int tw, int th) +{ + /* Enable this to help with debugging. It shows you which widgets are being + put where. */ + if (0) + { + GdkRGBA green = {0, 1, 0, 1}; + gtk_widget_override_background_color (GTK_WIDGET (view->output), + GTK_STATE_NORMAL, &green); + GdkRGBA red = {1, 0, 0, 1}; + gtk_widget_override_background_color (drawing_area, GTK_STATE_NORMAL, &red); + } + + g_object_set_data_full (G_OBJECT (drawing_area), + "rendering", r, free_rendering); + + g_signal_connect (drawing_area, "draw", + G_CALLBACK (draw_callback), view); + + gtk_widget_set_size_request (drawing_area, tw, th); + gint xpos = get_xpos (view, tw); + + gtk_layout_put (view->output, drawing_area, xpos, view->y); + + gtk_widget_show (drawing_area); +} + +static void +rerender (struct psppire_output_view *view) +{ + struct output_view_item *item; + GdkWindow *gdkw = gtk_widget_get_window (GTK_WIDGET (view->output)); + cairo_t *cr; + + if (!view->n_items || ! gdkw) + return; + + cr = gdk_cairo_create (gdkw); + if (view->xr == NULL) + create_xr (view); + view->y = 0; + view->max_width = 0; + for (item = view->items; item < &view->items[view->n_items]; item++) + { + struct xr_rendering *r; + GtkAllocation alloc; + int tw, th; + + if (view->y > 0) + view->y += view->font_height / 2; + + r = xr_rendering_create (view->xr, item->item, cr); + if (r == NULL) + { + g_warn_if_reached (); + continue; + } + + xr_rendering_measure (r, &tw, &th); + + gint xpos = get_xpos (view, tw); + + if (!item->drawing_area) + { + item->drawing_area = gtk_drawing_area_new (); + create_drawing_area (view, item->drawing_area, r, tw, th); + } + else + { + g_object_set_data_full (G_OBJECT (item->drawing_area), + "rendering", r, free_rendering); + gtk_widget_set_size_request (item->drawing_area, tw, th); + gtk_layout_move (view->output, item->drawing_area, xpos, view->y); + } + + { + gint minw; + gint minh; + /* This code probably doesn't bring us anthing, but Gtk + shows warnings if get_preferred_width/height is not + called before the size_allocate below is called. */ + gtk_widget_get_preferred_width (item->drawing_area, &minw, NULL); + gtk_widget_get_preferred_height (item->drawing_area, &minh, NULL); + if (th > minh) th = minh; + if (tw > minw) tw = minw; + } + alloc.x = xpos; + alloc.y = view->y; + alloc.width = tw; + alloc.height = th; + + gtk_widget_size_allocate (item->drawing_area, &alloc); + + if (view->max_width < tw) + view->max_width = tw; + view->y += th; + } + + gtk_layout_set_size (view->output, view->max_width, view->y); + cairo_destroy (cr); } void psppire_output_view_put (struct psppire_output_view *view, const struct output_item *item) { + struct output_view_item *view_item; GtkWidget *drawing_area; struct xr_rendering *r; - struct string title; + struct string name; GtkTreeStore *store; + cairo_t *cr = NULL; GtkTreePath *path; GtkTreeIter iter; - cairo_t *cr; int tw, th; - if (view->n_items >= view->allocated_items) - view->items = x2nrealloc (view->items, &view->allocated_items, - sizeof *view->items); - view->items[view->n_items++] = output_item_ref (item); - if (is_text_item (item)) { const struct text_item *text_item = to_text_item (item); @@ -150,75 +306,34 @@ psppire_output_view_put (struct psppire_output_view *view, return; } - cr = gdk_cairo_create (GTK_WIDGET (view->output)->window); - if (view->xr == NULL) - { - const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output)); - struct text_item *text_item; - PangoFontDescription *font_desc; - char *font_name; - int font_width; - - /* Set the widget's text color as the foreground color for the output driver */ - gchar *fgc = gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]); - - string_map_insert (&view->render_opts, "foreground-color", fgc); - g_free (fgc); - - /* Use GTK+ default font as proportional font. */ - font_name = pango_font_description_to_string (style->font_desc); - string_map_insert (&view->render_opts, "prop-font", font_name); - g_free (font_name); - - /* Derived emphasized font from proportional font. */ - font_desc = pango_font_description_copy (style->font_desc); - pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC); - font_name = pango_font_description_to_string (font_desc); - string_map_insert (&view->render_opts, "emph-font", font_name); - g_free (font_name); - pango_font_description_free (font_desc); - - /* Pretend that the "page" has a reasonable width and a very big length, - so that most tables can be conveniently viewed on-screen with vertical - scrolling only. (The length should not be increased very much because - it is already close enough to INT_MAX when expressed as thousands of a - point.) */ - string_map_insert (&view->render_opts, "paper-size", "300x200000mm"); - string_map_insert (&view->render_opts, "left-margin", "0"); - string_map_insert (&view->render_opts, "right-margin", "0"); - string_map_insert (&view->render_opts, "top-margin", "0"); - string_map_insert (&view->render_opts, "bottom-margin", "0"); - - view->xr = xr_driver_create (cr, &view->render_opts); - - text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X"); - r = xr_rendering_create (view->xr, text_item_super (text_item), cr); - xr_rendering_measure (r, &font_width, &view->font_height); - /* xr_rendering_destroy (r); */ - text_item_unref (text_item); - } - - if (view->y > 0) - view->y += view->font_height / 2; + if (view->n_items >= view->allocated_items) + view->items = x2nrealloc (view->items, &view->allocated_items, + sizeof *view->items); + view_item = &view->items[view->n_items++]; + view_item->item = output_item_ref (item); + view_item->drawing_area = NULL; - r = xr_rendering_create (view->xr, item, cr); - if (r == NULL) - goto done; + if (gtk_widget_get_window (GTK_WIDGET (view->output))) + { + view_item->drawing_area = drawing_area = gtk_drawing_area_new (); - xr_rendering_measure (r, &tw, &th); + cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output))); + if (view->xr == NULL) + create_xr (view); - drawing_area = gtk_drawing_area_new (); + if (view->y > 0) + view->y += view->font_height / 2; - g_object_set_data (G_OBJECT (drawing_area), "rendering", r); - g_signal_connect (drawing_area, "realize", - G_CALLBACK (on_dwgarea_realize), view); - g_signal_connect (drawing_area, "expose_event", - G_CALLBACK (expose_event_callback), view); + r = xr_rendering_create (view->xr, item, cr); + if (r == NULL) + goto done; - gtk_widget_set_size_request (drawing_area, tw, th); - gtk_layout_put (view->output, drawing_area, 0, view->y); + xr_rendering_measure (r, &tw, &th); - gtk_widget_show (drawing_area); + create_drawing_area (view, drawing_area, r, tw, th); + } + else + tw = th = 0; if (view->overview && (!is_text_item (item) @@ -227,7 +342,7 @@ psppire_output_view_put (struct psppire_output_view *view, { store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview)); - ds_init_empty (&title); + ds_init_empty (&name); if (is_text_item (item) && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN) { @@ -241,38 +356,38 @@ psppire_output_view_put (struct psppire_output_view *view, gtk_tree_store_append (store, &iter, p); } - ds_clear (&title); + ds_clear (&name); if (is_text_item (item)) - ds_put_cstr (&title, text_item_get_text (to_text_item (item))); + ds_put_cstr (&name, text_item_get_text (to_text_item (item))); else if (is_message_item (item)) { const struct message_item *msg_item = to_message_item (item); const struct msg *msg = message_item_get_msg (msg_item); - ds_put_format (&title, "%s: %s", _("Message"), + ds_put_format (&name, "%s: %s", _("Message"), msg_severity_to_string (msg->severity)); } else if (is_table_item (item)) { - const char *caption = table_item_get_caption (to_table_item (item)); - if (caption != NULL) - ds_put_format (&title, "Table: %s", caption); + const char *title = table_item_get_title (to_table_item (item)); + if (title != NULL) + ds_put_format (&name, "Table: %s", title); else - ds_put_cstr (&title, "Table"); + ds_put_cstr (&name, "Table"); } else if (is_chart_item (item)) { const char *s = chart_item_get_title (to_chart_item (item)); if (s != NULL) - ds_put_format (&title, "Chart: %s", s); + ds_put_format (&name, "Chart: %s", s); else - ds_put_cstr (&title, "Chart"); + ds_put_cstr (&name, "Chart"); } gtk_tree_store_set (store, &iter, - COL_TITLE, ds_cstr (&title), + COL_NAME, ds_cstr (&name), COL_ADDR, item, - COL_Y, view->y, + COL_Y, (view->y), -1); - ds_destroy (&title); + ds_destroy (&name); path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); gtk_tree_view_expand_row (view->overview, path, TRUE); @@ -309,9 +424,9 @@ on_row_activate (GtkTreeView *overview, y = g_value_get_long (&value); g_value_unset (&value); - vadj = gtk_layout_get_vadjustment (view->output); - min = vadj->lower; - max = vadj->upper - vadj->page_size; + vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view->output)); + min = gtk_adjustment_get_lower (vadj); + max = gtk_adjustment_get_upper (vadj) - gtk_adjustment_get_page_size (vadj); if (y < min) y = min; else if (y > max) @@ -320,32 +435,14 @@ on_row_activate (GtkTreeView *overview, } static void -copy_base_to_bg (GtkWidget *dest, GtkWidget *src) -{ - int i; - for (i = 0; i < 5; ++i) - { - gtk_widget_modify_bg (dest, i, >k_widget_get_style (src)->base[i]); - gtk_widget_modify_fg (dest, i, >k_widget_get_style (src)->text[i]); - } -} - -/* Copy the base style from the parent widget to the container and all its - children. We do this because the container's primary purpose is to display - text. This way psppire appears to follow the chosen gnome theme. */ -static void -on_style_set (GtkWidget *toplevel, GtkStyle *prev, - struct psppire_output_view *view) +on_style_updated (GtkWidget *toplevel, struct psppire_output_view *view) { - copy_base_to_bg (GTK_WIDGET (view->output), toplevel); - gtk_container_foreach (GTK_CONTAINER (view->output), - (GtkCallback) copy_base_to_bg, view->output); -} - -static void -on_dwgarea_realize (GtkWidget *dwg_area, gpointer data) -{ - copy_base_to_bg (dwg_area, gtk_widget_get_toplevel (dwg_area)); + if (!view->n_items || !gtk_widget_get_window (GTK_WIDGET (view->output))) + return; + string_map_clear (&view->render_opts); + xr_driver_destroy (view->xr); + create_xr (view); + rerender (view); } enum { @@ -451,7 +548,7 @@ clipboard_get_cb (GtkClipboard *clipboard, if ( g_file_get_contents (filename, &text, &length, NULL) ) { - gtk_selection_data_set (selection_data, selection_data->target, + gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data), 8, (const guchar *) text, length); } @@ -504,10 +601,12 @@ on_copy (struct psppire_output_view *view) } static void -on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action) +on_selection_change (GtkTreeSelection *sel, GAction *copy_action) { /* The Copy action is available only if there is something selected */ - gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0); + g_object_set (copy_action, + "enabled", gtk_tree_selection_count_selected_rows (sel) > 0, + NULL); } static void @@ -518,20 +617,60 @@ on_select_all (struct psppire_output_view *view) gtk_tree_selection_select_all (sel); } +static void +on_size_allocate (GtkWidget *widget, + GdkRectangle *allocation, + struct psppire_output_view *view) +{ + int new_render_width = MAX (300, allocation->width); + + if (view->render_width != new_render_width) + { + view->render_width = new_render_width; + rerender (view); + } +} + +static void +on_realize (GtkWidget *overview, GObject *view) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (overview)); + gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE); + + GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (overview)); + + GAction *copy_action = g_action_map_lookup_action (G_ACTION_MAP (toplevel), + "copy"); + + GAction *select_all_action = g_action_map_lookup_action (G_ACTION_MAP (toplevel), + "select-all"); + + g_object_set (copy_action, "enabled", FALSE, NULL); + + g_signal_connect_swapped (select_all_action, "activate", + G_CALLBACK (on_select_all), view); + + g_signal_connect_swapped (copy_action, "activate", + G_CALLBACK (on_copy), view); + + g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change), + copy_action); +} + struct psppire_output_view * -psppire_output_view_new (GtkLayout *output, GtkTreeView *overview, - GtkAction *copy_action, GtkAction *select_all_action) +psppire_output_view_new (GtkLayout *output, GtkTreeView *overview) { struct psppire_output_view *view; GtkTreeViewColumn *column; GtkCellRenderer *renderer; - GtkTreeSelection *sel; + GtkTreeModel *model; view = xmalloc (sizeof *view); view->xr = NULL; view->font_height = 0; view->output = output; + view->render_width = 0; view->max_width = 0; view->y = 0; string_map_init (&view->render_opts); @@ -547,38 +686,33 @@ psppire_output_view_new (GtkLayout *output, GtkTreeView *overview, view->print_n_pages = 0; view->paginated = FALSE; - g_signal_connect (view->toplevel, "style-set", G_CALLBACK (on_style_set), view); + g_signal_connect (output, "style-updated", G_CALLBACK (on_style_updated), view); + g_signal_connect (output, "size-allocate", G_CALLBACK (on_size_allocate), view); + + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (output)), + GTK_STYLE_CLASS_VIEW); if (overview) { + g_signal_connect (overview, "realize", G_CALLBACK (on_realize), view); + model = GTK_TREE_MODEL (gtk_tree_store_new ( N_COLS, - G_TYPE_STRING, /* COL_TITLE */ + G_TYPE_STRING, /* COL_NAME */ G_TYPE_POINTER, /* COL_ADDR */ G_TYPE_LONG)); /* COL_Y */ gtk_tree_view_set_model (overview, model); g_object_unref (model); - sel = gtk_tree_view_get_selection (overview); - gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE); - g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change), - copy_action); - column = gtk_tree_view_column_new (); gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column); renderer = gtk_cell_renderer_text_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); - gtk_tree_view_column_add_attribute (column, renderer, "text", COL_TITLE); + gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME); g_signal_connect (GTK_TREE_VIEW (overview), "row-activated", G_CALLBACK (on_row_activate), view); - - gtk_action_set_sensitive (copy_action, FALSE); - g_signal_connect_swapped (copy_action, "activate", - G_CALLBACK (on_copy), view); - g_signal_connect_swapped (select_all_action, "activate", - G_CALLBACK (on_select_all), view); } return view; @@ -592,13 +726,13 @@ psppire_output_view_destroy (struct psppire_output_view *view) if (!view) return; - g_signal_handlers_disconnect_by_func (view->toplevel, - G_CALLBACK (on_style_set), view); + g_signal_handlers_disconnect_by_func (view->output, + G_CALLBACK (on_style_updated), view); string_map_destroy (&view->render_opts); for (i = 0; i < view->n_items; i++) - output_item_unref (view->items[i]); + output_item_unref (view->items[i].item); free (view->items); view->items = NULL; view->n_items = view->allocated_items = 0; @@ -606,9 +740,30 @@ psppire_output_view_destroy (struct psppire_output_view *view) if (view->print_settings != NULL) g_object_unref (view->print_settings); + xr_driver_destroy (view->xr); + free (view); } - + +void +psppire_output_view_clear (struct psppire_output_view *view) +{ + size_t i; + + view->max_width = 0; + view->y = 0; + + for (i = 0; i < view->n_items; i++) + { + gtk_container_remove (GTK_CONTAINER (view->output), + view->items[i].drawing_area); + output_item_unref (view->items[i].item); + } + free (view->items); + view->items = NULL; + view->n_items = view->allocated_items = 0; +} + /* Export. */ void @@ -623,7 +778,7 @@ psppire_output_view_export (struct psppire_output_view *view, size_t i; for (i = 0; i < view->n_items; i++) - driver->class->submit (driver, view->items[i]); + driver->class->submit (driver, view->items[i].item); output_driver_destroy (driver); } } @@ -634,17 +789,17 @@ static cairo_t * get_cairo_context_from_print_context (GtkPrintContext *context) { cairo_t *cr = gtk_print_context_get_cairo_context (context); - + /* For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72. Windows returns 600. */ double xres = gtk_print_context_get_dpi_x (context); double yres = gtk_print_context_get_dpi_y (context); - + /* This means that the cairo context now has its dimensions in Points */ cairo_scale (cr, xres / 72.0, yres / 72.0); - + return cr; } @@ -698,10 +853,11 @@ paginate (GtkPrintOperation *operation, } else if ( view->print_item < view->n_items ) { - xr_driver_output_item (view->print_xrd, view->items[view->print_item++]); + xr_driver_output_item (view->print_xrd, + view->items[view->print_item++].item); while (xr_driver_need_new_page (view->print_xrd)) { - xr_driver_next_page (view->print_xrd, NULL); + xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context)); view->print_n_pages ++; } return FALSE; @@ -750,7 +906,7 @@ draw_page (GtkPrintOperation *operation, xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context)); while (!xr_driver_need_new_page (view->print_xrd) && view->print_item < view->n_items) - xr_driver_output_item (view->print_xrd, view->items [view->print_item++]); + xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item); } @@ -762,7 +918,7 @@ psppire_output_view_print (struct psppire_output_view *view, GtkPrintOperation *print = gtk_print_operation_new (); - if (view->print_settings != NULL) + if (view->print_settings != NULL) gtk_print_operation_set_print_settings (print, view->print_settings); g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view); @@ -782,3 +938,47 @@ psppire_output_view_print (struct psppire_output_view *view, g_object_unref (print); } + +struct psppire_output_view_driver + { + struct output_driver driver; + struct psppire_output_view *view; + }; + +static struct psppire_output_view_driver * +psppire_output_view_driver_cast (struct output_driver *driver) +{ + return UP_CAST (driver, struct psppire_output_view_driver, driver); +} + +static void +psppire_output_view_submit (struct output_driver *this, + const struct output_item *item) +{ + struct psppire_output_view_driver *povd = psppire_output_view_driver_cast (this); + + if (is_table_item (item)) + psppire_output_view_put (povd->view, item); +} + +static struct output_driver_class psppire_output_view_driver_class = + { + "PSPPIRE Output View", /* name */ + NULL, /* destroy */ + psppire_output_view_submit, /* submit */ + NULL, /* flush */ + }; + +void +psppire_output_view_register_driver (struct psppire_output_view *view) +{ + struct psppire_output_view_driver *povd; + struct output_driver *d; + + povd = xzalloc (sizeof *povd); + povd->view = view; + d = &povd->driver; + output_driver_init (d, &psppire_output_view_driver_class, "PSPPIRE Output View", + SETTINGS_DEVICE_UNFILTERED); + output_driver_register (d); +}