738b709e4c2d8a971f340885b8e5af0c10833d31
[modest] / src / maemo / modest-main-window.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 <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
34 #include <tny-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
40 #include <string.h>
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-maemo-utils.h>
57 #include "modest-tny-platform-factory.h"
58 #include "modest-tny-msg.h"
59 #include "modest-mail-operation.h"
60 #include "modest-icon-names.h"
61 #include "modest-progress-bar-widget.h"
62 #include "modest-text-utils.h"
63 #include "modest-ui-dimming-manager.h"
64 #include "maemo/modest-osso-state-saving.h"
65 #include "modest-text-utils.h"
66 #include "modest-signal-mgr.h"
67
68 #ifdef MODEST_HAVE_HILDON0_WIDGETS
69 #include <hildon-widgets/hildon-program.h>
70 #else
71 #include <hildon/hildon-program.h>
72 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
73
74 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
75
76 #define XALIGN 0.5
77 #define YALIGN 0.0
78 #define XSPACE 1
79 #define YSPACE 0
80
81 /* 'private'/'protected' functions */
82 static void modest_main_window_class_init  (ModestMainWindowClass *klass);
83 static void modest_main_window_init        (ModestMainWindow *obj);
84 static void modest_main_window_finalize    (GObject *obj);
85
86 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
87                                                        GdkEventWindowState *event, 
88                                                        gpointer userdata);
89
90 static void connect_signals (ModestMainWindow *self);
91
92 static void modest_main_window_disconnect_signals (ModestWindow *self);
93
94 static void restore_settings (ModestMainWindow *self, 
95                               gboolean do_folder_view_too);
96
97 static void save_state (ModestWindow *self);
98
99 static void update_menus (ModestMainWindow* self);
100
101 static void modest_main_window_show_toolbar   (ModestWindow *window,
102                                                gboolean show_toolbar);
103
104 static void cancel_progressbar (GtkToolButton *toolbutton,
105                                 ModestMainWindow *self);
106
107 static void on_queue_changed   (ModestMailOperationQueue *queue,
108                                 ModestMailOperation *mail_op,
109                                 ModestMailOperationQueueNotification type,
110                                 ModestMainWindow *self);
111
112 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
113
114 static void
115 on_account_inserted (TnyAccountStore *accoust_store,
116                      TnyAccount *account,
117                      gpointer user_data);
118
119 static void
120 on_account_removed (TnyAccountStore *accoust_store,
121                     TnyAccount *account,
122                     gpointer user_data);
123
124 static void on_default_account_changed (ModestAccountMgr* mgr,
125                                         gpointer user_data);
126
127 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
128                                                GdkEventKey *event,
129                                                gpointer user_data);
130
131 static void on_configuration_key_changed      (ModestConf* conf, 
132                                                const gchar *key, 
133                                                ModestConfEvent event,
134                                                ModestConfNotificationId id,
135                                                ModestMainWindow *self);
136
137 static void set_toolbar_mode                  (ModestMainWindow *self, 
138                                                ModestToolBarModes mode);
139
140 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
141
142 static void on_show_account_action_toggled      (GtkToggleAction *action,
143                                                  gpointer user_data);
144
145 static void on_refresh_account_action_activated   (GtkAction *action,
146                                                    gpointer user_data);
147
148 static void on_send_receive_csm_activated         (GtkMenuItem *item,
149                                                    gpointer user_data);
150
151 static void on_msg_count_changed (ModestHeaderView *header_view,
152                                   TnyFolder *folder,
153                                   TnyFolderChange *change,
154                                   ModestMainWindow *main_window);
155
156 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
157
158
159 static GtkWidget * create_empty_view (void);
160
161 static gboolean  on_folder_view_focus_in (GtkWidget *widget,
162                                           GdkEventFocus *event,
163                                           gpointer userdata);
164
165 static gboolean  on_header_view_focus_in (GtkWidget *widget,
166                                           GdkEventFocus *event,
167                                           gpointer userdata);
168
169 static void      modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
170                                                                  TnyFolderStore *folder_store, 
171                                                                  gboolean selected,
172                                                                  ModestMainWindow *main_window);
173                                                 
174 static void set_at_least_one_account_visible(ModestMainWindow *self);
175
176 static void on_updating_msg_list (ModestHeaderView *header_view,
177                                   gboolean starting,
178                                   gpointer user_data);
179
180 static gboolean restore_paned_timeout_handler (gpointer *data);
181
182 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
183 struct _ModestMainWindowPrivate {
184         GtkWidget *msg_paned;
185         GtkWidget *main_paned;
186         GtkWidget *main_vbox;
187         GtkWidget *contents_widget;
188         GtkWidget *empty_view;
189
190         /* Progress observers */
191         GtkWidget   *progress_bar;
192         GSList      *progress_widgets;
193
194         /* Tollbar items */
195         GtkWidget   *progress_toolitem;
196         GtkWidget   *cancel_toolitem;
197         GtkWidget   *sort_toolitem;
198         GtkWidget   *refresh_toolitem;
199         ModestToolBarModes current_toolbar_mode;
200
201         /* Merge ids used to add/remove accounts to the ViewMenu*/
202         GByteArray *merge_ids;
203         GtkActionGroup *view_additions_group;
204
205         /* On-demand widgets */
206         GtkWidget *accounts_popup;
207         GtkWidget *details_widget;
208
209         /* Optimized view enabled */
210         gboolean optimized_view;
211
212         /* Optimized view enabled */
213         gboolean send_receive_in_progress;
214
215         ModestHeaderView *header_view;
216         ModestFolderView *folder_view;
217
218         ModestMainWindowStyle style;
219         ModestMainWindowContentsStyle contents_style;
220
221         guint progress_bar_timeout;
222         guint restore_paned_timeout;
223
224         /* Signal handler UIDs */
225         GList *queue_err_signals;
226         GSList *sighandlers;
227
228         /* "Updating" banner for header view */
229         GtkWidget *updating_banner;
230         guint updating_banner_timeout;
231 };
232 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
233                                                 MODEST_TYPE_MAIN_WINDOW, \
234                                                 ModestMainWindowPrivate))
235
236 typedef struct _GetMsgAsyncHelper {
237         ModestMainWindowPrivate *main_window_private;
238         guint action;
239         ModestTnyMsgReplyType reply_type;
240         ModestTnyMsgForwardType forward_type;
241         gchar *from;
242         TnyIterator *iter;
243 } GetMsgAsyncHelper;
244
245
246 /* globals */
247 static GtkWindowClass *parent_class = NULL;
248
249
250 /* Private actions */
251 /* This is the context sensitive menu: */
252 static const GtkActionEntry modest_folder_view_action_entries [] = {
253
254         /* Folder View CSM actions */
255         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
256         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
257         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL,  G_CALLBACK (modest_ui_actions_on_paste)},
258         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
259         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
260         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
261 };
262
263 static const GtkActionEntry modest_header_view_action_entries [] = {
264
265         /* Header View CSM actions */
266         { "HeaderViewCSMOpen",          NULL,  N_("mcen_me_inbox_open"),        NULL,       NULL, G_CALLBACK (modest_ui_actions_on_open) },
267         { "HeaderViewCSMReply",         NULL,  N_("mcen_me_inbox_reply"),       NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply) },
268         { "HeaderViewCSMReplyAll",      NULL,  N_("mcen_me_inbox_replytoall"),  NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
269         { "HeaderViewCSMForward",       NULL,  N_("mcen_me_inbox_forward"),     NULL,      NULL, G_CALLBACK (modest_ui_actions_on_forward) },
270         { "HeaderViewCSMCut",           NULL,  N_("mcen_me_inbox_cut"),         "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
271         { "HeaderViewCSMCopy",          NULL,  N_("mcen_me_inbox_copy"),        "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
272         { "HeaderViewCSMPaste",         NULL,  N_("mcen_me_inbox_paste"),       "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
273         { "HeaderViewCSMDelete",        NULL,  N_("mcen_me_inbox_delete"),      NULL,      NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
274         { "HeaderViewCSMCancelSending", NULL,  N_("mcen_me_outbox_cancelsend"), NULL,      NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
275         { "HeaderViewCSMHelp",          NULL,  N_("mcen_me_inbox_help"),        NULL,      NULL, G_CALLBACK (modest_ui_actions_on_help) },
276 };
277
278 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
279         { "ToggleFolders",     MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
280 };
281
282 /************************************************************************/
283
284 GType
285 modest_main_window_get_type (void)
286 {
287         static GType my_type = 0;
288         if (!my_type) {
289                 static const GTypeInfo my_info = {
290                         sizeof(ModestMainWindowClass),
291                         NULL,           /* base init */
292                         NULL,           /* base finalize */
293                         (GClassInitFunc) modest_main_window_class_init,
294                         NULL,           /* class finalize */
295                         NULL,           /* class data */
296                         sizeof(ModestMainWindow),
297                         1,              /* n_preallocs */
298                         (GInstanceInitFunc) modest_main_window_init,
299                         NULL
300                 };
301                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
302                                                   "ModestMainWindow",
303                                                   &my_info, 0);
304         }
305         return my_type;
306 }
307
308 static void
309 modest_main_window_class_init (ModestMainWindowClass *klass)
310 {
311         GObjectClass *gobject_class;
312         gobject_class = (GObjectClass*) klass;
313         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
314
315         parent_class            = g_type_class_peek_parent (klass);
316         gobject_class->finalize = modest_main_window_finalize;
317
318         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
319         
320         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
321         modest_window_class->save_state_func = save_state;
322         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
323         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
324         modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
325 }
326
327 static void
328 modest_main_window_init (ModestMainWindow *obj)
329 {
330         ModestMainWindowPrivate *priv;
331
332         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
333
334         priv->queue_err_signals = NULL;
335         priv->msg_paned    = NULL;
336         priv->main_paned   = NULL;      
337         priv->main_vbox    = NULL;
338         priv->header_view  = NULL;
339         priv->folder_view  = NULL;
340         priv->contents_widget  = NULL;
341         priv->accounts_popup  = NULL;
342         priv->details_widget  = NULL;
343         priv->empty_view  = NULL;
344         priv->progress_widgets  = NULL;
345         priv->progress_bar = NULL;
346         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
347         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
348         priv->contents_style  = -1; /* invalid contents style. We need this to select it for the first time */
349         priv->merge_ids = NULL;
350         priv->optimized_view  = FALSE;
351         priv->send_receive_in_progress  = FALSE;
352         priv->progress_bar_timeout = 0;
353         priv->restore_paned_timeout = 0;
354         priv->sighandlers = NULL;
355         priv->updating_banner = NULL;
356         priv->updating_banner_timeout = 0;
357 }
358
359 static void
360 modest_main_window_finalize (GObject *obj)
361 {
362         ModestMainWindowPrivate *priv;
363
364         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
365
366         /* Sanity check: shouldn't be needed, the window mgr should
367            call this function before */
368         modest_main_window_disconnect_signals (MODEST_WINDOW (obj));
369
370         modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
371
372         g_slist_free (priv->progress_widgets);
373
374         g_byte_array_free (priv->merge_ids, TRUE);
375
376         if (priv->progress_bar_timeout > 0) {
377                 g_source_remove (priv->progress_bar_timeout);
378                 priv->progress_bar_timeout = 0;
379         }
380
381         if (priv->updating_banner_timeout > 0) {
382                 g_source_remove (priv->updating_banner_timeout);
383                 priv->updating_banner_timeout = 0;
384         }
385
386         if (priv->restore_paned_timeout > 0) {
387                 g_source_remove (priv->restore_paned_timeout);
388                 priv->restore_paned_timeout = 0;
389         }
390
391         G_OBJECT_CLASS(parent_class)->finalize (obj);
392 }
393
394 GtkWidget*
395 modest_main_window_get_child_widget (ModestMainWindow *self,
396                                      ModestMainWindowWidgetType widget_type)
397 {
398         ModestMainWindowPrivate *priv;
399         GtkWidget *widget;
400         
401         g_return_val_if_fail (self, NULL);
402         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
403                               NULL);
404         
405         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
406
407         switch (widget_type) {
408         case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
409                 widget = (GtkWidget*)priv->header_view; break;
410         case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
411                 widget = (GtkWidget*)priv->folder_view; break;
412         default:
413                 return NULL;
414         }
415
416         return widget ? GTK_WIDGET(widget) : NULL;
417 }
418
419 static gboolean 
420 restore_paned_timeout_handler (gpointer *data)
421 {
422         ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
423         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
424         ModestConf *conf;
425
426         if (GTK_WIDGET_VISIBLE (main_window)) {
427                 conf = modest_runtime_get_conf ();
428                 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
429                                               MODEST_CONF_MAIN_PANED_KEY);
430         }
431         return FALSE;
432 }
433
434
435 static void
436 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
437 {
438         ModestConf *conf;
439         ModestMainWindowPrivate *priv;
440
441         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
442
443         conf = modest_runtime_get_conf ();
444
445         modest_widget_memory_restore (conf, G_OBJECT(self),
446                                       MODEST_CONF_MAIN_WINDOW_KEY);
447
448         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
449                                       MODEST_CONF_HEADER_VIEW_KEY);
450
451         if (do_folder_view_too)
452                 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
453                                       MODEST_CONF_FOLDER_VIEW_KEY);
454
455         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
456                                       MODEST_CONF_MAIN_PANED_KEY);
457
458         g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
459
460         /* We need to force a redraw here in order to get the right
461            position of the horizontal paned separator */
462         gtk_widget_show (GTK_WIDGET (self));
463 }
464
465
466 static void
467 save_state (ModestWindow *window)
468 {
469         ModestConf *conf;
470         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
471         ModestMainWindowPrivate *priv;
472                 
473         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
474         conf = modest_runtime_get_conf ();
475         
476         modest_widget_memory_save (conf,G_OBJECT(self), 
477                                    MODEST_CONF_MAIN_WINDOW_KEY);
478         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
479                                    MODEST_CONF_MAIN_PANED_KEY);
480         //      modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
481         //                         MODEST_CONF_HEADER_VIEW_KEY);
482         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
483                                    MODEST_CONF_FOLDER_VIEW_KEY);
484 }
485
486 static gint
487 compare_display_names (ModestAccountData *a,
488                        ModestAccountData *b)
489 {
490         return strcmp (a->display_name, b->display_name);
491 }
492
493 static void
494 update_menus (ModestMainWindow* self)
495 {       
496         GSList *account_names, *iter, *accounts;
497         ModestMainWindowPrivate *priv;
498         ModestWindowPrivate *parent_priv;
499         ModestAccountMgr *mgr;
500         gint i, num_accounts;
501         GList *groups;
502         gchar *default_account;
503         GtkWidget *send_receive_button, *item;
504         GtkAction *send_receive_all = NULL;
505         GSList *radio_group;
506
507         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
508         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
509
510         /* Get enabled account IDs */
511         mgr = modest_runtime_get_account_mgr ();
512         account_names = modest_account_mgr_account_names (mgr, TRUE);
513         iter = account_names;
514         accounts = NULL;
515
516         while (iter) {
517                 ModestAccountData *account_data = 
518                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
519                 accounts = g_slist_prepend (accounts, account_data);
520
521                 iter = iter->next;
522         }
523         modest_account_mgr_free_account_names (account_names);
524         account_names = NULL;
525
526         /* Order the list of accounts by its display name */
527         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
528         num_accounts = g_slist_length (accounts);
529
530         send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
531                                                       "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
532         gtk_action_set_visible (send_receive_all, num_accounts > 1);
533
534         /* Delete old send&receive popup items. We can not just do a
535            menu_detach because it does not work well with
536            tap_and_hold */
537         if (priv->accounts_popup)
538                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
539                                        (GtkCallback) gtk_widget_destroy, NULL);
540
541         /* Delete old entries in the View menu. Do not free groups, it
542            belongs to Gtk+ */
543         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
544         while (groups) {
545                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
546                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
547                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
548                                                             GTK_ACTION_GROUP (groups->data));
549                         groups = NULL;
550                         /* Remove uis */
551                         if (priv->merge_ids) {
552                                 for (i = 0; i < priv->merge_ids->len; i++)
553                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
554                                 g_byte_array_free (priv->merge_ids, TRUE);
555                         }
556                         /* We need to call this in order to ensure
557                            that the new actions are added in the right
558                            order (alphabetical) */
559                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
560                 } else 
561                         groups = g_list_next (groups);
562         }
563         priv->merge_ids = g_byte_array_sized_new (num_accounts);
564
565         /* Get send receive button */
566         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
567                                                           "/ToolBar/ToolbarSendReceive");
568
569         /* Create the menu */
570         if (num_accounts > 1) {
571                 if (!priv->accounts_popup)
572                         priv->accounts_popup = gtk_menu_new ();
573                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
574                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
575                 g_signal_connect (G_OBJECT (item), 
576                                   "activate", 
577                                   G_CALLBACK (on_send_receive_csm_activated),
578                                   NULL);
579                 item = gtk_separator_menu_item_new ();
580                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
581         }
582
583         /* Create a new action group */
584         default_account = modest_account_mgr_get_default_account (mgr);
585         priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
586         radio_group = NULL;
587         for (i = 0; i < num_accounts; i++) {
588                 gchar *display_name = NULL;     
589                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
590
591                 if (default_account && account_data->account_name && 
592                         !(strcmp (default_account, account_data->account_name) == 0)) {
593                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
594                                                         account_data->display_name);
595                 }
596                 else {
597                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
598                                                         account_data->display_name);
599                 }
600
601                 /* Create action and add it to the action group. The
602                    action name must be the account name, this way we
603                    could know in the handlers the account to show */
604                 if(account_data && account_data->account_name) {
605                         gchar* item_name, *refresh_action_name;
606                         guint8 merge_id = 0;
607                         GtkAction *view_account_action, *refresh_account_action;
608
609                         view_account_action = GTK_ACTION (gtk_radio_action_new (account_data->account_name,
610                                                                                 display_name, NULL, NULL, 0));
611                         gtk_action_group_add_action (priv->view_additions_group, view_account_action);
612                         gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
613                         radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
614
615                         if (default_account && account_data->account_name && 
616                             (strcmp (default_account, account_data->account_name) == 0)) {
617                                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
618                         }
619
620                         /* Add ui from account data. We allow 2^9-1 account
621                            changes in a single execution because we're
622                            downcasting the guint to a guint8 in order to use a
623                            GByteArray. It should be enough. */
624                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
625                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
626                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
627                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
628                                                merge_id,
629                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
630                                                item_name,
631                                                account_data->account_name,
632                                                GTK_UI_MANAGER_MENUITEM,
633                                                FALSE);
634
635                         /* Connect the action signal "activate" */
636                         g_signal_connect_after (G_OBJECT (view_account_action),
637                                                 "toggled",
638                                                 G_CALLBACK (on_show_account_action_toggled),
639                                                 self);
640
641                         /* Create the items for the Tools->Send&Receive submenu */
642                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
643                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
644                                                                  display_name, NULL, NULL);
645                         gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
646
647                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
648                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
649                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
650                                                merge_id,
651                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
652                                                item_name,
653                                                refresh_action_name,
654                                                GTK_UI_MANAGER_MENUITEM,
655                                                FALSE);
656                         g_free (refresh_action_name);
657
658                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
659                                                "activate", 
660                                                G_CALLBACK (on_refresh_account_action_activated), 
661                                                g_strdup (account_data->account_name),
662                                                (GClosureNotify) g_free,
663                                                0);
664
665                         /* Create item and add it to the send&receive
666                            CSM. If there is only one account then
667                            it'll be no menu */
668                         if (priv->accounts_popup) {
669                                 GtkWidget *label = gtk_label_new(NULL);
670                                 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
671                                 if (default_account && (strcmp(account_data->account_name, default_account) == 0))
672                                 {
673                                         gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
674                                         gtk_label_set_markup (GTK_LABEL (label), escaped);
675                                         g_free (escaped);
676                                 }
677                                 else
678                                 {
679                                         gtk_label_set_text (GTK_LABEL (label), display_name);
680                                 }
681
682                                 item = gtk_menu_item_new ();
683                                 gtk_container_add (GTK_CONTAINER (item), label);
684
685                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
686                                 g_signal_connect_data (G_OBJECT (item), 
687                                                        "activate", 
688                                                        G_CALLBACK (on_send_receive_csm_activated),
689                                                        g_strdup (account_data->account_name),
690                                                        (GClosureNotify) g_free,
691                                                        0);
692                         }
693                         g_free (item_name);
694                 }
695
696                 /* Frees */
697                 g_free (display_name);
698         }
699
700         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
701
702         /* We cannot do this in the loop above because this relies on the action
703          * group being inserted. This makes the default account appear in bold.
704          * I agree it is a rather ugly way, but I don't see another possibility. armin. */
705         for (i = 0; i < num_accounts; i++) {
706                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
707
708                 if(account_data->account_name && default_account &&
709                    strcmp (account_data->account_name, default_account) == 0) {
710                         gchar *item_name = g_strconcat (account_data->account_name, "Menu", NULL);
711
712                         gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
713                         GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
714                         g_free(path);
715
716                         if (item) {
717                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
718                                 if (GTK_IS_LABEL (child)) {
719                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
720                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
721                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
722                                         g_free (bold_name);
723                                 }
724                         }
725
726                         path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
727                         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
728                         g_free (path);
729
730                         if (item) {
731                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
732                                 if (GTK_IS_LABEL (child)) {
733                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
734                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
735                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
736                                         g_free (bold_name);
737                                 }
738                         }
739
740                         g_free(item_name);
741                 }
742
743                 modest_account_mgr_free_account_data (mgr, account_data);
744         }
745
746         if (priv->accounts_popup) {
747                 /* Mandatory in order to view the menu contents */
748                 gtk_widget_show_all (priv->accounts_popup);
749
750                 /* Setup tap_and_hold just if was not done before*/
751                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
752                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
753         }
754
755         /* Frees */
756         g_slist_free (accounts);
757         g_free (default_account);
758
759
760         /* Make sure that at least one account is viewed if there are any 
761          * accounts, for instance when adding the first account: */
762         set_at_least_one_account_visible (self);
763 }
764
765 static void
766 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
767 {
768         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
769                 gtk_scrolled_window_add_with_viewport
770                         (GTK_SCROLLED_WINDOW(win), widget);
771         else
772                 gtk_container_add (GTK_CONTAINER(win),
773                                    widget);
774 }
775
776
777 typedef struct {
778         TnySendQueue *queue;
779         guint signal;
780 } QueueErrorSignal;
781
782 static void
783 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
784 {
785         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
786
787         GList *oerrsignals = priv->queue_err_signals;
788         while (oerrsignals) {
789                 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
790                 g_signal_handler_disconnect (esignal->queue, esignal->signal);
791                 g_slice_free (QueueErrorSignal, esignal);
792                 oerrsignals = g_list_next (oerrsignals);
793         }
794         g_list_free (priv->queue_err_signals);
795         priv->queue_err_signals = NULL;
796 }
797
798
799 static void
800 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
801 {
802         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
803
804         /* Update dimmed */     
805         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
806 }
807
808 static void
809 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
810 {
811         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
812
813         /* Update visibility */
814
815         /* Update dimmed */     
816         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
817 }
818
819 static void
820 modest_main_window_disconnect_signals (ModestWindow *self)
821 {       
822         ModestMainWindowPrivate *priv;  
823         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
824
825         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
826         priv->sighandlers = NULL;       
827 }
828
829 static void
830 connect_signals (ModestMainWindow *self)
831 {       
832         ModestWindowPrivate *parent_priv;
833         ModestMainWindowPrivate *priv;
834         GtkWidget *menu;
835         
836         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
837         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
838
839         /* folder view */
840         
841         priv->sighandlers = 
842                 modest_signal_mgr_connect (priv->sighandlers,
843                                            G_OBJECT(priv->folder_view), "key-press-event",
844                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
845         priv->sighandlers = 
846                 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "folder_selection_changed",
847                                            G_CALLBACK (modest_main_window_on_folder_selection_changed), self);
848         priv->sighandlers = 
849                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), "folder-display-name-changed",
850                                            G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), self);
851         priv->sighandlers = 
852                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), "focus-in-event", 
853                                            G_CALLBACK (on_folder_view_focus_in), self);
854
855         /* Folder view CSM */
856         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
857         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
858         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
859                                                        G_CALLBACK(_folder_view_csm_menu_activated),
860                                                        self);
861         /* header view */
862         priv->sighandlers = 
863                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
864                                            G_CALLBACK(modest_ui_actions_on_header_selected), self);
865         priv->sighandlers = 
866                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
867                                            G_CALLBACK(modest_ui_actions_on_header_activated), self);
868         priv->sighandlers = 
869                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
870                                            G_CALLBACK(modest_ui_actions_on_item_not_found), self);
871         priv->sighandlers = 
872                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
873                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
874         priv->sighandlers = 
875                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
876                                            G_CALLBACK(on_msg_count_changed), self);
877         priv->sighandlers = 
878                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
879                                            G_CALLBACK (on_header_view_focus_in), self);
880         priv->sighandlers = 
881                 modest_signal_mgr_connect (priv->sighandlers,
882                                            G_OBJECT (priv->header_view), 
883                                            "updating-msg-list",
884                                            G_CALLBACK (on_updating_msg_list), 
885                                            self);
886         
887         /* Header view CSM */
888         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
889         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
890         priv->sighandlers = 
891                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
892                                            G_CALLBACK(_header_view_csm_menu_activated),
893                                            self);
894         
895         /* window */
896         priv->sighandlers = 
897                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
898                                            G_CALLBACK (modest_main_window_window_state_event),
899                                            NULL);
900
901         /* Mail Operation Queue */
902         priv->sighandlers = 
903                 modest_signal_mgr_connect (priv->sighandlers,
904                                            G_OBJECT (modest_runtime_get_mail_operation_queue ()),
905                                            "queue-changed", 
906                                            G_CALLBACK (on_queue_changed), self);
907         
908         /* Track changes in the device name */
909         priv->sighandlers = 
910                 modest_signal_mgr_connect (priv->sighandlers,
911                                            G_OBJECT(modest_runtime_get_conf ()),
912                                            "key_changed", 
913                                            G_CALLBACK (on_configuration_key_changed), 
914                                            self);
915         
916         /* Track account changes. We need to refresh the toolbar */
917         priv->sighandlers = 
918                 modest_signal_mgr_connect (priv->sighandlers,
919                                            G_OBJECT (modest_runtime_get_account_store ()),
920                                            "account_inserted", 
921                                            G_CALLBACK (on_account_inserted),
922                                            self);
923         priv->sighandlers = 
924                 modest_signal_mgr_connect (priv->sighandlers,
925                                            G_OBJECT (modest_runtime_get_account_store ()),
926                                            "account_removed", 
927                                            G_CALLBACK (on_account_removed),
928                                            self);
929
930         /* We need to refresh the send & receive menu to change the bold
931          * account when the default account changes. */
932         priv->sighandlers = 
933                 modest_signal_mgr_connect (priv->sighandlers,
934                                            G_OBJECT (modest_runtime_get_account_mgr ()),
935                                            "default_account_changed", 
936                                            G_CALLBACK (on_default_account_changed),
937                                            self);
938
939         /* Account store */
940         priv->sighandlers = 
941                 modest_signal_mgr_connect (priv->sighandlers,
942                                            G_OBJECT (modest_runtime_get_account_store()), 
943                                            "password_requested",
944                                            G_CALLBACK (modest_ui_actions_on_password_requested), 
945                                            self);
946 }
947
948 #if 0
949 /** Idle handler, to send/receive at startup .*/
950 gboolean
951 sync_accounts_cb (ModestMainWindow *win)
952 {
953         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
954         return FALSE; /* Do not call this idle handler again. */
955 }
956 #endif
957
958 static void 
959 on_hildon_program_is_topmost_notify(GObject *self,
960                                     GParamSpec *propert_param, gpointer user_data)
961 {
962         HildonProgram *app = HILDON_PROGRAM (self);
963         
964         /*
965         ModestWindow* self = MODEST_WINDOW(user_data);
966         */
967         
968         /* Note that use of hildon_program_set_can_hibernate() 
969          * is generally referred to as "setting the killable flag", 
970          * though hibernation does not seem equal to death.
971          * murrayc */
972                  
973         if (hildon_program_get_is_topmost (app)) {
974                 /* Prevent hibernation when the progam comes to the foreground,
975                  * because hibernation should only happen when the application 
976                  * is in the background: */
977                 hildon_program_set_can_hibernate (app, FALSE);
978         } else {
979                 /* Allow hibernation if the program has gone to the background: */
980                 
981                 /* However, prevent hibernation while the settings are being changed: */
982                 const gboolean hibernation_prevented = 
983                         modest_window_mgr_get_hibernation_is_prevented (
984         modest_runtime_get_window_mgr ()); 
985         
986                 if (hibernation_prevented)
987                         hildon_program_set_can_hibernate (app, FALSE);
988                 else {
989                         /* Allow hibernation, after saving the state: */
990                         modest_osso_save_state();
991                         hildon_program_set_can_hibernate (app, TRUE);
992                 }
993         }
994         
995 }
996
997 static void
998 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
999 {
1000         GtkWidget *folder_win = (GtkWidget *) user_data;
1001         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1002         
1003         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1004         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1005 /*      wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
1006
1007         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1008
1009         /* Connect signals */
1010         connect_signals (MODEST_MAIN_WINDOW (self));
1011
1012         /* Set account store */
1013         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1014                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1015
1016         /* Load previous osso state, for instance if we are being restored from 
1017          * hibernation:  */
1018         modest_osso_load_state ();
1019
1020         /* Restore window & widget settings */  
1021         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1022
1023 /*      /\* The UI spec wants us to show a connection dialog when the application is  */
1024 /*       * started by the user, if there is no connection. */
1025 /*       * Do this before showing the account wizard,  */
1026 /*       * because wizard needs a connection to discover capabilities. *\/ */
1027 /*       modest_platform_connect_and_wait (GTK_WINDOW (self), NULL); */
1028          
1029         /* Check if accounts exist and show the account wizard if not */
1030         gboolean accounts_exist = 
1031                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1032
1033         if (!accounts_exist) {
1034                 /* This is necessary to have the main window shown behind the dialog 
1035                 It's an ugly hack... jschmid */
1036                 gtk_widget_show_all(GTK_WIDGET(self));
1037                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1038         } else {
1039                 GSList *accounts;
1040                 GtkAction *send_receive_all;
1041                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1042                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1043                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1044                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1045                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1046                 modest_account_mgr_free_account_names (accounts);
1047         }
1048 }
1049
1050 ModestWindow *
1051 modest_main_window_new (void)
1052 {
1053         ModestMainWindow *self = NULL;  
1054         ModestMainWindowPrivate *priv = NULL;
1055         ModestWindowPrivate *parent_priv = NULL;
1056         GtkWidget *folder_win = NULL;
1057         ModestDimmingRulesGroup *menu_rules_group = NULL;
1058         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1059         GtkActionGroup *action_group = NULL;
1060         GError *error = NULL;
1061         ModestConf *conf = NULL;
1062         GtkAction *action = NULL;
1063         GdkPixbuf *window_icon;
1064         
1065         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1066         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1067         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1068
1069         parent_priv->ui_manager = gtk_ui_manager_new();
1070         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1071
1072         action_group = gtk_action_group_new ("ModestMainWindowActions");
1073         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1074
1075         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1076         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1077
1078         /* Add common actions */
1079         gtk_action_group_add_actions (action_group,
1080                                       modest_action_entries,
1081                                       G_N_ELEMENTS (modest_action_entries),
1082                                       self);
1083
1084         gtk_action_group_add_actions (action_group,
1085                                       modest_folder_view_action_entries,
1086                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1087                                       self);
1088
1089         gtk_action_group_add_actions (action_group,
1090                                       modest_header_view_action_entries,
1091                                       G_N_ELEMENTS (modest_header_view_action_entries),
1092                                       self);
1093
1094         gtk_action_group_add_toggle_actions (action_group,
1095                                              modest_toggle_action_entries,
1096                                              G_N_ELEMENTS (modest_toggle_action_entries),
1097                                              self);
1098
1099         gtk_action_group_add_toggle_actions (action_group,
1100                                              modest_main_window_toggle_action_entries,
1101                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1102                                              self);
1103
1104         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1105         g_object_unref (action_group);
1106
1107         /* Load the UI definition */
1108         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1109                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1110         if (error != NULL) {
1111                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1112                 g_error_free (error);
1113                 error = NULL;
1114         }
1115
1116         /* Add common dimming rules */
1117         modest_dimming_rules_group_add_rules (menu_rules_group, 
1118                                               modest_main_window_menu_dimming_entries,
1119                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1120                                               MODEST_WINDOW (self));
1121         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1122                                               modest_main_window_toolbar_dimming_entries,
1123                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1124                                               MODEST_WINDOW (self));
1125
1126         /* Insert dimming rules group for this window */
1127         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1128         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1129         g_object_unref (menu_rules_group);
1130         g_object_unref (toolbar_rules_group);
1131         
1132         /* Add accelerators */
1133         gtk_window_add_accel_group (GTK_WINDOW (self), 
1134                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1135
1136         /* Menubar. Update the state of some toggles */
1137         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1138         conf = modest_runtime_get_conf ();
1139         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1140                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1141         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1142                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1143         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1144                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1145         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1146                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1147         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1148         gtk_widget_show (parent_priv->menubar);
1149
1150         /* Get device name */
1151         modest_maemo_utils_get_device_name ();
1152
1153         /* header view */
1154         priv->header_view =
1155                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1156         if (!priv->header_view)
1157                 g_printerr ("modest: cannot instantiate header view\n");
1158         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1159         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1160                                       MODEST_CONF_HEADER_VIEW_KEY);
1161
1162         /* Other style properties of header view */
1163         g_object_set (G_OBJECT (priv->header_view), 
1164                       "rules-hint", FALSE,
1165                       NULL);
1166         /* gtk_widget_show (priv->header_view); */
1167
1168         /* Empty view */ 
1169         priv->empty_view = create_empty_view ();
1170         gtk_widget_show (priv->empty_view);
1171                  
1172         /* Create scrolled windows */
1173         folder_win = gtk_scrolled_window_new (NULL, NULL);
1174         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1175         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1176                                         GTK_POLICY_NEVER,
1177                                         GTK_POLICY_AUTOMATIC);
1178         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1179                                         GTK_POLICY_NEVER,
1180                                         GTK_POLICY_AUTOMATIC);
1181         /* gtk_widget_show (priv->contents_widget); */
1182
1183         /* paned */
1184         priv->main_paned = gtk_hpaned_new ();
1185         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1186         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1187         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1188
1189         /* putting it all together... */
1190         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1191         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1192         gtk_widget_show (priv->main_vbox);
1193         
1194         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1195         
1196         HildonProgram *app = hildon_program_get_instance ();
1197         hildon_program_add_window (app, HILDON_WINDOW (self));
1198         
1199         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1200                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1201
1202         g_signal_connect (G_OBJECT(self), "show",
1203                           G_CALLBACK (modest_main_window_on_show), folder_win);
1204                 
1205         /* Set window icon */
1206         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1207         if (window_icon) {
1208                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1209                 g_object_unref (window_icon);
1210         }
1211
1212         /* Dont't restore settings here, 
1213          * because it requires a gtk_widget_show(), 
1214          * and we don't want to do that until later,
1215          * so that the UI is not visible for non-menu D-Bus activation.
1216          */
1217         /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1218
1219         return MODEST_WINDOW(self);
1220 }
1221
1222 void 
1223 modest_main_window_set_style (ModestMainWindow *self, 
1224                               ModestMainWindowStyle style)
1225 {
1226         ModestMainWindowPrivate *priv;
1227         ModestWindowPrivate *parent_priv;
1228         GtkAction *action;
1229         gboolean active;
1230
1231         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1232
1233         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1234         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1235
1236         /* no change -> nothing to do */
1237         if (priv->style == style)
1238                 return;
1239
1240        /* Get toggle button and update the state if needed. This will
1241           happen only when the set_style is not invoked from the UI,
1242           for example when it's called from widget memory */
1243        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1244        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1245        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1246            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1247                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1248                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1249                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1250        }
1251
1252         priv->style = style;
1253         switch (style) {
1254         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1255                 /* Remove main paned */
1256                 g_object_ref (priv->main_paned);
1257                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1258
1259                 /* Reparent the contents widget to the main vbox */
1260                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1261
1262                 break;
1263         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1264                 /* Remove header view */
1265                 g_object_ref (priv->contents_widget);
1266                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1267
1268                 /* Reparent the main paned */
1269                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1270                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1271
1272                 break;
1273         default:
1274                 g_return_if_reached ();
1275         }
1276
1277         /* Let header view grab the focus if it's being shown */
1278         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1279                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1280         else 
1281                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1282
1283         /* Show changes */
1284         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1285 }
1286
1287 ModestMainWindowStyle
1288 modest_main_window_get_style (ModestMainWindow *self)
1289 {
1290         ModestMainWindowPrivate *priv;
1291
1292         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1293
1294         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1295         return priv->style;
1296 }
1297
1298
1299
1300 static gboolean
1301 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1302 {
1303         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1304                 ModestWindowPrivate *parent_priv;
1305                 ModestWindowMgr *mgr;
1306                 gboolean is_fullscreen;
1307                 GtkAction *fs_toggle_action;
1308                 gboolean active;
1309                 
1310                 mgr = modest_runtime_get_window_mgr ();
1311                 
1312                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1313
1314                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1315                 
1316                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1317                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1318                 if (is_fullscreen != active) {
1319                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1320                 }
1321         }
1322
1323         return FALSE;
1324
1325 }
1326
1327 static void
1328 set_homogeneous (GtkWidget *widget,
1329                  gpointer data)
1330 {
1331         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1332         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1333 }
1334
1335 static void 
1336 modest_main_window_show_toolbar (ModestWindow *self,
1337                                  gboolean show_toolbar)
1338 {
1339         ModestMainWindowPrivate *priv = NULL;
1340         ModestWindowPrivate *parent_priv = NULL;        
1341         GtkWidget *reply_button = NULL, *menu = NULL;
1342         GtkWidget *placeholder = NULL;
1343         gint insert_index;
1344         const gchar *action_name;
1345         GtkAction *action;
1346
1347         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1348         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1349         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1350
1351         /* Set optimized view status */
1352         priv->optimized_view = !show_toolbar;
1353
1354         if (!parent_priv->toolbar) {
1355                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1356                                                                   "/ToolBar");
1357                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1358
1359                 /* Set homogeneous toolbar */
1360                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1361                                        set_homogeneous, NULL);
1362         
1363                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1364                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1365                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1366                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1367                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1368                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1369                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1370                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1371
1372                 /* Add ProgressBar (Transfer toolbar) */ 
1373                 priv->progress_bar = modest_progress_bar_widget_new ();
1374                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1375                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1376                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1377                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1378                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1379                 
1380                 /* Connect cancel 'clicked' signal to abort progress mode */
1381                 g_signal_connect(priv->cancel_toolitem, "clicked",
1382                                  G_CALLBACK(cancel_progressbar),
1383                                  self);
1384                 
1385                 /* Add it to the observers list */
1386                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1387
1388                 /* Add to window */
1389                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1390                                            GTK_TOOLBAR (parent_priv->toolbar));
1391
1392                 /* Set reply button tap and hold menu */
1393                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1394                                                           "/ToolBar/ToolbarMessageReply");
1395                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1396                                                   "/ToolbarReplyCSM");
1397                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1398
1399                 /* Set send & receive button tap and hold menu */
1400                 update_menus (MODEST_MAIN_WINDOW (self));
1401         }
1402         
1403         if (show_toolbar) {
1404                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1405                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1406                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1407
1408                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1409                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1410         } else {
1411                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1412
1413         }
1414
1415         /* Update also the actions (to update the toggles in the
1416            menus), we have to do it manually because some other window
1417            of the same time could have changed it (remember that the
1418            toolbar fullscreen mode is shared by all the windows of the
1419            same type */
1420         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1421                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1422         else
1423                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1424
1425         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1426         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1427                                                             show_toolbar);
1428 }
1429
1430 static void
1431 on_account_inserted (TnyAccountStore *accoust_store,
1432                      TnyAccount *account,
1433                      gpointer user_data)
1434 {
1435         update_menus (MODEST_MAIN_WINDOW (user_data));
1436 }
1437
1438 static void
1439 on_default_account_changed (ModestAccountMgr* mgr,
1440                             gpointer user_data)
1441 {
1442         update_menus (MODEST_MAIN_WINDOW (user_data));
1443 }
1444
1445 static void
1446 on_account_removed (TnyAccountStore *accoust_store,
1447                      TnyAccount *account,
1448                      gpointer user_data)
1449 {
1450         update_menus (MODEST_MAIN_WINDOW (user_data));
1451 }
1452
1453 /* 
1454  * This function manages the key events used to navigate between
1455  * header and folder views (when the window is in split view)
1456  *
1457  * FROM         KEY        ACTION
1458  * -------------------------------------------------
1459  * HeaderView   GDK_Left   Move focus to folder view
1460  * FolderView   GDK_Right  Move focus to header view
1461  *
1462  * There is no need to scroll to selected row, the widgets will be the
1463  * responsibles of doing that (probably managing the focus-in event
1464  */
1465 static gboolean 
1466 on_inner_widgets_key_pressed (GtkWidget *widget,
1467                               GdkEventKey *event,
1468                               gpointer user_data)
1469 {
1470         ModestMainWindowPrivate *priv;
1471
1472         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1473
1474         /* Do nothing if we're in SIMPLE style */
1475         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1476                 return FALSE;
1477
1478         if (MODEST_IS_HEADER_VIEW (widget)) {
1479                 if (event->keyval == GDK_Left)
1480                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1481                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1482                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1483                         if (selected_headers > 1) {
1484                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1485                                 return TRUE;
1486                         }
1487                 }
1488         } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1489                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1490
1491         return FALSE;
1492 }
1493
1494 static void
1495 set_alignment (GtkWidget *widget,
1496                gpointer data)
1497 {
1498         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1499         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1500 }
1501
1502 static GtkWidget *
1503 create_empty_view (void)
1504 {
1505         GtkLabel *label = NULL;
1506         GtkWidget *align = NULL;
1507
1508         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1509         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1510         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1511         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1512
1513         return GTK_WIDGET(align);
1514 }
1515
1516 /*
1517  * Free the returned string
1518  */
1519 static gchar *
1520 get_gray_color_markup (GtkWidget *styled_widget)
1521 {
1522         gchar *gray_color_markup;
1523
1524         /* Obtain the secondary text color. We need a realized widget, that's why 
1525            we get styled_widget from outside */
1526 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1527         GdkColor color;
1528         gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1529         gray_color_markup = modest_text_utils_get_color_string (&color);
1530 #else
1531         gray_color_markup = g_strdup ("#BBBBBB");
1532 #endif  
1533         return gray_color_markup;
1534 }
1535
1536 /*
1537  * Free the returned string
1538  */
1539 static gchar*
1540 create_device_name_visual_string (const gchar *device_name,
1541                                   const gchar *gray_color_markup)
1542 {
1543         gchar *tmp, *label;
1544
1545         /* We have to use "" to fill the %s of the translation. We can
1546            not just use the device name because the device name is
1547            shown in a different color, so it could not be included
1548            into the <span> tag */
1549         tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1550         label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s", 
1551                                          gray_color_markup, 
1552                                          tmp, 
1553                                          device_name);
1554         g_free (tmp);
1555
1556         return label;
1557 }
1558
1559 static GtkWidget *
1560 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1561 {
1562         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1563         
1564         GtkWidget *vbox;
1565         GtkWidget *label_w;
1566         gchar *label;
1567         gchar *gray_color_markup;
1568
1569         vbox = gtk_vbox_new (FALSE, 0);
1570
1571         gray_color_markup = get_gray_color_markup (styled_widget);
1572
1573         /* Account description: */
1574         if (modest_tny_account_is_virtual_local_folders (account)
1575                 || (modest_tny_account_is_memory_card_account (account))) {
1576         
1577                 /* Get device name */
1578                 gchar *device_name = NULL;
1579                 if (modest_tny_account_is_virtual_local_folders (account))
1580                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1581                                                       MODEST_CONF_DEVICE_NAME, NULL);
1582                 else
1583                         device_name = g_strdup (tny_account_get_name (account));
1584
1585                 label = create_device_name_visual_string ((const gchar *) device_name, 
1586                                                           (const gchar *) gray_color_markup);
1587                 label_w = gtk_label_new (NULL);
1588                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1589                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1590                 g_free (device_name);
1591                 g_free (label);
1592         } else {
1593                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1594                         gtk_box_pack_start (GTK_BOX (vbox), 
1595                                 gtk_label_new (tny_account_get_name (account)), 
1596                                 FALSE, FALSE, 0);
1597                 } else {
1598                         /* Other accounts, such as IMAP and POP: */
1599                         
1600                         GString *proto;
1601                         gchar *tmp;
1602         
1603                         /* Put proto in uppercase */
1604                         proto = g_string_new (tny_account_get_proto (account));
1605                         proto = g_string_ascii_up (proto);
1606                         
1607                         /* note: mcen_fi_localroot_description is something like "%s account"
1608                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1609                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1610                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1611                                                          gray_color_markup, tmp, tny_account_get_name (account));
1612                         g_free (tmp);
1613
1614                         label_w = gtk_label_new (NULL);
1615                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1616                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1617                         g_string_free (proto, TRUE);
1618                         g_free (label);
1619                 }
1620         }
1621
1622         /* Message count */
1623         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1624         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1625                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1626                                          modest_tny_folder_store_get_message_count (folder_store));
1627         label_w = gtk_label_new (NULL);
1628         gtk_label_set_markup (GTK_LABEL (label_w), label);
1629         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1630         g_free (label);
1631
1632         /* Folder count */
1633         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1634                                          gray_color_markup, 
1635                                          _("mcen_fi_rootfolder_folders"), 
1636                                          modest_tny_folder_store_get_folder_count (folder_store));
1637         label_w = gtk_label_new (NULL);
1638         gtk_label_set_markup (GTK_LABEL (label_w), label);
1639         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1640         g_free (label);
1641
1642         /* Size / Date */
1643         if (modest_tny_account_is_virtual_local_folders (account)
1644                 || modest_tny_account_is_memory_card_account (account)) {
1645
1646                 gchar *size = modest_text_utils_get_display_size (
1647                         modest_tny_folder_store_get_local_size (folder_store));
1648                 
1649                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1650                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1651                                                  size);
1652                 g_free (size);
1653                 
1654                 label_w = gtk_label_new (NULL);
1655                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1656                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1657                 g_free (label);
1658         } else if (TNY_IS_ACCOUNT(folder_store)) {
1659                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1660                 
1661                 time_t last_updated;
1662                 gchar *last_updated_string;
1663                 /* Get last updated from configuration */
1664                 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (), 
1665                                                                     tny_account_get_id (account));
1666
1667                 if (last_updated > 0) 
1668                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1669                 else
1670                         last_updated_string = g_strdup (_("mcen_va_never"));
1671
1672                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1673                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1674                 label_w = gtk_label_new (NULL);
1675                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1676                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1677                 g_free (last_updated_string);
1678                 g_free (label);
1679         }
1680
1681         g_free (gray_color_markup);
1682
1683         /* Set alignment */
1684         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1685
1686         return vbox;
1687 }
1688
1689 gboolean
1690 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1691 {
1692         ModestMainWindowPrivate *priv = NULL;
1693         
1694         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1695
1696         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1697
1698         return priv->send_receive_in_progress;
1699 }
1700
1701 void 
1702 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1703 {
1704         GtkAction *action = NULL;
1705         GtkWidget *widget = NULL;
1706         ModestMainWindowPrivate *priv = NULL;
1707                 
1708         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1709         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1710         
1711         priv->send_receive_in_progress  = TRUE;
1712
1713         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1714         gtk_action_set_sensitive (action, FALSE);
1715 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1716 /*      gtk_action_set_sensitive (action, FALSE); */
1717         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1718         gtk_widget_set_sensitive (widget, FALSE);
1719
1720
1721 void 
1722 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1723 {
1724         GtkAction *action = NULL;
1725         GtkWidget *widget = NULL;
1726         ModestMainWindowPrivate *priv = NULL;
1727                 
1728         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1729         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1730
1731         priv->send_receive_in_progress  = FALSE;
1732
1733         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1734         gtk_action_set_sensitive (action, TRUE);
1735 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1736 /*      gtk_action_set_sensitive (action, TRUE); */
1737         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1738         gtk_widget_set_sensitive (widget, TRUE);
1739
1740
1741
1742 static void
1743 on_msg_count_changed (ModestHeaderView *header_view,
1744                       TnyFolder *folder,
1745                       TnyFolderChange *change,
1746                       ModestMainWindow *main_window)
1747 {
1748         gboolean folder_empty = FALSE;
1749         gboolean all_marked_as_deleted = FALSE;
1750         TnyFolderChangeChanged changed; 
1751         ModestMainWindowPrivate *priv;
1752         
1753         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1754         g_return_if_fail (TNY_IS_FOLDER(folder));
1755         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1756         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1757         
1758         changed = tny_folder_change_get_changed (change);
1759         
1760         /* If something changes */
1761         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1762                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1763         else
1764                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1765         
1766 /*      Check header removed  (hide marked as DELETED headers) */
1767         if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1768                 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1769         }
1770
1771         /* Check if all messages are marked to be deleted */
1772         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1773         folder_empty = folder_empty || all_marked_as_deleted ;
1774         
1775         /* Set contents style of headers view */
1776         if (folder_empty)  {
1777                 modest_main_window_set_contents_style (main_window,
1778                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1779                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1780         }
1781         else {
1782                 modest_main_window_set_contents_style (main_window,
1783                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1784         }       
1785 }
1786
1787
1788 void 
1789 modest_main_window_set_contents_style (ModestMainWindow *self, 
1790                                        ModestMainWindowContentsStyle style)
1791 {
1792         ModestMainWindowPrivate *priv;
1793
1794         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1795
1796         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1797
1798         /* We allow to set the same content style than the previously
1799            set if there are details, because it could happen when we're
1800            selecting different accounts consecutively */
1801         if ((priv->contents_style == style) &&
1802             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1803                 return;
1804
1805         /* Remove previous child. Delete it if it was an account
1806            details widget */
1807         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1808         if (content) {
1809                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1810                         g_object_ref (content);
1811                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1812                         g_object_ref (priv->empty_view);
1813                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1814                 }
1815                 
1816                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1817         }
1818
1819         priv->contents_style = style;
1820
1821         switch (priv->contents_style) {
1822         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1823                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1824                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1825                                                       TRUE);
1826                 break;
1827         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1828         {
1829                 /* if we're started without main win, there may not be a folder
1830                  * view. this fixes a GLib-Critical */
1831                 if (priv->folder_view) {
1832                         TnyFolderStore *selected_folderstore = 
1833                                 modest_folder_view_get_selected (priv->folder_view);
1834                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1835                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1836                                                                 TNY_ACCOUNT (selected_folderstore));
1837                                 
1838                                 wrap_in_scrolled_window (priv->contents_widget, 
1839                                                          priv->details_widget);
1840                         }
1841                         g_object_unref (selected_folderstore);
1842                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1843                                                               FALSE);
1844                 }
1845                 break;
1846         }
1847         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1848                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1849                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1850                                                       FALSE);
1851                 break;
1852         default:
1853                 g_return_if_reached ();
1854         }
1855
1856         /* Show */
1857         gtk_widget_show_all (priv->contents_widget);
1858 }
1859
1860 ModestMainWindowContentsStyle
1861 modest_main_window_get_contents_style (ModestMainWindow *self)
1862 {
1863         ModestMainWindowPrivate *priv;
1864
1865         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1866
1867         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1868         return priv->contents_style;
1869 }
1870
1871
1872 static void 
1873 on_configuration_key_changed (ModestConf* conf, 
1874                               const gchar *key, 
1875                               ModestConfEvent event,
1876                               ModestConfNotificationId id, 
1877                               ModestMainWindow *self)
1878 {
1879         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1880         TnyAccount *account = NULL;
1881
1882         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1883                 return;
1884
1885         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1886                 return;
1887
1888         if (priv->folder_view) 
1889                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1890
1891         if (account && TNY_IS_ACCOUNT (account) &&
1892             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1893                 GList *children;
1894                 GtkLabel *label;
1895                 const gchar *device_name;
1896                 gchar *new_text, *gray_color_markup;
1897                 
1898                 /* Get label */
1899                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1900                 label = GTK_LABEL (children->data);
1901                 
1902                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1903                                                       MODEST_CONF_DEVICE_NAME, NULL);
1904
1905                 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));          
1906                 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1907                 
1908                 gtk_label_set_markup (label, new_text);
1909                 gtk_widget_show (GTK_WIDGET (label));
1910                 
1911                 g_free (gray_color_markup);
1912                 g_free (new_text);
1913                 g_list_free (children);
1914         }
1915         g_object_unref (account);
1916 }
1917
1918 static gboolean
1919 set_toolbar_transfer_mode (ModestMainWindow *self)
1920 {
1921         ModestMainWindowPrivate *priv = NULL;
1922         
1923         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1924
1925         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1926
1927         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1928         
1929         if (priv->progress_bar_timeout > 0) {
1930                 g_source_remove (priv->progress_bar_timeout);
1931                 priv->progress_bar_timeout = 0;
1932         }
1933
1934         return FALSE;
1935 }
1936
1937 static void 
1938 set_toolbar_mode (ModestMainWindow *self, 
1939                   ModestToolBarModes mode)
1940 {
1941         ModestWindowPrivate *parent_priv = NULL;
1942         ModestMainWindowPrivate *priv = NULL;
1943         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1944         
1945         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1946
1947         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1948         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1949
1950         /* In case this was called before the toolbar exists: */
1951         if (!(parent_priv->toolbar))
1952                 return;
1953
1954         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1955         
1956         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1957         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1958         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1959
1960         /* Sets current toolbar mode */
1961         priv->current_toolbar_mode = mode;
1962
1963         /* Checks the dimming rules */
1964         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1965
1966         /* Show and hide toolbar items */
1967         switch (mode) {
1968         case TOOLBAR_MODE_NORMAL:
1969                 if (sort_action)
1970                         gtk_action_set_visible (sort_action, TRUE);
1971                 if (refresh_action)
1972                         gtk_action_set_visible (refresh_action, TRUE);
1973                 if (priv->progress_toolitem) {
1974                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1975                         gtk_widget_hide (priv->progress_toolitem);
1976                 }
1977                 if (priv->progress_bar)
1978                         gtk_widget_hide (priv->progress_bar);
1979                 
1980                 if (cancel_action)
1981                         gtk_action_set_visible (cancel_action, FALSE);
1982
1983                 /* Hide toolbar if optimized view is enabled */
1984                 if (priv->optimized_view)
1985                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1986                 break;
1987         case TOOLBAR_MODE_TRANSFER:
1988                 if (sort_action)
1989                         gtk_action_set_visible (sort_action, FALSE);
1990                 if (refresh_action)
1991                         gtk_action_set_visible (refresh_action, FALSE);
1992                 if (cancel_action)
1993                         gtk_action_set_visible (cancel_action, TRUE);
1994                 if (priv->progress_toolitem) {
1995                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1996                         gtk_widget_show (priv->progress_toolitem);
1997                 }
1998                 if (priv->progress_bar)
1999                         gtk_widget_show (priv->progress_bar);
2000
2001                 /* Show toolbar if it's hiden (optimized view ) */
2002                 if (priv->optimized_view)
2003                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2004                 break;
2005         default:
2006                 g_return_if_reached ();
2007         }
2008 }
2009
2010 gboolean
2011 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2012 {
2013         ModestMainWindowPrivate *priv;
2014
2015         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2016         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2017
2018         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2019 }
2020
2021 static void
2022 cancel_progressbar (GtkToolButton *toolbutton,
2023                     ModestMainWindow *self)
2024 {
2025         GSList *tmp;
2026         ModestMainWindowPrivate *priv;
2027         
2028         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2029
2030         /* Get operation observers and cancel all the operations */
2031         tmp = priv->progress_widgets;
2032         while (tmp) {
2033                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2034                 tmp=g_slist_next(tmp);
2035         }
2036 }
2037
2038 static gboolean
2039 observers_empty (ModestMainWindow *self)
2040 {
2041         GSList *tmp = NULL;
2042         ModestMainWindowPrivate *priv;
2043         gboolean is_empty = TRUE;
2044         guint pending_ops = 0;
2045  
2046         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2047         tmp = priv->progress_widgets;
2048
2049         /* Check all observers */
2050         while (tmp && is_empty)  {
2051                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2052                 is_empty = pending_ops == 0;
2053                 
2054                 tmp = g_slist_next(tmp);
2055         }
2056         
2057         return is_empty;
2058 }
2059
2060
2061 /**
2062  * Gets the toolbar mode needed for each mail operation. It stores in
2063  * @mode_changed if the toolbar mode has changed or not
2064  */
2065 static ModestToolBarModes
2066 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2067                                       ModestMailOperation *mail_op,
2068                                       gboolean *mode_changed)
2069 {
2070         ModestToolBarModes mode;
2071         ModestMainWindowPrivate *priv;
2072
2073         *mode_changed = FALSE;
2074         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2075
2076         /* Get toolbar mode from operation id*/
2077         switch (modest_mail_operation_get_type_operation (mail_op)) {
2078         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2079         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2080                 mode = TOOLBAR_MODE_TRANSFER;
2081                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2082                         *mode_changed = TRUE;
2083                 break;
2084         default:
2085                 mode = TOOLBAR_MODE_NORMAL;             
2086         }
2087         return mode;
2088 }
2089
2090 static void 
2091 on_mail_operation_started (ModestMailOperation *mail_op,
2092                            gpointer user_data)
2093 {
2094         ModestMainWindow *self;
2095         ModestMailOperationTypeOperation op_type;
2096         ModestMainWindowPrivate *priv;
2097         ModestToolBarModes mode;
2098         GSList *tmp;
2099         gboolean mode_changed = FALSE;
2100         TnyAccount *account;
2101
2102         self = MODEST_MAIN_WINDOW (user_data);
2103         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2104
2105         /* Do not show progress for receiving operations if the
2106            account is the local account or the MMC one */
2107         op_type = modest_mail_operation_get_type_operation (mail_op);
2108         account = modest_mail_operation_get_account (mail_op);
2109         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2110                 gboolean is_remote;
2111
2112                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2113                               modest_tny_account_is_memory_card_account (account));
2114                 g_object_unref (account);
2115                 if (!is_remote)
2116                         return;
2117         }
2118                
2119         /* Get toolbar mode from operation id*/
2120         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2121
2122         /* Add operation observers and change toolbar if neccessary*/
2123         tmp = priv->progress_widgets;
2124         if (mode == TOOLBAR_MODE_TRANSFER) {
2125                 if (mode_changed)
2126                         set_toolbar_transfer_mode(self);                    
2127
2128                 while (tmp) {
2129                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2130                                                               mail_op);
2131                         tmp = g_slist_next (tmp);
2132                 }
2133         }
2134 }
2135
2136 static void 
2137 on_mail_operation_finished (ModestMailOperation *mail_op,
2138                             gpointer user_data)
2139 {
2140         ModestToolBarModes mode;
2141         ModestMailOperationTypeOperation op_type;
2142         GSList *tmp = NULL;
2143         ModestMainWindow *self;
2144         gboolean mode_changed;
2145         TnyAccount *account;
2146         ModestMainWindowPrivate *priv;
2147
2148         self = MODEST_MAIN_WINDOW (user_data);
2149         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2150
2151         /* The mail operation was not added to the progress objects if
2152            the account was the local account or the MMC one */
2153         op_type = modest_mail_operation_get_type_operation (mail_op);
2154         account = modest_mail_operation_get_account (mail_op);
2155         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2156                 gboolean is_remote;
2157
2158                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2159                               modest_tny_account_is_memory_card_account (account));
2160                 g_object_unref (account);
2161                 if (!is_remote)
2162                         return;
2163         }
2164
2165         /* Get toolbar mode from operation id*/
2166         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2167
2168         /* Change toolbar mode */
2169         tmp = priv->progress_widgets;
2170         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2171                 while (tmp) {
2172                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2173                                                                  mail_op);
2174                         tmp = g_slist_next (tmp);
2175                 }
2176                 
2177                 /* If no more operations are being observed, NORMAL mode is enabled again */
2178                 if (observers_empty (self)) {
2179                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2180                 }
2181         }
2182 }
2183
2184 static void
2185 on_queue_changed (ModestMailOperationQueue *queue,
2186                   ModestMailOperation *mail_op,
2187                   ModestMailOperationQueueNotification type,
2188                   ModestMainWindow *self)
2189 {
2190         ModestMainWindowPrivate *priv;
2191
2192         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2193
2194         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2195                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2196                                                                G_OBJECT (mail_op),
2197                                                                "operation-started",
2198                                                                G_CALLBACK (on_mail_operation_started),
2199                                                                self);
2200                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2201                                                                G_OBJECT (mail_op),
2202                                                                "operation-finished",
2203                                                                G_CALLBACK (on_mail_operation_finished),
2204                                                                self);
2205         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2206                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2207                                                                   G_OBJECT (mail_op),
2208                                                                   "operation-started");
2209                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2210                                                                   G_OBJECT (mail_op),
2211                                                                   "operation-finished");
2212         }
2213 }
2214
2215 static void
2216 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2217 {
2218         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2219         GtkAction *action;
2220
2221         /* Get account data */
2222         ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2223         ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2224
2225         /* Set the new visible & active account */
2226         if (acc_data && acc_data->store_account) { 
2227                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2228                                                                              acc_data->store_account->account_name);
2229                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2230                 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2231                 if (action != NULL) {
2232                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2233                                 modest_maemo_toggle_action_set_active_block_notify (
2234                                         GTK_TOGGLE_ACTION (action),
2235                                         TRUE);
2236                         }
2237                 }
2238         }
2239         
2240         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2241
2242
2243         /* Free */
2244         if (acc_data)
2245                 modest_account_mgr_free_account_data (mgr, acc_data);
2246 }
2247
2248 /* Make sure that at least one account is "viewed": */
2249 static void
2250 set_at_least_one_account_visible(ModestMainWindow *self)
2251 {
2252         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2253         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2254
2255         if (!(priv->folder_view)) {
2256                 /* It is too early to do this. */
2257                 return; 
2258         }
2259         
2260         const gchar *active_server_account_name = 
2261                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);        
2262         if (!active_server_account_name ||
2263                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2264         {
2265                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2266                 if (first_modest_name) {
2267                         set_account_visible (self, first_modest_name);
2268                         g_free (first_modest_name);
2269                 }
2270         }
2271 }
2272
2273 static void 
2274 on_show_account_action_toggled  (GtkToggleAction *action,
2275                                    gpointer user_data)
2276 {
2277         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2278
2279         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2280         if (gtk_toggle_action_get_active (action))
2281                 set_account_visible (self, acc_name);
2282 }
2283
2284 static void
2285 refresh_account (const gchar *account_name)
2286 {
2287         ModestWindow *win;
2288         
2289         /* win must already exists here, obviously */ 
2290         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2291                                                  FALSE);
2292         if (!win) {
2293                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2294                 return;
2295         }
2296         
2297         /* If account_name == NULL, we must update all (option All) */
2298         if (!account_name)
2299                 modest_ui_actions_do_send_receive_all (win);
2300         else
2301                 modest_ui_actions_do_send_receive (account_name, win);
2302         
2303 }
2304
2305 static void 
2306 on_refresh_account_action_activated  (GtkAction *action,
2307                                       gpointer user_data)
2308 {
2309         refresh_account ((const gchar*) user_data);
2310 }
2311
2312 static void
2313 on_send_receive_csm_activated (GtkMenuItem *item,
2314                                gpointer user_data)
2315 {
2316         refresh_account ((const gchar*) user_data);
2317 }
2318
2319 static gboolean
2320 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2321 {
2322         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2323
2324         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2325         return FALSE;
2326
2327 }
2328
2329 static gboolean
2330 on_folder_view_focus_in (GtkWidget *widget,
2331                          GdkEventFocus *event,
2332                          gpointer userdata)
2333 {
2334         ModestMainWindow *main_window = NULL;
2335         
2336         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2337         main_window = MODEST_MAIN_WINDOW (userdata);
2338         
2339         /* Update toolbar dimming state */
2340         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2341
2342         return FALSE;
2343 }
2344
2345 static gboolean
2346 on_header_view_focus_in (GtkWidget *widget,
2347                          GdkEventFocus *event,
2348                          gpointer userdata)
2349 {
2350         ModestMainWindow *main_window = NULL;
2351         ModestMainWindowPrivate *priv = NULL;
2352
2353         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2354         main_window = MODEST_MAIN_WINDOW (userdata);
2355         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2356
2357         /* Update toolbar dimming state */
2358         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2359
2360         return FALSE;
2361 }
2362
2363 static void 
2364 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2365                                                 TnyFolderStore *folder_store, 
2366                                                 gboolean selected,
2367                                                 ModestMainWindow *main_window)
2368 {
2369         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2370         GtkAction *action = NULL;
2371         gboolean show_reply = TRUE;
2372         gboolean show_forward = TRUE;
2373         gboolean show_cancel_send = FALSE;
2374         gboolean show_clipboard = TRUE;
2375         gboolean show_delete = TRUE;
2376
2377         if (selected) {
2378                 if (TNY_IS_ACCOUNT (folder_store)) {
2379                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2380                 } else if (TNY_IS_FOLDER (folder_store)) {
2381                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2382                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2383                                         TNY_FOLDER (folder_store));
2384                                 switch (folder_type) {
2385                                 case TNY_FOLDER_TYPE_DRAFTS:
2386                                         show_clipboard = show_delete = TRUE;
2387                                         show_reply = show_forward = show_cancel_send = FALSE;
2388                                         break;
2389                                 case TNY_FOLDER_TYPE_SENT:
2390                                         show_forward = show_clipboard = show_delete = TRUE;
2391                                         show_reply = show_cancel_send = FALSE;
2392                                         break;
2393                                 case TNY_FOLDER_TYPE_OUTBOX:
2394                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2395                                         show_reply = show_forward = FALSE;
2396                                         break;
2397                                 case TNY_FOLDER_TYPE_INVALID:
2398                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2399                                         break;
2400                                 default:
2401                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2402                                         show_cancel_send = FALSE;
2403                                 }
2404                         } else {
2405                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2406                                 show_cancel_send = FALSE;
2407                         }
2408                 }
2409         }
2410
2411         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2412         gtk_action_set_visible (action, show_reply);
2413         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2414         gtk_action_set_visible (action, show_reply);
2415         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2416         gtk_action_set_visible (action, show_forward);
2417         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2418         gtk_action_set_visible (action, show_cancel_send);
2419         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2420         gtk_action_set_visible (action, show_delete);
2421
2422         /* We finally call to the ui actions handler, after updating properly
2423          * the header view CSM */
2424         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2425 }
2426
2427 gboolean 
2428 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2429                                                    GtkTreeModel *model,
2430                                                    GtkTreeRowReference *row_reference,
2431                                                    ModestMainWindow *self)
2432 {
2433         ModestMainWindowPrivate *priv = NULL;
2434         GtkTreeModel *header_model = NULL;
2435         GtkTreePath *path = NULL;
2436
2437         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2438         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2439         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2440
2441         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2442         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2443
2444         /* Do nothing if we changed the folder in the main view */
2445         if (header_model != model)
2446                 return FALSE;
2447
2448         /* Select the message in the header view */
2449         path = gtk_tree_row_reference_get_path (row_reference);
2450         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2451                                   path, NULL, FALSE);
2452         gtk_tree_path_free (path);
2453
2454         return TRUE;
2455 }
2456
2457 static gboolean
2458 show_updating_banner (gpointer user_data)
2459 {
2460         ModestMainWindowPrivate *priv = NULL;
2461
2462         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2463
2464         priv->updating_banner = 
2465                 modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2466                                                   _CS ("ckdg_pb_updating"));
2467
2468         /* Remove timeout */
2469         priv->updating_banner_timeout = 0;
2470         return FALSE;
2471 }
2472
2473 /**
2474  * We use this function to show/hide a progress banner showing
2475  * "Updating" while the header view is being filled. We're not showing
2476  * it unless the update takes more than 2 seconds
2477  *
2478  * If starting = TRUE then the refresh is starting, otherwise it means
2479  * that is has just finished
2480  */
2481 static void 
2482 on_updating_msg_list (ModestHeaderView *header_view,
2483                       gboolean starting,
2484                       gpointer user_data)
2485 {
2486         ModestMainWindowPrivate *priv = NULL;
2487
2488         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2489
2490         /* Remove old timeout */
2491         if (priv->updating_banner_timeout > 0) {
2492                 g_source_remove (priv->updating_banner_timeout);
2493                 priv->updating_banner_timeout = 0;
2494         }
2495
2496         /* Create a new timeout */
2497         if (starting) {
2498                 priv->updating_banner_timeout = 
2499                         g_timeout_add (2000, show_updating_banner, user_data);
2500         } else {
2501                 /* Remove the banner if exists */
2502                 if (priv->updating_banner) {
2503                         gtk_widget_destroy (priv->updating_banner);
2504                         priv->updating_banner = NULL;
2505                 }
2506         }
2507 }