* Optimization, do not emit the folder selection changed signal when there is nothin...
[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), 
872                                            "folder_selection_changed",
873                                            G_CALLBACK (modest_main_window_on_folder_selection_changed), 
874                                            self);
875         priv->sighandlers = 
876                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), 
877                                            "folder-display-name-changed",
878                                            G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), 
879                                            self);
880         priv->sighandlers = 
881                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), 
882                                            "focus-in-event", 
883                                            G_CALLBACK (on_folder_view_focus_in), 
884                                            self);
885
886         /* Folder view CSM */
887         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
888         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
889         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
890                                                        G_CALLBACK(_folder_view_csm_menu_activated),
891                                                        self);
892         /* header view */
893         priv->sighandlers = 
894                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
895                                            G_CALLBACK(modest_ui_actions_on_header_selected), self);
896         priv->sighandlers = 
897                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
898                                            G_CALLBACK(modest_ui_actions_on_header_activated), self);
899         priv->sighandlers = 
900                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
901                                            G_CALLBACK(modest_ui_actions_on_item_not_found), self);
902         priv->sighandlers = 
903                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
904                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
905         priv->sighandlers = 
906                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
907                                            G_CALLBACK(on_msg_count_changed), self);
908         priv->sighandlers = 
909                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
910                                            G_CALLBACK (on_header_view_focus_in), self);
911         priv->sighandlers = 
912                 modest_signal_mgr_connect (priv->sighandlers,
913                                            G_OBJECT (priv->header_view), 
914                                            "updating-msg-list",
915                                            G_CALLBACK (on_updating_msg_list), 
916                                            self);
917         
918         /* Header view CSM */
919         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
920         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
921         priv->sighandlers = 
922                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
923                                            G_CALLBACK(_header_view_csm_menu_activated),
924                                            self);
925         
926         /* window */
927         priv->sighandlers = 
928                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
929                                            G_CALLBACK (modest_main_window_window_state_event),
930                                            NULL);
931
932         /* Mail Operation Queue */
933         priv->sighandlers = 
934                 modest_signal_mgr_connect (priv->sighandlers,
935                                            G_OBJECT (modest_runtime_get_mail_operation_queue ()),
936                                            "queue-changed", 
937                                            G_CALLBACK (on_queue_changed), self);
938         
939         /* Track changes in the device name */
940         priv->sighandlers = 
941                 modest_signal_mgr_connect (priv->sighandlers,
942                                            G_OBJECT(modest_runtime_get_conf ()),
943                                            "key_changed", 
944                                            G_CALLBACK (on_configuration_key_changed), 
945                                            self);
946         
947         /* Track account changes. We need to refresh the toolbar */
948         priv->sighandlers = 
949                 modest_signal_mgr_connect (priv->sighandlers,
950                                            G_OBJECT (modest_runtime_get_account_store ()),
951                                            "account_inserted", 
952                                            G_CALLBACK (on_account_inserted),
953                                            self);
954         priv->sighandlers = 
955                 modest_signal_mgr_connect (priv->sighandlers,
956                                            G_OBJECT (modest_runtime_get_account_store ()),
957                                            "account_removed", 
958                                            G_CALLBACK (on_account_removed),
959                                            self);
960
961         /* We need to refresh the send & receive menu to change the bold
962          * account when the default account changes. */
963         priv->sighandlers = 
964                 modest_signal_mgr_connect (priv->sighandlers,
965                                            G_OBJECT (modest_runtime_get_account_mgr ()),
966                                            "default_account_changed", 
967                                            G_CALLBACK (on_default_account_changed),
968                                            self);
969
970         /* Account store */
971         priv->sighandlers = 
972                 modest_signal_mgr_connect (priv->sighandlers,
973                                            G_OBJECT (modest_runtime_get_account_store()), 
974                                            "password_requested",
975                                            G_CALLBACK (modest_ui_actions_on_password_requested), 
976                                            self);
977 }
978
979 #if 0
980 /** Idle handler, to send/receive at startup .*/
981 gboolean
982 sync_accounts_cb (ModestMainWindow *win)
983 {
984         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
985         return FALSE; /* Do not call this idle handler again. */
986 }
987 #endif
988
989 static void 
990 on_hildon_program_is_topmost_notify(GObject *self,
991                                     GParamSpec *propert_param, gpointer user_data)
992 {
993         HildonProgram *app = HILDON_PROGRAM (self);
994         
995         /*
996         ModestWindow* self = MODEST_WINDOW(user_data);
997         */
998         
999         /* Note that use of hildon_program_set_can_hibernate() 
1000          * is generally referred to as "setting the killable flag", 
1001          * though hibernation does not seem equal to death.
1002          * murrayc */
1003                  
1004         if (hildon_program_get_is_topmost (app)) {
1005                 /* Prevent hibernation when the progam comes to the foreground,
1006                  * because hibernation should only happen when the application 
1007                  * is in the background: */
1008                 hildon_program_set_can_hibernate (app, FALSE);
1009         } else {
1010                 /* Allow hibernation if the program has gone to the background: */
1011                 
1012                 /* However, prevent hibernation while the settings are being changed: */
1013                 const gboolean hibernation_prevented = 
1014                         modest_window_mgr_get_hibernation_is_prevented (
1015         modest_runtime_get_window_mgr ()); 
1016         
1017                 if (hibernation_prevented)
1018                         hildon_program_set_can_hibernate (app, FALSE);
1019                 else {
1020                         /* Allow hibernation, after saving the state: */
1021                         modest_osso_save_state();
1022                         hildon_program_set_can_hibernate (app, TRUE);
1023                 }
1024         }
1025         
1026 }
1027
1028 static void
1029 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1030 {
1031         GtkWidget *folder_win = (GtkWidget *) user_data;
1032         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1033         
1034         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1035         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1036
1037         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1038
1039         /* Connect signals */
1040         connect_signals (MODEST_MAIN_WINDOW (self));
1041
1042         /* Set account store */
1043         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1044                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1045
1046         /* Load previous osso state, for instance if we are being restored from 
1047          * hibernation:  */
1048         modest_osso_load_state ();
1049
1050         /* Restore window & widget settings */  
1051         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1052
1053         /* Check if accounts exist and show the account wizard if not */
1054         gboolean accounts_exist = 
1055                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1056
1057         if (!accounts_exist) {
1058                 /* This is necessary to have the main window shown behind the dialog 
1059                 It's an ugly hack... jschmid */
1060                 gtk_widget_show_all(GTK_WIDGET(self));
1061                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1062         } else {
1063                 GSList *accounts;
1064                 GtkAction *send_receive_all;
1065                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1066                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1067                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1068                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1069                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 1);
1070                 modest_account_mgr_free_account_names (accounts);
1071                 update_menus (MODEST_MAIN_WINDOW (self));
1072         }
1073 }
1074
1075 ModestWindow *
1076 modest_main_window_new (void)
1077 {
1078         ModestMainWindow *self = NULL;  
1079         ModestMainWindowPrivate *priv = NULL;
1080         ModestWindowPrivate *parent_priv = NULL;
1081         GtkWidget *folder_win = NULL;
1082         ModestDimmingRulesGroup *menu_rules_group = NULL;
1083         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1084         GtkActionGroup *action_group = NULL;
1085         GError *error = NULL;
1086         ModestConf *conf = NULL;
1087         GtkAction *action = NULL;
1088         GdkPixbuf *window_icon;
1089         
1090         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1091         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1092         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1093
1094         parent_priv->ui_manager = gtk_ui_manager_new();
1095         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1096
1097         action_group = gtk_action_group_new ("ModestMainWindowActions");
1098         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1099
1100         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1101         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1102
1103         /* Add common actions */
1104         gtk_action_group_add_actions (action_group,
1105                                       modest_action_entries,
1106                                       G_N_ELEMENTS (modest_action_entries),
1107                                       self);
1108
1109         gtk_action_group_add_actions (action_group,
1110                                       modest_folder_view_action_entries,
1111                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1112                                       self);
1113
1114         gtk_action_group_add_actions (action_group,
1115                                       modest_header_view_action_entries,
1116                                       G_N_ELEMENTS (modest_header_view_action_entries),
1117                                       self);
1118
1119         gtk_action_group_add_toggle_actions (action_group,
1120                                              modest_toggle_action_entries,
1121                                              G_N_ELEMENTS (modest_toggle_action_entries),
1122                                              self);
1123
1124         gtk_action_group_add_toggle_actions (action_group,
1125                                              modest_main_window_toggle_action_entries,
1126                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1127                                              self);
1128
1129         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1130         g_object_unref (action_group);
1131
1132         /* Load the UI definition */
1133         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1134                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1135         if (error != NULL) {
1136                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1137                 g_error_free (error);
1138                 error = NULL;
1139         }
1140
1141         /* Add common dimming rules */
1142         modest_dimming_rules_group_add_rules (menu_rules_group, 
1143                                               modest_main_window_menu_dimming_entries,
1144                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1145                                               MODEST_WINDOW (self));
1146         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1147                                               modest_main_window_toolbar_dimming_entries,
1148                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1149                                               MODEST_WINDOW (self));
1150
1151         /* Insert dimming rules group for this window */
1152         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1153         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1154         g_object_unref (menu_rules_group);
1155         g_object_unref (toolbar_rules_group);
1156         
1157         /* Add accelerators */
1158         gtk_window_add_accel_group (GTK_WINDOW (self), 
1159                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1160
1161         /* Menubar. Update the state of some toggles */
1162         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
1163         conf = modest_runtime_get_conf ();
1164         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1165                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1166         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1167                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1168         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1169                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1170         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1171                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1172         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1173         gtk_widget_show (parent_priv->menubar);
1174
1175         /* Get device name */
1176         modest_maemo_utils_get_device_name ();
1177
1178         /* header view */
1179         priv->header_view =
1180                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1181         if (!priv->header_view)
1182                 g_printerr ("modest: cannot instantiate header view\n");
1183         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1184         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1185                                       MODEST_CONF_HEADER_VIEW_KEY);
1186
1187         /* Other style properties of header view */
1188         g_object_set (G_OBJECT (priv->header_view), 
1189                       "rules-hint", FALSE,
1190                       NULL);
1191         /* gtk_widget_show (priv->header_view); */
1192
1193         /* Empty view */ 
1194         priv->empty_view = create_empty_view ();
1195         gtk_widget_show (priv->empty_view);
1196                  
1197         /* Create scrolled windows */
1198         folder_win = gtk_scrolled_window_new (NULL, NULL);
1199         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1200         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1201                                         GTK_POLICY_NEVER,
1202                                         GTK_POLICY_AUTOMATIC);
1203         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1204                                         GTK_POLICY_NEVER,
1205                                         GTK_POLICY_AUTOMATIC);
1206         /* gtk_widget_show (priv->contents_widget); */
1207
1208         /* paned */
1209         priv->main_paned = gtk_hpaned_new ();
1210         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1211         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1212         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1213
1214         /* putting it all together... */
1215         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1216         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1217         gtk_widget_show (priv->main_vbox);
1218         
1219         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1220         
1221         HildonProgram *app = hildon_program_get_instance ();
1222         hildon_program_add_window (app, HILDON_WINDOW (self));
1223         
1224         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1225                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1226
1227         g_signal_connect (G_OBJECT(self), "show",
1228                           G_CALLBACK (modest_main_window_on_show), folder_win);
1229                 
1230         /* Set window icon */
1231         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
1232         if (window_icon) {
1233                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1234                 g_object_unref (window_icon);
1235         }
1236
1237         /* Dont't restore settings here, 
1238          * because it requires a gtk_widget_show(), 
1239          * and we don't want to do that until later,
1240          * so that the UI is not visible for non-menu D-Bus activation.
1241          */
1242         /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1243
1244         return MODEST_WINDOW(self);
1245 }
1246
1247 void 
1248 modest_main_window_set_style (ModestMainWindow *self, 
1249                               ModestMainWindowStyle style)
1250 {
1251         ModestMainWindowPrivate *priv;
1252         ModestWindowPrivate *parent_priv;
1253         GtkAction *action;
1254         gboolean active;
1255
1256         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1257
1258         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1259         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1260
1261         /* no change -> nothing to do */
1262         if (priv->style == style)
1263                 return;
1264
1265        /* Get toggle button and update the state if needed. This will
1266           happen only when the set_style is not invoked from the UI,
1267           for example when it's called from widget memory */
1268        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1269        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1270        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1271            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1272                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1273                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1274                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1275        }
1276
1277         priv->style = style;
1278         switch (style) {
1279         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1280                 /* Remove main paned */
1281                 g_object_ref (priv->main_paned);
1282                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1283
1284                 /* Reparent the contents widget to the main vbox */
1285                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1286
1287                 break;
1288         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1289                 /* Remove header view */
1290                 g_object_ref (priv->contents_widget);
1291                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1292
1293                 /* Reparent the main paned */
1294                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1295                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1296
1297                 break;
1298         default:
1299                 g_return_if_reached ();
1300         }
1301
1302         /* Let header view grab the focus if it's being shown */
1303         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1304                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1305         else 
1306                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1307
1308         /* Show changes */
1309         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1310 }
1311
1312 ModestMainWindowStyle
1313 modest_main_window_get_style (ModestMainWindow *self)
1314 {
1315         ModestMainWindowPrivate *priv;
1316
1317         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1318
1319         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1320         return priv->style;
1321 }
1322
1323
1324
1325 static gboolean
1326 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1327 {
1328         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1329                 ModestWindowPrivate *parent_priv;
1330                 ModestWindowMgr *mgr;
1331                 gboolean is_fullscreen;
1332                 GtkAction *fs_toggle_action;
1333                 gboolean active;
1334                 
1335                 mgr = modest_runtime_get_window_mgr ();
1336                 
1337                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1338
1339                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1340                 
1341                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1342                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1343                 if (is_fullscreen != active) {
1344                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1345                 }
1346         }
1347
1348         return FALSE;
1349
1350 }
1351
1352 static void
1353 set_homogeneous (GtkWidget *widget,
1354                  gpointer data)
1355 {
1356         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1357         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1358 }
1359
1360 static void 
1361 modest_main_window_show_toolbar (ModestWindow *self,
1362                                  gboolean show_toolbar)
1363 {
1364         ModestMainWindowPrivate *priv = NULL;
1365         ModestWindowPrivate *parent_priv = NULL;        
1366         GtkWidget *reply_button = NULL, *menu = NULL;
1367         GtkWidget *placeholder = NULL;
1368         gint insert_index;
1369         const gchar *action_name;
1370         GtkAction *action;
1371
1372         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1373         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1374         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1375
1376         /* Set optimized view status */
1377         priv->optimized_view = !show_toolbar;
1378
1379         if (!parent_priv->toolbar) {
1380                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1381                                                                   "/ToolBar");
1382                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1383
1384                 /* Set homogeneous toolbar */
1385                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1386                                        set_homogeneous, NULL);
1387         
1388                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1389                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1390                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1391                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1392                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1393                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1394                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1395                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1396
1397                 /* Add ProgressBar (Transfer toolbar) */ 
1398                 priv->progress_bar = modest_progress_bar_widget_new ();
1399                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1400                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1401                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1402                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1403                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1404                 
1405                 /* Connect cancel 'clicked' signal to abort progress mode */
1406                 g_signal_connect(priv->cancel_toolitem, "clicked",
1407                                  G_CALLBACK(cancel_progressbar),
1408                                  self);
1409                 
1410                 /* Add it to the observers list */
1411                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1412
1413                 /* Add to window */
1414                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1415                                            GTK_TOOLBAR (parent_priv->toolbar));
1416
1417                 /* Set reply button tap and hold menu */
1418                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1419                                                           "/ToolBar/ToolbarMessageReply");
1420                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1421                                                   "/ToolbarReplyCSM");
1422                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1423
1424                 /* Set send & receive button tap and hold menu */
1425                 update_menus (MODEST_MAIN_WINDOW (self));
1426         }
1427         
1428         if (show_toolbar) {
1429                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1430                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1431                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1432
1433                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1434                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1435         } else {
1436                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1437
1438         }
1439
1440         /* Update also the actions (to update the toggles in the
1441            menus), we have to do it manually because some other window
1442            of the same time could have changed it (remember that the
1443            toolbar fullscreen mode is shared by all the windows of the
1444            same type */
1445         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1446                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1447         else
1448                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1449
1450         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1451         modest_maemo_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1452                                                             show_toolbar);
1453 }
1454
1455 static void
1456 on_account_inserted (TnyAccountStore *accoust_store,
1457                      TnyAccount *account,
1458                      gpointer user_data)
1459 {
1460         update_menus (MODEST_MAIN_WINDOW (user_data));
1461 }
1462
1463 static void
1464 on_default_account_changed (ModestAccountMgr* mgr,
1465                             gpointer user_data)
1466 {
1467         update_menus (MODEST_MAIN_WINDOW (user_data));
1468 }
1469
1470 static void
1471 on_account_removed (TnyAccountStore *accoust_store,
1472                      TnyAccount *account,
1473                      gpointer user_data)
1474 {
1475         update_menus (MODEST_MAIN_WINDOW (user_data));
1476 }
1477
1478 /* 
1479  * This function manages the key events used to navigate between
1480  * header and folder views (when the window is in split view)
1481  *
1482  * FROM         KEY        ACTION
1483  * -------------------------------------------------
1484  * HeaderView   GDK_Left   Move focus to folder view
1485  * FolderView   GDK_Right  Move focus to header view
1486  *
1487  * There is no need to scroll to selected row, the widgets will be the
1488  * responsibles of doing that (probably managing the focus-in event
1489  */
1490 static gboolean 
1491 on_inner_widgets_key_pressed (GtkWidget *widget,
1492                               GdkEventKey *event,
1493                               gpointer user_data)
1494 {
1495         ModestMainWindowPrivate *priv;
1496
1497         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1498
1499         /* Do nothing if we're in SIMPLE style */
1500         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1501                 return FALSE;
1502
1503         if (MODEST_IS_HEADER_VIEW (widget)) {
1504                 if (event->keyval == GDK_Left)
1505                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1506                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1507                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1508                         if (selected_headers > 1) {
1509                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1510                                 return TRUE;
1511                         }
1512                 }
1513         } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1514                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1515
1516         return FALSE;
1517 }
1518
1519 static void
1520 set_alignment (GtkWidget *widget,
1521                gpointer data)
1522 {
1523         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1524         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1525 }
1526
1527 static GtkWidget *
1528 create_empty_view (void)
1529 {
1530         GtkLabel *label = NULL;
1531         GtkWidget *align = NULL;
1532
1533         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1534         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1535         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1536         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1537
1538         return GTK_WIDGET(align);
1539 }
1540
1541 /*
1542  * Free the returned string
1543  */
1544 static gchar *
1545 get_gray_color_markup (GtkWidget *styled_widget)
1546 {
1547         gchar *gray_color_markup = NULL;
1548 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1549         /* Obtain the secondary text color. We need a realized widget, that's why 
1550            we get styled_widget from outside */
1551         GdkColor color;
1552         if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color)) 
1553                 gray_color_markup = modest_text_utils_get_color_string (&color);
1554 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1555         
1556         if (!gray_color_markup) 
1557                 gray_color_markup = g_strdup ("#BBBBBB");
1558
1559         return gray_color_markup;
1560 }
1561
1562 /*
1563  * Free the returned string
1564  */
1565 static gchar*
1566 create_device_name_visual_string (const gchar *device_name,
1567                                   const gchar *gray_color_markup)
1568 {
1569         gchar *tmp, *label;
1570
1571         /* We have to use "" to fill the %s of the translation. We can
1572            not just use the device name because the device name is
1573            shown in a different color, so it could not be included
1574            into the <span> tag */
1575         tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1576         label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s", 
1577                                          gray_color_markup, 
1578                                          tmp, 
1579                                          device_name);
1580         g_free (tmp);
1581
1582         return label;
1583 }
1584
1585 static GtkWidget *
1586 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1587 {
1588         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1589         
1590         GtkWidget *vbox;
1591         GtkWidget *label_w;
1592         gchar *label;
1593         gchar *gray_color_markup;
1594
1595         vbox = gtk_vbox_new (FALSE, 0);
1596
1597         gray_color_markup = get_gray_color_markup (styled_widget);
1598
1599         /* Account description: */
1600         if (modest_tny_account_is_virtual_local_folders (account)
1601                 || (modest_tny_account_is_memory_card_account (account))) {
1602         
1603                 /* Get device name */
1604                 gchar *device_name = NULL;
1605                 if (modest_tny_account_is_virtual_local_folders (account))
1606                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1607                                                       MODEST_CONF_DEVICE_NAME, NULL);
1608                 else
1609                         device_name = g_strdup (tny_account_get_name (account));
1610
1611                 label = create_device_name_visual_string ((const gchar *) device_name, 
1612                                                           (const gchar *) gray_color_markup);
1613                 label_w = gtk_label_new (NULL);
1614                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1615                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1616                 g_free (device_name);
1617                 g_free (label);
1618         } else {
1619                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1620                         gtk_box_pack_start (GTK_BOX (vbox), 
1621                                 gtk_label_new (tny_account_get_name (account)), 
1622                                 FALSE, FALSE, 0);
1623                 } else {
1624                         /* Other accounts, such as IMAP and POP: */
1625                         
1626                         GString *proto;
1627                         gchar *tmp;
1628         
1629                         /* Put proto in uppercase */
1630                         proto = g_string_new (tny_account_get_proto (account));
1631                         proto = g_string_ascii_up (proto);
1632                         
1633                         /* note: mcen_fi_localroot_description is something like "%s account"
1634                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1635                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1636                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1637                                                          gray_color_markup, tmp, tny_account_get_name (account));
1638                         g_free (tmp);
1639
1640                         label_w = gtk_label_new (NULL);
1641                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1642                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1643                         g_string_free (proto, TRUE);
1644                         g_free (label);
1645                 }
1646         }
1647
1648         /* Message count */
1649         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1650         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1651                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1652                                          modest_tny_folder_store_get_message_count (folder_store));
1653         label_w = gtk_label_new (NULL);
1654         gtk_label_set_markup (GTK_LABEL (label_w), label);
1655         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1656         g_free (label);
1657
1658         /* Folder count */
1659         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1660                                          gray_color_markup, 
1661                                          _("mcen_fi_rootfolder_folders"), 
1662                                          modest_tny_folder_store_get_folder_count (folder_store));
1663         label_w = gtk_label_new (NULL);
1664         gtk_label_set_markup (GTK_LABEL (label_w), label);
1665         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1666         g_free (label);
1667
1668         /* Size / Date */
1669         if (modest_tny_account_is_virtual_local_folders (account)
1670                 || modest_tny_account_is_memory_card_account (account)) {
1671
1672                 gchar *size = modest_text_utils_get_display_size (
1673                         modest_tny_folder_store_get_local_size (folder_store));
1674                 
1675                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1676                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1677                                                  size);
1678                 g_free (size);
1679                 
1680                 label_w = gtk_label_new (NULL);
1681                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1682                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1683                 g_free (label);
1684         } else if (TNY_IS_ACCOUNT(folder_store)) {
1685                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1686                 
1687                 time_t last_updated;
1688                 const gchar *last_updated_string;
1689                 /* Get last updated from configuration */
1690                 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (), 
1691                                                                     tny_account_get_id (account));
1692
1693                 if (last_updated > 0) 
1694                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1695                 else
1696                         last_updated_string = g_strdup (_("mcen_va_never"));
1697
1698                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1699                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1700                 label_w = gtk_label_new (NULL);
1701                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1702                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1703                 g_free (label);
1704         }
1705
1706         g_free (gray_color_markup);
1707
1708         /* Set alignment */
1709         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1710
1711         return vbox;
1712 }
1713
1714 gboolean
1715 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1716 {
1717         ModestMainWindowPrivate *priv = NULL;
1718         
1719         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1720
1721         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1722
1723         return priv->send_receive_in_progress;
1724 }
1725
1726 void 
1727 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1728 {
1729         GtkAction *action = NULL;
1730         GtkWidget *widget = NULL;
1731         ModestMainWindowPrivate *priv = NULL;
1732                 
1733         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1734         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1735         
1736         priv->send_receive_in_progress  = TRUE;
1737
1738         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1739         gtk_action_set_sensitive (action, FALSE);
1740 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1741 /*      gtk_action_set_sensitive (action, FALSE); */
1742         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1743         gtk_widget_set_sensitive (widget, FALSE);
1744
1745
1746 void 
1747 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1748 {
1749         GtkAction *action = NULL;
1750         GtkWidget *widget = NULL;
1751         ModestMainWindowPrivate *priv = NULL;
1752                 
1753         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1754         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1755
1756         priv->send_receive_in_progress  = FALSE;
1757
1758         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1759         gtk_action_set_sensitive (action, TRUE);
1760 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1761 /*      gtk_action_set_sensitive (action, TRUE); */
1762         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1763         gtk_widget_set_sensitive (widget, TRUE);
1764
1765
1766
1767 static void
1768 on_msg_count_changed (ModestHeaderView *header_view,
1769                       TnyFolder *folder,
1770                       TnyFolderChange *change,
1771                       ModestMainWindow *main_window)
1772 {
1773         gboolean folder_empty = FALSE;
1774         gboolean all_marked_as_deleted = FALSE;
1775         TnyFolderChangeChanged changed; 
1776         ModestMainWindowPrivate *priv;
1777         
1778         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1779         g_return_if_fail (TNY_IS_FOLDER(folder));
1780         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1781         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1782         
1783         changed = tny_folder_change_get_changed (change);
1784         
1785         /* If something changes */
1786         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1787                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1788         else
1789                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1790         
1791 /*      Check header removed  (hide marked as DELETED headers) */
1792         if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1793                 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1794         }
1795
1796         /* Check if all messages are marked to be deleted */
1797         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1798         folder_empty = folder_empty || all_marked_as_deleted ;
1799         
1800         /* Set contents style of headers view */
1801         if (folder_empty)  {
1802                 modest_main_window_set_contents_style (main_window,
1803                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1804                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1805         }
1806         else {
1807                 modest_main_window_set_contents_style (main_window,
1808                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1809         }       
1810 }
1811
1812
1813 void 
1814 modest_main_window_set_contents_style (ModestMainWindow *self, 
1815                                        ModestMainWindowContentsStyle style)
1816 {
1817         ModestMainWindowPrivate *priv;
1818
1819         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1820
1821         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1822
1823         /* We allow to set the same content style than the previously
1824            set if there are details, because it could happen when we're
1825            selecting different accounts consecutively */
1826         if ((priv->contents_style == style) &&
1827             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1828                 return;
1829
1830         /* Remove previous child. Delete it if it was an account
1831            details widget */
1832         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1833         if (content) {
1834                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1835                         g_object_ref (content);
1836                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1837                         g_object_ref (priv->empty_view);
1838                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1839                 }
1840                 
1841                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1842         }
1843
1844         priv->contents_style = style;
1845
1846         switch (priv->contents_style) {
1847         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1848                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1849                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1850                                                       TRUE);
1851                 break;
1852         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1853         {
1854                 /* if we're started without main win, there may not be a folder
1855                  * view. this fixes a GLib-Critical */
1856                 if (priv->folder_view) {
1857                         TnyFolderStore *selected_folderstore = 
1858                                 modest_folder_view_get_selected (priv->folder_view);
1859                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1860                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1861                                                                 TNY_ACCOUNT (selected_folderstore));
1862                                 
1863                                 wrap_in_scrolled_window (priv->contents_widget, 
1864                                                          priv->details_widget);
1865                         }
1866                         g_object_unref (selected_folderstore);
1867                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1868                                                               FALSE);
1869                 }
1870                 break;
1871         }
1872         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1873                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1874                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1875                                                       FALSE);
1876                 break;
1877         default:
1878                 g_return_if_reached ();
1879         }
1880
1881         /* Show */
1882         gtk_widget_show_all (priv->contents_widget);
1883 }
1884
1885 ModestMainWindowContentsStyle
1886 modest_main_window_get_contents_style (ModestMainWindow *self)
1887 {
1888         ModestMainWindowPrivate *priv;
1889
1890         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1891
1892         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1893         return priv->contents_style;
1894 }
1895
1896
1897 static void 
1898 on_configuration_key_changed (ModestConf* conf, 
1899                               const gchar *key, 
1900                               ModestConfEvent event,
1901                               ModestConfNotificationId id, 
1902                               ModestMainWindow *self)
1903 {
1904         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1905         TnyAccount *account = NULL;
1906
1907         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1908                 return;
1909
1910         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1911                 return;
1912
1913         if (priv->folder_view) 
1914                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1915
1916         if (account && TNY_IS_ACCOUNT (account) &&
1917             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1918                 GList *children;
1919                 GtkLabel *label;
1920                 const gchar *device_name;
1921                 gchar *new_text, *gray_color_markup;
1922                 
1923                 /* Get label */
1924                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1925                 label = GTK_LABEL (children->data);
1926                 
1927                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1928                                                       MODEST_CONF_DEVICE_NAME, NULL);
1929
1930                 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));          
1931                 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1932                 
1933                 gtk_label_set_markup (label, new_text);
1934                 gtk_widget_show (GTK_WIDGET (label));
1935                 
1936                 g_free (gray_color_markup);
1937                 g_free (new_text);
1938                 g_list_free (children);
1939         }
1940         g_object_unref (account);
1941 }
1942
1943 static gboolean
1944 set_toolbar_transfer_mode (ModestMainWindow *self)
1945 {
1946         ModestMainWindowPrivate *priv = NULL;
1947         
1948         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1949
1950         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1951
1952         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1953         
1954         if (priv->progress_bar_timeout > 0) {
1955                 g_source_remove (priv->progress_bar_timeout);
1956                 priv->progress_bar_timeout = 0;
1957         }
1958
1959         return FALSE;
1960 }
1961
1962 static void 
1963 set_toolbar_mode (ModestMainWindow *self, 
1964                   ModestToolBarModes mode)
1965 {
1966         ModestWindowPrivate *parent_priv = NULL;
1967         ModestMainWindowPrivate *priv = NULL;
1968         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1969         
1970         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1971
1972         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1973         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1974
1975         /* In case this was called before the toolbar exists: */
1976         if (!(parent_priv->toolbar))
1977                 return;
1978
1979         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1980         
1981         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1982         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1983         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1984
1985         /* Sets current toolbar mode */
1986         priv->current_toolbar_mode = mode;
1987
1988         /* Checks the dimming rules */
1989         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1990
1991         /* Show and hide toolbar items */
1992         switch (mode) {
1993         case TOOLBAR_MODE_NORMAL:
1994                 if (sort_action)
1995                         gtk_action_set_visible (sort_action, TRUE);
1996                 if (refresh_action)
1997                         gtk_action_set_visible (refresh_action, TRUE);
1998                 if (priv->progress_toolitem) {
1999                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2000                         gtk_widget_hide (priv->progress_toolitem);
2001                 }
2002                 if (priv->progress_bar)
2003                         gtk_widget_hide (priv->progress_bar);
2004                 
2005                 if (cancel_action)
2006                         gtk_action_set_visible (cancel_action, FALSE);
2007
2008                 /* Hide toolbar if optimized view is enabled */
2009                 if (priv->optimized_view)
2010                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2011                 break;
2012         case TOOLBAR_MODE_TRANSFER:
2013                 if (sort_action)
2014                         gtk_action_set_visible (sort_action, FALSE);
2015                 if (refresh_action)
2016                         gtk_action_set_visible (refresh_action, FALSE);
2017                 if (cancel_action)
2018                         gtk_action_set_visible (cancel_action, TRUE);
2019                 if (priv->progress_toolitem) {
2020                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2021                         gtk_widget_show (priv->progress_toolitem);
2022                 }
2023                 if (priv->progress_bar)
2024                         gtk_widget_show (priv->progress_bar);
2025
2026                 /* Show toolbar if it's hiden (optimized view ) */
2027                 if (priv->optimized_view)
2028                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2029                 break;
2030         default:
2031                 g_return_if_reached ();
2032         }
2033 }
2034
2035 gboolean
2036 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2037 {
2038         ModestMainWindowPrivate *priv;
2039
2040         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2041         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2042
2043         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2044 }
2045
2046 static void
2047 cancel_progressbar (GtkToolButton *toolbutton,
2048                     ModestMainWindow *self)
2049 {
2050         GSList *tmp;
2051         ModestMainWindowPrivate *priv;
2052         
2053         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2054
2055         /* Get operation observers and cancel all the operations */
2056         tmp = priv->progress_widgets;
2057         while (tmp) {
2058                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2059                 tmp=g_slist_next(tmp);
2060         }
2061 }
2062
2063 static gboolean
2064 observers_empty (ModestMainWindow *self)
2065 {
2066         GSList *tmp = NULL;
2067         ModestMainWindowPrivate *priv;
2068         gboolean is_empty = TRUE;
2069         guint pending_ops = 0;
2070  
2071         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2072         tmp = priv->progress_widgets;
2073
2074         /* Check all observers */
2075         while (tmp && is_empty)  {
2076                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2077                 is_empty = pending_ops == 0;
2078                 
2079                 tmp = g_slist_next(tmp);
2080         }
2081         
2082         return is_empty;
2083 }
2084
2085
2086 /**
2087  * Gets the toolbar mode needed for each mail operation. It stores in
2088  * @mode_changed if the toolbar mode has changed or not
2089  */
2090 static ModestToolBarModes
2091 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2092                                       ModestMailOperation *mail_op,
2093                                       gboolean *mode_changed)
2094 {
2095         ModestToolBarModes mode;
2096         ModestMainWindowPrivate *priv;
2097
2098         *mode_changed = FALSE;
2099         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2100
2101         /* Get toolbar mode from operation id*/
2102         switch (modest_mail_operation_get_type_operation (mail_op)) {
2103         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2104         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2105                 mode = TOOLBAR_MODE_TRANSFER;
2106                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2107                         *mode_changed = TRUE;
2108                 break;
2109         default:
2110                 mode = TOOLBAR_MODE_NORMAL;             
2111         }
2112         return mode;
2113 }
2114
2115 static void 
2116 on_mail_operation_started (ModestMailOperation *mail_op,
2117                            gpointer user_data)
2118 {
2119         ModestMainWindow *self;
2120         ModestMailOperationTypeOperation op_type;
2121         ModestMainWindowPrivate *priv;
2122         ModestToolBarModes mode;
2123         GSList *tmp;
2124         gboolean mode_changed = FALSE;
2125         TnyAccount *account;
2126
2127         self = MODEST_MAIN_WINDOW (user_data);
2128         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2129
2130         /* Do not show progress for receiving operations if the
2131            account is the local account or the MMC one */
2132         op_type = modest_mail_operation_get_type_operation (mail_op);
2133         account = modest_mail_operation_get_account (mail_op);
2134         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2135                 gboolean is_remote;
2136
2137                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2138                               modest_tny_account_is_memory_card_account (account));
2139                 g_object_unref (account);
2140                 if (!is_remote)
2141                         return;
2142         }
2143                
2144         /* Get toolbar mode from operation id*/
2145         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2146
2147         /* Add operation observers and change toolbar if neccessary*/
2148         tmp = priv->progress_widgets;
2149         if (mode == TOOLBAR_MODE_TRANSFER) {
2150                 if (mode_changed)
2151                         set_toolbar_transfer_mode(self);                    
2152
2153                 while (tmp) {
2154                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2155                                                               mail_op);
2156                         tmp = g_slist_next (tmp);
2157                 }
2158         }
2159 }
2160
2161 static void 
2162 on_mail_operation_finished (ModestMailOperation *mail_op,
2163                             gpointer user_data)
2164 {
2165         ModestToolBarModes mode;
2166         ModestMailOperationTypeOperation op_type;
2167         GSList *tmp = NULL;
2168         ModestMainWindow *self;
2169         gboolean mode_changed;
2170         TnyAccount *account;
2171         ModestMainWindowPrivate *priv;
2172
2173         self = MODEST_MAIN_WINDOW (user_data);
2174         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2175
2176         /* The mail operation was not added to the progress objects if
2177            the account was the local account or the MMC one */
2178         op_type = modest_mail_operation_get_type_operation (mail_op);
2179         account = modest_mail_operation_get_account (mail_op);
2180         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2181                 gboolean is_remote;
2182
2183                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2184                               modest_tny_account_is_memory_card_account (account));
2185                 g_object_unref (account);
2186                 if (!is_remote)
2187                         return;
2188         }
2189
2190         /* Get toolbar mode from operation id*/
2191         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2192
2193         /* Change toolbar mode */
2194         tmp = priv->progress_widgets;
2195         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2196                 while (tmp) {
2197                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2198                                                                  mail_op);
2199                         tmp = g_slist_next (tmp);
2200                 }
2201                 
2202                 /* If no more operations are being observed, NORMAL mode is enabled again */
2203                 if (observers_empty (self)) {
2204                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2205                 }
2206         }
2207 }
2208
2209 static void
2210 on_queue_changed (ModestMailOperationQueue *queue,
2211                   ModestMailOperation *mail_op,
2212                   ModestMailOperationQueueNotification type,
2213                   ModestMainWindow *self)
2214 {
2215         ModestMainWindowPrivate *priv;
2216
2217         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2218
2219         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2220                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2221                                                                G_OBJECT (mail_op),
2222                                                                "operation-started",
2223                                                                G_CALLBACK (on_mail_operation_started),
2224                                                                self);
2225                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2226                                                                G_OBJECT (mail_op),
2227                                                                "operation-finished",
2228                                                                G_CALLBACK (on_mail_operation_finished),
2229                                                                self);
2230         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2231                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2232                                                                   G_OBJECT (mail_op),
2233                                                                   "operation-started");
2234                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2235                                                                   G_OBJECT (mail_op),
2236                                                                   "operation-finished");
2237         }
2238 }
2239
2240 static void
2241 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2242 {
2243         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2244         GtkAction *action;
2245
2246         /* Get account data */
2247         ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2248         ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2249
2250         /* Set the new visible & active account */
2251         if (acc_data && acc_data->store_account) { 
2252                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2253                                                                              acc_data->store_account->account_name);
2254                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2255                 action = gtk_action_group_get_action (priv->view_additions_group, acc_data->account_name);
2256                 if (action != NULL) {
2257                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2258                                 modest_maemo_toggle_action_set_active_block_notify (
2259                                         GTK_TOGGLE_ACTION (action),
2260                                         TRUE);
2261                         }
2262                 }
2263         }
2264         
2265         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2266
2267
2268         /* Free */
2269         if (acc_data)
2270                 modest_account_mgr_free_account_data (mgr, acc_data);
2271 }
2272
2273 /* Make sure that at least one account is "viewed": */
2274 static void
2275 set_at_least_one_account_visible(ModestMainWindow *self)
2276 {
2277         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2278         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2279
2280         if (!(priv->folder_view)) {
2281                 /* It is too early to do this. */
2282                 return; 
2283         }
2284         
2285         const gchar *active_server_account_name = 
2286                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2287         
2288         if (!active_server_account_name ||
2289                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2290         {
2291                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2292                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2293                 if (default_modest_name) {
2294                         set_account_visible (self, default_modest_name);
2295                 } else if (first_modest_name) {
2296                         set_account_visible (self, first_modest_name);
2297                 }
2298                 g_free (first_modest_name);
2299                 g_free (default_modest_name);
2300         }
2301 }
2302
2303 static void 
2304 on_show_account_action_toggled  (GtkToggleAction *action,
2305                                    gpointer user_data)
2306 {
2307         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2308
2309         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2310         if (gtk_toggle_action_get_active (action))
2311                 set_account_visible (self, acc_name);
2312 }
2313
2314 static void
2315 refresh_account (const gchar *account_name)
2316 {
2317         ModestWindow *win;
2318         
2319         /* win must already exists here, obviously */ 
2320         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2321                                                  FALSE);
2322         if (!win) {
2323                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2324                 return;
2325         }
2326         
2327         /* If account_name == NULL, we must update all (option All) */
2328         if (!account_name)
2329                 modest_ui_actions_do_send_receive_all (win);
2330         else
2331                 modest_ui_actions_do_send_receive (account_name, win);
2332         
2333 }
2334
2335 static void 
2336 on_refresh_account_action_activated  (GtkAction *action,
2337                                       gpointer user_data)
2338 {
2339         refresh_account ((const gchar*) user_data);
2340 }
2341
2342 static void
2343 on_send_receive_csm_activated (GtkMenuItem *item,
2344                                gpointer user_data)
2345 {
2346         refresh_account ((const gchar*) user_data);
2347 }
2348
2349 static gboolean
2350 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2351 {
2352         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2353
2354         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2355         return FALSE;
2356
2357 }
2358
2359 static gboolean
2360 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2361 {
2362         ModestMainWindow *main_window = NULL;
2363         
2364         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2365         main_window = MODEST_MAIN_WINDOW (userdata);
2366         
2367         /* Update toolbar dimming state */
2368         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2369
2370         return FALSE;
2371 }
2372
2373 static gboolean
2374 on_header_view_focus_in (GtkWidget *widget,
2375                          GdkEventFocus *event,
2376                          gpointer userdata)
2377 {
2378         ModestMainWindow *main_window = NULL;
2379
2380         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2381
2382         main_window = MODEST_MAIN_WINDOW (userdata);
2383
2384         /* Update toolbar dimming state */
2385         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2386
2387         return FALSE;
2388 }
2389
2390 static void 
2391 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2392                                                 TnyFolderStore *folder_store, 
2393                                                 gboolean selected,
2394                                                 ModestMainWindow *main_window)
2395 {
2396         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2397         GtkAction *action = NULL;
2398         gboolean show_reply = TRUE;
2399         gboolean show_forward = TRUE;
2400         gboolean show_cancel_send = FALSE;
2401         gboolean show_clipboard = TRUE;
2402         gboolean show_delete = TRUE;
2403
2404         if (selected) {
2405                 if (TNY_IS_ACCOUNT (folder_store)) {
2406                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2407                 } else if (TNY_IS_FOLDER (folder_store)) {
2408                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2409                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2410                                         TNY_FOLDER (folder_store));
2411                                 switch (folder_type) {
2412                                 case TNY_FOLDER_TYPE_DRAFTS:
2413                                         show_clipboard = show_delete = TRUE;
2414                                         show_reply = show_forward = show_cancel_send = FALSE;
2415                                         break;
2416                                 case TNY_FOLDER_TYPE_SENT:
2417                                         show_forward = show_clipboard = show_delete = TRUE;
2418                                         show_reply = show_cancel_send = FALSE;
2419                                         break;
2420                                 case TNY_FOLDER_TYPE_OUTBOX:
2421                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2422                                         show_reply = show_forward = FALSE;
2423                                         break;
2424                                 case TNY_FOLDER_TYPE_INVALID:
2425                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2426                                         break;
2427                                 default:
2428                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2429                                         show_cancel_send = FALSE;
2430                                 }
2431                         } else {
2432                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2433                                 show_cancel_send = FALSE;
2434                         }
2435                 }
2436         }
2437
2438         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2439         gtk_action_set_visible (action, show_reply);
2440         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2441         gtk_action_set_visible (action, show_reply);
2442         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2443         gtk_action_set_visible (action, show_forward);
2444         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2445         gtk_action_set_visible (action, show_cancel_send);
2446         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2447         gtk_action_set_visible (action, show_delete);
2448
2449         /* We finally call to the ui actions handler, after updating properly
2450          * the header view CSM */
2451         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2452 }
2453
2454 gboolean 
2455 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2456                                                    GtkTreeModel *model,
2457                                                    GtkTreeRowReference *row_reference,
2458                                                    ModestMainWindow *self)
2459 {
2460         ModestMainWindowPrivate *priv = NULL;
2461         GtkTreeModel *header_model = NULL;
2462         GtkTreePath *path = NULL;
2463
2464         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2465         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2466         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2467
2468         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2469         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2470
2471         /* Do nothing if we changed the folder in the main view */
2472         if (header_model != model)
2473                 return FALSE;
2474
2475         /* Select the message in the header view */
2476         path = gtk_tree_row_reference_get_path (row_reference);
2477         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2478                                   path, NULL, FALSE);
2479         gtk_tree_path_free (path);
2480
2481         return TRUE;
2482 }
2483
2484 static gboolean
2485 show_updating_banner (gpointer user_data)
2486 {
2487         ModestMainWindowPrivate *priv = NULL;
2488
2489         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2490
2491         if (priv->updating_banner == NULL) {
2492
2493                 /* We're outside the main lock */
2494                 gdk_threads_enter ();
2495                 priv->updating_banner = 
2496                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2497                                                           _CS ("ckdg_pb_updating"));
2498                 gdk_threads_leave ();
2499         }
2500
2501         /* Remove timeout */
2502         priv->updating_banner_timeout = 0;
2503         return FALSE;
2504 }
2505
2506 /**
2507  * We use this function to show/hide a progress banner showing
2508  * "Updating" while the header view is being filled. We're not showing
2509  * it unless the update takes more than 2 seconds
2510  *
2511  * If starting = TRUE then the refresh is starting, otherwise it means
2512  * that is has just finished
2513  */
2514 static void 
2515 on_updating_msg_list (ModestHeaderView *header_view,
2516                       gboolean starting,
2517                       gpointer user_data)
2518 {
2519         ModestMainWindowPrivate *priv = NULL;
2520
2521         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2522         
2523         /* Remove old timeout */
2524         if (priv->updating_banner_timeout > 0) {
2525                 g_source_remove (priv->updating_banner_timeout);
2526                 priv->updating_banner_timeout = 0;
2527         }
2528
2529         /* Create a new timeout */
2530         if (starting) {
2531                 priv->updating_banner_timeout = 
2532                         g_timeout_add (2000, show_updating_banner, user_data);
2533         } else {
2534                 /* Remove the banner if exists */
2535                 if (priv->updating_banner) {
2536                         gtk_widget_destroy (priv->updating_banner);
2537                         priv->updating_banner = NULL;
2538                 }
2539         }
2540 }