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