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