* src/widgets/modest-header-view-render.c:
[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-tny-send-queue.h>
35 #include <modest-tny-folder.h>
36 #include <modest-tny-account.h>
37 #include <modest-runtime.h>
38 #include <glib/gi18n.h>
39 #include <modest-platform.h>
40 #include <string.h>
41
42
43 void 
44 fill_list_of_caches (gpointer key, gpointer value, gpointer userdata)
45 {
46         GSList **send_queues = (GSList **) userdata;
47         *send_queues = g_slist_prepend (*send_queues, value);
48 }
49
50 static ModestTnySendQueueStatus
51 get_status_of_uid (const gchar *uid)
52 {
53         ModestCacheMgr *cache_mgr;
54         GHashTable     *send_queue_cache;
55         GSList *send_queues = NULL, *node;
56         /* get_msg_status returns suspended by default, so we want to detect changes */
57         ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
58         
59         cache_mgr = modest_runtime_get_cache_mgr ();
60         send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
61                                                        MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
62
63         g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
64
65         for (node = send_queues; node != NULL; node = g_slist_next (node)) {
66                 ModestTnySendQueueStatus queue_status = modest_tny_send_queue_get_msg_status (
67                         MODEST_TNY_SEND_QUEUE (node->data), uid);
68                 if (queue_status != MODEST_TNY_SEND_QUEUE_SUSPENDED)
69                         status = queue_status;
70                 break;
71         }
72         g_slist_free (send_queues);
73         return status;
74 }
75
76 static const gchar *
77 get_status_string (ModestTnySendQueueStatus status)
78 {
79         switch (status) {
80         case MODEST_TNY_SEND_QUEUE_WAITING:
81                 return _("mcen_li_outbox_waiting");
82                 break;
83         case MODEST_TNY_SEND_QUEUE_SENDING:
84                 return _("mcen_li_outbox_sending");
85                 break;
86         case MODEST_TNY_SEND_QUEUE_SUSPENDED:
87                 return _("mcen_li_outbox_suspended");
88                 break;
89         case MODEST_TNY_SEND_QUEUE_FAILED:
90                 return _("mcen_li_outbox_failed");
91                 break;
92         default:
93                 return "";
94                 break;
95         }
96 }
97
98 static GdkPixbuf*
99 get_pixbuf_for_flag (TnyHeaderFlags flag)
100 {
101         /* optimization */
102         static GdkPixbuf *deleted_pixbuf          = NULL;
103         static GdkPixbuf *seen_pixbuf             = NULL;
104         static GdkPixbuf *unread_pixbuf           = NULL;
105         static GdkPixbuf *attachments_pixbuf      = NULL;
106         static GdkPixbuf *high_pixbuf             = NULL;
107         static GdkPixbuf *low_pixbuf             = NULL;
108         
109         switch (flag) {
110         case TNY_HEADER_FLAG_DELETED:
111                 if (G_UNLIKELY(!deleted_pixbuf))
112                         deleted_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_DELETED);
113                 return deleted_pixbuf;
114         case TNY_HEADER_FLAG_SEEN:
115                 if (G_UNLIKELY(!seen_pixbuf))
116                         seen_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_READ);
117                 return seen_pixbuf;
118         case TNY_HEADER_FLAG_ATTACHMENTS:
119                 if (G_UNLIKELY(!attachments_pixbuf))
120                         attachments_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_ATTACH);
121                 return attachments_pixbuf;
122         case TNY_HEADER_FLAG_HIGH_PRIORITY:
123                 if (G_UNLIKELY(!high_pixbuf))
124                         high_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_HIGH_PRIORITY);
125                 return high_pixbuf;
126         case TNY_HEADER_FLAG_LOW_PRIORITY:
127                 if (G_UNLIKELY(!low_pixbuf))
128                         low_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_LOW_PRIORITY);
129                 return low_pixbuf;
130         default:
131                 if (G_UNLIKELY(!unread_pixbuf))
132                         unread_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_UNREAD);
133                 return unread_pixbuf;
134         }
135 }
136
137 static void
138 set_common_flags (GtkCellRenderer *renderer, TnyHeaderFlags flags)
139 {
140         g_object_set (G_OBJECT(renderer),
141                       "weight", (flags & TNY_HEADER_FLAG_SEEN) ? PANGO_WEIGHT_NORMAL: PANGO_WEIGHT_ULTRABOLD,
142                       "strikethrough",  (flags & TNY_HEADER_FLAG_DELETED) ?  TRUE:FALSE,
143                       NULL);    
144 }
145
146
147 void
148 _modest_header_view_msgtype_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
149                    GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
150 {
151         TnyHeaderFlags flags;
152                 
153         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
154                             &flags, -1);
155
156         if (flags & TNY_HEADER_FLAG_DELETED)
157                 g_object_set (G_OBJECT (renderer), "pixbuf",
158                               get_pixbuf_for_flag (TNY_HEADER_FLAG_DELETED), NULL);           
159         else if (flags & TNY_HEADER_FLAG_SEEN)
160                 g_object_set (G_OBJECT (renderer), "pixbuf",
161                               get_pixbuf_for_flag (TNY_HEADER_FLAG_SEEN), NULL);              
162         else 
163                 g_object_set (G_OBJECT (renderer), "pixbuf",
164                               get_pixbuf_for_flag (0), NULL); /* ughh, FIXME */               
165 }
166
167 void
168 _modest_header_view_attach_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
169                                       GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
170 {
171         TnyHeaderFlags flags;
172
173         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
174                             &flags, -1);
175
176         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
177                 g_object_set (G_OBJECT (renderer), "pixbuf",
178                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
179                               NULL);
180 }
181
182 void
183 _modest_header_view_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
184                   GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
185 {
186         TnyHeaderFlags flags;
187         
188         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
189                             &flags, -1);
190         set_common_flags (renderer, flags);
191 }
192
193
194 void
195 _modest_header_view_date_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
196                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
197                                      gpointer user_data)
198 {
199         TnyHeaderFlags flags;
200         guint date, date_col;
201         gchar *display_date = NULL;
202         gboolean received = GPOINTER_TO_INT(user_data);
203
204         if (received)
205                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
206         else
207                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
208
209         gtk_tree_model_get (tree_model, iter,
210                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
211                             date_col, &date,
212                             -1);
213
214         display_date = modest_text_utils_get_display_date (date);
215         g_object_set (G_OBJECT(renderer), "text", display_date, NULL);  
216
217         set_common_flags (renderer, flags);
218         g_free (display_date);
219 }
220
221 void
222 _modest_header_view_sender_receiver_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
223                             GtkTreeModel *tree_model,  GtkTreeIter *iter,  gboolean is_sender)
224 {
225         TnyHeaderFlags flags;
226         gchar *address;
227         gint sender_receiver_col;
228
229         if (is_sender)
230                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
231         else
232                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
233                 
234         gtk_tree_model_get (tree_model, iter,
235                             sender_receiver_col,  &address,
236                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
237                             -1);
238         
239         g_object_set (G_OBJECT(renderer),
240                       "text",
241                       modest_text_utils_get_display_address (address),
242                       NULL);
243         g_free (address);
244         set_common_flags (renderer, flags);
245 }
246 /*
247  * this for both incoming and outgoing mail, depending on the the user_data
248  * parameter. in the incoming case, show 'From' and 'Received date', in the
249  * outgoing case, show 'To' and 'Sent date'
250  */
251 void
252 _modest_header_view_compact_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
253                                                GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
254 {
255         TnyHeaderFlags flags;
256         gchar *address, *subject, *header;
257         time_t date;
258         ModestHeaderViewCompactHeaderMode header_mode;
259         GtkCellRenderer *recipient_cell, *date_or_status_cell, *subject_cell,
260                 *attach_cell, *priority_cell,
261                 *recipient_box, *subject_box;
262         TnyHeader *msg_header;
263         gchar *display_date = NULL, *tmp_date = NULL;
264
265         recipient_box = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (renderer), "recpt-box-renderer"));
266         subject_box = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (renderer), "subject-box-renderer"));
267         priority_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (subject_box), "priority-renderer"));
268         subject_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (subject_box), "subject-renderer"));
269         attach_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "attach-renderer"));
270         recipient_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "recipient-renderer"));
271         date_or_status_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "date-renderer"));
272
273         header_mode = GPOINTER_TO_INT (user_data); 
274
275         if (header_mode == MODEST_HEADER_VIEW_COMPACT_HEADER_MODE_IN)
276                 gtk_tree_model_get (tree_model, iter,
277                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
278                                     TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN,  &address,
279                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
280                                     TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN, &date,   
281                                     -1);
282         else
283                 gtk_tree_model_get (tree_model, iter,
284                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
285                                     TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN,  &address,
286                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
287                                     TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN, &date,
288                                     TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &msg_header,
289                                     -1);
290
291         /* flags */
292         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
293                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
294                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
295                               NULL);
296         else
297                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
298                               NULL, NULL);
299         if (flags & TNY_HEADER_FLAG_PRIORITY)
300                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
301                               get_pixbuf_for_flag (flags & TNY_HEADER_FLAG_PRIORITY),
302                               NULL);
303         else
304                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
305                               NULL, NULL);
306         header = g_markup_printf_escaped ("%s", (subject && strlen (subject)) ? subject : _("mail_va_no_subject"));
307         g_free (subject);
308         g_object_set (G_OBJECT (subject_cell), "markup", header, NULL);
309         g_free (header);
310         set_common_flags (subject_cell, flags);
311         
312         header = g_markup_printf_escaped ("<small>%s</small>", modest_text_utils_get_display_address (address));
313         g_free (address);
314         g_object_set (G_OBJECT (recipient_cell), "markup", header, NULL);
315         g_free (header);
316         set_common_flags (recipient_cell, flags);
317
318         if (header_mode == MODEST_HEADER_VIEW_COMPACT_HEADER_MODE_OUTBOX) {
319                 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_WAITING;
320                 const gchar *status_str = "";
321                 if (msg_header != NULL) {
322                         status = get_status_of_uid (tny_header_get_message_id (msg_header));
323                 }
324                 status_str = get_status_string (status);
325                 /* TODO: for now we set the status to waiting always, we need a way to
326                  * retrieve the current send status of a message */
327                 status_str = get_status_string (MODEST_TNY_SEND_QUEUE_WAITING);
328                 display_date = g_strdup_printf("<small>%s</small>", status_str);
329                 g_object_set (G_OBJECT (date_or_status_cell), "markup", display_date, NULL);
330                 g_free (display_date);
331         } else {
332                 /* in some rare cases, mail might have no Date: field. it case,
333                  * don't show the date, instead of bogus 1/1/1970
334                  */
335                 if (date)
336                         tmp_date = modest_text_utils_get_display_date (date);
337                 else
338                         tmp_date = g_strdup ("");
339                 
340                 display_date = g_strdup_printf ("<small>%s</small>", tmp_date);
341                 g_object_set (G_OBJECT (date_or_status_cell), "markup", display_date, NULL);
342                 g_free (tmp_date);
343                 g_free (display_date);
344         }
345         set_common_flags (date_or_status_cell, flags);
346 }
347
348
349 void
350 _modest_header_view_size_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
351                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
352                                      gpointer user_data)
353 {
354         TnyHeaderFlags flags;
355         guint size;
356         gchar *size_str;
357         
358         gtk_tree_model_get (tree_model, iter,
359                            TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
360                            TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &size,
361                             -1);
362         
363         size_str = modest_text_utils_get_display_size (size);
364         
365         g_object_set (G_OBJECT(renderer), "text", size_str, NULL);
366         set_common_flags (renderer, flags);
367
368         g_free (size_str);
369  }
370
371 void
372 _modest_header_view_status_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
373                                        GtkTreeModel *tree_model,  GtkTreeIter *iter,
374                                        gpointer user_data)
375 {
376         TnyHeaderFlags flags;
377         //guint status;
378         gchar *status_str;
379         
380         gtk_tree_model_get (tree_model, iter,
381                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
382         //                  TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &status,
383                             -1);
384         
385         status_str = g_strdup(_("mcen_li_outbox_waiting"));
386         
387         g_object_set (G_OBJECT(renderer), "text", status_str, NULL);
388         set_common_flags (renderer, flags);
389
390         g_free (status_str);
391  }
392