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