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