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