fd9f115f44c2e4454d3a1612521e13f24dd7c98f
[modest] / src / widgets / modest-account-view.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 <glib/gi18n.h>
31 #include "modest-account-view.h"
32
33 #include <modest-account-mgr.h>
34 #include <modest-account-mgr-helpers.h>
35 #include <modest-tny-account.h>
36 #include <modest-text-utils.h>
37 #include <modest-runtime.h>
38 #include <modest-signal-mgr.h>
39
40 #include <gtk/gtkcellrenderertoggle.h>
41 #include <gtk/gtkcellrenderertext.h>
42 #include <gtk/gtktreeselection.h>
43 #include <gtk/gtkliststore.h>
44 #include <string.h> /* For strcmp(). */
45 #include <modest-account-mgr-helpers.h>
46 #include <modest-datetime-formatter.h>
47 #ifdef MODEST_TOOLKIT_HILDON2
48 #include <hildon/hildon-defines.h>
49 #endif
50 #ifdef MODEST_USE_LIBTIME
51 #include <clockd/libtime.h>
52 #endif
53
54 /* 'private'/'protected' functions */
55 static void modest_account_view_class_init    (ModestAccountViewClass *klass);
56 static void modest_account_view_init          (ModestAccountView *obj);
57 static void modest_account_view_finalize      (GObject *obj);
58
59 static void modest_account_view_select_account (ModestAccountView *account_view, 
60                                                 const gchar* account_name);
61
62 static void on_default_account_changed         (ModestAccountMgr *mgr,
63                                                 gpointer user_data);
64
65 static void on_display_name_changed            (ModestAccountMgr *self, 
66                                                 const gchar *account,
67                                                 gpointer user_data);
68
69 #ifndef MODEST_TOOLKIT_HILDON2
70 static void modest_account_view_select_first_account (ModestAccountView *account_view);
71 #endif
72
73 static void on_account_updated (ModestAccountMgr* mgr, gchar* account_name,
74                     gpointer user_data);
75 static void update_account_view (ModestAccountMgr *account_mgr, ModestAccountView *view);
76 static void on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata);
77 static void update_display_mode (ModestAccountView *self);
78
79 typedef enum {
80         MODEST_ACCOUNT_VIEW_NAME_COLUMN,
81         MODEST_ACCOUNT_VIEW_DISPLAY_NAME_COLUMN,
82         MODEST_ACCOUNT_VIEW_IS_ENABLED_COLUMN,
83         MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN,
84         MODEST_ACCOUNT_VIEW_PROTO_COLUMN,
85         MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN,
86
87         MODEST_ACCOUNT_VIEW_COLUMN_NUM
88 } AccountViewColumns;
89
90 typedef struct _ModestAccountViewPrivate ModestAccountViewPrivate;
91 struct _ModestAccountViewPrivate {
92         ModestAccountMgr *account_mgr;
93
94         ModestDatetimeFormatter *datetime_formatter;
95         gboolean picker_mode;
96         gboolean show_last_updated;
97
98         /* Signal handlers */
99         GSList *sig_handlers;
100 };
101 #define MODEST_ACCOUNT_VIEW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
102                                                  MODEST_TYPE_ACCOUNT_VIEW, \
103                                                  ModestAccountViewPrivate))
104 /* globals */
105 static GtkTreeViewClass *parent_class = NULL;
106
107 GType
108 modest_account_view_get_type (void)
109 {
110         static GType my_type = 0;
111         if (!my_type) {
112                 static const GTypeInfo my_info = {
113                         sizeof(ModestAccountViewClass),
114                         NULL,           /* base init */
115                         NULL,           /* base finalize */
116                         (GClassInitFunc) modest_account_view_class_init,
117                         NULL,           /* class finalize */
118                         NULL,           /* class data */
119                         sizeof(ModestAccountView),
120                         1,              /* n_preallocs */
121                         (GInstanceInitFunc) modest_account_view_init,
122                         NULL
123                 };
124                 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
125                                                   "ModestAccountView",
126                                                   &my_info, 0);
127         }
128         return my_type;
129 }
130
131 static void
132 modest_account_view_class_init (ModestAccountViewClass *klass)
133 {
134         GObjectClass *gobject_class;
135         gobject_class = (GObjectClass*) klass;
136
137         parent_class            = g_type_class_peek_parent (klass);
138         gobject_class->finalize = modest_account_view_finalize;
139
140         g_type_class_add_private (gobject_class, sizeof(ModestAccountViewPrivate));
141 }
142
143 static void
144 datetime_format_changed (ModestDatetimeFormatter *formatter,
145                          ModestAccountView *self)
146 {
147         ModestAccountViewPrivate *priv;
148         
149         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
150         update_account_view (priv->account_mgr, self);
151 }
152
153 static void
154 modest_account_view_init (ModestAccountView *obj)
155 {
156         ModestAccountViewPrivate *priv;
157         
158         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(obj);
159         
160         priv->sig_handlers = NULL;
161
162         priv->datetime_formatter = modest_datetime_formatter_new ();
163         priv->picker_mode = FALSE;
164         priv->show_last_updated = TRUE;
165         g_signal_connect (G_OBJECT (priv->datetime_formatter), "format-changed", 
166                           G_CALLBACK (datetime_format_changed), (gpointer) obj);
167 #ifdef MODEST_TOOLKIT_HILDON2
168         gtk_rc_parse_string ("style \"fremantle-modest-account-view\" {\n"
169                              "  GtkWidget::hildon-mode = 1\n"
170                              "} widget \"*.fremantle-modest-account-view\" style \"fremantle-modest-account-view\""
171                              "widget_class \"*<HildonPannableArea>.ModestAccountView\" style :highest \"fremantle-modest-account-view\"");
172         
173 #endif
174         g_signal_connect (G_OBJECT (obj), "notify::style", G_CALLBACK (on_notify_style), (gpointer) obj);
175 }
176
177 static void
178 modest_account_view_finalize (GObject *obj)
179 {
180         ModestAccountViewPrivate *priv;
181
182         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(obj);
183
184         if (priv->datetime_formatter) {
185                 g_object_unref (priv->datetime_formatter);
186                 priv->datetime_formatter = NULL;
187         }
188
189         /* Disconnect signals */
190         modest_signal_mgr_disconnect_all_and_destroy (priv->sig_handlers);
191
192         if (priv->account_mgr) {        
193                 g_object_unref (G_OBJECT(priv->account_mgr));
194                 priv->account_mgr = NULL; 
195         }
196         
197         G_OBJECT_CLASS(parent_class)->finalize (obj);
198 }
199
200 /* Get the string for the last updated time. Result must NOT be g_freed */
201 static const gchar*
202 get_last_updated_string(ModestAccountView *self, ModestAccountMgr* account_mgr, ModestAccountSettings *settings)
203 {
204         /* FIXME: let's assume that 'last update' applies to the store account... */
205         const gchar *last_updated_string;
206         const gchar *store_account_name;
207         const gchar *account_name;
208         time_t last_updated;
209         ModestServerAccountSettings *server_settings;
210         ModestAccountViewPrivate *priv;
211
212         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE (self);
213         server_settings = modest_account_settings_get_store_settings (settings);
214         store_account_name = modest_server_account_settings_get_account_name (server_settings);
215         last_updated = modest_account_mgr_get_last_updated (account_mgr, store_account_name);
216
217         g_object_unref (server_settings);
218         account_name = modest_account_settings_get_account_name (settings);
219         if (!modest_account_mgr_account_is_busy(account_mgr, account_name)) {
220                 if (last_updated > 0) {
221                         last_updated_string = 
222                                 modest_datetime_formatter_display_datetime (priv->datetime_formatter,
223                                                                            last_updated);
224                 } else {
225                         last_updated_string = _("mcen_va_never");
226                 }
227         } else  {
228                 last_updated_string = _("mcen_va_refreshing");
229         }
230
231         return last_updated_string;
232 }
233
234 static void
235 update_account_view (ModestAccountMgr *account_mgr, ModestAccountView *view)
236 {
237         GSList *account_names, *cursor;
238         GtkListStore *model;
239         ModestAccountViewPrivate *priv;
240         
241         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(view);
242         model = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(view)));
243
244         /* Get the ID of the currently-selected account,
245          * so we can select it again after rebuilding the list.
246          * Note that the name doesn't change even when the display name changes.
247          */
248         gchar *selected_name = modest_account_view_get_selected_account (view);
249
250         gtk_list_store_clear (model);
251
252         /* Note: We do not show disabled accounts.
253          * Of course, this means that there is no UI to enable or disable
254          * accounts. That is OK for maemo where no such feature or UI is
255          * specified, so the "enabled" property is used internally to avoid
256          * showing unfinished accounts. If a user-visible "enabled" is
257          * needed in the future, we must use a second property for the
258          * current use instead */
259         cursor = account_names = modest_account_mgr_account_names (account_mgr,
260                 TRUE /* only enabled accounts. */);
261
262         while (cursor) {
263                 gchar *account_name;
264                 ModestAccountSettings *settings;
265                 ModestServerAccountSettings *store_settings;
266                 
267                 account_name = (gchar*)cursor->data;
268                 
269                 settings = modest_account_mgr_load_account_settings (account_mgr, account_name);
270                 if (!settings) {
271                         g_printerr ("modest: failed to get account data for %s\n", account_name);
272                         cursor = cursor->next;
273                         continue;
274                 }
275                 store_settings = modest_account_settings_get_store_settings (settings);
276
277                 /* don't display accounts without stores */
278                 if (modest_server_account_settings_get_account_name (store_settings) != NULL) {
279
280                         GtkTreeIter iter;
281
282                         /* don't free */
283                         const gchar *last_updated_string = get_last_updated_string(view, account_mgr, settings);
284                         
285                         if (modest_account_settings_get_enabled (settings)) {
286                                 ModestProtocolType protocol_type;
287                                 ModestProtocolRegistry *protocol_registry;
288                                 ModestProtocol *protocol;
289                                 const gchar *proto_name;
290 #ifdef MODEST_TOOLKIT_HILDON2
291                                 gchar *last_updated_hildon2;
292
293                                 if (priv->show_last_updated) {
294                                         last_updated_hildon2 = g_strconcat (_("mcen_ti_lastupdated"), "\n", 
295                                                                             last_updated_string,
296                                                                             NULL);
297                                 } else {
298                                         last_updated_hildon2 = g_strconcat (_("mcen_ti_lastupdated"), "\n", NULL);
299                                 }
300 #endif
301                                 protocol_registry = modest_runtime_get_protocol_registry ();
302                                 protocol_type = modest_server_account_settings_get_protocol (store_settings);
303                                 protocol = modest_protocol_registry_get_protocol_by_type (protocol_registry, protocol_type);
304                                 proto_name = modest_protocol_get_name (protocol);
305                                 gtk_list_store_insert_with_values (
306                                         model, &iter, 0,
307                                         MODEST_ACCOUNT_VIEW_NAME_COLUMN, account_name,
308                                         MODEST_ACCOUNT_VIEW_DISPLAY_NAME_COLUMN, 
309                                         modest_account_settings_get_display_name (settings),
310                                         MODEST_ACCOUNT_VIEW_IS_ENABLED_COLUMN, 
311                                         modest_account_settings_get_enabled (settings),
312                                         MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN, 
313                                         modest_account_settings_get_is_default (settings),
314                                         MODEST_ACCOUNT_VIEW_PROTO_COLUMN, proto_name,
315 #ifdef MODEST_TOOLKIT_HILDON2
316                                         MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN,  last_updated_hildon2,
317 #else
318                                         MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN,  last_updated_string,
319 #endif
320                                         -1);
321 #ifdef MODEST_TOOLKIT_HILDON2
322                                 g_free (last_updated_hildon2);
323 #endif
324                         }
325                 }
326                 
327                 g_object_unref (store_settings);
328                 g_object_unref (settings);
329                 cursor = cursor->next;
330         }
331
332         modest_account_mgr_free_account_names (account_names);
333         account_names = NULL;
334         
335         /* Try to re-select the same account: */
336         if (selected_name) {
337                 modest_account_view_select_account (view, selected_name);
338                 g_free (selected_name);
339         } else {
340 #ifndef MODEST_TOOLKIT_HILDON2
341                 modest_account_view_select_first_account (view);
342 #endif
343         }
344 }
345
346 static void
347 on_account_busy_changed(ModestAccountMgr *account_mgr, 
348                         const gchar *account_name,
349                         gboolean busy, 
350                         ModestAccountView *self)
351 {
352         GtkListStore *model = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(self)));
353         GtkTreeIter iter;
354         gboolean found = FALSE;
355
356         if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
357                 return;
358
359         do {
360                 gchar* cur_name;
361                 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 
362                                    MODEST_ACCOUNT_VIEW_NAME_COLUMN, 
363                                    &cur_name, -1);
364
365                 if (g_str_equal(cur_name, account_name)) {
366                         ModestAccountSettings* settings = 
367                                 modest_account_mgr_load_account_settings (account_mgr, account_name);
368                         if (!settings) {
369                                 g_free (cur_name);
370                                 return;
371                         }
372                         const gchar* last_updated_string = get_last_updated_string(self, account_mgr, settings);
373 #ifdef MODEST_TOOLKIT_HILDON2
374                         gchar *last_updated_hildon2;
375
376                         last_updated_hildon2 = g_strconcat (_("mcen_ti_lastupdated"), "\n", 
377                                                             last_updated_string,
378                                                             NULL);
379 #endif
380                         gtk_list_store_set(model, &iter, 
381 #ifdef MODEST_TOOLKIT_HILDON2
382                                            MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN, last_updated_hildon2,
383 #else
384                                            MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN, last_updated_string,
385 #endif
386                                            -1);
387
388 #ifdef MODEST_TOOLKIT_HILDON2
389                         g_free (last_updated_hildon2);
390 #endif
391                         g_object_unref (settings);
392                         found = TRUE;
393                 }
394                 g_free (cur_name);
395
396         } while (!found && gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
397 }
398
399 static void
400 on_account_inserted (TnyAccountStore *account_store, 
401                      TnyAccount *account,
402                      gpointer user_data)
403 {
404         ModestAccountView *self;
405         ModestAccountViewPrivate *priv;
406
407         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (user_data));
408
409         self = MODEST_ACCOUNT_VIEW (user_data);
410         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE (self);
411
412         /* Do not refresh the view with transport accounts */
413         if (TNY_IS_STORE_ACCOUNT (account))
414                 update_account_view (priv->account_mgr, self);
415 }
416
417 static void
418 on_account_removed (TnyAccountStore *account_store, 
419                     TnyAccount *account,
420                     gpointer user_data)
421 {
422         ModestAccountView *self;
423         ModestAccountViewPrivate *priv;
424         gchar *selected_name;
425
426         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (user_data));
427
428         self = MODEST_ACCOUNT_VIEW (user_data);
429         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE (self);
430
431         /* Do not refresh the view with transport accounts */
432         if (!TNY_IS_STORE_ACCOUNT (account))
433                 return;
434         
435         selected_name = modest_account_view_get_selected_account (self);
436         if (selected_name == NULL) {
437 #ifndef MODEST_TOOLKIT_HILDON2
438                 /* we select the first account if none is selected */
439                 modest_account_view_select_first_account (self);
440 #endif
441         } else {
442                 g_free (selected_name);
443         }
444         
445         update_account_view (priv->account_mgr, self);
446 }
447
448
449 static void
450 on_account_default_toggled (GtkCellRendererToggle *cell_renderer, 
451                             gchar *path,
452                             ModestAccountView *self)
453 {
454         ModestAccountViewPrivate *priv;
455         GtkTreeModel *model;
456         GtkTreeIter iter;
457         gchar *account_name = NULL;
458
459         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (self));
460
461         /* If it's active then do nothing, no need to reenable it as
462            default account */
463         if (gtk_cell_renderer_toggle_get_active (cell_renderer))
464                 return;
465
466         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
467         model = gtk_tree_view_get_model (GTK_TREE_VIEW(self));
468
469         if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
470                 g_warning ("Got path of a not existing iter");
471                 return;
472         }
473         
474         gtk_tree_model_get (model, &iter, 
475                             MODEST_ACCOUNT_VIEW_NAME_COLUMN, 
476                             &account_name, -1);
477
478         /* Set this previously-non-default account as the
479            default. We're not updating here the value of the
480            DEFAULT_COLUMN because we'll do it in the
481            "default_account_changed" signal handler. We do it like
482            this because that way the signal handler is useful also
483            when we're inserting a new account and there is no other
484            one defined, in that case the change of account is provoked
485            by the account mgr and not by a signal toggle.*/
486         modest_account_mgr_set_default_account (priv->account_mgr, account_name);
487
488         g_free (account_name);
489 }
490
491 static void
492 on_account_updated (ModestAccountMgr* mgr,
493                     gchar* account_name,
494                     gpointer user_data)
495 {
496         update_account_view (mgr, MODEST_ACCOUNT_VIEW (user_data));
497 }
498
499 static void
500 bold_if_default_account_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
501                                     GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
502 {
503         gboolean is_default;
504         GtkStyle *style;
505         const gchar *font_style;
506         PangoAttribute *attr;
507         PangoAttrList *attr_list = NULL;
508         GtkWidget *widget;
509
510         gtk_tree_model_get (tree_model, iter, MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN,
511                             &is_default, -1);
512
513 /*      widget = gtk_tree_view_column_get_tree_view (column); */
514         widget = GTK_WIDGET (user_data);
515         font_style = is_default?"EmpSystemFont":"SystemFont";
516         style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (GTK_WIDGET(widget)),
517                                            font_style, NULL,
518                                            G_TYPE_NONE);
519         if (style) {
520                 attr = pango_attr_font_desc_new (pango_font_description_copy (style->font_desc));
521
522                 attr_list = pango_attr_list_new ();
523                 pango_attr_list_insert (attr_list, attr);
524
525                 g_object_set (G_OBJECT(renderer),
526                               "attributes", attr_list, 
527                               NULL);
528
529                 pango_attr_list_unref (attr_list);
530         } else {
531                 g_object_set (G_OBJECT(renderer),
532                               "weight", is_default ? 800: 400,
533                               NULL);
534         }
535 }
536
537 static void
538 bold_if_default_last_updated_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
539                                          GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer user_data)
540 {
541         gboolean is_default;
542         GtkStyle *style;
543         const gchar *font_style;
544         PangoAttribute *attr;
545         PangoAttrList *attr_list = NULL;
546         GtkWidget *widget;
547
548         gtk_tree_model_get (tree_model, iter, MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN,
549                             &is_default, -1);
550
551 /*      widget = gtk_tree_view_column_get_tree_view (column); */
552         widget = GTK_WIDGET (user_data);
553         font_style = is_default?"EmpSmallSystemFont":"SmallSystemFont";
554         style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (GTK_WIDGET(widget)),
555                                            font_style, NULL,
556                                            G_TYPE_NONE);
557         if (style) {
558                 attr = pango_attr_font_desc_new (pango_font_description_copy (style->font_desc));
559
560                 attr_list = pango_attr_list_new ();
561                 pango_attr_list_insert (attr_list, attr);
562
563                 g_object_set (G_OBJECT(renderer),
564                               "attributes", attr_list, 
565                               NULL);
566
567                 pango_attr_list_unref (attr_list);
568         } else {
569                 g_object_set (G_OBJECT(renderer),
570                               "weight", is_default ? 800: 400,
571                               NULL);
572         }
573 }
574
575 static void
576 init_view (ModestAccountView *self)
577 {
578         ModestAccountViewPrivate *priv;
579         GtkCellRenderer *toggle_renderer, *text_renderer;
580         GtkListStore *model;
581         GtkTreeViewColumn *column;
582         
583         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (self));
584         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
585                 
586         model = gtk_list_store_new (6,
587                                     G_TYPE_STRING,  /* account name */
588                                     G_TYPE_STRING,  /* account display name */
589                                     G_TYPE_BOOLEAN, /* is-enabled */
590                                     G_TYPE_BOOLEAN, /* is-default */
591                                     G_TYPE_STRING,  /* account proto (pop, imap,...) */
592                                     G_TYPE_STRING   /* last updated (time_t) */
593                 ); 
594                 
595         gtk_tree_sortable_set_sort_column_id (
596                 GTK_TREE_SORTABLE (model), MODEST_ACCOUNT_VIEW_DISPLAY_NAME_COLUMN, 
597                 GTK_SORT_ASCENDING);
598
599         gtk_tree_view_set_model (GTK_TREE_VIEW(self), GTK_TREE_MODEL(model));
600         g_object_unref (G_OBJECT (model));
601
602         toggle_renderer = gtk_cell_renderer_toggle_new ();
603         /* the is_default column */
604         g_object_set (G_OBJECT(toggle_renderer), "activatable", TRUE, "radio", TRUE, NULL);
605         column = gtk_tree_view_column_new_with_attributes 
606                 (_("mcen_ti_default"), toggle_renderer,
607                  "active", MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN, NULL);
608         gtk_tree_view_append_column (GTK_TREE_VIEW(self),
609                                      column);
610 #ifdef MODEST_TOOLKIT_HILDON2
611         gtk_tree_view_column_set_visible (column, FALSE);
612 #endif
613                                         
614         /* Disable the Maemo GtkTreeView::allow-checkbox-mode Maemo modification, 
615          * which causes the model column to be updated automatically when the row is clicked.
616          * Making this the default in Maemo's GTK+ is obviously a bug:
617          * https://maemo.org/bugzilla/show_bug.cgi?id=146
618          *
619          * djcb: indeed, they have been removed for post-bora, i added the ifdefs...
620          */
621
622         priv->sig_handlers = 
623                 modest_signal_mgr_connect (priv->sig_handlers,
624                                            G_OBJECT(toggle_renderer), 
625                                            "toggled", 
626                                            G_CALLBACK(on_account_default_toggled),
627                                            self);
628         
629         /* account name */
630         text_renderer = gtk_cell_renderer_text_new ();
631         g_object_set (G_OBJECT (text_renderer), 
632                       "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, 
633 #ifdef MODEST_TOOLKIT_HILDON2
634                       "xpad", HILDON_MARGIN_DOUBLE,
635 #endif
636                       NULL);
637
638         column =  gtk_tree_view_column_new_with_attributes (_("mcen_ti_account"), text_renderer, "text",
639                                                             MODEST_ACCOUNT_VIEW_DISPLAY_NAME_COLUMN, NULL);
640         gtk_tree_view_append_column (GTK_TREE_VIEW(self), column);
641         gtk_tree_view_column_set_expand (column, TRUE);
642         gtk_tree_view_column_set_cell_data_func(column, text_renderer, bold_if_default_account_cell_data,
643                                                 self, NULL);
644
645         /* last update for this account */
646         text_renderer = gtk_cell_renderer_text_new ();
647         g_object_set (G_OBJECT (text_renderer), 
648                       "alignment", PANGO_ALIGN_RIGHT, 
649                       "xalign", 1.0,
650 #ifdef MODEST_TOOLKIT_HILDON2
651                       "xpad", HILDON_MARGIN_DOUBLE,
652 #endif
653                       NULL);
654
655         column =  gtk_tree_view_column_new_with_attributes (_("mcen_ti_lastupdated"), text_renderer,"markup",
656                                                             MODEST_ACCOUNT_VIEW_LAST_UPDATED_COLUMN, NULL);
657         gtk_tree_view_append_column (GTK_TREE_VIEW(self),column);
658         gtk_tree_view_column_set_expand (column, FALSE);
659         gtk_tree_view_column_set_cell_data_func(column, text_renderer, bold_if_default_last_updated_cell_data,
660                                                 self, NULL);
661
662         /* Show the column headers,
663          * which does not seem to be the default on Maemo.
664          */
665 #ifndef MODEST_TOOLKIT_HILDON2
666         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self), TRUE);
667 #endif
668
669         update_display_mode (self);
670
671         priv->sig_handlers = 
672                 modest_signal_mgr_connect (priv->sig_handlers, 
673                                            G_OBJECT (modest_runtime_get_account_store ()),
674                                            "account_removed",
675                                            G_CALLBACK(on_account_removed), 
676                                            self);
677         priv->sig_handlers = 
678                 modest_signal_mgr_connect (priv->sig_handlers, 
679                                            G_OBJECT (modest_runtime_get_account_store ()),
680                                            "account_inserted",
681                                            G_CALLBACK(on_account_inserted), 
682                                            self);
683         priv->sig_handlers = 
684                 modest_signal_mgr_connect (priv->sig_handlers, 
685                                            G_OBJECT(priv->account_mgr),
686                                            "account_busy_changed",
687                                            G_CALLBACK(on_account_busy_changed), 
688                                            self);
689         priv->sig_handlers = 
690                 modest_signal_mgr_connect (priv->sig_handlers, 
691                                            G_OBJECT(priv->account_mgr),
692                                            "default_account_changed",
693                                            G_CALLBACK(on_default_account_changed), 
694                                            self);
695         priv->sig_handlers = 
696                 modest_signal_mgr_connect (priv->sig_handlers, 
697                                            G_OBJECT(priv->account_mgr),
698                                            "display_name_changed",
699                                            G_CALLBACK(on_display_name_changed), 
700                                            self);
701         priv->sig_handlers = 
702                         modest_signal_mgr_connect (priv->sig_handlers,
703                                                    G_OBJECT (priv->account_mgr),
704                                                    "account_updated", 
705                                                    G_CALLBACK (on_account_updated),
706                                                    self);
707 }
708
709
710 ModestAccountView*
711 modest_account_view_new (ModestAccountMgr *account_mgr)
712 {
713         GObject *obj;
714         ModestAccountViewPrivate *priv;
715         
716         g_return_val_if_fail (account_mgr, NULL);
717         
718         obj  = g_object_new(MODEST_TYPE_ACCOUNT_VIEW, 
719 #ifdef MODEST_TOOLKIT_HILDON2
720                             "hildon-ui-mode", HILDON_UI_MODE_NORMAL,
721 #endif
722                             NULL);
723         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(obj);
724         
725         g_object_ref (G_OBJECT (account_mgr));
726         priv->account_mgr = account_mgr;
727
728         init_view (MODEST_ACCOUNT_VIEW (obj));
729         update_account_view (account_mgr, MODEST_ACCOUNT_VIEW (obj));
730         
731         return MODEST_ACCOUNT_VIEW (obj);
732 }
733
734 gchar *
735 modest_account_view_get_selected_account (ModestAccountView *self)
736 {
737         gchar *account_name = NULL;
738         GtkTreeSelection *sel;
739         GtkTreeModel *model;
740         GtkTreeIter iter;
741
742         g_return_val_if_fail (MODEST_IS_ACCOUNT_VIEW (self), NULL);
743         
744         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
745         if (gtk_tree_selection_get_selected (sel, &model, &iter)) {
746                 gtk_tree_model_get (model, &iter, 
747                                     MODEST_ACCOUNT_VIEW_NAME_COLUMN, 
748                                     &account_name, -1);
749         }
750
751         return account_name;
752 }
753
754 gchar *
755 modest_account_view_get_path_account (ModestAccountView *self, GtkTreePath *path)
756 {
757         gchar *account_name = NULL;
758         GtkTreeModel *model;
759         GtkTreeIter iter;
760
761         g_return_val_if_fail (MODEST_IS_ACCOUNT_VIEW (self), NULL);
762
763         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
764         if (gtk_tree_model_get_iter (model, &iter, path)) {
765                 gtk_tree_model_get (model, &iter, 
766                                     MODEST_ACCOUNT_VIEW_NAME_COLUMN, 
767                                     &account_name, -1);
768         }
769
770         return account_name;
771 }
772
773 /* This allows us to pass more than one piece of data to the signal handler,
774  * and get a result: */
775 typedef struct 
776 {
777                 ModestAccountView* self;
778                 const gchar *account_name;
779 } ForEachData;
780
781 static gboolean
782 on_model_foreach_select_account(GtkTreeModel *model, 
783         GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
784 {
785         ForEachData *state = (ForEachData*)(user_data);
786         
787         /* Select the item if it has the matching account name: */
788         gchar *this_account_name = NULL;
789         gtk_tree_model_get (model, iter, 
790                 MODEST_ACCOUNT_VIEW_NAME_COLUMN, &this_account_name, 
791                 -1); 
792         if(this_account_name && state->account_name 
793                 && (strcmp (this_account_name, state->account_name) == 0)) {
794                 
795                 GtkTreeSelection *selection = 
796                         gtk_tree_view_get_selection (GTK_TREE_VIEW (state->self));
797                 gtk_tree_selection_select_iter (selection, iter);
798                 
799                 return TRUE; /* Stop walking the tree. */
800         }
801         
802         return FALSE; /* Keep walking the tree. */
803 }
804
805 static void 
806 modest_account_view_select_account (ModestAccountView *account_view, 
807                                     const gchar* account_name)
808 {       
809 #ifdef MODEST_TOOLKIT_HILDON2
810         return;
811 #endif
812         /* Create a state instance so we can send two items of data to the signal handler: */
813         ForEachData *state = g_new0 (ForEachData, 1);
814         state->self = account_view;
815         state->account_name = account_name;
816         
817         GtkTreeModel *model = gtk_tree_view_get_model (
818                 GTK_TREE_VIEW (account_view));
819         gtk_tree_model_foreach (model, 
820                 on_model_foreach_select_account, state);
821                 
822         g_free (state);
823 }
824
825 #ifndef MODEST_TOOLKIT_HILDON2
826 static void
827 modest_account_view_select_first_account (ModestAccountView *account_view)
828 {
829         GtkTreeIter iter;
830         GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (account_view));
831
832         if (gtk_tree_model_get_iter_first (model, &iter)) {
833                 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (account_view));
834
835                 gtk_tree_selection_select_iter (selection, &iter);
836         }
837 }
838 #endif
839
840 static void
841 on_default_account_changed (ModestAccountMgr *mgr,
842                             gpointer user_data)
843 {
844         GtkTreeIter iter;
845         gchar *default_account_name;
846         GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data));
847
848         if (!gtk_tree_model_get_iter_first(model, &iter))
849                 return;
850
851         default_account_name = modest_account_mgr_get_default_account (mgr);
852
853         do {
854                 gboolean is_default;
855                 gchar *name;
856
857                 gtk_tree_model_get (model, &iter, 
858                                     MODEST_ACCOUNT_VIEW_NAME_COLUMN, &name,
859                                     MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN, &is_default, 
860                                     -1);
861
862                 /* Update the default account column */
863                 if ((default_account_name != NULL) && (!strcmp (name, default_account_name)))
864                         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
865                                             MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN, TRUE, -1);
866                 else
867                         gtk_list_store_set (GTK_LIST_STORE (model), &iter,
868                                             MODEST_ACCOUNT_VIEW_IS_DEFAULT_COLUMN, FALSE, -1);
869
870                 g_free (name);
871
872         } while (gtk_tree_model_iter_next(model, &iter));
873
874         /* Free and force a redraw */
875         g_free (default_account_name);
876         gtk_widget_queue_draw (GTK_WIDGET (user_data));
877 }
878
879 static void 
880 on_display_name_changed (ModestAccountMgr *mgr, 
881                          const gchar *account,
882                          gpointer user_data)
883 {
884         /* Update the view */
885         update_account_view (mgr, MODEST_ACCOUNT_VIEW (user_data));
886 }
887
888 static void 
889 on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata)
890 {
891         if (strcmp ("style", spec->name) == 0) {
892                 gtk_widget_queue_draw (GTK_WIDGET (obj));
893         } 
894 }
895
896 static void
897 update_display_mode (ModestAccountView *self)
898 {
899         ModestAccountViewPrivate *priv;
900         GtkTreeViewColumn *column;
901         GList *renderers;
902         GtkCellRenderer *renderer;
903         
904         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (self));
905         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
906
907         /* Last updated column */
908         column = gtk_tree_view_get_column (GTK_TREE_VIEW (self), 2);
909         gtk_tree_view_column_set_visible (column, !priv->picker_mode);
910
911         /* Name column */
912         column = gtk_tree_view_get_column (GTK_TREE_VIEW (self), 1);
913         renderers = gtk_tree_view_column_get_cell_renderers (column);
914         renderer = (GtkCellRenderer *) renderers->data;
915         g_object_set (renderer, 
916                       "align-set", TRUE,
917                       "alignment", priv->picker_mode?PANGO_ALIGN_CENTER:PANGO_ALIGN_LEFT,
918                       NULL);
919         g_list_free (renderers);
920 }
921
922 void 
923 modest_account_view_set_picker_mode (ModestAccountView *self, gboolean enable)
924 {
925         ModestAccountViewPrivate *priv;
926         
927         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (self));
928         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
929
930         priv->picker_mode = enable;
931         update_display_mode (self);
932 }
933
934 gboolean 
935 modest_account_view_get_picker_mode (ModestAccountView *self)
936 {
937         ModestAccountViewPrivate *priv;
938         
939         g_return_val_if_fail (MODEST_IS_ACCOUNT_VIEW (self), FALSE);
940         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
941
942         return priv->picker_mode;
943 }
944
945 void
946 modest_account_view_set_show_last_update (ModestAccountView *self, 
947                                           gboolean show)
948 {
949         ModestAccountViewPrivate *priv;
950         
951         g_return_if_fail (MODEST_IS_ACCOUNT_VIEW (self));
952         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
953
954         priv->show_last_updated = show;
955         update_account_view (priv->account_mgr, self);
956 }
957
958 gboolean 
959 modest_account_view_get_show_last_updated (ModestAccountView *self)
960 {
961         ModestAccountViewPrivate *priv;
962         
963         g_return_val_if_fail (MODEST_IS_ACCOUNT_VIEW (self), FALSE);
964         priv = MODEST_ACCOUNT_VIEW_GET_PRIVATE(self);
965
966         return priv->show_last_updated;
967 }