1 
2 /*
3  * print.c: Printing routines for Gnumeric
4  *
5  * Authors:
6  *    Miguel de Icaza (miguel@gnu.org)
7  *    Morten Welinder (terra@gnome.org)
8  *    Andreas J. Guelzow (aguelzow@pyrshep.ca)
9  *
10  * Copyright 2007, Andreas J. Guelzow, All Rights Reserved
11  * Copyright (C) 2007-2009 Morten Welinder (terra@gnome.org)
12  *
13  * Handles printing of Sheets.
14  */
15 #include <gnumeric-config.h>
16 #include <print-cell.h>
17 
18 #include <gnumeric.h>
19 #include <print.h>
20 
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>
44 
45 #include <gsf/gsf-meta-names.h>
46 
47 #include <glib/gi18n-lib.h>
48 #include <glib/gstdio.h>
49 #include <glib.h>
50 
51 #include <unistd.h>
52 #include <errno.h>
53 
54 #ifdef G_OS_WIN32
55 #include <windows.h>
56 /* see bug #533795. */
57 #define PREVIEW_VIA_PDF
58 #endif
59 
60 /*  The following structure is used by the printing system */
61 
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;
81 
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;
90 
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;
99 
100 typedef struct {
101 	gint rc;
102 	gint count;
103 	gint first_rep;
104 	gint n_rep;
105 } PaginationInfo;
106 
107 
108 GType
gnm_print_range_get_type(void)109 gnm_print_range_get_type (void)
110 {
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 }
139 		};
140 		etype = g_enum_register_static ("GnmPrintRange", values);
141 	}
142 	return etype;
143 }
144 
145 
146 static PrintingInstance *
printing_instance_new(void)147 printing_instance_new (void)
148 {
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;
153 
154 	return pi;
155 }
156 
157 static void
sheet_print_info_free(gpointer data)158 sheet_print_info_free (gpointer data)
159 {
160 	SheetPrintInfo *spi = data;
161 
162 	g_array_unref (spi->column_pagination);
163 	g_array_unref (spi->row_pagination);
164 	g_free (data);
165 }
166 
167 static void
printing_instance_delete(PrintingInstance * pi)168 printing_instance_delete (PrintingInstance *pi)
169 {
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);
174 	}
175 	g_free (pi);
176 }
177 
178 void
gnm_print_sheet_objects(cairo_t * cr,Sheet const * sheet,GnmRange * range,double base_x,double base_y)179 gnm_print_sheet_objects (cairo_t *cr,
180 			 Sheet const *sheet,
181 			 GnmRange *range,
182 			 double base_x, double base_y)
183 {
184 	GSList *ptr, *objects;
185 	double width, height;
186 
187 	g_return_if_fail (IS_SHEET (sheet));
188 	g_return_if_fail (cr != NULL);
189 	g_return_if_fail (range != NULL);
190 
191 	cairo_save (cr);
192 
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);
197 
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);
207 
208 	objects = g_slist_reverse (g_slist_copy (sheet->sheet_objects));
209 
210 	for (ptr = objects; ptr; ptr = ptr->next) {
211 		SheetObject *so = GNM_SO (ptr->data);
212 		GnmRange const *r = &so->anchor.cell_bound;
213 
214 		if (!sheet_object_can_print (so) ||
215 		    !range_overlap (range, &so->anchor.cell_bound))
216 			continue;
217 
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;
243 			}
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));
256 
257 		sheet_object_draw_cairo (so, (gpointer)cr, sheet->text_is_rtl);
258 		cairo_restore (cr);
259 	}
260 
261 	g_slist_free (objects);
262 
263 	cairo_restore (cr);
264 }
265 
266 static void
print_page_cells(G_GNUC_UNUSED GtkPrintContext * context,G_GNUC_UNUSED PrintingInstance * pi,cairo_t * cr,Sheet const * sheet,GnmRange * range,double base_x,double base_y)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)
271 {
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);
276 }
277 
278 static void
print_header_gtk(GtkPrintContext * context,cairo_t * cr,double x,double y,double w,double h,char const * name,PangoFontDescription * desc)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)
283 {
284 	PangoLayout *layout;
285 	gint layout_height;
286 	gdouble text_height;
287 
288 	cairo_rectangle (cr, x, y, w, h);
289 	cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
290 	cairo_fill (cr);
291 
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);
295 
296 	pango_layout_set_text (layout, name, -1);
297 	pango_layout_set_width (layout, w);
298 	pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
299 
300 	pango_layout_get_size (layout, NULL, &layout_height);
301 	text_height = (gdouble)layout_height / PANGO_SCALE;
302 
303 	cairo_move_to (cr, x + w/2,  y + (h - text_height) / 2);
304 	pango_cairo_show_layout (cr, layout);
305 
306 	g_object_unref (layout);
307 
308 }
309 
310 static void
print_page_col_headers(GtkPrintContext * context,G_GNUC_UNUSED PrintingInstance * pi,cairo_t * cr,Sheet const * sheet,GnmRange * range,double row_header_width,double col_header_height)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)
315 {
316 	int start_col, end_col;
317 	int col;
318 	double x;
319 	PangoFontDescription *desc;
320 	double hscale;
321 
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);
325 
326 	hscale = sheet->display_formulas ? 2 : 1;
327 	desc = pango_font_description_from_string ("sans 12");
328 
329 	start_col = range->start.col;
330 	end_col = range->end.col;
331 
332 	x = (row_header_width + GNM_COL_MARGIN) * (sheet->text_is_rtl ? -1. : 1.);
333 
334 	for (col = start_col; col <= end_col ; col++) {
335 		ColRowInfo const *ci = sheet_col_get_info (sheet, col);
336 
337 		if (ci->visible) {
338 			if (sheet->text_is_rtl)
339 				x -= ci->size_pts * hscale;
340 
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);
346 
347 			if (!sheet->text_is_rtl)
348 				x += ci->size_pts * hscale;
349 		}
350 	}
351 
352 	pango_font_description_free (desc);
353 }
354 
355 static void
print_page_row_headers(GtkPrintContext * context,G_GNUC_UNUSED PrintingInstance * pi,cairo_t * cr,Sheet const * sheet,GnmRange * range,double row_header_width,double col_header_height)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)
360 {
361 	int start_row, end_row;
362 	int row;
363 	double x = 0, y;
364 	PangoFontDescription *desc;
365 
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);
369 
370 	desc = pango_font_description_from_string ("sans 12");
371 
372 	start_row = range->start.row;
373 	end_row = range->end.row;
374 
375 	if (sheet->text_is_rtl)
376 		x = - (row_header_width - 0.5);
377 
378 	for (row = start_row, y = col_header_height; row <= end_row ; row++) {
379 		ColRowInfo const *ri = sheet_row_get_info (sheet, row);
380 
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;
388 		}
389 	}
390 
391 	pango_font_description_free (desc);
392 }
393 
394 static PangoLayout *
ensure_decoration_layout(GtkPrintContext * context)395 ensure_decoration_layout (GtkPrintContext *context)
396 {
397 	GnmStyle *style;
398 	GnmFont *font;
399 	PangoLayout *layout;
400 
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);
407 
408 	return layout;
409 }
410 
411 
412 /*
413  * print_hf_element
414  * @pj: printing context
415  * @format:
416  * @side:
417  * @y:
418  *
419  * Print a header/footer line.
420  *
421  * Position at y, and clip to rectangle.
422  */
423 static void
print_hf_element(GtkPrintContext * context,cairo_t * cr,G_GNUC_UNUSED Sheet const * sheet,char const * format,PangoAlignment side,gdouble width,gboolean align_bottom,GnmPrintHFRenderInfo * hfi)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)
429 {
430 	PangoLayout *layout;
431 
432 	gdouble text_height = 0.;
433 	char *text;
434 
435 	if (format == NULL)
436 		return;
437 
438 	text = gnm_print_hf_format_render (format, hfi, HF_RENDER_PRINT);
439 
440 	if (text == NULL)
441 		return;
442 
443 	layout = ensure_decoration_layout (context);
444 
445 	pango_layout_set_text (layout, text, -1);
446 	pango_layout_set_width (layout, width * PANGO_SCALE);
447 	pango_layout_set_alignment (layout, side);
448 
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;
453 	}
454 
455 	cairo_move_to (cr, 0., - text_height);
456 	pango_cairo_show_layout (cr, layout);
457 
458 	g_object_unref (layout);
459 	g_free(text);
460 }
461 
462 /*
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
467  *
468  * Print a header/footer line.
469  *
470  */
471 static void
print_hf_line(GtkPrintContext * context,cairo_t * cr,Sheet const * sheet,GnmPrintHF const * hf,gboolean align_bottom,gdouble width,GnmPrintHFRenderInfo * hfi)472 print_hf_line (GtkPrintContext   *context, cairo_t *cr, Sheet const *sheet,
473 	       GnmPrintHF const *hf, gboolean align_bottom, gdouble width, GnmPrintHFRenderInfo *hfi)
474 {
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);
478 }
479 
480 
481 
482 /**
483  * print_page:
484  * @pj:        printing context
485  * @gsr:      the page information
486  *
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.
491  */
492 static gboolean
print_page(G_GNUC_UNUSED GtkPrintOperation * operation,GtkPrintContext * context,PrintingInstance * pi,SheetPageRange * gsr)493 print_page (G_GNUC_UNUSED GtkPrintOperation *operation,
494 	    GtkPrintContext   *context,
495 	    PrintingInstance * pi,
496 	    SheetPageRange *gsr)
497 {
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;
514 
515 	px = pinfo->scaling.percentage.x / 100.;
516 	py = pinfo->scaling.percentage.y / 100.;
517 
518 	if (px <= 0.)
519 		px = 1.;
520 	if (py <= 0.)
521 		py = 1.;
522 
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);
526 
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;
530 	}
531 
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;
535 
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);
552        }
553 
554 	print_height = main_height + col_header_height + rep_row_height;
555 	print_width = main_width + row_header_width + rep_col_width;
556 
557 	/* printing header  */
558 
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);
564 	}
565 
566 	/* printing footer  */
567 
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);
574 	}
575 
576 /* setting up content area */
577 	cairo_save (cr);
578 	cairo_translate (cr, sheet->text_is_rtl ? width : 0, edge_to_below_header - header);
579 
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);
587 		}
588 	} else {
589 
590 		if (pinfo->center_horizontally == 1 || pinfo->center_vertically == 1) {
591 			double shift_x = 0;
592 			double shift_y = 0;
593 
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);
599 		}
600 		cairo_scale (cr, px, py);
601 
602 /* printing column and row headers */
603 
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 );
611 			}
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);
621 			}
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);
626 		}
627 
628 /* printing repeated row/col intersect */
629 
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);
634 		}
635 
636 /* printing repeated rows  */
637 
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 );
649 		}
650 
651 /* printing repeated cols */
652 
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 );
660 		}
661 
662 /* printing page content  */
663 
664 		print_page_cells (context, pi, cr, sheet, &gsr->range,
665 				  dir * GNM_COL_MARGIN, -GNM_ROW_MARGIN);
666 	}
667 
668 	cairo_restore (cr);
669 	return 1;
670 }
671 
672 /*
673  * Computes number of rows or columns that fit in @usable starting
674  * at index @start and limited to index @end
675  */
676 static int
compute_group(Sheet const * sheet,int start,int end,double usable,ColRowInfo const * (get_info)(Sheet const * sheet,int const p))677 compute_group (Sheet const *sheet,
678 	       int start, int end, double usable,
679 	       ColRowInfo const *(get_info)(Sheet const *sheet, int const p))
680 {
681 	double size_pts = 1.; /* The initial grid line */
682 	int idx, count = 0;
683 
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;
690 		}
691 	}
692 
693 	/* FIXME : Find a way to inform the user that one of the rows/cols does
694 	 * not fit on a page
695 	 */
696 
697 	if (count ==0) {
698 		g_warning (_("Even one cell is too large for this page."));
699 
700 		/* If we do not return at least one we are going into an infinite loop! */
701 		return 1;
702 	}
703 
704 	return count;
705 }
706 
707 static void
adjust_repetition(Sheet const * sheet,gint i,gint first_rep,gint n_rep,gdouble repeating,gint * first_rep_used,gint * n_rep_used,gdouble * repeating_used,double (sheet_get_distance_pts)(Sheet const * sheet,int from,int to))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))
717 {
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;
727 		}
728 	}
729 }
730 
731 static gint
paginate(GArray * paginationInfo,Sheet const * sheet,gint start,gint end,gdouble usable,gboolean repeat,gint repeat_start,gint repeat_end,double (sheet_get_distance_pts)(Sheet const * sheet,int from,int to),ColRowInfo const * (get_info)(Sheet const * sheet,int const p),GnmPageBreaks * pb,gboolean store_breaks)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)
739 {
740 	int rc = start;
741 	gint n_rep = 0, first_rep = 0;
742 	gdouble repeating = 0.;
743 	gint page_count = 0;
744 
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);
749 	}
750 
751 	while (rc <= end) {
752 		gint n_end;
753 
754 		n_end = gnm_page_breaks_get_next_manual_break (pb, rc) - 1;
755 		if (n_end < rc)
756 			n_end = end;
757 
758 		while (rc <= n_end) {
759 			int count;
760 
761 			gdouble repeating_used = 0.;
762 			gint n_rep_used = 0, first_rep_used = 0;
763 
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);
770 
771 			count = compute_group (sheet, rc, n_end,
772 					       usable - repeating_used,
773 					       get_info);
774 
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);
782 			}
783 			page_count++;
784 
785 			rc += count;
786 			if (store_breaks && (rc < n_end))
787 				gnm_page_breaks_set_break (pb, rc, GNM_PAGE_BREAK_AUTO);
788 		}
789 	}
790 
791 	return page_count;
792 }
793 
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.
801  */
802 static double
compute_scale_fit_to(Sheet const * sheet,int start,int end,double usable,ColRowInfo const * (get_info)(Sheet const * sheet,int const p),double (get_distance_pts)(Sheet const * sheet,int from,int to),gint pages,double max_percent,double header,gboolean repeat,gint repeat_start,gint repeat_end,GnmPageBreaks * pb)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)
809 {
810 	double max_p, min_p;
811 	gint   max_pages;
812 	double extent;
813 
814 	extent = get_distance_pts (sheet, start, end + 1);
815 
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);
820 
821 	/* This means to take whatever space is needed.  */
822 	if (pages <= 0)
823 		return max_percent;
824 
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);
829 	}
830 
831 	/* There is no easy way to calculate really which percentage is needed */
832 	/* without in fact allocating the cols/rows to pages.                  */
833 
834 	/* We first calculate the max percentage needed */
835 
836 	max_p = (pages * usable)/(extent + pages * header);
837 	max_p = CLAMP (max_p, 0.01, max_percent);
838 
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);
842 
843 	if (max_pages == pages)
844 		return max_p;
845 
846 	/* The we calculate the min percentage */
847 
848 	min_p = usable/(extent + header);
849 	min_p = CLAMP (min_p, 0.01, max_percent);
850 
851 	paginate (NULL, sheet, start, end, usable/min_p - header,
852 		  repeat, repeat_start, repeat_end,
853 		  get_distance_pts, get_info, pb, FALSE);
854 
855 
856 	/* And then we pick the middle until the percentage is within 0.1% of */
857 	/* the desired percentage */
858 
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);
864 
865 		if (cur_pages > pages)
866 			max_p = cur_p;
867 		else
868 			min_p = cur_p;
869 	}
870 
871 	return min_p;
872 }
873 
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)))
876 
877 static void
compute_sheet_pages_add_sheet(PrintingInstance * pi,Sheet const * sheet,gboolean selection,gboolean ignore_printarea)878 compute_sheet_pages_add_sheet (PrintingInstance * pi, Sheet const *sheet,
879 			       gboolean selection,
880 			       gboolean ignore_printarea)
881 {
882 	SheetPrintInfo *spi = g_new0 (SheetPrintInfo, 1);
883 
884 	spi->sheet = (Sheet *) sheet;
885 	spi->selection = selection;
886 	spi->ignore_printarea = ignore_printarea;
887 	pi->gnmSheets = g_list_append(pi->gnmSheets, spi);
888 }
889 
890 static Sheet *
print_get_sheet(PrintingInstance * pi,guint page_no)891 print_get_sheet (PrintingInstance *pi, guint page_no)
892 {
893 	GList *l;
894 
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;
901 	}
902 
903 	return NULL;
904 }
905 
906 static SheetPageRange *
print_get_sheet_page_range(PrintingInstance * pi,guint page_no)907 print_get_sheet_page_range (PrintingInstance *pi, guint page_no)
908 {
909 	GList *l;
910 
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;
918 
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;
925 			}
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;
945 	}
946 
947 	return NULL;
948 }
949 
950 /*
951   return TRUE in case of trouble
952 */
953 
954 static gboolean
compute_sheet_pages(GtkPrintContext * context,PrintingInstance * pi,SheetPrintInfo * spi)955 compute_sheet_pages (GtkPrintContext   *context,
956 		     PrintingInstance * pi,
957 		     SheetPrintInfo *spi)
958 {
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;
977 
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;
981 	}
982 
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;
998 		}
999 	};
1000 
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));
1007 
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;
1011 
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;
1015 
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);
1027 
1028 	}
1029 
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;
1034 
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);
1051 
1052 		pinfo->scaling.percentage.x = pxy * 100.;
1053 		pinfo->scaling.percentage.y = pxy * 100.;
1054 	}
1055 
1056 	px = pinfo->scaling.percentage.x / 100.;
1057 	py = pinfo->scaling.percentage.y / 100.;
1058 
1059 	if (px <= 0.)
1060 		px = 1.;
1061 	if (py <= 0.)
1062 		py = 1.;
1063 
1064 	usable_x   = page_width / px;
1065 	usable_y   = page_height / py;
1066 
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);
1077 
1078 	spi->column_pagination = column_pagination;
1079 	spi->row_pagination = row_pagination;
1080 	spi->pages = column_pagination->len * row_pagination->len;
1081 
1082 	return FALSE;
1083 }
1084 
1085 /*
1086  * Computes the pages that will be output by a specific
1087  * print request.
1088  */
1089 static void
compute_pages(G_GNUC_UNUSED GtkPrintOperation * operation,PrintingInstance * pi)1090 compute_pages (G_GNUC_UNUSED GtkPrintOperation *operation,
1091 	       PrintingInstance * pi)
1092 {
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;
1100 
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);
1117 		}
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);
1127 		}
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);
1145 		}
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;
1156 	}
1157 	return;
1158 }
1159 
1160 #if 0
1161 
1162 static PrintJobInfo *
1163 print_job_info_get (Sheet *sheet, PrintRange range, gboolean const preview)
1164 {
1165 	PrintJobInfo *pj = g_new0 (PrintJobInfo, 1);
1166 
1167 	pj->gp_config = print_info_make_config (sheet->print_info);
1168 
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;
1176 
1177 	/*
1178 	 * Setup render info
1179 	 */
1180 	pj->render_info = gnm_print_hf_render_info_new ();
1181 	pj->render_info->sheet = sheet;
1182 	pj->render_info->page = 1;
1183 
1184 	return pj;
1185 }
1186 
1187 static void
1188 print_job_info_destroy (PrintJobInfo *pj)
1189 {
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);
1197 }
1198 
1199 #endif
1200 
1201 static gboolean
gnm_paginate_cb(GtkPrintOperation * operation,GtkPrintContext * context,gpointer user_data)1202 gnm_paginate_cb (GtkPrintOperation *operation,
1203 		 GtkPrintContext   *context,
1204 		 gpointer           user_data)
1205 {
1206 	PrintingInstance * pi = (PrintingInstance *) user_data;
1207 	guint paginate = (pi->last_pagination)++;
1208 	SheetPrintInfo *spi;
1209 
1210 	if (gnm_debug_flag ("print"))
1211 		g_printerr ("paginate %d\n", paginate);
1212 
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;
1220 
1221 			for (l = pi->gnmSheets; l != NULL; l = l->next) {
1222 				SheetPrintInfo *spi = l->data;
1223 				n_pages += spi->pages;
1224 			}
1225 
1226 			if (pi->preview && n_pages > 1000) {
1227 				int i, count = 0;
1228 
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),
1234 					     i))
1235 						count++;
1236 					if (count > 1000)
1237 						break;
1238 				}
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;
1247 			}
1248 
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;
1252 
1253 			if (n_pages == 0) /* gtk+ cannot handle 0 pages */
1254 				gtk_print_operation_cancel (operation);
1255 		}
1256 		return TRUE;
1257 	}
1258 
1259 	if (compute_sheet_pages (context, pi, spi)) {
1260 		gtk_print_operation_cancel (operation);
1261 		return TRUE;
1262 	}
1263 
1264 	return FALSE;
1265 }
1266 
1267 static void
cb_progress_response(G_GNUC_UNUSED GtkDialog * dialog,G_GNUC_UNUSED gint response_id,PrintingInstance * pi)1268 cb_progress_response (G_GNUC_UNUSED GtkDialog *dialog,
1269 		      G_GNUC_UNUSED gint       response_id,
1270 		      PrintingInstance *pi)
1271 {
1272 	pi->cancel = TRUE;
1273 }
1274 
1275 static gboolean
cb_progress_delete(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEvent * event,PrintingInstance * pi)1276 cb_progress_delete (G_GNUC_UNUSED GtkWidget *widget,
1277 		    G_GNUC_UNUSED GdkEvent  *event,
1278 		    PrintingInstance *pi)
1279 {
1280 	pi->cancel = TRUE;
1281 	return TRUE;
1282 }
1283 
1284 static gboolean
gnm_ready_preview_cb(G_GNUC_UNUSED GtkPrintOperation * operation,G_GNUC_UNUSED GtkPrintOperationPreview * preview,G_GNUC_UNUSED GtkPrintContext * context,G_GNUC_UNUSED GtkWindow * parent,gpointer user_data)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)
1290 {
1291 	PrintingInstance * pi = (PrintingInstance *) user_data;
1292 	pi->preview = TRUE;
1293 
1294 	return FALSE;
1295 }
1296 
1297 static void
gnm_begin_print_cb(GtkPrintOperation * operation,G_GNUC_UNUSED GtkPrintContext * context,gpointer user_data)1298 gnm_begin_print_cb (GtkPrintOperation *operation,
1299                     G_GNUC_UNUSED GtkPrintContext   *context,
1300 		    gpointer           user_data)
1301 {
1302 	PrintingInstance * pi = (PrintingInstance *) user_data;
1303 
1304 	if (gnm_debug_flag ("print"))
1305 		g_printerr ("begin-print\n");
1306 
1307 	{
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);
1320 	}
1321 
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);
1337 	}
1338 
1339 	compute_pages (operation, pi);
1340 }
1341 
1342 static void
gnm_end_print_cb(G_GNUC_UNUSED GtkPrintOperation * operation,G_GNUC_UNUSED GtkPrintContext * context,G_GNUC_UNUSED gpointer user_data)1343 gnm_end_print_cb (G_GNUC_UNUSED GtkPrintOperation *operation,
1344                   G_GNUC_UNUSED GtkPrintContext   *context,
1345                   G_GNUC_UNUSED gpointer           user_data)
1346 {
1347 	if (gnm_debug_flag ("print"))
1348 		g_printerr ("end-print\n");
1349 }
1350 
1351 static void
cp_gtk_page_setup(GtkPageSetup * from,GtkPageSetup * to)1352 cp_gtk_page_setup (GtkPageSetup *from, GtkPageSetup *to)
1353 {
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);
1364 }
1365 
1366 static void
gnm_request_page_setup_cb(GtkPrintOperation * operation,G_GNUC_UNUSED GtkPrintContext * context,gint page_nr,GtkPageSetup * setup,gpointer user_data)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)
1372 {
1373 	PrintingInstance * pi = (PrintingInstance *) user_data;
1374 	Sheet *sheet;
1375 	GtkPrintSettings* settings = gtk_print_operation_get_print_settings
1376 				     (operation);
1377 
1378 	g_return_if_fail (pi != NULL);
1379 
1380 	sheet = print_get_sheet (pi, page_nr);
1381 
1382 	if (sheet == NULL) {
1383 		/* g_warning ("Avoiding gtk+ bug 492498"); */
1384 		return;
1385 	}
1386 
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);
1392 }
1393 
1394 static void
gnm_draw_page_cb(GtkPrintOperation * operation,GtkPrintContext * context,gint page_nr,gpointer user_data)1395 gnm_draw_page_cb (GtkPrintOperation *operation,
1396                   GtkPrintContext   *context,
1397 		  gint               page_nr,
1398 		  gpointer           user_data)
1399 {
1400 
1401 	PrintingInstance * pi = (PrintingInstance *) user_data;
1402 	SheetPageRange * gsr;
1403 
1404 	if (gnm_debug_flag ("print"))
1405 		g_printerr ("draw-page %d\n", page_nr);
1406 
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;
1412 	}
1413 
1414 	gsr = print_get_sheet_page_range (pi, page_nr);
1415 	if (gsr) {
1416 		if (pi->progress) {
1417 			char *text;
1418 
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);
1435 		}
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);
1446 	}
1447 }
1448 
1449 static void
widget_button_cb(GtkToggleButton * togglebutton,GtkWidget * check)1450 widget_button_cb (GtkToggleButton *togglebutton, GtkWidget *check)
1451 {
1452 	gtk_widget_set_sensitive (check, gtk_toggle_button_get_active (togglebutton));
1453 }
1454 
1455 static guint
workbook_visible_sheet_count(Workbook * wb)1456 workbook_visible_sheet_count (Workbook *wb)
1457 {
1458 	guint i;
1459 	guint n = workbook_sheet_count (wb);
1460 	guint count = 0;
1461 
1462 	for (i = 0; i < n; i++) {
1463 		Sheet *sheet = workbook_sheet_by_index (wb, i);
1464 		if (sheet_is_visible(sheet))
1465 			count++;
1466 	}
1467 	return count;
1468 }
1469 
1470 static GObject*
gnm_create_widget_cb(GtkPrintOperation * operation,gpointer user_data)1471 gnm_create_widget_cb (GtkPrintOperation *operation, gpointer user_data)
1472 {
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);
1483 
1484 	if (gnm_debug_flag ("print"))
1485 		g_printerr ("Creating custom print widget\n");
1486 
1487 	grid = gtk_grid_new ();
1488 	g_object_set (grid,
1489 	              "column-spacing", 12,
1490 	              "row-spacing", 6,
1491 	              "border-width", 6,
1492 	              NULL);
1493 
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);
1498 
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);
1506 
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);
1511 
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);
1516 
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);
1524 
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);
1532 
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);
1539 
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);
1543 
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);
1547 
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);
1552 
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);
1556 
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);
1561 
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);
1566 
1567 	g_signal_connect_after (G_OBJECT (button_all_sheets), "toggled",
1568 		G_CALLBACK (widget_button_cb), button_print_hidden_sheets);
1569 
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);
1578 
1579 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button_selected_sheet), TRUE);
1580 
1581 	settings =  gtk_print_operation_get_print_settings (operation);
1582 
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;
1609 		}
1610 
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));
1623 	}
1624 
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));
1629 
1630 	gtk_widget_show_all (grid);
1631 
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;
1642 
1643 	if (gnm_debug_flag ("print"))
1644 		g_printerr ("Done with creating custom print widget\n");
1645 
1646 	return G_OBJECT (grid);
1647 }
1648 
1649 static void
gnm_custom_widget_apply_cb(GtkPrintOperation * operation,G_GNUC_UNUSED GtkWidget * widget,gpointer user_data)1650 gnm_custom_widget_apply_cb (GtkPrintOperation       *operation,
1651 			    G_GNUC_UNUSED GtkWidget *widget,
1652 			    gpointer                 user_data)
1653 {
1654 	PrintingInstance * pi = (PrintingInstance *) user_data;
1655 	GtkPrintSettings * settings;
1656 	PrintRange pr = GNM_PRINT_ACTIVE_SHEET;
1657 	guint from, to;
1658 	gboolean ignore_pb;
1659 
1660 	settings =  gtk_print_operation_get_print_settings (operation);
1661 
1662 	g_return_if_fail (settings != NULL);
1663 
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));
1666 
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;
1675 
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;
1696 	}
1697 
1698 	gtk_print_settings_set_int (settings,
1699 				    GNUMERIC_PRINT_SETTING_PRINTRANGE_KEY, pr);
1700 
1701 	pi->pr = pr;
1702 
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;
1707 }
1708 
1709 static void
cb_delete_and_free(char * tmp_file_name)1710 cb_delete_and_free (char *tmp_file_name)
1711 {
1712 	if (tmp_file_name) {
1713 		g_unlink (tmp_file_name);
1714 		g_free (tmp_file_name);
1715 	}
1716 }
1717 
1718 static gchar *
gnm_print_uri_change_extension(char const * uri,GtkPrintSettings * settings)1719 gnm_print_uri_change_extension (char const *uri, GtkPrintSettings* settings)
1720 {
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);
1729 
1730 	if (ext == NULL) {
1731 		ext = "pdf";
1732 		gtk_print_settings_set (settings,
1733 					GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT,
1734 					ext);
1735 	}
1736 
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;
1746 }
1747 
1748 void
gnm_print_sheet(WorkbookControl * wbc,Sheet * sheet,gboolean preview,PrintRange default_range,GsfOutput * export_dst)1749 gnm_print_sheet (WorkbookControl *wbc, Sheet *sheet,
1750 		 gboolean preview, PrintRange default_range,
1751 		 GsfOutput *export_dst)
1752 {
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;
1770 
1771 #ifdef PREVIEW_VIA_PDF
1772 	preview_via_pdf = preview;
1773 #endif
1774 
1775 	g_return_if_fail (sheet != NULL && sheet->workbook != NULL);
1776 
1777 	if (preview)
1778 		g_return_if_fail (!export_dst && wbc);
1779 
1780 	doc = GO_DOC (sheet->workbook);
1781 
1782 	print = gtk_print_operation_new ();
1783 
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;
1789 
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];
1797 	}
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);
1823 		}
1824 	}
1825 
1826 	gtk_print_operation_set_print_settings (print, settings);
1827 	g_object_unref (settings);
1828 
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);
1832 
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);
1839 
1840 	gtk_print_operation_set_use_full_page (print, FALSE);
1841 	gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
1842 
1843 	if (NULL != wbc && GNM_IS_WBC_GTK(wbc))
1844 		parent = wbcg_toplevel (WBC_GTK (wbc));
1845 
1846 	if (preview_via_pdf || export_dst) {
1847 		GError *err = NULL;
1848 
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);
1862 			}
1863 			g_error_free (err);
1864 			goto out;
1865 		}
1866 
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);
1878 	}
1879 
1880 	res = gtk_print_operation_run (print, action, parent, NULL);
1881 
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);
1898 			}
1899 		}
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: ;
1911 	}
1912 	printing_instance_delete (pi);
1913 
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);
1927 		}
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
1936 
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;
1948 
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);
1954 			}
1955 		}
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));
1962 		}
1963 	}
1964 
1965  out:
1966 	if (tmp_file_fd >= 0)
1967 		close (tmp_file_fd);
1968 	cb_delete_and_free (tmp_file_name);
1969 
1970 	g_object_unref (print);
1971 }
1972 
1973 static void
gnm_draw_so_page_cb(G_GNUC_UNUSED GtkPrintOperation * operation,GtkPrintContext * context,G_GNUC_UNUSED gint page_nr,gpointer user_data)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)
1978 {
1979 
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);
1983 
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);
1988 }
1989 
1990 /**
1991  * gnm_print_so:
1992  * @wbc:
1993  * @sos: (element-type SheetObject) (transfer none):
1994  * @export_dst:
1995  */
1996 void
gnm_print_so(WorkbookControl * wbc,GPtrArray * sos,GsfOutput * export_dst)1997 gnm_print_so (WorkbookControl *wbc, GPtrArray *sos,
1998 	      GsfOutput *export_dst)
1999 {
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;
2009 
2010 	g_return_if_fail (sos != NULL && sos->len > 0);
2011 
2012 	/* FIXME: we should print all objects in the array, not just the first! */
2013 
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));
2018 
2019 	print = gtk_print_operation_new ();
2020 
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);
2026 
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);
2030 
2031 	gtk_print_operation_set_n_pages (print, 1);
2032 	gtk_print_operation_set_embed_page_setup (print, TRUE);
2033 
2034 	g_signal_connect (print, "draw-page", G_CALLBACK (gnm_draw_so_page_cb), so);
2035 
2036 	gtk_print_operation_set_use_full_page (print, FALSE);
2037 	gtk_print_operation_set_unit (print, GTK_UNIT_POINTS);
2038 
2039 	if (export_dst) {
2040 		GError *err = NULL;
2041 
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);
2051 
2052 			g_object_unref (print);
2053 			return;
2054 		}
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);
2061 	}
2062 
2063 	gtk_print_operation_run (print, action, parent, NULL);
2064 
2065 	if (tmp_file_name) {
2066 		char buffer[64 * 1024];
2067 		gssize bytes_read;
2068 
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);
2075 			}
2076 		}
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));
2083 		}
2084 		close (tmp_file_fd);
2085 		cb_delete_and_free (tmp_file_name);
2086 	}
2087 
2088 	g_object_unref (print);
2089 }
2090