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 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 create_drawing_area (struct psppire_output_view *view,
193 GtkWidget *drawing_area, struct xr_rendering *r,
196 g_object_set_data_full (G_OBJECT (drawing_area),
197 "rendering", r, free_rendering);
199 g_signal_connect (drawing_area, "realize",
200 G_CALLBACK (on_dwgarea_realize), view);
201 g_signal_connect (drawing_area, "expose_event",
202 G_CALLBACK (expose_event_callback), view);
204 gtk_widget_set_size_request (drawing_area, tw, th);
205 gtk_layout_put (view->output, drawing_area, 0, view->y);
207 gtk_widget_show (drawing_area);
211 rerender (struct psppire_output_view *view)
213 struct output_view_item *item;
216 if (!view->n_items || !GTK_WIDGET (view->output)->window)
219 string_map_clear (&view->render_opts);
220 xr_driver_destroy (view->xr);
223 cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
227 for (item = view->items; item < &view->items[view->n_items]; item++)
229 struct xr_rendering *r;
233 view->y += view->font_height / 2;
235 r = xr_rendering_create (view->xr, item->item, cr);
238 g_warn_if_reached ();
242 xr_rendering_measure (r, &tw, &th);
244 if (!item->drawing_area)
246 item->drawing_area = gtk_drawing_area_new ();
247 create_drawing_area (view, item->drawing_area, r, tw, th);
251 g_object_set_data_full (G_OBJECT (item->drawing_area),
252 "rendering", r, free_rendering);
253 gtk_widget_set_size_request (item->drawing_area, tw, th);
254 gtk_layout_move (view->output, item->drawing_area, 0, view->y);
257 if (view->max_width < tw)
258 view->max_width = tw;
262 gtk_layout_set_size (view->output, view->max_width, view->y);
267 psppire_output_view_put (struct psppire_output_view *view,
268 const struct output_item *item)
270 struct output_view_item *view_item;
271 GtkWidget *drawing_area;
272 struct xr_rendering *r;
280 if (is_text_item (item))
282 const struct text_item *text_item = to_text_item (item);
283 enum text_item_type type = text_item_get_type (text_item);
284 const char *text = text_item_get_text (text_item);
286 if (type == TEXT_ITEM_COMMAND_CLOSE)
288 view->in_command = false;
291 else if (text[0] == '\0')
295 if (view->n_items >= view->allocated_items)
296 view->items = x2nrealloc (view->items, &view->allocated_items,
297 sizeof *view->items);
298 view_item = &view->items[view->n_items++];
299 view_item->item = output_item_ref (item);
300 view_item->drawing_area = NULL;
302 if (GTK_WIDGET (view->output)->window)
304 view_item->drawing_area = drawing_area = gtk_drawing_area_new ();
306 cr = gdk_cairo_create (GTK_WIDGET (view->output)->window);
307 if (view->xr == NULL)
311 view->y += view->font_height / 2;
313 r = xr_rendering_create (view->xr, item, cr);
317 xr_rendering_measure (r, &tw, &th);
319 create_drawing_area (view, drawing_area, r, tw, th);
325 && (!is_text_item (item)
326 || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
327 || !view->in_command))
329 store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview));
331 ds_init_empty (&name);
332 if (is_text_item (item)
333 && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
335 gtk_tree_store_append (store, &iter, NULL);
336 view->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
337 view->in_command = true;
341 GtkTreeIter *p = view->in_command ? &view->cur_command : NULL;
342 gtk_tree_store_append (store, &iter, p);
346 if (is_text_item (item))
347 ds_put_cstr (&name, text_item_get_text (to_text_item (item)));
348 else if (is_message_item (item))
350 const struct message_item *msg_item = to_message_item (item);
351 const struct msg *msg = message_item_get_msg (msg_item);
352 ds_put_format (&name, "%s: %s", _("Message"),
353 msg_severity_to_string (msg->severity));
355 else if (is_table_item (item))
357 const char *title = table_item_get_title (to_table_item (item));
359 ds_put_format (&name, "Table: %s", title);
361 ds_put_cstr (&name, "Table");
363 else if (is_chart_item (item))
365 const char *s = chart_item_get_title (to_chart_item (item));
367 ds_put_format (&name, "Chart: %s", s);
369 ds_put_cstr (&name, "Chart");
371 gtk_tree_store_set (store, &iter,
372 COL_NAME, ds_cstr (&name),
378 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
379 gtk_tree_view_expand_row (view->overview, path, TRUE);
380 gtk_tree_path_free (path);
383 if (view->max_width < tw)
384 view->max_width = tw;
387 gtk_layout_set_size (view->output, view->max_width, view->y);
394 on_row_activate (GtkTreeView *overview,
396 GtkTreeViewColumn *column,
397 struct psppire_output_view *view)
405 model = gtk_tree_view_get_model (overview);
406 if (!gtk_tree_model_get_iter (model, &iter, path))
409 gtk_tree_model_get_value (model, &iter, COL_Y, &value);
410 y = g_value_get_long (&value);
411 g_value_unset (&value);
413 vadj = gtk_layout_get_vadjustment (view->output);
415 max = vadj->upper - vadj->page_size;
420 gtk_adjustment_set_value (vadj, y);
424 copy_base_to_bg (GtkWidget *dest, GtkWidget *src)
427 for (i = 0; i < 5; ++i)
429 gtk_widget_modify_bg (dest, i, >k_widget_get_style (src)->base[i]);
430 gtk_widget_modify_fg (dest, i, >k_widget_get_style (src)->text[i]);
434 /* Copy the base style from the parent widget to the container and all its
435 children. We do this because the container's primary purpose is to display
436 text. This way psppire appears to follow the chosen gnome theme. */
438 on_style_set (GtkWidget *toplevel, GtkStyle *prev,
439 struct psppire_output_view *view)
441 copy_base_to_bg (GTK_WIDGET (view->output), toplevel);
442 gtk_container_foreach (GTK_CONTAINER (view->output),
443 (GtkCallback) copy_base_to_bg, view->output);
447 on_dwgarea_realize (GtkWidget *dwg_area, gpointer data)
449 copy_base_to_bg (dwg_area, gtk_widget_get_toplevel (dwg_area));
460 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
461 Temporary directory names are usually not that long. */
463 # define PATH_MAX 1024
467 clipboard_get_cb (GtkClipboard *clipboard,
468 GtkSelectionData *selection_data,
472 struct psppire_output_view *view = data;
476 struct output_driver *driver = NULL;
477 char dirname[PATH_MAX], *filename;
478 struct string_map options;
480 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
481 GtkTreeModel *model = gtk_tree_view_get_model (view->overview);
483 GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
489 if (path_search (dirname, sizeof dirname, NULL, NULL, true)
490 || mkdtemp (dirname) == NULL)
492 msg_error (errno, _("failed to create temporary directory during clipboard operation"));
495 filename = xasprintf ("%s/clip.tmp", dirname);
497 string_map_init (&options);
498 string_map_insert (&options, "output-file", filename);
502 case SELECT_FMT_UTF8:
503 string_map_insert (&options, "box", "unicode");
506 case SELECT_FMT_TEXT:
507 string_map_insert (&options, "format", "txt");
510 case SELECT_FMT_HTML:
511 string_map_insert (&options, "format", "html");
512 string_map_insert (&options, "borders", "false");
513 string_map_insert (&options, "css", "false");
517 string_map_insert (&options, "format", "odt");
521 g_warning ("unsupported clip target\n");
526 driver = output_driver_create (&options);
532 GtkTreePath *path = n->data ;
534 struct output_item *item ;
536 gtk_tree_model_get_iter (model, &iter, path);
537 gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
539 driver->class->submit (driver, item);
544 if ( driver->class->flush)
545 driver->class->flush (driver);
548 /* Some drivers (eg: the odt one) don't write anything until they
550 output_driver_destroy (driver);
553 if ( g_file_get_contents (filename, &text, &length, NULL) )
555 gtk_selection_data_set (selection_data, selection_data->target,
557 (const guchar *) text, length);
563 output_driver_destroy (driver);
575 clipboard_clear_cb (GtkClipboard *clipboard,
580 static const GtkTargetEntry targets[] = {
582 { "STRING", 0, SELECT_FMT_TEXT },
583 { "TEXT", 0, SELECT_FMT_TEXT },
584 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
585 { "text/plain", 0, SELECT_FMT_TEXT },
587 { "UTF8_STRING", 0, SELECT_FMT_UTF8 },
588 { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
590 { "text/html", 0, SELECT_FMT_HTML },
592 { "application/vnd.oasis.opendocument.text", 0, SELECT_FMT_ODT }
596 on_copy (struct psppire_output_view *view)
598 GtkWidget *widget = GTK_WIDGET (view->overview);
599 GtkClipboard *cb = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
601 if (!gtk_clipboard_set_with_data (cb, targets, G_N_ELEMENTS (targets),
602 clipboard_get_cb, clipboard_clear_cb,
604 clipboard_clear_cb (cb, view);
608 on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
610 /* The Copy action is available only if there is something selected */
611 gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
615 on_select_all (struct psppire_output_view *view)
617 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
618 gtk_tree_view_expand_all (view->overview);
619 gtk_tree_selection_select_all (sel);
623 on_size_allocate (GtkWidget *widget,
624 GdkRectangle *allocation,
625 struct psppire_output_view *view)
627 int new_render_width = MAX (300, allocation->width);
628 if (view->render_width != new_render_width)
630 view->render_width = new_render_width;
635 struct psppire_output_view *
636 psppire_output_view_new (GtkLayout *output, GtkTreeView *overview,
637 GtkAction *copy_action, GtkAction *select_all_action)
639 struct psppire_output_view *view;
640 GtkTreeViewColumn *column;
641 GtkCellRenderer *renderer;
642 GtkTreeSelection *sel;
645 view = xmalloc (sizeof *view);
647 view->font_height = 0;
648 view->output = output;
649 view->render_width = 0;
652 string_map_init (&view->render_opts);
653 view->overview = overview;
654 memset (&view->cur_command, 0, sizeof view->cur_command);
655 view->in_command = false;
656 view->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output));
658 view->n_items = view->allocated_items = 0;
659 view->print_settings = NULL;
660 view->print_xrd = NULL;
661 view->print_item = 0;
662 view->print_n_pages = 0;
663 view->paginated = FALSE;
665 g_signal_connect (view->toplevel, "style-set", G_CALLBACK (on_style_set), view);
667 g_signal_connect (output, "size-allocate", G_CALLBACK (on_size_allocate), view);
671 model = GTK_TREE_MODEL (gtk_tree_store_new (
673 G_TYPE_STRING, /* COL_NAME */
674 G_TYPE_POINTER, /* COL_ADDR */
675 G_TYPE_LONG)); /* COL_Y */
676 gtk_tree_view_set_model (overview, model);
677 g_object_unref (model);
679 sel = gtk_tree_view_get_selection (overview);
680 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
681 g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change),
684 column = gtk_tree_view_column_new ();
685 gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column);
686 renderer = gtk_cell_renderer_text_new ();
687 gtk_tree_view_column_pack_start (column, renderer, TRUE);
688 gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME);
690 g_signal_connect (GTK_TREE_VIEW (overview),
691 "row-activated", G_CALLBACK (on_row_activate), view);
693 gtk_action_set_sensitive (copy_action, FALSE);
694 g_signal_connect_swapped (copy_action, "activate",
695 G_CALLBACK (on_copy), view);
696 g_signal_connect_swapped (select_all_action, "activate",
697 G_CALLBACK (on_select_all), view);
704 psppire_output_view_destroy (struct psppire_output_view *view)
711 g_signal_handlers_disconnect_by_func (view->toplevel,
712 G_CALLBACK (on_style_set), view);
714 string_map_destroy (&view->render_opts);
716 for (i = 0; i < view->n_items; i++)
717 output_item_unref (view->items[i].item);
720 view->n_items = view->allocated_items = 0;
722 if (view->print_settings != NULL)
723 g_object_unref (view->print_settings);
725 xr_driver_destroy (view->xr);
731 psppire_output_view_clear (struct psppire_output_view *view)
738 for (i = 0; i < view->n_items; i++)
740 gtk_container_remove (GTK_CONTAINER (view->output),
741 view->items[i].drawing_area);
742 output_item_unref (view->items[i].item);
746 view->n_items = view->allocated_items = 0;
752 psppire_output_view_export (struct psppire_output_view *view,
753 struct string_map *options)
755 struct output_driver *driver;
757 driver = output_driver_create (options);
762 for (i = 0; i < view->n_items; i++)
763 driver->class->submit (driver, view->items[i].item);
764 output_driver_destroy (driver);
771 get_cairo_context_from_print_context (GtkPrintContext *context)
773 cairo_t *cr = gtk_print_context_get_cairo_context (context);
776 For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
779 double xres = gtk_print_context_get_dpi_x (context);
780 double yres = gtk_print_context_get_dpi_y (context);
782 /* This means that the cairo context now has its dimensions in Points */
783 cairo_scale (cr, xres / 72.0, yres / 72.0);
790 create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
792 struct string_map options;
793 GtkPageSetup *page_setup;
794 double width, height;
798 double bottom_margin;
800 page_setup = gtk_print_context_get_page_setup (context);
801 width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
802 height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
803 left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
804 right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
805 top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
806 bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
808 string_map_init (&options);
809 string_map_insert_nocopy (&options, xstrdup ("paper-size"),
810 c_xasprintf("%.2fx%.2fmm", width, height));
811 string_map_insert_nocopy (&options, xstrdup ("left-margin"),
812 c_xasprintf ("%.2fmm", left_margin));
813 string_map_insert_nocopy (&options, xstrdup ("right-margin"),
814 c_xasprintf ("%.2fmm", right_margin));
815 string_map_insert_nocopy (&options, xstrdup ("top-margin"),
816 c_xasprintf ("%.2fmm", top_margin));
817 string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
818 c_xasprintf ("%.2fmm", bottom_margin));
820 view->print_xrd = xr_driver_create (get_cairo_context_from_print_context (context), &options);
822 string_map_destroy (&options);
826 paginate (GtkPrintOperation *operation,
827 GtkPrintContext *context,
828 struct psppire_output_view *view)
832 /* Sometimes GTK+ emits this signal again even after pagination is
833 complete. Don't let that screw up printing. */
836 else if ( view->print_item < view->n_items )
838 xr_driver_output_item (view->print_xrd,
839 view->items[view->print_item++].item);
840 while (xr_driver_need_new_page (view->print_xrd))
842 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
843 view->print_n_pages ++;
849 gtk_print_operation_set_n_pages (operation, view->print_n_pages);
851 /* Re-create the driver to do the real printing. */
852 xr_driver_destroy (view->print_xrd);
853 create_xr_print_driver (context, view);
854 view->print_item = 0;
855 view->paginated = TRUE;
862 begin_print (GtkPrintOperation *operation,
863 GtkPrintContext *context,
864 struct psppire_output_view *view)
866 create_xr_print_driver (context, view);
868 view->print_item = 0;
869 view->print_n_pages = 1;
870 view->paginated = FALSE;
874 end_print (GtkPrintOperation *operation,
875 GtkPrintContext *context,
876 struct psppire_output_view *view)
878 xr_driver_destroy (view->print_xrd);
883 draw_page (GtkPrintOperation *operation,
884 GtkPrintContext *context,
886 struct psppire_output_view *view)
888 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
889 while (!xr_driver_need_new_page (view->print_xrd)
890 && view->print_item < view->n_items)
891 xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item);
896 psppire_output_view_print (struct psppire_output_view *view,
897 GtkWindow *parent_window)
899 GtkPrintOperationResult res;
901 GtkPrintOperation *print = gtk_print_operation_new ();
903 if (view->print_settings != NULL)
904 gtk_print_operation_set_print_settings (print, view->print_settings);
906 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
907 g_signal_connect (print, "end_print", G_CALLBACK (end_print), view);
908 g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);
909 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), view);
911 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
912 parent_window, NULL);
914 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
916 if (view->print_settings != NULL)
917 g_object_unref (view->print_settings);
918 view->print_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
921 g_object_unref (print);
924 struct psppire_output_view_driver
926 struct output_driver driver;
927 struct psppire_output_view *view;
930 static struct psppire_output_view_driver *
931 psppire_output_view_driver_cast (struct output_driver *driver)
933 return UP_CAST (driver, struct psppire_output_view_driver, driver);
937 psppire_output_view_submit (struct output_driver *this,
938 const struct output_item *item)
940 struct psppire_output_view_driver *povd = psppire_output_view_driver_cast (this);
942 if (is_table_item (item))
943 psppire_output_view_put (povd->view, item);
946 static struct output_driver_class psppire_output_view_driver_class =
948 "PSPPIRE Output View", /* name */
950 psppire_output_view_submit, /* submit */
955 psppire_output_view_register_driver (struct psppire_output_view *view)
957 struct psppire_output_view_driver *povd;
958 struct output_driver *d;
960 povd = xzalloc (sizeof *povd);
963 output_driver_init (d, &psppire_output_view_driver_class, "PSPPIRE Output View",
964 SETTINGS_DEVICE_UNFILTERED);
965 output_driver_register (d);