* Add the MsgView Window dimming rules file.
[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-maemo-conic-device.h>
35 #include "modest-hildon-includes.h"
36 #include "modest-defs.h"
37 #include <string.h>
38
39 #include "widgets/modest-main-window.h"
40 #include "widgets/modest-msg-edit-window.h"
41 #include "widgets/modest-account-view-window.h"
42 #include "modest-runtime.h"
43 #include "modest-account-mgr-helpers.h"
44 #include "modest-platform.h"
45 #include "modest-widget-memory.h"
46 #include "modest-window-priv.h"
47 #include "modest-main-window-ui.h"
48 #include "modest-main-window-ui-dimming.h"
49 #include "modest-account-mgr.h"
50 #include "modest-tny-account.h"
51 #include "modest-conf.h"
52 #include <modest-maemo-utils.h>
53 #include "modest-tny-platform-factory.h"
54 #include "modest-tny-msg.h"
55 #include "modest-mail-operation.h"
56 #include "modest-icon-names.h"
57 #include "modest-progress-bar-widget.h"
58 #include "modest-text-utils.h"
59 #include "modest-ui-dimming-manager.h"
60 #include "maemo/modest-osso-state-saving.h"
61
62 #ifdef MODEST_HILDON_VERSION_0
63 #include <hildon-widgets/hildon-program.h>
64 #else
65 #include <hildon/hildon-program.h>
66 #endif /*MODEST_HILDON_VERSION_0*/
67
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
69
70 /* 'private'/'protected' functions */
71 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
72 static void modest_main_window_init          (ModestMainWindow *obj);
73 static void modest_main_window_finalize      (GObject *obj);
74 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
75                                                            GdkEventWindowState *event, 
76                                                            gpointer userdata);
77
78 static void connect_signals (ModestMainWindow *self);
79
80 static void restore_settings (ModestMainWindow *self);
81 static void save_state (ModestWindow *self);
82
83 static void modest_main_window_show_toolbar   (ModestWindow *window,
84                                                gboolean show_toolbar);
85
86 static void cancel_progressbar (GtkToolButton *toolbutton,
87                                 ModestMainWindow *self);
88
89 static void         on_queue_changed                     (ModestMailOperationQueue *queue,
90                                                           ModestMailOperation *mail_op,
91                                                           ModestMailOperationQueueNotification type,
92                                                           ModestMainWindow *self);
93
94 static void on_account_update                 (TnyAccountStore *account_store, 
95                                                const gchar *account_name,
96                                                gpointer user_data);
97
98 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
99                                                GdkEventKey *event,
100                                                gpointer user_data);
101
102 static void on_configuration_key_changed      (ModestConf* conf, 
103                                                const gchar *key, 
104                                                ModestConfEvent event, 
105                                                ModestMainWindow *self);
106
107 static void set_toolbar_mode                  (ModestMainWindow *self, 
108                                                ModestToolBarModes mode);
109
110 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
111
112 static void on_show_account_action_activated      (GtkAction *action,
113                                                    gpointer user_data);
114
115 static void on_refresh_account_action_activated   (GtkAction *action,
116                                                    gpointer user_data);
117
118 static void on_send_receive_csm_activated         (GtkMenuItem *item,
119                                                    gpointer user_data);
120 /* list my signals */
121 enum {
122         /* MY_SIGNAL_1, */
123         /* MY_SIGNAL_2, */
124         LAST_SIGNAL
125 };
126
127
128 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
129 struct _ModestMainWindowPrivate {
130         GtkWidget *msg_paned;
131         GtkWidget *main_paned;
132         GtkWidget *main_vbox;
133         GtkWidget *contents_widget;
134
135         /* Progress observers */
136         GtkWidget        *progress_bar;
137         GSList           *progress_widgets;
138
139         /* Tollbar items */
140         GtkWidget   *progress_toolitem;
141         GtkWidget   *cancel_toolitem;
142         GtkWidget   *sort_toolitem;
143         GtkWidget   *refresh_toolitem;
144         ModestToolBarModes current_toolbar_mode;
145
146         /* Merge ids used to add/remove accounts to the ViewMenu*/
147         GByteArray *merge_ids;
148
149         /* On-demand widgets */
150         GtkWidget *accounts_popup;
151         GtkWidget *details_widget;
152
153         /* Optimized view enabled */
154         gboolean optimized_view;
155
156         ModestHeaderView *header_view;
157         ModestFolderView *folder_view;
158
159         ModestMainWindowStyle style;
160         ModestMainWindowContentsStyle contents_style;
161
162         guint progress_bar_timeout;
163
164 };
165 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
166                                                 MODEST_TYPE_MAIN_WINDOW, \
167                                                 ModestMainWindowPrivate))
168
169 typedef struct _GetMsgAsyncHelper {
170         ModestMainWindowPrivate *main_window_private;
171         guint action;
172         ModestTnyMsgReplyType reply_type;
173         ModestTnyMsgForwardType forward_type;
174         gchar *from;
175         TnyIterator *iter;
176 } GetMsgAsyncHelper;
177
178
179 /* globals */
180 static GtkWindowClass *parent_class = NULL;
181
182
183 /* Private actions */
184 /* This is the context sensitive menu: */
185 static const GtkActionEntry modest_folder_view_action_entries [] = {
186
187         /* Folder View CSM actions */
188         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
189         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
190         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, NULL },
191         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
192         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, NULL },
193         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, NULL },
194 };
195
196
197 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
198         { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
199 };
200
201 /************************************************************************/
202
203 GType
204 modest_main_window_get_type (void)
205 {
206         static GType my_type = 0;
207         if (!my_type) {
208                 static const GTypeInfo my_info = {
209                         sizeof(ModestMainWindowClass),
210                         NULL,           /* base init */
211                         NULL,           /* base finalize */
212                         (GClassInitFunc) modest_main_window_class_init,
213                         NULL,           /* class finalize */
214                         NULL,           /* class data */
215                         sizeof(ModestMainWindow),
216                         1,              /* n_preallocs */
217                         (GInstanceInitFunc) modest_main_window_init,
218                         NULL
219                 };
220                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
221                                                   "ModestMainWindow",
222                                                   &my_info, 0);
223         }
224         return my_type;
225 }
226
227 static void
228 modest_main_window_class_init (ModestMainWindowClass *klass)
229 {
230         GObjectClass *gobject_class;
231         gobject_class = (GObjectClass*) klass;
232         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
233
234         parent_class            = g_type_class_peek_parent (klass);
235         gobject_class->finalize = modest_main_window_finalize;
236
237         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
238         
239         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
240         modest_window_class->save_state_func = save_state;
241 }
242
243 static void
244 modest_main_window_init (ModestMainWindow *obj)
245 {
246         ModestMainWindowPrivate *priv;
247
248         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
249
250         priv->msg_paned    = NULL;
251         priv->main_paned   = NULL;      
252         priv->main_vbox    = NULL;
253         priv->header_view  = NULL;
254         priv->folder_view  = NULL;
255         priv->contents_widget  = NULL;
256         priv->accounts_popup  = NULL;
257         priv->details_widget  = NULL;
258
259         priv->progress_widgets  = NULL;
260         priv->progress_bar = NULL;
261         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
262
263         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
264         priv->contents_style  = MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS;
265
266         priv->merge_ids = NULL;
267
268         priv->optimized_view  = FALSE;
269         priv->progress_bar_timeout = 0;
270 }
271
272 static void
273 modest_main_window_finalize (GObject *obj)
274 {
275         ModestMainWindowPrivate *priv;
276
277         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
278
279         g_slist_free (priv->progress_widgets);
280
281         g_byte_array_free (priv->merge_ids, TRUE);
282
283         if (priv->progress_bar_timeout > 0) {
284                 g_source_remove (priv->progress_bar_timeout);
285                 priv->progress_bar_timeout = 0;
286         }
287
288         G_OBJECT_CLASS(parent_class)->finalize (obj);
289 }
290
291 GtkWidget*
292 modest_main_window_get_child_widget (ModestMainWindow *self,
293                                      ModestWidgetType widget_type)
294 {
295         ModestMainWindowPrivate *priv;
296         GtkWidget *widget;
297         
298         g_return_val_if_fail (self, NULL);
299         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
300                               NULL);
301         
302         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
303
304         switch (widget_type) {
305         case MODEST_WIDGET_TYPE_HEADER_VIEW:
306                 widget = (GtkWidget*)priv->header_view; break;
307         case MODEST_WIDGET_TYPE_FOLDER_VIEW:
308                 widget = (GtkWidget*)priv->folder_view; break;
309         default:
310                 return NULL;
311         }
312
313         return widget ? GTK_WIDGET(widget) : NULL;
314 }
315
316
317
318 static void
319 restore_settings (ModestMainWindow *self)
320 {
321         ModestConf *conf;
322         ModestMainWindowPrivate *priv;
323
324         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
325
326         conf = modest_runtime_get_conf ();
327         
328         modest_widget_memory_restore (conf, G_OBJECT(self),
329                                       MODEST_CONF_MAIN_WINDOW_KEY);
330         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
331                                       MODEST_CONF_HEADER_VIEW_KEY);
332         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
333                                       MODEST_CONF_MAIN_PANED_KEY);
334         modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
335                                       MODEST_CONF_FOLDER_VIEW_KEY);
336 }
337
338
339 static void
340 save_state (ModestWindow *window)
341 {
342         ModestConf *conf;
343         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
344         ModestMainWindowPrivate *priv;
345                 
346         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
347         conf = modest_runtime_get_conf ();
348         
349         modest_widget_memory_save (conf,G_OBJECT(self), 
350                                    MODEST_CONF_MAIN_WINDOW_KEY);
351         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
352                                    MODEST_CONF_MAIN_PANED_KEY);
353         modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
354                                    MODEST_CONF_HEADER_VIEW_KEY);
355         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
356                                    MODEST_CONF_FOLDER_VIEW_KEY);
357 }
358
359 static void
360 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
361 {
362         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
363                 gtk_scrolled_window_add_with_viewport
364                         (GTK_SCROLLED_WINDOW(win), widget);
365         else
366                 gtk_container_add (GTK_CONTAINER(win),
367                                    widget);
368 }
369
370
371 static gboolean
372 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
373 {
374         modest_window_save_state (MODEST_WINDOW(self));
375         return FALSE;
376 }
377
378
379 static void
380 on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self)
381 {
382         /* When going online, do the equivalent of pressing the send/receive button, 
383          * as per the specification:
384          * (without the check for >0 accounts, though that is not specified): */
385
386         TnyDevice *device = tny_account_store_get_device (store);
387         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
388         printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id);
389         
390         /* Stop the existing send queues: */
391         modest_runtime_remove_all_send_queues ();
392         
393         /* Create the send queues again, using the appropriate transport accounts 
394          * for this new connection.
395          * This could be the first time that they are created if this is the first 
396          * connection. */
397         /* TODO: Does this really destroy the TnySendQueues and their threads
398          * We do not want 2 TnySendQueues to exist with the same underlying 
399          * outbox directory. */
400         GSList *account_names = modest_account_mgr_account_names (
401                 modest_runtime_get_account_mgr(), 
402                 TRUE /* enabled accounts only */);
403         GSList *iter = account_names;
404         while (iter) {
405                 const gchar *account_name = (const gchar*)(iter->data);
406                         if (account_name) {
407                         TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (
408                                 modest_tny_account_store_get_transport_account_for_open_connection
409                                                  (modest_runtime_get_account_store(), account_name));
410                         if (account) {
411                                 printf ("debug: %s:\n  Transport account for %s: %s\n", __FUNCTION__, account_name, 
412                                         tny_account_get_id(TNY_ACCOUNT(account)));
413                                 modest_runtime_get_send_queue (account);
414                         }
415                 }
416                 
417                 iter = g_slist_next (iter);
418         }
419         
420         g_slist_free (account_names);
421         
422         
423         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
424 }
425
426 static void
427 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
428 {
429         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
430
431         /* Update dimmed */     
432         modest_window_check_dimming_rules (MODEST_WINDOW (user_data));  
433 }
434
435
436 static void
437 connect_signals (ModestMainWindow *self)
438 {       
439         ModestWindowPrivate *parent_priv;
440         ModestMainWindowPrivate *priv;
441         GtkWidget *menu;
442         
443         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
444         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
445         
446         /* folder view */
447         g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
448                           G_CALLBACK(on_inner_widgets_key_pressed), self);
449         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
450                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
451         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
452                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
453
454         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
455         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
456         g_signal_connect (G_OBJECT(priv->folder_view), "tap-and-hold",
457                           G_CALLBACK(_folder_view_csm_menu_activated),
458                           self);
459         /* header view */
460 /*      g_signal_connect (G_OBJECT(priv->header_view), "status_update", */
461 /*                        G_CALLBACK(modest_ui_actions_on_header_status_update), self); */
462         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
463                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
464         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
465                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
466         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
467                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
468         g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
469                           G_CALLBACK(on_inner_widgets_key_pressed), self);
470
471         /* window */
472         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
473         g_signal_connect (G_OBJECT (self), "window-state-event",
474                           G_CALLBACK (modest_main_window_window_state_event),
475                           NULL);
476         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
477
478         /* Mail Operation Queue */
479         g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
480                           "queue-changed",
481                           G_CALLBACK (on_queue_changed),
482                           self);
483
484         /* Track changes in the device name */
485         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
486                           "key_changed",
487                           G_CALLBACK (on_configuration_key_changed), 
488                           self);
489
490         /* Track account changes. We need to refresh the toolbar */
491         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
492                           "account_update",
493                           G_CALLBACK (on_account_update),
494                           self);
495
496         /* Account store */
497         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), "password_requested",
498                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
499                           
500         /* Device */
501         g_signal_connect (G_OBJECT(modest_runtime_get_account_store()), "connecting-finished",
502                           G_CALLBACK(on_account_store_connecting_finished), self);
503 }
504
505 #if 0
506 /** Idle handler, to send/receive at startup .*/
507 gboolean
508 sync_accounts_cb (ModestMainWindow *win)
509 {
510         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
511         return FALSE; /* Do not call this idle handler again. */
512 }
513 #endif
514
515 static void on_hildon_program_is_topmost_notify(GObject *self,
516         GParamSpec *propert_param, gpointer user_data)
517 {
518         HildonProgram *app = HILDON_PROGRAM (self);
519         
520         /*
521         ModestWindow* self = MODEST_WINDOW(user_data);
522         */
523         
524         /* Note that use of hildon_program_set_can_hibernate() 
525          * is generally referred to as "setting the killable flag", 
526          * though hibernation does not seem equal to death.
527          * murrayc */
528                  
529         if (hildon_program_get_is_topmost (app)) {
530                 /* Prevent hibernation when the progam comes to the foreground,
531                  * because hibernation should only happen when the application 
532                  * is in the background: */
533                 hildon_program_set_can_hibernate (app, FALSE);
534         } else {
535                 /* Allow hibernation if the program has gone to the background: */
536                 
537                 /* However, prevent hibernation while the settings are being changed: */
538                 const gboolean hibernation_prevented = 
539                         modest_window_mgr_get_hibernation_is_prevented (
540         modest_runtime_get_window_mgr ()); 
541         
542                 if (hibernation_prevented)
543                         hildon_program_set_can_hibernate (app, FALSE);
544                 else {
545                         /* Allow hibernation, after saving the state: */
546                         modest_osso_save_state();
547                         hildon_program_set_can_hibernate (app, TRUE);
548                 }
549         }
550         
551 }
552
553
554
555 ModestWindow*
556 modest_main_window_new (void)
557 {
558         ModestMainWindow *self = NULL;  
559         ModestMainWindowPrivate *priv = NULL;
560         ModestWindowPrivate *parent_priv = NULL;
561         GtkWidget *folder_win = NULL;
562         ModestDimmingRulesGroup *rules_group = NULL;
563         GtkActionGroup *action_group = NULL;
564         GError *error = NULL;
565         TnyFolderStoreQuery *query = NULL;
566         GdkPixbuf *window_icon = NULL; 
567         ModestConf *conf = NULL;
568         GtkAction *action = NULL;
569
570         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
571         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
572         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
573
574         parent_priv->ui_manager = gtk_ui_manager_new();
575         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
576
577         action_group = gtk_action_group_new ("ModestMainWindowActions");
578         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
579
580         rules_group = modest_dimming_rules_group_new ("ModestCommonDimmingRules");
581
582         /* Add common actions */
583         gtk_action_group_add_actions (action_group,
584                                       modest_action_entries,
585                                       G_N_ELEMENTS (modest_action_entries),
586                                       self);
587
588         gtk_action_group_add_actions (action_group,
589                                       modest_folder_view_action_entries,
590                                       G_N_ELEMENTS (modest_folder_view_action_entries),
591                                       self);
592
593         gtk_action_group_add_toggle_actions (action_group,
594                                              modest_toggle_action_entries,
595                                              G_N_ELEMENTS (modest_toggle_action_entries),
596                                              self);
597
598         gtk_action_group_add_toggle_actions (action_group,
599                                              modest_main_window_toggle_action_entries,
600                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
601                                              self);
602
603         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
604         g_object_unref (action_group);
605
606         /* Load the UI definition */
607         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
608                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
609         if (error != NULL) {
610                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
611                 g_error_free (error);
612                 error = NULL;
613         }
614
615         /* Add common dimming rules */
616         modest_dimming_rules_group_add_rules (rules_group, 
617                                               modest_dimming_entries,
618                                               G_N_ELEMENTS (modest_dimming_entries),
619                                               self);
620
621         /* Insert dimming rules group for this window */
622         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, rules_group);                                                     
623         g_object_unref (rules_group);
624         
625         /* Add accelerators */
626         gtk_window_add_accel_group (GTK_WINDOW (self), 
627                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
628
629         /* Menubar. Update the state of some toggles */
630         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
631         conf = modest_runtime_get_conf ();
632         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
633                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
634         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
635                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
636         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
637                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
638         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
639                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
640         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
641
642         /* Get device name */
643         modest_maemo_utils_get_device_name ();
644
645         /* folder view */
646         query = tny_folder_store_query_new ();
647         tny_folder_store_query_add_item (query, NULL,
648                                          TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
649         priv->folder_view = MODEST_FOLDER_VIEW(modest_folder_view_new (query));
650         if (!priv->folder_view)
651                 g_printerr ("modest: cannot instantiate folder view\n");
652         g_object_unref (G_OBJECT (query));
653         modest_folder_view_set_style (priv->folder_view,
654                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
655
656         /* header view */
657         priv->header_view  =
658                 MODEST_HEADER_VIEW(modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
659         if (!priv->header_view)
660                 g_printerr ("modest: cannot instantiate header view\n");
661         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
662         
663         /* Create scrolled windows */
664         folder_win = gtk_scrolled_window_new (NULL, NULL);
665         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
666         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
667                                         GTK_POLICY_NEVER,
668                                         GTK_POLICY_AUTOMATIC);
669         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
670                                         GTK_POLICY_NEVER,
671                                         GTK_POLICY_AUTOMATIC);
672
673         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
674         wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view));
675
676         /* paned */
677         priv->main_paned = gtk_hpaned_new ();
678         gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
679         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->contents_widget);
680         gtk_widget_show (GTK_WIDGET(priv->header_view));
681         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
682
683         /* putting it all together... */
684         priv->main_vbox = gtk_vbox_new (FALSE, 6);
685         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
686
687         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
688         restore_settings (MODEST_MAIN_WINDOW(self));
689
690         /* Set window icon */
691         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
692         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
693         
694         /* Connect signals */
695         connect_signals (self);
696
697         /* Set account store */
698         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
699                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
700
701         /* Do send & receive when we are idle */
702         /* TODO: Enable this again. I have commented it out because, 
703          * at least in scratchbox, this can cause us to start a second 
704          * update (in response to a connection change) when we are already 
705          * doing an update (started here, at startup). Tinymail doesn't like that.
706          * murrayc.
707          */
708         /* g_idle_add ((GSourceFunc)sync_accounts_cb, self); */
709         
710         HildonProgram *app = hildon_program_get_instance ();
711         hildon_program_add_window (app, HILDON_WINDOW (self));
712         
713         /* Register HildonProgram  signal handlers: */
714         /* These are apparently deprecated, according to the 
715          * "HildonApp/HildonAppView to HildonProgram/HildonWindow migration guide",
716          * though the API reference does not mention that:
717          *
718         g_signal_connect (G_OBJECT(app), "topmost_status_lose",
719                 G_CALLBACK (on_hildon_program_save_state), self);
720         g_signal_connect (G_OBJECT(app), "topmost_status_acquire",
721                 G_CALLBACK (on_hildon_program_status_acquire), self);
722     */
723         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
724                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
725                 
726         /* Load previous osso state, for instance if we are being restored from 
727          * hibernation:  */
728         modest_osso_load_state();
729
730         return MODEST_WINDOW(self);
731 }
732
733 gboolean 
734 modest_main_window_close_all (ModestMainWindow *self)
735 {
736         GtkWidget *note;
737         GtkResponseType response;
738
739         /* Create the confirmation dialog MSG-NOT308 */
740         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
741                                                          _("emev_nc_close_windows"),
742                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
743                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
744                                                          NULL);
745
746         response = gtk_dialog_run (GTK_DIALOG (note));
747         gtk_widget_destroy (GTK_WIDGET (note));
748
749         if (response == GTK_RESPONSE_YES)
750                 return TRUE;
751         else
752                 return FALSE;
753 }
754
755
756 void 
757 modest_main_window_set_style (ModestMainWindow *self, 
758                               ModestMainWindowStyle style)
759 {
760         ModestMainWindowPrivate *priv;
761         ModestWindowPrivate *parent_priv;
762         GtkAction *action;
763
764         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
765
766         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
767         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
768
769         /* no change -> nothing to do */
770         if (priv->style == style)
771                 return;
772
773         /* Get toggle button */
774         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
775
776         priv->style = style;
777         switch (style) {
778         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
779                 /* Remove main paned */
780                 g_object_ref (priv->main_paned);
781                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
782
783                 /* Reparent the contents widget to the main vbox */
784                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
785
786                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
787                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
788                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
789
790                 break;
791         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
792                 /* Remove header view */
793                 g_object_ref (priv->contents_widget);
794                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
795
796                 /* Reparent the main paned */
797                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
798                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
799
800                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
801                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
802                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
803
804                 break;
805         default:
806                 g_return_if_reached ();
807         }
808
809         /* Let header view grab the focus if it's being shown */
810         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
811                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
812         else 
813                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
814
815         /* Show changes */
816         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
817 }
818
819 ModestMainWindowStyle
820 modest_main_window_get_style (ModestMainWindow *self)
821 {
822         ModestMainWindowPrivate *priv;
823
824         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
825
826         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
827         return priv->style;
828 }
829
830
831
832 static gboolean
833 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
834 {
835         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
836                 ModestWindowPrivate *parent_priv;
837                 ModestWindowMgr *mgr;
838                 gboolean is_fullscreen;
839                 GtkAction *fs_toggle_action;
840                 gboolean active;
841                 
842                 mgr = modest_runtime_get_window_mgr ();
843                 
844                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
845
846                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
847                 
848                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
849                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
850                 if (is_fullscreen != active) {
851                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
852                 }
853         }
854
855         return FALSE;
856
857 }
858
859 static void
860 set_homogeneous (GtkWidget *widget,
861                  gpointer data)
862 {
863         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
864         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
865 }
866
867 static void 
868 modest_main_window_show_toolbar (ModestWindow *self,
869                                  gboolean show_toolbar)
870 {
871         ModestMainWindowPrivate *priv = NULL;
872         ModestWindowPrivate *parent_priv = NULL;        
873         GtkWidget *reply_button = NULL, *menu = NULL;
874         GtkWidget *placeholder = NULL;
875         gint insert_index;
876
877         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
878         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
879         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
880
881         /* Set optimized view status */
882         priv->optimized_view = !show_toolbar;
883
884         if (!parent_priv->toolbar) {
885                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
886                                                                   "/ToolBar");
887
888                 /* Set homogeneous toolbar */
889                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
890                                        set_homogeneous, NULL);
891         
892                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
893                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
894                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
895                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
896                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
897                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
898                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
899                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
900
901                 /* Add ProgressBar (Transfer toolbar) */ 
902                 priv->progress_bar = modest_progress_bar_widget_new ();
903                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
904                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
905                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
906                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
907                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
908                 
909                 /* Connect cancel 'clicked' signal to abort progress mode */
910                 g_signal_connect(priv->cancel_toolitem, "clicked",
911                                  G_CALLBACK(cancel_progressbar),
912                                  self);
913                 
914                 /* Add it to the observers list */
915                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
916
917                 /* Add to window */
918                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
919                                            GTK_TOOLBAR (parent_priv->toolbar));
920
921                 /* Set reply button tap and hold menu */
922                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
923                                                           "/ToolBar/ToolbarMessageReply");
924                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
925                                                   "/ToolbarReplyCSM");
926                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
927
928                 /* Set send & receive button tap and hold menu */
929                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
930                                    NULL, self);
931         }
932
933         if (show_toolbar) {
934                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
935                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
936                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
937
938                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
939                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
940         } else
941                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
942
943 }
944
945 static gint
946 compare_display_names (ModestAccountData *a,
947                        ModestAccountData *b)
948 {
949         return strcmp (a->display_name, b->display_name);
950 }
951
952 static void 
953 on_account_update (TnyAccountStore *account_store, 
954                    const gchar *account_name,
955                    gpointer user_data)
956 {
957         GSList *account_names, *iter, *accounts;
958         ModestMainWindow *self;
959         ModestMainWindowPrivate *priv;
960         ModestWindowPrivate *parent_priv;
961         ModestAccountMgr *mgr;
962         gint i, num_accounts;                                   
963         GtkActionGroup *action_group;
964         GList *groups;
965         gchar *default_account;
966         GtkWidget *send_receive_button, *item;
967                 
968         self = MODEST_MAIN_WINDOW (user_data);
969         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
970         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
971
972         /* Get enabled account IDs */
973         mgr = modest_runtime_get_account_mgr ();
974         account_names = modest_account_mgr_account_names (mgr, TRUE);
975         iter = account_names;
976         accounts = NULL;
977
978         while (iter) {
979                 ModestAccountData *account_data = 
980                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
981                 accounts = g_slist_prepend (accounts, account_data);
982
983                 iter = iter->next;
984         }
985         g_slist_free (account_names);
986
987         /* Order the list of accounts by its display name */
988         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
989         num_accounts = g_slist_length (accounts);
990
991         /* Delete old send&receive popup items. We can not just do a
992            menu_detach because it does not work well with
993            tap_and_hold */
994         if (priv->accounts_popup)
995                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
996                                        (GtkCallback) gtk_widget_destroy, NULL);
997
998         /* Delete old entries in the View menu. Do not free groups, it
999            belongs to Gtk+ */
1000         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1001         while (groups) {
1002                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1003                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1004                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
1005                                                             GTK_ACTION_GROUP (groups->data));
1006                         groups = NULL;
1007                         /* Remove uis */
1008                         if (priv->merge_ids) {
1009                                 for (i = 0; i < priv->merge_ids->len; i++)
1010                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1011                                 g_byte_array_free (priv->merge_ids, TRUE);
1012                         }
1013                         /* We need to call this in order to ensure
1014                            that the new actions are added in the right
1015                            order (alphabetical */
1016                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1017                 } else 
1018                         groups = g_list_next (groups);
1019         }
1020         priv->merge_ids = g_byte_array_sized_new (num_accounts);
1021
1022         /* Get send receive button */
1023         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1024                                                           "/ToolBar/ToolbarSendReceive");
1025
1026         /* Create the menu */
1027         if (num_accounts > 1) {
1028                 if (!priv->accounts_popup)
1029                         priv->accounts_popup = gtk_menu_new ();
1030                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1031                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1032                 g_signal_connect (G_OBJECT (item), 
1033                                   "activate", 
1034                                   G_CALLBACK (on_send_receive_csm_activated),
1035                                   NULL);
1036                 item = gtk_separator_menu_item_new ();
1037                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1038         }
1039
1040         /* Create a new action group */
1041         default_account = modest_account_mgr_get_default_account (mgr);
1042         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1043         for (i = 0; i < num_accounts; i++) {
1044                 gchar *display_name = NULL;
1045                 
1046                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1047
1048                 /* Create display name. The default account is shown differently */
1049                 if (default_account && account_data->account_name && 
1050                         !(strcmp (default_account, account_data->account_name) == 0)) {
1051                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
1052                                                         account_data->display_name);
1053                 }
1054                 else {
1055                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
1056                                                         account_data->display_name);
1057                 }
1058
1059                 /* Create action and add it to the action group. The
1060                    action name must be the account name, this way we
1061                    could know in the handlers the account to show */
1062                 if(account_data->account_name) {
1063                         gchar* item_name, *refresh_action_name;
1064                         guint8 merge_id;
1065                         GtkAction *view_account_action, *refresh_account_action;
1066
1067                         view_account_action = gtk_action_new (account_data->account_name,
1068                                                               display_name, NULL, NULL);
1069                         gtk_action_group_add_action (action_group, view_account_action);
1070
1071                         /* Add ui from account data. We allow 2^9-1 account
1072                            changes in a single execution because we're
1073                            downcasting the guint to a guint8 in order to use a
1074                            GByteArray, it should be enough */
1075                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1076                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1077                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1078                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
1079                                                merge_id,
1080                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
1081                                                item_name,
1082                                                account_data->account_name,
1083                                                GTK_UI_MANAGER_MENUITEM,
1084                                                FALSE);
1085         
1086                         /* Connect the action signal "activate" */
1087                         g_signal_connect (G_OBJECT (view_account_action),
1088                                           "activate",
1089                                           G_CALLBACK (on_show_account_action_activated),
1090                                           self);
1091
1092                         /* Create the items for the Tools->Send&Receive submenu */
1093                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1094                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
1095                                                                  display_name, NULL, NULL);
1096                         gtk_action_group_add_action (action_group, refresh_account_action);
1097
1098                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1099                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1100                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
1101                                                merge_id,
1102                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1103                                                item_name,
1104                                                refresh_action_name,
1105                                                GTK_UI_MANAGER_MENUITEM,
1106                                                FALSE);
1107                         g_free (refresh_action_name);
1108
1109                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
1110                                                "activate", 
1111                                                G_CALLBACK (on_refresh_account_action_activated), 
1112                                                g_strdup (account_data->account_name),
1113                                                (GClosureNotify) g_free,
1114                                                0);
1115
1116                         /* Create item and add it to the send&receive
1117                            CSM. If there is only one account then
1118                            it'll be no menu */
1119                         if (priv->accounts_popup) {
1120                                 item = gtk_menu_item_new_with_label (display_name);
1121                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1122                                 g_signal_connect_data (G_OBJECT (item), 
1123                                                        "activate", 
1124                                                        G_CALLBACK (on_send_receive_csm_activated),
1125                                                        g_strdup (account_data->account_name),
1126                                                        (GClosureNotify) g_free,
1127                                                        0);
1128                         }
1129                         g_free (item_name);
1130                 }
1131
1132                 /* Frees */
1133                 g_free (display_name);
1134                 modest_account_mgr_free_account_data (mgr, account_data);
1135         }
1136         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1137
1138         if (priv->accounts_popup) {
1139                 /* Mandatory in order to view the menu contents */
1140                 gtk_widget_show_all (priv->accounts_popup);
1141
1142                 /* Setup tap_and_hold just if was not done before*/
1143                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1144                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1145         }
1146
1147         /* Frees */
1148         g_slist_free (accounts);
1149         g_free (default_account);
1150 }
1151
1152 /* 
1153  * This function manages the key events used to navigate between
1154  * header and folder views (when the window is in split view)
1155  *
1156  * FROM         KEY        ACTION
1157  * -------------------------------------------------
1158  * HeaderView   GDK_Left   Move focus to folder view
1159  * FolderView   GDK_Right  Move focus to header view
1160  *
1161  * There is no need to scroll to selected row, the widgets will be the
1162  * responsibles of doing that (probably managing the focus-in event
1163  */
1164 static gboolean 
1165 on_inner_widgets_key_pressed (GtkWidget *widget,
1166                               GdkEventKey *event,
1167                               gpointer user_data)
1168 {
1169         ModestMainWindowPrivate *priv;
1170
1171         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1172
1173         /* Do nothing if we're in SIMPLE style */
1174         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1175                 return FALSE;
1176
1177         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1178                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1179         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1180                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1181
1182         return FALSE;
1183 }
1184
1185 static void
1186 set_alignment (GtkWidget *widget,
1187                gpointer data)
1188 {
1189         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1190         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1191 }
1192
1193 static GtkWidget *
1194 create_details_widget (TnyFolderStore *folder_store)
1195 {
1196         GtkWidget *vbox;
1197         gchar *label;
1198
1199         vbox = gtk_vbox_new (FALSE, 0);
1200
1201         /* Account description: */
1202         
1203         if (modest_tny_folder_store_is_virtual_local_folders (folder_store)) {
1204                 /* Local folders: */
1205         
1206                 /* Get device name */
1207                 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1208                                                       MODEST_CONF_DEVICE_NAME, NULL);
1209    
1210                 label = g_strdup_printf ("%s: %s",
1211                                          _("mcen_fi_localroot_description"),
1212                                          device_name);
1213                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1214                 g_free (device_name);
1215                 g_free (label);
1216         } else if (TNY_IS_ACCOUNT (folder_store)) {
1217                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1218                 
1219                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1220                         /* TODO: MMC ? */
1221                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1222                 } else {
1223                         /* Other accounts, such as IMAP and POP: */
1224                         
1225                         GString *proto;
1226         
1227                         /* Put proto in uppercase */
1228                         proto = g_string_new (tny_account_get_proto (account));
1229                         proto = g_string_ascii_up (proto);
1230         
1231                         label = g_strdup_printf ("%s %s: %s", 
1232                                                  proto->str,
1233                                                  _("mcen_fi_remoteroot_account"),
1234                                                  tny_account_get_name (account));
1235                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1236                         g_string_free (proto, TRUE);
1237                         g_free (label);
1238                 }
1239         }
1240
1241         /* Message count */
1242         
1243         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1244                                  modest_tny_folder_store_get_message_count (folder_store));
1245         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1246         g_free (label);
1247
1248         /* Folder count */
1249         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1250                                  modest_tny_folder_store_get_folder_count (folder_store));
1251         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1252         g_free (label);
1253
1254         /* Size / Date */
1255         if (modest_tny_folder_store_is_virtual_local_folders (folder_store)) {
1256                 /* FIXME: format size */
1257                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1258                                          modest_tny_folder_store_get_local_size (folder_store));
1259                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1260                 g_free (label);
1261         } else if (TNY_IS_ACCOUNT(folder_store)) {
1262                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1263                 
1264                 if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1265                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1266                 } else {
1267                         time_t last_updated;
1268                         gchar *last_updated_string;
1269                         /* Get last updated from configuration */
1270                         last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1271                                                                   tny_account_get_id (account), 
1272                                                                   MODEST_ACCOUNT_LAST_UPDATED, 
1273                                                                   TRUE);
1274                         if (last_updated > 0) 
1275                                 last_updated_string = modest_text_utils_get_display_date(last_updated);
1276                         else
1277                                 last_updated_string = g_strdup (_("FIXME: Never"));
1278         
1279                         label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1280                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1281                         g_free (last_updated_string);
1282                         g_free (label);
1283                 }
1284         }
1285
1286         /* Set alignment */
1287         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1288
1289         return vbox;
1290 }
1291
1292 void 
1293 modest_main_window_set_contents_style (ModestMainWindow *self, 
1294                                        ModestMainWindowContentsStyle style)
1295 {
1296         ModestMainWindowPrivate *priv;
1297
1298         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1299
1300         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1301
1302         /* We allow to set the same content style than the previously
1303            set if there are details, because it could happen when we're
1304            selecting different accounts consecutively */
1305         if ((priv->contents_style == style) &&
1306             (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS))
1307                 return;
1308
1309         /* Remove previous child. Delete it if it was an account
1310            details widget */
1311         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1312         if (content) {
1313                 if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1314                         g_object_ref (content);
1315                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1316         }
1317
1318         priv->contents_style = style;
1319
1320         switch (priv->contents_style) {
1321         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1322                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1323                 break;
1324         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1325         {
1326                 /* TODO: show here account details */
1327                 TnyFolderStore *selected_folderstore = 
1328                         modest_folder_view_get_selected (priv->folder_view);
1329                         
1330                 priv->details_widget = create_details_widget (selected_folderstore);
1331
1332                 wrap_in_scrolled_window (priv->contents_widget, 
1333                                  priv->details_widget);
1334                 break;
1335         }
1336         default:
1337                 g_return_if_reached ();
1338         }
1339
1340         /* Show */
1341         gtk_widget_show_all (priv->contents_widget);
1342 }
1343
1344 static void 
1345 on_configuration_key_changed (ModestConf* conf, 
1346                               const gchar *key, 
1347                               ModestConfEvent event, 
1348                               ModestMainWindow *self)
1349 {
1350         ModestMainWindowPrivate *priv;
1351         TnyAccount *account;
1352
1353         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1354                 return;
1355
1356         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1357
1358         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1359                 return;
1360
1361         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1362         if (TNY_IS_ACCOUNT (account) &&
1363             !strcmp (tny_account_get_id (account), MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID)) {
1364                 GList *children;
1365                 GtkLabel *label;
1366                 const gchar *device_name;
1367                 gchar *new_text;
1368                 
1369                 /* Get label */
1370                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1371                 label = GTK_LABEL (children->data);
1372                 
1373                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1374                                                       MODEST_CONF_DEVICE_NAME, NULL);
1375                 
1376                 new_text = g_strdup_printf ("%s: %s",
1377                                             _("mcen_fi_localroot_description"),
1378                                             device_name);
1379                 
1380                 gtk_label_set_text (label, new_text);
1381                 gtk_widget_show (GTK_WIDGET (label));
1382                 
1383                 g_free (new_text);
1384                 g_list_free (children);
1385         }
1386 }
1387
1388 static gboolean
1389 set_toolbar_transfer_mode (ModestMainWindow *self)
1390 {
1391         ModestMainWindowPrivate *priv = NULL;
1392         
1393         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1394
1395         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1396
1397         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1398         
1399         if (priv->progress_bar_timeout > 0) {
1400                 g_source_remove (priv->progress_bar_timeout);
1401                 priv->progress_bar_timeout = 0;
1402         }
1403
1404         return FALSE;
1405 }
1406
1407 static void 
1408 set_toolbar_mode (ModestMainWindow *self, 
1409                   ModestToolBarModes mode)
1410 {
1411         ModestWindowPrivate *parent_priv = NULL;
1412         ModestMainWindowPrivate *priv = NULL;
1413         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1414         
1415         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1416
1417         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1418         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1419
1420         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1421         
1422         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1423         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1424         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1425
1426         /* Sets current toolbar mode */
1427         priv->current_toolbar_mode = mode;
1428
1429         /* Show and hide toolbar items */
1430         switch (mode) {
1431         case TOOLBAR_MODE_NORMAL:
1432                 if (sort_action) 
1433                         gtk_action_set_visible (sort_action, TRUE);
1434                 if (refresh_action) 
1435                         gtk_action_set_visible (refresh_action, TRUE);
1436                 if (priv->progress_toolitem) {
1437                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1438                         gtk_widget_hide (priv->progress_toolitem);
1439                 }
1440                 if (priv->progress_bar)
1441                         gtk_widget_hide (priv->progress_bar);                   
1442                 
1443                 if (cancel_action)
1444                         gtk_action_set_visible (cancel_action, FALSE);
1445
1446                 /* Hide toolbar if optimized view is enabled */
1447                 if (priv->optimized_view)
1448                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1449                 break;
1450         case TOOLBAR_MODE_TRANSFER:
1451                 if (sort_action)
1452                         gtk_action_set_visible (sort_action, FALSE);
1453                 if (refresh_action)
1454                         gtk_action_set_visible (refresh_action, FALSE);
1455                 if (cancel_action)
1456                         gtk_action_set_visible (cancel_action, TRUE);
1457                 if (priv->progress_toolitem) {
1458                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1459                         gtk_widget_show (priv->progress_toolitem);
1460                 }
1461                 if (priv->progress_bar)
1462                         gtk_widget_show (priv->progress_bar);                   
1463
1464                 /* Show toolbar if it's hiden (optimized view ) */
1465                 if (priv->optimized_view)
1466                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1467                 break;
1468         default:
1469                 g_return_if_reached ();
1470         }
1471 }
1472
1473 static void
1474 cancel_progressbar (GtkToolButton *toolbutton,
1475                     ModestMainWindow *self)
1476 {
1477         GSList *tmp;
1478         ModestMainWindowPrivate *priv;
1479         
1480         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1481
1482         /* Get operation observers and cancel its current operation */
1483         tmp = priv->progress_widgets;
1484         while (tmp) {
1485                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1486                 tmp=g_slist_next(tmp);
1487         }
1488 }
1489
1490 static gboolean
1491 observers_empty (ModestMainWindow *self)
1492 {
1493         GSList *tmp = NULL;
1494         ModestMainWindowPrivate *priv;
1495         gboolean is_empty = TRUE;
1496         guint pending_ops = 0;
1497  
1498         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1499         tmp = priv->progress_widgets;
1500
1501         /* Check all observers */
1502         while (tmp && is_empty)  {
1503                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1504                 is_empty = pending_ops == 0;
1505                 
1506                 tmp = g_slist_next(tmp);
1507         }
1508         
1509         return is_empty;
1510 }
1511
1512 static void
1513 on_queue_changed (ModestMailOperationQueue *queue,
1514                   ModestMailOperation *mail_op,
1515                   ModestMailOperationQueueNotification type,
1516                   ModestMainWindow *self)
1517 {
1518         ModestMainWindowPrivate *priv;
1519         ModestMailOperationTypeOperation op_type;
1520         ModestToolBarModes mode;
1521         GSList *tmp;
1522         gboolean mode_changed = FALSE;
1523 /*      ModestMailOperationStatus status; */
1524
1525         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1526         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1527                
1528         /* Get toolbar mode from operation id*/
1529         op_type = modest_mail_operation_get_type_operation (mail_op);
1530         switch (op_type) {
1531         case MODEST_MAIL_OPERATION_TYPE_SEND:
1532         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1533                 mode = TOOLBAR_MODE_TRANSFER;
1534                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1535                         mode_changed = TRUE;
1536                 break;
1537         default:
1538                 mode = TOOLBAR_MODE_NORMAL;
1539                 
1540         }
1541                 
1542                        
1543         /* Add operation observers and change toolbar if neccessary*/
1544         tmp = priv->progress_widgets;
1545         switch (type) {
1546         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1547                 if (mode == TOOLBAR_MODE_TRANSFER) {
1548                         if (mode_changed)
1549                                 set_toolbar_transfer_mode(self);                    
1550                         while (tmp) {
1551                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1552                                                                       mail_op);
1553                                 tmp = g_slist_next (tmp);
1554                         }
1555                 }
1556                 break;
1557         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1558                 /* Change toolbar mode */
1559                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1560                         while (tmp) {
1561                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1562                                                                          mail_op);
1563                                 tmp = g_slist_next (tmp);
1564                         }
1565                         
1566                         /* If no more operations are being observed, NORMAL mode is enabled again */
1567                         if (observers_empty (self)) {
1568                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1569                                 
1570                         }
1571                 }
1572
1573                 break;
1574         }       
1575
1576 }
1577
1578 static void 
1579 on_show_account_action_activated  (GtkAction *action,
1580                                    gpointer user_data)
1581 {
1582         ModestAccountData *acc_data;
1583         ModestMainWindow *self;
1584         ModestMainWindowPrivate *priv;
1585         ModestAccountMgr *mgr;
1586         const gchar *acc_name;
1587
1588         self = MODEST_MAIN_WINDOW (user_data);
1589         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1590
1591         /* Get account data */
1592         acc_name = gtk_action_get_name (action);
1593         mgr = modest_runtime_get_account_mgr ();
1594         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1595
1596         /* Set the new visible & active account */
1597         if (acc_data->store_account) { 
1598                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1599                                                                              acc_data->store_account->account_name);
1600                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1601         }
1602
1603         /* Free */
1604         modest_account_mgr_free_account_data (mgr, acc_data);
1605 }
1606
1607 static void
1608 refresh_account (const gchar *account_name)
1609 {
1610         ModestWindow *win;
1611
1612         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1613
1614         /* If account_name == NULL, we must update all (option All) */
1615         if (!account_name)
1616                 modest_ui_actions_do_send_receive_all (win);
1617         else
1618                 modest_ui_actions_do_send_receive (account_name, win);
1619 }
1620
1621 static void 
1622 on_refresh_account_action_activated  (GtkAction *action,
1623                                       gpointer user_data)
1624 {
1625         refresh_account ((const gchar*) user_data);
1626 }
1627
1628 static void
1629 on_send_receive_csm_activated (GtkMenuItem *item,
1630                                gpointer user_data)
1631 {
1632         refresh_account ((const gchar*) user_data);
1633 }