c0177da9fcf289bfe3574bac12af4d06d15d946f
[modest] / src / widgets / modest-header-view-render.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-header-view.h>
31 #include <modest-header-view-priv.h>
32 #include <modest-icon-names.h>
33 #include <modest-text-utils.h>
34 #include <modest-runtime.h>
35 #include <glib/gi18n.h>
36 #include <modest-platform.h>
37
38
39 static gchar *
40 _pango_replace_string (const gchar *string, 
41                        const gchar *in,
42                        const gchar *out) 
43 {
44         gchar **tmp = NULL;     
45         gchar *new_string = NULL;
46         gchar *tmp_string = NULL;
47         guint i = 0;
48
49         /* Split data */
50         if (string == NULL) return g_strdup("");
51         tmp = g_strsplit(string, in, 0);        
52         if (tmp[0] == NULL) return g_strdup(string);
53
54         /* Replace and concat data*/
55         new_string = g_strdup(tmp[0]);
56         for (i = 1; tmp[i] != NULL; i++) {
57                 tmp_string = g_strconcat (new_string, out, tmp[i], NULL);
58                 g_free(new_string);
59                 new_string = g_strdup(tmp_string);
60                 g_free(tmp_string);
61         } 
62         
63         /* Free */
64         g_strfreev(tmp);
65
66         return new_string;
67 }
68
69 static gchar *
70 _pango_parse_string (const gchar *string) 
71 {
72         gchar *parsed_string = NULL;
73         gchar *tmp = NULL;
74         
75         if (string == NULL) return g_strdup("");
76         parsed_string = g_strdup(string);
77
78         /* Check for '&' special character */   
79         tmp = g_strdup(parsed_string);
80         g_free(parsed_string);
81         parsed_string = _pango_replace_string (tmp, "&", "&amp;");
82         g_free(tmp);
83
84         /* Check for '<' special character */
85         tmp = g_strdup(parsed_string);
86         g_free(parsed_string);
87         parsed_string = _pango_replace_string (tmp, "<", "&lt;");
88         g_free(tmp);
89
90         /* Check for '>' special character */
91         tmp = g_strdup(parsed_string);
92         g_free(parsed_string);
93         parsed_string = _pango_replace_string (tmp, ">", "&gt;");
94         g_free(tmp);
95
96         /* Check for ''' special character */
97         tmp = g_strdup(parsed_string);
98         g_free(parsed_string);
99         parsed_string = _pango_replace_string (tmp, "'", "&apos;");
100         g_free(tmp);
101
102         return parsed_string;
103 }
104
105
106 static GdkPixbuf*
107 get_pixbuf_for_flag (TnyHeaderFlags flag)
108 {
109         /* optimization */
110         static GdkPixbuf *deleted_pixbuf          = NULL;
111         static GdkPixbuf *seen_pixbuf             = NULL;
112         static GdkPixbuf *unread_pixbuf           = NULL;
113         static GdkPixbuf *attachments_pixbuf      = NULL;
114         
115         switch (flag) {
116         case TNY_HEADER_FLAG_DELETED:
117                 if (G_UNLIKELY(!deleted_pixbuf))
118                         deleted_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_DELETED);
119                 return deleted_pixbuf;
120         case TNY_HEADER_FLAG_SEEN:
121                 if (G_UNLIKELY(!seen_pixbuf))
122                         seen_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_READ);
123                 return seen_pixbuf;
124         case TNY_HEADER_FLAG_ATTACHMENTS:
125                 if (G_UNLIKELY(!attachments_pixbuf))
126                         attachments_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_ATTACH);
127                 return attachments_pixbuf;
128         default:
129                 if (G_UNLIKELY(!unread_pixbuf))
130                         unread_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_UNREAD);
131                 return unread_pixbuf;
132         }
133 }
134
135 static GdkPixbuf*
136 get_pixbuf_for_compact_flag (TnyHeaderFlags flags)
137 {
138         /* optimization */
139         static GdkPixbuf *high_attachments_pixbuf   = NULL;
140         static GdkPixbuf *normal_attachments_pixbuf = NULL;
141         static GdkPixbuf *low_attachments_pixbuf    = NULL;
142         static GdkPixbuf *high_pixbuf               = NULL;
143         static GdkPixbuf *low_pixbuf                = NULL;
144         TnyHeaderFlags prior;
145
146         prior = flags & TNY_HEADER_FLAG_HIGH_PRIORITY;
147         switch (prior) {
148         case TNY_HEADER_FLAG_HIGH_PRIORITY:
149                 if (flags & TNY_HEADER_FLAG_ATTACHMENTS) {
150                         if (G_UNLIKELY(!high_attachments_pixbuf))
151                                 high_attachments_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_ATTACH_HIGH_PRIORITY);
152                         return high_attachments_pixbuf;
153                 } else {
154                         if (G_UNLIKELY(!high_pixbuf))
155                                 high_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_HIGH_PRIORITY);
156                         return high_pixbuf;
157                 }
158                 break;
159         case TNY_HEADER_FLAG_LOW_PRIORITY:
160                 if (flags & TNY_HEADER_FLAG_ATTACHMENTS) {
161                         if (G_UNLIKELY(!low_attachments_pixbuf))
162                                 low_attachments_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_ATTACH_LOW_PRIORITY);
163                         return low_attachments_pixbuf;
164                 } else {                
165                         if (G_UNLIKELY(!low_pixbuf))
166                                 low_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_LOW_PRIORITY);
167                         return low_pixbuf;
168                 }
169                 break;
170         default:
171                 if (flags & TNY_HEADER_FLAG_ATTACHMENTS) {
172                         if (G_UNLIKELY(!normal_attachments_pixbuf))
173                                 normal_attachments_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_ATTACH_NORM_PRIORITY);
174                         return normal_attachments_pixbuf;
175                 }               
176         }
177         
178         return NULL;
179 }
180
181 static void
182 set_common_flags (GtkCellRenderer *renderer, TnyHeaderFlags flags)
183 {
184         g_object_set (G_OBJECT(renderer),
185                       "weight", (flags & TNY_HEADER_FLAG_SEEN) ? PANGO_WEIGHT_NORMAL: PANGO_WEIGHT_ULTRABOLD,
186                       "strikethrough",  (flags & TNY_HEADER_FLAG_DELETED) ?  TRUE:FALSE,
187                       NULL);    
188 }
189
190
191 void
192 _modest_header_view_msgtype_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
193                    GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
194 {
195         TnyHeaderFlags flags;
196                 
197         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
198                             &flags, -1);
199
200         if (flags & TNY_HEADER_FLAG_DELETED)
201                 g_object_set (G_OBJECT (renderer), "pixbuf",
202                               get_pixbuf_for_flag (TNY_HEADER_FLAG_DELETED), NULL);           
203         else if (flags & TNY_HEADER_FLAG_SEEN)
204                 g_object_set (G_OBJECT (renderer), "pixbuf",
205                               get_pixbuf_for_flag (TNY_HEADER_FLAG_SEEN), NULL);              
206         else 
207                 g_object_set (G_OBJECT (renderer), "pixbuf",
208                               get_pixbuf_for_flag (0), NULL); /* ughh, FIXME */               
209 }
210
211 void
212 _modest_header_view_attach_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
213                                       GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
214 {
215         TnyHeaderFlags flags;
216
217         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
218                             &flags, -1);
219
220         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
221                 g_object_set (G_OBJECT (renderer), "pixbuf",
222                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
223                               NULL);
224 }
225
226 void
227 _modest_header_view_compact_flag_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
228                                             GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
229 {
230         TnyHeaderFlags flags;
231         GdkPixbuf* pixbuf = NULL;
232
233         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
234                             &flags, -1);
235         
236         pixbuf = get_pixbuf_for_compact_flag (flags);
237         if (pixbuf != NULL)     
238                 g_object_set (G_OBJECT (renderer), "pixbuf", pixbuf, NULL);
239         
240 }
241
242 void
243 _modest_header_view_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
244                   GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
245 {
246         TnyHeaderFlags flags;
247         
248         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
249                             &flags, -1);
250         set_common_flags (renderer, flags);
251 }
252
253
254 void
255 _modest_header_view_date_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
256                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
257                                      gpointer user_data)
258 {
259         TnyHeaderFlags flags;
260         guint date, date_col;
261         gchar *display_date = NULL;
262         gboolean received = GPOINTER_TO_INT(user_data);
263
264         if (received)
265                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
266         else
267                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
268
269         gtk_tree_model_get (tree_model, iter,
270                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
271                             date_col, &date,
272                             -1);
273
274         display_date = modest_text_utils_get_display_date (date);
275         g_object_set (G_OBJECT(renderer), "text", display_date, NULL);  
276
277         set_common_flags (renderer, flags);
278         g_free (display_date);
279 }
280
281 void
282 _modest_header_view_compact_date_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
283                                              GtkTreeModel *tree_model,  GtkTreeIter *iter,
284                                              gpointer user_data)
285 {
286         TnyHeaderFlags flags;
287         guint date, date_col;
288         gchar *display_date = NULL, *tmp_date = NULL;
289         gboolean received = GPOINTER_TO_INT(user_data);
290
291         if (received)
292                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
293         else
294                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
295
296         gtk_tree_model_get (tree_model, iter,
297                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
298                             date_col, &date,
299                             -1);
300
301         tmp_date = modest_text_utils_get_display_date (date);
302         display_date = g_strdup_printf ("\n<small>%s</small>", tmp_date);
303         g_object_set (G_OBJECT(renderer), "markup", display_date, NULL);        
304
305         set_common_flags (renderer, flags);
306         g_free (tmp_date);
307         g_free (display_date);
308 }
309
310 void
311 _modest_header_view_sender_receiver_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
312                             GtkTreeModel *tree_model,  GtkTreeIter *iter,  gboolean is_sender)
313 {
314         TnyHeaderFlags flags;
315         gchar *address;
316         gint sender_receiver_col;
317
318         if (is_sender)
319                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
320         else
321                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
322                 
323         gtk_tree_model_get (tree_model, iter,
324                             sender_receiver_col,  &address,
325                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
326                             -1);
327         
328         g_object_set (G_OBJECT(renderer),
329                       "text",
330                       modest_text_utils_get_display_address (address),
331                       NULL);
332         g_free (address);
333         set_common_flags (renderer, flags);
334 }
335 /*
336  * this for both incoming and outgoing mail, depending on the the user_data
337  * parameter. in the incoming case, show 'From' and 'Received date', in the
338  * outgoing case, show 'To' and 'Sent date'
339  */
340 void
341 _modest_header_view_compact_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
342                                                GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
343 {
344         GObject *rendobj;
345         TnyHeaderFlags flags;
346         gchar *address, *subject, *header, *display_address;
347         gchar *parsed_address, *parsed_subject;
348         time_t date;
349         gboolean is_incoming;
350
351         is_incoming = GPOINTER_TO_INT(user_data); /* GPOINTER_TO_BOOLEAN is not available
352                                                    * in older versions of glib...*/
353
354         if (is_incoming)
355                 gtk_tree_model_get (tree_model, iter,
356                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
357                                     TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN,  &address,
358                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
359                                     TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN, &date,   
360                                     -1);
361         else
362                 gtk_tree_model_get (tree_model, iter,
363                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
364                                     TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN,  &address,
365                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
366                                     TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN, &date,   
367                                     -1);
368         
369         rendobj = G_OBJECT(renderer);
370
371         /* deal with empty subjects */
372         if (!subject)
373                 subject = g_strdup (_("mail_va_no_subject"));
374         
375         /* Escape special characteres to allow pango makup`*/
376         display_address = modest_text_utils_get_display_address (address);
377         parsed_address = _pango_parse_string (display_address);
378         parsed_subject = _pango_parse_string (subject);
379
380         header = g_strdup_printf ("%s\n<small>%s</small>",
381                                   parsed_subject,
382                                   parsed_address);
383         g_free (address);
384         g_free (subject);
385         g_free(parsed_subject);
386         g_free(parsed_address);
387
388         g_object_set (rendobj, "markup", header, NULL); 
389         set_common_flags (renderer, flags);
390         
391         g_free (header);
392 }
393
394
395 void
396 _modest_header_view_size_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
397                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
398                                      gpointer user_data)
399 {
400         TnyHeaderFlags flags;
401         guint size;
402         gchar *size_str;
403         
404         gtk_tree_model_get (tree_model, iter,
405                            TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
406                            TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &size,
407                             -1);
408         
409         size_str = modest_text_utils_get_display_size (size);
410         
411         g_object_set (G_OBJECT(renderer), "text", size_str, NULL);
412         set_common_flags (renderer, flags);
413
414         g_free (size_str);
415  }
416
417 void
418 _modest_header_view_status_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
419                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
420                                      gpointer user_data)
421 {
422         TnyHeaderFlags flags;
423         guint status;
424         gchar *status_str;
425         
426         gtk_tree_model_get (tree_model, iter,
427                            TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
428                            TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &status,
429                             -1);
430         
431 /*      size_str = modest_text_utils_get_display_size (size); */
432         status_str = g_strdup(_("mcen_li_outbox_waiting"));
433         
434         g_object_set (G_OBJECT(renderer), "text", status_str, NULL);
435         set_common_flags (renderer, flags);
436
437         g_free (status_str);
438  }
439