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