1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008, 2009, 2010, 2011 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/>. */
23 #include <sys/types.h>
26 #include "libpspp/cast.h"
27 #include "libpspp/message.h"
28 #include "libpspp/string-map.h"
29 #include "output/cairo.h"
30 #include "output/chart-item.h"
31 #include "output/driver-provider.h"
32 #include "output/message-item.h"
33 #include "output/output-item.h"
34 #include "output/tab.h"
35 #include "output/table-item.h"
36 #include "output/text-item.h"
37 #include "ui/gui/help-menu.h"
38 #include "ui/gui/helper.h"
39 #include "ui/gui/psppire-output-window.h"
42 #include "gl/tmpdir.h"
43 #include "gl/xalloc.h"
46 #define _(msgid) gettext (msgid)
47 #define N_(msgid) msgid
51 COL_TITLE, /* Table title. */
52 COL_ADDR, /* Pointer to the table */
53 COL_Y, /* Y position of top of title. */
57 static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer);
58 static void psppire_output_window_base_init (PsppireOutputWindowClass *class);
59 static void psppire_output_window_class_init (PsppireOutputWindowClass *class);
60 static void psppire_output_window_init (PsppireOutputWindow *window);
62 static void psppire_output_window_style_set (GtkWidget *window, GtkStyle *prev);
66 psppire_output_window_get_type (void)
68 static GType psppire_output_window_type = 0;
70 if (!psppire_output_window_type)
72 static const GTypeInfo psppire_output_window_info =
74 sizeof (PsppireOutputWindowClass),
75 (GBaseInitFunc) psppire_output_window_base_init,
76 (GBaseFinalizeFunc) psppire_output_window_base_finalize,
77 (GClassInitFunc)psppire_output_window_class_init,
78 (GClassFinalizeFunc) NULL,
80 sizeof (PsppireOutputWindow),
82 (GInstanceInitFunc) psppire_output_window_init,
85 psppire_output_window_type =
86 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireOutputWindow",
87 &psppire_output_window_info, 0);
90 return psppire_output_window_type;
93 static GObjectClass *parent_class;
96 psppire_output_window_finalize (GObject *object)
98 if (G_OBJECT_CLASS (parent_class)->finalize)
99 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
104 psppire_output_window_dispose (GObject *obj)
106 PsppireOutputWindow *viewer = PSPPIRE_OUTPUT_WINDOW (obj);
109 for (i = 0; i < viewer->n_items; i++)
110 output_item_unref (viewer->items[i]);
111 free (viewer->items);
112 viewer->items = NULL;
113 viewer->n_items = viewer->allocated_items = 0;
115 if (viewer->print_settings != NULL)
116 g_object_unref (viewer->print_settings);
118 /* Chain up to the parent class */
119 G_OBJECT_CLASS (parent_class)->dispose (obj);
123 psppire_output_window_class_init (PsppireOutputWindowClass *class)
125 GObjectClass *object_class = G_OBJECT_CLASS (class);
127 parent_class = g_type_class_peek_parent (class);
128 object_class->dispose = psppire_output_window_dispose;
130 GTK_WIDGET_CLASS (object_class)->style_set = psppire_output_window_style_set;
135 psppire_output_window_base_init (PsppireOutputWindowClass *class)
137 GObjectClass *object_class = G_OBJECT_CLASS (class);
139 object_class->finalize = psppire_output_window_finalize;
145 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
150 /* Output driver class. */
152 struct psppire_output_driver
154 struct output_driver driver;
155 PsppireOutputWindow *viewer;
156 struct xr_driver *xr;
160 static struct output_driver_class psppire_output_class;
162 static struct psppire_output_driver *
163 psppire_output_cast (struct output_driver *driver)
165 assert (driver->class == &psppire_output_class);
166 return UP_CAST (driver, struct psppire_output_driver, driver);
169 static void on_dwgarea_realize (GtkWidget *widget, gpointer data);
172 expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
174 struct xr_rendering *r = g_object_get_data (G_OBJECT (widget), "rendering");
175 cairo_t *cr = gdk_cairo_create (widget->window);
177 xr_rendering_draw (r, cr, event->area.x, event->area.y,
178 event->area.width, event->area.height);
185 psppire_output_submit (struct output_driver *this,
186 const struct output_item *item)
188 struct psppire_output_driver *pod = psppire_output_cast (this);
189 PsppireOutputWindow *viewer;
190 GtkWidget *drawing_area;
191 struct xr_rendering *r;
199 if (pod->viewer == NULL)
201 pod->viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
202 gtk_widget_show_all (GTK_WIDGET (pod->viewer));
203 pod->viewer->driver = pod;
205 viewer = pod->viewer;
207 if (viewer->n_items >= viewer->allocated_items)
208 viewer->items = x2nrealloc (viewer->items, &viewer->allocated_items,
209 sizeof *viewer->items);
210 viewer->items[viewer->n_items++] = output_item_ref (item);
212 if (is_text_item (item))
214 const struct text_item *text_item = to_text_item (item);
215 enum text_item_type type = text_item_get_type (text_item);
216 const char *text = text_item_get_text (text_item);
218 if (type == TEXT_ITEM_COMMAND_CLOSE)
220 viewer->in_command = false;
223 else if (text[0] == '\0')
227 cr = gdk_cairo_create (GTK_WIDGET (pod->viewer)->window);
230 const GtkStyle *style = gtk_widget_get_style (GTK_WIDGET (viewer));
231 struct string_map options = STRING_MAP_INITIALIZER (options);
232 struct text_item *text_item;
233 PangoFontDescription *font_desc;
237 /* Set the widget's text color as the foreground color for the output driver */
238 gchar *fgc = gdk_color_to_string (&style->text[gtk_widget_get_state (GTK_WIDGET (viewer))]);
239 string_map_insert (&options, "foreground-color", fgc);
242 /* Use GTK+ default font as proportional font. */
243 font_name = pango_font_description_to_string (style->font_desc);
244 string_map_insert (&options, "prop-font", font_name);
247 /* Derived emphasized font from proportional font. */
248 font_desc = pango_font_description_copy (style->font_desc);
249 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
250 font_name = pango_font_description_to_string (font_desc);
251 string_map_insert (&options, "emph-font", font_name);
253 pango_font_description_free (font_desc);
255 /* Pretend that the "page" has a reasonable width and a very big length,
256 so that most tables can be conveniently viewed on-screen with vertical
257 scrolling only. (The length should not be increased very much because
258 it is already close enough to INT_MAX when expressed as thousands of a
260 string_map_insert (&options, "paper-size", "300x200000mm");
261 string_map_insert (&options, "left-margin", "0");
262 string_map_insert (&options, "right-margin", "0");
263 string_map_insert (&options, "top-margin", "0");
264 string_map_insert (&options, "bottom-margin", "0");
266 pod->xr = xr_driver_create (cr, &options);
268 string_map_destroy (&options);
270 text_item = text_item_create (TEXT_ITEM_PARAGRAPH, "X");
271 r = xr_rendering_create (pod->xr, text_item_super (text_item), cr);
272 xr_rendering_measure (r, &font_width, &pod->font_height);
273 /* xr_rendering_destroy (r); */
274 text_item_unref (text_item);
277 pod->viewer->y += pod->font_height / 2;
279 r = xr_rendering_create (pod->xr, item, cr);
283 xr_rendering_measure (r, &tw, &th);
285 drawing_area = gtk_drawing_area_new ();
287 g_object_set_data (G_OBJECT (drawing_area), "rendering", r);
288 g_signal_connect (drawing_area, "realize",
289 G_CALLBACK (on_dwgarea_realize), pod->viewer);
291 g_signal_connect (drawing_area, "expose_event",
292 G_CALLBACK (expose_event_callback), NULL);
294 gtk_widget_set_size_request (drawing_area, tw, th);
295 gtk_layout_put (pod->viewer->output, drawing_area, 0, pod->viewer->y);
297 gtk_widget_show (drawing_area);
299 if (!is_text_item (item)
300 || text_item_get_type (to_text_item (item)) != TEXT_ITEM_SYNTAX
301 || !viewer->in_command)
303 store = GTK_TREE_STORE (gtk_tree_view_get_model (viewer->overview));
305 ds_init_empty (&title);
306 if (is_text_item (item)
307 && text_item_get_type (to_text_item (item)) == TEXT_ITEM_COMMAND_OPEN)
309 gtk_tree_store_append (store, &iter, NULL);
310 viewer->cur_command = iter; /* XXX shouldn't save a GtkTreeIter */
311 viewer->in_command = true;
315 GtkTreeIter *p = viewer->in_command ? &viewer->cur_command : NULL;
316 gtk_tree_store_append (store, &iter, p);
320 if (is_text_item (item))
321 ds_put_cstr (&title, text_item_get_text (to_text_item (item)));
322 else if (is_message_item (item))
324 const struct message_item *msg_item = to_message_item (item);
325 const struct msg *msg = message_item_get_msg (msg_item);
326 ds_put_format (&title, "%s: %s", _("Message"),
327 msg_severity_to_string (msg->severity));
329 else if (is_table_item (item))
331 const char *caption = table_item_get_caption (to_table_item (item));
333 ds_put_format (&title, "Table: %s", caption);
335 ds_put_cstr (&title, "Table");
337 else if (is_chart_item (item))
339 const char *s = chart_item_get_title (to_chart_item (item));
341 ds_put_format (&title, "Chart: %s", s);
343 ds_put_cstr (&title, "Chart");
345 gtk_tree_store_set (store, &iter,
346 COL_TITLE, ds_cstr (&title),
352 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
353 gtk_tree_view_expand_row (viewer->overview, path, TRUE);
354 gtk_tree_path_free (path);
357 if (pod->viewer->max_width < tw)
358 pod->viewer->max_width = tw;
359 pod->viewer->y += th;
361 gtk_layout_set_size (pod->viewer->output,
362 pod->viewer->max_width, pod->viewer->y);
364 gtk_window_set_urgency_hint (GTK_WINDOW (pod->viewer), TRUE);
370 static struct output_driver_class psppire_output_class =
372 "PSPPIRE", /* name */
374 psppire_output_submit, /* submit */
379 psppire_output_window_setup (void)
381 struct psppire_output_driver *pod;
382 struct output_driver *d;
384 pod = xzalloc (sizeof *pod);
386 output_driver_init (d, &psppire_output_class, "PSPPIRE",
387 SETTINGS_DEVICE_UNFILTERED);
388 output_driver_register (d);
393 /* Callback for the "delete" action (clicking the x on the top right
394 hand corner of the window) */
396 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
398 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
400 gtk_widget_destroy (GTK_WIDGET (ow));
402 ow->driver->viewer = NULL;
410 cancel_urgency (GtkWindow *window, gpointer data)
412 gtk_window_set_urgency_hint (window, FALSE);
416 on_row_activate (GtkTreeView *overview,
418 GtkTreeViewColumn *column,
419 PsppireOutputWindow *window)
427 model = gtk_tree_view_get_model (overview);
428 if (!gtk_tree_model_get_iter (model, &iter, path))
431 gtk_tree_model_get_value (model, &iter, COL_Y, &value);
432 y = g_value_get_long (&value);
433 g_value_unset (&value);
435 vadj = gtk_layout_get_vadjustment (window->output);
437 max = vadj->upper - vadj->page_size;
442 gtk_adjustment_set_value (vadj, y);
445 static void psppire_output_window_print (PsppireOutputWindow *window);
449 export_output (PsppireOutputWindow *window, struct string_map *options,
452 struct output_driver *driver;
455 string_map_insert (options, "format", format);
456 driver = output_driver_create (options);
460 for (i = 0; i < window->n_items; i++)
461 driver->class->submit (driver, window->items[i]);
462 output_driver_destroy (driver);
484 #define N_EXTENSIONS (n_FT - 1)
486 struct file_types ft[n_FT] = {
487 {N_("Infer file type from extension"), NULL},
488 {N_("PDF (*.pdf)"), ".pdf"},
489 {N_("HTML (*.html)"), ".html"},
490 {N_("OpenDocument (*.odt)"), ".odt"},
491 {N_("Text (*.txt)"), ".txt"},
492 {N_("PostScript (*.ps)"), ".ps"},
493 {N_("Comma-Separated Values (*.csv)"), ".csv"}
498 on_combo_change (GtkFileChooser *chooser)
500 gboolean sensitive = FALSE;
501 GtkWidget *combo = gtk_file_chooser_get_extra_widget (chooser);
504 gchar *fn = gtk_file_chooser_get_filename (chooser);
506 if (combo && gtk_widget_get_realized (combo))
507 x = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
519 for (i = 1 ; i < N_EXTENSIONS ; ++i)
521 if ( g_str_has_suffix (fn, ft[i].ext))
531 gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_ACCEPT, sensitive);
536 on_file_chooser_change (GObject *w, GParamSpec *pspec, gpointer data)
539 GtkFileChooser *chooser = data;
540 const gchar *name = g_param_spec_get_name (pspec);
542 if ( ! gtk_widget_get_realized (GTK_WIDGET (chooser)))
545 /* Ignore this one. It causes recursion. */
546 if ( 0 == strcmp ("tooltip-text", name))
549 on_combo_change (chooser);
553 /* Recursively descend all the children of W, connecting
554 to their "notify" signal */
556 iterate_widgets (GtkWidget *w, gpointer data)
558 if ( GTK_IS_CONTAINER (w))
559 gtk_container_forall (GTK_CONTAINER (w), iterate_widgets, data);
561 g_signal_connect (w, "notify", G_CALLBACK (on_file_chooser_change), data);
566 static GtkListStore *
567 create_file_type_list (void)
571 GtkListStore *list = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
573 for (i = 0 ; i < n_FT ; ++i)
575 gtk_list_store_append (list, &iter);
576 gtk_list_store_set (list, &iter,
577 0, gettext (ft[i].label),
586 psppire_output_window_export (PsppireOutputWindow *window)
592 GtkFileChooser *chooser;
594 GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Export Output"),
596 GTK_FILE_CHOOSER_ACTION_SAVE,
597 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
598 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
601 g_object_set (dialog, "local-only", FALSE, NULL);
603 chooser = GTK_FILE_CHOOSER (dialog);
605 list = create_file_type_list ();
607 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (list));
611 /* Create text cell renderer */
612 GtkCellRenderer *cell = gtk_cell_renderer_text_new();
613 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE );
615 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell, "text", 0);
618 g_signal_connect_swapped (combo, "changed", G_CALLBACK (on_combo_change), chooser);
620 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
622 gtk_file_chooser_set_extra_widget (chooser, combo);
624 /* This kludge is necessary because there is no signal to tell us
625 when the candidate filename of a GtkFileChooser has changed */
626 gtk_container_forall (GTK_CONTAINER (dialog), iterate_widgets, dialog);
629 gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
631 response = gtk_dialog_run (GTK_DIALOG (dialog));
633 if ( response == GTK_RESPONSE_ACCEPT )
635 int file_type = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
636 char *filename = gtk_file_chooser_get_filename (chooser);
637 struct string_map options;
639 g_return_if_fail (filename);
641 if (file_type == FT_AUTO)
644 for (i = 1 ; i < N_EXTENSIONS ; ++i)
646 if ( g_str_has_suffix (filename, ft[i].ext))
655 string_map_init (&options);
656 string_map_insert (&options, "output-file", filename);
661 export_output (window, &options, "pdf");
664 export_output (window, &options, "html");
667 export_output (window, &options, "odt");
670 export_output (window, &options, "ps");
673 export_output (window, &options, "csv");
677 string_map_insert (&options, "headers", "false");
678 string_map_insert (&options, "paginate", "false");
679 string_map_insert (&options, "squeeze", "true");
680 string_map_insert (&options, "emphasis", "none");
681 string_map_insert (&options, "charts", "none");
682 string_map_insert (&options, "top-margin", "0");
683 string_map_insert (&options, "bottom-margin", "0");
684 export_output (window, &options, "txt");
687 g_assert_not_reached ();
690 string_map_destroy (&options);
695 gtk_widget_destroy (dialog);
708 clipboard_get_cb (GtkClipboard *clipboard,
709 GtkSelectionData *selection_data,
713 PsppireOutputWindow *window = data;
717 struct output_driver *driver = NULL;
718 char dirname[PATH_MAX], *filename;
719 struct string_map options;
721 GtkTreeSelection *sel = gtk_tree_view_get_selection (window->overview);
722 GtkTreeModel *model = gtk_tree_view_get_model (window->overview);
724 GList *rows = gtk_tree_selection_get_selected_rows (sel, &model);
730 if (path_search (dirname, sizeof dirname, NULL, NULL, true)
731 || mkdtemp (dirname) == NULL)
733 error (0, errno, _("failed to create temporary directory"));
736 filename = xasprintf ("%s/clip.tmp", dirname);
738 string_map_init (&options);
739 string_map_insert (&options, "output-file", filename);
743 case SELECT_FMT_UTF8:
744 string_map_insert (&options, "box", "unicode");
747 case SELECT_FMT_TEXT:
748 string_map_insert (&options, "format", "txt");
751 case SELECT_FMT_HTML:
752 string_map_insert (&options, "format", "html");
753 string_map_insert (&options, "borders", "false");
754 string_map_insert (&options, "css", "false");
758 string_map_insert (&options, "format", "odt");
762 g_warning ("unsupported clip target\n");
767 driver = output_driver_create (&options);
773 GtkTreePath *path = n->data ;
775 struct output_item *item ;
777 gtk_tree_model_get_iter (model, &iter, path);
778 gtk_tree_model_get (model, &iter, COL_ADDR, &item, -1);
780 driver->class->submit (driver, item);
785 if ( driver->class->flush)
786 driver->class->flush (driver);
789 /* Some drivers (eg: the odt one) don't write anything until they
791 output_driver_destroy (driver);
794 if ( g_file_get_contents (filename, &text, &length, NULL) )
796 gtk_selection_data_set (selection_data, selection_data->target,
798 (const guchar *) text, length);
804 output_driver_destroy (driver);
816 clipboard_clear_cb (GtkClipboard *clipboard,
821 static const GtkTargetEntry targets[] = {
823 { "STRING", 0, SELECT_FMT_TEXT },
824 { "TEXT", 0, SELECT_FMT_TEXT },
825 { "COMPOUND_TEXT", 0, SELECT_FMT_TEXT },
826 { "text/plain", 0, SELECT_FMT_TEXT },
828 { "UTF8_STRING", 0, SELECT_FMT_UTF8 },
829 { "text/plain;charset=utf-8", 0, SELECT_FMT_UTF8 },
831 { "text/html", 0, SELECT_FMT_HTML },
833 { "application/vnd.oasis.opendocument.text", 0, SELECT_FMT_ODT }
837 on_copy (PsppireOutputWindow *window)
840 GtkClipboard *clipboard =
841 gtk_widget_get_clipboard (GTK_WIDGET (window),
842 GDK_SELECTION_CLIPBOARD);
844 if (!gtk_clipboard_set_with_data (clipboard, targets,
845 G_N_ELEMENTS (targets),
846 clipboard_get_cb, clipboard_clear_cb,
849 clipboard_clear_cb (clipboard, window);
854 on_selection_change (GtkTreeSelection *sel, GtkAction *copy_action)
856 /* The Copy action is available only if there is something selected */
857 gtk_action_set_sensitive (copy_action, gtk_tree_selection_count_selected_rows (sel) > 0);
861 on_select_all (PsppireOutputWindow *window)
863 GtkTreeSelection *sel = gtk_tree_view_get_selection (window->overview);
864 gtk_tree_view_expand_all (window->overview);
865 gtk_tree_selection_select_all (sel);
870 copy_base_to_bg (GtkWidget *dest, GtkWidget *src)
873 for (i = 0; i < 5; ++i)
875 GdkColor *col = >k_widget_get_style (src)->base[i];
876 gtk_widget_modify_bg (dest, i, col);
878 col = >k_widget_get_style (src)->text[i];
879 gtk_widget_modify_fg (dest, i, col);
884 on_dwgarea_realize (GtkWidget *dwg_area, gpointer data)
886 GtkWidget *viewer = GTK_WIDGET (data);
888 copy_base_to_bg (dwg_area, viewer);
893 psppire_output_window_style_set (GtkWidget *w, GtkStyle *prev)
895 GtkWidget *op = GTK_WIDGET (PSPPIRE_OUTPUT_WINDOW (w)->output);
897 /* Copy the base style from the parent widget to the container and
899 We do this, because the container's primary purpose is to
900 display text. This way psppire appears to follow the chosen
903 copy_base_to_bg (op, w);
904 gtk_container_foreach (GTK_CONTAINER (op), (GtkCallback) copy_base_to_bg,
905 PSPPIRE_OUTPUT_WINDOW (w)->output);
907 /* Chain up to the parent class */
908 GTK_WIDGET_CLASS (parent_class)->style_set (w, prev);
912 psppire_output_window_init (PsppireOutputWindow *window)
914 GtkTreeViewColumn *column;
915 GtkCellRenderer *renderer;
917 GtkAction *copy_action;
918 GtkAction *select_all_action;
919 GtkTreeSelection *sel;
921 xml = builder_new ("output-viewer.ui");
923 copy_action = get_action_assert (xml, "edit_copy");
924 select_all_action = get_action_assert (xml, "edit_select-all");
926 gtk_action_set_sensitive (copy_action, FALSE);
928 g_signal_connect_swapped (copy_action, "activate", G_CALLBACK (on_copy), window);
930 g_signal_connect_swapped (select_all_action, "activate", G_CALLBACK (on_select_all), window);
932 gtk_widget_reparent (get_widget_assert (xml, "vbox1"), GTK_WIDGET (window));
934 window->output = GTK_LAYOUT (get_widget_assert (xml, "output"));
937 window->overview = GTK_TREE_VIEW (get_widget_assert (xml, "overview"));
939 sel = gtk_tree_view_get_selection (window->overview);
941 gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
943 g_signal_connect (sel, "changed", G_CALLBACK (on_selection_change), copy_action);
945 gtk_tree_view_set_model (window->overview,
946 GTK_TREE_MODEL (gtk_tree_store_new (
948 G_TYPE_STRING, /* COL_TITLE */
949 G_TYPE_POINTER, /* COL_ADDR */
950 G_TYPE_LONG))); /* COL_Y */
952 window->in_command = false;
954 window->items = NULL;
955 window->n_items = window->allocated_items = 0;
957 column = gtk_tree_view_column_new ();
958 gtk_tree_view_append_column (GTK_TREE_VIEW (window->overview), column);
959 renderer = gtk_cell_renderer_text_new ();
960 gtk_tree_view_column_pack_start (column, renderer, TRUE);
961 gtk_tree_view_column_add_attribute (column, renderer, "text", COL_TITLE);
963 g_signal_connect (GTK_TREE_VIEW (window->overview),
964 "row-activated", G_CALLBACK (on_row_activate), window);
968 g_signal_connect (window,
970 G_CALLBACK (cancel_urgency),
973 g_signal_connect (get_action_assert (xml,"windows_minimise-all"),
975 G_CALLBACK (psppire_window_minimise_all),
979 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1", GTK_TYPE_UI_MANAGER));
980 merge_help_menu (uim);
982 PSPPIRE_WINDOW (window)->menu =
983 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar/windows_menuitem/windows_minimise-all")->parent);
986 g_signal_connect_swapped (get_action_assert (xml, "file_export"), "activate",
987 G_CALLBACK (psppire_output_window_export), window);
990 g_signal_connect_swapped (get_action_assert (xml, "file_print"), "activate",
991 G_CALLBACK (psppire_output_window_print), window);
993 g_object_unref (xml);
995 g_signal_connect (window, "delete-event",
996 G_CALLBACK (on_delete), window);
1001 psppire_output_window_new (void)
1003 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
1004 /* TRANSLATORS: This will form a filename. Please avoid whitespace. */
1005 "filename", _("Output"),
1006 "description", _("Output Viewer"),
1013 create_xr_print_driver (GtkPrintContext *context, PsppireOutputWindow *window)
1015 struct string_map options;
1016 GtkPageSetup *page_setup;
1017 double width, height;
1019 double right_margin;
1021 double bottom_margin;
1023 page_setup = gtk_print_context_get_page_setup (context);
1024 width = gtk_page_setup_get_paper_width (page_setup, GTK_UNIT_MM);
1025 height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_MM);
1026 left_margin = gtk_page_setup_get_left_margin (page_setup, GTK_UNIT_MM);
1027 right_margin = gtk_page_setup_get_right_margin (page_setup, GTK_UNIT_MM);
1028 top_margin = gtk_page_setup_get_top_margin (page_setup, GTK_UNIT_MM);
1029 bottom_margin = gtk_page_setup_get_bottom_margin (page_setup, GTK_UNIT_MM);
1031 string_map_init (&options);
1032 string_map_insert_nocopy (&options, xstrdup ("paper-size"),
1033 xasprintf("%.2fx%.2fmm", width, height));
1034 string_map_insert_nocopy (&options, xstrdup ("left-margin"),
1035 xasprintf ("%.2fmm", left_margin));
1036 string_map_insert_nocopy (&options, xstrdup ("right-margin"),
1037 xasprintf ("%.2fmm", right_margin));
1038 string_map_insert_nocopy (&options, xstrdup ("top-margin"),
1039 xasprintf ("%.2fmm", top_margin));
1040 string_map_insert_nocopy (&options, xstrdup ("bottom-margin"),
1041 xasprintf ("%.2fmm", bottom_margin));
1044 xr_driver_create (gtk_print_context_get_cairo_context (context), &options);
1046 string_map_destroy (&options);
1050 paginate (GtkPrintOperation *operation,
1051 GtkPrintContext *context,
1052 PsppireOutputWindow *window)
1054 if (window->paginated)
1056 /* Sometimes GTK+ emits this signal again even after pagination is
1057 complete. Don't let that screw up printing. */
1060 else if ( window->print_item < window->n_items )
1062 xr_driver_output_item (window->print_xrd, window->items[window->print_item++]);
1063 while (xr_driver_need_new_page (window->print_xrd))
1065 xr_driver_next_page (window->print_xrd, NULL);
1066 window->print_n_pages ++;
1072 gtk_print_operation_set_n_pages (operation, window->print_n_pages);
1074 /* Re-create the driver to do the real printing. */
1075 xr_driver_destroy (window->print_xrd);
1076 create_xr_print_driver (context, window);
1077 window->print_item = 0;
1078 window->paginated = TRUE;
1085 begin_print (GtkPrintOperation *operation,
1086 GtkPrintContext *context,
1087 PsppireOutputWindow *window)
1089 create_xr_print_driver (context, window);
1091 window->print_item = 0;
1092 window->print_n_pages = 1;
1093 window->paginated = FALSE;
1097 end_print (GtkPrintOperation *operation,
1098 GtkPrintContext *context,
1099 PsppireOutputWindow *window)
1101 xr_driver_destroy (window->print_xrd);
1106 draw_page (GtkPrintOperation *operation,
1107 GtkPrintContext *context,
1109 PsppireOutputWindow *window)
1111 xr_driver_next_page (window->print_xrd, gtk_print_context_get_cairo_context (context));
1112 while (!xr_driver_need_new_page (window->print_xrd)
1113 && window->print_item < window->n_items)
1114 xr_driver_output_item (window->print_xrd, window->items [window->print_item++]);
1119 psppire_output_window_print (PsppireOutputWindow *window)
1121 GtkPrintOperationResult res;
1123 GtkPrintOperation *print = gtk_print_operation_new ();
1125 if (window->print_settings != NULL)
1126 gtk_print_operation_set_print_settings (print, window->print_settings);
1128 g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), window);
1129 g_signal_connect (print, "end_print", G_CALLBACK (end_print), window);
1130 g_signal_connect (print, "paginate", G_CALLBACK (paginate), window);
1131 g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), window);
1133 res = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
1134 GTK_WINDOW (window), NULL);
1136 if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
1138 if (window->print_settings != NULL)
1139 g_object_unref (window->print_settings);
1140 window->print_settings = g_object_ref (gtk_print_operation_get_print_settings (print));
1144 g_object_unref (print);