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