~drbob/+junk/diary-main

« back to all changes in this revision

Viewing changes to src/printing.c

  • Committer: Philip Withnall
  • Date: 2008-05-20 21:24:47 UTC
  • Revision ID: philip@tecnocode.co.uk-20080520212447-mqaw7h0dy3ht3qyu
2008-05-20  Philip Withnall  <philip@tecnocode.co.uk>

        * src/interface.c:
        * src/interface.h:
        * src/main-window.c:
        * src/Makefile.am:
        * src/printing.c:
        * src/printing.h:
        * src/storage-manager.h:
        * data/diary.ui: Add printing support.
        * configure.ac: Remove redundant dependency on libcryptui.
        * intltool-extract.in:
        * intltool-merge.in:
        * intltool-update.in: Upgrade intltool scripts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 
2
/*
 
3
 * Diary
 
4
 * Copyright (C) Philip Withnall 2008 <philip@tecnocode.co.uk>
 
5
 * 
 
6
 * Diary is free software: you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation, either version 3 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * Diary is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with Diary.  If not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
#include <glib.h>
 
21
#include <glib/gi18n.h>
 
22
#include <gtk/gtk.h>
 
23
 
 
24
#include "storage-manager.h"
 
25
#include "interface.h"
 
26
#include "main.h"
 
27
 
 
28
#define TITLE_MARGIN_BOTTOM 15 /* margin under the title, in pixels */
 
29
#define ENTRY_MARGIN_BOTTOM 10 /* margin under the entry, in pixels */
 
30
#define MAX_ORPHANS 3 /* maximum number of orphan lines to be forced to the next page */
 
31
 
 
32
typedef struct {
 
33
        GDate *start_date;
 
34
        GDate *end_date;
 
35
        GDate *current_date;
 
36
        GtkCalendar *start_calendar;
 
37
        GtkCalendar *end_calendar;
 
38
        guint current_line;
 
39
        gboolean paginated;
 
40
        gdouble y;
 
41
} DiaryPrintOperation;
 
42
 
 
43
/* TRUE if the entry was printed OK on the current page, FALSE if it needs to be moved to a new page/is split across pages */
 
44
static gboolean
 
45
print_entry (GtkPrintOperation *operation, GtkPrintContext *context, DiaryPrintOperation *diary_operation)
 
46
{
 
47
        gchar *entry, title[100];
 
48
        PangoLayout *title_layout = NULL, *entry_layout;
 
49
        PangoLayoutLine *entry_line;
 
50
        PangoRectangle logical_extents;
 
51
        gint height;
 
52
        guint i;
 
53
        gdouble title_y = 0, entry_y;
 
54
        cairo_t *cr = NULL;
 
55
 
 
56
        entry = diary_storage_manager_get_entry (diary->storage_manager, g_date_get_year (diary_operation->current_date),
 
57
                                                                         g_date_get_month (diary_operation->current_date),
 
58
                                                                         g_date_get_day (diary_operation->current_date));
 
59
 
 
60
        if (diary_operation->current_line == 0) {
 
61
                /* Set up the title layout */
 
62
                title_layout = gtk_print_context_create_pango_layout (context);
 
63
                pango_layout_set_width (title_layout, gtk_print_context_get_width (context) * PANGO_SCALE);
 
64
 
 
65
                /* Translators: This is a strftime()-format string for the date displayed above each printed entry. */
 
66
                g_date_strftime (title, sizeof (title), _("<b>%A, %e %B %Y</b>"), diary_operation->current_date);
 
67
                pango_layout_set_markup (title_layout, title, -1);
 
68
 
 
69
                title_y = diary_operation->y;
 
70
                pango_layout_get_pixel_size (title_layout, NULL, &height);
 
71
                diary_operation->y += height + TITLE_MARGIN_BOTTOM;
 
72
        }
 
73
 
 
74
        /* Set up the entry layout */
 
75
        entry_layout = gtk_print_context_create_pango_layout (context);
 
76
        pango_layout_set_width (entry_layout, gtk_print_context_get_width (context) * PANGO_SCALE);
 
77
        pango_layout_set_ellipsize (entry_layout, PANGO_ELLIPSIZE_NONE);
 
78
 
 
79
        if (entry == NULL)
 
80
                pango_layout_set_markup (entry_layout, _("<i>No entry for this date.</i>"), -1);
 
81
        else
 
82
                pango_layout_set_text (entry_layout, entry, -1);
 
83
 
 
84
        /* Check we're not orphaning things */
 
85
        entry_line = pango_layout_get_line_readonly (entry_layout, MIN (pango_layout_get_line_count (entry_layout), diary_operation->current_line + MAX_ORPHANS) - 1);
 
86
        pango_layout_line_get_pixel_extents (entry_line, NULL, &logical_extents);
 
87
 
 
88
        if (diary_operation->y + (MIN (pango_layout_get_line_count (entry_layout), MAX_ORPHANS) * logical_extents.height) > gtk_print_context_get_height (context)) {
 
89
                /* Not enough space on the page to contain the title and orphaned lines */
 
90
                if (title_layout != NULL)
 
91
                        g_object_unref (title_layout);
 
92
                g_object_unref (entry_layout);
 
93
                g_free (entry);
 
94
 
 
95
                diary_operation->current_line = 0;
 
96
 
 
97
                return FALSE;
 
98
        }
 
99
 
 
100
        if (diary_operation->paginated == TRUE) {
 
101
                cr = gtk_print_context_get_cairo_context (context);
 
102
 
 
103
                if (diary_operation->current_line == 0) {
 
104
                        /* Draw the title */
 
105
                        cairo_move_to (cr, 0, title_y);
 
106
                        pango_cairo_show_layout (cr, title_layout);
 
107
                }
 
108
        }
 
109
 
 
110
        entry_y = diary_operation->y;
 
111
 
 
112
        /* Draw the lines in the entry */
 
113
        for (i = diary_operation->current_line; i < pango_layout_get_line_count (entry_layout); i++) {
 
114
                entry_line = pango_layout_get_line_readonly (entry_layout, i);
 
115
                pango_layout_line_get_pixel_extents (entry_line, NULL, &logical_extents);
 
116
 
 
117
                /* Check we're not going to overflow the page */
 
118
                if (entry_y + logical_extents.height > gtk_print_context_get_height (context)) {
 
119
                        /* Paint the rest on the next page */
 
120
                        if (title_layout != NULL)
 
121
                                g_object_unref (title_layout);
 
122
                        g_object_unref (entry_layout);
 
123
                        g_free (entry);
 
124
 
 
125
                        diary_operation->current_line = i;
 
126
 
 
127
                        return FALSE;
 
128
                }
 
129
 
 
130
                if (diary_operation->paginated == TRUE) {
 
131
                        /* Draw the entry line */
 
132
                        cairo_move_to (cr, 0, entry_y);
 
133
                        pango_cairo_show_layout_line (cr, entry_line);
 
134
                }
 
135
 
 
136
                entry_y += logical_extents.height;
 
137
        }
 
138
 
 
139
        /* Add the entry's height to the amount printed for this page */
 
140
        pango_layout_get_pixel_size (entry_layout, NULL, &height);
 
141
        diary_operation->y = entry_y + ENTRY_MARGIN_BOTTOM;
 
142
 
 
143
        if (title_layout != NULL)
 
144
                g_object_unref (title_layout);
 
145
        g_object_unref (entry_layout);
 
146
        g_free (entry);
 
147
 
 
148
        diary_operation->current_line = 0;
 
149
 
 
150
        return TRUE;
 
151
}
 
152
 
 
153
static gboolean
 
154
paginate_cb (GtkPrintOperation *operation, GtkPrintContext *context, DiaryPrintOperation *diary_operation)
 
155
{
 
156
        /* Calculate the number of pages by laying everything out :( */
 
157
        while (g_date_compare (diary_operation->current_date, diary_operation->end_date) <= 0 &&
 
158
               print_entry (operation, context, diary_operation) == TRUE) {
 
159
                g_date_add_days (diary_operation->current_date, 1);
 
160
        }
 
161
 
 
162
        if (g_date_compare (diary_operation->current_date, diary_operation->end_date) > 0) {
 
163
                /* We're done paginating */
 
164
                return TRUE;
 
165
        } else {
 
166
                /* More pages! */
 
167
                gint pages;
 
168
                g_object_get (operation, "n-pages", &pages, NULL);
 
169
                gtk_print_operation_set_n_pages (operation, pages + 1);
 
170
 
 
171
                diary_operation->y = 0;
 
172
 
 
173
                return FALSE;
 
174
        }
 
175
}
 
176
 
 
177
static void
 
178
draw_page_cb (GtkPrintOperation *operation, GtkPrintContext *context, gint page_number, DiaryPrintOperation *diary_operation)
 
179
{
 
180
        if (diary_operation->paginated == FALSE) {
 
181
                /* Reset things before we start printing */
 
182
                diary_operation->paginated = TRUE;
 
183
                diary_operation->current_line = 0;
 
184
                g_date_set_dmy (diary_operation->current_date,
 
185
                                g_date_get_day (diary_operation->start_date),
 
186
                                g_date_get_month (diary_operation->start_date),
 
187
                                g_date_get_year (diary_operation->start_date));
 
188
        }
 
189
 
 
190
        diary_operation->y = 0;
 
191
 
 
192
        while (g_date_compare (diary_operation->current_date, diary_operation->end_date) <= 0 &&
 
193
               print_entry (operation, context, diary_operation) == TRUE) {
 
194
                g_date_add_days (diary_operation->current_date, 1);
 
195
        }
 
196
}
 
197
 
 
198
static GtkWidget *
 
199
create_custom_widget_cb (GtkPrintOperation *operation, DiaryPrintOperation *diary_operation)
 
200
{
 
201
        GtkWidget *start_calendar, *end_calendar, *start_label, *end_label;
 
202
        GtkTable *table;
 
203
 
 
204
        start_calendar = gtk_calendar_new ();
 
205
        g_signal_connect (start_calendar, "month-changed", G_CALLBACK (diary_calendar_month_changed_cb), NULL);
 
206
        end_calendar = gtk_calendar_new ();
 
207
        g_signal_connect (end_calendar, "month-changed", G_CALLBACK (diary_calendar_month_changed_cb), NULL);
 
208
 
 
209
        start_label = gtk_label_new (NULL);
 
210
        gtk_label_set_markup (GTK_LABEL (start_label), _("<b>Start Date</b>"));
 
211
        end_label = gtk_label_new (NULL);
 
212
        gtk_label_set_markup (GTK_LABEL (end_label), _("<b>End Date</b>"));
 
213
 
 
214
        table = GTK_TABLE (gtk_table_new (2, 2, FALSE));
 
215
        gtk_table_attach (table, start_calendar, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);
 
216
        gtk_table_attach (table, end_calendar, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 5, 5);
 
217
        gtk_table_attach (table, start_label, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 5, 5);
 
218
        gtk_table_attach (table, end_label, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 5, 5);
 
219
 
 
220
        diary_operation->start_calendar = GTK_CALENDAR (start_calendar);
 
221
        diary_operation->end_calendar = GTK_CALENDAR (end_calendar);
 
222
 
 
223
        gtk_widget_show_all (GTK_WIDGET (table));
 
224
 
 
225
        /* Make sure they have the dates with entries marked */
 
226
        diary_calendar_month_changed_cb (GTK_CALENDAR (start_calendar), NULL);
 
227
        diary_calendar_month_changed_cb (GTK_CALENDAR (end_calendar), NULL);
 
228
 
 
229
        return GTK_WIDGET (table);
 
230
}
 
231
 
 
232
static void
 
233
custom_widget_apply_cb (GtkPrintOperation *operation, GtkWidget *widget, DiaryPrintOperation *diary_operation)
 
234
{
 
235
        guint year, month, day;
 
236
 
 
237
        /* Start date */
 
238
        gtk_calendar_get_date (diary_operation->start_calendar, &year, &month, &day);
 
239
        diary_operation->start_date = g_date_new_dmy (day, month + 1, year);
 
240
        diary_operation->current_date = g_memdup (diary_operation->start_date, sizeof (*diary_operation->start_date));
 
241
 
 
242
        /* End date */
 
243
        gtk_calendar_get_date (diary_operation->end_calendar, &year, &month, &day);
 
244
        diary_operation->end_date = g_date_new_dmy (day, month + 1, year);
 
245
}
 
246
 
 
247
void
 
248
diary_print_entries (void)
 
249
{
 
250
        GtkPrintOperation *operation;
 
251
        GtkPrintOperationResult res;
 
252
        static GtkPrintSettings *settings;
 
253
        DiaryPrintOperation diary_operation;
 
254
 
 
255
        operation = gtk_print_operation_new ();
 
256
        diary_operation.current_date = NULL;
 
257
        diary_operation.paginated = FALSE;
 
258
        diary_operation.y = 0;
 
259
        diary_operation.current_line = 0;
 
260
 
 
261
        if (settings != NULL) 
 
262
                gtk_print_operation_set_print_settings (operation, settings);
 
263
 
 
264
        gtk_print_operation_set_n_pages (operation, 1);
 
265
 
 
266
        g_signal_connect (operation, "paginate", G_CALLBACK (paginate_cb), &diary_operation);
 
267
        g_signal_connect (operation, "draw-page", G_CALLBACK (draw_page_cb), &diary_operation);
 
268
        g_signal_connect (operation, "create-custom-widget", G_CALLBACK (create_custom_widget_cb), &diary_operation);
 
269
        g_signal_connect (operation, "custom-widget-apply", G_CALLBACK (custom_widget_apply_cb), &diary_operation);
 
270
 
 
271
        res = gtk_print_operation_run (operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
 
272
                                       GTK_WINDOW (diary->main_window), NULL);
 
273
 
 
274
        if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
 
275
                if (settings != NULL)
 
276
                        g_object_unref (settings);
 
277
                settings = g_object_ref (gtk_print_operation_get_print_settings (operation));
 
278
        }
 
279
 
 
280
        if (diary_operation.current_date != NULL) {
 
281
                g_date_free (diary_operation.current_date);
 
282
                g_date_free (diary_operation.start_date);
 
283
                g_date_free (diary_operation.end_date);
 
284
        }
 
285
        g_object_unref (operation);
 
286
}
 
287