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