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