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