1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008-2015 Free Software Foundation.
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 "ui/gui/psppire-output-view.h"
24 #include "libpspp/assertion.h"
25 #include "libpspp/string-map.h"
26 #include "output/cairo.h"
27 #include "output/driver-provider.h"
28 #include "output/driver.h"
29 #include "output/chart-item.h"
30 #include "output/message-item.h"
31 #include "output/output-item.h"
32 #include "output/table-item.h"
33 #include "output/text-item.h"
35 #include "gl/c-xvasprintf.h"
36 #include "gl/minmax.h"
37 #include "gl/tmpdir.h"
38 #include "gl/xalloc.h"
41 #define _(msgid) gettext (msgid)
43 struct output_view_item
45 struct output_item *item;
46 GtkWidget *drawing_area;
49 struct psppire_output_view
59 struct string_map render_opts;
60 GtkTreeView *overview;
61 GtkTreeIter cur_command;
66 struct output_view_item *items;
67 size_t n_items, allocated_items;
69 /* Variables pertaining to printing */
70 GtkPrintSettings *print_settings;
71 struct xr_driver *print_xrd;
79 COL_NAME, /* Table name. */
80 COL_ADDR, /* Pointer to the table */
81 COL_Y, /* Y position of top of name. */
85 static void on_dwgarea_realize (GtkWidget *widget, gpointer data);
88 draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
90 struct psppire_output_view *view = data;
91 struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering");
93 const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output));
95 PangoFontDescription *font_desc;
99 gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]);
101 string_map_replace (&view->render_opts, "foreground-color", fgc);
105 /* Use GTK+ default font as proportional font. */
106 font_name = pango_font_description_to_string (style->font_desc);
107 string_map_replace (&view->render_opts, "prop-font", font_name);
110 /* Derived emphasized font from proportional font. */
111 font_desc = pango_font_description_copy (style->font_desc);
112 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
113 font_name = pango_font_description_to_string (font_desc);
114 string_map_replace (&view->render_opts, "emph-font", font_name);
116 pango_font_description_free (font_desc);
118 xr_rendering_apply_options (r, &view->render_opts);
120 xr_rendering_draw_all (r, cr);
126 free_rendering (gpointer rendering_)
128 struct xr_rendering *rendering = rendering_;
129 xr_rendering_destroy (rendering);
133 create_xr (struct psppire_output_view *view)
135 const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output));
136 struct text_item *text_item;
137 PangoFontDescription *font_desc;
138 struct xr_rendering *r;
144 cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output)));
146 /* Set the widget's text color as the foreground color for the output driver */
147 fgc = gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]);
149 string_map_insert (&view->render_opts, "foreground-color", fgc);
152 /* Use GTK+ default font as proportional font. */
153 font_name = pango_font_description_to_string (style->font_desc);
154 string_map_insert (&view->render_opts, "prop-font", font_name);
157 /* Derived emphasized font from proportional font. */
158 font_desc = pango_font_description_copy (style->font_desc);
159 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
160 font_name = pango_font_description_to_string (font_desc);
161 string_map_insert (&view->render_opts, "emph-font", font_name);
163 pango_font_description_free (font_desc);
165 /* Pretend that the "page" has a reasonable width and a very big length,
166 so that most tables can be conveniently viewed on-screen with vertical
167 scrolling only. (The length should not be increased very much because
168 it is already close enough to INT_MAX when expressed as thousands of a
170 string_map_insert_nocopy (&view->render_opts, xstrdup ("paper-size"),
171 xasprintf ("%dx1000000pt", view->render_width));
172 string_map_insert (&view->render_opts, "left-margin", "0");
173 string_map_insert (&view->render_opts, "right-margin", "0");
174 string_map_insert (&view->render_opts, "top-margin", "0");
175 string_map_insert (&view->render_opts, "bottom-margin", "0");
177 view->xr = xr_driver_create (cr, &view->render_opts);
179 text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X");
180 r = xr_rendering_create (view->xr, text_item_super (text_item), cr);
181 xr_rendering_measure (r, &font_width, &view->font_height);
182 /* xr_rendering_destroy (r); */
183 text_item_unref (text_item);
189 create_drawing_area (struct psppire_output_view *view,
190 GtkWidget *drawing_area, struct xr_rendering *r,
193 g_object_set_data_full (G_OBJECT (drawing_area),
194 "rendering", r, free_rendering);
196 g_signal_connect (drawing_area, "realize",
197 G_CALLBACK (on_dwgarea_realize), view);
198 g_signal_connect (drawing_area, "draw",
199 G_CALLBACK (draw_callback), view);
201 gtk_widget_set_size_request (drawing_area, tw, th);
202 gtk_layout_put (view->output, drawing_area, 0, view->y);
204 gtk_widget_show (drawing_area);
208 rerender (struct psppire_output_view *view)
210 struct output_view_item *item;
213 if (!view->n_items || !gtk_widget_get_window (GTK_WIDGET (view->output)))
216 string_map_clear (&view->render_opts);
217 xr_driver_destroy (view->xr);
220 cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output)));
224 for (item = view->items; item < &view->items[view->n_items]; item++)
226 struct xr_rendering *r;
230 view->y += view->font_height / 2;
232 r = xr_rendering_create (view->xr, item->item, cr);
235 g_warn_if_reached ();
239 xr_rendering_measure (r, &tw, &th);
241 if (!item->drawing_area)
243 item->drawing_area = gtk_drawing_area_new ();
244 create_drawing_area (view, item->drawing_area, r, tw, th);
248 g_object_set_data_full (G_OBJECT (item->drawing_area),
249 "rendering", r, free_rendering);
250 gtk_widget_set_size_request (item->drawing_area, tw, th);
251 gtk_layout_move (view->output, item->drawing_area, 0, view->y);
254 if (view->max_width < tw)
255 view->max_width = tw;
259 gtk_layout_set_size (view->output, view->max_width, view->y);
264 psppire_output_view_put (struct psppire_output_view *view,
265 const struct output_item *item)
267 struct output_view_item *view_item;
268 GtkWidget *drawing_area;
269 struct xr_rendering *r;
277 if (is_text_item (item))
279 const struct text_item *text_item = to_text_item (item);
280 enum text_item_type type = text_item_get_type (text_item);
281 const char *text = text_item_get_text (text_item);
283 if (type == TEXT_ITEM_COMMAND_CLOSE)
285 view->in_command = false;
288 else if (text[0] == '\0')
292 if (view->n_items >= view->allocated_items)
293 view->items = x2nrealloc (view->items, &view->allocated_items,
294 sizeof *view->items);
295 view_item = &view->items[view->n_items++];
296 view_item->item = output_item_ref (item);
297 view_item->drawing_area = NULL;
299 if (gtk_widget_get_window (GTK_WIDGET (view->output)))
301 view_item->drawing_area = drawing_area = gtk_drawing_area_new ();
303 cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output)));
304 if (view->xr == NULL)
308 view->y += view->font_height / 2;
310 r = xr_rendering_create (view->xr, item, cr);
314 xr_rendering_measure (r, &tw, &th);
316 create_drawing_area (view, drawing_area, r, tw, th);
322 && (!is_text_item (item)
323 || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
324 || !view->in_command))
326 store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview));
328 ds_init_empty (&name);
329 if (is_text_item (item)
330 && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
332 gtk_tree_store_append (store, &iter, NULL);
333 view->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
334 view->in_command = true;
338 GtkTreeIter *p = view->in_command ? &view->cur_command : NULL;
339 gtk_tree_store_append (store, &iter, p);
343 if (is_text_item (item))
344 ds_put_cstr (&name, text_item_get_text (to_text_item (item)));
345 else if (is_message_item (item))
347 const struct message_item *msg_item = to_message_item (item);
348 const struct msg *msg = message_item_get_msg (msg_item);
349 ds_put_format (&name, "%s: %s", _("Message"),
350 msg_severity_to_string (msg->severity));
352 else if (is_table_item (item))
354 const char *title = table_item_get_title (to_table_item (item));
356 ds_put_format (&name, "Table: %s", title);
358 ds_put_cstr (&name, "Table");
360 else if (is_chart_item (item))
362 const char *s = chart_item_get_title (to_chart_item (item));
364 ds_put_format (&name, "Chart: %s", s);
366 ds_put_cstr (&name, "Chart");
368 gtk_tree_store_set (store, &iter,
369 COL_NAME, ds_cstr (&name),
375 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
376 gtk_tree_view_expand_row (view->overview, path, TRUE);
377 gtk_tree_path_free (path);
380 if (view->max_width < tw)
381 view->max_width = tw;
384 gtk_layout_set_size (view->output, view->max_width, view->y);
391 on_row_activate (GtkTreeView *overview,
393 GtkTreeViewColumn *column,
394 struct psppire_output_view *view)
402 model = gtk_tree_view_get_model (overview);
403 if (!gtk_tree_model_get_iter (model, &iter, path))
406 gtk_tree_model_get_value (model, &iter, COL_Y, &value);
407 y = g_value_get_long (&value);
408 g_value_unset (&value);
410 vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view->output));
411 min = gtk_adjustment_get_lower (vadj);
412 max = gtk_adjustment_get_upper (vadj) - gtk_adjustment_get_page_size (vadj);
417 gtk_adjustment_set_value (vadj, y);
421 copy_base_to_bg (GtkWidget *dest, GtkWidget *src)
424 for (i = 0; i < 5; ++i)
426 gtk_widget_modify_bg (dest, i, >k_widget_get_style (src)->base[i]);
427 gtk_widget_modify_fg (dest, i, >k_widget_get_style (src)->text[i]);
431 /* Copy the base style from the parent widget to the container and all its
432 children. We do this because the container's primary purpose is to display
433 text. This way psppire appears to follow the chosen gnome theme. */
435 on_style_set (GtkWidget *toplevel, GtkStyle *prev,
436 struct psppire_output_view *view)
438 copy_base_to_bg (GTK_WIDGET (view->output), toplevel);
439 gtk_container_foreach (GTK_CONTAINER (view->output),
440 (GtkCallback) copy_base_to_bg, view->output);
444 on_dwgarea_realize (GtkWidget *dwg_area, gpointer data)
446 copy_base_to_bg (dwg_area, gtk_widget_get_toplevel (dwg_area));
457 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
458 Temporary directory names are usually not that long. */
460 # define PATH_MAX 1024
464 clipboard_get_cb (GtkClipboard *clipboard,
465 GtkSelectionData *selection_data,
469 struct psppire_output_view *view = data;
473 struct output_driver *driver = NULL;
474 char dirname[PATH_MAX], *filename;
475 struct string_map options;
477 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
478 GtkTreeModel *model = gtk_tree_view_get_model (view->overview);
480 GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
486 if (path_search (dirname, sizeof dirname, NULL, NULL, true)
487 || mkdtemp (dirname) == NULL)
489 msg_error (errno, _("failed to create temporary directory during clipboard operation"));
492 filename = xasprintf ("%s/clip.tmp", dirname);
494 string_map_init (&options);
495 string_map_insert (&options, "output-file", filename);
499 case SELECT_FMT_UTF8:
500 string_map_insert (&options, "box", "unicode");
503 case SELECT_FMT_TEXT:
504 string_map_insert (&options, "format", "txt");
507 case SELECT_FMT_HTML:
508 string_map_insert (&options, "format", "html");
509 string_map_insert (&options, "borders", "false");
510 string_map_insert (&options, "css", "false");
514 string_map_insert (&options, "format", "odt");
518 g_warning ("unsupported clip target\n");
523 driver = output_driver_create (&options);
529 GtkTreePath *path = n->data ;
531 struct output_item *item ;
533 gtk_tree_model_get_iter (model, &iter, path);
534 gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
536 driver->class->submit (driver, item);
541 if ( driver->class->flush)
542 driver->class->flush (driver);
545 /* Some drivers (eg: the odt one) don't write anything until they
547 output_driver_destroy (driver);
550 if ( g_file_get_contents (filename, &text, &length, NULL) )
552 gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
554 (const guchar *) text, length);
560 output_driver_destroy (driver);
572 clipboard_clear_cb (GtkClipboard *clipboard,
577 static const GtkTargetEntry targets[] = {
579 { "STRING", 0, SELECT_FMT_TEXT },
580 { "TEXT", 0, SELECT_FMT_TEXT },
581 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
582 { "text/plain", 0, SELECT_FMT_TEXT },
584 { "UTF8_STRING", 0, SELECT_FMT_UTF8 },
585 { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
587 { "text/html", 0, SELECT_FMT_HTML },
589 { "application/vnd.oasis.opendocument.text", 0, SELECT_FMT_ODT }
593 on_copy (struct psppire_output_view *view)
595 GtkWidget *widget = GTK_WIDGET (view->overview);
596 GtkClipboard *cb = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
598 if (!gtk_clipboard_set_with_data (cb, targets, G_N_ELEMENTS (targets),
599 clipboard_get_cb, clipboard_clear_cb,
601 clipboard_clear_cb (cb, view);
605 on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
607 /* The Copy action is available only if there is something selected */
608 gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
612 on_select_all (struct psppire_output_view *view)
614 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
615 gtk_tree_view_expand_all (view->overview);
616 gtk_tree_selection_select_all (sel);
620 on_size_allocate (GtkWidget *widget,
621 GdkRectangle *allocation,
622 struct psppire_output_view *view)
624 int new_render_width = MAX (300, allocation->width);
625 if (view->render_width != new_render_width)
627 view->render_width = new_render_width;
632 struct psppire_output_view *
633 psppire_output_view_new (GtkLayout *output, GtkTreeView *overview,
634 GtkAction *copy_action, GtkAction *select_all_action)
636 struct psppire_output_view *view;
637 GtkTreeViewColumn *column;
638 GtkCellRenderer *renderer;
639 GtkTreeSelection *sel;
642 view = xmalloc (sizeof *view);
644 view->font_height = 0;
645 view->output = output;
646 view->render_width = 0;
649 string_map_init (&view->render_opts);
650 view->overview = overview;
651 memset (&view->cur_command, 0, sizeof view->cur_command);
652 view->in_command = false;
653 view->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output));
655 view->n_items = view->allocated_items = 0;
656 view->print_settings = NULL;
657 view->print_xrd = NULL;
658 view->print_item = 0;
659 view->print_n_pages = 0;
660 view->paginated = FALSE;
662 g_signal_connect (view->toplevel, "style-set", G_CALLBACK (on_style_set), view);
664 g_signal_connect (output, "size-allocate", G_CALLBACK (on_size_allocate), view);
668 model = GTK_TREE_MODEL (gtk_tree_store_new (
670 G_TYPE_STRING, /* COL_NAME */
671 G_TYPE_POINTER, /* COL_ADDR */
672 G_TYPE_LONG)); /* COL_Y */
673 gtk_tree_view_set_model (overview, model);
674 g_object_unref (model);
676 sel = gtk_tree_view_get_selection (overview);
677 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
678 g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change),
681 column = gtk_tree_view_column_new ();
682 gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column);
683 renderer = gtk_cell_renderer_text_new ();
684 gtk_tree_view_column_pack_start (column, renderer, TRUE);
685 gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME);
687 g_signal_connect (GTK_TREE_VIEW (overview),
688 "row-activated", G_CALLBACK (on_row_activate), view);
690 gtk_action_set_sensitive (copy_action, FALSE);
691 g_signal_connect_swapped (copy_action, "activate",
692 G_CALLBACK (on_copy), view);
693 g_signal_connect_swapped (select_all_action, "activate",
694 G_CALLBACK (on_select_all), view);
701 psppire_output_view_destroy (struct psppire_output_view *view)
708 g_signal_handlers_disconnect_by_func (view->toplevel,
709 G_CALLBACK (on_style_set), view);
711 string_map_destroy (&view->render_opts);
713 for (i = 0; i < view->n_items; i++)
714 output_item_unref (view->items[i].item);
717 view->n_items = view->allocated_items = 0;
719 if (view->print_settings != NULL)
720 g_object_unref (view->print_settings);
722 xr_driver_destroy (view->xr);
728 psppire_output_view_clear (struct psppire_output_view *view)
735 for (i = 0; i < view->n_items; i++)
737 gtk_container_remove (GTK_CONTAINER (view->output),
738 view->items[i].drawing_area);
739 output_item_unref (view->items[i].item);
743 view->n_items = view->allocated_items = 0;
749 psppire_output_view_export (struct psppire_output_view *view,
750 struct string_map *options)
752 struct output_driver *driver;
754 driver = output_driver_create (options);
759 for (i = 0; i < view->n_items; i++)
760 driver->class->submit (driver, view->items[i].item);
761 output_driver_destroy (driver);
768 get_cairo_context_from_print_context (GtkPrintContext *context)
770 cairo_t *cr = gtk_print_context_get_cairo_context (context);
773 For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
776 double xres = gtk_print_context_get_dpi_x (context);
777 double yres = gtk_print_context_get_dpi_y (context);
779 /* This means that the cairo context now has its dimensions in Points */
780 cairo_scale (cr, xres / 72.0, yres / 72.0);
787 create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
789 struct string_map options;
790 GtkPageSetup *page_setup;
791 double width, height;
795 double bottom_margin;
797 page_setup = gtk_print_context_get_page_setup (context);
798 width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
799 height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
800 left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
801 right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
802 top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
803 bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
805 string_map_init (&options);
806 string_map_insert_nocopy (&options, xstrdup ("paper-size"),
807 c_xasprintf("%.2fx%.2fmm", width, height));
808 string_map_insert_nocopy (&options, xstrdup ("left-margin"),
809 c_xasprintf ("%.2fmm", left_margin));
810 string_map_insert_nocopy (&options, xstrdup ("right-margin"),
811 c_xasprintf ("%.2fmm", right_margin));
812 string_map_insert_nocopy (&options, xstrdup ("top-margin"),
813 c_xasprintf ("%.2fmm", top_margin));
814 string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
815 c_xasprintf ("%.2fmm", bottom_margin));
817 view->print_xrd = xr_driver_create (get_cairo_context_from_print_context (context), &options);
819 string_map_destroy (&options);
823 paginate (GtkPrintOperation *operation,
824 GtkPrintContext *context,
825 struct psppire_output_view *view)
829 /* Sometimes GTK+ emits this signal again even after pagination is
830 complete. Don't let that screw up printing. */
833 else if ( view->print_item < view->n_items )
835 xr_driver_output_item (view->print_xrd,
836 view->items[view->print_item++].item);
837 while (xr_driver_need_new_page (view->print_xrd))
839 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
840 view->print_n_pages ++;
846 gtk_print_operation_set_n_pages (operation, view->print_n_pages);
848 /* Re-create the driver to do the real printing. */
849 xr_driver_destroy (view->print_xrd);
850 create_xr_print_driver (context, view);
851 view->print_item = 0;
852 view->paginated = TRUE;
859 begin_print (GtkPrintOperation *operation,
860 GtkPrintContext *context,
861 struct psppire_output_view *view)
863 create_xr_print_driver (context, view);
865 view->print_item = 0;
866 view->print_n_pages = 1;
867 view->paginated = FALSE;
871 end_print (GtkPrintOperation *operation,
872 GtkPrintContext *context,
873 struct psppire_output_view *view)
875 xr_driver_destroy (view->print_xrd);
880 draw_page (GtkPrintOperation *operation,
881 GtkPrintContext *context,
883 struct psppire_output_view *view)
885 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
886 while (!xr_driver_need_new_page (view->print_xrd)
887 && view->print_item < view->n_items)
888 xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item);
893 psppire_output_view_print (struct psppire_output_view *view,
894 GtkWindow *parent_window)
896 GtkPrintOperationResult res;
898 GtkPrintOperation *print = gtk_print_operation_new ();
900 if (view->print_settings != NULL)
901 gtk_print_operation_set_print_settings (print, view->print_settings);
903 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
904 g_signal_connect (print, "end_print", G_CALLBACK (end_print), view);
905 g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);
906 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), view);
908 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
909 parent_window, NULL);
911 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
913 if (view->print_settings != NULL)
914 g_object_unref (view->print_settings);
915 view->print_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
918 g_object_unref (print);
921 struct psppire_output_view_driver
923 struct output_driver driver;
924 struct psppire_output_view *view;
927 static struct psppire_output_view_driver *
928 psppire_output_view_driver_cast (struct output_driver *driver)
930 return UP_CAST (driver, struct psppire_output_view_driver, driver);
934 psppire_output_view_submit (struct output_driver *this,
935 const struct output_item *item)
937 struct psppire_output_view_driver *povd = psppire_output_view_driver_cast (this);
939 if (is_table_item (item))
940 psppire_output_view_put (povd->view, item);
943 static struct output_driver_class psppire_output_view_driver_class =
945 "PSPPIRE Output View", /* name */
947 psppire_output_view_submit, /* submit */
952 psppire_output_view_register_driver (struct psppire_output_view *view)
954 struct psppire_output_view_driver *povd;
955 struct output_driver *d;
957 povd = xzalloc (sizeof *povd);
960 output_driver_init (d, &psppire_output_view_driver_class, "PSPPIRE Output View",
961 SETTINGS_DEVICE_UNFILTERED);
962 output_driver_register (d);