* Uncomment flush call to tny_send_queue.
[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, prior_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         flags = tny_header_get_flags (msg_header);
293         prior_flags = flags & TNY_HEADER_FLAG_PRIORITY;
294         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
295                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
296                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
297                               NULL);
298         else
299                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
300                               NULL, NULL);
301         if (flags & TNY_HEADER_FLAG_PRIORITY)
302                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
303                               get_pixbuf_for_flag (prior_flags),
304 /*                            get_pixbuf_for_flag (flags & TNY_HEADER_FLAG_PRIORITY), */
305                               NULL);
306         else
307                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
308                               NULL, NULL);
309         header = g_markup_printf_escaped ("%s", (subject && strlen (subject)) ? subject : _("mail_va_no_subject"));
310         g_free (subject);
311         g_object_set (G_OBJECT (subject_cell), "markup", header, NULL);
312         g_free (header);
313         set_common_flags (subject_cell, flags);
314
315
316         /* fixme: we hardcode the color to #666666; instead we should use SecundaryTextColour from the
317          * theme (gtkrc file) */
318         
319         header = g_markup_printf_escaped ("<small>%s</small>", modest_text_utils_get_display_address (address));
320         g_free (address);
321         g_object_set (G_OBJECT (recipient_cell),
322                       "markup", header,
323                       "foreground", "#666666",
324                       NULL);
325         g_free (header);
326         set_common_flags (recipient_cell, flags);
327
328         if (header_mode == MODEST_HEADER_VIEW_COMPACT_HEADER_MODE_OUTBOX) {
329                 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_WAITING;
330                 const gchar *status_str = "";
331                 if (msg_header != NULL) {
332                         /* TODO: ask send queue for msg sending status */
333 /*                      status = get_status_of_uid (tny_header_get_message_id (msg_header)); */
334                         if (prior_flags == TNY_HEADER_FLAG_SUSPENDED_PRIORITY)
335                                 status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
336                 }
337                 status_str = get_status_string (status);
338                 /* TODO: for now we set the status to waiting always, we need a way to
339                  * retrieve the current send status of a message */
340 /*              status_str = get_status_string (MODEST_TNY_SEND_QUEUE_WAITING); */
341                 display_date = g_strdup_printf("<small>%s</small>", status_str);
342                 g_object_set (G_OBJECT (date_or_status_cell),
343                               "markup", display_date,
344                               "foreground", "#666666",
345                               NULL);
346                 g_free (display_date);
347         } else {
348                 /* in some rare cases, mail might have no Date: field. it case,
349                  * don't show the date, instead of bogus 1/1/1970
350                  */
351                 if (date)
352                         tmp_date = modest_text_utils_get_display_date (date);
353                 else
354                         tmp_date = g_strdup ("");
355                 
356                 display_date = g_strdup_printf ("<small>%s</small>", tmp_date);
357                 g_object_set (G_OBJECT (date_or_status_cell),
358                               "markup", display_date,
359                               "foreground", "#666666",
360                               NULL);
361                 g_free (tmp_date);
362                 g_free (display_date);
363         }
364         set_common_flags (date_or_status_cell, flags);
365 }
366
367
368 void
369 _modest_header_view_size_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
370                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
371                                      gpointer user_data)
372 {
373         TnyHeaderFlags flags;
374         guint size;
375         gchar *size_str;
376         
377         gtk_tree_model_get (tree_model, iter,
378                            TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
379                            TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &size,
380                             -1);
381         
382         size_str = modest_text_utils_get_display_size (size);
383         
384         g_object_set (G_OBJECT(renderer), "text", size_str, NULL);
385         set_common_flags (renderer, flags);
386
387         g_free (size_str);
388  }
389
390 void
391 _modest_header_view_status_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
392                                        GtkTreeModel *tree_model,  GtkTreeIter *iter,
393                                        gpointer user_data)
394 {
395         TnyHeaderFlags flags, prior_flags;
396         //guint status;
397         gchar *status_str;
398         
399         gtk_tree_model_get (tree_model, iter,
400                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
401                             -1);
402         
403        prior_flags = flags & TNY_HEADER_FLAG_PRIORITY;
404        if (prior_flags == TNY_HEADER_FLAG_SUSPENDED_PRIORITY)
405                status_str = g_strdup(_("mcen_li_outbox_suspended"));
406        else            
407                status_str = g_strdup(_("mcen_li_outbox_waiting"));
408        
409         g_object_set (G_OBJECT(renderer), "text", status_str, NULL);
410         set_common_flags (renderer, flags);
411
412         g_free (status_str);
413  }
414