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