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