Use GTK+ single includes
[modest] / src / widgets / modest-details-dialog.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "modest-details-dialog.h"
31
32 #include <glib/gi18n.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <gtk/gtk.h>
35 #include <tny-msg.h>
36 #include <tny-header.h>
37 #include <tny-header-view.h>
38 #include <tny-folder-store.h>
39 #include <modest-tny-folder.h>
40 #include <modest-tny-account.h>
41 #include <modest-text-utils.h>
42 #include <modest-datetime-formatter.h>
43 #include <string.h> /* for strlen */
44
45 static void    modest_details_dialog_set_header_default          (ModestDetailsDialog *self,
46                                                                   TnyHeader *header,
47                                                                   gboolean get_size);
48
49 static void    modest_details_dialog_set_folder_default          (ModestDetailsDialog *self,
50                                                                   TnyFolder *foler);
51
52 static void    modest_details_dialog_set_message_size_default    (ModestDetailsDialog *self, 
53                                                                   guint message_size);
54
55 static void    modest_details_dialog_create_container_default    (ModestDetailsDialog *self);
56
57 static void    modest_details_dialog_add_data_default            (ModestDetailsDialog *self,
58                                                                   const gchar *label,
59                                                                   const gchar *value);
60
61
62 G_DEFINE_TYPE (ModestDetailsDialog, 
63                modest_details_dialog, 
64                GTK_TYPE_DIALOG);
65
66 #define MODEST_DETAILS_DIALOG_GET_PRIVATE(o) \
67         (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_DETAILS_DIALOG, ModestDetailsDialogPrivate))
68
69
70 typedef struct _ModestDetailsDialogPrivate ModestDetailsDialogPrivate;
71
72 struct _ModestDetailsDialogPrivate
73 {
74         GtkWidget *props_table;
75 };
76
77 static void
78 modest_details_dialog_finalize (GObject *object)
79 {
80         G_OBJECT_CLASS (modest_details_dialog_parent_class)->finalize (object);
81 }
82
83 static void
84 modest_details_dialog_class_init (ModestDetailsDialogClass *klass)
85 {
86         GObjectClass *object_class = G_OBJECT_CLASS (klass);
87
88         g_type_class_add_private (klass, sizeof (ModestDetailsDialogPrivate));
89         object_class->finalize = modest_details_dialog_finalize;
90
91         klass->create_container_func = modest_details_dialog_create_container_default;
92         klass->add_data_func = modest_details_dialog_add_data_default;
93         klass->set_header_func = modest_details_dialog_set_header_default;
94         klass->set_message_size_func = modest_details_dialog_set_message_size_default;
95         klass->set_folder_func = modest_details_dialog_set_folder_default;
96 }
97
98 static void
99 modest_details_dialog_init (ModestDetailsDialog *self)
100 {
101 }
102
103 GtkWidget*
104 modest_details_dialog_new_with_header (GtkWindow *parent, 
105                                        TnyHeader *header,
106                                        gboolean get_size)
107 {
108         ModestDetailsDialog *dialog;
109
110         g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
111         g_return_val_if_fail (TNY_IS_HEADER (header), NULL);
112
113         dialog = (ModestDetailsDialog *) (g_object_new (MODEST_TYPE_DETAILS_DIALOG, 
114                                                         "transient-for", parent, 
115                                                         NULL));
116
117         MODEST_DETAILS_DIALOG_GET_CLASS (dialog)->create_container_func (dialog);
118         MODEST_DETAILS_DIALOG_GET_CLASS (dialog)->set_header_func (dialog, header, get_size);
119
120         /* Add close button */
121         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_close"), GTK_RESPONSE_CLOSE);
122
123         return GTK_WIDGET (dialog);
124 }
125
126 GtkWidget* 
127 modest_details_dialog_new_with_folder  (GtkWindow *parent, 
128                                         TnyFolder *folder)
129 {
130         ModestDetailsDialog *dialog;
131
132         g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
133         g_return_val_if_fail (TNY_IS_FOLDER (folder), NULL);
134
135         dialog = (ModestDetailsDialog *) (g_object_new (MODEST_TYPE_DETAILS_DIALOG, 
136                                                         "transient-for", parent, 
137                                                         NULL));
138
139         MODEST_DETAILS_DIALOG_GET_CLASS (dialog)->create_container_func (dialog);
140         MODEST_DETAILS_DIALOG_GET_CLASS (dialog)->set_folder_func (dialog, folder);
141
142         /* Add close button */
143         gtk_dialog_add_button (GTK_DIALOG (dialog), _("mcen_bd_close"), GTK_RESPONSE_CLOSE);
144
145         return GTK_WIDGET (dialog);
146 }
147
148 void
149 modest_details_dialog_add_data (ModestDetailsDialog *self,
150                                 const gchar *label,
151                                 const gchar *value)
152 {
153         MODEST_DETAILS_DIALOG_GET_CLASS (self)->add_data_func (self, label, value);
154 }
155
156 void
157 modest_details_dialog_set_message_size (ModestDetailsDialog *self,
158                                         guint size)
159 {
160         MODEST_DETAILS_DIALOG_GET_CLASS (self)->set_message_size_func (self, size);
161 }
162
163 static void
164 modest_details_dialog_add_data_default (ModestDetailsDialog *self,
165                                         const gchar *label,
166                                         const gchar *value)
167 {
168         ModestDetailsDialogPrivate *priv;
169         guint n_rows = 0;
170         GtkWidget *label_w, *value_w;
171         gchar *secure_value;
172
173         priv = MODEST_DETAILS_DIALOG_GET_PRIVATE (self);
174
175         g_object_get (G_OBJECT (priv->props_table), "n-rows", &n_rows,NULL);
176
177         /* Create label */
178         label_w = gtk_label_new (label);
179         gtk_misc_set_alignment (GTK_MISC (label_w), 1.0, 0.0);
180         gtk_label_set_justify (GTK_LABEL (label_w), GTK_JUSTIFY_RIGHT);
181
182         /* Create secure value */
183         secure_value = modest_text_utils_get_secure_header (value, "");
184
185         /* Create value */
186         value_w = gtk_label_new (secure_value);
187         gtk_label_set_line_wrap ((GtkLabel *) value_w, TRUE);
188         gtk_label_set_line_wrap_mode ((GtkLabel *) value_w, PANGO_WRAP_WORD_CHAR);
189         gtk_misc_set_alignment (GTK_MISC (value_w), 0.0, 0.0);
190         gtk_label_set_justify ((GtkLabel *) value_w, GTK_JUSTIFY_LEFT);
191
192         /* Attach label and value */
193         gtk_table_attach (GTK_TABLE (priv->props_table), 
194                           label_w, 0, 1, 
195                           n_rows, n_rows + 1, 
196                           GTK_SHRINK|GTK_FILL, 
197                           GTK_SHRINK|GTK_FILL, 
198                           0, 0);
199         gtk_table_attach (GTK_TABLE (priv->props_table), 
200                           value_w, 1, 2, 
201                           n_rows, n_rows + 1, 
202                           GTK_EXPAND|GTK_FILL, 
203                           GTK_SHRINK|GTK_FILL, 
204                           0, 0);
205
206         g_free (secure_value);
207 }
208
209 static void 
210 replace_recipients (gchar **recipients)
211 {
212
213         gchar *result;
214
215         result = modest_text_utils_simplify_recipients (*recipients);
216
217         g_free (*recipients);
218         *recipients = result;
219 }
220
221 static void
222 modest_details_dialog_set_header_default (ModestDetailsDialog *self,
223                                           TnyHeader *header,
224                                           gboolean get_size)
225 {
226         gchar *from = NULL, *subject = NULL, *to = NULL, *cc = NULL, *bcc = NULL;
227         time_t received, sent;
228         guint size;
229         gchar *size_s;
230         TnyFolder *folder;
231         TnyFolderType folder_type;
232         ModestDatetimeFormatter *datetime_formatter;
233         const gchar *date_time_str;
234
235         datetime_formatter = modest_datetime_formatter_new ();
236
237         /* Set window title */
238         gtk_window_set_title (GTK_WINDOW (self), _("mcen_ti_message_properties"));
239
240         folder = tny_header_get_folder (header);
241         if (folder) {
242                 folder_type = modest_tny_folder_guess_folder_type (folder);
243                 g_object_unref (folder);
244         } else {
245                 folder_type = TNY_FOLDER_TYPE_NORMAL;
246         }
247
248         g_return_if_fail (folder_type != TNY_FOLDER_TYPE_INVALID);
249
250         /* Get header data */
251         from = tny_header_dup_from (header);
252         to = tny_header_dup_to (header);
253         subject = tny_header_dup_subject (header);
254         cc = tny_header_dup_cc (header);
255         bcc = tny_header_dup_bcc (header);
256         received = tny_header_get_date_received (header);
257         sent = tny_header_get_date_sent (header);
258         if (get_size) {
259                 size = tny_header_get_message_size (header);
260         } else {
261                 size = -1;
262         }
263
264         replace_recipients (&from);
265         replace_recipients (&to);
266         replace_recipients (&cc);
267         if (subject == NULL)
268                 subject = g_strdup ("");
269
270         if (!strcmp (subject, "")) {
271                 g_free (subject);
272                 subject = g_strdup (_("mail_va_no_subject"));
273         }
274
275         /* Add from and subject for all folders */
276         modest_details_dialog_add_data (self, _("mcen_fi_message_properties_from"), from);
277         modest_details_dialog_add_data (self, _("mcen_fi_message_properties_subject"), subject);
278
279
280         /* for inbox, user-created folders and archive: Received */
281         if (received && (folder_type != TNY_FOLDER_TYPE_SENT) &&
282             (folder_type != TNY_FOLDER_TYPE_DRAFTS) &&
283             (folder_type != TNY_FOLDER_TYPE_OUTBOX)) {
284                 date_time_str = modest_datetime_formatter_display_long_datetime (datetime_formatter, 
285                                                                             received);
286
287                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_received"),
288                                                 date_time_str);
289         }
290
291         /* for drafts (created) */
292         if (folder_type == TNY_FOLDER_TYPE_DRAFTS) {
293                 date_time_str = modest_datetime_formatter_display_long_datetime (datetime_formatter, 
294                                                                             received);
295                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_created"),
296                                                 date_time_str);
297         }
298
299         /* for everyting except outbox, drafts: Sent */
300         if (sent && (folder_type != TNY_FOLDER_TYPE_DRAFTS)&&
301             (folder_type != TNY_FOLDER_TYPE_OUTBOX)) {
302                 
303                 date_time_str = modest_datetime_formatter_display_long_datetime (datetime_formatter, 
304                                                                             sent);
305                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_sent"),
306                                                 date_time_str);
307         }
308
309         /* Set To and CC */
310         modest_details_dialog_add_data (self, _("mcen_fi_message_properties_to"), to);
311
312         /* only show cc when it's there */
313         if (cc && strlen(cc) > 0)
314                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_cc"), cc);
315
316         /* only show cc when it's there */
317         if (bcc && strlen(bcc) > 0) {
318                 replace_recipients (&bcc);
319                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_bcc"), bcc);
320         }
321
322         /* Set size */
323         if (get_size) {
324                 size_s = modest_text_utils_get_display_size (size);
325                 modest_details_dialog_add_data (self, _("mcen_fi_message_properties_size"), size_s);
326                 g_free (size_s);
327         }
328
329         /* Frees */
330         g_object_unref (datetime_formatter);
331         g_free (to);
332         g_free (from);
333         g_free (subject);
334         g_free (cc);
335         g_free (bcc);
336 }
337
338 static void
339 modest_details_dialog_set_message_size_default (ModestDetailsDialog *self,
340                                                 guint size)
341 {
342         gchar *size_s;
343         size_s = modest_text_utils_get_display_size (size);
344         modest_details_dialog_add_data (self, _("mcen_fi_message_properties_size"), size_s);
345         g_free (size_s);
346         gtk_widget_show_all (GTK_WIDGET (self));
347 }
348
349 static void
350 modest_details_dialog_set_folder_default (ModestDetailsDialog *self,
351                                           TnyFolder *folder)
352 {
353         gchar *count_s, *size_s, *name = NULL;
354         gchar *tmp = NULL;
355         guint size, count;
356
357         g_return_if_fail (folder && TNY_IS_FOLDER (folder));
358         g_return_if_fail (modest_tny_folder_guess_folder_type (folder)
359                           != TNY_FOLDER_TYPE_INVALID);
360
361         /* Set window title */
362         gtk_window_set_title (GTK_WINDOW (self), _("mcen_ti_folder_properties"));
363
364         /* Get data. We use our function because it's recursive */
365         count = tny_folder_get_all_count (TNY_FOLDER (folder));
366         size = tny_folder_get_local_size (TNY_FOLDER (folder));
367
368         /* Format count and size */
369         count_s = g_strdup_printf ("%d", count);
370         size_s = modest_text_utils_get_display_size (size);
371
372         /* Different names for the local folders */
373         if (modest_tny_folder_is_local_folder (folder) ||
374             modest_tny_folder_is_memory_card_folder (folder)) {
375                 gint type = modest_tny_folder_get_local_or_mmc_folder_type (folder);
376                 if (type != TNY_FOLDER_TYPE_UNKNOWN)
377                         name = g_strdup(modest_local_folder_info_get_type_display_name (type));
378         }
379
380         if (!name) {
381                 if (tny_folder_get_folder_type (folder) == TNY_FOLDER_TYPE_INBOX)
382                         name = g_strdup (_("mcen_me_folder_inbox"));
383                 else
384                         name = g_strdup (tny_folder_get_name (folder));
385         }
386
387         tmp = g_strconcat (_("mcen_fi_folder_properties_foldername"), ":", NULL);
388         modest_details_dialog_add_data (self, tmp, name);
389         g_free (tmp);
390
391         tmp = g_strconcat (_("mcen_fi_folder_properties_messages"), ":", NULL);
392         modest_details_dialog_add_data (self, tmp, count_s);
393         g_free (tmp);
394
395         tmp = g_strconcat (_("mcen_fi_folder_properties_size"), ":", NULL);
396         modest_details_dialog_add_data (self, tmp, size_s);
397         g_free (tmp);
398
399         /* Frees */
400         g_free (name);
401         g_free (size_s);
402         g_free (count_s);
403 }
404
405 static gboolean
406 on_key_press_event (GtkWindow *window, GdkEventKey *event, gpointer userdata)
407 {
408         GtkWidget *focused;
409
410         focused = gtk_window_get_focus (window);
411         if (GTK_IS_SCROLLED_WINDOW (focused)) {
412                 GtkAdjustment *vadj;
413                 gboolean return_value;
414
415                 vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (focused));
416                 switch (event->keyval) {
417                 case GDK_Up:
418                 case GDK_KP_Up:
419                         if (vadj->value > 0.0) {
420                                 g_signal_emit_by_name (G_OBJECT (focused), "scroll-child", GTK_SCROLL_STEP_UP, FALSE, 
421                                                        &return_value);
422                                 return TRUE;
423                         }
424                         break;
425                 case GDK_Down:
426                 case GDK_KP_Down:
427                         if (vadj->value < vadj->upper - vadj->page_size) {
428                                 g_signal_emit_by_name (G_OBJECT (focused), "scroll-child", GTK_SCROLL_STEP_DOWN, FALSE, 
429                                                        &return_value);
430                                 return TRUE;
431                         }
432                         break;
433                 }
434         }
435
436         return FALSE;
437 }
438
439 static void
440 modest_details_dialog_create_container_default (ModestDetailsDialog *self)
441 {
442         ModestDetailsDialogPrivate *priv;
443         GtkWidget *scrollbar;
444
445         priv = MODEST_DETAILS_DIALOG_GET_PRIVATE (self);
446         scrollbar = gtk_scrolled_window_new (NULL, NULL);
447
448         gtk_window_set_default_size (GTK_WINDOW (self), 400, 220);
449
450         priv->props_table = gtk_table_new (0, 2, FALSE);
451         gtk_table_set_col_spacings (GTK_TABLE (priv->props_table), 12);
452         gtk_table_set_row_spacings (GTK_TABLE (priv->props_table), 1);
453         gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrollbar), priv->props_table);
454         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollbar), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
455         gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->props_table), 
456                                              gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrollbar)));
457         gtk_container_add (GTK_CONTAINER (GTK_DIALOG (self)->vbox), scrollbar);
458
459         gtk_dialog_set_has_separator (GTK_DIALOG (self), FALSE);
460
461         g_signal_connect (self, "key-press-event", G_CALLBACK (on_key_press_event), self);
462 }