* Some changes to cancel sending operation
[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 (TnyHeader *header)
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         ModestTnySendQueueStatus queue_status = MODEST_TNY_SEND_QUEUE_SUSPENDED;
59         gchar *msg_uid = NULL;
60         
61         msg_uid = modest_tny_send_queue_get_msg_id (header);
62         cache_mgr = modest_runtime_get_cache_mgr ();
63         send_queue_cache = modest_cache_mgr_get_cache (cache_mgr,
64                                                        MODEST_CACHE_MGR_CACHE_TYPE_SEND_QUEUE);
65         
66         g_hash_table_foreach (send_queue_cache, (GHFunc) fill_list_of_caches, &send_queues);
67         
68         for (node = send_queues; node != NULL; node = g_slist_next (node)) {
69                 ModestTnySendQueue *send_queue = MODEST_TNY_SEND_QUEUE (node->data);
70
71                 queue_status = modest_tny_send_queue_get_msg_status (send_queue, msg_uid);
72                 if (queue_status != MODEST_TNY_SEND_QUEUE_UNKNONW) {
73                         status = queue_status;
74                         break;
75                 }
76         }
77
78         g_free(msg_uid);
79         g_slist_free (send_queues);
80         return status;
81 }
82
83 static const gchar *
84 get_status_string (ModestTnySendQueueStatus status)
85 {
86         switch (status) {
87         case MODEST_TNY_SEND_QUEUE_WAITING:
88                 return _("mcen_li_outbox_waiting");
89                 break;
90         case MODEST_TNY_SEND_QUEUE_SENDING:
91                 return _("mcen_li_outbox_sending");
92                 break;
93         case MODEST_TNY_SEND_QUEUE_SUSPENDED:
94                 return _("mcen_li_outbox_suspended");
95                 break;
96         case MODEST_TNY_SEND_QUEUE_FAILED:
97                 return _("mcen_li_outbox_failed");
98                 break;
99         default:
100                 return "";
101                 break;
102         }
103 }
104
105 static GdkPixbuf*
106 get_pixbuf_for_flag (TnyHeaderFlags flag)
107 {
108         /* optimization */
109         static GdkPixbuf *deleted_pixbuf          = NULL;
110         static GdkPixbuf *seen_pixbuf             = NULL;
111         static GdkPixbuf *unread_pixbuf           = NULL;
112         static GdkPixbuf *attachments_pixbuf      = NULL;
113         static GdkPixbuf *high_pixbuf             = NULL;
114         static GdkPixbuf *low_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         case TNY_HEADER_FLAG_HIGH_PRIORITY:
130                 if (G_UNLIKELY(!high_pixbuf))
131                         high_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_HIGH_PRIORITY);
132                 return high_pixbuf;
133         case TNY_HEADER_FLAG_LOW_PRIORITY:
134                 if (G_UNLIKELY(!low_pixbuf))
135                         low_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_LOW_PRIORITY);
136                 return low_pixbuf;
137         default:
138                 if (G_UNLIKELY(!unread_pixbuf))
139                         unread_pixbuf = modest_platform_get_icon (MODEST_HEADER_ICON_UNREAD);
140                 return unread_pixbuf;
141         }
142 }
143
144 static void
145 set_common_flags (GtkCellRenderer *renderer, TnyHeaderFlags flags)
146 {
147         g_object_set (G_OBJECT(renderer),
148                       "weight", (flags & TNY_HEADER_FLAG_SEEN) ? PANGO_WEIGHT_NORMAL: PANGO_WEIGHT_ULTRABOLD,
149                       "strikethrough",  (flags & TNY_HEADER_FLAG_DELETED) ?  TRUE:FALSE,
150                       NULL);    
151 }
152
153
154 void
155 _modest_header_view_msgtype_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
156                    GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
157 {
158         TnyHeaderFlags flags;
159                 
160         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
161                             &flags, -1);
162
163         if (flags & TNY_HEADER_FLAG_DELETED)
164                 g_object_set (G_OBJECT (renderer), "pixbuf",
165                               get_pixbuf_for_flag (TNY_HEADER_FLAG_DELETED), NULL);           
166         else if (flags & TNY_HEADER_FLAG_SEEN)
167                 g_object_set (G_OBJECT (renderer), "pixbuf",
168                               get_pixbuf_for_flag (TNY_HEADER_FLAG_SEEN), NULL);              
169         else 
170                 g_object_set (G_OBJECT (renderer), "pixbuf",
171                               get_pixbuf_for_flag (0), NULL); /* ughh, FIXME */               
172 }
173
174 void
175 _modest_header_view_attach_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
176                                       GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
177 {
178         TnyHeaderFlags flags;
179
180         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
181                             &flags, -1);
182
183         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
184                 g_object_set (G_OBJECT (renderer), "pixbuf",
185                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
186                               NULL);
187 }
188
189 void
190 _modest_header_view_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
191                   GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
192 {
193         TnyHeaderFlags flags;
194         
195         gtk_tree_model_get (tree_model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN,
196                             &flags, -1);
197         set_common_flags (renderer, flags);
198 }
199
200
201 void
202 _modest_header_view_date_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
203                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
204                                      gpointer user_data)
205 {
206         TnyHeaderFlags flags;
207         guint date, date_col;
208         gchar *display_date = NULL;
209         gboolean received = GPOINTER_TO_INT(user_data);
210
211         if (received)
212                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN;
213         else
214                 date_col = TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN;
215
216         gtk_tree_model_get (tree_model, iter,
217                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
218                             date_col, &date,
219                             -1);
220
221         display_date = modest_text_utils_get_display_date (date);
222         g_object_set (G_OBJECT(renderer), "text", display_date, NULL);  
223
224         set_common_flags (renderer, flags);
225         g_free (display_date);
226 }
227
228 void
229 _modest_header_view_sender_receiver_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
230                             GtkTreeModel *tree_model,  GtkTreeIter *iter,  gboolean is_sender)
231 {
232         TnyHeaderFlags flags;
233         gchar *address;
234         gint sender_receiver_col;
235
236         if (is_sender)
237                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN;
238         else
239                 sender_receiver_col = TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN;
240                 
241         gtk_tree_model_get (tree_model, iter,
242                             sender_receiver_col,  &address,
243                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
244                             -1);
245         
246         g_object_set (G_OBJECT(renderer),
247                       "text",
248                       modest_text_utils_get_display_address (address),
249                       NULL);
250         g_free (address);
251         set_common_flags (renderer, flags);
252 }
253 /*
254  * this for both incoming and outgoing mail, depending on the the user_data
255  * parameter. in the incoming case, show 'From' and 'Received date', in the
256  * outgoing case, show 'To' and 'Sent date'
257  */
258 void
259 _modest_header_view_compact_header_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
260                                                GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
261 {
262         TnyHeaderFlags flags, prior_flags;
263         gchar *address, *subject, *header;
264         time_t date;
265         ModestHeaderViewCompactHeaderMode header_mode;
266         GtkCellRenderer *recipient_cell, *date_or_status_cell, *subject_cell,
267                 *attach_cell, *priority_cell,
268                 *recipient_box, *subject_box;
269         TnyHeader *msg_header;
270         gchar *display_date = NULL, *tmp_date = NULL;
271
272         recipient_box = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (renderer), "recpt-box-renderer"));
273         subject_box = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (renderer), "subject-box-renderer"));
274         priority_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (subject_box), "priority-renderer"));
275         subject_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (subject_box), "subject-renderer"));
276         attach_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "attach-renderer"));
277         recipient_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "recipient-renderer"));
278         date_or_status_cell = GTK_CELL_RENDERER (g_object_get_data (G_OBJECT (recipient_box), "date-renderer"));
279
280         header_mode = GPOINTER_TO_INT (user_data); 
281
282         if (header_mode == MODEST_HEADER_VIEW_COMPACT_HEADER_MODE_IN)
283                 gtk_tree_model_get (tree_model, iter,
284                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
285                                     TNY_GTK_HEADER_LIST_MODEL_FROM_COLUMN,  &address,
286                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
287                                     TNY_GTK_HEADER_LIST_MODEL_DATE_RECEIVED_TIME_T_COLUMN, &date,   
288                                     -1);
289         else
290                 gtk_tree_model_get (tree_model, iter,
291                                     TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
292                                     TNY_GTK_HEADER_LIST_MODEL_TO_COLUMN,  &address,
293                                     TNY_GTK_HEADER_LIST_MODEL_SUBJECT_COLUMN, &subject,
294                                     TNY_GTK_HEADER_LIST_MODEL_DATE_SENT_TIME_T_COLUMN, &date,
295                                     TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &msg_header,
296                                     -1);
297
298         /* flags */
299         prior_flags = flags & TNY_HEADER_FLAG_PRIORITY;
300         if (flags & TNY_HEADER_FLAG_ATTACHMENTS)
301                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
302                               get_pixbuf_for_flag (TNY_HEADER_FLAG_ATTACHMENTS),
303                               NULL);
304         else
305                 g_object_set (G_OBJECT (attach_cell), "pixbuf",
306                               NULL, NULL);
307         if (flags & TNY_HEADER_FLAG_PRIORITY)
308                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
309                               get_pixbuf_for_flag (prior_flags),
310 /*                            get_pixbuf_for_flag (flags & TNY_HEADER_FLAG_PRIORITY), */
311                               NULL);
312         else
313                 g_object_set (G_OBJECT (priority_cell), "pixbuf",
314                               NULL, NULL);
315         header = g_markup_printf_escaped ("%s", (subject && strlen (subject)) ? subject : _("mail_va_no_subject"));
316         g_free (subject);
317         g_object_set (G_OBJECT (subject_cell), "markup", header, NULL);
318         g_free (header);
319         set_common_flags (subject_cell, flags);
320
321
322         /* fixme: we hardcode the color to #666666; instead we should use SecundaryTextColour from the
323          * theme (gtkrc file) */
324         
325         header = g_markup_printf_escaped ("<small>%s</small>", modest_text_utils_get_display_address (address));
326         g_free (address);
327         g_object_set (G_OBJECT (recipient_cell),
328                       "markup", header,
329                       "foreground", "#666666",
330                       NULL);
331         g_free (header);
332         set_common_flags (recipient_cell, flags);
333
334         if (header_mode == MODEST_HEADER_VIEW_COMPACT_HEADER_MODE_OUTBOX) {
335                 ModestTnySendQueueStatus status = MODEST_TNY_SEND_QUEUE_WAITING;
336                 const gchar *status_str = "";
337                 if (msg_header != NULL) {
338                         status = get_status_of_uid (msg_header);
339                         if (status == MODEST_TNY_SEND_QUEUE_SUSPENDED) {
340                                 tny_header_unset_flags (msg_header, TNY_HEADER_FLAG_PRIORITY);
341                                 tny_header_set_flags (msg_header, TNY_HEADER_FLAG_SUSPENDED_PRIORITY);
342                         }
343 /*                      if (prior_flags == TNY_HEADER_FLAG_SUSPENDED_PRIORITY) */
344 /*                              status = MODEST_TNY_SEND_QUEUE_SUSPENDED; */
345                 }
346                 status_str = get_status_string (status);
347                 display_date = g_strdup_printf("<small>%s</small>", status_str);
348                 g_object_set (G_OBJECT (date_or_status_cell),
349                               "markup", display_date,
350                               "foreground", "#666666",
351                               NULL);
352                 g_free (display_date);
353         } else {
354                 /* in some rare cases, mail might have no Date: field. it case,
355                  * don't show the date, instead of bogus 1/1/1970
356                  */
357                 if (date)
358                         tmp_date = modest_text_utils_get_display_date (date);
359                 else
360                         tmp_date = g_strdup ("");
361                 
362                 display_date = g_strdup_printf ("<small>%s</small>", tmp_date);
363                 g_object_set (G_OBJECT (date_or_status_cell),
364                               "markup", display_date,
365                               "foreground", "#666666",
366                               NULL);
367                 g_free (tmp_date);
368                 g_free (display_date);
369         }
370         set_common_flags (date_or_status_cell, flags);
371 }
372
373
374 void
375 _modest_header_view_size_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
376                                      GtkTreeModel *tree_model,  GtkTreeIter *iter,
377                                      gpointer user_data)
378 {
379         TnyHeaderFlags flags;
380         guint size;
381         gchar *size_str;
382         
383         gtk_tree_model_get (tree_model, iter,
384                            TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
385                            TNY_GTK_HEADER_LIST_MODEL_MESSAGE_SIZE_COLUMN, &size,
386                             -1);
387         
388         size_str = modest_text_utils_get_display_size (size);
389         
390         g_object_set (G_OBJECT(renderer), "text", size_str, NULL);
391         set_common_flags (renderer, flags);
392
393         g_free (size_str);
394  }
395
396 void
397 _modest_header_view_status_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
398                                        GtkTreeModel *tree_model,  GtkTreeIter *iter,
399                                        gpointer user_data)
400 {
401         TnyHeaderFlags flags, prior_flags;
402         //guint status;
403         gchar *status_str;
404         
405         gtk_tree_model_get (tree_model, iter,
406                             TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &flags,
407                             -1);
408         
409        prior_flags = flags & TNY_HEADER_FLAG_PRIORITY;
410        if (prior_flags == TNY_HEADER_FLAG_SUSPENDED_PRIORITY)
411                status_str = g_strdup(_("mcen_li_outbox_suspended"));
412        else            
413                status_str = g_strdup(_("mcen_li_outbox_waiting"));
414        
415         g_object_set (G_OBJECT(renderer), "text", status_str, NULL);
416         set_common_flags (renderer, flags);
417
418         g_free (status_str);
419  }
420