2 * Evolution calendar - Print support
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Michael Zucchi <notzed@ximian.com>
19 * Federico Mena-Quintero <federico@ximian.com>
20 * Damon Chaplin <damon@ximian.com>
22 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
26 #include "evolution-config.h"
37 #include <glib/gi18n.h>
39 #include "e-cal-model.h"
40 #include "e-day-view.h"
41 #include "e-day-view-layout.h"
42 #include "e-week-view.h"
43 #include "e-week-view-layout.h"
44 #include "e-task-table.h"
46 #include "data/xpm/jump.xpm"
48 typedef struct PrintCompItem PrintCompItem
;
49 typedef struct PrintCalItem PrintCalItem
;
51 struct PrintCompItem
{
55 gboolean use_24_hour_format
;
59 ECalendarView
*cal_view
;
61 EPrintView print_view_type
;
66 evo_calendar_print_renderer_get_width (GtkPrintContext
*context
,
67 PangoFontDescription
*font
,
71 gint layout_width
, layout_height
;
73 layout
= gtk_print_context_create_pango_layout (context
);
75 pango_layout_set_font_description (layout
, font
);
76 pango_layout_set_text (layout
, text
, -1);
77 pango_layout_set_indent (layout
, 0);
78 pango_layout_get_size (layout
, &layout_width
, &layout_height
);
80 g_object_unref (layout
);
82 return pango_units_to_double (layout_width
);
86 evo_calendar_print_renderer_get_height (GtkPrintContext
*context
,
87 PangoFontDescription
*font
,
91 gint layout_width
, layout_height
;
93 layout
= gtk_print_context_create_pango_layout (context
);
95 pango_layout_set_font_description (layout
, font
);
96 pango_layout_set_text (layout
, text
, -1);
97 pango_layout_set_indent (layout
, 0);
98 pango_layout_get_size (layout
, &layout_width
, &layout_height
);
100 g_object_unref (layout
);
102 return pango_units_to_double (layout_height
);
106 get_font_size (PangoFontDescription
*font
)
108 g_return_val_if_fail (font
, 0.0);
110 return pango_units_to_double (pango_font_description_get_size (font
));
114 get_day_view_time_divisions (void)
119 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
121 time_divisions
= g_settings_get_int (settings
, "time-divisions");
122 if (time_divisions
< 5 || time_divisions
> 30)
125 g_object_unref (settings
);
127 return time_divisions
;
131 * Note that most dimensions are in points (1/72 of an inch) since that is
132 * what gnome-print uses.
135 /* GtkHTML prints using a fixed margin. It has code to get the margins from
136 * gnome-print keys, but it's commented out. The corresponding code here
137 * doesn't seem to work either (getting zero margins), so we adopt
138 * gtkhtml's cheat. */
140 #define TEMP_MARGIN .05
142 /* The fonts to use */
143 #define FONT_FAMILY "Sans"
145 /* The font size to use for normal text. */
146 #define DAY_NORMAL_FONT_SIZE 12
147 #define WEEK_NORMAL_FONT_SIZE 12
148 #define MONTH_NORMAL_FONT_SIZE 8
149 #define WEEK_EVENT_FONT_SIZE 9
150 #define WEEK_SMALL_FONT_SIZE 8
152 /* The height of the header bar across the top of the Day, Week & Month views,
153 * which contains the dates shown and the 2 small calendar months. */
154 #define HEADER_HEIGHT 80
156 /* The width of the small calendar months, the space from the right edge of
157 * the header rectangle, and the space between the months. */
158 #define MIN_SMALL_MONTH_WIDTH 120
159 #define SMALL_MONTH_PAD 5
160 #define SMALL_MONTH_SPACING 20
162 /* The minimum number of rows we leave space for for the long events in the
164 #define DAY_VIEW_MIN_ROWS_IN_TOP_DISPLAY 2
166 /* The row height for long events in the day view. */
167 #define DAY_VIEW_ROW_HEIGHT 14
169 #define CALC_DAY_VIEW_ROWS(divis) ((60 / divis) * 24)
171 /* The width of the column with all the times in it. */
172 #define DAY_VIEW_TIME_COLUMN_WIDTH 36
174 /* The space on the right of each event. */
175 #define DAY_VIEW_EVENT_X_PAD 8
177 /* Allowance for small errors in floating point comparisons. */
180 /* The weird month of September 1752, where 3 Sep through 13 Sep were
181 * eliminated due to the Gregorian reformation. */
182 static const gint sept_1752
[42] = {
183 0, 0, 1, 2, 14, 15, 16,
184 17, 18, 19, 20, 21, 22, 23,
185 24, 25, 26, 27, 28, 29, 30,
190 #define SEPT_1752_START 2 /* Start day within month */
191 #define SEPT_1752_END 20 /* End day within month */
196 time_t day_starts
[E_DAY_VIEW_MAX_DAYS
+ 1];
199 GArray
*events
[E_DAY_VIEW_MAX_DAYS
];
203 gint start_minute_offset
;
204 gint end_minute_offset
;
207 guint8 cols_per_row
[CALC_DAY_VIEW_ROWS (1)];
208 gboolean use_24_hour_format
;
214 time_t day_starts
[E_WEEK_VIEW_MAX_WEEKS
* 7 + 1];
219 gint rows_per_compressed_cell
;
220 GDateWeekday display_start_weekday
;
221 gboolean multi_week_view
;
224 gboolean compress_weekend
;
225 gboolean use_24_hour_format
;
227 gdouble header_row_height
;
231 /* Convenience function to help the transition to timezone functions.
232 * It converts a time_t to a struct tm. */
234 convert_timet_to_struct_tm (time_t time
,
238 struct icaltimetype tt
;
240 /* Convert it to an icaltimetype. */
241 tt
= icaltime_from_timet_with_zone (time
, FALSE
, zone
);
243 /* Fill in the struct tm. */
244 tm
->tm_year
= tt
.year
- 1900;
245 tm
->tm_mon
= tt
.month
- 1;
246 tm
->tm_mday
= tt
.day
;
247 tm
->tm_hour
= tt
.hour
;
248 tm
->tm_min
= tt
.minute
;
249 tm
->tm_sec
= tt
.second
;
250 tm
->tm_isdst
= tt
.is_daylight
;
252 tm
->tm_wday
= time_day_of_week (tt
.day
, tt
.month
- 1, tt
.year
);
255 /* Fills the 42-element days array with the day numbers for the specified
256 * month. Slots outside the bounds of the month are filled with zeros.
257 * The starting and ending indexes of the days are returned in the start
258 * and end arguments. */
260 build_month (ECalModel
*model
,
270 GDateWeekday weekday
;
271 GDateWeekday week_start_day
;
273 /* Note that months are zero-based, so September is month 8 */
275 if ((year
== 1752) && (month
== 8)) {
276 memcpy (days
, sept_1752
, 42 * sizeof (gint
));
279 *start
= SEPT_1752_START
;
282 *end
= SEPT_1752_END
;
287 for (i
= 0; i
< 42; i
++)
290 d_month
= time_days_in_month (year
, month
);
291 /* Get the start weekday in the month, 0=Sun to 6=Sat. */
292 d_week
= time_day_of_week (1, month
, year
);
294 /* Get the configuration setting specifying which weekday we put on
295 * the left column. */
296 week_start_day
= e_cal_model_get_week_start_day (model
);
298 weekday
= e_weekday_from_tm_wday (d_week
);
300 /* Figure out which square we want to put the 1 in. */
301 weekday
= (weekday
+ 7 - week_start_day
) % 7;
303 for (i
= 0; i
< d_month
; i
++)
304 days
[weekday
+ i
] = i
+ 1;
307 *start
= e_weekday_get_days_between (week_start_day
, weekday
);
310 *end
= d_week
+ d_month
- 1;
313 static PangoFontDescription
*
314 get_font_for_size (gdouble height
,
317 PangoFontDescription
*desc
;
320 #define MAGIC_SCALE_FACTOR (0.86)
321 size
= pango_units_from_double (height
* MAGIC_SCALE_FACTOR
);
323 desc
= pango_font_description_new ();
324 pango_font_description_set_size (desc
, size
);
325 pango_font_description_set_weight (desc
, weight
);
326 pango_font_description_set_family_static (desc
, FONT_FAMILY
);
331 /* Prints a rectangle, with or without a border, filled or outline, and
332 * possibly with triangular arrows at one or both horizontal edges.
333 * width = width of border, -ve means no border.
334 * red,green,blue = bgcolor to fill, -ve means no fill.
335 * left_triangle_width, right_triangle_width = width from edge of rectangle to
336 * point of triangle, or -ve for no triangle. */
338 print_border_with_triangles (GtkPrintContext
*pc
,
345 gdouble left_triangle_width
,
346 gdouble right_triangle_width
)
348 cairo_t
*cr
= gtk_print_context_get_cairo_context (pc
);
352 /* Fill in the interior of the rectangle, if desired. */
353 if (bg_rgba
.red
>= -EPSILON
&& bg_rgba
.green
>= -EPSILON
&& bg_rgba
.blue
>= -EPSILON
) {
355 cairo_move_to (cr
, x1
, y1
);
357 if (left_triangle_width
> 0.0)
359 cr
, x1
- left_triangle_width
,
362 cairo_line_to (cr
, x1
, y2
);
363 cairo_line_to (cr
, x2
, y2
);
365 if (right_triangle_width
> 0.0)
366 cairo_line_to (cr
, x2
+ right_triangle_width
, (y1
+ y2
) / 2);
368 cairo_line_to (cr
, x2
, y1
);
369 cairo_close_path (cr
);
370 gdk_cairo_set_source_rgba (cr
, &bg_rgba
);
376 /* Draw the outline, if desired. */
377 if (line_width
>= EPSILON
) {
379 cr
= gtk_print_context_get_cairo_context (pc
);
380 cairo_move_to (cr
, x1
, y1
);
382 if (left_triangle_width
> 0.0)
384 cr
, x1
- left_triangle_width
,
387 cairo_line_to (cr
, x1
, y2
);
388 cairo_line_to (cr
, x2
, y2
);
390 if (right_triangle_width
> 0.0)
392 cr
, x2
+ right_triangle_width
,
395 cairo_line_to (cr
, x2
, y1
);
396 cairo_close_path (cr
);
397 cairo_set_source_rgb (cr
, 0, 0, 0);
398 cairo_set_line_width (cr
, line_width
);
405 /* Prints a rectangle, with or without a border, and filled or outline.
406 * width = width of border, -ve means no border.
407 * fillcolor = shade of fill, -ve means no fill. */
409 print_border_rgb (GtkPrintContext
*pc
,
417 print_border_with_triangles (
418 pc
, x1
, x2
, y1
, y2
, line_width
,
419 bg_rgba
, -1.0, -1.0);
423 print_border (GtkPrintContext
*pc
,
433 bg_rgba
.red
= fillcolor
;
434 bg_rgba
.green
= fillcolor
;
435 bg_rgba
.blue
= fillcolor
;
438 print_border_rgb (pc
, x1
, x2
, y1
, y2
, line_width
, bg_rgba
);
442 print_rectangle (GtkPrintContext
*context
,
449 cairo_t
*cr
= gtk_print_context_get_cairo_context (context
);
453 cairo_rectangle (cr
, x
, y
, width
, height
);
454 gdk_cairo_set_source_rgba (cr
, &bg_rgba
);
460 /* Recreate the layout by shrinking the text string if we have a line that's
464 shrink_text_to_line (PangoLayout
*layout
,
467 GtkPrintContext
*context
,
468 PangoFontDescription
*desc
,
470 PangoAlignment alignment
,
478 if (layout_width
== 0 || x2
- x1
< EPSILON
)
479 return layout
; /* Do nothing */
481 new_length
= (gint
) floor (pango_units_from_double (x2
- x1
) /
482 (gdouble
) layout_width
* (gdouble
) strlen (text
));
484 if (new_length
< strlen (text
)) {
485 g_object_unref (layout
); /* Destroy old layout */
486 layout
= gtk_print_context_create_pango_layout (context
);
488 pango_layout_set_font_description (layout
, desc
);
489 pango_layout_set_alignment (layout
, alignment
);
490 pango_layout_set_text (layout
, text
, new_length
);
496 /* Prints 1 line of aligned text in a box. It is centered vertically, and
497 * the horizontal alignment can be either PANGO_ALIGN_LEFT, PANGO_ALIGN_RIGHT,
498 * or PANGO_ALIGN_CENTER. Text is truncated if too long for cell. */
500 print_text_line (GtkPrintContext
*context
,
501 PangoFontDescription
*desc
,
503 PangoAlignment alignment
,
509 const GdkRGBA
*bg_rgba
)
512 gint layout_width
, layout_height
;
515 cr
= gtk_print_context_get_cairo_context (context
);
516 layout
= gtk_print_context_create_pango_layout (context
);
518 pango_layout_set_font_description (layout
, desc
);
519 pango_layout_set_alignment (layout
, alignment
);
520 pango_layout_set_text (layout
, text
, -1);
522 /* Grab the width before expanding the layout. */
523 pango_layout_get_size (layout
, &layout_width
, &layout_height
);
525 if (shrink
&& layout_width
> pango_units_from_double (x2
- x1
)) /* Too wide */
526 layout
= shrink_text_to_line (
527 layout
, layout_width
, layout_height
,
528 context
, desc
, text
, alignment
,
531 pango_layout_set_width (layout
, pango_units_from_double (x2
- x1
));
535 /* Set a clipping rectangle. */
536 cairo_move_to (cr
, x1
, y1
);
537 cairo_rectangle (cr
, x1
, y1
, x2
- x1
, y2
- y1
);
541 if (!bg_rgba
|| (bg_rgba
->red
> 0.7) || (bg_rgba
->green
> 0.7) || (bg_rgba
->blue
> 0.7))
542 cairo_set_source_rgb (cr
, 0.0, 0.0, 0.0);
544 cairo_set_source_rgb (cr
, 1.0, 1.0, 1.0);
546 cairo_move_to (cr
, x1
, y1
);
547 pango_cairo_show_layout (cr
, layout
);
553 g_object_unref (layout
);
555 return pango_units_to_double (layout_width
);
558 /* Prints 1 or more lines of aligned text in a box. It is centered vertically, and
559 * the horizontal alignment can be either PANGO_ALIGN_LEFT, PANGO_ALIGN_RIGHT,
560 * or PANGO_ALIGN_CENTER. */
562 print_text (GtkPrintContext
*context
,
563 PangoFontDescription
*desc
,
565 PangoAlignment alignment
,
571 return print_text_line (
574 x1
, x2
, y1
, y2
, FALSE
, NULL
);
577 /* gets/frees the font for you, as a bold font */
579 print_text_size_bold (GtkPrintContext
*context
,
581 PangoAlignment alignment
,
587 PangoFontDescription
*font
;
590 font
= get_font_for_size (ABS (y2
- y1
) * 0.5, PANGO_WEIGHT_BOLD
);
591 w
= print_text (context
, font
, text
, alignment
, x1
, x2
, y1
, y2
);
592 pango_font_description_free (font
);
597 /* gets/frees the font for you, as a bold font - absolute size parameter */
599 print_text_abs_bold (GtkPrintContext
*context
,
602 PangoAlignment alignment
,
608 PangoFontDescription
*font
;
611 font
= get_font_for_size (font_size
, PANGO_WEIGHT_BOLD
);
612 w
= print_text_line (context
, font
, text
, alignment
, x1
, x2
, y1
, y2
, TRUE
, NULL
);
613 pango_font_description_free (font
);
619 titled_box (GtkPrintContext
*context
,
621 PangoFontDescription
*font
,
622 PangoAlignment alignment
,
631 size
= evo_calendar_print_renderer_get_height (context
, font
, text
);
632 print_border (context
, *x1
, *x2
, *y1
, *y1
+ size
+ 2, linewidth
, 0.9);
633 print_border (context
, *x1
, *x2
, *y1
+ size
+ 2, *y2
, linewidth
, -1.0);
637 print_text (context
, font
, text
, alignment
, *x1
, *x2
, *y1
+ 1.0, *y1
+ size
);
642 get_show_week_numbers (void)
645 gboolean show_week_numbers
;
647 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
650 g_settings_get_boolean (settings
, "show-week-numbers");
652 g_object_unref (settings
);
654 return show_week_numbers
;
660 DATE_DAYNAME
= 1 << 2,
665 format the date 'nicely' and consistently for various headers
668 format_date (struct tm
*tm
,
673 GString
*fmt
= g_string_new ("");
675 if (flags
& DATE_DAYNAME
) {
676 g_string_append (fmt
, "%A");
678 if (flags
& DATE_DAY
) {
679 if (flags
& DATE_DAYNAME
)
680 g_string_append (fmt
, " ");
681 g_string_append (fmt
, e_cal_recur_get_localized_nth (tm
->tm_mday
- 1));
683 if (flags
& DATE_MONTH
) {
684 if (flags
& (DATE_DAY
| DATE_DAYNAME
))
685 g_string_append (fmt
, " ");
686 g_string_append (fmt
, "%B");
687 if ((flags
& (DATE_DAY
| DATE_YEAR
)) == (DATE_DAY
| DATE_YEAR
))
688 g_string_append (fmt
, ",");
690 if (flags
& DATE_YEAR
) {
691 if (flags
& (DATE_DAY
| DATE_DAYNAME
| DATE_MONTH
))
692 g_string_append (fmt
, " ");
693 g_string_append (fmt
, "%Y");
695 e_utf8_strftime (buffer
, bufflen
, fmt
->str
, tm
);
696 buffer
[bufflen
- 1] = '\0';
698 g_string_free (fmt
, TRUE
);
704 instance_cb (ECalComponent
*comp
,
705 time_t instance_start
,
710 gboolean
*found
= ((ECalModelGenerateInstancesData
*) data
)->cb_data
;
717 const gchar
*daynames
[] = {
718 /* G_DATE_BAD_WEEKDAY */ "",
719 /* Translators: These are workday abbreviations,
720 * e.g. Su=Sunday and Th=thursday */
721 /* G_DATE_MONDAY */ N_("Mo"),
722 /* G_DATE_TUESDAY */ N_("Tu"),
723 /* G_DATE_WEDNESDAY */ N_("We"),
724 /* G_DATE_THURSDAY */ N_("Th"),
725 /* G_DATE_FRIDAY */ N_("Fr"),
726 /* G_DATE_SATURDAY */ N_("Sa"),
727 /* G_DATE_SUNDAY */ N_("Su")
731 calc_small_month_width (GtkPrintContext
*context
,
735 PangoFontDescription
*font_bold
;
739 font_bold
= get_font_for_size (for_height
/ 7.4, PANGO_WEIGHT_BOLD
);
740 res
= MAX (evo_calendar_print_renderer_get_width (
741 context
, font_bold
, "23"), res
);
742 for (ii
= G_DATE_MONDAY
; ii
< G_N_ELEMENTS (daynames
); ii
++) {
743 res
= MAX (evo_calendar_print_renderer_get_width (
744 context
, font_bold
, _(daynames
[ii
])), res
);
747 pango_font_description_free (font_bold
);
749 /* res is max cell width, so multiply it with column
750 * count plus some space between columns. */
751 res
= (res
+ 1.0) * (7 + (get_show_week_numbers () ? 1 : 0)) - 1.0;
753 if (res
< MIN_SMALL_MONTH_WIDTH
)
754 res
= MIN_SMALL_MONTH_WIDTH
;
760 print out the month small, embolden any days with events.
763 print_month_small (GtkPrintContext
*context
,
776 PangoFontDescription
*font
, *font_bold
, *font_normal
;
781 GDateWeekday weekday
;
782 GDateWeekday week_start_day
;
786 gdouble header_size
, col_width
, row_height
, text_xpad
, w
;
787 gdouble cell_top
, cell_bottom
, cell_left
, cell_right
, text_right
;
788 gboolean week_numbers
;
791 zone
= e_cal_model_get_timezone (model
);
793 week_numbers
= get_show_week_numbers ();
795 /* Print the title, e.g. 'June 2001', in the top 16% of the area. */
796 convert_timet_to_struct_tm (month
, zone
, &tm
);
797 format_date (&tm
, titleflags
, buf
, 100);
799 header_size
= ABS (y2
- y1
) * 0.16;
801 font
= get_font_for_size (header_size
, PANGO_WEIGHT_BOLD
);
803 print_border (context
, x1
, x2
, y1
, y1
+ header_size
, 1.0, 0.9);
805 context
, font
, buf
, PANGO_ALIGN_CENTER
, x1
, x2
,
806 y1
, y1
+ header_size
);
807 pango_font_description_free (font
);
810 col_width
= (x2
- x1
) / (7 + (week_numbers
? 1 : 0));
812 /* The top row with the day abbreviations gets an extra bit of
813 * vertical space around it. */
814 row_height
= ABS (y2
- y1
) / 7.4;
816 /* First we need to calculate a reasonable font size. We start with a
817 * rough guess of just under the height of each row. */
818 font_size
= row_height
;
821 convert_timet_to_struct_tm (month
, zone
, &tm
);
822 build_month (model
, tm
.tm_mon
, tm
.tm_year
+ 1900, days
, NULL
, NULL
);
824 font_normal
= get_font_for_size (font_size
, PANGO_WEIGHT_NORMAL
);
825 font_bold
= get_font_for_size (font_size
, PANGO_WEIGHT_BOLD
);
827 /* Get a reasonable estimate of the largest number we will need,
828 * and use it to calculate the offset from the right edge of the
829 * cell that we should put the numbers. */
830 w
= evo_calendar_print_renderer_get_width (context
, font_bold
, "23");
831 text_xpad
= (col_width
- w
) / 2;
833 cr
= gtk_print_context_get_cairo_context (context
);
834 cairo_set_source_rgb (cr
, 0, 0, 0);
836 /* Print the abbreviated day names across the top in bold. */
837 week_start_day
= e_cal_model_get_week_start_day (model
);
838 weekday
= week_start_day
;
839 for (x
= 0; x
< 7; x
++) {
842 _(daynames
[weekday
]), PANGO_ALIGN_RIGHT
,
843 x1
+ (x
+ (week_numbers
? 1 : 0)) * col_width
,
844 x1
+ (x
+ 1 + (week_numbers
? 1 : 0)) * col_width
,
845 y1
, y1
+ row_height
* 1.4);
846 weekday
= e_weekday_get_next (weekday
);
849 y1
+= row_height
* 1.4;
851 now
= time_month_begin_with_zone (month
, zone
);
852 for (y
= 0; y
< 6; y
++) {
854 cell_top
= y1
+ y
* row_height
;
855 cell_bottom
= cell_top
+ row_height
;
859 /* We add a 0.05 to make sure the cells meet up with
860 * each other. Otherwise you sometimes get lines
861 * between them which looks bad. Maybe I'm not using
862 * coords in the way gnome-print expects. */
863 cell_right
= cell_left
+ col_width
+ 0.05;
864 text_right
= cell_right
- text_xpad
;
866 /* last week can be empty */
867 for (x
= 0; x
< 7; x
++) {
868 day
= days
[y
* 7 + x
];
877 wday
= e_weekday_to_tm_wday (week_start_day
);
878 week_begin
= time_week_begin_with_zone (
881 convert_timet_to_struct_tm (
882 week_begin
, zone
, &tm
);
884 /* Month in e_calendar_item_get_week_number
885 * is also zero-based. */
888 e_calendar_item_get_week_number (
889 NULL
, tm
.tm_mday
, tm
.tm_mon
,
893 context
, font_normal
,
894 buf
, PANGO_ALIGN_RIGHT
,
895 cell_left
, text_right
,
896 cell_top
, cell_bottom
);
900 for (x
= 0; x
< 7; x
++) {
902 cell_left
= x1
+ (x
+ (week_numbers
? 1 : 0)) * col_width
;
903 /* We add a 0.05 to make sure the cells meet up with
904 * each other. Otherwise you sometimes get lines
905 * between them which looks bad. Maybe I'm not using
906 * coords in the way gnome-print expects. */
907 cell_right
= cell_left
+ col_width
+ 0.05;
908 text_right
= cell_right
- text_xpad
;
910 day
= days
[y
* 7 + x
];
912 gboolean found
= FALSE
;
913 sprintf (buf
, "%d", day
);
915 /* this is a slow messy way to do this ... but easy ... */
916 e_cal_model_generate_instances_sync (
918 time_day_end_with_zone (now
, zone
),
919 instance_cb
, &found
);
921 font
= found
? font_bold
: font_normal
;
923 next
= time_add_day_with_zone (now
, 1, zone
);
924 if ((now
>= greystart
&& now
< greyend
)
925 || (greystart
>= now
&& greystart
< next
)) {
928 cell_left
, cell_right
,
929 cell_top
, cell_bottom
,
933 context
, font
, buf
, PANGO_ALIGN_RIGHT
,
934 cell_left
, text_right
,
935 cell_top
, cell_bottom
);
941 pango_font_description_free (font_normal
);
942 pango_font_description_free (font_bold
);
945 /* wraps text into the print context, not taking up more than its allowed space */
947 bound_text (GtkPrintContext
*context
,
948 PangoFontDescription
*font
,
956 const GdkRGBA
*bg_rgba
,
957 gdouble
*last_page_start
,
961 gint layout_width
, layout_height
;
964 cr
= gtk_print_context_get_cairo_context (context
);
965 layout
= gtk_print_context_create_pango_layout (context
);
967 pango_layout_set_font_description (layout
, font
);
968 pango_layout_set_text (layout
, text
, len
);
969 pango_layout_set_width (layout
, pango_units_from_double (x2
- x1
));
972 pango_layout_set_wrap (layout
, PANGO_WRAP_WORD_CHAR
);
974 pango_layout_get_size (layout
, &layout_width
, &layout_height
);
976 if (last_page_start
&&
977 y1
+ pango_units_to_double (layout_height
) >
978 y2
+ (*last_page_start
)) {
979 /* draw this on new page */
983 *last_page_start
= *last_page_start
+ y2
;
984 y1
= *last_page_start
+ 10.0;
987 if (!last_page_start
|| (y1
>= 0.0 && y1
< y2
)) {
990 /* Set a clipping rectangle. */
991 cairo_move_to (cr
, x1
, y1
);
992 cairo_rectangle (cr
, x1
, y1
, x2
- x1
, y2
- y1
);
996 if (!bg_rgba
|| (bg_rgba
->red
> 0.7) || (bg_rgba
->green
> 0.7) || (bg_rgba
->blue
> 0.7))
997 cairo_set_source_rgb (cr
, 0.0, 0.0, 0.0);
999 cairo_set_source_rgb (cr
, 1.0, 1.0, 1.0);
1001 cairo_move_to (cr
, x1
, y1
);
1002 pango_cairo_show_layout (cr
, layout
);
1008 g_object_unref (layout
);
1010 return y1
+ pango_units_to_double (layout_height
);
1013 /* Draw the borders, lines, and times down the left of the day view. */
1015 print_day_background (GtkPrintContext
*context
,
1024 PangoFontDescription
*font_hour
, *font_minute
;
1026 gdouble width
= DAY_VIEW_TIME_COLUMN_WIDTH
;
1027 gdouble font_size
, max_font_size
, hour_font_size
, minute_font_size
;
1029 const gchar
*minute
;
1030 gboolean use_24_hour
;
1032 gdouble hour_minute_x
, hour_minute_width
;
1035 use_24_hour
= e_cal_model_get_use_24_hour_format (model
);
1037 /* Fill the time column in light-gray. */
1038 print_border (context
, left
, left
+ width
, top
, bottom
, -1.0, 0.9);
1040 /* Draw the border around the entire view. */
1041 cr
= gtk_print_context_get_cairo_context (context
);
1043 cairo_set_source_rgb (cr
, 0, 0, 0);
1044 print_border (context
, left
, right
, top
, bottom
, 1.0, -1.0);
1046 /* Draw the vertical line on the right of the time column. */
1047 cr
= gtk_print_context_get_cairo_context (context
);
1048 cairo_set_line_width (cr
, 0.0);
1049 cairo_move_to (cr
, left
+ width
, bottom
);
1050 cairo_line_to (cr
, left
+ width
, top
);
1053 /* Calculate the row height. */
1055 yinc
= (top
- bottom
) / (pdi
->end_hour
- pdi
->start_hour
);
1057 yinc
= (bottom
- top
) / (pdi
->end_hour
- pdi
->start_hour
);
1059 /* Get the 2 fonts we need. */
1060 font_size
= yinc
* 0.6;
1061 max_font_size
= width
* 0.45;
1062 hour_font_size
= MIN (font_size
, max_font_size
);
1063 font_hour
= get_font_for_size (hour_font_size
, PANGO_WEIGHT_BOLD
);
1065 font_size
= yinc
* 0.33;
1066 max_font_size
= width
* 0.2;
1067 minute_font_size
= MIN (font_size
, max_font_size
);
1068 font_minute
= get_font_for_size (minute_font_size
, PANGO_WEIGHT_BOLD
);
1069 hour_minute_width
= evo_calendar_print_renderer_get_width (
1070 context
, font_minute
, use_24_hour
? "00" : _("am"));
1072 hour_minute_width
= MAX (
1074 evo_calendar_print_renderer_get_width (
1075 context
, font_minute
, _("pm")));
1078 hour_minute_x
= left
+ width
- hour_minute_width
- 3;
1079 for (i
= pdi
->start_hour
; i
< pdi
->end_hour
; i
++) {
1080 y
= top
+ yinc
* (row
+ 1);
1081 cr
= gtk_print_context_get_cairo_context (context
);
1082 cairo_set_source_rgb (cr
, 0, 0, 0);
1098 /* the hour label/minute */
1099 sprintf (buf
, "%d", hour
);
1101 context
, font_hour
, buf
, PANGO_ALIGN_RIGHT
,
1102 left
, hour_minute_x
,
1103 y
- yinc
, y
- yinc
+ hour_font_size
);
1105 context
, font_minute
, minute
, PANGO_ALIGN_LEFT
,
1106 hour_minute_x
, left
+ width
- 3,
1107 y
- yinc
, y
- yinc
+ minute_font_size
);
1109 /* Draw the horizontal line between hours, across the entire
1110 width of the day view. */
1111 cr
= gtk_print_context_get_cairo_context (context
);
1112 cairo_move_to (cr
, left
, y
);
1113 cairo_line_to (cr
, right
, y
);
1114 cairo_set_line_width (cr
, 1);
1117 /* Draw the horizontal line for the 1/2-hours, across the
1118 * entire width except for part of the time column. */
1119 cairo_move_to (cr
, left
+ width
* 0.6, y
- yinc
/ 2);
1120 cairo_line_to (cr
, right
, y
- yinc
/ 2);
1121 cairo_set_line_width (cr
, 1);
1126 pango_font_description_free (font_hour
);
1127 pango_font_description_free (font_minute
);
1130 /* This adds one event to the view, adding it to the appropriate array. */
1132 print_day_add_event (ECalModelComponent
*comp_data
,
1138 GArray
*long_events
,
1142 EDayViewEvent event
;
1144 struct icaltimetype start_tt
, end_tt
;
1147 g_print ("Day view lower: %s", ctime (&day_starts
[0]));
1148 g_print ("Day view upper: %s", ctime (&day_starts
[days_shown
]));
1149 g_print ("Event start: %s", ctime (&start
));
1150 g_print ("Event end : %s\n", ctime (&end
));
1153 /* Check that the event times are valid. */
1154 g_return_val_if_fail (start
<= end
, -1);
1155 g_return_val_if_fail (start
< day_starts
[days_shown
], -1);
1156 g_return_val_if_fail (end
> day_starts
[0], -1);
1158 start_tt
= icaltime_from_timet_with_zone (start
, FALSE
, zone
);
1159 end_tt
= icaltime_from_timet_with_zone (end
, FALSE
, zone
);
1161 event
.comp_data
= comp_data
;
1162 event
.start
= start
;
1164 event
.canvas_item
= NULL
;
1166 /* Calculate the start & end minute, relative to the top of the
1168 /*offset = day_view->first_hour_shown * 60
1169 + day_view->first_minute_shown;*/
1171 event
.start_minute
= start_tt
.hour
* 60 + start_tt
.minute
- offset
;
1172 event
.end_minute
= end_tt
.hour
* 60 + end_tt
.minute
- offset
;
1174 event
.start_row_or_col
= 0;
1175 event
.num_columns
= 0;
1177 /* Find out which array to add the event to. */
1178 for (day
= 0; day
< days_shown
; day
++) {
1179 if (start
>= day_starts
[day
] && end
<= day_starts
[day
+ 1]) {
1181 /* Special case for when the appointment ends at
1182 * midnight, i.e. the start of the next day. */
1183 if (end
== day_starts
[day
+ 1]) {
1185 /* If the event last the entire day, then we
1186 * skip it here so it gets added to the top
1188 if (start
== day_starts
[day
])
1191 event
.end_minute
= 24 * 60;
1193 g_array_append_val (events
[day
], event
);
1198 /* The event wasn't within one day so it must be a long event,
1199 * i.e. shown in the top canvas. */
1200 g_array_append_val (long_events
, event
);
1201 return E_DAY_VIEW_LONG_EVENT
;
1205 print_day_details_cb (ECalComponent
*comp
,
1210 ECalModelGenerateInstancesData
*mdata
= (ECalModelGenerateInstancesData
*) data
;
1211 struct pdinfo
*pdi
= (struct pdinfo
*) mdata
->cb_data
;
1213 print_day_add_event (
1214 mdata
->comp_data
, istart
, iend
,
1215 pdi
->zone
, pdi
->days_shown
, pdi
->day_starts
,
1216 pdi
->long_events
, pdi
->events
);
1222 free_event_array (GArray
*array
)
1224 EDayViewEvent
*event
;
1227 for (event_num
= 0; event_num
< array
->len
; event_num
++) {
1228 event
= &g_array_index (array
, EDayViewEvent
, event_num
);
1229 if (event
->canvas_item
)
1230 g_object_run_dispose (G_OBJECT (event
->canvas_item
));
1233 g_array_set_size (array
, 0);
1236 static const gchar
*
1237 get_type_as_string (icalparameter_cutype cutype
)
1242 case ICAL_CUTYPE_NONE
: res
= NULL
; break;
1243 case ICAL_CUTYPE_INDIVIDUAL
: res
= _("Individual"); break;
1244 case ICAL_CUTYPE_GROUP
: res
= _("Group"); break;
1245 case ICAL_CUTYPE_RESOURCE
: res
= _("Resource"); break;
1246 case ICAL_CUTYPE_ROOM
: res
= _("Room"); break;
1247 default: res
= _("Unknown"); break;
1253 static const gchar
*
1254 get_role_as_string (icalparameter_role role
)
1259 case ICAL_ROLE_NONE
: res
= NULL
; break;
1260 case ICAL_ROLE_CHAIR
: res
= _("Chair"); break;
1261 case ICAL_ROLE_REQPARTICIPANT
: res
= _("Required Participant"); break;
1262 case ICAL_ROLE_OPTPARTICIPANT
: res
= _("Optional Participant"); break;
1263 case ICAL_ROLE_NONPARTICIPANT
: res
= _("Non-Participant"); break;
1264 default: res
= _("Unknown"); break;
1271 print_attendees (GtkPrintContext
*context
,
1272 PangoFontDescription
*font
,
1278 ECalComponent
*comp
,
1282 GSList
*attendees
= NULL
, *l
;
1284 g_return_val_if_fail (context
!= NULL
, top
);
1285 g_return_val_if_fail (font
!= NULL
, top
);
1286 g_return_val_if_fail (cr
!= NULL
, top
);
1288 e_cal_component_get_attendee_list (comp
, &attendees
);
1290 for (l
= attendees
; l
; l
= l
->next
) {
1291 ECalComponentAttendee
*attendee
= l
->data
;
1293 if (attendee
&& attendee
->value
&& *attendee
->value
) {
1297 tmp
= get_type_as_string (attendee
->cutype
);
1298 text
= g_string_new (tmp
? tmp
: "");
1301 g_string_append (text
, " ");
1303 if (attendee
->cn
&& *attendee
->cn
)
1304 g_string_append (text
, attendee
->cn
);
1306 /* it's usually in form of "mailto:email@domain" */
1307 tmp
= strchr (attendee
->value
, ':');
1308 g_string_append (text
, tmp
? tmp
+ 1 : attendee
->value
);
1311 tmp
= get_role_as_string (attendee
->role
);
1313 g_string_append (text
, " (");
1314 g_string_append (text
, tmp
);
1315 g_string_append (text
, ")");
1320 cairo_show_page (cr
);
1324 context
, font
, text
->str
, -1, left
+ 40.0,
1325 top
, right
, bottom
, FALSE
, NULL
, NULL
, pages
);
1327 g_string_free (text
, TRUE
);
1331 e_cal_component_free_attendee_list (attendees
);
1337 get_summary_with_location (icalcomponent
*icalcomp
)
1339 const gchar
*summary
, *location
;
1342 g_return_val_if_fail (icalcomp
!= NULL
, NULL
);
1344 summary
= icalcomponent_get_summary (icalcomp
);
1345 if (summary
== NULL
)
1348 location
= icalcomponent_get_location (icalcomp
);
1349 if (location
&& *location
) {
1350 text
= g_strdup_printf ("%s (%s)", summary
, location
);
1352 text
= g_strdup (summary
);
1359 print_day_long_event (GtkPrintContext
*context
,
1360 PangoFontDescription
*font
,
1366 EDayViewEvent
*event
,
1370 gdouble x1
, x2
, y1
, y2
;
1371 gdouble left_triangle_width
= -1.0, right_triangle_width
= -1.0;
1377 if (!is_comp_data_valid (event
))
1380 /* If the event starts before the first day being printed, draw a
1381 * triangle. (Note that I am assuming we are just showing 1 day at
1383 if (event
->start
< pdi
->day_starts
[0])
1384 left_triangle_width
= 4;
1386 /* If the event ends after the last day being printed, draw a
1388 if (event
->end
> pdi
->day_starts
[1])
1389 right_triangle_width
= 4;
1393 y1
= top
+ event
->start_row_or_col
* row_height
+ 1;
1394 y2
= y1
+ row_height
- 1;
1396 if (!e_cal_model_get_rgba_for_component (model
, event
->comp_data
, &bg_rgba
)) {
1398 bg_rgba
.green
= 0.95;
1399 bg_rgba
.blue
= 0.95;
1400 bg_rgba
.alpha
= 1.0;
1403 print_border_with_triangles (
1404 context
, x1
, x2
, y1
, y2
, 0.5, bg_rgba
,
1405 left_triangle_width
,
1406 right_triangle_width
);
1408 /* If the event starts after the first day being printed, we need to
1409 * print the start time. */
1410 if (event
->start
> pdi
->day_starts
[0]) {
1411 date_tm
.tm_year
= 2001;
1413 date_tm
.tm_mday
= 1;
1414 date_tm
.tm_hour
= event
->start_minute
/ 60;
1415 date_tm
.tm_min
= event
->start_minute
% 60;
1417 date_tm
.tm_isdst
= -1;
1419 e_time_format_time (&date_tm
, pdi
->use_24_hour_format
, FALSE
,
1420 buffer
, sizeof (buffer
));
1423 x1
+= print_text_line (context
, font
, buffer
, PANGO_ALIGN_LEFT
, x1
, x2
, y1
, y2
, FALSE
, &bg_rgba
);
1426 /* If the event ends before the end of the last day being printed,
1427 * we need to print the end time. */
1428 if (event
->end
< pdi
->day_starts
[1]) {
1429 date_tm
.tm_year
= 2001;
1431 date_tm
.tm_mday
= 1;
1432 date_tm
.tm_hour
= event
->end_minute
/ 60;
1433 date_tm
.tm_min
= event
->end_minute
% 60;
1435 date_tm
.tm_isdst
= -1;
1437 e_time_format_time (&date_tm
, pdi
->use_24_hour_format
, FALSE
,
1438 buffer
, sizeof (buffer
));
1441 x2
-= print_text_line (context
, font
, buffer
, PANGO_ALIGN_RIGHT
, x1
, x2
, y1
, y2
, FALSE
, &bg_rgba
);
1444 /* Print the text. */
1445 text
= get_summary_with_location (event
->comp_data
->icalcomp
);
1449 print_text_line (context
, font
, text
, PANGO_ALIGN_CENTER
, x1
, x2
, y1
, y2
, TRUE
, &bg_rgba
);
1455 print_day_event (GtkPrintContext
*context
,
1456 PangoFontDescription
*font
,
1461 EDayViewEvent
*event
,
1465 gdouble x1
, x2
, y1
, y2
, col_width
, row_height
;
1466 gint start_offset
, end_offset
, start_row
, end_row
;
1467 gchar
*text
, start_buffer
[32], end_buffer
[32];
1468 gboolean display_times
= FALSE
;
1472 if (!is_comp_data_valid (event
))
1475 if ((event
->start_minute
>= pdi
->end_minute_offset
)
1476 || (event
->end_minute
<= pdi
->start_minute_offset
))
1479 start_offset
= event
->start_minute
- pdi
->start_minute_offset
;
1480 end_offset
= event
->end_minute
- pdi
->start_minute_offset
;
1482 start_row
= start_offset
/ pdi
->mins_per_row
;
1483 start_row
= MAX (0, start_row
);
1484 end_row
= (end_offset
- 1) / pdi
->mins_per_row
;
1485 end_row
= MIN (pdi
->rows
- 1, end_row
);
1486 col_width
= (right
- left
) /
1487 pdi
->cols_per_row
[event
->start_minute
/ pdi
->mins_per_row
];
1489 if (start_offset
!= start_row
* pdi
->mins_per_row
1490 || end_offset
!= (end_row
+ 1) * pdi
->mins_per_row
)
1491 display_times
= TRUE
;
1493 x1
= left
+ event
->start_row_or_col
* col_width
;
1494 x2
= x1
+ event
->num_columns
* col_width
- DAY_VIEW_EVENT_X_PAD
;
1496 row_height
= (bottom
- top
) / pdi
->rows
;
1497 y1
= top
+ start_row
* row_height
;
1498 y2
= top
+ (end_row
+ 1) * row_height
;
1501 "Event: %g,%g %g,%g\n row_height: %g start_row: %i top: %g rows: %i\n",
1502 x1
, y1
, x2
, y2
, row_height
, start_row
, top
, pdi
->rows
);
1505 if (!e_cal_model_get_rgba_for_component (model
, event
->comp_data
, &bg_rgba
)) {
1507 bg_rgba
.green
= 0.95;
1508 bg_rgba
.blue
= 0.95;
1509 bg_rgba
.alpha
= 1.0;
1512 print_border_rgb (context
, x1
, x2
, y1
, y2
, 1.0, bg_rgba
);
1514 text
= get_summary_with_location (event
->comp_data
->icalcomp
);
1516 if (display_times
) {
1519 date_tm
.tm_year
= 2001;
1521 date_tm
.tm_mday
= 1;
1522 date_tm
.tm_hour
= event
->start_minute
/ 60;
1523 date_tm
.tm_min
= event
->start_minute
% 60;
1525 date_tm
.tm_isdst
= -1;
1527 e_time_format_time (&date_tm
, pdi
->use_24_hour_format
, FALSE
,
1528 start_buffer
, sizeof (start_buffer
));
1530 date_tm
.tm_hour
= event
->end_minute
/ 60;
1531 date_tm
.tm_min
= event
->end_minute
% 60;
1533 e_time_format_time (&date_tm
, pdi
->use_24_hour_format
, FALSE
,
1534 end_buffer
, sizeof (end_buffer
));
1537 text
= g_strdup_printf (
1539 start_buffer
, end_buffer
, text
);
1544 bound_text (context
, font
, text
, -1, x1
+ 2, y1
, x2
- 2, y2
, FALSE
, &bg_rgba
, NULL
, NULL
);
1550 print_day_details (GtkPrintContext
*context
,
1559 EDayViewEvent
*event
;
1560 PangoFontDescription
*font
;
1562 struct pdinfo pdi
= { 0 };
1563 gint rows_in_top_display
, i
, rows_with_30_mins
;
1564 gdouble font_size
, max_font_size
;
1566 GdkPixbuf
*pixbuf
= NULL
;
1567 #define LONG_DAY_EVENTS_TOP_SPACING 4
1568 #define LONG_DAY_EVENTS_BOTTOM_SPACING 2
1570 zone
= e_cal_model_get_timezone (model
);
1572 start
= time_day_begin_with_zone (whence
, zone
);
1573 end
= time_day_end_with_zone (start
, zone
);
1576 pdi
.day_starts
[0] = start
;
1577 pdi
.day_starts
[1] = end
;
1578 pdi
.long_events
= g_array_new (FALSE
, FALSE
, sizeof (EDayViewEvent
));
1579 pdi
.events
[0] = g_array_new (FALSE
, FALSE
, sizeof (EDayViewEvent
));
1580 pdi
.start_hour
= e_cal_model_get_work_day_start_hour (model
);
1581 pdi
.end_hour
= e_cal_model_get_work_day_end_hour (model
);
1582 if (e_cal_model_get_work_day_end_minute (model
) != 0)
1584 pdi
.mins_per_row
= get_day_view_time_divisions ();
1585 pdi
.rows
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / pdi
.mins_per_row
);
1586 pdi
.start_minute_offset
= pdi
.start_hour
* 60;
1587 pdi
.end_minute_offset
= pdi
.end_hour
* 60;
1588 pdi
.use_24_hour_format
= e_cal_model_get_use_24_hour_format (model
);
1589 pdi
.zone
= e_cal_model_get_timezone (model
);
1591 /* Get the events from the server. */
1592 e_cal_model_generate_instances_sync (model
, start
, end
, print_day_details_cb
, &pdi
);
1594 pdi
.long_events
->data
, pdi
.long_events
->len
,
1595 sizeof (EDayViewEvent
), e_day_view_event_sort_func
);
1597 pdi
.events
[0]->data
, pdi
.events
[0]->len
,
1598 sizeof (EDayViewEvent
), e_day_view_event_sort_func
);
1600 /* Also print events outside of work hours */
1601 if (pdi
.events
[0]->len
> 0) {
1602 struct icaltimetype tt
;
1604 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, 0);
1605 tt
= icaltime_from_timet_with_zone (event
->start
, FALSE
, zone
);
1606 if (tt
.hour
< pdi
.start_hour
)
1607 pdi
.start_hour
= tt
.hour
;
1608 pdi
.start_minute_offset
= pdi
.start_hour
* 60;
1610 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, pdi
.events
[0]->len
- 1);
1611 tt
= icaltime_from_timet_with_zone (event
->end
, FALSE
, zone
);
1612 if (tt
.hour
> pdi
.end_hour
|| tt
.hour
== 0) {
1613 pdi
.end_hour
= tt
.hour
? tt
.hour
: 24;
1617 pdi
.end_minute_offset
= pdi
.end_hour
* 60;
1619 pdi
.rows
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / pdi
.mins_per_row
);
1622 /* Lay them out the long events, across the top of the page. */
1623 e_day_view_layout_long_events (
1624 pdi
.long_events
, pdi
.days_shown
,
1625 pdi
.day_starts
, &rows_in_top_display
);
1627 /*Print the long events. */
1628 font
= get_font_for_size (12, PANGO_WEIGHT_NORMAL
);
1630 /* We always leave space for DAY_VIEW_MIN_ROWS_IN_TOP_DISPLAY in the
1631 * top display, but we may have more rows than that, in which case
1632 * the main display area will be compressed. */
1633 /* Limit long day event to half the height of the panel */
1634 rows_in_top_display
= MIN (
1635 MAX (rows_in_top_display
,
1636 DAY_VIEW_MIN_ROWS_IN_TOP_DISPLAY
),
1637 (bottom
- top
) * 0.5 / DAY_VIEW_ROW_HEIGHT
);
1639 if (rows_in_top_display
> pdi
.long_events
->len
)
1640 rows_in_top_display
= pdi
.long_events
->len
;
1642 for (i
= 0; i
< rows_in_top_display
&& i
< pdi
.long_events
->len
; i
++) {
1643 event
= &g_array_index (pdi
.long_events
, EDayViewEvent
, i
);
1644 print_day_long_event (
1645 context
, font
, left
, right
,
1646 top
+ LONG_DAY_EVENTS_TOP_SPACING
, bottom
,
1647 DAY_VIEW_ROW_HEIGHT
, event
, &pdi
, model
);
1650 if (rows_in_top_display
< pdi
.long_events
->len
) {
1651 /* too many events */
1652 cairo_t
*cr
= gtk_print_context_get_cairo_context (context
);
1656 const gchar
**xpm
= (const gchar
**) jump_xpm
;
1658 /* this ugly thing is here only to get rid of compiler warning
1659 * about unused 'jump_xpm_focused' */
1661 /* coverity[dead_error_line] */
1662 xpm
= (const gchar
**) jump_xpm_focused
;
1665 pixbuf
= gdk_pixbuf_new_from_xpm_data (xpm
);
1668 /* Right align - 10 comes from print_day_long_event too */
1669 x
= right
- gdk_pixbuf_get_width (pixbuf
) * 0.5 - 10;
1670 /* Placing '...' over the last all day event entry printed. '-1 -1' comes
1671 from print_long_day_event (top / bottom spacing in each cell) */
1672 y
= top
+ LONG_DAY_EVENTS_TOP_SPACING
1673 + DAY_VIEW_ROW_HEIGHT
* (i
- 1)
1674 + (DAY_VIEW_ROW_HEIGHT
- 1 - 1) * 0.5;
1677 cairo_scale (cr
, 0.5, 0.5);
1678 gdk_cairo_set_source_pixbuf (cr
, pixbuf
, x
* 2.0, y
* 2.0);
1683 if (!rows_in_top_display
)
1684 rows_in_top_display
++;
1686 /* Draw the border around the long events. */
1687 cr
= gtk_print_context_get_cairo_context (context
);
1689 cairo_set_source_rgb (cr
, 0, 0, 0);
1691 context
, left
, right
,
1692 top
, top
+ rows_in_top_display
* DAY_VIEW_ROW_HEIGHT
+
1693 LONG_DAY_EVENTS_TOP_SPACING
+ LONG_DAY_EVENTS_BOTTOM_SPACING
,
1696 /* Adjust the area containing the main display. */
1697 top
+= rows_in_top_display
* DAY_VIEW_ROW_HEIGHT
1698 + LONG_DAY_EVENTS_TOP_SPACING
1699 + LONG_DAY_EVENTS_BOTTOM_SPACING
;
1701 /* Draw the borders, lines, and times down the left. */
1702 print_day_background (
1703 context
, model
, whence
, &pdi
,
1704 left
, right
, top
, bottom
);
1705 /* Now adjust to get rid of the time column. */
1706 left
+= DAY_VIEW_TIME_COLUMN_WIDTH
;
1708 /* lay out the short events, within the day. */
1709 e_day_view_layout_day_events (
1710 pdi
.events
[0], CALC_DAY_VIEW_ROWS (pdi
.mins_per_row
),
1711 pdi
.mins_per_row
, pdi
.cols_per_row
, -1);
1713 /* use font like with 30 minutes time division */
1714 rows_with_30_mins
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / 30);
1716 pango_font_description_free (font
);
1718 /* print the short events. */
1720 max_font_size
= ((top
- bottom
) / rows_with_30_mins
) - 4;
1722 max_font_size
= ((bottom
- top
) / rows_with_30_mins
) - 4;
1723 font_size
= MIN (DAY_NORMAL_FONT_SIZE
, max_font_size
);
1724 font
= get_font_for_size (font_size
, PANGO_WEIGHT_NORMAL
);
1726 for (i
= 0; i
< pdi
.events
[0]->len
; i
++) {
1727 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, i
);
1729 context
, font
, left
, right
, top
, bottom
,
1730 event
, &pdi
, model
);
1733 /* Free everything. */
1735 g_object_unref (pixbuf
);
1736 free_event_array (pdi
.long_events
);
1737 pango_font_description_free (font
);
1738 g_array_free (pdi
.long_events
, TRUE
);
1739 free_event_array (pdi
.events
[0]);
1740 g_array_free (pdi
.events
[0], TRUE
);
1743 /* Returns TRUE if the event is a one-day event (i.e. not a long event). */
1745 print_is_one_day_week_event (EWeekViewEvent
*event
,
1746 EWeekViewEventSpan
*span
,
1749 if (event
->start
== day_starts
[span
->start_day
]
1750 && event
->end
== day_starts
[span
->start_day
+ 1])
1753 if (span
->num_days
== 1
1754 && event
->start
>= day_starts
[span
->start_day
]
1755 && event
->end
<= day_starts
[span
->start_day
+ 1])
1762 print_week_long_event (GtkPrintContext
*context
,
1763 PangoFontDescription
*font
,
1769 EWeekViewEvent
*event
,
1770 EWeekViewEventSpan
*span
,
1774 gdouble left_triangle_width
= -1.0, right_triangle_width
= -1.0;
1778 /* If the event starts before the first day of the span, draw a
1779 * triangle to indicate it continues. */
1780 if (event
->start
< psi
->day_starts
[span
->start_day
])
1781 left_triangle_width
= 4;
1783 /* If the event ends after the last day of the span, draw a
1785 if (event
->end
> psi
->day_starts
[span
->start_day
+ span
->num_days
])
1786 right_triangle_width
= 4;
1788 print_border_with_triangles (
1789 context
, x1
+ 6, x2
- 6, y1
, y1
+ row_height
, 0.0, bg_rgba
,
1790 left_triangle_width
, right_triangle_width
);
1795 /* If the event starts after the first day being printed, we need to
1796 * print the start time. */
1797 if (event
->start
> psi
->day_starts
[span
->start_day
]) {
1798 date_tm
.tm_year
= 2001;
1800 date_tm
.tm_mday
= 1;
1801 date_tm
.tm_hour
= event
->start_minute
/ 60;
1802 date_tm
.tm_min
= event
->start_minute
% 60;
1804 date_tm
.tm_isdst
= -1;
1806 e_time_format_time (&date_tm
, psi
->use_24_hour_format
, FALSE
,
1807 buffer
, sizeof (buffer
));
1810 x1
+= print_text_line (
1811 context
, font
, buffer
, PANGO_ALIGN_LEFT
,
1812 x1
, x2
- 2, y1
, y1
+ row_height
, TRUE
, &bg_rgba
);
1815 /* If the event ends before the end of the last day being printed,
1816 * we need to print the end time. */
1817 if (event
->end
< psi
->day_starts
[span
->start_day
+ span
->num_days
]) {
1818 date_tm
.tm_year
= 2001;
1820 date_tm
.tm_mday
= 1;
1821 date_tm
.tm_hour
= event
->end_minute
/ 60;
1822 date_tm
.tm_min
= event
->end_minute
% 60;
1824 date_tm
.tm_isdst
= -1;
1826 e_time_format_time (&date_tm
, psi
->use_24_hour_format
, FALSE
,
1827 buffer
, sizeof (buffer
));
1830 x2
-= print_text_line (
1831 context
, font
, buffer
, PANGO_ALIGN_RIGHT
,
1832 x1
+ 2, x2
, y1
, y1
+ row_height
, TRUE
, &bg_rgba
);
1837 print_text_line (context
, font
, text
, PANGO_ALIGN_CENTER
, x1
, x2
, y1
, y1
+ row_height
, TRUE
, &bg_rgba
);
1841 print_week_day_event (GtkPrintContext
*context
,
1842 PangoFontDescription
*font
,
1848 EWeekViewEvent
*event
,
1849 EWeekViewEventSpan
*span
,
1856 date_tm
.tm_year
= 2001;
1858 date_tm
.tm_mday
= 1;
1859 date_tm
.tm_hour
= event
->start_minute
/ 60;
1860 date_tm
.tm_min
= event
->start_minute
% 60;
1862 date_tm
.tm_isdst
= -1;
1864 e_time_format_time (&date_tm
, psi
->use_24_hour_format
, FALSE
,
1865 buffer
, sizeof (buffer
));
1866 print_rectangle (context
, x1
+ 1, y1
, x2
- x1
- 2, row_height
, bg_rgba
);
1867 x1
+= print_text_line (
1868 context
, font
, buffer
, PANGO_ALIGN_LEFT
,
1869 x1
+ 2, x2
- 3, y1
, y1
+ row_height
, TRUE
, &bg_rgba
) + 4;
1871 if (psi
->weeks_shown
<= 2) {
1872 date_tm
.tm_hour
= event
->end_minute
/ 60;
1873 date_tm
.tm_min
= event
->end_minute
% 60;
1875 e_time_format_time (&date_tm
, psi
->use_24_hour_format
, FALSE
,
1876 buffer
, sizeof (buffer
));
1878 x1
+= print_text_line (
1879 context
, font
, buffer
, PANGO_ALIGN_LEFT
,
1880 x1
, x2
- 3, y1
, y1
+ row_height
, TRUE
, &bg_rgba
) + 4;
1884 context
, font
, text
, PANGO_ALIGN_LEFT
,
1885 x1
, x2
- 3, y1
, y1
+ row_height
, TRUE
, &bg_rgba
);
1889 print_week_event (GtkPrintContext
*context
,
1890 PangoFontDescription
*font
,
1895 gdouble cell_height
,
1897 EWeekViewEvent
*event
,
1900 EWeekViewEventSpan
*span
;
1903 gint num_days
, start_x
, start_y
, start_h
, end_x
, end_y
, end_h
;
1906 GdkPixbuf
*pixbuf
= NULL
;
1908 if (!is_comp_data_valid (event
))
1911 text
= get_summary_with_location (event
->comp_data
->icalcomp
);
1913 for (span_num
= 0; span_num
< event
->num_spans
; span_num
++) {
1914 span
= &g_array_index (spans
, EWeekViewEventSpan
,
1915 event
->spans_index
+ span_num
);
1917 if (e_week_view_layout_get_span_position (
1920 psi
->rows_per_compressed_cell
,
1921 psi
->display_start_weekday
,
1922 psi
->multi_week_view
,
1923 psi
->compress_weekend
,
1926 e_week_view_layout_get_day_position
1928 psi
->multi_week_view
,
1930 psi
->display_start_weekday
,
1931 psi
->compress_weekend
,
1932 &start_x
, &start_y
, &start_h
);
1934 if (num_days
== 1) {
1939 e_week_view_layout_get_day_position
1940 (span
->start_day
+ num_days
- 1,
1941 psi
->multi_week_view
,
1943 psi
->display_start_weekday
,
1944 psi
->compress_weekend
,
1945 &end_x
, &end_y
, &end_h
);
1948 x1
= left
+ start_x
* cell_width
;
1949 x2
= left
+ (end_x
+ 1) * cell_width
;
1950 y1
= top
+ start_y
* cell_height
1951 + psi
->header_row_height
1952 + span
->row
* (psi
->row_height
+ 2);
1954 if (!e_cal_model_get_rgba_for_component (model
, event
->comp_data
, &bg_rgba
)) {
1956 bg_rgba
.green
= 0.9;
1958 bg_rgba
.alpha
= 1.0;
1961 if (print_is_one_day_week_event (event
, span
,
1963 print_week_day_event (
1965 x1
, x2
, y1
, psi
->row_height
,
1966 event
, span
, text
, bg_rgba
);
1968 print_week_long_event (
1970 x1
, x2
, y1
, psi
->row_height
,
1971 event
, span
, text
, bg_rgba
);
1974 cairo_t
*cr
= gtk_print_context_get_cairo_context (context
);
1976 e_week_view_layout_get_day_position (
1978 psi
->multi_week_view
,
1980 psi
->display_start_weekday
,
1981 psi
->compress_weekend
,
1982 &start_x
, &start_y
, &start_h
);
1984 y1
= top
+ start_y
* cell_height
1985 + psi
->header_row_height
1986 + psi
->rows_per_cell
* (psi
->row_height
+ 2);
1988 if (span
->row
>= psi
->rows_per_compressed_cell
&& psi
->compress_weekend
) {
1989 GDateWeekday end_weekday
;
1990 gboolean end_on_weekend
;
1992 end_weekday
= e_weekday_add_days (
1993 psi
->display_start_weekday
,
1997 (end_weekday
== G_DATE_SATURDAY
) ||
1998 (end_weekday
== G_DATE_SUNDAY
);
2000 if (end_on_weekend
) {
2001 y1
= top
+ start_y
* cell_height
2002 + psi
->header_row_height
2003 + psi
->rows_per_compressed_cell
* (psi
->row_height
+ 2);
2009 const gchar
**xpm
= (const gchar
**) jump_xpm
;
2011 pixbuf
= gdk_pixbuf_new_from_xpm_data (xpm
);
2014 x1
= left
+ (start_x
+ 1) * cell_width
- 6 -
2015 gdk_pixbuf_get_width (pixbuf
) * 0.5;
2018 cairo_scale (cr
, 0.5, 0.5);
2019 gdk_cairo_set_source_pixbuf (cr
, pixbuf
, x1
* 2.0, y1
* 2.0);
2026 g_object_unref (pixbuf
);
2032 print_week_view_background (GtkPrintContext
*context
,
2033 PangoFontDescription
*font
,
2038 gdouble cell_height
)
2041 gint day
, day_x
, day_y
, day_h
;
2042 gdouble x1
, x2
, y1
, y2
, font_size
, fillcolor
;
2043 const gchar
*format_string
;
2047 font_size
= get_font_size (font
);
2049 for (day
= 0; day
< psi
->days_shown
; day
++) {
2050 e_week_view_layout_get_day_position
2051 (day
, psi
->multi_week_view
, psi
->weeks_shown
,
2052 psi
->display_start_weekday
, psi
->compress_weekend
,
2053 &day_x
, &day_y
, &day_h
);
2055 x1
= left
+ day_x
* cell_width
;
2056 x2
= left
+ (day_x
+ 1) * cell_width
;
2057 y1
= top
+ day_y
* cell_height
;
2058 y2
= y1
+ day_h
* cell_height
;
2060 convert_timet_to_struct_tm (psi
->day_starts
[day
], psi
->zone
, &tm
);
2062 /* In the month view we draw a grey background for the end
2063 * of the previous month and the start of the following. */
2065 if (psi
->multi_week_view
&& (tm
.tm_mon
!= psi
->month
))
2068 print_border (context
, x1
, x2
, y1
, y2
, 1.0, fillcolor
);
2070 if (psi
->multi_week_view
) {
2071 if (tm
.tm_mday
== 1)
2072 format_string
= _("%d %B");
2074 format_string
= "%d";
2076 cr
= gtk_print_context_get_cairo_context (context
);
2079 cr
, x1
+ 0.1 * cell_width
,
2080 y1
+ psi
->header_row_height
- 4);
2083 y1
+ psi
->header_row_height
- 4);
2085 cairo_set_source_rgb (cr
, 0, 0, 0);
2086 cairo_set_line_width (cr
, 0.5);
2089 /* strftime format %A = full weekday name, %d = day of
2090 * month, %B = full month name. You can change the
2091 * order but don't change the specifiers or add
2093 format_string
= _("%A %d %B");
2097 e_utf8_strftime (buffer
, sizeof (buffer
), format_string
, &tm
);
2100 context
, font
, buffer
, PANGO_ALIGN_RIGHT
,
2101 x1
, x2
- 4, y1
+ 2, y1
+ 2 + font_size
, TRUE
, NULL
);
2105 /* This adds one event to the view, adding it to the appropriate array. */
2107 print_week_summary_cb (ECalComponent
*comp
,
2113 EWeekViewEvent event
;
2114 struct icaltimetype start_tt
, end_tt
;
2115 ECalModelGenerateInstancesData
*mdata
= (ECalModelGenerateInstancesData
*) data
;
2116 struct psinfo
*psi
= (struct psinfo
*) mdata
->cb_data
;
2118 /* Check that the event times are valid. */
2122 "View start:%li end:%li Event start:%li end:%li\n",
2123 psi
->day_starts
[0], psi
->day_starts
[psi
->days_shown
],
2127 g_return_val_if_fail (start
<= end
, TRUE
);
2128 g_return_val_if_fail (start
< psi
->day_starts
[psi
->days_shown
], TRUE
);
2129 g_return_val_if_fail (end
> psi
->day_starts
[0], TRUE
);
2131 start_tt
= icaltime_from_timet_with_zone (start
, FALSE
, psi
->zone
);
2132 end_tt
= icaltime_from_timet_with_zone (end
, FALSE
, psi
->zone
);
2134 event
.comp_data
= g_object_ref (mdata
->comp_data
);
2136 event
.start
= start
;
2138 event
.spans_index
= 0;
2139 event
.num_spans
= 0;
2141 event
.start_minute
= start_tt
.hour
* 60 + start_tt
.minute
;
2142 event
.end_minute
= end_tt
.hour
* 60 + end_tt
.minute
;
2143 if (event
.end_minute
== 0 && start
!= end
)
2144 event
.end_minute
= 24 * 60;
2146 g_array_append_val (psi
->events
, event
);
2152 print_week_summary (GtkPrintContext
*context
,
2155 gboolean multi_week_view
,
2159 gdouble font_size_background
,
2166 EWeekViewEvent
*event
;
2167 struct psinfo psi
= { 0 };
2169 gint rows_per_day
[E_WEEK_VIEW_MAX_WEEKS
* 7], day
, event_num
;
2171 PangoFontDescription
*font
, *font_background
;
2172 gdouble cell_width
, cell_height
;
2174 zone
= e_cal_model_get_timezone (model
);
2176 psi
.days_shown
= weeks_shown
* 7;
2177 psi
.events
= g_array_new (FALSE
, FALSE
, sizeof (EWeekViewEvent
));
2178 psi
.multi_week_view
= multi_week_view
;
2179 psi
.weeks_shown
= weeks_shown
;
2183 /* Get a few config settings. */
2184 if (multi_week_view
)
2185 psi
.compress_weekend
= e_cal_model_get_compress_weekend (model
);
2187 psi
.compress_weekend
= TRUE
;
2188 psi
.use_24_hour_format
= e_cal_model_get_use_24_hour_format (model
);
2190 psi
.display_start_weekday
= e_cal_model_get_week_start_day (model
);
2192 /* If weekends are compressed then we can't start on a Sunday. */
2193 if (psi
.compress_weekend
&& psi
.display_start_weekday
== G_DATE_SUNDAY
)
2194 psi
.display_start_weekday
= G_DATE_SATURDAY
;
2196 day_start
= time_day_begin_with_zone (whence
, zone
);
2197 for (day
= 0; day
<= psi
.days_shown
; day
++) {
2198 psi
.day_starts
[day
] = day_start
;
2199 day_start
= time_add_day_with_zone (day_start
, 1, zone
);
2202 /* Get the events from the server. */
2203 e_cal_model_generate_instances_sync (
2205 psi
.day_starts
[0], psi
.day_starts
[psi
.days_shown
],
2206 print_week_summary_cb
, &psi
);
2208 psi
.events
->data
, psi
.events
->len
,
2209 sizeof (EWeekViewEvent
), e_week_view_event_sort_func
);
2211 /* Layout the events. */
2212 spans
= e_week_view_layout_events (
2214 psi
.multi_week_view
,
2216 psi
.compress_weekend
,
2217 psi
.display_start_weekday
,
2218 psi
.day_starts
, rows_per_day
);
2220 /* Calculate the size of the cells. */
2221 if (multi_week_view
) {
2222 cell_width
= (right
- left
) / (psi
.compress_weekend
? 6 : 7);
2223 cell_height
= (bottom
- top
) / (weeks_shown
* 2);
2225 cell_width
= (right
- left
) / 2;
2226 cell_height
= (bottom
- top
) / 6;
2229 /* Calculate the row height, using the normal font and with room for
2230 * space or a rectangle around it. */
2231 psi
.row_height
= font_size
* 1.2;
2232 psi
.header_row_height
= font_size
* 1.5;
2234 /* Calculate how many rows we can fit into each type of cell. */
2235 psi
.rows_per_cell
= ((cell_height
* 2) - psi
.header_row_height
)
2236 / (psi
.row_height
+ 2);
2237 psi
.rows_per_compressed_cell
= (cell_height
- psi
.header_row_height
)
2238 / (psi
.row_height
+ 2);
2240 /* Draw the grid and the day names/numbers. */
2241 font_background
= get_font_for_size (font_size_background
, PANGO_WEIGHT_NORMAL
);
2242 print_week_view_background (
2243 context
, font_background
, &psi
, left
, top
,
2244 cell_width
, cell_height
);
2245 pango_font_description_free (font_background
);
2247 /* Print the events. */
2248 font
= get_font_for_size (font_size
, PANGO_WEIGHT_NORMAL
);
2249 for (event_num
= 0; event_num
< psi
.events
->len
; event_num
++) {
2250 event
= &g_array_index (psi
.events
, EWeekViewEvent
, event_num
);
2252 context
, font
, &psi
, left
, top
,
2253 cell_width
, cell_height
, model
, event
, spans
);
2256 pango_font_description_free (font
);
2258 /* Free everything. */
2259 for (event_num
= 0; event_num
< psi
.events
->len
; event_num
++) {
2260 event
= &g_array_index (psi
.events
, EWeekViewEvent
, event_num
);
2261 g_object_unref (event
->comp_data
);
2263 g_array_free (psi
.events
, TRUE
);
2264 g_array_free (spans
, TRUE
);
2268 print_month_summary (GtkPrintContext
*context
,
2270 ECalendarView
*calendar_view
,
2271 EPrintView print_view_type
,
2281 struct icaltimetype tt
;
2283 PangoFontDescription
*font
;
2284 gboolean compress_weekend
;
2285 gint columns
, col
, month
, weeks
;
2286 GDateWeekday weekday
;
2288 gdouble font_size
, cell_width
, x1
, x2
, y1
, y2
;
2290 zone
= e_cal_model_get_timezone (model
);
2291 weekday
= e_cal_model_get_week_start_day (model
);
2292 compress_weekend
= e_cal_model_get_compress_weekend (model
);
2296 if (print_view_type
== E_PRINT_VIEW_MONTH
) {
2297 EWeekView
*week_view
;
2298 GDate first_day_shown
;
2299 gboolean multi_week_view
;
2302 week_view
= E_WEEK_VIEW (calendar_view
);
2303 weeks_shown
= e_week_view_get_weeks_shown (week_view
);
2304 multi_week_view
= e_week_view_get_multi_week_view (week_view
);
2305 e_week_view_get_first_day_shown (week_view
, &first_day_shown
);
2307 if (multi_week_view
&& !(weeks_shown
>= 4 &&
2308 g_date_valid (&first_day_shown
))) {
2309 weeks
= weeks_shown
;
2314 /* Remember which month we want. */
2315 tt
= icaltime_from_timet_with_zone (whence
, FALSE
, zone
);
2316 month
= tt
.month
- 1;
2318 /* Find the start of the month, and then the start of the week on
2319 * or before that day. */
2321 date
= time_month_begin_with_zone (whence
, zone
);
2323 wday
= e_weekday_to_tm_wday (weekday
);
2324 date
= time_week_begin_with_zone (date
, wday
, zone
);
2326 /* If weekends are compressed then we can't start on a Sunday. */
2327 if (compress_weekend
&& weekday
== G_DATE_SUNDAY
)
2328 date
= time_add_day_with_zone (date
, -1, zone
);
2330 /* do day names ... */
2332 /* We are only interested in outputting the weekday here, but we want
2333 * to be able to step through the week without worrying about
2334 * overflows making strftime choke, so we move near to the start of
2336 convert_timet_to_struct_tm (date
, zone
, &tm
);
2337 tm
.tm_mday
= (tm
.tm_mday
% 7) + 7;
2339 font
= get_font_for_size (MONTH_NORMAL_FONT_SIZE
, PANGO_WEIGHT_BOLD
);
2340 font_size
= get_font_size (font
);
2342 columns
= compress_weekend
? 6 : 7;
2343 cell_width
= (right
- left
) / columns
;
2345 y2
= top
+ font_size
* 1.5;
2347 for (col
= 0; col
< columns
; col
++) {
2348 if (tm
.tm_wday
== 6 && compress_weekend
)
2350 buffer
, sizeof (buffer
), "%s/%s",
2351 e_get_weekday_name (G_DATE_SATURDAY
, TRUE
),
2352 e_get_weekday_name (G_DATE_SUNDAY
, TRUE
));
2355 buffer
, sizeof (buffer
), "%s",
2356 e_get_weekday_name (
2357 tm
.tm_wday
? tm
.tm_wday
: 7, FALSE
));
2359 x1
= left
+ cell_width
* col
;
2360 x2
= x1
+ cell_width
;
2362 print_border (context
, x1
, x2
, y1
, y2
, 1.0, -1.0);
2363 print_text_line (context
, font
, buffer
, PANGO_ALIGN_CENTER
, x1
, x2
, y1
, y2
, TRUE
, NULL
);
2366 tm
.tm_wday
= (tm
.tm_wday
+ 1) % 7;
2368 pango_font_description_free (font
);
2371 print_week_summary (
2372 context
, model
, date
, TRUE
, weeks
, month
,
2373 MONTH_NORMAL_FONT_SIZE
, MONTH_NORMAL_FONT_SIZE
,
2374 left
, right
, top
, bottom
);
2378 print_todo_details (GtkPrintContext
*context
,
2379 ETable
*tasks_table
,
2387 PangoFontDescription
*font_summary
;
2388 gdouble y
, yend
, x
, xend
;
2389 struct icaltimetype
*tt
;
2394 /* We get the tasks directly from the TaskPad ETable. This means we
2395 * get them filtered & sorted for free. */
2396 g_return_if_fail (tasks_table
!= NULL
);
2397 model
= e_task_table_get_model (E_TASK_TABLE (tasks_table
));
2399 font_summary
= get_font_for_size (12, PANGO_WEIGHT_NORMAL
);
2401 cr
= gtk_print_context_get_cairo_context (context
);
2403 cairo_set_source_rgb (cr
, 0, 0, 0);
2404 cairo_set_line_width (cr
, 0.0);
2408 context
, _("Tasks"), font_summary
, PANGO_ALIGN_CENTER
,
2409 &left
, &top
, &right
, &bottom
, 1.0);
2414 rows
= e_table_model_row_count (E_TABLE_MODEL (model
));
2415 for (row
= 0; row
< rows
; row
++) {
2416 ECalModelComponent
*comp_data
;
2417 ECalComponent
*comp
;
2418 ECalComponentText summary
;
2421 model_row
= e_table_view_to_model_row (tasks_table
, row
);
2422 comp_data
= e_cal_model_get_component_at (model
, model_row
);
2426 comp
= e_cal_component_new ();
2427 e_cal_component_set_icalcomponent (
2428 comp
, icalcomponent_new_clone (comp_data
->icalcomp
));
2430 e_cal_component_get_summary (comp
, &summary
);
2431 if (!summary
.value
) {
2432 g_object_unref (comp
);
2439 g_object_unref (comp
);
2443 /* Print the box to put the tick in. */
2444 print_border (context
, x
+ 2, x
+ 8, y
+ 6, y
+ 15, 0.1, -1.0);
2446 /* If the task is complete, print a tick in the box. */
2447 e_cal_component_get_completed (comp
, &tt
);
2449 e_cal_component_free_icaltimetype (tt
);
2451 cr
= gtk_print_context_get_cairo_context (context
);
2452 cairo_set_source_rgb (cr
, 0, 0, 0);
2453 cairo_move_to (cr
, x
+ 3, y
+ 11);
2454 cairo_line_to (cr
, x
+ 5, y
+ 14);
2455 cairo_line_to (cr
, x
+ 7, y
+ 5.5);
2456 cairo_set_line_width (cr
, 1);
2461 context
, font_summary
, summary
.value
, -1,
2462 x
+ 14, y
+ 4, xend
, yend
, FALSE
, NULL
, NULL
, NULL
);
2464 y
+= get_font_size (font_summary
) - 5;
2465 cr
= gtk_print_context_get_cairo_context (context
);
2466 cairo_move_to (cr
, x
, y
);
2467 cairo_line_to (cr
, xend
, y
);
2468 cairo_set_line_width (cr
, 1);
2471 g_object_unref (comp
);
2474 pango_font_description_free (font_summary
);
2478 print_day_view (GtkPrintContext
*context
,
2479 ECalendarView
*cal_view
,
2480 ETable
*tasks_table
,
2484 GtkPageSetup
*setup
;
2487 gdouble todo
, l
, week_numbers_inc
, small_month_width
;
2489 gdouble width
, height
;
2492 model
= e_calendar_view_get_model (cal_view
);
2493 zone
= e_cal_model_get_timezone (model
);
2495 setup
= gtk_print_context_get_page_setup (context
);
2497 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
2498 height
= gtk_page_setup_get_page_height (setup
, GTK_UNIT_POINTS
);
2499 small_month_width
= calc_small_month_width (context
, HEADER_HEIGHT
);
2500 week_numbers_inc
= get_show_week_numbers () ? small_month_width
/ 7.0 : 0;
2502 for (i
= 0; i
< days
; i
++) {
2503 todo
= width
* 0.75;
2505 /* Print the main view with all the events in. */
2507 context
, model
, date
,
2508 0.0, todo
- 2.0, HEADER_HEIGHT
+ 4,
2511 /* Print the TaskPad down the right. */
2512 print_todo_details (
2513 context
, tasks_table
, 0, INT_MAX
,
2514 todo
, width
, HEADER_HEIGHT
+ 4,
2517 /* Print the filled border around the header. */
2519 context
, 0.0, width
,
2520 0.0, HEADER_HEIGHT
+ 4, 1.0, 0.9);
2522 /* Print the 2 mini calendar-months. */
2523 l
= width
- SMALL_MONTH_PAD
-
2524 (small_month_width
+ week_numbers_inc
) * 2 -
2525 SMALL_MONTH_SPACING
;
2528 context
, model
, date
,
2529 l
, 2, l
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 2,
2530 DATE_MONTH
| DATE_YEAR
, date
, date
, FALSE
);
2532 l
+= SMALL_MONTH_SPACING
+ small_month_width
+ week_numbers_inc
;
2535 time_add_month_with_zone (date
, 1, zone
),
2536 l
, 2, l
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 2,
2537 DATE_MONTH
| DATE_YEAR
, 0, 0, FALSE
);
2539 /* Print the date, e.g. '8th May, 2001'. */
2540 convert_timet_to_struct_tm (date
, zone
, &tm
);
2541 format_date (&tm
, DATE_DAY
| DATE_MONTH
| DATE_YEAR
,
2544 print_text_size_bold (
2545 context
, buf
, PANGO_ALIGN_LEFT
,
2549 /* Print the day, e.g. 'Tuesday'. */
2550 format_date (&tm
, DATE_DAYNAME
, buf
, 100);
2552 print_text_size_bold (
2553 context
, buf
, PANGO_ALIGN_LEFT
,
2556 HEADER_HEIGHT
+ 9 + 18);
2558 date
= time_add_day_with_zone (date
, 1, zone
);
2563 print_work_week_background (GtkPrintContext
*context
,
2572 PangoFontDescription
*font_hour
, *font_minute
;
2574 gdouble width
= DAY_VIEW_TIME_COLUMN_WIDTH
;
2576 gdouble font_size
, max_font_size
, hour_font_size
, minute_font_size
;
2578 const gchar
*minute
;
2579 const gint LONG_EVENT_OFFSET
= 6;
2580 gboolean use_24_hour
;
2582 gdouble hour_minute_xl
, hour_minute_xr
;
2585 use_24_hour
= e_cal_model_get_use_24_hour_format (model
);
2587 /* Fill the left time column in light-gray. */
2588 print_border (context
, left
, left
+ width
, top
, bottom
, -1.0, 0.9);
2589 /* Fill the right time column in light-gray */
2590 print_border (context
, right
- width
, right
, top
, bottom
, -1.0, 0.9);
2592 /* Draw the border around the entire view. */
2593 cr
= gtk_print_context_get_cairo_context (context
);
2595 cairo_set_source_rgb (cr
, 0, 0, 0);
2596 print_border (context
, left
, right
, top
, bottom
, 1.0, -1.0);
2598 /* Draw the vertical line on the right of the time column. */
2599 cr
= gtk_print_context_get_cairo_context (context
);
2600 cairo_set_line_width (cr
, 0.0);
2601 cairo_move_to (cr
, left
+ width
, bottom
);
2602 cairo_line_to (cr
, left
+ width
, top
);
2605 cairo_move_to (cr
, right
- width
, bottom
);
2606 cairo_line_to (cr
, right
- width
, top
);
2609 /* Calculate the row height. */
2611 yinc
= (top
- bottom
) / (pdi
->end_hour
- pdi
->start_hour
);
2613 yinc
= (bottom
- top
) / (pdi
->end_hour
- pdi
->start_hour
);
2615 /* Get the 2 fonts we need. */
2616 font_size
= yinc
* 0.6;
2617 max_font_size
= width
* 0.45;
2618 hour_font_size
= MIN (font_size
, max_font_size
);
2619 font_hour
= get_font_for_size (hour_font_size
, PANGO_WEIGHT_BOLD
);
2621 font_size
= yinc
* 0.33;
2622 max_font_size
= width
* 0.2;
2623 minute_font_size
= MIN (font_size
, max_font_size
);
2624 font_minute
= get_font_for_size (minute_font_size
, PANGO_WEIGHT_BOLD
);
2625 hour_minute_xr
= evo_calendar_print_renderer_get_width (
2626 context
, font_minute
, use_24_hour
? "00" : _("am"));
2628 hour_minute_xr
= MAX (
2630 evo_calendar_print_renderer_get_width (
2631 context
, font_minute
, _("pm")));
2634 hour_minute_xl
= left
+ width
- hour_minute_xr
- 3;
2635 hour_minute_xr
= right
- hour_minute_xr
- 3;
2636 for (i
= pdi
->start_hour
; i
< pdi
->end_hour
; i
++) {
2637 y
= top
+ yinc
* (row
+ 1);
2638 cr
= gtk_print_context_get_cairo_context (context
);
2639 cairo_set_source_rgb (cr
, 0, 0, 0);
2655 /* the hour label/minute */
2656 sprintf (buf
, "%d", hour
);
2658 context
, font_hour
, buf
, PANGO_ALIGN_RIGHT
,
2659 left
, hour_minute_xl
,
2660 y
- yinc
, y
- yinc
+ hour_font_size
);
2662 context
, font_minute
, minute
, PANGO_ALIGN_LEFT
,
2663 hour_minute_xl
, left
+ width
- 3,
2664 y
- yinc
, y
- yinc
+ minute_font_size
);
2668 context
, font_hour
, buf
, PANGO_ALIGN_RIGHT
,
2669 right
- width
, hour_minute_xr
,
2670 y
- yinc
, y
- yinc
+ hour_font_size
);
2672 context
, font_minute
, minute
, PANGO_ALIGN_LEFT
,
2673 hour_minute_xr
, right
- 3,
2674 y
- yinc
, y
- yinc
+ minute_font_size
);
2676 /* Draw the horizontal line between hours, across the entire
2677 width of the day view. */
2678 cr
= gtk_print_context_get_cairo_context (context
);
2679 cairo_move_to (cr
, left
, y
);
2680 cairo_line_to (cr
, right
, y
);
2681 cairo_set_line_width (cr
, 1);
2684 /* Draw the horizontal line for the 1/2-hours, across the
2685 * entire width except for part of the time column. */
2686 cairo_move_to (cr
, left
+ width
* 0.6, y
- yinc
/ 2);
2687 cairo_line_to (cr
, right
, y
- yinc
/ 2);
2688 cairo_set_line_width (cr
, 1);
2693 /* Draw the vertical lines for the days */
2694 day_width
= (right
- left
- 2 *width
) / pdi
->days_shown
;
2695 for (i
= 0; i
< pdi
->days_shown
- 1; ++i
) {
2696 cr
= gtk_print_context_get_cairo_context (context
);
2697 cairo_move_to (cr
, left
+ width
+ day_width
* (i
+ 1), top
);
2698 cairo_line_to (cr
, left
+ width
+ day_width
* (i
+ 1), bottom
);
2699 cairo_set_line_width (cr
, 1);
2703 /* And now the ones from the border to the hours, looks weird otherwise */
2704 cr
= gtk_print_context_get_cairo_context (context
);
2705 cairo_move_to (cr
, left
, HEADER_HEIGHT
);
2706 cairo_line_to (cr
, left
, HEADER_HEIGHT
+ DAY_VIEW_ROW_HEIGHT
+ LONG_EVENT_OFFSET
);
2708 cairo_move_to (cr
, right
, HEADER_HEIGHT
);
2709 cairo_line_to (cr
, right
, HEADER_HEIGHT
+ DAY_VIEW_ROW_HEIGHT
+ LONG_EVENT_OFFSET
);
2712 pango_font_description_free (font_hour
);
2713 pango_font_description_free (font_minute
);
2717 print_work_week_day_details (GtkPrintContext
*context
,
2724 struct pdinfo
*_pdi
)
2727 EDayViewEvent
*event
;
2728 PangoFontDescription
*font
;
2730 struct pdinfo pdi
= { 0 };
2731 gint rows_in_top_display
, i
, rows_with_30_mins
;
2732 gdouble font_size
, max_font_size
;
2734 GdkPixbuf
*pixbuf
= NULL
;
2735 #define LONG_DAY_EVENTS_TOP_SPACING 4
2736 #define LONG_DAY_EVENTS_BOTTOM_SPACING 2
2738 zone
= e_cal_model_get_timezone (model
);
2740 start
= time_day_begin_with_zone (whence
, zone
);
2741 end
= time_day_end_with_zone (start
, zone
);
2744 pdi
.day_starts
[0] = start
;
2745 pdi
.day_starts
[1] = end
;
2746 pdi
.long_events
= g_array_new (FALSE
, FALSE
, sizeof (EDayViewEvent
));
2747 pdi
.events
[0] = g_array_new (FALSE
, FALSE
, sizeof (EDayViewEvent
));
2748 pdi
.start_hour
= e_cal_model_get_work_day_start_hour (model
);
2749 pdi
.end_hour
= e_cal_model_get_work_day_end_hour (model
);
2750 if (e_cal_model_get_work_day_end_minute (model
) != 0)
2752 pdi
.mins_per_row
= get_day_view_time_divisions ();
2753 pdi
.rows
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / pdi
.mins_per_row
);
2754 pdi
.start_minute_offset
= pdi
.start_hour
* 60;
2755 pdi
.end_minute_offset
= pdi
.end_hour
* 60;
2756 pdi
.use_24_hour_format
= e_cal_model_get_use_24_hour_format (model
);
2757 pdi
.zone
= e_cal_model_get_timezone (model
);
2759 /* Get the events from the server. */
2760 e_cal_model_generate_instances_sync (model
, start
, end
, print_day_details_cb
, &pdi
);
2762 pdi
.long_events
->data
, pdi
.long_events
->len
,
2763 sizeof (EDayViewEvent
), e_day_view_event_sort_func
);
2765 pdi
.events
[0]->data
, pdi
.events
[0]->len
,
2766 sizeof (EDayViewEvent
), e_day_view_event_sort_func
);
2768 pdi
.start_hour
= MIN (pdi
.start_hour
, _pdi
->start_hour
);
2769 pdi
.end_hour
= MAX (pdi
.end_hour
, _pdi
->end_hour
);
2771 /* TODO: This should be redundant */
2772 /* Also print events outside of work hours */
2773 if (pdi
.events
[0]->len
> 0) {
2774 struct icaltimetype tt
;
2776 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, 0);
2777 tt
= icaltime_from_timet_with_zone (event
->start
, FALSE
, zone
);
2778 if (tt
.hour
< pdi
.start_hour
)
2779 pdi
.start_hour
= tt
.hour
;
2780 pdi
.start_minute_offset
= pdi
.start_hour
* 60;
2782 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, pdi
.events
[0]->len
- 1);
2783 tt
= icaltime_from_timet_with_zone (event
->end
, FALSE
, zone
);
2784 if (tt
.hour
> pdi
.end_hour
|| tt
.hour
== 0) {
2785 pdi
.end_hour
= tt
.hour
? tt
.hour
: 24;
2789 pdi
.end_minute_offset
= pdi
.end_hour
* 60;
2791 pdi
.rows
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / pdi
.mins_per_row
);
2794 /* Lay them out the long events, across the top of the page. */
2795 e_day_view_layout_long_events (
2796 pdi
.long_events
, pdi
.days_shown
,
2797 pdi
.day_starts
, &rows_in_top_display
);
2799 /*Print the long events. */
2800 font
= get_font_for_size (12, PANGO_WEIGHT_NORMAL
);
2802 /* We always leave space for DAY_VIEW_MIN_ROWS_IN_TOP_DISPLAY in the
2803 * top display, but we may have more rows than that, in which case
2804 * the main display area will be compressed. */
2805 /* Limit long day event to half the height of the panel */
2806 rows_in_top_display
= MIN (
2807 MAX (rows_in_top_display
,
2808 DAY_VIEW_MIN_ROWS_IN_TOP_DISPLAY
),
2809 (bottom
- top
) * 0.5 / DAY_VIEW_ROW_HEIGHT
);
2811 if (rows_in_top_display
> pdi
.long_events
->len
)
2812 rows_in_top_display
= pdi
.long_events
->len
;
2814 for (i
= 0; i
< rows_in_top_display
&& i
< pdi
.long_events
->len
; i
++) {
2815 event
= &g_array_index (pdi
.long_events
, EDayViewEvent
, i
);
2816 print_day_long_event (
2817 context
, font
, left
, right
,
2818 top
+ LONG_DAY_EVENTS_TOP_SPACING
, bottom
,
2819 DAY_VIEW_ROW_HEIGHT
, event
, &pdi
, model
);
2822 if (rows_in_top_display
< pdi
.long_events
->len
) {
2823 /* too many events */
2824 cairo_t
*cr
= gtk_print_context_get_cairo_context (context
);
2828 const gchar
**xpm
= (const gchar
**) jump_xpm
;
2830 pixbuf
= gdk_pixbuf_new_from_xpm_data (xpm
);
2833 /* Right align - 10 comes from print_day_long_event too */
2834 x
= right
- gdk_pixbuf_get_width (pixbuf
) * 0.5 - 10;
2835 /* Placing '...' over the last all day event entry printed. '-1 -1' comes
2836 from print_long_day_event (top / bottom spacing in each cell) */
2837 y
= top
+ LONG_DAY_EVENTS_TOP_SPACING
2838 + DAY_VIEW_ROW_HEIGHT
* (i
- 1)
2839 + (DAY_VIEW_ROW_HEIGHT
- 1 - 1) * 0.5;
2842 cairo_scale (cr
, 0.5, 0.5);
2843 gdk_cairo_set_source_pixbuf (cr
, pixbuf
, x
* 2.0, y
* 2.0);
2848 if (!rows_in_top_display
)
2849 rows_in_top_display
++;
2851 /* Draw the border around the long events. */
2852 cr
= gtk_print_context_get_cairo_context (context
);
2854 cairo_set_source_rgb (cr
, 0, 0, 0);
2856 context
, left
, right
,
2857 top
, top
+ rows_in_top_display
* DAY_VIEW_ROW_HEIGHT
+
2858 LONG_DAY_EVENTS_TOP_SPACING
+ LONG_DAY_EVENTS_BOTTOM_SPACING
,
2861 /* Adjust the area containing the main display. */
2862 top
+= rows_in_top_display
* DAY_VIEW_ROW_HEIGHT
2863 + LONG_DAY_EVENTS_TOP_SPACING
2864 + LONG_DAY_EVENTS_BOTTOM_SPACING
;
2866 /* lay out the short events, within the day. */
2867 e_day_view_layout_day_events (
2868 pdi
.events
[0], CALC_DAY_VIEW_ROWS (pdi
.mins_per_row
),
2869 pdi
.mins_per_row
, pdi
.cols_per_row
, -1);
2871 /* use font like with 30 minutes time division */
2872 rows_with_30_mins
= (pdi
.end_hour
- pdi
.start_hour
) * (60 / 30);
2874 pango_font_description_free (font
);
2876 /* print the short events. */
2878 max_font_size
= ((top
- bottom
) / rows_with_30_mins
) - 4;
2880 max_font_size
= ((bottom
- top
) / rows_with_30_mins
) - 4;
2881 font_size
= MIN (DAY_NORMAL_FONT_SIZE
, max_font_size
);
2882 font
= get_font_for_size (font_size
, PANGO_WEIGHT_NORMAL
);
2884 for (i
= 0; i
< pdi
.events
[0]->len
; i
++) {
2885 event
= &g_array_index (pdi
.events
[0], EDayViewEvent
, i
);
2887 context
, font
, left
,
2888 right
, top
, bottom
, event
, &pdi
, model
);
2891 /* Free everything. */
2893 g_object_unref (pixbuf
);
2894 free_event_array (pdi
.long_events
);
2895 pango_font_description_free (font
);
2896 g_array_free (pdi
.long_events
, TRUE
);
2897 free_event_array (pdi
.events
[0]);
2898 g_array_free (pdi
.events
[0], TRUE
);
2901 /* Figure out what the overal hour limits are */
2903 print_work_week_view_cb (ECalComponent
*comp
,
2908 ECalModelGenerateInstancesData
*mdata
= (ECalModelGenerateInstancesData
*) data
;
2909 struct pdinfo
*pdi
= (struct pdinfo
*) mdata
->cb_data
;
2910 struct icaltimetype tt
;
2912 tt
= icaltime_from_timet_with_zone (istart
, FALSE
, pdi
->zone
);
2913 pdi
->start_hour
= MIN (pdi
->start_hour
, tt
.hour
);
2915 tt
= icaltime_from_timet_with_zone (iend
, FALSE
, pdi
->zone
);
2916 /* If we're past the hour, use the next one */
2917 pdi
->end_hour
= MAX (pdi
->end_hour
, tt
.minute
? tt
.hour
+ 1 : tt
.hour
);
2923 print_work_week_view (GtkPrintContext
*context
,
2924 ECalendarView
*cal_view
,
2927 GtkPageSetup
*setup
;
2929 time_t when
, start
, end
;
2930 gdouble width
, height
, l
;
2931 gdouble small_month_width
;
2932 gdouble weeknum_inc
;
2935 const gint LONG_EVENT_OFFSET
= 6;
2936 struct pdinfo pdi
= { 0 };
2938 gdouble day_width
, day_x
;
2941 model
= e_calendar_view_get_model (cal_view
);
2942 zone
= e_cal_model_get_timezone (model
);
2944 setup
= gtk_print_context_get_page_setup (context
);
2946 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
2947 height
= gtk_page_setup_get_page_height (setup
, GTK_UNIT_POINTS
);
2949 small_month_width
= calc_small_month_width (context
, HEADER_HEIGHT
);
2950 weeknum_inc
= get_show_week_numbers () ? small_month_width
/ 7.0 : 0;
2952 /* We always start on a Monday */
2953 start
= time_week_begin_with_zone (date
, 1, zone
);
2954 end
= time_add_day_with_zone (start
, days
, zone
);
2956 pdi
.days_shown
= days
;
2957 pdi
.start_hour
= e_cal_model_get_work_day_start_hour (model
);
2958 pdi
.end_hour
= e_cal_model_get_work_day_end_hour (model
);
2961 e_cal_model_generate_instances_sync (model
, start
, end
, print_work_week_view_cb
, &pdi
);
2963 print_work_week_background (
2964 context
, model
, date
, &pdi
, 0.0, width
,
2965 HEADER_HEIGHT
+ DAY_VIEW_ROW_HEIGHT
+ LONG_EVENT_OFFSET
,
2968 print_border (context
, 0.0, width
, 0.0, HEADER_HEIGHT
, 1.0, 0.9);
2970 /* Print the 2 mini calendar-months. */
2971 l
= width
- SMALL_MONTH_PAD
- (small_month_width
+ weeknum_inc
) * 2 -
2972 SMALL_MONTH_SPACING
;
2975 context
, model
, start
,
2976 l
, 4, l
+ small_month_width
+ weeknum_inc
, HEADER_HEIGHT
+ 4,
2977 DATE_MONTH
| DATE_YEAR
, start
, end
, FALSE
);
2979 l
+= SMALL_MONTH_SPACING
+ small_month_width
+ weeknum_inc
;
2982 time_add_month_with_zone (start
, 1, zone
),
2983 l
, 4, l
+ small_month_width
+ weeknum_inc
, HEADER_HEIGHT
+ 4,
2984 DATE_MONTH
| DATE_YEAR
, 0, 0, FALSE
);
2986 /* Print the start day of the week, e.g. '7th May 2001'. */
2987 convert_timet_to_struct_tm (start
, zone
, &tm
);
2988 format_date (&tm
, DATE_DAY
| DATE_MONTH
| DATE_YEAR
, buf
, 100);
2989 print_text_size_bold (
2990 context
, buf
, PANGO_ALIGN_LEFT
,
2994 /* Print the end day of the week, e.g. '13th May 2001'. */
2995 /* We need to substract one or the wrong day will be printed */
2996 convert_timet_to_struct_tm (
2997 time_add_day_with_zone (end
, -1, zone
), zone
, &tm
);
2998 format_date (&tm
, DATE_DAY
| DATE_MONTH
| DATE_YEAR
, buf
, 100);
2999 print_text_size_bold (
3000 context
, buf
, PANGO_ALIGN_LEFT
,
3002 24 + 3, 24 + 3 + 24);
3004 /* Now print each days' events */
3005 day_width
= (width
- 2 *DAY_VIEW_TIME_COLUMN_WIDTH
) / days
;
3007 for (i
= 0; i
< days
; ++i
) {
3008 day_x
= DAY_VIEW_TIME_COLUMN_WIDTH
+ day_width
* i
;
3010 /* Print the day, e.g. 'Tuesday'. */
3011 convert_timet_to_struct_tm (when
, zone
, &tm
);
3012 format_date (&tm
, DATE_DAYNAME
, buf
, 100);
3014 print_text_size_bold (
3015 context
, buf
, PANGO_ALIGN_LEFT
,
3016 day_x
+ 4, day_x
+ day_width
,
3017 HEADER_HEIGHT
+ 4, HEADER_HEIGHT
+ 4 + 18);
3019 print_work_week_day_details (
3020 context
, model
, when
,
3021 day_x
, day_x
+ day_width
,
3022 HEADER_HEIGHT
, height
, &pdi
);
3023 when
= time_add_day_with_zone (when
, 1, zone
);
3028 print_week_view (GtkPrintContext
*context
,
3029 ECalendarView
*cal_view
,
3032 GtkPageSetup
*setup
;
3035 gdouble l
, week_numbers_inc
, small_month_width
;
3038 GDateWeekday week_start_day
;
3041 gdouble width
, height
;
3043 setup
= gtk_print_context_get_page_setup (context
);
3045 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
3046 height
= gtk_page_setup_get_page_height (setup
, GTK_UNIT_POINTS
);
3047 small_month_width
= calc_small_month_width (context
, HEADER_HEIGHT
);
3048 week_numbers_inc
= get_show_week_numbers () ? small_month_width
/ 7.0 : 0;
3050 model
= e_calendar_view_get_model (cal_view
);
3051 zone
= e_cal_model_get_timezone (model
);
3053 convert_timet_to_struct_tm (date
, zone
, &tm
);
3054 week_start_day
= e_cal_model_get_week_start_day (model
);
3056 wday
= e_weekday_to_tm_wday (week_start_day
);
3057 when
= time_week_begin_with_zone (date
, wday
, zone
);
3059 /* If the week starts on a Sunday, we have to show the Saturday first,
3060 * since the weekend is compressed. */
3061 if (week_start_day
== G_DATE_SUNDAY
) {
3062 if (tm
.tm_wday
== 6)
3063 when
= time_add_day_with_zone (when
, 6, zone
);
3065 when
= time_add_day_with_zone (when
, -1, zone
);
3068 /* Print the main week view. */
3069 print_week_summary (
3070 context
, model
, when
, FALSE
, 1, 0,
3071 WEEK_EVENT_FONT_SIZE
, WEEK_SMALL_FONT_SIZE
,
3073 HEADER_HEIGHT
+ 20, height
);
3075 /* Print the border around the main view. */
3077 context
, 0.0, width
, HEADER_HEIGHT
,
3080 /* Print the border around the header area. */
3082 context
, 0.0, width
,
3083 0.0, HEADER_HEIGHT
+ 2.0 + 20, 1.0, 0.9);
3085 /* Print the 2 mini calendar-months. */
3086 l
= width
- SMALL_MONTH_PAD
- (small_month_width
+ week_numbers_inc
) * 2
3087 - SMALL_MONTH_SPACING
;
3089 context
, model
, when
,
3090 l
, 4, l
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 10,
3091 DATE_MONTH
| DATE_YEAR
, when
,
3092 time_add_week_with_zone (when
, 1, zone
), FALSE
);
3094 l
+= SMALL_MONTH_SPACING
+ small_month_width
+ week_numbers_inc
;
3097 time_add_month_with_zone (when
, 1, zone
),
3098 l
, 4, l
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 10,
3099 DATE_MONTH
| DATE_YEAR
, when
,
3100 time_add_week_with_zone (when
, 1, zone
), FALSE
);
3102 /* Print the start day of the week, e.g. '7th May 2001'. */
3103 convert_timet_to_struct_tm (when
, zone
, &tm
);
3104 format_date (&tm
, DATE_DAY
| DATE_MONTH
| DATE_YEAR
, buf
, 100);
3105 print_text_abs_bold (
3106 context
, buf
, WEEK_NORMAL_FONT_SIZE
, PANGO_ALIGN_LEFT
,
3107 3, width
, 4, 4 + 24);
3109 /* Print the end day of the week, e.g. '13th May 2001'. */
3110 when
= time_add_day_with_zone (when
, 6, zone
);
3111 convert_timet_to_struct_tm (when
, zone
, &tm
);
3112 format_date (&tm
, DATE_DAY
| DATE_MONTH
| DATE_YEAR
, buf
, 100);
3113 print_text_abs_bold (
3114 context
, buf
, WEEK_NORMAL_FONT_SIZE
, PANGO_ALIGN_LEFT
,
3115 3, width
, 24 + 3, 24 + 3 + 24);
3119 print_month_view (GtkPrintContext
*context
,
3120 ECalendarView
*cal_view
,
3121 EPrintView print_view_type
,
3125 GtkPageSetup
*setup
;
3128 gdouble width
, height
;
3129 gdouble l
, week_numbers_inc
, small_month_width
;
3132 model
= e_calendar_view_get_model (cal_view
);
3133 zone
= e_cal_model_get_timezone (model
);
3135 setup
= gtk_print_context_get_page_setup (context
);
3137 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
3138 height
= gtk_page_setup_get_page_height (setup
, GTK_UNIT_POINTS
);
3139 small_month_width
= calc_small_month_width (context
, HEADER_HEIGHT
);
3140 week_numbers_inc
= get_show_week_numbers () ? small_month_width
/ 7.0 : 0;
3142 /* Print the main month view. */
3143 print_month_summary (context
, model
, cal_view
, print_view_type
, date
, 0.0, width
, HEADER_HEIGHT
, height
);
3145 /* Print the border around the header. */
3146 print_border (context
, 0.0, width
, 0.0, HEADER_HEIGHT
+ 10, 1.0, 0.9);
3148 l
= width
- SMALL_MONTH_PAD
- small_month_width
- week_numbers_inc
;
3150 /* Print the 2 mini calendar-months. */
3153 time_add_month_with_zone (date
, 1, zone
),
3154 l
, 4, l
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 4,
3155 DATE_MONTH
| DATE_YEAR
, 0, 0, FALSE
);
3159 time_add_month_with_zone (date
, -1, zone
),
3160 SMALL_MONTH_PAD
, 4, SMALL_MONTH_PAD
+ small_month_width
+ week_numbers_inc
, HEADER_HEIGHT
+ 4,
3161 DATE_MONTH
| DATE_YEAR
, 0, 0, FALSE
);
3163 /* Print the month, e.g. 'May 2001'. */
3164 convert_timet_to_struct_tm (date
, zone
, &tm
);
3165 format_date (&tm
, DATE_MONTH
| DATE_YEAR
, buf
, 100);
3166 print_text_size_bold (
3167 context
, buf
, PANGO_ALIGN_CENTER
,
3174 same_date (struct tm tm1
,
3180 convert_timet_to_struct_tm (t2
, zone
, &tm2
);
3183 tm1
.tm_mday
== tm2
.tm_mday
&&
3184 tm1
.tm_mon
== tm2
.tm_mon
&&
3185 tm1
.tm_year
== tm2
.tm_year
;
3189 write_label_piece (time_t t
,
3192 gboolean use_24_hour_format
,
3201 convert_timet_to_struct_tm (t
, zone
, &tmp_tm
);
3204 strcat (buffer
, stext
);
3206 len
= strlen (buffer
);
3207 if (start_cmp
&& same_date (tmp_tm
, *start_cmp
, zone
))
3208 e_time_format_time (
3209 &tmp_tm
, use_24_hour_format
,
3210 FALSE
, &buffer
[len
], size
- len
);
3212 e_time_format_date_and_time (
3213 &tmp_tm
, use_24_hour_format
, FALSE
,
3214 FALSE
, &buffer
[len
], size
- len
);
3216 strcat (buffer
, etext
);
3219 static icaltimezone
*
3220 get_zone_from_tzid (ECalClient
*client
,
3225 /* Note that the timezones may not be on the server, so we try to get
3226 * the builtin timezone with the TZID first. */
3227 zone
= icaltimezone_get_builtin_timezone_from_tzid (tzid
);
3228 if (!zone
&& tzid
) {
3229 GError
*error
= NULL
;
3231 e_cal_client_get_timezone_sync (
3232 client
, tzid
, &zone
, NULL
, &error
);
3234 if (error
!= NULL
) {
3236 "Couldn't get timezone '%s' from server: %s",
3237 tzid
? tzid
: "", error
->message
);
3238 g_error_free (error
);
3246 print_date_label (GtkPrintContext
*context
,
3247 ECalComponent
*comp
,
3250 gboolean use_24_hour_format
,
3256 icaltimezone
*start_zone
, *end_zone
, *due_zone
, *completed_zone
;
3257 ECalComponentDateTime datetime
;
3258 time_t start
= 0, end
= 0, complete
= 0, due
= 0;
3259 static gchar buffer
[1024];
3261 e_cal_component_get_dtstart (comp
, &datetime
);
3262 if (datetime
.value
) {
3263 start_zone
= get_zone_from_tzid (client
, datetime
.tzid
);
3264 if (!start_zone
|| datetime
.value
->is_date
)
3266 start
= icaltime_as_timet_with_zone (
3270 e_cal_component_free_datetime (&datetime
);
3272 e_cal_component_get_dtend (comp
, &datetime
);
3273 if (datetime
.value
) {
3274 end_zone
= get_zone_from_tzid (client
, datetime
.tzid
);
3275 if (!end_zone
|| datetime
.value
->is_date
)
3277 end
= icaltime_as_timet_with_zone (
3281 e_cal_component_free_datetime (&datetime
);
3283 e_cal_component_get_due (comp
, &datetime
);
3284 if (datetime
.value
) {
3285 due_zone
= get_zone_from_tzid (client
, datetime
.tzid
);
3286 if (!due_zone
|| datetime
.value
->is_date
)
3288 due
= icaltime_as_timet_with_zone (
3289 *datetime
.value
, due_zone
);
3291 e_cal_component_free_datetime (&datetime
);
3293 e_cal_component_get_completed (comp
, &datetime
.value
);
3294 if (datetime
.value
) {
3295 completed_zone
= icaltimezone_get_utc_timezone ();
3296 complete
= icaltime_as_timet_with_zone (
3297 *datetime
.value
, completed_zone
);
3298 e_cal_component_free_icaltimetype (datetime
.value
);
3305 start
, NULL
, zone
, use_24_hour_format
,
3306 buffer
, 1024, NULL
, NULL
);
3308 if (end
> 0 && start
> 0) {
3310 end
, &start
, zone
, use_24_hour_format
,
3311 /* Translators: This is part of "START to END" text,
3312 * where START and END are date/times. */
3313 buffer
, 1024, _(" to "), NULL
);
3319 complete
, NULL
, zone
, use_24_hour_format
,
3320 /* Translators: This is part of "START to END
3321 * (Completed COMPLETED)", where COMPLETED is a
3322 * completed date/time. */
3323 buffer
, 1024, _(" (Completed "), ")");
3326 complete
, &start
, zone
, use_24_hour_format
,
3327 /* Translators: This is part of "Completed COMPLETED",
3328 * where COMPLETED is a completed date/time. */
3329 buffer
, 1024, _("Completed "), NULL
);
3333 if (due
> 0 && complete
== 0) {
3336 due
, NULL
, zone
, use_24_hour_format
,
3337 /* Translators: This is part of "START (Due DUE)",
3338 * where START and DUE are dates/times. */
3339 buffer
, 1024, _(" (Due "), ")");
3342 due
, &start
, zone
, use_24_hour_format
,
3343 /* Translators: This is part of "Due DUE",
3344 * where DUE is a date/time due the event
3345 * should be finished. */
3346 buffer
, 1024, _("Due "), NULL
);
3350 print_text_size_bold (
3351 context
, buffer
, PANGO_ALIGN_LEFT
,
3352 left
, right
, top
, top
+ 24);
3356 print_calendar_draw_page (GtkPrintOperation
*operation
,
3357 GtkPrintContext
*context
,
3359 PrintCalItem
*pcali
)
3361 switch (pcali
->print_view_type
) {
3362 case E_PRINT_VIEW_DAY
:
3363 print_day_view (context
, pcali
->cal_view
, pcali
->tasks_table
, pcali
->start
);
3365 case E_PRINT_VIEW_WORKWEEK
:
3366 print_work_week_view (context
, pcali
->cal_view
, pcali
->start
);
3368 case E_PRINT_VIEW_WEEK
:
3369 print_week_view (context
, pcali
->cal_view
, pcali
->start
);
3371 case E_PRINT_VIEW_MONTH
:
3372 print_month_view (context
, pcali
->cal_view
, pcali
->print_view_type
, pcali
->start
);
3375 g_return_if_reached ();
3380 print_calendar (ECalendarView
*cal_view
,
3381 ETable
*tasks_table
,
3382 EPrintView print_view_type
,
3383 GtkPrintOperationAction action
,
3386 GtkPrintOperation
*operation
;
3389 g_return_if_fail (cal_view
!= NULL
);
3390 g_return_if_fail (E_IS_CALENDAR_VIEW (cal_view
));
3392 if (print_view_type
== E_PRINT_VIEW_MONTH
) {
3393 EWeekView
*week_view
;
3395 gboolean multi_week_view
;
3398 week_view
= E_WEEK_VIEW (cal_view
);
3399 weeks_shown
= e_week_view_get_weeks_shown (week_view
);
3400 multi_week_view
= e_week_view_get_multi_week_view (week_view
);
3401 e_week_view_get_first_day_shown (week_view
, &date
);
3403 if (multi_week_view
&&
3405 g_date_valid (&date
)) {
3407 struct icaltimetype start_tt
;
3409 g_date_add_days (&date
, 7);
3411 start_tt
= icaltime_null_time ();
3412 start_tt
.is_date
= TRUE
;
3413 start_tt
.year
= g_date_get_year (&date
);
3414 start_tt
.month
= g_date_get_month (&date
);
3415 start_tt
.day
= g_date_get_day (&date
);
3417 start
= icaltime_as_timet (start_tt
);
3418 } else if (multi_week_view
) {
3419 start
= week_view
->day_starts
[0];
3423 pcali
.cal_view
= cal_view
;
3424 pcali
.tasks_table
= tasks_table
;
3425 pcali
.print_view_type
= print_view_type
;
3426 pcali
.start
= start
;
3428 operation
= e_print_operation_new ();
3429 gtk_print_operation_set_n_pages (operation
, 1);
3432 operation
, "draw_page",
3433 G_CALLBACK (print_calendar_draw_page
), &pcali
);
3435 gtk_print_operation_run (operation
, action
, NULL
, NULL
);
3437 g_object_unref (operation
);
3440 /* returns number of required pages, when page_nr is -1 */
3442 print_comp_draw_real (GtkPrintOperation
*operation
,
3443 GtkPrintContext
*context
,
3447 GtkPageSetup
*setup
;
3448 PangoFontDescription
*font
;
3450 ECalComponent
*comp
;
3451 ECalComponentVType vtype
;
3452 ECalComponentText text
;
3454 GSList
*contact_list
, *elem
;
3456 const gchar
*title
, *categories
, *location
;
3457 gchar
*categories_string
, *location_string
, *summary_string
;
3458 gdouble header_size
;
3460 gdouble width
, height
, page_start
;
3464 setup
= gtk_print_context_get_page_setup (context
);
3466 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
3467 height
= gtk_page_setup_get_page_height (setup
, GTK_UNIT_POINTS
);
3471 /* Either draw only the right page or do not draw
3472 * anything when calculating number of pages. */
3474 top
= top
- ((page_nr
) * height
);
3480 /* PrintCompItem structure contains elements to be used
3481 * with the Print Context , obtained in comp_draw_page
3483 client
= pci
->client
;
3486 vtype
= e_cal_component_get_vtype (comp
);
3488 /* We should only be asked to print VEVENTs, VTODOs, or VJOURNALs. */
3489 if (vtype
== E_CAL_COMPONENT_EVENT
)
3490 title
= _("Appointment");
3491 else if (vtype
== E_CAL_COMPONENT_TODO
)
3493 else if (vtype
== E_CAL_COMPONENT_JOURNAL
)
3498 cr
= gtk_print_context_get_cairo_context (context
);
3500 /* Print the title in a box at the top of the page. */
3501 font
= get_font_for_size (18, PANGO_WEIGHT_BOLD
);
3506 context
, 0.0, width
, 0.0, header_size
,
3509 context
, font
, title
, PANGO_ALIGN_CENTER
, 0.0, width
,
3510 0.1, header_size
- 0.1);
3513 pango_font_description_free (font
);
3515 top
+= header_size
+ 30;
3518 font
= get_font_for_size (18, PANGO_WEIGHT_BOLD
);
3519 e_cal_component_get_summary (comp
, &text
);
3520 summary_string
= g_strdup_printf (_("Summary: %s"), text
.value
? text
.value
: "");
3522 context
, font
, summary_string
, -1, 0.0, top
, width
,
3523 height
, FALSE
, NULL
, &page_start
, &pages
);
3525 g_free (summary_string
);
3528 e_cal_component_get_location (comp
, &location
);
3529 if (location
&& location
[0]) {
3530 location_string
= g_strdup_printf (
3534 context
, font
, location_string
, -1, 0.0,
3535 top
+ 3, width
, height
, FALSE
, NULL
, &page_start
, &pages
);
3536 g_free (location_string
);
3539 /* Date information */
3542 context
, comp
, client
,
3543 pci
->zone
, pci
->use_24_hour_format
,
3544 0.0, width
, top
+ 3, top
+ 15);
3548 if ((page_nr
== 0) && e_cal_component_has_attendees (comp
)) {
3550 context
, font
, _("Attendees: "), -1, 0.0,
3551 top
, width
, height
, FALSE
, NULL
, &page_start
, &pages
);
3552 pango_font_description_free (font
);
3553 font
= get_font_for_size (12, PANGO_WEIGHT_NORMAL
);
3554 top
= print_attendees (
3555 context
, font
, cr
, 0.0, width
,
3556 top
, height
, comp
, page_nr
, &pages
);
3557 top
+= get_font_size (font
) - 6;
3560 pango_font_description_free (font
);
3562 font
= get_font_for_size (12, PANGO_WEIGHT_NORMAL
);
3564 /* For a VTODO we print the Status, Priority, % Complete and URL. */
3565 if (vtype
== E_CAL_COMPONENT_TODO
) {
3566 icalproperty_status status
;
3567 const gchar
*status_string
= NULL
;
3573 e_cal_component_get_status (comp
, &status
);
3574 if (status
!= ICAL_STATUS_NONE
) {
3576 case ICAL_STATUS_NEEDSACTION
:
3577 status_string
= _("Not Started");
3579 case ICAL_STATUS_INPROCESS
:
3580 status_string
= _("In Progress");
3582 case ICAL_STATUS_COMPLETED
:
3583 status_string
= _("Completed");
3585 case ICAL_STATUS_CANCELLED
:
3586 status_string
= _("Cancelled");
3592 if (status_string
) {
3593 gchar
*status_text
= g_strdup_printf (
3597 context
, font
, status_text
, -1,
3598 0.0, top
, width
, height
, FALSE
, NULL
, &page_start
, &pages
);
3599 top
+= get_font_size (font
) - 6;
3600 g_free (status_text
);
3605 e_cal_component_get_priority (comp
, &priority
);
3606 if (priority
&& *priority
>= 0) {
3609 pri_text
= g_strdup_printf (
3611 e_cal_util_priority_to_string (*priority
));
3613 context
, font
, pri_text
, -1,
3614 0.0, top
, width
, height
, FALSE
, NULL
,
3615 &page_start
, &pages
);
3616 top
+= get_font_size (font
) - 6;
3621 e_cal_component_free_priority (priority
);
3623 /* Percent Complete */
3624 e_cal_component_get_percent (comp
, &percent
);
3626 gchar
*percent_string
;
3628 percent_string
= g_strdup_printf (_("Percent Complete: %i"), *percent
);
3629 e_cal_component_free_percent (percent
);
3632 context
, font
, percent_string
, -1,
3633 0.0, top
, width
, height
, FALSE
, NULL
, &page_start
, &pages
);
3634 top
+= get_font_size (font
) - 6;
3638 e_cal_component_get_url (comp
, &url
);
3639 if (url
&& url
[0]) {
3642 url_string
= g_strdup_printf (_("URL: %s"), url
);
3645 context
, font
, url_string
, -1,
3646 0.0, top
, width
, height
, TRUE
, NULL
, &page_start
, &pages
);
3647 top
+= get_font_size (font
) - 6;
3648 g_free (url_string
);
3653 e_cal_component_get_categories (comp
, &categories
);
3654 if (categories
&& categories
[0]) {
3655 categories_string
= g_strdup_printf (
3656 _("Categories: %s"), categories
);
3658 context
, font
, categories_string
, -1,
3659 0.0, top
, width
, height
, TRUE
, NULL
, &page_start
, &pages
);
3660 top
+= get_font_size (font
) - 6;
3661 g_free (categories_string
);
3665 e_cal_component_get_contact_list (comp
, &contact_list
);
3667 GString
*contacts
= g_string_new (_("Contacts: "));
3668 for (elem
= contact_list
; elem
; elem
= elem
->next
) {
3669 ECalComponentText
*t
= elem
->data
;
3670 /* Put a comma between contacts. */
3671 if (elem
!= contact_list
)
3672 g_string_append (contacts
, ", ");
3673 g_string_append (contacts
, t
->value
);
3675 e_cal_component_free_text_list (contact_list
);
3678 context
, font
, contacts
->str
, -1,
3679 0.0, top
, width
, height
, TRUE
, NULL
, &page_start
, &pages
);
3680 top
+= get_font_size (font
) - 6;
3681 g_string_free (contacts
, TRUE
);
3686 e_cal_component_get_description_list (comp
, &desc
);
3687 for (l
= desc
; l
!= NULL
; l
= l
->next
) {
3688 ECalComponentText
*ptext
= l
->data
;
3689 const gchar
*line
, *next_line
;
3691 for (line
= ptext
->value
; line
!= NULL
; line
= next_line
) {
3692 next_line
= strchr (line
, '\n');
3695 context
, font
, line
,
3696 next_line
? next_line
- line
: -1,
3697 0.0, top
+ 3, width
, height
, TRUE
, NULL
,
3698 &page_start
, &pages
);
3709 e_cal_component_free_text_list (desc
);
3710 pango_font_description_free (font
);
3716 print_comp_draw_page (GtkPrintOperation
*operation
,
3717 GtkPrintContext
*context
,
3721 print_comp_draw_real (operation
, context
, page_nr
, pci
);
3725 print_comp_begin_print (GtkPrintOperation
*operation
,
3726 GtkPrintContext
*context
,
3731 pages
= print_comp_draw_real (operation
, context
, -1, pci
);
3733 gtk_print_operation_set_n_pages (operation
, pages
);
3737 print_comp (ECalComponent
*comp
,
3738 ECalClient
*cal_client
,
3740 gboolean use_24_hour_format
,
3741 GtkPrintOperationAction action
)
3743 GtkPrintOperation
*operation
;
3746 g_return_if_fail (E_IS_CAL_COMPONENT (comp
));
3749 pci
.client
= cal_client
;
3751 pci
.use_24_hour_format
= use_24_hour_format
;
3753 operation
= e_print_operation_new ();
3754 gtk_print_operation_set_n_pages (operation
, 1);
3757 operation
, "begin-print",
3758 G_CALLBACK (print_comp_begin_print
), &pci
);
3761 operation
, "draw-page",
3762 G_CALLBACK (print_comp_draw_page
), &pci
);
3764 gtk_print_operation_run (operation
, action
, NULL
, NULL
);
3766 g_object_unref (operation
);
3770 print_title (GtkPrintContext
*context
,
3774 PangoFontDescription
*desc
;
3775 PangoLayout
*layout
;
3778 cr
= gtk_print_context_get_cairo_context (context
);
3780 desc
= pango_font_description_from_string (FONT_FAMILY
" Bold 18");
3782 layout
= gtk_print_context_create_pango_layout (context
);
3783 pango_layout_set_text (layout
, text
, -1);
3784 pango_layout_set_font_description (layout
, desc
);
3785 pango_layout_set_alignment (layout
, PANGO_ALIGN_CENTER
);
3786 pango_layout_set_width (layout
, pango_units_from_double (page_width
));
3790 cairo_move_to (cr
, 0.0, 0.0);
3791 pango_cairo_show_layout (cr
, layout
);
3792 cairo_translate (cr
, 0.0, 18);
3796 g_object_unref (layout
);
3798 pango_font_description_free (desc
);
3802 EPrintable
*printable
;
3803 const gchar
*print_header
;
3807 print_table_draw_page (GtkPrintOperation
*operation
,
3808 GtkPrintContext
*context
,
3810 struct print_opts
*opts
)
3812 GtkPageSetup
*setup
;
3815 setup
= gtk_print_context_get_page_setup (context
);
3817 width
= gtk_page_setup_get_page_width (setup
, GTK_UNIT_POINTS
);
3820 /* TODO Allow the user to customize the title. */
3821 print_title (context
, opts
->print_header
, width
);
3823 if (e_printable_data_left (opts
->printable
))
3824 e_printable_print_page (
3825 opts
->printable
, context
, width
, 24, TRUE
);
3827 } while (e_printable_data_left (opts
->printable
));
3833 print_table (ETable
*table
,
3834 const gchar
*dialog_title
,
3835 const gchar
*print_header
,
3836 GtkPrintOperationAction action
)
3838 GtkPrintOperation
*operation
;
3839 EPrintable
*printable
;
3840 struct print_opts
*opts
;
3842 printable
= e_table_get_printable (table
);
3843 g_object_ref_sink (printable
);
3844 e_printable_reset (printable
);
3846 operation
= e_print_operation_new ();
3847 gtk_print_operation_set_n_pages (operation
, 1);
3849 opts
= g_malloc (sizeof (struct print_opts
));
3850 opts
->printable
= printable
;
3851 opts
->print_header
= print_header
;
3854 operation
, "draw_page",
3855 G_CALLBACK (print_table_draw_page
), opts
);
3857 gtk_print_operation_run (operation
, action
, NULL
, NULL
);
3859 g_object_unref (operation
);