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