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