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;
231 view->y += view->font_height / 2;
233 r = xr_rendering_create (view->xr, item->item, cr);
236 g_warn_if_reached ();
240 xr_rendering_measure (r, &tw, &th);
242 if (!item->drawing_area)
244 item->drawing_area = gtk_drawing_area_new ();
245 create_drawing_area (view, item->drawing_area, r, tw, th);
249 g_object_set_data_full (G_OBJECT (item->drawing_area),
250 "rendering", r, free_rendering);
251 gtk_widget_set_size_request (item->drawing_area, tw, th);
252 gtk_layout_move (view->output, item->drawing_area, 0, view->y);
259 gtk_widget_size_allocate(item->drawing_area,&alloc);
261 if (view->max_width < tw)
262 view->max_width = tw;
266 gtk_layout_set_size (view->output, view->max_width, view->y);
271 psppire_output_view_put (struct psppire_output_view *view,
272 const struct output_item *item)
274 struct output_view_item *view_item;
275 GtkWidget *drawing_area;
276 struct xr_rendering *r;
284 if (is_text_item (item))
286 const struct text_item *text_item = to_text_item (item);
287 enum text_item_type type = text_item_get_type (text_item);
288 const char *text = text_item_get_text (text_item);
290 if (type == TEXT_ITEM_COMMAND_CLOSE)
292 view->in_command = false;
295 else if (text[0] == '\0')
299 if (view->n_items >= view->allocated_items)
300 view->items = x2nrealloc (view->items, &view->allocated_items,
301 sizeof *view->items);
302 view_item = &view->items[view->n_items++];
303 view_item->item = output_item_ref (item);
304 view_item->drawing_area = NULL;
306 if (gtk_widget_get_window (GTK_WIDGET (view->output)))
308 view_item->drawing_area = drawing_area = gtk_drawing_area_new ();
310 cr = gdk_cairo_create (gtk_widget_get_window (GTK_WIDGET (view->output)));
311 if (view->xr == NULL)
315 view->y += view->font_height / 2;
317 r = xr_rendering_create (view->xr, item, cr);
321 xr_rendering_measure (r, &tw, &th);
323 create_drawing_area (view, drawing_area, r, tw, th);
329 && (!is_text_item (item)
330 || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
331 || !view->in_command))
333 store = GTK_TREE_STORE (gtk_tree_view_get_model (view->overview));
335 ds_init_empty (&name);
336 if (is_text_item (item)
337 && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
339 gtk_tree_store_append (store, &iter, NULL);
340 view->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
341 view->in_command = true;
345 GtkTreeIter *p = view->in_command ? &view->cur_command : NULL;
346 gtk_tree_store_append (store, &iter, p);
350 if (is_text_item (item))
351 ds_put_cstr (&name, text_item_get_text (to_text_item (item)));
352 else if (is_message_item (item))
354 const struct message_item *msg_item = to_message_item (item);
355 const struct msg *msg = message_item_get_msg (msg_item);
356 ds_put_format (&name, "%s: %s", _("Message"),
357 msg_severity_to_string (msg->severity));
359 else if (is_table_item (item))
361 const char *title = table_item_get_title (to_table_item (item));
363 ds_put_format (&name, "Table: %s", title);
365 ds_put_cstr (&name, "Table");
367 else if (is_chart_item (item))
369 const char *s = chart_item_get_title (to_chart_item (item));
371 ds_put_format (&name, "Chart: %s", s);
373 ds_put_cstr (&name, "Chart");
375 gtk_tree_store_set (store, &iter,
376 COL_NAME, ds_cstr (&name),
378 COL_Y, (glong)(view->y),
382 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
383 gtk_tree_view_expand_row (view->overview, path, TRUE);
384 gtk_tree_path_free (path);
387 if (view->max_width < tw)
388 view->max_width = tw;
391 gtk_layout_set_size (view->output, view->max_width, view->y);
398 on_row_activate (GtkTreeView *overview,
400 GtkTreeViewColumn *column,
401 struct psppire_output_view *view)
409 model = gtk_tree_view_get_model (overview);
410 if (!gtk_tree_model_get_iter (model, &iter, path))
413 gtk_tree_model_get_value (model, &iter, COL_Y, &value);
414 y = g_value_get_long (&value);
415 g_value_unset (&value);
417 vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (view->output));
418 min = gtk_adjustment_get_lower (vadj);
419 max = gtk_adjustment_get_upper (vadj) - gtk_adjustment_get_page_size (vadj);
424 gtk_adjustment_set_value (vadj, y);
428 copy_base_to_bg (GtkWidget *dest, GtkWidget *src)
431 for (i = 0; i < 5; ++i)
433 gtk_widget_modify_bg (dest, i, >k_widget_get_style (src)->base[i]);
434 gtk_widget_modify_fg (dest, i, >k_widget_get_style (src)->text[i]);
438 /* Copy the base style from the parent widget to the container and all its
439 children. We do this because the container's primary purpose is to display
440 text. This way psppire appears to follow the chosen gnome theme. */
442 on_style_set (GtkWidget *toplevel, GtkStyle *prev,
443 struct psppire_output_view *view)
445 copy_base_to_bg (GTK_WIDGET (view->output), toplevel);
446 gtk_container_foreach (GTK_CONTAINER (view->output),
447 (GtkCallback) copy_base_to_bg, view->output);
451 on_dwgarea_realize (GtkWidget *dwg_area, gpointer data)
453 copy_base_to_bg (dwg_area, gtk_widget_get_toplevel (dwg_area));
464 /* GNU Hurd doesn't have PATH_MAX. Use a fallback.
465 Temporary directory names are usually not that long. */
467 # define PATH_MAX 1024
471 clipboard_get_cb (GtkClipboard *clipboard,
472 GtkSelectionData *selection_data,
476 struct psppire_output_view *view = data;
480 struct output_driver *driver = NULL;
481 char dirname[PATH_MAX], *filename;
482 struct string_map options;
484 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
485 GtkTreeModel *model = gtk_tree_view_get_model (view->overview);
487 GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
493 if (path_search (dirname, sizeof dirname, NULL, NULL, true)
494 || mkdtemp (dirname) == NULL)
496 msg_error (errno, _("failed to create temporary directory during clipboard operation"));
499 filename = xasprintf ("%s/clip.tmp", dirname);
501 string_map_init (&options);
502 string_map_insert (&options, "output-file", filename);
506 case SELECT_FMT_UTF8:
507 string_map_insert (&options, "box", "unicode");
510 case SELECT_FMT_TEXT:
511 string_map_insert (&options, "format", "txt");
514 case SELECT_FMT_HTML:
515 string_map_insert (&options, "format", "html");
516 string_map_insert (&options, "borders", "false");
517 string_map_insert (&options, "css", "false");
521 string_map_insert (&options, "format", "odt");
525 g_warning ("unsupported clip target\n");
530 driver = output_driver_create (&options);
536 GtkTreePath *path = n->data ;
538 struct output_item *item ;
540 gtk_tree_model_get_iter (model, &iter, path);
541 gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
543 driver->class->submit (driver, item);
548 if ( driver->class->flush)
549 driver->class->flush (driver);
552 /* Some drivers (eg: the odt one) don't write anything until they
554 output_driver_destroy (driver);
557 if ( g_file_get_contents (filename, &text, &length, NULL) )
559 gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
561 (const guchar *) text, length);
567 output_driver_destroy (driver);
579 clipboard_clear_cb (GtkClipboard *clipboard,
584 static const GtkTargetEntry targets[] = {
586 { "STRING", 0, SELECT_FMT_TEXT },
587 { "TEXT", 0, SELECT_FMT_TEXT },
588 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
589 { "text/plain", 0, SELECT_FMT_TEXT },
591 { "UTF8_STRING", 0, SELECT_FMT_UTF8 },
592 { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
594 { "text/html", 0, SELECT_FMT_HTML },
596 { "application/vnd.oasis.opendocument.text", 0, SELECT_FMT_ODT }
600 on_copy (struct psppire_output_view *view)
602 GtkWidget *widget = GTK_WIDGET (view->overview);
603 GtkClipboard *cb = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD);
605 if (!gtk_clipboard_set_with_data (cb, targets, G_N_ELEMENTS (targets),
606 clipboard_get_cb, clipboard_clear_cb,
608 clipboard_clear_cb (cb, view);
612 on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
614 /* The Copy action is available only if there is something selected */
615 gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
619 on_select_all (struct psppire_output_view *view)
621 GtkTreeSelection *sel = gtk_tree_view_get_selection (view->overview);
622 gtk_tree_view_expand_all (view->overview);
623 gtk_tree_selection_select_all (sel);
627 on_size_allocate (GtkWidget *widget,
628 GdkRectangle *allocation,
629 struct psppire_output_view *view)
631 int new_render_width = MAX (300, allocation->width);
632 if (view->render_width != new_render_width)
634 view->render_width = new_render_width;
639 struct psppire_output_view *
640 psppire_output_view_new (GtkLayout *output, GtkTreeView *overview,
641 GtkAction *copy_action, GtkAction *select_all_action)
643 struct psppire_output_view *view;
644 GtkTreeViewColumn *column;
645 GtkCellRenderer *renderer;
646 GtkTreeSelection *sel;
649 view = xmalloc (sizeof *view);
651 view->font_height = 0;
652 view->output = output;
653 view->render_width = 0;
656 string_map_init (&view->render_opts);
657 view->overview = overview;
658 memset (&view->cur_command, 0, sizeof view->cur_command);
659 view->in_command = false;
660 view->toplevel = gtk_widget_get_toplevel (GTK_WIDGET (output));
662 view->n_items = view->allocated_items = 0;
663 view->print_settings = NULL;
664 view->print_xrd = NULL;
665 view->print_item = 0;
666 view->print_n_pages = 0;
667 view->paginated = FALSE;
669 g_signal_connect (view->toplevel, "style-set", G_CALLBACK (on_style_set), view);
671 g_signal_connect (output, "size-allocate", G_CALLBACK (on_size_allocate), view);
675 model = GTK_TREE_MODEL (gtk_tree_store_new (
677 G_TYPE_STRING, /* COL_NAME */
678 G_TYPE_POINTER, /* COL_ADDR */
679 G_TYPE_LONG)); /* COL_Y */
680 gtk_tree_view_set_model (overview, model);
681 g_object_unref (model);
683 sel = gtk_tree_view_get_selection (overview);
684 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
685 g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change),
688 column = gtk_tree_view_column_new ();
689 gtk_tree_view_append_column (GTK_TREE_VIEW (overview), column);
690 renderer = gtk_cell_renderer_text_new ();
691 gtk_tree_view_column_pack_start (column, renderer, TRUE);
692 gtk_tree_view_column_add_attribute (column, renderer, "text", COL_NAME);
694 g_signal_connect (GTK_TREE_VIEW (overview),
695 "row-activated", G_CALLBACK (on_row_activate), view);
697 gtk_action_set_sensitive (copy_action, FALSE);
698 g_signal_connect_swapped (copy_action, "activate",
699 G_CALLBACK (on_copy), view);
700 g_signal_connect_swapped (select_all_action, "activate",
701 G_CALLBACK (on_select_all), view);
708 psppire_output_view_destroy (struct psppire_output_view *view)
715 g_signal_handlers_disconnect_by_func (view->toplevel,
716 G_CALLBACK (on_style_set), view);
718 string_map_destroy (&view->render_opts);
720 for (i = 0; i < view->n_items; i++)
721 output_item_unref (view->items[i].item);
724 view->n_items = view->allocated_items = 0;
726 if (view->print_settings != NULL)
727 g_object_unref (view->print_settings);
729 xr_driver_destroy (view->xr);
735 psppire_output_view_clear (struct psppire_output_view *view)
742 for (i = 0; i < view->n_items; i++)
744 gtk_container_remove (GTK_CONTAINER (view->output),
745 view->items[i].drawing_area);
746 output_item_unref (view->items[i].item);
750 view->n_items = view->allocated_items = 0;
756 psppire_output_view_export (struct psppire_output_view *view,
757 struct string_map *options)
759 struct output_driver *driver;
761 driver = output_driver_create (options);
766 for (i = 0; i < view->n_items; i++)
767 driver->class->submit (driver, view->items[i].item);
768 output_driver_destroy (driver);
775 get_cairo_context_from_print_context (GtkPrintContext *context)
777 cairo_t *cr = gtk_print_context_get_cairo_context (context);
780 For all platforms except windows, gtk_print_context_get_dpi_[xy] returns 72.
783 double xres = gtk_print_context_get_dpi_x (context);
784 double yres = gtk_print_context_get_dpi_y (context);
786 /* This means that the cairo context now has its dimensions in Points */
787 cairo_scale (cr, xres / 72.0, yres / 72.0);
794 create_xr_print_driver (GtkPrintContext *context, struct psppire_output_view *view)
796 struct string_map options;
797 GtkPageSetup *page_setup;
798 double width, height;
802 double bottom_margin;
804 page_setup = gtk_print_context_get_page_setup (context);
805 width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
806 height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
807 left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
808 right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
809 top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
810 bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
812 string_map_init (&options);
813 string_map_insert_nocopy (&options, xstrdup ("paper-size"),
814 c_xasprintf("%.2fx%.2fmm", width, height));
815 string_map_insert_nocopy (&options, xstrdup ("left-margin"),
816 c_xasprintf ("%.2fmm", left_margin));
817 string_map_insert_nocopy (&options, xstrdup ("right-margin"),
818 c_xasprintf ("%.2fmm", right_margin));
819 string_map_insert_nocopy (&options, xstrdup ("top-margin"),
820 c_xasprintf ("%.2fmm", top_margin));
821 string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
822 c_xasprintf ("%.2fmm", bottom_margin));
824 view->print_xrd = xr_driver_create (get_cairo_context_from_print_context (context), &options);
826 string_map_destroy (&options);
830 paginate (GtkPrintOperation *operation,
831 GtkPrintContext *context,
832 struct psppire_output_view *view)
836 /* Sometimes GTK+ emits this signal again even after pagination is
837 complete. Don't let that screw up printing. */
840 else if ( view->print_item < view->n_items )
842 xr_driver_output_item (view->print_xrd,
843 view->items[view->print_item++].item);
844 while (xr_driver_need_new_page (view->print_xrd))
846 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
847 view->print_n_pages ++;
853 gtk_print_operation_set_n_pages (operation, view->print_n_pages);
855 /* Re-create the driver to do the real printing. */
856 xr_driver_destroy (view->print_xrd);
857 create_xr_print_driver (context, view);
858 view->print_item = 0;
859 view->paginated = TRUE;
866 begin_print (GtkPrintOperation *operation,
867 GtkPrintContext *context,
868 struct psppire_output_view *view)
870 create_xr_print_driver (context, view);
872 view->print_item = 0;
873 view->print_n_pages = 1;
874 view->paginated = FALSE;
878 end_print (GtkPrintOperation *operation,
879 GtkPrintContext *context,
880 struct psppire_output_view *view)
882 xr_driver_destroy (view->print_xrd);
887 draw_page (GtkPrintOperation *operation,
888 GtkPrintContext *context,
890 struct psppire_output_view *view)
892 xr_driver_next_page (view->print_xrd, get_cairo_context_from_print_context (context));
893 while (!xr_driver_need_new_page (view->print_xrd)
894 && view->print_item < view->n_items)
895 xr_driver_output_item (view->print_xrd, view->items [view->print_item++].item);
900 psppire_output_view_print (struct psppire_output_view *view,
901 GtkWindow *parent_window)
903 GtkPrintOperationResult res;
905 GtkPrintOperation *print = gtk_print_operation_new ();
907 if (view->print_settings != NULL)
908 gtk_print_operation_set_print_settings (print, view->print_settings);
910 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), view);
911 g_signal_connect (print, "end_print", G_CALLBACK (end_print), view);
912 g_signal_connect (print, "paginate", G_CALLBACK (paginate), view);
913 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), view);
915 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
916 parent_window, NULL);
918 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
920 if (view->print_settings != NULL)
921 g_object_unref (view->print_settings);
922 view->print_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
925 g_object_unref (print);
928 struct psppire_output_view_driver
930 struct output_driver driver;
931 struct psppire_output_view *view;
934 static struct psppire_output_view_driver *
935 psppire_output_view_driver_cast (struct output_driver *driver)
937 return UP_CAST (driver, struct psppire_output_view_driver, driver);
941 psppire_output_view_submit (struct output_driver *this,
942 const struct output_item *item)
944 struct psppire_output_view_driver *povd = psppire_output_view_driver_cast (this);
946 if (is_table_item (item))
947 psppire_output_view_put (povd->view, item);
950 static struct output_driver_class psppire_output_view_driver_class =
952 "PSPPIRE Output View", /* name */
954 psppire_output_view_submit, /* submit */
959 psppire_output_view_register_driver (struct psppire_output_view *view)
961 struct psppire_output_view_driver *povd;
962 struct output_driver *d;
964 povd = xzalloc (sizeof *povd);
967 output_driver_init (d, &psppire_output_view_driver_class, "PSPPIRE Output View",
968 SETTINGS_DEVICE_UNFILTERED);
969 output_driver_register (d);