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