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