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