1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008-2014 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 expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
90 struct psppire_output_view *view = data;
91 struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering");
92 cairo_t *cr = gdk_cairo_create (widget->window);
94 const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output));
96 PangoFontDescription *font_desc;
100 gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]);
102 string_map_replace (&view->render_opts, "foreground-color", fgc);
106 /* Use GTK+ default font as proportional font. */
107 font_name = pango_font_description_to_string (style->font_desc);
108 string_map_replace (&view->render_opts, "prop-font", font_name);
111 /* Derived emphasized font from proportional font. */
112 font_desc = pango_font_description_copy (style->font_desc);
113 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
114 font_name = pango_font_description_to_string (font_desc);
115 string_map_replace (&view->render_opts, "emph-font", font_name);
117 pango_font_description_free (font_desc);
119 xr_rendering_apply_options (r, &view->render_opts);
121 xr_rendering_draw (r, cr, event->area.x, event->area.y,
122 event->area.width, event->area.height);
129 free_rendering (gpointer rendering_)
131 struct xr_rendering *rendering = rendering_;
132 xr_rendering_destroy (rendering);
136 create_xr (struct psppire_output_view *view)
138 const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (view->output));
139 struct text_item *text_item;
140 PangoFontDescription *font_desc;
141 struct xr_rendering *r;
147 cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
149 /* Set the widget's text color as the foreground color for the output driver */
150 fgc = gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (view->output))]);
152 string_map_insert (&view->render_opts, "foreground-color", fgc);
155 /* Use GTK+ default font as proportional font. */
156 font_name = pango_font_description_to_string (style->font_desc);
157 string_map_insert (&view->render_opts, "prop-font", font_name);
160 /* Derived emphasized font from proportional font. */
161 font_desc = pango_font_description_copy (style->font_desc);
162 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
163 font_name = pango_font_description_to_string (font_desc);
164 string_map_insert (&view->render_opts, "emph-font", font_name);
166 pango_font_description_free (font_desc);
168 /* Pretend that the "page" has a reasonable width and a very big length,
169 so that most tables can be conveniently viewed on-screen with vertical
170 scrolling only. (The length should not be increased very much because
171 it is already close enough to INT_MAX when expressed as thousands of a
173 string_map_insert_nocopy (&view->render_opts, xstrdup ("paper-size"),
174 xasprintf ("%dx1000000pt", view->render_width));
175 string_map_insert (&view->render_opts, "left-margin", "0");
176 string_map_insert (&view->render_opts, "right-margin", "0");
177 string_map_insert (&view->render_opts, "top-margin", "0");
178 string_map_insert (&view->render_opts, "bottom-margin", "0");
180 view->xr = xr_driver_create (cr, &view->render_opts);
182 text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X");
183 r = xr_rendering_create (view->xr, text_item_super (text_item), cr);
184 xr_rendering_measure (r, &font_width, &view->font_height);
185 /* xr_rendering_destroy (r); */
186 text_item_unref (text_item);
192 rerender (struct psppire_output_view *view)
194 struct output_view_item *item;
197 if (!view->n_items || !GTK_WIDGET (view->output)->window)
200 string_map_clear (&view->render_opts);
201 xr_driver_destroy (view->xr);
204 cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
208 for (item = view->items; item < &view->items[view->n_items]; item++)
210 struct xr_rendering *r;
215 view->y += view->font_height / 2;
217 r = xr_rendering_create (view->xr, item->item, cr);
220 g_warn_if_reached ();
224 xr_rendering_measure (r, &tw, &th);
226 new = !item->drawing_area;
228 item->drawing_area = gtk_drawing_area_new ();
229 g_object_set_data_full (G_OBJECT (item->drawing_area),
230 "rendering", r, free_rendering);
232 gtk_widget_set_size_request (item->drawing_area, tw, th);
234 gtk_layout_put (view->output, item->drawing_area, 0, view->y);
236 gtk_layout_move (view->output, item->drawing_area, 0, view->y);
238 if (view->max_width < tw)
239 view->max_width = tw;
243 gtk_layout_set_size (view->output, view->max_width, view->y);
248 psppire_output_view_put (struct psppire_output_view *view,
249 const struct output_item *item)
251 struct output_view_item *view_item;
252 GtkWidget *drawing_area;
253 struct xr_rendering *r;
261 if (is_text_item (item))
263 const struct text_item *text_item = to_text_item (item);
264 enum text_item_type type = text_item_get_type (text_item);
265 const char *text = text_item_get_text (text_item);
267 if (type == TEXT_ITEM_COMMAND_CLOSE)
269 view->in_command = false;
272 else if (text[0] == '\0')
276 if (view->n_items >= view->allocated_items)
277 view->items = x2nrealloc (view->items, &view->allocated_items,
278 sizeof *view->items);
279 view_item = &view->items[view->n_items++];
280 view_item->item = output_item_ref (item);
281 view_item->drawing_area = NULL;
283 if (GTK_WIDGET (view->output)->window)
285 view_item->drawing_area = drawing_area = gtk_drawing_area_new ();
287 cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
288 if (view->xr == NULL)
292 view->y += view->font_height / 2;
294 r = xr_rendering_create (view->xr, item, cr);
298 xr_rendering_measure (r, &tw, &th);
300 g_object_set_data_full (G_OBJECT (drawing_area), "rendering", r, free_rendering);
301 g_signal_connect (drawing_area, "realize",
302 G_CALLBACK (on_dwgarea_realize), view);
303 g_signal_connect (drawing_area, "expose_event",
304 G_CALLBACK (expose_event_callback), view);
306 gtk_widget_set_size_request (drawing_area, tw, th);
307 gtk_layout_put (view->output, drawing_area, 0, view->y);
309 gtk_widget_show (drawing_area);
313 && (!is_text_item (item)
314 || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
315 || !view->in_command))
317 store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview));
319 ds_init_empty (&name);
320 if (is_text_item (item)
321 && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
323 gtk_tree_store_append (store, &iter, NULL);
324 view->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
325 view->in_command = true;
329 GtkTreeIter *p = view->in_command ? &view->cur_command : NULL;
330 gtk_tree_store_append (store, &iter, p);
334 if (is_text_item (item))
335 ds_put_cstr (&name, text_item_get_text (to_text_item (item)));
336 else if (is_message_item (item))
338 const struct message_item *msg_item = to_message_item (item);
339 const struct msg *msg = message_item_get_msg (msg_item);
340 ds_put_format (&name, "%s: %s", _("Message"),
341 msg_severity_to_string (msg->severity));
343 else if (is_table_item (item))
345 const char *title = table_item_get_title (to_table_item (item));
347 ds_put_format (&name, "Table: %s", title);
349 ds_put_cstr (&name, "Table");
351 else if (is_chart_item (item))
353 const char *s = chart_item_get_title (to_chart_item (item));
355 ds_put_format (&name, "Chart: %s", s);
357 ds_put_cstr (&name, "Chart");
359 gtk_tree_store_set (store, &iter,
360 COL_NAME, ds_cstr (&name),
366 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
367 gtk_tree_view_expand_row (view->overview, path, TRUE);
368 gtk_tree_path_free (path);
371 if (view->max_width < tw)
372 view->max_width = tw;
375 gtk_layout_set_size (view->output, view->max_width, view->y);
382 on_row_activate (GtkTreeView *overview,
384 GtkTreeViewColumn *column,
385 struct psppire_output_view *view)
393 model = gtk_tree_view_get_model (overview);
394 if (!gtk_tree_model_get_iter (model, &iter, path))
397 gtk_tree_model_get_value (model, &iter, COL_Y, &value);
398 y = g_value_get_long (&value);
399 g_value_unset (&value);
401 vadj = gtk_layout_get_vadjustment (view->output);
403 max = vadj->upper - vadj->page_size;
408 gtk_adjustment_set_value (vadj, y);
412 copy_base_to_bg (GtkWidget *dest, GtkWidget *src)
415 for (i = 0; i < 5; ++i)
417 gtk_widget_modify_bg (dest, i, >k_widget_get_style (src)->base[i]);
418 gtk_widget_modify_fg (dest, i, >k_widget_get_style (src)->text[i]);
422 /* Copy the base style from the parent widget to the container and all its
423 children. We do this because the container's primary purpose is to display
424 text. This way psppire appears to follow the chosen gnome theme. */
426 on_style_set (GtkWidget *toplevel, GtkStyle *prev,
427 struct psppire_output_view *view)
429 copy_base_to_bg (GTK_WIDGET (view->output), toplevel);
430 gtk_container_foreach (GTK_CONTAINER (view->output),
431 (GtkCallback) copy_base_to_bg, view->output);
435 on_dwgarea_realize (GtkWidget *dwg_area, gpointer data)
437 copy_base_to_bg (dwg_area, gtk_widget_get_toplevel (dwg_area));
448 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
449 Temporary directory names are usually not that long. */
451 # define PATH_MAX 1024
455 clipboard_get_cb (GtkClipboard *clipboard,
456 GtkSelectionData *selection_data,
460 struct psppire_output_view *view = data;
464 struct output_driver *driver = NULL;
465 char dirname[PATH_MAX], *filename;
466 struct string_map options;
468 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
469 GtkTreeModel *model = gtk_tree_view_get_model (view->overview);
471 GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
477 if (path_search (dirname, sizeof dirname, NULL, NULL, true)
478 || mkdtemp (dirname) == NULL)
480 msg_error (errno, _("failed to create temporary directory during clipboard operation"));
483 filename = xasprintf ("%s/clip.tmp", dirname);
485 string_map_init (&options);
486 string_map_insert (&options, "output-file", filename);
490 case SELECT_FMT_UTF8:
491 string_map_insert (&options, "box", "unicode");
494 case SELECT_FMT_TEXT:
495 string_map_insert (&options, "format", "txt");
498 case SELECT_FMT_HTML:
499 string_map_insert (&options, "format", "html");
500 string_map_insert (&options, "borders", "false");
501 string_map_insert (&options, "css", "false");
505 string_map_insert (&options, "format", "odt");
509 g_warning ("unsupported clip target\n");
514 driver = output_driver_create (&options);
520 GtkTreePath *path = n->data ;
522 struct output_item *item ;
524 gtk_tree_model_get_iter (model, &iter, path);
525 gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
527 driver->class->submit (driver, item);
532 if ( driver->class->flush)
533 driver->class->flush (driver);
536 /* Some drivers (eg: the odt one) don't write anything until they
538 output_driver_destroy (driver);
541 if ( g_file_get_contents (filename, &text, &length, NULL) )
543 gtk_selection_data_set (selection_data, selection_data->target,
545 (const guchar *) text, length);
551 output_driver_destroy (driver);
563 clipboard_clear_cb (GtkClipboard *clipboard,
568 static const GtkTargetEntry targets[] = {
570 { "STRING", 0, SELECT_FMT_TEXT },
571 { "TEXT", 0, SELECT_FMT_TEXT },
572 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
573 { "text/plain", 0, SELECT_FMT_TEXT },
575 { "UTF8_STRING", 0, SELECT_FMT_UTF8 },
576 { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
578 { "text/html", 0, SELECT_FMT_HTML },
580 { "application/vnd.oasis.opendocument.text", 0, SELECT_FMT_ODT }
584 on_copy (struct psppire_output_view *view)
586 GtkWidget *widget = GTK_WIDGET (view->overview);
587 GtkClipboard *cb = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
589 if (!gtk_clipboard_set_with_data (cb, targets, G_N_ELEMENTS (targets),
590 clipboard_get_cb, clipboard_clear_cb,
592 clipboard_clear_cb (cb, view);
596 on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
598 /* The Copy action is available only if there is something selected */
599 gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
603 on_select_all (struct psppire_output_view *view)
605 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
606 gtk_tree_view_expand_all (view->overview);
607 gtk_tree_selection_select_all (sel);
611 on_size_allocate (GtkWidget *widget,
612 GdkRectangle *allocation,
613 struct psppire_output_view *view)
615 int new_render_width = MAX (300, allocation->width);
616 if (view->render_width != new_render_width)
618 view->render_width = new_render_width;
623 struct psppire_output_view *
624 psppire_output_view_new (GtkLayout *output, GtkTreeView *overview,
625 GtkAction *copy_action, GtkAction *select_all_action)
627 struct psppire_output_view *view;
628 GtkTreeViewColumn *column;
629 GtkCellRenderer *renderer;
630 GtkTreeSelection *sel;
633 view = xmalloc (sizeof *view);
635 view->font_height = 0;
636 view->output = output;
637 view->render_width = 0;
640 string_map_init (&view->render_opts);
641 view->overview = overview;
642 memset (&view->cur_command, 0, sizeof view->cur_command);
643 view->in_command = false;
644 view->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output));
646 view->n_items = view->allocated_items = 0;
647 view->print_settings = NULL;
648 view->print_xrd = NULL;
649 view->print_item = 0;
650 view->print_n_pages = 0;
651 view->paginated = FALSE;
653 g_signal_connect (view->toplevel, "style-set", G_CALLBACK (on_style_set), view);
655 g_signal_connect (output, "size-allocate", G_CALLBACK (on_size_allocate), view);
659 model = GTK_TREE_MODEL (gtk_tree_store_new (
661 G_TYPE_STRING, /* COL_NAME */
662 G_TYPE_POINTER, /* COL_ADDR */
663 G_TYPE_LONG)); /* COL_Y */
664 gtk_tree_view_set_model (overview, model);
665 g_object_unref (model);
667 sel = gtk_tree_view_get_selection (overview);
668 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
669 g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change),
672 column = gtk_tree_view_column_new ();
673 gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column);
674 renderer = gtk_cell_renderer_text_new ();
675 gtk_tree_view_column_pack_start (column, renderer, TRUE);
676 gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME);
678 g_signal_connect (GTK_TREE_VIEW (overview),
679 "row-activated", G_CALLBACK (on_row_activate), view);
681 gtk_action_set_sensitive (copy_action, FALSE);
682 g_signal_connect_swapped (copy_action, "activate",
683 G_CALLBACK (on_copy), view);
684 g_signal_connect_swapped (select_all_action, "activate",
685 G_CALLBACK (on_select_all), view);
692 psppire_output_view_destroy (struct psppire_output_view *view)
699 g_signal_handlers_disconnect_by_func (view->toplevel,
700 G_CALLBACK (on_style_set), view);
702 string_map_destroy (&view->render_opts);
704 for (i = 0; i < view->n_items; i++)
705 output_item_unref (view->items[i].item);
708 view->n_items = view->allocated_items = 0;
710 if (view->print_settings != NULL)
711 g_object_unref (view->print_settings);
713 xr_driver_destroy (view->xr);
719 psppire_output_view_clear (struct psppire_output_view *view)
726 for (i = 0; i < view->n_items; i++)
728 gtk_container_remove (GTK_CONTAINER (view->output),
729 view->items[i].drawing_area);
730 output_item_unref (view->items[i].item);
734 view->n_items = view->allocated_items = 0;
740 psppire_output_view_export (struct psppire_output_view *view,
741 struct string_map *options)
743 struct output_driver *driver;
745 driver = output_driver_create (options);
750 for (i = 0; i < view->n_items; i++)
751 driver->class->submit (driver, view->items[i].item);
752 output_driver_destroy (driver);
759 get_cairo_context_from_print_context (GtkPrintContext *context)
761 cairo_t *cr = gtk_print_context_get_cairo_context (context);
764 For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
767 double xres = gtk_print_context_get_dpi_x (context);
768 double yres = gtk_print_context_get_dpi_y (context);
770 /* This means that the cairo context now has its dimensions in Points */
771 cairo_scale (cr, xres / 72.0, yres / 72.0);
778 create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
780 struct string_map options;
781 GtkPageSetup *page_setup;
782 double width, height;
786 double bottom_margin;
788 page_setup = gtk_print_context_get_page_setup (context);
789 width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
790 height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
791 left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
792 right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
793 top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
794 bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
796 string_map_init (&options);
797 string_map_insert_nocopy (&options, xstrdup ("paper-size"),
798 c_xasprintf("%.2fx%.2fmm", width, height));
799 string_map_insert_nocopy (&options, xstrdup ("left-margin"),
800 c_xasprintf ("%.2fmm", left_margin));
801 string_map_insert_nocopy (&options, xstrdup ("right-margin"),
802 c_xasprintf ("%.2fmm", right_margin));
803 string_map_insert_nocopy (&options, xstrdup ("top-margin"),
804 c_xasprintf ("%.2fmm", top_margin));
805 string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
806 c_xasprintf ("%.2fmm", bottom_margin));
808 view->print_xrd = xr_driver_create (get_cairo_context_from_print_context (context), &options);
810 string_map_destroy (&options);
814 paginate (GtkPrintOperation *operation,
815 GtkPrintContext *context,
816 struct psppire_output_view *view)
820 /* Sometimes GTK+ emits this signal again even after pagination is
821 complete. Don't let that screw up printing. */
824 else if ( view->print_item < view->n_items )
826 xr_driver_output_item (view->print_xrd,
827 view->items[view->print_item++].item);
828 while (xr_driver_need_new_page (view->print_xrd))
830 xr_driver_next_page (view->print_xrd, NULL);
831 view->print_n_pages ++;
837 gtk_print_operation_set_n_pages (operation, view->print_n_pages);
839 /* Re-create the driver to do the real printing. */
840 xr_driver_destroy (view->print_xrd);
841 create_xr_print_driver (context, view);
842 view->print_item = 0;
843 view->paginated = TRUE;
850 begin_print (GtkPrintOperation *operation,
851 GtkPrintContext *context,
852 struct psppire_output_view *view)
854 create_xr_print_driver (context, view);
856 view->print_item = 0;
857 view->print_n_pages = 1;
858 view->paginated = FALSE;
862 end_print (GtkPrintOperation *operation,
863 GtkPrintContext *context,
864 struct psppire_output_view *view)
866 xr_driver_destroy (view->print_xrd);
871 draw_page (GtkPrintOperation *operation,
872 GtkPrintContext *context,
874 struct psppire_output_view *view)
876 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
877 while (!xr_driver_need_new_page (view->print_xrd)
878 && view->print_item < view->n_items)
879 xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item);
884 psppire_output_view_print (struct psppire_output_view *view,
885 GtkWindow *parent_window)
887 GtkPrintOperationResult res;
889 GtkPrintOperation *print = gtk_print_operation_new ();
891 if (view->print_settings != NULL)
892 gtk_print_operation_set_print_settings (print, view->print_settings);
894 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
895 g_signal_connect (print, "end_print", G_CALLBACK (end_print), view);
896 g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);
897 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), view);
899 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
900 parent_window, NULL);
902 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
904 if (view->print_settings != NULL)
905 g_object_unref (view->print_settings);
906 view->print_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
909 g_object_unref (print);
912 struct psppire_output_view_driver
914 struct output_driver driver;
915 struct psppire_output_view *view;
918 static struct psppire_output_view_driver *
919 psppire_output_view_driver_cast (struct output_driver *driver)
921 return UP_CAST (driver, struct psppire_output_view_driver, driver);
925 psppire_output_view_submit (struct output_driver *this,
926 const struct output_item *item)
928 struct psppire_output_view_driver *povd = psppire_output_view_driver_cast (this);
930 if (is_table_item (item))
931 psppire_output_view_put (povd->view, item);
934 static struct output_driver_class psppire_output_view_driver_class =
936 "PSPPIRE Output View", /* name */
938 psppire_output_view_submit, /* submit */
943 psppire_output_view_register_driver (struct psppire_output_view *view)
945 struct psppire_output_view_driver *povd;
946 struct output_driver *d;
948 povd = xzalloc (sizeof *povd);
951 output_driver_init (d, &psppire_output_view_driver_class, "PSPPIRE Output View",
952 SETTINGS_DEVICE_UNFILTERED);
953 output_driver_register (d);