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