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