Update Spanish translation
[gnumeric.git] / src / print.c
blob274ee18859859d09694aa9f36c13a322fe934eb2
2 /*
3 * print.c: Printing routines for Gnumeric
5 * Authors:
6 * Miguel de Icaza (miguel@gnu.org)
7 * Morten Welinder (terra@gnome.org)
8 * Andreas J. Guelzow (aguelzow@pyrshep.ca)
10 * Copyright 2007, Andreas J. Guelzow, All Rights Reserved
11 * Copyright (C) 2007-2009 Morten Welinder (terra@gnome.org)
13 * Handles printing of Sheets.
15 #include <gnumeric-config.h>
16 #include <print-cell.h>
18 #include <gnumeric.h>
19 #include <print.h>
21 #include <gui-util.h>
22 #include <gutils.h>
23 #include <sheet-object.h>
24 #include <sheet-object-impl.h>
25 #include <selection.h>
26 #include <workbook.h>
27 #include <workbook-control.h>
28 #include <wbc-gtk.h>
29 #include <command-context.h>
30 #include <dialogs/dialogs.h>
31 #include <gnumeric-conf.h>
32 #include <libgnumeric.h>
33 #include <sheet.h>
34 #include <value.h>
35 #include <cellspan.h>
36 #include <print-info.h>
37 #include <application.h>
38 #include <sheet-style.h>
39 #include <ranges.h>
40 #include <parse-util.h>
41 #include <style-font.h>
42 #include <gnumeric-conf.h>
43 #include <goffice/goffice.h>
45 #include <gsf/gsf-meta-names.h>
47 #include <glib/gi18n-lib.h>
48 #include <glib/gstdio.h>
49 #include <glib.h>
51 #include <unistd.h>
52 #include <errno.h>
54 #ifdef G_OS_WIN32
55 #include <windows.h>
56 /* see bug #533795. */
57 #define PREVIEW_VIA_PDF
58 #endif
60 /* The following structure is used by the printing system */
62 typedef struct {
63 GList *gnmSheets;
64 Workbook *wb;
65 WorkbookControl *wbc;
66 Sheet *sheet;
67 GtkWidget *button_all_sheets, *button_selected_sheet,
68 *button_spec_sheets;
69 GtkWidget *button_selection, *button_ignore_printarea, *button_print_hidden_sheets;
70 GtkWidget *button_ignore_page_breaks;
71 GtkWidget *spin_from, *spin_to;
72 PrintRange pr;
73 guint to, from;
74 gboolean ignore_pb;
75 guint last_pagination;
76 GnmPrintHFRenderInfo *hfi;
77 GtkWidget *progress;
78 gboolean cancel;
79 gboolean preview;
80 } PrintingInstance;
82 typedef struct {
83 Sheet *sheet;
84 gboolean selection;
85 gboolean ignore_printarea;
86 GArray *column_pagination;
87 GArray *row_pagination;
88 guint pages;
89 } SheetPrintInfo;
91 typedef struct {
92 Sheet *sheet;
93 GnmRange range;
94 gint n_rep_cols;
95 gint n_rep_rows;
96 gint first_rep_cols;
97 gint first_rep_rows;
98 } SheetPageRange;
100 typedef struct {
101 gint rc;
102 gint count;
103 gint first_rep;
104 gint n_rep;
105 } PaginationInfo;
108 GType
109 gnm_print_range_get_type (void)
111 static GType etype = 0;
112 if (etype == 0) {
113 static GEnumValue const values[] = {
114 { GNM_PRINT_SAVED_INFO,
115 "GNM_PRINT_SAVED_INFO",
116 "as-saved"},
117 { GNM_PRINT_ACTIVE_SHEET,
118 "GNM_PRINT_ACTIVE_SHEET",
119 "active-sheet"},
120 { GNM_PRINT_ALL_SHEETS,
121 "GNM_PRINT_ALL_SHEETS",
122 "all-sheets"},
123 { GNM_PRINT_ALL_SHEETS_INCLUDING_HIDDEN,
124 "GNM_PRINT_ALL_SHEETS_INCLUDING_HIDDEN",
125 "all-sheets-incl-hidden"},
126 { GNM_PRINT_SHEET_RANGE,
127 "GNM_PRINT_SHEET_RANGE",
128 "sheet-range"},
129 { GNM_PRINT_SHEET_SELECTION,
130 "GNM_PRINT_SHEET_SELECTION",
131 "sheet-selection"},
132 { GNM_PRINT_IGNORE_PRINTAREA,
133 "GNM_PRINT_IGNORE_PRINTAREA",
134 "ignore-print-area"},
135 { GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA,
136 "GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA",
137 "sheet-selection-ignore-printarea"},
138 { 0, NULL, NULL }
140 etype = g_enum_register_static ("GnmPrintRange", values);
142 return etype;
146 static PrintingInstance *
147 printing_instance_new (void)
149 PrintingInstance * pi = g_new0 (PrintingInstance,1);
150 pi->hfi = gnm_print_hf_render_info_new ();
151 pi->cancel = FALSE;
152 pi->hfi->pages = -1;
154 return pi;
157 static void
158 sheet_print_info_free (gpointer data)
160 SheetPrintInfo *spi = data;
162 g_array_unref (spi->column_pagination);
163 g_array_unref (spi->row_pagination);
164 g_free (data);
167 static void
168 printing_instance_delete (PrintingInstance *pi)
170 g_list_free_full (pi->gnmSheets, sheet_print_info_free);
171 gnm_print_hf_render_info_destroy (pi->hfi);
172 if (pi->progress) {
173 gtk_widget_destroy (pi->progress);
175 g_free (pi);
178 void
179 gnm_print_sheet_objects (cairo_t *cr,
180 Sheet const *sheet,
181 GnmRange *range,
182 double base_x, double base_y)
184 GSList *ptr, *objects;
185 double width, height;
187 g_return_if_fail (IS_SHEET (sheet));
188 g_return_if_fail (cr != NULL);
189 g_return_if_fail (range != NULL);
191 cairo_save (cr);
193 height = sheet_row_get_distance_pts (sheet, range->start.row,
194 range->end.row + 1);
195 width = sheet_col_get_distance_pts (sheet,
196 range->start.col, range->end.col + 1);
198 if (sheet->text_is_rtl)
199 cairo_rectangle (cr,
200 base_x - width, base_y,
201 width, height);
202 else
203 cairo_rectangle (cr,
204 base_x, base_y,
205 width, height);
206 cairo_clip (cr);
208 objects = g_slist_reverse (g_slist_copy (sheet->sheet_objects));
210 for (ptr = objects; ptr; ptr = ptr->next) {
211 SheetObject *so = GNM_SO (ptr->data);
212 GnmRange const *r = &so->anchor.cell_bound;
214 if (!sheet_object_can_print (so) ||
215 !range_overlap (range, &so->anchor.cell_bound))
216 continue;
218 cairo_save (cr);
219 /* move to top left */
220 if (sheet->text_is_rtl) {
221 double tr_x, tr_y;
222 switch (so->anchor.mode) {
223 case GNM_SO_ANCHOR_ABSOLUTE:
224 tr_x = base_x - 0.5; /* because of leading gridline */
225 tr_y = base_y + 0.5;
226 break;
227 case GNM_SO_ANCHOR_ONE_CELL:
228 tr_x = base_x - 0.5
229 - sheet_col_get_distance_pts (sheet, 0, r->start.col+1)
230 + sheet_col_get_distance_pts (sheet, 0, range->start.col);
231 tr_y = base_y + 0.5
232 + sheet_row_get_distance_pts (sheet, 0, r->start.row)
233 - sheet_row_get_distance_pts (sheet, 0, range->start.row);
234 break;
235 default:
236 tr_x = base_x - 0.5
237 - sheet_col_get_distance_pts (sheet, 0, r->end.col+1)
238 + sheet_col_get_distance_pts (sheet, 0, range->start.col);
239 tr_y = base_y + 0.5
240 + sheet_row_get_distance_pts (sheet, 0, r->start.row)
241 - sheet_row_get_distance_pts (sheet, 0, range->start.row);
242 break;
244 cairo_translate (cr, tr_x, tr_y);
245 } else
246 cairo_translate (cr, (so->anchor.mode == GNM_SO_ANCHOR_ABSOLUTE)?
247 base_x + 0.5: base_x + 0.5
248 + sheet_col_get_distance_pts (sheet, 0, r->start.col)
249 - sheet_col_get_distance_pts (sheet, 0,
250 range->start.col),
251 (so->anchor.mode == GNM_SO_ANCHOR_ABSOLUTE)?
252 base_y + 0.5: base_y + 0.5
253 + sheet_row_get_distance_pts (sheet, 0, r->start.row)
254 - sheet_row_get_distance_pts (sheet, 0,
255 range->start.row));
257 sheet_object_draw_cairo (so, (gpointer)cr, sheet->text_is_rtl);
258 cairo_restore (cr);
261 g_slist_free (objects);
263 cairo_restore (cr);
266 static void
267 print_page_cells (G_GNUC_UNUSED GtkPrintContext *context,
268 G_GNUC_UNUSED PrintingInstance * pi,
269 cairo_t *cr, Sheet const *sheet, GnmRange *range,
270 double base_x, double base_y)
272 gnm_gtk_print_cell_range (cr, sheet, range,
273 base_x, base_y,
274 (GnmPrintInformation const *) sheet->print_info);
275 gnm_print_sheet_objects (cr, sheet, range, base_x, base_y);
278 static void
279 print_header_gtk (GtkPrintContext *context, cairo_t *cr,
280 double x, double y, double w, double h,
281 char const *name,
282 PangoFontDescription *desc)
284 PangoLayout *layout;
285 gint layout_height;
286 gdouble text_height;
288 cairo_rectangle (cr, x, y, w, h);
289 cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
290 cairo_fill (cr);
292 cairo_set_source_rgb (cr, 0., 0., 0.);
293 layout = gtk_print_context_create_pango_layout (context);
294 pango_layout_set_font_description (layout, desc);
296 pango_layout_set_text (layout, name, -1);
297 pango_layout_set_width (layout, w);
298 pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
300 pango_layout_get_size (layout, NULL, &layout_height);
301 text_height = (gdouble)layout_height / PANGO_SCALE;
303 cairo_move_to (cr, x + w/2, y + (h - text_height) / 2);
304 pango_cairo_show_layout (cr, layout);
306 g_object_unref (layout);
310 static void
311 print_page_col_headers (GtkPrintContext *context,
312 G_GNUC_UNUSED PrintingInstance * pi,
313 cairo_t *cr, Sheet const *sheet, GnmRange *range,
314 double row_header_width, double col_header_height)
316 int start_col, end_col;
317 int col;
318 double x;
319 PangoFontDescription *desc;
320 double hscale;
322 g_return_if_fail (IS_SHEET (sheet));
323 g_return_if_fail (range != NULL);
324 g_return_if_fail (range->start.col <= range->end.col);
326 hscale = sheet->display_formulas ? 2 : 1;
327 desc = pango_font_description_from_string ("sans 12");
329 start_col = range->start.col;
330 end_col = range->end.col;
332 x = (row_header_width + GNM_COL_MARGIN) * (sheet->text_is_rtl ? -1. : 1.);
334 for (col = start_col; col <= end_col ; col++) {
335 ColRowInfo const *ci = sheet_col_get_info (sheet, col);
337 if (ci->visible) {
338 if (sheet->text_is_rtl)
339 x -= ci->size_pts * hscale;
341 print_header_gtk (context, cr,
342 x + 0.5, 0,
343 ci->size_pts * hscale - 1,
344 col_header_height - 0.5,
345 col_name (col), desc);
347 if (!sheet->text_is_rtl)
348 x += ci->size_pts * hscale;
352 pango_font_description_free (desc);
355 static void
356 print_page_row_headers (GtkPrintContext *context,
357 G_GNUC_UNUSED PrintingInstance * pi,
358 cairo_t *cr, Sheet const *sheet, GnmRange *range,
359 double row_header_width, double col_header_height)
361 int start_row, end_row;
362 int row;
363 double x = 0, y;
364 PangoFontDescription *desc;
366 g_return_if_fail (IS_SHEET (sheet));
367 g_return_if_fail (range != NULL);
368 g_return_if_fail (range->start.row <= range->end.row);
370 desc = pango_font_description_from_string ("sans 12");
372 start_row = range->start.row;
373 end_row = range->end.row;
375 if (sheet->text_is_rtl)
376 x = - (row_header_width - 0.5);
378 for (row = start_row, y = col_header_height; row <= end_row ; row++) {
379 ColRowInfo const *ri = sheet_row_get_info (sheet, row);
381 if (ri->visible) {
382 print_header_gtk (context, cr,
383 x, y + 0.5,
384 row_header_width - 0.5,
385 ri->size_pts - 1,
386 row_name (row), desc);
387 y += ri->size_pts;
391 pango_font_description_free (desc);
394 static PangoLayout *
395 ensure_decoration_layout (GtkPrintContext *context)
397 GnmStyle *style;
398 GnmFont *font;
399 PangoLayout *layout;
401 layout = gtk_print_context_create_pango_layout (context);
402 style = gnm_conf_get_printer_decoration_font ();
403 font = gnm_style_get_font
404 (style, pango_layout_get_context (layout));
405 pango_layout_set_font_description (layout, font->go.font->desc);
406 gnm_style_unref (style);
408 return layout;
413 * print_hf_element
414 * @pj: printing context
415 * @format:
416 * @side:
417 * @y:
419 * Print a header/footer line.
421 * Position at y, and clip to rectangle.
423 static void
424 print_hf_element (GtkPrintContext *context, cairo_t *cr,
425 G_GNUC_UNUSED Sheet const *sheet,
426 char const *format,
427 PangoAlignment side, gdouble width, gboolean align_bottom,
428 GnmPrintHFRenderInfo *hfi)
430 PangoLayout *layout;
432 gdouble text_height = 0.;
433 char *text;
435 if (format == NULL)
436 return;
438 text = gnm_print_hf_format_render (format, hfi, HF_RENDER_PRINT);
440 if (text == NULL)
441 return;
443 layout = ensure_decoration_layout (context);
445 pango_layout_set_text (layout, text, -1);
446 pango_layout_set_width (layout, width * PANGO_SCALE);
447 pango_layout_set_alignment (layout, side);
449 if (align_bottom) {
450 gint layout_height = 0;
451 pango_layout_get_size (layout, NULL, &layout_height);
452 text_height = (gdouble)layout_height / PANGO_SCALE;
455 cairo_move_to (cr, 0., - text_height);
456 pango_cairo_show_layout (cr, layout);
458 g_object_unref (layout);
459 g_free(text);
463 * print_hf_line
464 * @hf: header/footer descriptor
465 * @align_bottom: vertical position (whether to print above or below
466 * @width: width of header line
468 * Print a header/footer line.
471 static void
472 print_hf_line (GtkPrintContext *context, cairo_t *cr, Sheet const *sheet,
473 GnmPrintHF const *hf, gboolean align_bottom, gdouble width, GnmPrintHFRenderInfo *hfi)
475 print_hf_element (context, cr, sheet, hf->left_format, PANGO_ALIGN_LEFT, width, align_bottom, hfi);
476 print_hf_element (context, cr, sheet, hf->middle_format, PANGO_ALIGN_CENTER, width, align_bottom, hfi);
477 print_hf_element (context, cr, sheet, hf->right_format, PANGO_ALIGN_RIGHT, width, align_bottom, hfi);
483 * print_page:
484 * @pj: printing context
485 * @gsr: the page information
487 * Excel prints repeated rows like this: Pages up to and including the page
488 * where the first of the repeated rows "naturally" occurs are printed in
489 * the normal way. On subsequent pages, repated rows are printed before the
490 * regular flow.
492 static gboolean
493 print_page (G_GNUC_UNUSED GtkPrintOperation *operation,
494 GtkPrintContext *context,
495 PrintingInstance * pi,
496 SheetPageRange *gsr)
498 Sheet *sheet = gsr->sheet;
499 GnmPrintInformation *pinfo = sheet->print_info;
500 gdouble print_height, print_width;
501 gdouble main_height, main_width;
502 gdouble header, footer, left, right;
503 gdouble edge_to_below_header, edge_to_above_footer;
504 cairo_t *cr;
505 gdouble px, py;
506 gdouble width;
507 gdouble height;
508 gdouble col_header_height = 0.;
509 gdouble row_header_width = 0.;
510 gdouble rep_row_height = 0.;
511 gdouble rep_col_width = 0.;
512 gdouble dir = (sheet->text_is_rtl ? -1. : 1.);
513 GnmRange r_repeating_intersect;
515 px = pinfo->scaling.percentage.x / 100.;
516 py = pinfo->scaling.percentage.y / 100.;
518 if (px <= 0.)
519 px = 1.;
520 if (py <= 0.)
521 py = 1.;
523 cr = gtk_print_context_get_cairo_context (context);
524 print_info_get_margins (pinfo, &header, &footer, &left, &right,
525 &edge_to_below_header, &edge_to_above_footer);
527 if (sheet->print_info->print_titles) {
528 col_header_height = sheet->rows.default_style.size_pts;
529 row_header_width = sheet->cols.default_style.size_pts;
532 width = gtk_print_context_get_width (context);
533 height = print_info_get_paper_height (pinfo,GTK_UNIT_POINTS)
534 - edge_to_below_header - edge_to_above_footer;
536 main_height = sheet_row_get_distance_pts (sheet, gsr->range.start.row,
537 gsr->range.end.row + 1);
538 main_width = sheet_col_get_distance_pts (sheet, gsr->range.start.col,
539 gsr->range.end.col + 1);
540 if (gsr->n_rep_rows > 0)
541 rep_row_height = sheet_row_get_distance_pts
542 (sheet, gsr->first_rep_rows,
543 gsr->first_rep_rows + gsr->n_rep_rows);
544 if (gsr->n_rep_cols > 0)
545 rep_col_width = sheet_col_get_distance_pts
546 (sheet, gsr->first_rep_cols,
547 gsr->first_rep_cols + gsr->n_rep_cols);
548 if ((gsr->n_rep_rows > 0) || (gsr->n_rep_cols > 0)) {
549 range_init (&r_repeating_intersect, gsr->first_rep_cols, gsr->first_rep_rows,
550 gsr->first_rep_cols + gsr->n_rep_cols - 1,
551 gsr->first_rep_rows + gsr->n_rep_rows - 1);
554 print_height = main_height + col_header_height + rep_row_height;
555 print_width = main_width + row_header_width + rep_col_width;
557 /* printing header */
559 if (edge_to_below_header > header) {
560 cairo_save (cr);
561 print_hf_line (context, cr, sheet, pinfo->header,
562 FALSE, width, pi->hfi);
563 cairo_restore (cr);
566 /* printing footer */
568 if (edge_to_above_footer > footer) {
569 cairo_save (cr);
570 cairo_translate (cr, 0, height + (edge_to_below_header - header) + (edge_to_above_footer - footer));
571 print_hf_line (context, cr, sheet, pinfo->footer, TRUE, width,
572 pi->hfi);
573 cairo_restore (cr);
576 /* setting up content area */
577 cairo_save (cr);
578 cairo_translate (cr, sheet->text_is_rtl ? width : 0, edge_to_below_header - header);
580 if (sheet->sheet_type == GNM_SHEET_OBJECT) {
581 SheetObject *so = sheet->sheet_objects
582 ? sheet->sheet_objects->data
583 : NULL;
584 if (so) {
585 cairo_scale (cr, px, py);
586 sheet_object_draw_cairo_sized (so, cr, width, height);
588 } else {
590 if (pinfo->center_horizontally == 1 || pinfo->center_vertically == 1) {
591 double shift_x = 0;
592 double shift_y = 0;
594 if (pinfo->center_horizontally == 1)
595 shift_x = (width - print_width * px)/2;
596 if (pinfo->center_vertically == 1)
597 shift_y = (height - print_height * py)/2;
598 cairo_translate (cr, dir * shift_x, shift_y);
600 cairo_scale (cr, px, py);
602 /* printing column and row headers */
604 if (sheet->print_info->print_titles) {
605 cairo_save (cr);
606 if (gsr->n_rep_cols > 0) {
607 print_page_col_headers (context, pi, cr, sheet,
608 &r_repeating_intersect,
609 row_header_width, col_header_height);
610 cairo_translate (cr, dir * rep_col_width, 0 );
612 print_page_col_headers (context, pi, cr, sheet, &gsr->range,
613 row_header_width, col_header_height);
614 cairo_restore (cr);
615 cairo_save (cr);
616 if (gsr->n_rep_rows > 0) {
617 print_page_row_headers (context, pi, cr, sheet,
618 &r_repeating_intersect,
619 row_header_width, col_header_height);
620 cairo_translate (cr, 0, rep_row_height);
622 print_page_row_headers (context, pi, cr, sheet, &gsr->range,
623 row_header_width, col_header_height);
624 cairo_restore (cr);
625 cairo_translate (cr, dir * row_header_width, col_header_height);
628 /* printing repeated row/col intersect */
630 if ((gsr->n_rep_rows > 0) && (gsr->n_rep_cols > 0)) {
631 print_page_cells (context, pi, cr, sheet,
632 &r_repeating_intersect,
633 dir * GNM_COL_MARGIN, -GNM_ROW_MARGIN);
636 /* printing repeated rows */
638 if (gsr->n_rep_rows > 0) {
639 GnmRange r;
640 range_init (&r, gsr->range.start.col, gsr->first_rep_rows,
641 gsr->range.end.col, gsr->first_rep_rows + gsr->n_rep_rows - 1);
642 cairo_save (cr);
643 if (gsr->n_rep_cols > 0)
644 cairo_translate (cr, dir * rep_col_width, 0 );
645 print_page_cells (context, pi, cr, sheet, &r,
646 dir * GNM_COL_MARGIN, -GNM_ROW_MARGIN);
647 cairo_restore (cr);
648 cairo_translate (cr, 0, rep_row_height );
651 /* printing repeated cols */
653 if (gsr->n_rep_cols > 0) {
654 GnmRange r;
655 range_init (&r, gsr->first_rep_cols, gsr->range.start.row,
656 gsr->first_rep_cols + gsr->n_rep_cols - 1, gsr->range.end.row);
657 print_page_cells (context, pi, cr, sheet, &r,
658 dir * GNM_COL_MARGIN, -GNM_ROW_MARGIN);
659 cairo_translate (cr, dir * rep_col_width, 0 );
662 /* printing page content */
664 print_page_cells (context, pi, cr, sheet, &gsr->range,
665 dir * GNM_COL_MARGIN, -GNM_ROW_MARGIN);
668 cairo_restore (cr);
669 return 1;
673 * Computes number of rows or columns that fit in @usable starting
674 * at index @start and limited to index @end
676 static int
677 compute_group (Sheet const *sheet,
678 int start, int end, double usable,
679 ColRowInfo const *(get_info)(Sheet const *sheet, int const p))
681 double size_pts = 1.; /* The initial grid line */
682 int idx, count = 0;
684 for (idx = start; idx <= end; idx++, count++) {
685 ColRowInfo const *info = (*get_info) (sheet, idx);
686 if (info->visible) {
687 size_pts += info->size_pts;
688 if (size_pts > usable)
689 break;
693 /* FIXME : Find a way to inform the user that one of the rows/cols does
694 * not fit on a page
697 if (count ==0) {
698 g_warning (_("Even one cell is too large for this page."));
700 /* If we do not return at least one we are going into an infinite loop! */
701 return 1;
704 return count;
707 static void
708 adjust_repetition (Sheet const *sheet,
709 gint i,
710 gint first_rep,
711 gint n_rep,
712 gdouble repeating,
713 gint *first_rep_used,
714 gint *n_rep_used,
715 gdouble *repeating_used,
716 double (sheet_get_distance_pts) (Sheet const *sheet, int from, int to))
718 if (i > first_rep) {
719 *first_rep_used = first_rep;
720 if (i - first_rep < n_rep) {
721 *n_rep_used = i - first_rep;
722 *repeating_used = sheet_get_distance_pts
723 (sheet, first_rep, first_rep + *n_rep_used);
724 } else {
725 *repeating_used = repeating;
726 *n_rep_used = n_rep;
731 static gint
732 paginate (GArray *paginationInfo,
733 Sheet const *sheet,
734 gint start, gint end,
735 gdouble usable, gboolean repeat, gint repeat_start, gint repeat_end,
736 double (sheet_get_distance_pts) (Sheet const *sheet, int from, int to),
737 ColRowInfo const *(get_info)(Sheet const *sheet, int const p),
738 GnmPageBreaks *pb, gboolean store_breaks)
740 int rc = start;
741 gint n_rep = 0, first_rep = 0;
742 gdouble repeating = 0.;
743 gint page_count = 0;
745 if (repeat) {
746 first_rep = repeat_start;
747 n_rep = repeat_end - first_rep + 1;
748 repeating = sheet_get_distance_pts (sheet, first_rep, first_rep + n_rep);
751 while (rc <= end) {
752 gint n_end;
754 n_end = gnm_page_breaks_get_next_manual_break (pb, rc) - 1;
755 if (n_end < rc)
756 n_end = end;
758 while (rc <= n_end) {
759 int count;
761 gdouble repeating_used = 0.;
762 gint n_rep_used = 0, first_rep_used = 0;
764 adjust_repetition (sheet, rc,
765 first_rep, n_rep,
766 repeating,
767 &first_rep_used, &n_rep_used,
768 &repeating_used,
769 sheet_get_distance_pts);
771 count = compute_group (sheet, rc, n_end,
772 usable - repeating_used,
773 get_info);
775 if (paginationInfo) {
776 PaginationInfo item;
777 item.rc = rc;
778 item.count = count;
779 item.first_rep = first_rep_used;
780 item.n_rep = n_rep_used;
781 g_array_append_val (paginationInfo, item);
783 page_count++;
785 rc += count;
786 if (store_breaks && (rc < n_end))
787 gnm_page_breaks_set_break (pb, rc, GNM_PAGE_BREAK_AUTO);
791 return page_count;
794 /* computer_scale_fit_to
795 * Computes the scaling needed to fit all the rows or columns into the @usable
796 * area.
797 * This function is called when printing, and the user has selected the 'fit-to'
798 * printing option. It will adjust the internal x and y scaling values to
799 * make the sheet fit the desired number of pages, as suggested by the user.
800 * It will only reduce the scaling to fit inside a page, not enlarge.
802 static double
803 compute_scale_fit_to (Sheet const *sheet,
804 int start, int end, double usable,
805 ColRowInfo const *(get_info)(Sheet const *sheet, int const p),
806 double (get_distance_pts) (Sheet const *sheet, int from, int to),
807 gint pages, double max_percent, double header,
808 gboolean repeat, gint repeat_start, gint repeat_end, GnmPageBreaks *pb)
810 double max_p, min_p;
811 gint max_pages;
812 double extent;
814 extent = get_distance_pts (sheet, start, end + 1);
816 /* If the repeating columns are not included we should add them */
817 if (repeat && (repeat_start < start))
818 extent += get_distance_pts (sheet, repeat_start,
819 (repeat_end < start) ? (repeat_end + 1) : start);
821 /* This means to take whatever space is needed. */
822 if (pages <= 0)
823 return max_percent;
825 /* We can handle a single page easily: */
826 if (pages == 1) {
827 max_p = usable/(header + extent + 2.);
828 return ((max_p > max_percent) ? max_percent : max_p);
831 /* There is no easy way to calculate really which percentage is needed */
832 /* without in fact allocating the cols/rows to pages. */
834 /* We first calculate the max percentage needed */
836 max_p = (pages * usable)/(extent + pages * header);
837 max_p = CLAMP (max_p, 0.01, max_percent);
839 max_pages = paginate (NULL, sheet, start, end, usable/max_p - header,
840 repeat, repeat_start, repeat_end,
841 get_distance_pts, get_info, pb, FALSE);
843 if (max_pages == pages)
844 return max_p;
846 /* The we calculate the min percentage */
848 min_p = usable/(extent + header);
849 min_p = CLAMP (min_p, 0.01, max_percent);
851 paginate (NULL, sheet, start, end, usable/min_p - header,
852 repeat, repeat_start, repeat_end,
853 get_distance_pts, get_info, pb, FALSE);
856 /* And then we pick the middle until the percentage is within 0.1% of */
857 /* the desired percentage */
859 while (max_p - min_p > 0.001) {
860 double cur_p = (max_p + min_p) / 2.;
861 int cur_pages = paginate (NULL, sheet, start, end, usable/cur_p - header,
862 repeat, repeat_start, repeat_end,
863 get_distance_pts, get_info, pb, FALSE);
865 if (cur_pages > pages)
866 max_p = cur_p;
867 else
868 min_p = cur_p;
871 return min_p;
874 #define COL_FIT(col) (MIN (col, gnm_sheet_get_last_col (sheet)))
875 #define ROW_FIT(row) (MIN (row, gnm_sheet_get_last_row (sheet)))
877 static void
878 compute_sheet_pages_add_sheet (PrintingInstance * pi, Sheet const *sheet,
879 gboolean selection,
880 gboolean ignore_printarea)
882 SheetPrintInfo *spi = g_new0 (SheetPrintInfo, 1);
884 spi->sheet = (Sheet *) sheet;
885 spi->selection = selection;
886 spi->ignore_printarea = ignore_printarea;
887 pi->gnmSheets = g_list_append(pi->gnmSheets, spi);
890 static Sheet *
891 print_get_sheet (PrintingInstance *pi, guint page_no)
893 GList *l;
895 for (l = pi->gnmSheets; l != NULL; l = l->next) {
896 SheetPrintInfo *spi = l->data;
897 if (spi->pages > page_no)
898 return spi->sheet;
899 else
900 page_no -= spi->pages;
903 return NULL;
906 static SheetPageRange *
907 print_get_sheet_page_range (PrintingInstance *pi, guint page_no)
909 GList *l;
911 for (l = pi->gnmSheets; l != NULL; l = l->next) {
912 SheetPrintInfo *spi = l->data;
913 if (spi->pages > page_no) {
914 SheetPageRange *gsr;
915 guint col, row;
916 PaginationInfo *c_info, *r_info;
917 Sheet *sheet = spi->sheet;
919 if (sheet->print_info->print_across_then_down) {
920 col = page_no % spi->column_pagination->len;
921 row = page_no / spi->column_pagination->len;
922 } else {
923 col = page_no / spi->row_pagination->len;
924 row = page_no % spi->row_pagination->len;
926 g_return_val_if_fail (col < spi->column_pagination->len &&
927 row < spi->row_pagination->len, NULL);
928 gsr = g_new (SheetPageRange,1);
929 c_info = &(g_array_index (spi->column_pagination,
930 PaginationInfo, col));
931 r_info = &(g_array_index (spi->row_pagination,
932 PaginationInfo, row));
933 range_init (&gsr->range,
934 COL_FIT (c_info->rc), ROW_FIT (r_info->rc),
935 COL_FIT (c_info->rc + c_info->count - 1),
936 ROW_FIT (r_info->rc + r_info->count - 1));
937 gsr->n_rep_cols = c_info->n_rep;
938 gsr->first_rep_cols = c_info->first_rep;
939 gsr->n_rep_rows = r_info->n_rep;
940 gsr->first_rep_rows = r_info->first_rep;
941 gsr->sheet = sheet;
942 return gsr;
943 } else
944 page_no -= spi->pages;
947 return NULL;
951 return TRUE in case of trouble
954 static gboolean
955 compute_sheet_pages (GtkPrintContext *context,
956 PrintingInstance * pi,
957 SheetPrintInfo *spi)
959 Sheet *sheet = spi->sheet;
960 GnmPrintInformation *pinfo = sheet->print_info;
961 GnmRange r;
962 GnmRange const *selection_range;
963 GnmRange print_area;
964 gdouble col_header_height = 0.;
965 gdouble row_header_width = 0.;
966 gdouble page_width, page_height;
967 gdouble top_margin, bottom_margin, edge_to_below_header, edge_to_above_footer;
968 gdouble px, py;
969 gdouble usable_x, usable_y;
970 GArray *column_pagination = g_array_sized_new
971 (FALSE, TRUE, sizeof (PaginationInfo), 100);
972 GArray *row_pagination = g_array_sized_new
973 (FALSE, TRUE, sizeof (PaginationInfo), 100);
974 gboolean repeat_top_use, repeat_left_use;
975 int repeat_top_start, repeat_top_end, repeat_left_start, repeat_left_end;
976 double const hscale = sheet->display_formulas ? 2 : 1;
978 if (pinfo->print_titles) {
979 col_header_height = sheet->rows.default_style.size_pts;
980 row_header_width = sheet->cols.default_style.size_pts;
983 print_area = sheet_get_printarea (sheet,
984 pinfo->print_even_if_only_styles,
985 spi->ignore_printarea);
986 if (spi->selection) {
987 selection_range = selection_first_range
988 (sheet_get_view (sheet, wb_control_view (pi->wbc)),
989 GO_CMD_CONTEXT (pi->wbc), _("Print Selection"));
990 if (selection_range == NULL)
991 return TRUE;
992 if (spi->ignore_printarea) {
993 print_area = *selection_range;
994 } else {
995 if (!range_intersection (&r, selection_range, &print_area))
996 return FALSE;
997 print_area = r;
1001 page_width = gtk_print_context_get_width (context);
1002 page_height = gtk_print_context_get_height (context);
1003 print_info_get_margins (pinfo, &top_margin, &bottom_margin, NULL, NULL,
1004 &edge_to_below_header, &edge_to_above_footer);
1005 page_height -= ((edge_to_below_header - top_margin)
1006 + (edge_to_above_footer - bottom_margin));
1008 repeat_top_use = print_load_repeat_range (pinfo->repeat_top, &r, sheet);
1009 repeat_top_start = repeat_top_use ? r.start.row : 0;
1010 repeat_top_end = repeat_top_use ? r.end.row : 0;
1012 repeat_left_use = print_load_repeat_range (pinfo->repeat_left, &r, sheet);
1013 repeat_left_start = repeat_left_use ? r.start.col : 0;
1014 repeat_left_end = repeat_left_use ? r.end.col : 0;
1016 if (!pi->ignore_pb) {
1017 if (pinfo->page_breaks.h == NULL)
1018 print_info_set_breaks (pinfo,
1019 gnm_page_breaks_new (FALSE));
1020 else
1021 gnm_page_breaks_clean (pinfo->page_breaks.h);
1022 if (pinfo->page_breaks.v == NULL)
1023 print_info_set_breaks (pinfo,
1024 gnm_page_breaks_new (TRUE));
1025 else
1026 gnm_page_breaks_clean (pinfo->page_breaks.v);
1030 if (pinfo->scaling.type == PRINT_SCALE_FIT_PAGES) {
1031 /* Note that the resulting scale is independent from */
1032 /* whether we print first down or across! */
1033 gdouble pxy;
1035 pxy = compute_scale_fit_to (sheet, print_area.start.row, print_area.end.row,
1036 page_height, sheet_row_get_info,
1037 sheet_row_get_distance_pts,
1038 pinfo->scaling.dim.rows, 1.,
1039 col_header_height,
1040 repeat_top_use,
1041 repeat_top_start, repeat_top_end,
1042 pi->ignore_pb ? NULL : pinfo->page_breaks.h);
1043 pxy = compute_scale_fit_to (sheet, print_area.start.col, print_area.end.col,
1044 page_width, sheet_col_get_info,
1045 sheet_col_get_distance_pts,
1046 pinfo->scaling.dim.cols, pxy,
1047 row_header_width,
1048 repeat_left_use,
1049 repeat_left_start, repeat_left_end,
1050 pi->ignore_pb ? NULL : pinfo->page_breaks.v);
1052 pinfo->scaling.percentage.x = pxy * 100.;
1053 pinfo->scaling.percentage.y = pxy * 100.;
1056 px = pinfo->scaling.percentage.x / 100.;
1057 py = pinfo->scaling.percentage.y / 100.;
1059 if (px <= 0.)
1060 px = 1.;
1061 if (py <= 0.)
1062 py = 1.;
1064 usable_x = page_width / px;
1065 usable_y = page_height / py;
1067 paginate (column_pagination, sheet, print_area.start.col, print_area.end.col,
1068 (usable_x - row_header_width)/hscale,
1069 repeat_left_use, repeat_left_start, repeat_left_end,
1070 sheet_col_get_distance_pts, sheet_col_get_info,
1071 pi->ignore_pb ? NULL : pinfo->page_breaks.v, !pi->ignore_pb);
1072 paginate (row_pagination, sheet, print_area.start.row, print_area.end.row,
1073 usable_y - col_header_height,
1074 repeat_top_use, repeat_top_start, repeat_top_end,
1075 sheet_row_get_distance_pts, sheet_row_get_info,
1076 pi->ignore_pb ? NULL : pinfo->page_breaks.h, !pi->ignore_pb);
1078 spi->column_pagination = column_pagination;
1079 spi->row_pagination = row_pagination;
1080 spi->pages = column_pagination->len * row_pagination->len;
1082 return FALSE;
1086 * Computes the pages that will be output by a specific
1087 * print request.
1089 static void
1090 compute_pages (G_GNUC_UNUSED GtkPrintOperation *operation,
1091 PrintingInstance * pi)
1093 Workbook *wb = pi->wb;
1094 guint i;
1095 guint n;
1096 guint ct;
1097 PrintRange pr = pi->pr;
1098 guint from = pi->from;
1099 guint to = pi->to;
1101 switch (pr) {
1102 case GNM_PRINT_SAVED_INFO:
1103 /* This should never happen. */
1104 case GNM_PRINT_ACTIVE_SHEET:
1105 compute_sheet_pages_add_sheet (pi, pi->sheet, FALSE, FALSE);
1106 break;
1107 case GNM_PRINT_ALL_SHEETS:
1108 n = workbook_sheet_count (wb);
1109 for (i = 0; i < n; i++) {
1110 Sheet *sheet = workbook_sheet_by_index (wb, i);
1111 if (sheet->print_info->do_not_print)
1112 continue;
1113 if (!sheet_is_visible(sheet))
1114 continue;
1115 compute_sheet_pages_add_sheet (pi, sheet,
1116 FALSE, FALSE);
1118 break;
1119 case GNM_PRINT_ALL_SHEETS_INCLUDING_HIDDEN:
1120 n = workbook_sheet_count (wb);
1121 for (i = 0; i < n; i++) {
1122 Sheet *sheet = workbook_sheet_by_index (wb, i);
1123 if (sheet->print_info->do_not_print)
1124 continue;
1125 compute_sheet_pages_add_sheet (pi, sheet,
1126 FALSE, FALSE);
1128 break;
1129 case GNM_PRINT_SHEET_RANGE:
1130 if (from > to)
1131 break;
1132 n = workbook_sheet_count (wb);
1133 ct = 0;
1134 for (i = 0; i < n; i++){
1135 Sheet *sheet = workbook_sheet_by_index (wb, i);
1136 if (sheet_is_visible(sheet))
1137 ct++;
1138 else
1139 continue;
1140 if (sheet->print_info->do_not_print)
1141 continue;
1142 if ((ct >= from) && (ct <= to))
1143 compute_sheet_pages_add_sheet (pi, sheet,
1144 FALSE, FALSE);
1146 break;
1147 case GNM_PRINT_SHEET_SELECTION:
1148 compute_sheet_pages_add_sheet (pi, pi->sheet, TRUE, FALSE);
1149 break;
1150 case GNM_PRINT_IGNORE_PRINTAREA:
1151 compute_sheet_pages_add_sheet (pi, pi->sheet, FALSE, TRUE);
1152 break;
1153 case GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA:
1154 compute_sheet_pages_add_sheet (pi, pi->sheet, TRUE, TRUE);
1155 break;
1157 return;
1160 #if 0
1162 static PrintJobInfo *
1163 print_job_info_get (Sheet *sheet, PrintRange range, gboolean const preview)
1165 PrintJobInfo *pj = g_new0 (PrintJobInfo, 1);
1167 pj->gp_config = print_info_make_config (sheet->print_info);
1169 /* Values that should be entered in a dialog box */
1170 pj->start_page = 0;
1171 pj->end_page = workbook_sheet_count (sheet->workbook) - 1;
1172 pj->range = range;
1173 pj->sorted_print = TRUE;
1174 pj->is_preview = preview;
1175 pj->current_output_sheet = 0;
1178 * Setup render info
1180 pj->render_info = gnm_print_hf_render_info_new ();
1181 pj->render_info->sheet = sheet;
1182 pj->render_info->page = 1;
1184 return pj;
1187 static void
1188 print_job_info_destroy (PrintJobInfo *pj)
1190 g_object_unref (pj->gp_config);
1191 gnm_print_hf_render_info_destroy (pj->render_info);
1192 if (pj->decoration_layout)
1193 g_object_unref (pj->decoration_layout);
1194 if (pj->print_context)
1195 g_object_unref (pj->print_context);
1196 g_free (pj);
1199 #endif
1201 static gboolean
1202 gnm_paginate_cb (GtkPrintOperation *operation,
1203 GtkPrintContext *context,
1204 gpointer user_data)
1206 PrintingInstance * pi = (PrintingInstance *) user_data;
1207 guint paginate = (pi->last_pagination)++;
1208 SheetPrintInfo *spi;
1210 if (gnm_debug_flag ("print"))
1211 g_printerr ("paginate %d\n", paginate);
1213 spi = g_list_nth_data (pi->gnmSheets, paginate);
1214 if (spi == NULL) { /*We are done paginating */
1215 /* GTK sends additional pagination requests! */
1216 /* We only need to do this once though! */
1217 if (g_list_nth_data (pi->gnmSheets, paginate - 1) != NULL) {
1218 GList *l;
1219 gint n_pages = 0;
1221 for (l = pi->gnmSheets; l != NULL; l = l->next) {
1222 SheetPrintInfo *spi = l->data;
1223 n_pages += spi->pages;
1226 if (pi->preview && n_pages > 1000) {
1227 int i, count = 0;
1229 gtk_print_operation_set_n_pages
1230 (operation, n_pages == 0 ? 1 : n_pages);
1231 for (i = 0; i < n_pages; i++) {
1232 if (gtk_print_operation_preview_is_selected
1233 (GTK_PRINT_OPERATION_PREVIEW (operation),
1235 count++;
1236 if (count > 1000)
1237 break;
1239 if (count > 1000 && !go_gtk_query_yes_no
1240 (pi->progress != NULL ?
1241 GTK_WINDOW (pi->progress) : wbcg_toplevel (WBC_GTK (pi->wbc)),
1242 FALSE, "%s",
1243 _("You have chosen more than 1000 pages to preview. "
1244 "This may take a long time. "
1245 "Do you really want to proceed?")))
1246 n_pages = 0;
1249 gtk_print_operation_set_n_pages (operation, n_pages == 0 ? 1 : n_pages);
1250 gtk_print_operation_set_unit (operation, GTK_UNIT_POINTS);
1251 pi->hfi->pages = n_pages;
1253 if (n_pages == 0) /* gtk+ cannot handle 0 pages */
1254 gtk_print_operation_cancel (operation);
1256 return TRUE;
1259 if (compute_sheet_pages (context, pi, spi)) {
1260 gtk_print_operation_cancel (operation);
1261 return TRUE;
1264 return FALSE;
1267 static void
1268 cb_progress_response (G_GNUC_UNUSED GtkDialog *dialog,
1269 G_GNUC_UNUSED gint response_id,
1270 PrintingInstance *pi)
1272 pi->cancel = TRUE;
1275 static gboolean
1276 cb_progress_delete (G_GNUC_UNUSED GtkWidget *widget,
1277 G_GNUC_UNUSED GdkEvent *event,
1278 PrintingInstance *pi)
1280 pi->cancel = TRUE;
1281 return TRUE;
1284 static gboolean
1285 gnm_ready_preview_cb (G_GNUC_UNUSED GtkPrintOperation *operation,
1286 G_GNUC_UNUSED GtkPrintOperationPreview *preview,
1287 G_GNUC_UNUSED GtkPrintContext *context,
1288 G_GNUC_UNUSED GtkWindow *parent,
1289 gpointer user_data)
1291 PrintingInstance * pi = (PrintingInstance *) user_data;
1292 pi->preview = TRUE;
1294 return FALSE;
1297 static void
1298 gnm_begin_print_cb (GtkPrintOperation *operation,
1299 G_GNUC_UNUSED GtkPrintContext *context,
1300 gpointer user_data)
1302 PrintingInstance * pi = (PrintingInstance *) user_data;
1304 if (gnm_debug_flag ("print"))
1305 g_printerr ("begin-print\n");
1308 /* Working around gtk+ bug 423484. */
1309 GtkPrintSettings *settings = gtk_print_operation_get_print_settings (operation);
1310 gtk_print_settings_set_int
1311 (settings, GNUMERIC_PRINT_SETTING_PRINT_FROM_SHEET_KEY,
1312 pi->from);
1313 gtk_print_settings_set_int
1314 (settings, GNUMERIC_PRINT_SETTING_PRINT_TO_SHEET_KEY,
1315 pi->to);
1316 gtk_print_settings_set_int
1317 (settings, GNUMERIC_PRINT_SETTING_PRINTRANGE_KEY, pi->pr);
1318 gtk_print_settings_set_int
1319 (settings, GNUMERIC_PRINT_SETTING_IGNORE_PAGE_BREAKS_KEY, pi->ignore_pb ? 1 : 0);
1322 if (NULL != pi->wbc && GNM_IS_WBC_GTK(pi->wbc)) {
1323 pi->progress = gtk_message_dialog_new (wbcg_toplevel (WBC_GTK (pi->wbc)),
1324 GTK_DIALOG_MODAL |
1325 GTK_DIALOG_DESTROY_WITH_PARENT,
1326 GTK_MESSAGE_INFO,
1327 GTK_BUTTONS_CANCEL,
1328 "%s", /* please clang */
1329 pi->preview ?
1330 _("Preparing to preview"):
1331 _("Preparing to print"));
1332 g_signal_connect (G_OBJECT (pi->progress), "response",
1333 G_CALLBACK (cb_progress_response), pi);
1334 g_signal_connect (G_OBJECT (pi->progress), "delete-event",
1335 G_CALLBACK (cb_progress_delete), pi);
1336 gtk_widget_show_all (pi->progress);
1339 compute_pages (operation, pi);
1342 static void
1343 gnm_end_print_cb (G_GNUC_UNUSED GtkPrintOperation *operation,
1344 G_GNUC_UNUSED GtkPrintContext *context,
1345 G_GNUC_UNUSED gpointer user_data)
1347 if (gnm_debug_flag ("print"))
1348 g_printerr ("end-print\n");
1351 static void
1352 cp_gtk_page_setup (GtkPageSetup *from, GtkPageSetup *to)
1354 gtk_page_setup_set_paper_size (to, gtk_page_setup_get_paper_size (from));
1355 gtk_page_setup_set_orientation (to,gtk_page_setup_get_orientation (from));
1356 gtk_page_setup_set_top_margin
1357 (to, gtk_page_setup_get_top_margin (from, GTK_UNIT_MM), GTK_UNIT_MM);
1358 gtk_page_setup_set_bottom_margin
1359 (to, gtk_page_setup_get_bottom_margin (from, GTK_UNIT_MM), GTK_UNIT_MM);
1360 gtk_page_setup_set_left_margin
1361 (to, gtk_page_setup_get_left_margin (from, GTK_UNIT_MM), GTK_UNIT_MM);
1362 gtk_page_setup_set_right_margin
1363 (to, gtk_page_setup_get_right_margin (from, GTK_UNIT_MM), GTK_UNIT_MM);
1366 static void
1367 gnm_request_page_setup_cb (GtkPrintOperation *operation,
1368 G_GNUC_UNUSED GtkPrintContext *context,
1369 gint page_nr,
1370 GtkPageSetup *setup,
1371 gpointer user_data)
1373 PrintingInstance * pi = (PrintingInstance *) user_data;
1374 Sheet *sheet;
1375 GtkPrintSettings* settings = gtk_print_operation_get_print_settings
1376 (operation);
1378 g_return_if_fail (pi != NULL);
1380 sheet = print_get_sheet (pi, page_nr);
1382 if (sheet == NULL) {
1383 /* g_warning ("Avoiding gtk+ bug 492498"); */
1384 return;
1387 gtk_print_settings_set_use_color (settings, !sheet->print_info->print_black_and_white);
1388 if (sheet->print_info->page_setup == NULL)
1389 gnm_print_info_load_defaults (sheet->print_info);
1390 if (sheet->print_info->page_setup != NULL)
1391 cp_gtk_page_setup (sheet->print_info->page_setup, setup);
1394 static void
1395 gnm_draw_page_cb (GtkPrintOperation *operation,
1396 GtkPrintContext *context,
1397 gint page_nr,
1398 gpointer user_data)
1401 PrintingInstance * pi = (PrintingInstance *) user_data;
1402 SheetPageRange * gsr;
1404 if (gnm_debug_flag ("print"))
1405 g_printerr ("draw-page %d\n", page_nr);
1407 if (pi->cancel) {
1408 gtk_print_operation_cancel (operation);
1409 g_signal_handlers_disconnect_by_func
1410 (G_OBJECT (operation), G_CALLBACK (gnm_draw_page_cb), user_data);
1411 return;
1414 gsr = print_get_sheet_page_range (pi, page_nr);
1415 if (gsr) {
1416 if (pi->progress) {
1417 char *text;
1419 if (pi->hfi->pages == -1)
1420 text = g_strdup_printf
1421 (pi->preview ? _("Creating preview of page %3d")
1422 : _("Printing page %3d"), page_nr);
1423 else
1424 text = g_strdup_printf
1425 (pi->preview ?
1426 ngettext("Creating preview of page %3d of %3d page",
1427 "Creating preview of page %3d of %3d pages",
1428 pi->hfi->pages)
1429 : ngettext("Printing page %3d of %3d page",
1430 "Printing page %3d of %3d pages",
1431 pi->hfi->pages),
1432 page_nr, pi->hfi->pages);
1433 g_object_set (G_OBJECT (pi->progress), "text", text, NULL);
1434 g_free (text);
1436 pi->hfi->page = page_nr + 1;
1437 pi->hfi->sheet = gsr->sheet;
1438 pi->hfi->page_area = gsr->range;
1439 pi->hfi->top_repeating = gsr->range.start;
1440 if (gsr->n_rep_cols > 0)
1441 pi->hfi->top_repeating.col = gsr->first_rep_cols;
1442 if (gsr->n_rep_rows > 0)
1443 pi->hfi->top_repeating.row = gsr->first_rep_rows;
1444 print_page (operation, context, pi, gsr);
1445 g_free (gsr);
1449 static void
1450 widget_button_cb (GtkToggleButton *togglebutton, GtkWidget *check)
1452 gtk_widget_set_sensitive (check, gtk_toggle_button_get_active (togglebutton));
1455 static guint
1456 workbook_visible_sheet_count (Workbook *wb)
1458 guint i;
1459 guint n = workbook_sheet_count (wb);
1460 guint count = 0;
1462 for (i = 0; i < n; i++) {
1463 Sheet *sheet = workbook_sheet_by_index (wb, i);
1464 if (sheet_is_visible(sheet))
1465 count++;
1467 return count;
1470 static GObject*
1471 gnm_create_widget_cb (GtkPrintOperation *operation, gpointer user_data)
1473 PrintingInstance * pi = (PrintingInstance *) user_data;
1474 GtkWidget *grid;
1475 GtkWidget *button_all_sheets, *button_selected_sheet, *button_spec_sheets;
1476 GtkWidget *button_selection, *button_ignore_printarea;
1477 GtkWidget *button_print_hidden_sheets;
1478 GtkWidget *label_from, *label_to;
1479 GtkWidget *spin_from, *spin_to;
1480 GtkWidget *button_ignore_page_breaks;
1481 GtkPrintSettings * settings;
1482 guint n_sheets = workbook_visible_sheet_count (pi->wb);
1484 if (gnm_debug_flag ("print"))
1485 g_printerr ("Creating custom print widget\n");
1487 grid = gtk_grid_new ();
1488 g_object_set (grid,
1489 "column-spacing", 12,
1490 "row-spacing", 6,
1491 "border-width", 6,
1492 NULL);
1494 button_all_sheets = gtk_radio_button_new_with_mnemonic (NULL,
1495 _("_All workbook sheets"));
1496 gtk_widget_set_hexpand (button_all_sheets, TRUE);
1497 gtk_grid_attach (GTK_GRID (grid), button_all_sheets, 0, 0, 5, 1);
1499 button_print_hidden_sheets = gtk_check_button_new_with_mnemonic
1500 (_("Also print _hidden sheets"));
1501 g_object_set (button_print_hidden_sheets,
1502 "hexpand", TRUE,
1503 "margin-left", 24,
1504 NULL);
1505 gtk_grid_attach (GTK_GRID (grid), button_print_hidden_sheets, 0, 1, 5, 1);
1507 button_selected_sheet = gtk_radio_button_new_with_mnemonic_from_widget
1508 (GTK_RADIO_BUTTON (button_all_sheets), _("A_ctive workbook sheet"));
1509 gtk_widget_set_hexpand (button_selected_sheet, TRUE);
1510 gtk_grid_attach (GTK_GRID (grid), button_selected_sheet, 0, 2, 5, 1);
1512 button_spec_sheets = gtk_radio_button_new_with_mnemonic_from_widget
1513 (GTK_RADIO_BUTTON (button_all_sheets), _("_Workbook sheets:"));
1514 gtk_widget_set_hexpand (button_spec_sheets, TRUE);
1515 gtk_grid_attach (GTK_GRID (grid), button_spec_sheets, 0, 5, 1, 1);
1517 button_selection = gtk_check_button_new_with_mnemonic
1518 (_("Current _selection only"));
1519 g_object_set (button_selection,
1520 "hexpand", TRUE,
1521 "margin-left", 24,
1522 NULL);
1523 gtk_grid_attach (GTK_GRID (grid), button_selection, 0, 3, 5, 1);
1525 button_ignore_printarea = gtk_check_button_new_with_mnemonic
1526 (_("_Ignore defined print area"));
1527 g_object_set (button_ignore_printarea,
1528 "hexpand", TRUE,
1529 "margin-left", 24,
1530 NULL);
1531 gtk_grid_attach (GTK_GRID (grid), button_ignore_printarea, 0, 4, 5, 1);
1533 label_from = gtk_label_new (_("from:"));
1534 g_object_set (label_from,
1535 "hexpand", TRUE,
1536 "margin-left", 24,
1537 NULL);
1538 gtk_grid_attach (GTK_GRID (grid), label_from, 1, 5, 1, 1);
1540 spin_from = gtk_spin_button_new_with_range (1, n_sheets, 1);
1541 gtk_widget_set_hexpand (spin_from, TRUE);
1542 gtk_grid_attach (GTK_GRID (grid), spin_from, 2, 5, 1, 1);
1544 label_to = gtk_label_new (_("to:"));
1545 gtk_widget_set_hexpand (label_to, TRUE);
1546 gtk_grid_attach (GTK_GRID (grid), label_to, 3, 5, 1, 1);
1548 spin_to = gtk_spin_button_new_with_range (1, n_sheets, 1);
1549 gtk_widget_set_hexpand (spin_to, TRUE);
1550 gtk_grid_attach (GTK_GRID (grid), spin_to, 4, 5, 1, 1);
1551 gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin_to), n_sheets);
1553 button_ignore_page_breaks = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
1554 gtk_widget_set_hexpand (button_ignore_page_breaks, TRUE);
1555 gtk_grid_attach (GTK_GRID (grid), button_ignore_page_breaks, 0, 6, 5, 1);
1557 button_ignore_page_breaks = gtk_check_button_new_with_mnemonic (_("Ignore all _manual page breaks"));
1558 gtk_widget_set_hexpand (button_ignore_page_breaks, TRUE);
1559 gtk_grid_attach (GTK_GRID (grid), button_ignore_page_breaks, 0, 7, 5, 1);
1560 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_ignore_page_breaks), TRUE);
1562 g_signal_connect_after (G_OBJECT (button_selected_sheet), "toggled",
1563 G_CALLBACK (widget_button_cb), button_selection);
1564 g_signal_connect_after (G_OBJECT (button_selected_sheet), "toggled",
1565 G_CALLBACK (widget_button_cb), button_ignore_printarea);
1567 g_signal_connect_after (G_OBJECT (button_all_sheets), "toggled",
1568 G_CALLBACK (widget_button_cb), button_print_hidden_sheets);
1570 g_signal_connect_after (G_OBJECT (button_spec_sheets), "toggled",
1571 G_CALLBACK (widget_button_cb), label_from);
1572 g_signal_connect_after (G_OBJECT (button_spec_sheets), "toggled",
1573 G_CALLBACK (widget_button_cb), label_to);
1574 g_signal_connect_after (G_OBJECT (button_spec_sheets), "toggled",
1575 G_CALLBACK (widget_button_cb), spin_from);
1576 g_signal_connect_after (G_OBJECT (button_spec_sheets), "toggled",
1577 G_CALLBACK (widget_button_cb), spin_to);
1579 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_selected_sheet), TRUE);
1581 settings = gtk_print_operation_get_print_settings (operation);
1583 if (settings) {
1584 switch (gtk_print_settings_get_int_with_default
1585 (settings, GNUMERIC_PRINT_SETTING_PRINTRANGE_KEY,
1586 GNM_PRINT_ACTIVE_SHEET)) {
1587 case GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA:
1588 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_ignore_printarea), TRUE);
1589 /* no break */
1590 case GNM_PRINT_SHEET_SELECTION:
1591 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_selection), TRUE);
1592 /* no break */
1593 case GNM_PRINT_ACTIVE_SHEET:
1594 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_selected_sheet), TRUE);
1595 break;
1596 case GNM_PRINT_IGNORE_PRINTAREA:
1597 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_ignore_printarea), TRUE);
1598 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_selected_sheet), TRUE);
1599 break;
1600 case GNM_PRINT_SHEET_RANGE:
1601 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_spec_sheets), TRUE);
1602 break;
1603 case GNM_PRINT_ALL_SHEETS_INCLUDING_HIDDEN:
1604 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_print_hidden_sheets), TRUE);
1605 /* no break */
1606 case GNM_PRINT_ALL_SHEETS:
1607 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_all_sheets), TRUE);
1608 break;
1611 gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin_from),
1612 gtk_print_settings_get_int_with_default
1613 (settings, GNUMERIC_PRINT_SETTING_PRINT_FROM_SHEET_KEY,
1614 1));
1615 gtk_spin_button_set_value (GTK_SPIN_BUTTON (spin_to),
1616 gtk_print_settings_get_int_with_default
1617 (settings, GNUMERIC_PRINT_SETTING_PRINT_TO_SHEET_KEY,
1618 n_sheets));
1619 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_ignore_page_breaks),
1620 0 != gtk_print_settings_get_int_with_default
1621 (settings, GNUMERIC_PRINT_SETTING_IGNORE_PAGE_BREAKS_KEY,
1622 0));
1625 /* We are sending toggled signals to ensure that all widgets are */
1626 /* correctly enabled or disabled. */
1627 gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (button_selected_sheet));
1628 gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (button_spec_sheets));
1630 gtk_widget_show_all (grid);
1632 /* Let's save the widgets */
1633 pi->button_all_sheets = button_all_sheets;
1634 pi->button_selected_sheet = button_selected_sheet;
1635 pi->button_spec_sheets = button_spec_sheets;
1636 pi->button_selection = button_selection;
1637 pi->button_ignore_printarea = button_ignore_printarea;
1638 pi->button_print_hidden_sheets = button_print_hidden_sheets;
1639 pi->spin_from = spin_from;
1640 pi->spin_to = spin_to;
1641 pi->button_ignore_page_breaks = button_ignore_page_breaks;
1643 if (gnm_debug_flag ("print"))
1644 g_printerr ("Done with creating custom print widget\n");
1646 return G_OBJECT (grid);
1649 static void
1650 gnm_custom_widget_apply_cb (GtkPrintOperation *operation,
1651 G_GNUC_UNUSED GtkWidget *widget,
1652 gpointer user_data)
1654 PrintingInstance * pi = (PrintingInstance *) user_data;
1655 GtkPrintSettings * settings;
1656 PrintRange pr = GNM_PRINT_ACTIVE_SHEET;
1657 guint from, to;
1658 gboolean ignore_pb;
1660 settings = gtk_print_operation_get_print_settings (operation);
1662 g_return_if_fail (settings != NULL);
1664 from = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (pi->spin_from));
1665 to = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (pi->spin_to));
1667 gtk_print_settings_set_int (settings,
1668 GNUMERIC_PRINT_SETTING_PRINT_FROM_SHEET_KEY,
1669 from);
1670 gtk_print_settings_set_int (settings,
1671 GNUMERIC_PRINT_SETTING_PRINT_TO_SHEET_KEY,
1672 to);
1673 pi->from = from;
1674 pi->to = to;
1676 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pi->button_all_sheets))) {
1677 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pi->button_print_hidden_sheets)))
1678 pr = GNM_PRINT_ALL_SHEETS_INCLUDING_HIDDEN;
1679 else
1680 pr = GNM_PRINT_ALL_SHEETS;
1681 } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pi->button_spec_sheets))) {
1682 pr = GNM_PRINT_SHEET_RANGE;
1683 } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pi->button_selected_sheet))) {
1684 gboolean ignore_printarea = gtk_toggle_button_get_active
1685 (GTK_TOGGLE_BUTTON (pi->button_ignore_printarea));
1686 gboolean selection = gtk_toggle_button_get_active
1687 (GTK_TOGGLE_BUTTON (pi->button_selection));
1688 if (selection && ignore_printarea)
1689 pr = GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA;
1690 else if (selection)
1691 pr = GNM_PRINT_SHEET_SELECTION;
1692 else if (ignore_printarea)
1693 pr = GNM_PRINT_IGNORE_PRINTAREA;
1694 else
1695 pr = GNM_PRINT_ACTIVE_SHEET;
1698 gtk_print_settings_set_int (settings,
1699 GNUMERIC_PRINT_SETTING_PRINTRANGE_KEY, pr);
1701 pi->pr = pr;
1703 ignore_pb= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pi->button_ignore_page_breaks)) ? 1 : 0;
1704 gtk_print_settings_set_int (settings, GNUMERIC_PRINT_SETTING_IGNORE_PAGE_BREAKS_KEY,
1705 ignore_pb);
1706 pi->ignore_pb = ignore_pb;
1709 static void
1710 cb_delete_and_free (char *tmp_file_name)
1712 if (tmp_file_name) {
1713 g_unlink (tmp_file_name);
1714 g_free (tmp_file_name);
1718 static gchar *
1719 gnm_print_uri_change_extension (char const *uri, GtkPrintSettings* settings)
1721 const gchar *ext = gtk_print_settings_get
1722 (settings,
1723 GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
1724 gchar *base;
1725 gchar *used_ext;
1726 gint strip;
1727 gchar *res;
1728 gint uri_len = strlen(uri);
1730 if (ext == NULL) {
1731 ext = "pdf";
1732 gtk_print_settings_set (settings,
1733 GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT,
1734 ext);
1737 base = g_path_get_basename (uri);
1738 used_ext = strrchr (base, '.');
1739 if (used_ext == NULL)
1740 return g_strconcat (uri, ".", ext, NULL);
1741 strip = strlen (base) - (used_ext - base);
1742 res = g_strndup (uri, uri_len - strip + 1 + strlen (ext));
1743 res[uri_len - strip] = '.';
1744 strcpy (res + uri_len - strip + 1, ext);
1745 return res;
1748 void
1749 gnm_print_sheet (WorkbookControl *wbc, Sheet *sheet,
1750 gboolean preview, PrintRange default_range,
1751 GsfOutput *export_dst)
1753 GtkPrintOperation *print;
1754 GtkPrintOperationResult res;
1755 GtkPageSetup *page_setup;
1756 PrintingInstance *pi;
1757 GtkPrintSettings* settings;
1758 GtkWindow *parent = NULL;
1759 GtkPrintOperationAction action;
1760 gchar *tmp_file_name = NULL;
1761 int tmp_file_fd = -1;
1762 gboolean preview_via_pdf = FALSE;
1763 PrintRange pr_translator[] = {GNM_PRINT_ACTIVE_SHEET, GNM_PRINT_ALL_SHEETS,
1764 GNM_PRINT_ALL_SHEETS, GNM_PRINT_ACTIVE_SHEET,
1765 GNM_PRINT_SHEET_SELECTION, GNM_PRINT_ACTIVE_SHEET,
1766 GNM_PRINT_SHEET_SELECTION_IGNORE_PRINTAREA};
1767 GODoc *doc;
1768 gchar *output_uri = NULL;
1769 gchar const *saved_uri = NULL;
1771 #ifdef PREVIEW_VIA_PDF
1772 preview_via_pdf = preview;
1773 #endif
1775 g_return_if_fail (sheet != NULL && sheet->workbook != NULL);
1777 if (preview)
1778 g_return_if_fail (!export_dst && wbc);
1780 doc = GO_DOC (sheet->workbook);
1782 print = gtk_print_operation_new ();
1784 pi = printing_instance_new ();
1785 pi->wb = sheet->workbook;
1786 pi->wbc = wbc ? GNM_WBC (wbc) : NULL;
1787 pi->sheet = sheet;
1788 pi->preview = preview;
1790 settings = gnm_conf_get_print_settings ();
1791 if (default_range == GNM_PRINT_SAVED_INFO) {
1792 gint dr = print_info_get_printrange (sheet->print_info);
1793 if (dr < 0 || dr >= (gint)G_N_ELEMENTS (pr_translator))
1794 default_range = GNM_PRINT_ACTIVE_SHEET;
1795 else
1796 default_range = pr_translator[dr];
1798 gtk_print_settings_set_int (settings,
1799 GNUMERIC_PRINT_SETTING_PRINTRANGE_KEY,
1800 default_range);
1801 pi->pr = default_range;
1802 gtk_print_settings_set_use_color (settings,
1803 !sheet->print_info->print_black_and_white);
1804 if (!export_dst && !preview_via_pdf && !preview) {
1805 /* We should be setting the output file name to something */
1806 /* reasonable */
1807 saved_uri = print_info_get_printtofile_uri (sheet->print_info);
1808 if (saved_uri != NULL &&
1809 g_ascii_strncasecmp (doc->uri, "file:///", 8) == 0)
1810 output_uri = gnm_print_uri_change_extension (saved_uri,
1811 settings);
1812 else
1813 saved_uri = NULL;
1814 if (output_uri == NULL && doc->uri != NULL
1815 && g_ascii_strncasecmp (doc->uri, "file:///", 8) == 0)
1816 output_uri = gnm_print_uri_change_extension (doc->uri,
1817 settings);
1818 if (output_uri != NULL) {
1819 gtk_print_settings_set (settings,
1820 GTK_PRINT_SETTINGS_OUTPUT_URI,
1821 output_uri);
1822 g_free (output_uri);
1826 gtk_print_operation_set_print_settings (print, settings);
1827 g_object_unref (settings);
1829 page_setup = gnm_print_info_get_page_setup (sheet->print_info);
1830 if (page_setup)
1831 gtk_print_operation_set_default_page_setup (print, page_setup);
1833 g_signal_connect (print, "preview", G_CALLBACK (gnm_ready_preview_cb), pi);
1834 g_signal_connect (print, "begin-print", G_CALLBACK (gnm_begin_print_cb), pi);
1835 g_signal_connect (print, "paginate", G_CALLBACK (gnm_paginate_cb), pi);
1836 g_signal_connect (print, "draw-page", G_CALLBACK (gnm_draw_page_cb), pi);
1837 g_signal_connect (print, "end-print", G_CALLBACK (gnm_end_print_cb), pi);
1838 g_signal_connect (print, "request-page-setup", G_CALLBACK (gnm_request_page_setup_cb), pi);
1840 gtk_print_operation_set_use_full_page (print, FALSE);
1841 gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
1843 if (NULL != wbc && GNM_IS_WBC_GTK(wbc))
1844 parent = wbcg_toplevel (WBC_GTK (wbc));
1846 if (preview_via_pdf || export_dst) {
1847 GError *err = NULL;
1849 tmp_file_fd = g_file_open_tmp ("gnmXXXXXX.pdf",
1850 &tmp_file_name, &err);
1851 if (err) {
1852 if (export_dst)
1853 gsf_output_set_error (export_dst, 0,
1854 "%s", err->message);
1855 else {
1856 char *text = g_strdup_printf
1857 (_("Failed to create temporary file for printing: %s"),
1858 err->message);
1859 go_cmd_context_error_export
1860 (GO_CMD_CONTEXT (wbc), text);
1861 g_free (text);
1863 g_error_free (err);
1864 goto out;
1867 action = GTK_PRINT_OPERATION_ACTION_EXPORT;
1868 gtk_print_operation_set_export_filename (print, tmp_file_name);
1869 gtk_print_operation_set_show_progress (print, FALSE);
1870 } else {
1871 action = preview
1872 ? GTK_PRINT_OPERATION_ACTION_PREVIEW
1873 : GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
1874 gtk_print_operation_set_show_progress (print, FALSE);
1875 gtk_print_operation_set_custom_tab_label (print, _("Gnumeric Print Range"));
1876 g_signal_connect (print, "create-custom-widget", G_CALLBACK (gnm_create_widget_cb), pi);
1877 g_signal_connect (print, "custom-widget-apply", G_CALLBACK (gnm_custom_widget_apply_cb), pi);
1880 res = gtk_print_operation_run (print, action, parent, NULL);
1882 switch (res) {
1883 case GTK_PRINT_OPERATION_RESULT_APPLY:
1884 if (action == GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG) {
1885 char const *printer;
1886 settings = gtk_print_operation_get_print_settings (print);
1887 gnm_conf_set_print_settings (settings);
1888 gnm_insert_meta_date (doc, GSF_META_NAME_PRINT_DATE);
1889 printer = gtk_print_settings_get_printer (settings);
1890 if (strcmp (printer, "Print to File") == 0 ||
1891 strcmp (printer, _("Print to File")) == 0) {
1892 gchar *wb_output_uri =
1893 gnm_print_uri_change_extension (doc->uri,
1894 settings);
1895 print_info_set_printtofile_from_settings
1896 (sheet->print_info, settings, wb_output_uri);
1897 g_free (wb_output_uri);
1900 print_info_set_from_settings
1901 (sheet->print_info, settings);
1902 break;
1903 case GTK_PRINT_OPERATION_RESULT_CANCEL:
1904 break;
1905 case GTK_PRINT_OPERATION_RESULT_ERROR:
1906 break;
1907 case GTK_PRINT_OPERATION_RESULT_IN_PROGRESS:
1908 /* This can only happen if we were allowing asynchronous operation */
1909 break;
1910 default: ;
1912 printing_instance_delete (pi);
1914 if (preview_via_pdf) {
1915 #ifdef G_OS_WIN32
1916 /* For some reason the general code doesn't work for me.
1917 Be brutal, even if this might not work for non-ASCII
1918 filenames. */
1919 int res = (int)ShellExecute (NULL, "open",
1920 tmp_file_name,
1921 NULL,
1922 NULL,
1923 SW_SHOW);
1924 if (gnm_debug_flag ("preview")) {
1925 g_printerr ("tmp_file_name=%s\n", tmp_file_name);
1926 g_printerr ("res=%d\n", res);
1928 #else
1929 GdkScreen *screen = parent
1930 ? gtk_widget_get_screen (GTK_WIDGET (parent))
1931 : NULL;
1932 char *url = go_filename_to_uri (tmp_file_name);
1933 go_gtk_url_show (url, screen);
1934 g_free (url);
1935 #endif
1937 /* We hook this up to delete the temp file when the workbook
1938 is closed or when a new preview is done for the same
1939 workbook. That's not perfect, but good enough while
1940 we wait for gtk+ to fix printing. */
1941 g_object_set_data_full (G_OBJECT (wbc),
1942 "temp-file", tmp_file_name,
1943 (GDestroyNotify)cb_delete_and_free);
1944 tmp_file_name = NULL;
1945 } else if (tmp_file_name) {
1946 char buffer[64 * 1024];
1947 gssize bytes_read;
1949 if (lseek (tmp_file_fd, 0, SEEK_SET) < 0)
1950 bytes_read = -1;
1951 else {
1952 while ((bytes_read = read (tmp_file_fd, buffer, sizeof (buffer))) > 0) {
1953 gsf_output_write (export_dst, bytes_read, buffer);
1956 if (bytes_read < 0) {
1957 int save_errno = errno;
1958 if (!gsf_output_error (export_dst))
1959 gsf_output_set_error (export_dst,
1960 g_file_error_from_errno (save_errno),
1961 "%s", g_strerror (save_errno));
1965 out:
1966 if (tmp_file_fd >= 0)
1967 close (tmp_file_fd);
1968 cb_delete_and_free (tmp_file_name);
1970 g_object_unref (print);
1973 static void
1974 gnm_draw_so_page_cb (G_GNUC_UNUSED GtkPrintOperation *operation,
1975 GtkPrintContext *context,
1976 G_GNUC_UNUSED gint page_nr,
1977 gpointer user_data)
1980 SheetObject *so = (SheetObject *) user_data;
1981 cairo_t *cr= gtk_print_context_get_cairo_context (context);
1982 Sheet *sheet = sheet_object_get_sheet (so);
1984 cairo_save (cr);
1985 cairo_translate (cr, 0, 0);
1986 sheet_object_draw_cairo (so, (gpointer)cr, sheet->text_is_rtl);
1987 cairo_restore (cr);
1991 * gnm_print_so:
1992 * @wbc:
1993 * @sos: (element-type SheetObject) (transfer none):
1994 * @export_dst:
1996 void
1997 gnm_print_so (WorkbookControl *wbc, GPtrArray *sos,
1998 GsfOutput *export_dst)
2000 GtkPrintOperation *print;
2001 GtkPageSetup *page_setup;
2002 GtkPrintSettings* settings;
2003 Sheet *sheet;
2004 GtkWindow *parent = NULL;
2005 GtkPrintOperationAction action;
2006 gchar *tmp_file_name = NULL;
2007 int tmp_file_fd = -1;
2008 SheetObject *so;
2010 g_return_if_fail (sos != NULL && sos->len > 0);
2012 /* FIXME: we should print all objects in the array, not just the first! */
2014 so = g_ptr_array_index (sos, 0),
2015 sheet = sheet_object_get_sheet (so);
2016 if (NULL != wbc && GNM_IS_WBC_GTK(wbc))
2017 parent = wbcg_toplevel (WBC_GTK (wbc));
2019 print = gtk_print_operation_new ();
2021 settings = gnm_conf_get_print_settings ();
2022 gtk_print_settings_set_use_color (settings,
2023 !sheet->print_info->print_black_and_white);
2024 gtk_print_operation_set_print_settings (print, settings);
2025 g_object_unref (settings);
2027 page_setup = gnm_print_info_get_page_setup (sheet->print_info);
2028 if (page_setup)
2029 gtk_print_operation_set_default_page_setup (print, page_setup);
2031 gtk_print_operation_set_n_pages (print, 1);
2032 gtk_print_operation_set_embed_page_setup (print, TRUE);
2034 g_signal_connect (print, "draw-page", G_CALLBACK (gnm_draw_so_page_cb), so);
2036 gtk_print_operation_set_use_full_page (print, FALSE);
2037 gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
2039 if (export_dst) {
2040 GError *err = NULL;
2042 tmp_file_fd = g_file_open_tmp ("gnmXXXXXX.pdf",
2043 &tmp_file_name, &err);
2044 if (err) {
2045 gsf_output_set_error (export_dst, 0,
2046 "%s", err->message);
2047 g_error_free (err);
2048 if (tmp_file_fd >= 0)
2049 close (tmp_file_fd);
2050 cb_delete_and_free (tmp_file_name);
2052 g_object_unref (print);
2053 return;
2055 action = GTK_PRINT_OPERATION_ACTION_EXPORT;
2056 gtk_print_operation_set_export_filename (print, tmp_file_name);
2057 gtk_print_operation_set_show_progress (print, FALSE);
2058 } else {
2059 action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
2060 gtk_print_operation_set_show_progress (print, TRUE);
2063 gtk_print_operation_run (print, action, parent, NULL);
2065 if (tmp_file_name) {
2066 char buffer[64 * 1024];
2067 gssize bytes_read;
2069 if (lseek (tmp_file_fd, 0, SEEK_SET) < 0)
2070 bytes_read = -1;
2071 else {
2072 while ((bytes_read = read
2073 (tmp_file_fd, buffer, sizeof (buffer))) > 0) {
2074 gsf_output_write (export_dst, bytes_read, buffer);
2077 if (bytes_read < 0) {
2078 int save_errno = errno;
2079 if (!gsf_output_error (export_dst))
2080 gsf_output_set_error (export_dst,
2081 g_file_error_from_errno (save_errno),
2082 "%s", g_strerror (save_errno));
2084 close (tmp_file_fd);
2085 cb_delete_and_free (tmp_file_name);
2088 g_object_unref (print);