* leak fixes; free both list and its elements when we call modest_account_mgr_account...
[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         modest_account_mgr_free_account_names (account_names);
565         account_names = NULL;
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         modest_account_mgr_free_account_names (account_names);
1183         account_names = NULL;
1184
1185         /* Order the list of accounts by its display name */
1186         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1187         num_accounts = g_slist_length (accounts);
1188
1189         /* Delete old send&receive popup items. We can not just do a
1190            menu_detach because it does not work well with
1191            tap_and_hold */
1192         if (priv->accounts_popup)
1193                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
1194                                        (GtkCallback) gtk_widget_destroy, NULL);
1195
1196         /* Delete old entries in the View menu. Do not free groups, it
1197            belongs to Gtk+ */
1198         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1199         while (groups) {
1200                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1201                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1202                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
1203                                                             GTK_ACTION_GROUP (groups->data));
1204                         groups = NULL;
1205                         /* Remove uis */
1206                         if (priv->merge_ids) {
1207                                 for (i = 0; i < priv->merge_ids->len; i++)
1208                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1209                                 g_byte_array_free (priv->merge_ids, TRUE);
1210                         }
1211                         /* We need to call this in order to ensure
1212                            that the new actions are added in the right
1213                            order (alphabetical */
1214                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1215                 } else 
1216                         groups = g_list_next (groups);
1217         }
1218         priv->merge_ids = g_byte_array_sized_new (num_accounts);
1219
1220         /* Get send receive button */
1221         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1222                                                           "/ToolBar/ToolbarSendReceive");
1223
1224         /* Create the menu */
1225         if (num_accounts > 1) {
1226                 if (!priv->accounts_popup)
1227                         priv->accounts_popup = gtk_menu_new ();
1228                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1229                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1230                 g_signal_connect (G_OBJECT (item), 
1231                                   "activate", 
1232                                   G_CALLBACK (on_send_receive_csm_activated),
1233                                   NULL);
1234                 item = gtk_separator_menu_item_new ();
1235                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1236         }
1237
1238         /* Create a new action group */
1239         default_account = modest_account_mgr_get_default_account (mgr);
1240         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1241         for (i = 0; i < num_accounts; i++) {
1242                 gchar *display_name = NULL;
1243                 
1244                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1245
1246                 /* Create display name. The default account is shown differently */
1247                 if (default_account && account_data->account_name && 
1248                         !(strcmp (default_account, account_data->account_name) == 0)) {
1249                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
1250                                                         account_data->display_name);
1251                 }
1252                 else {
1253                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
1254                                                         account_data->display_name);
1255                 }
1256
1257                 /* Create action and add it to the action group. The
1258                    action name must be the account name, this way we
1259                    could know in the handlers the account to show */
1260                 if(account_data->account_name) {
1261                         gchar* item_name, *refresh_action_name;
1262                         guint8 merge_id;
1263                         GtkAction *view_account_action, *refresh_account_action;
1264
1265                         view_account_action = gtk_action_new (account_data->account_name,
1266                                                               display_name, NULL, NULL);
1267                         gtk_action_group_add_action (action_group, view_account_action);
1268
1269                         /* Add ui from account data. We allow 2^9-1 account
1270                            changes in a single execution because we're
1271                            downcasting the guint to a guint8 in order to use a
1272                            GByteArray, it should be enough */
1273                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1274                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1275                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1276                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
1277                                                merge_id,
1278                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
1279                                                item_name,
1280                                                account_data->account_name,
1281                                                GTK_UI_MANAGER_MENUITEM,
1282                                                FALSE);
1283         
1284                         /* Connect the action signal "activate" */
1285                         g_signal_connect (G_OBJECT (view_account_action),
1286                                           "activate",
1287                                           G_CALLBACK (on_show_account_action_activated),
1288                                           self);
1289
1290                         /* Create the items for the Tools->Send&Receive submenu */
1291                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1292                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
1293                                                                  display_name, NULL, NULL);
1294                         gtk_action_group_add_action (action_group, refresh_account_action);
1295
1296                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1297                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1298                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
1299                                                merge_id,
1300                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1301                                                item_name,
1302                                                refresh_action_name,
1303                                                GTK_UI_MANAGER_MENUITEM,
1304                                                FALSE);
1305                         g_free (refresh_action_name);
1306
1307                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
1308                                                "activate", 
1309                                                G_CALLBACK (on_refresh_account_action_activated), 
1310                                                g_strdup (account_data->account_name),
1311                                                (GClosureNotify) g_free,
1312                                                0);
1313
1314                         /* Create item and add it to the send&receive
1315                            CSM. If there is only one account then
1316                            it'll be no menu */
1317                         if (priv->accounts_popup) {
1318                                 item = gtk_menu_item_new_with_label (display_name);
1319                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1320                                 g_signal_connect_data (G_OBJECT (item), 
1321                                                        "activate", 
1322                                                        G_CALLBACK (on_send_receive_csm_activated),
1323                                                        g_strdup (account_data->account_name),
1324                                                        (GClosureNotify) g_free,
1325                                                        0);
1326                         }
1327                         g_free (item_name);
1328                 }
1329
1330                 /* Frees */
1331                 g_free (display_name);
1332                 modest_account_mgr_free_account_data (mgr, account_data);
1333         }
1334         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1335
1336         if (priv->accounts_popup) {
1337                 /* Mandatory in order to view the menu contents */
1338                 gtk_widget_show_all (priv->accounts_popup);
1339
1340                 /* Setup tap_and_hold just if was not done before*/
1341                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1342                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1343         }
1344
1345         /* Frees */
1346         g_slist_free (accounts);
1347         g_free (default_account);
1348 }
1349
1350 /* 
1351  * This function manages the key events used to navigate between
1352  * header and folder views (when the window is in split view)
1353  *
1354  * FROM         KEY        ACTION
1355  * -------------------------------------------------
1356  * HeaderView   GDK_Left   Move focus to folder view
1357  * FolderView   GDK_Right  Move focus to header view
1358  *
1359  * There is no need to scroll to selected row, the widgets will be the
1360  * responsibles of doing that (probably managing the focus-in event
1361  */
1362 static gboolean 
1363 on_inner_widgets_key_pressed (GtkWidget *widget,
1364                               GdkEventKey *event,
1365                               gpointer user_data)
1366 {
1367         ModestMainWindowPrivate *priv;
1368
1369         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1370
1371         /* Do nothing if we're in SIMPLE style */
1372         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1373                 return FALSE;
1374
1375         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1376                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1377         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1378                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1379
1380         return FALSE;
1381 }
1382
1383 static void
1384 set_alignment (GtkWidget *widget,
1385                gpointer data)
1386 {
1387         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1388         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1389 }
1390
1391 static GtkWidget *
1392 create_empty_view (void)
1393 {
1394         GtkLabel *label = NULL;
1395         GtkWidget *align = NULL;
1396
1397         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1398         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1399         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1400         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1401
1402         return GTK_WIDGET(align);
1403 }
1404
1405 static GtkWidget *
1406 create_details_widget (TnyAccount *account)
1407 {
1408         GtkWidget *vbox;
1409         gchar *label;
1410
1411         vbox = gtk_vbox_new (FALSE, 0);
1412
1413         /* Account description: */
1414         
1415         if (modest_tny_account_is_virtual_local_folders (account)) {
1416                 /* Local folders: */
1417         
1418                 /* Get device name */
1419                 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1420                                                       MODEST_CONF_DEVICE_NAME, NULL);
1421    
1422                 label = g_strdup_printf (_("mcen_fi_localroot_description"),
1423                                          device_name);
1424                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1425                 g_free (device_name);
1426                 g_free (label);
1427         } else {
1428                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1429                         gtk_box_pack_start (GTK_BOX (vbox), 
1430                                 gtk_label_new (tny_account_get_name (account)), 
1431                                 FALSE, FALSE, 0);
1432                 } else {
1433                         /* Other accounts, such as IMAP and POP: */
1434                         
1435                         GString *proto;
1436                         gchar *tmp;
1437         
1438                         /* Put proto in uppercase */
1439                         proto = g_string_new (tny_account_get_proto (account));
1440                         proto = g_string_ascii_up (proto);
1441                         
1442                         /* note: mcen_fi_localroot_description is something like "%s account"
1443                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1444                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1445                         label = g_strdup_printf ("%s: %s", tmp,tny_account_get_name (account));
1446                         g_free (tmp);
1447
1448                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1449                         g_string_free (proto, TRUE);
1450                         g_free (label);
1451                 }
1452         }
1453
1454         /* Message count */
1455         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1456         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1457                                  modest_tny_folder_store_get_message_count (folder_store));
1458         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1459         g_free (label);
1460
1461         /* Folder count */
1462         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1463                                  modest_tny_folder_store_get_folder_count (folder_store));
1464         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1465         g_free (label);
1466
1467         /* Size / Date */
1468         if (modest_tny_account_is_virtual_local_folders (account)) {
1469                 /* FIXME: format size */
1470                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1471                                          modest_tny_folder_store_get_local_size (folder_store));
1472                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1473                 g_free (label);
1474         } else if (TNY_IS_ACCOUNT(folder_store)) {
1475                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1476                 
1477                 time_t last_updated;
1478                 gchar *last_updated_string;
1479                 /* Get last updated from configuration */
1480                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1481                                                           tny_account_get_id (account), 
1482                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1483                                                           TRUE);
1484                 if (last_updated > 0) 
1485                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1486                 else
1487                         last_updated_string = g_strdup (_("mcen_va_never"));
1488
1489                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1490                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1491                 g_free (last_updated_string);
1492                 g_free (label);
1493         }
1494
1495         /* Set alignment */
1496         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1497
1498         return vbox;
1499 }
1500
1501 void 
1502 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1503 {
1504         GtkAction *action = NULL;
1505         GtkWidget *widget = NULL;
1506
1507         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1508
1509         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1510         gtk_action_set_sensitive (action, FALSE);
1511 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1512 /*      gtk_action_set_sensitive (action, FALSE); */
1513         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1514         gtk_widget_set_sensitive (widget, FALSE);
1515
1516
1517 void 
1518 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1519 {
1520         GtkAction *action = NULL;
1521         GtkWidget *widget = NULL;
1522
1523         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1524
1525         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1526         gtk_action_set_sensitive (action, TRUE);
1527 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1528 /*      gtk_action_set_sensitive (action, TRUE); */
1529         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1530         gtk_widget_set_sensitive (widget, TRUE);
1531
1532
1533
1534 static void
1535 _on_msg_count_changed (ModestHeaderView *header_view,
1536                        TnyFolder *folder,
1537                        TnyFolderChange *change,
1538                        ModestMainWindow *main_window)
1539 {
1540         printf ("DEBUG: %s\n", __FUNCTION__);
1541         gboolean folder_empty = FALSE;
1542         TnyFolderChangeChanged changed;
1543         
1544         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1545         g_return_if_fail (TNY_IS_FOLDER(folder));
1546         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1547         
1548         changed = tny_folder_change_get_changed (change);
1549         
1550         /* If something changes */
1551         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1552                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1553         else
1554                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1555         
1556         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1557
1558         /* Set contents style of headers view */
1559         if (folder_empty)  {
1560                 modest_main_window_set_contents_style (main_window,
1561                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1562         }
1563         else {
1564                 modest_main_window_set_contents_style (main_window,
1565                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1566         }
1567         
1568 }
1569
1570 void 
1571 modest_main_window_set_contents_style (ModestMainWindow *self, 
1572                                        ModestMainWindowContentsStyle style)
1573 {
1574         ModestMainWindowPrivate *priv;
1575
1576         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1577
1578         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1579
1580         /* We allow to set the same content style than the previously
1581            set if there are details, because it could happen when we're
1582            selecting different accounts consecutively */
1583         if ((priv->contents_style == style) &&
1584             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1585                 return;
1586
1587         /* Remove previous child. Delete it if it was an account
1588            details widget */
1589         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1590         if (content) {
1591                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1592                         g_object_ref (content);
1593                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1594                         g_object_ref (priv->empty_view);
1595                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1596                 }
1597                 
1598                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1599         }
1600
1601         priv->contents_style = style;
1602
1603         switch (priv->contents_style) {
1604         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1605                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1606                 break;
1607         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1608         {
1609                 TnyFolderStore *selected_folderstore = 
1610                         modest_folder_view_get_selected (priv->folder_view);
1611                 if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1612                         priv->details_widget = create_details_widget (
1613                                 TNY_ACCOUNT (selected_folderstore));
1614
1615                         wrap_in_scrolled_window (priv->contents_widget, 
1616                                          priv->details_widget);
1617                 }
1618                 g_object_unref (selected_folderstore);
1619                 break;
1620         }
1621         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1622                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1623                 break;
1624         default:
1625                 g_return_if_reached ();
1626         }
1627
1628         /* Show */
1629         gtk_widget_show_all (priv->contents_widget);
1630 }
1631
1632 ModestMainWindowContentsStyle
1633 modest_main_window_get_contents_style (ModestMainWindow *self)
1634 {
1635         ModestMainWindowPrivate *priv;
1636
1637         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1638
1639         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1640         return priv->contents_style;
1641 }
1642
1643
1644 static void 
1645 on_configuration_key_changed (ModestConf* conf, 
1646                               const gchar *key, 
1647                               ModestConfEvent event, 
1648                               ModestMainWindow *self)
1649 {
1650         ModestMainWindowPrivate *priv;
1651         TnyAccount *account;
1652
1653         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1654                 return;
1655
1656         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1657
1658         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1659                 return;
1660
1661         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1662         if (TNY_IS_ACCOUNT (account) &&
1663             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1664                 GList *children;
1665                 GtkLabel *label;
1666                 const gchar *device_name;
1667                 gchar *new_text;
1668                 
1669                 /* Get label */
1670                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1671                 label = GTK_LABEL (children->data);
1672                 
1673                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1674                                                       MODEST_CONF_DEVICE_NAME, NULL);
1675                 
1676                 new_text = g_strdup_printf ("%s: %s",
1677                                             _("mcen_fi_localroot_description"),
1678                                             device_name);
1679                 
1680                 gtk_label_set_text (label, new_text);
1681                 gtk_widget_show (GTK_WIDGET (label));
1682                 
1683                 g_free (new_text);
1684                 g_list_free (children);
1685         }
1686         g_object_unref (account);
1687 }
1688
1689 static gboolean
1690 set_toolbar_transfer_mode (ModestMainWindow *self)
1691 {
1692         ModestMainWindowPrivate *priv = NULL;
1693         
1694         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1695
1696         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1697
1698         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1699         
1700         if (priv->progress_bar_timeout > 0) {
1701                 g_source_remove (priv->progress_bar_timeout);
1702                 priv->progress_bar_timeout = 0;
1703         }
1704
1705         return FALSE;
1706 }
1707
1708 static void 
1709 set_toolbar_mode (ModestMainWindow *self, 
1710                   ModestToolBarModes mode)
1711 {
1712         ModestWindowPrivate *parent_priv = NULL;
1713         ModestMainWindowPrivate *priv = NULL;
1714         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1715         
1716         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1717
1718         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1719         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1720
1721         /* In case this was called before the toolbar exists: */
1722         if (!(parent_priv->toolbar))
1723                 return;
1724
1725         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1726         
1727         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1728         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1729         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1730
1731         /* Sets current toolbar mode */
1732         priv->current_toolbar_mode = mode;
1733
1734         /* Show and hide toolbar items */
1735         switch (mode) {
1736         case TOOLBAR_MODE_NORMAL:
1737                 if (sort_action) 
1738                         gtk_action_set_visible (sort_action, TRUE);
1739                 if (refresh_action) 
1740                         gtk_action_set_visible (refresh_action, TRUE);
1741                 if (priv->progress_toolitem) {
1742                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1743                         gtk_widget_hide (priv->progress_toolitem);
1744                 }
1745                 if (priv->progress_bar)
1746                         gtk_widget_hide (priv->progress_bar);                   
1747                 
1748                 if (cancel_action)
1749                         gtk_action_set_visible (cancel_action, FALSE);
1750
1751                 /* Hide toolbar if optimized view is enabled */
1752                 if (priv->optimized_view)
1753                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1754                 break;
1755         case TOOLBAR_MODE_TRANSFER:
1756                 if (sort_action)
1757                         gtk_action_set_visible (sort_action, FALSE);
1758                 if (refresh_action)
1759                         gtk_action_set_visible (refresh_action, FALSE);
1760                 if (cancel_action)
1761                         gtk_action_set_visible (cancel_action, TRUE);
1762                 if (priv->progress_toolitem) {
1763                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1764                         gtk_widget_show (priv->progress_toolitem);
1765                 }
1766                 if (priv->progress_bar)
1767                         gtk_widget_show (priv->progress_bar);                   
1768
1769                 /* Show toolbar if it's hiden (optimized view ) */
1770                 if (priv->optimized_view)
1771                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1772                 break;
1773         default:
1774                 g_return_if_reached ();
1775         }
1776 }
1777
1778 static void
1779 cancel_progressbar (GtkToolButton *toolbutton,
1780                     ModestMainWindow *self)
1781 {
1782         GSList *tmp;
1783         ModestMainWindowPrivate *priv;
1784         
1785         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1786
1787         /* Get operation observers and cancel its current operation */
1788         tmp = priv->progress_widgets;
1789         while (tmp) {
1790                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1791                 tmp=g_slist_next(tmp);
1792         }
1793 }
1794
1795 static gboolean
1796 observers_empty (ModestMainWindow *self)
1797 {
1798         GSList *tmp = NULL;
1799         ModestMainWindowPrivate *priv;
1800         gboolean is_empty = TRUE;
1801         guint pending_ops = 0;
1802  
1803         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1804         tmp = priv->progress_widgets;
1805
1806         /* Check all observers */
1807         while (tmp && is_empty)  {
1808                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1809                 is_empty = pending_ops == 0;
1810                 
1811                 tmp = g_slist_next(tmp);
1812         }
1813         
1814         return is_empty;
1815 }
1816
1817 static void
1818 on_queue_changed (ModestMailOperationQueue *queue,
1819                   ModestMailOperation *mail_op,
1820                   ModestMailOperationQueueNotification type,
1821                   ModestMainWindow *self)
1822 {
1823         ModestMainWindowPrivate *priv;
1824         ModestMailOperationTypeOperation op_type;
1825         ModestToolBarModes mode;
1826         GSList *tmp;
1827         gboolean mode_changed = FALSE;
1828 /*      ModestMailOperationStatus status; */
1829
1830         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1831         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1832                
1833         /* Get toolbar mode from operation id*/
1834         op_type = modest_mail_operation_get_type_operation (mail_op);
1835         switch (op_type) {
1836         case MODEST_MAIL_OPERATION_TYPE_SEND:
1837         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1838                 mode = TOOLBAR_MODE_TRANSFER;
1839                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1840                         mode_changed = TRUE;
1841                 break;
1842         default:
1843                 mode = TOOLBAR_MODE_NORMAL;
1844                 
1845         }
1846                 
1847                        
1848         /* Add operation observers and change toolbar if neccessary*/
1849         tmp = priv->progress_widgets;
1850         switch (type) {
1851         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1852                 if (mode == TOOLBAR_MODE_TRANSFER) {
1853                         if (mode_changed)
1854                                 set_toolbar_transfer_mode(self);                    
1855                         while (tmp) {
1856                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1857                                                                       mail_op);
1858                                 tmp = g_slist_next (tmp);
1859                         }
1860                 }
1861                 break;
1862         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1863                 /* Change toolbar mode */
1864                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1865                         while (tmp) {
1866                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1867                                                                          mail_op);
1868                                 tmp = g_slist_next (tmp);
1869                         }
1870                         
1871                         /* If no more operations are being observed, NORMAL mode is enabled again */
1872                         if (observers_empty (self)) {
1873                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1874                                 
1875                         }
1876                 }
1877
1878                 break;
1879         }       
1880
1881 }
1882
1883 static void 
1884 on_show_account_action_activated  (GtkAction *action,
1885                                    gpointer user_data)
1886 {
1887         ModestAccountData *acc_data;
1888         ModestMainWindow *self;
1889         ModestMainWindowPrivate *priv;
1890         ModestAccountMgr *mgr;
1891         const gchar *acc_name;
1892
1893         self = MODEST_MAIN_WINDOW (user_data);
1894         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1895
1896         /* Get account data */
1897         acc_name = gtk_action_get_name (action);
1898         mgr = modest_runtime_get_account_mgr ();
1899         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1900
1901         /* Set the new visible & active account */
1902         if (acc_data->store_account) { 
1903                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1904                                                                              acc_data->store_account->account_name);
1905                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1906         }
1907
1908         /* Free */
1909         modest_account_mgr_free_account_data (mgr, acc_data);
1910 }
1911
1912 static void
1913 refresh_account (const gchar *account_name)
1914 {
1915         ModestWindow *win;
1916
1917         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1918
1919         /* If account_name == NULL, we must update all (option All) */
1920         if (!account_name)
1921                 modest_ui_actions_do_send_receive_all (win);
1922         else
1923                 modest_ui_actions_do_send_receive (account_name, win);
1924 }
1925
1926 static void 
1927 on_refresh_account_action_activated  (GtkAction *action,
1928                                       gpointer user_data)
1929 {
1930         refresh_account ((const gchar*) user_data);
1931 }
1932
1933 static void
1934 on_send_receive_csm_activated (GtkMenuItem *item,
1935                                gpointer user_data)
1936 {
1937         refresh_account ((const gchar*) user_data);
1938 }
1939
1940 static gchar * 
1941 translate_func (const gchar *msgid,
1942                 const gchar *domain_name)
1943 {
1944         return _(msgid);
1945 }