Added listening on an extra signal
[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         }
749 }
750
751 ModestWindow *
752 modest_main_window_new (void)
753 {
754         ModestMainWindow *self = NULL;  
755         ModestMainWindowPrivate *priv = NULL;
756         ModestWindowPrivate *parent_priv = NULL;
757         GtkWidget *folder_win = NULL;
758         ModestDimmingRulesGroup *menu_rules_group = NULL;
759         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
760         GtkActionGroup *action_group = NULL;
761         GError *error = NULL;
762         GdkPixbuf *window_icon = NULL; 
763         ModestConf *conf = NULL;
764         GtkAction *action = NULL;
765
766         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
767         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
768         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
769
770         parent_priv->ui_manager = gtk_ui_manager_new();
771         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
772
773         action_group = gtk_action_group_new ("ModestMainWindowActions");
774         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
775
776         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules");
777         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules");
778
779         /* Add common actions */
780         gtk_action_group_add_actions (action_group,
781                                       modest_action_entries,
782                                       G_N_ELEMENTS (modest_action_entries),
783                                       self);
784
785         gtk_action_group_add_actions (action_group,
786                                       modest_folder_view_action_entries,
787                                       G_N_ELEMENTS (modest_folder_view_action_entries),
788                                       self);
789
790         gtk_action_group_add_actions (action_group,
791                                       modest_header_view_action_entries,
792                                       G_N_ELEMENTS (modest_header_view_action_entries),
793                                       self);
794
795         gtk_action_group_add_toggle_actions (action_group,
796                                              modest_toggle_action_entries,
797                                              G_N_ELEMENTS (modest_toggle_action_entries),
798                                              self);
799
800         gtk_action_group_add_toggle_actions (action_group,
801                                              modest_main_window_toggle_action_entries,
802                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
803                                              self);
804
805         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
806         g_object_unref (action_group);
807
808         /* Load the UI definition */
809         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
810                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
811         if (error != NULL) {
812                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
813                 g_error_free (error);
814                 error = NULL;
815         }
816
817         /* Add common dimming rules */
818         modest_dimming_rules_group_add_rules (menu_rules_group, 
819                                               modest_main_window_menu_dimming_entries,
820                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
821                                               self);
822         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
823                                               modest_main_window_toolbar_dimming_entries,
824                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
825                                               self);
826
827         /* Insert dimming rules group for this window */
828         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
829         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
830         g_object_unref (menu_rules_group);
831         g_object_unref (toolbar_rules_group);
832         
833         /* Add accelerators */
834         gtk_window_add_accel_group (GTK_WINDOW (self), 
835                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
836
837         /* Menubar. Update the state of some toggles */
838         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
839         conf = modest_runtime_get_conf ();
840         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
841                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
842         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
843                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
844         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
845                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
846         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
847                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
848         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
849
850         /* Get device name */
851         modest_maemo_utils_get_device_name ();
852
853         /* header view */
854         priv->header_view =
855                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
856         if (!priv->header_view)
857                 g_printerr ("modest: cannot instantiate header view\n");
858         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
859         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
860                                       MODEST_CONF_HEADER_VIEW_KEY);
861
862         /* Empty view */ 
863         priv->empty_view = create_empty_view ();
864                  
865         /* Create scrolled windows */
866         folder_win = gtk_scrolled_window_new (NULL, NULL);
867         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
868         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
869                                         GTK_POLICY_NEVER,
870                                         GTK_POLICY_AUTOMATIC);
871         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
872                                         GTK_POLICY_NEVER,
873                                         GTK_POLICY_AUTOMATIC);
874
875         /* paned */
876         priv->main_paned = gtk_hpaned_new ();
877         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
878         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
879         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
880
881         /* putting it all together... */
882         priv->main_vbox = gtk_vbox_new (FALSE, 6);
883         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
884
885         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
886
887         /* Set window icon */
888         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
889         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
890         
891         HildonProgram *app = hildon_program_get_instance ();
892         hildon_program_add_window (app, HILDON_WINDOW (self));
893         
894         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
895                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
896
897         g_signal_connect (G_OBJECT(self), "show",
898                           G_CALLBACK (modest_main_window_on_show), folder_win);
899                 
900
901         restore_settings (MODEST_MAIN_WINDOW(self), FALSE);
902
903         return MODEST_WINDOW(self);
904 }
905
906 gboolean 
907 modest_main_window_close_all (ModestMainWindow *self)
908 {
909         GtkWidget *note;
910         GtkResponseType response;
911
912         /* Create the confirmation dialog MSG-NOT308 */
913         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
914                                                          _("emev_nc_close_windows"),
915                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
916                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
917                                                          NULL);
918
919         response = gtk_dialog_run (GTK_DIALOG (note));
920         gtk_widget_destroy (GTK_WIDGET (note));
921
922         if (response == GTK_RESPONSE_YES)
923                 return TRUE;
924         else
925                 return FALSE;
926 }
927
928
929 void 
930 modest_main_window_set_style (ModestMainWindow *self, 
931                               ModestMainWindowStyle style)
932 {
933         ModestMainWindowPrivate *priv;
934         ModestWindowPrivate *parent_priv;
935         GtkAction *action;
936
937         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
938
939         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
940         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
941
942         /* no change -> nothing to do */
943         if (priv->style == style)
944                 return;
945
946         /* Get toggle button */
947         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
948
949         priv->style = style;
950         switch (style) {
951         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
952                 /* Remove main paned */
953                 g_object_ref (priv->main_paned);
954                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
955
956                 /* Reparent the contents widget to the main vbox */
957                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
958
959                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
960                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
961                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
962
963                 break;
964         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
965                 /* Remove header view */
966                 g_object_ref (priv->contents_widget);
967                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
968
969                 /* Reparent the main paned */
970                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
971                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
972
973                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
974                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
975                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
976
977                 break;
978         default:
979                 g_return_if_reached ();
980         }
981
982         /* Let header view grab the focus if it's being shown */
983         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
984                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
985         else 
986                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
987
988         /* Show changes */
989         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
990 }
991
992 ModestMainWindowStyle
993 modest_main_window_get_style (ModestMainWindow *self)
994 {
995         ModestMainWindowPrivate *priv;
996
997         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
998
999         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1000         return priv->style;
1001 }
1002
1003
1004
1005 static gboolean
1006 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1007 {
1008         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1009                 ModestWindowPrivate *parent_priv;
1010                 ModestWindowMgr *mgr;
1011                 gboolean is_fullscreen;
1012                 GtkAction *fs_toggle_action;
1013                 gboolean active;
1014                 
1015                 mgr = modest_runtime_get_window_mgr ();
1016                 
1017                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1018
1019                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1020                 
1021                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1022                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1023                 if (is_fullscreen != active) {
1024                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1025                 }
1026         }
1027
1028         return FALSE;
1029
1030 }
1031
1032 static void
1033 set_homogeneous (GtkWidget *widget,
1034                  gpointer data)
1035 {
1036         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1037         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1038 }
1039
1040 static void 
1041 modest_main_window_show_toolbar (ModestWindow *self,
1042                                  gboolean show_toolbar)
1043 {
1044         ModestMainWindowPrivate *priv = NULL;
1045         ModestWindowPrivate *parent_priv = NULL;        
1046         GtkWidget *reply_button = NULL, *menu = NULL;
1047         GtkWidget *placeholder = NULL;
1048         gint insert_index;
1049
1050         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1051         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1052         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1053
1054         /* Set optimized view status */
1055         priv->optimized_view = !show_toolbar;
1056
1057         if (!parent_priv->toolbar) {
1058                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1059                                                                   "/ToolBar");
1060
1061                 /* Set homogeneous toolbar */
1062                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1063                                        set_homogeneous, NULL);
1064         
1065                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1066                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1067                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1068                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1069                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1070                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1071                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1072                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1073
1074                 /* Add ProgressBar (Transfer toolbar) */ 
1075                 priv->progress_bar = modest_progress_bar_widget_new ();
1076                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1077                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1078                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1079                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1080                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1081                 
1082                 /* Connect cancel 'clicked' signal to abort progress mode */
1083                 g_signal_connect(priv->cancel_toolitem, "clicked",
1084                                  G_CALLBACK(cancel_progressbar),
1085                                  self);
1086                 
1087                 /* Add it to the observers list */
1088                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1089
1090                 /* Add to window */
1091                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1092                                            GTK_TOOLBAR (parent_priv->toolbar));
1093
1094                 /* Set reply button tap and hold menu */
1095                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1096                                                           "/ToolBar/ToolbarMessageReply");
1097                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1098                                                   "/ToolbarReplyCSM");
1099                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1100
1101                 /* Set send & receive button tap and hold menu */
1102                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1103                                    NULL, self);
1104         }
1105
1106         if (show_toolbar) {
1107                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1108                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1109                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1110
1111                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1112                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1113         } else
1114                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1115
1116 }
1117
1118 static gint
1119 compare_display_names (ModestAccountData *a,
1120                        ModestAccountData *b)
1121 {
1122         return strcmp (a->display_name, b->display_name);
1123 }
1124
1125 static void 
1126 on_account_update (TnyAccountStore *account_store, 
1127                    const gchar *account_name,
1128                    gpointer user_data)
1129 {
1130         GSList *account_names, *iter, *accounts;
1131         ModestMainWindow *self;
1132         ModestMainWindowPrivate *priv;
1133         ModestWindowPrivate *parent_priv;
1134         ModestAccountMgr *mgr;
1135         gint i, num_accounts;                                   
1136         GtkActionGroup *action_group;
1137         GList *groups;
1138         gchar *default_account;
1139         GtkWidget *send_receive_button, *item;
1140                 
1141         self = MODEST_MAIN_WINDOW (user_data);
1142         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1143         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1144
1145         /* Get enabled account IDs */
1146         mgr = modest_runtime_get_account_mgr ();
1147         account_names = modest_account_mgr_account_names (mgr, TRUE);
1148         iter = account_names;
1149         accounts = NULL;
1150
1151         while (iter) {
1152                 ModestAccountData *account_data = 
1153                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1154                 accounts = g_slist_prepend (accounts, account_data);
1155
1156                 iter = iter->next;
1157         }
1158         modest_account_mgr_free_account_names (account_names);
1159         account_names = NULL;
1160
1161         /* Order the list of accounts by its display name */
1162         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1163         num_accounts = g_slist_length (accounts);
1164
1165         /* Delete old send&receive popup items. We can not just do a
1166            menu_detach because it does not work well with
1167            tap_and_hold */
1168         if (priv->accounts_popup)
1169                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
1170                                        (GtkCallback) gtk_widget_destroy, NULL);
1171
1172         /* Delete old entries in the View menu. Do not free groups, it
1173            belongs to Gtk+ */
1174         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1175         while (groups) {
1176                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1177                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1178                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
1179                                                             GTK_ACTION_GROUP (groups->data));
1180                         groups = NULL;
1181                         /* Remove uis */
1182                         if (priv->merge_ids) {
1183                                 for (i = 0; i < priv->merge_ids->len; i++)
1184                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1185                                 g_byte_array_free (priv->merge_ids, TRUE);
1186                         }
1187                         /* We need to call this in order to ensure
1188                            that the new actions are added in the right
1189                            order (alphabetical */
1190                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1191                 } else 
1192                         groups = g_list_next (groups);
1193         }
1194         priv->merge_ids = g_byte_array_sized_new (num_accounts);
1195
1196         /* Get send receive button */
1197         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1198                                                           "/ToolBar/ToolbarSendReceive");
1199
1200         /* Create the menu */
1201         if (num_accounts > 1) {
1202                 if (!priv->accounts_popup)
1203                         priv->accounts_popup = gtk_menu_new ();
1204                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1205                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1206                 g_signal_connect (G_OBJECT (item), 
1207                                   "activate", 
1208                                   G_CALLBACK (on_send_receive_csm_activated),
1209                                   NULL);
1210                 item = gtk_separator_menu_item_new ();
1211                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1212         }
1213
1214         /* Create a new action group */
1215         default_account = modest_account_mgr_get_default_account (mgr);
1216         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1217         for (i = 0; i < num_accounts; i++) {
1218                 gchar *display_name = NULL;
1219                 
1220                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1221
1222                 /* Create display name. The default account is shown differently */
1223                 if (default_account && account_data->account_name && 
1224                         !(strcmp (default_account, account_data->account_name) == 0)) {
1225                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
1226                                                         account_data->display_name);
1227                 }
1228                 else {
1229                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
1230                                                         account_data->display_name);
1231                 }
1232
1233                 /* Create action and add it to the action group. The
1234                    action name must be the account name, this way we
1235                    could know in the handlers the account to show */
1236                 if(account_data->account_name) {
1237                         gchar* item_name, *refresh_action_name;
1238                         guint8 merge_id;
1239                         GtkAction *view_account_action, *refresh_account_action;
1240
1241                         view_account_action = gtk_action_new (account_data->account_name,
1242                                                               display_name, NULL, NULL);
1243                         gtk_action_group_add_action (action_group, view_account_action);
1244
1245                         /* Add ui from account data. We allow 2^9-1 account
1246                            changes in a single execution because we're
1247                            downcasting the guint to a guint8 in order to use a
1248                            GByteArray, it should be enough */
1249                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1250                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1251                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1252                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
1253                                                merge_id,
1254                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
1255                                                item_name,
1256                                                account_data->account_name,
1257                                                GTK_UI_MANAGER_MENUITEM,
1258                                                FALSE);
1259         
1260                         /* Connect the action signal "activate" */
1261                         g_signal_connect (G_OBJECT (view_account_action),
1262                                           "activate",
1263                                           G_CALLBACK (on_show_account_action_activated),
1264                                           self);
1265
1266                         /* Create the items for the Tools->Send&Receive submenu */
1267                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1268                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
1269                                                                  display_name, NULL, NULL);
1270                         gtk_action_group_add_action (action_group, refresh_account_action);
1271
1272                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1273                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1274                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
1275                                                merge_id,
1276                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1277                                                item_name,
1278                                                refresh_action_name,
1279                                                GTK_UI_MANAGER_MENUITEM,
1280                                                FALSE);
1281                         g_free (refresh_action_name);
1282
1283                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
1284                                                "activate", 
1285                                                G_CALLBACK (on_refresh_account_action_activated), 
1286                                                g_strdup (account_data->account_name),
1287                                                (GClosureNotify) g_free,
1288                                                0);
1289
1290                         /* Create item and add it to the send&receive
1291                            CSM. If there is only one account then
1292                            it'll be no menu */
1293                         if (priv->accounts_popup) {
1294                                 item = gtk_menu_item_new_with_label (display_name);
1295                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1296                                 g_signal_connect_data (G_OBJECT (item), 
1297                                                        "activate", 
1298                                                        G_CALLBACK (on_send_receive_csm_activated),
1299                                                        g_strdup (account_data->account_name),
1300                                                        (GClosureNotify) g_free,
1301                                                        0);
1302                         }
1303                         g_free (item_name);
1304                 }
1305
1306                 /* Frees */
1307                 g_free (display_name);
1308                 modest_account_mgr_free_account_data (mgr, account_data);
1309         }
1310         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1311
1312         if (priv->accounts_popup) {
1313                 /* Mandatory in order to view the menu contents */
1314                 gtk_widget_show_all (priv->accounts_popup);
1315
1316                 /* Setup tap_and_hold just if was not done before*/
1317                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1318                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1319         }
1320
1321         /* Frees */
1322         g_slist_free (accounts);
1323         g_free (default_account);
1324 }
1325
1326 /* 
1327  * This function manages the key events used to navigate between
1328  * header and folder views (when the window is in split view)
1329  *
1330  * FROM         KEY        ACTION
1331  * -------------------------------------------------
1332  * HeaderView   GDK_Left   Move focus to folder view
1333  * FolderView   GDK_Right  Move focus to header view
1334  *
1335  * There is no need to scroll to selected row, the widgets will be the
1336  * responsibles of doing that (probably managing the focus-in event
1337  */
1338 static gboolean 
1339 on_inner_widgets_key_pressed (GtkWidget *widget,
1340                               GdkEventKey *event,
1341                               gpointer user_data)
1342 {
1343         ModestMainWindowPrivate *priv;
1344
1345         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1346
1347         /* Do nothing if we're in SIMPLE style */
1348         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1349                 return FALSE;
1350
1351         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1352                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1353         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1354                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1355
1356         return FALSE;
1357 }
1358
1359 static void
1360 set_alignment (GtkWidget *widget,
1361                gpointer data)
1362 {
1363         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1364         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1365 }
1366
1367 static GtkWidget *
1368 create_empty_view (void)
1369 {
1370         GtkLabel *label = NULL;
1371         GtkWidget *align = NULL;
1372
1373         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1374         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1375         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1376         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1377
1378         return GTK_WIDGET(align);
1379 }
1380
1381 static GtkWidget *
1382 create_details_widget (TnyAccount *account)
1383 {
1384         GtkWidget *vbox;
1385         gchar *label;
1386
1387         vbox = gtk_vbox_new (FALSE, 0);
1388
1389         /* Account description: */
1390         
1391         if (modest_tny_account_is_virtual_local_folders (account)) {
1392                 /* Local folders: */
1393         
1394                 /* Get device name */
1395                 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1396                                                       MODEST_CONF_DEVICE_NAME, NULL);
1397    
1398                 label = g_strdup_printf (_("mcen_fi_localroot_description"),
1399                                          device_name);
1400                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1401                 g_free (device_name);
1402                 g_free (label);
1403         } else {
1404                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1405                         gtk_box_pack_start (GTK_BOX (vbox), 
1406                                 gtk_label_new (tny_account_get_name (account)), 
1407                                 FALSE, FALSE, 0);
1408                 } else {
1409                         /* Other accounts, such as IMAP and POP: */
1410                         
1411                         GString *proto;
1412                         gchar *tmp;
1413         
1414                         /* Put proto in uppercase */
1415                         proto = g_string_new (tny_account_get_proto (account));
1416                         proto = g_string_ascii_up (proto);
1417                         
1418                         /* note: mcen_fi_localroot_description is something like "%s account"
1419                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1420                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1421                         label = g_strdup_printf ("%s: %s", tmp,tny_account_get_name (account));
1422                         g_free (tmp);
1423
1424                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1425                         g_string_free (proto, TRUE);
1426                         g_free (label);
1427                 }
1428         }
1429
1430         /* Message count */
1431         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1432         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1433                                  modest_tny_folder_store_get_message_count (folder_store));
1434         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1435         g_free (label);
1436
1437         /* Folder count */
1438         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1439                                  modest_tny_folder_store_get_folder_count (folder_store));
1440         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1441         g_free (label);
1442
1443         /* Size / Date */
1444         if (modest_tny_account_is_virtual_local_folders (account)) {
1445                 /* FIXME: format size */
1446                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1447                                          modest_tny_folder_store_get_local_size (folder_store));
1448                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1449                 g_free (label);
1450         } else if (TNY_IS_ACCOUNT(folder_store)) {
1451                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1452                 
1453                 time_t last_updated;
1454                 gchar *last_updated_string;
1455                 /* Get last updated from configuration */
1456                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1457                                                           tny_account_get_id (account), 
1458                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1459                                                           TRUE);
1460                 if (last_updated > 0) 
1461                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1462                 else
1463                         last_updated_string = g_strdup (_("mcen_va_never"));
1464
1465                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1466                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1467                 g_free (last_updated_string);
1468                 g_free (label);
1469         }
1470
1471         /* Set alignment */
1472         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1473
1474         return vbox;
1475 }
1476
1477 void 
1478 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1479 {
1480         GtkAction *action = NULL;
1481         GtkWidget *widget = NULL;
1482
1483         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1484
1485         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1486         gtk_action_set_sensitive (action, FALSE);
1487 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1488 /*      gtk_action_set_sensitive (action, FALSE); */
1489         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1490         gtk_widget_set_sensitive (widget, FALSE);
1491
1492
1493 void 
1494 modest_main_window_notify_send_receive_completed (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, TRUE);
1503 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1504 /*      gtk_action_set_sensitive (action, TRUE); */
1505         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1506         gtk_widget_set_sensitive (widget, TRUE);
1507
1508
1509
1510 static void
1511 _on_msg_count_changed (ModestHeaderView *header_view,
1512                        TnyFolder *folder,
1513                        TnyFolderChange *change,
1514                        ModestMainWindow *main_window)
1515 {
1516         printf ("DEBUG: %s\n", __FUNCTION__);
1517         gboolean folder_empty = FALSE;
1518         TnyFolderChangeChanged changed;
1519         
1520         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1521         g_return_if_fail (TNY_IS_FOLDER(folder));
1522         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1523         
1524         changed = tny_folder_change_get_changed (change);
1525         
1526         /* If something changes */
1527         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1528                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1529         else
1530                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1531         
1532         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1533
1534         /* Set contents style of headers view */
1535         if (folder_empty)  {
1536                 modest_main_window_set_contents_style (main_window,
1537                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1538         }
1539         else {
1540                 modest_main_window_set_contents_style (main_window,
1541                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1542         }
1543         
1544 }
1545
1546 void 
1547 modest_main_window_set_contents_style (ModestMainWindow *self, 
1548                                        ModestMainWindowContentsStyle style)
1549 {
1550         ModestMainWindowPrivate *priv;
1551
1552         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1553
1554         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1555
1556         /* We allow to set the same content style than the previously
1557            set if there are details, because it could happen when we're
1558            selecting different accounts consecutively */
1559         if ((priv->contents_style == style) &&
1560             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1561                 return;
1562
1563         /* Remove previous child. Delete it if it was an account
1564            details widget */
1565         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1566         if (content) {
1567                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1568                         g_object_ref (content);
1569                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1570                         g_object_ref (priv->empty_view);
1571                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1572                 }
1573                 
1574                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1575         }
1576
1577         priv->contents_style = style;
1578
1579         switch (priv->contents_style) {
1580         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1581                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1582                 break;
1583         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1584         {
1585                 TnyFolderStore *selected_folderstore = 
1586                         modest_folder_view_get_selected (priv->folder_view);
1587                 if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1588                         priv->details_widget = create_details_widget (
1589                                 TNY_ACCOUNT (selected_folderstore));
1590
1591                         wrap_in_scrolled_window (priv->contents_widget, 
1592                                          priv->details_widget);
1593                 }
1594                 g_object_unref (selected_folderstore);
1595                 break;
1596         }
1597         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1598                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1599                 break;
1600         default:
1601                 g_return_if_reached ();
1602         }
1603
1604         /* Show */
1605         gtk_widget_show_all (priv->contents_widget);
1606 }
1607
1608 ModestMainWindowContentsStyle
1609 modest_main_window_get_contents_style (ModestMainWindow *self)
1610 {
1611         ModestMainWindowPrivate *priv;
1612
1613         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1614
1615         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1616         return priv->contents_style;
1617 }
1618
1619
1620 static void 
1621 on_configuration_key_changed (ModestConf* conf, 
1622                               const gchar *key, 
1623                               ModestConfEvent event, 
1624                               ModestMainWindow *self)
1625 {
1626         ModestMainWindowPrivate *priv;
1627         TnyAccount *account;
1628
1629         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1630                 return;
1631
1632         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1633
1634         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1635                 return;
1636
1637         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1638         if (TNY_IS_ACCOUNT (account) &&
1639             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1640                 GList *children;
1641                 GtkLabel *label;
1642                 const gchar *device_name;
1643                 gchar *new_text;
1644                 
1645                 /* Get label */
1646                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1647                 label = GTK_LABEL (children->data);
1648                 
1649                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1650                                                       MODEST_CONF_DEVICE_NAME, NULL);
1651                 
1652                 new_text = g_strdup_printf ("%s: %s",
1653                                             _("mcen_fi_localroot_description"),
1654                                             device_name);
1655                 
1656                 gtk_label_set_text (label, new_text);
1657                 gtk_widget_show (GTK_WIDGET (label));
1658                 
1659                 g_free (new_text);
1660                 g_list_free (children);
1661         }
1662         g_object_unref (account);
1663 }
1664
1665 static gboolean
1666 set_toolbar_transfer_mode (ModestMainWindow *self)
1667 {
1668         ModestMainWindowPrivate *priv = NULL;
1669         
1670         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1671
1672         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1673
1674         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1675         
1676         if (priv->progress_bar_timeout > 0) {
1677                 g_source_remove (priv->progress_bar_timeout);
1678                 priv->progress_bar_timeout = 0;
1679         }
1680
1681         return FALSE;
1682 }
1683
1684 static void 
1685 set_toolbar_mode (ModestMainWindow *self, 
1686                   ModestToolBarModes mode)
1687 {
1688         ModestWindowPrivate *parent_priv = NULL;
1689         ModestMainWindowPrivate *priv = NULL;
1690         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1691         
1692         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1693
1694         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1695         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1696
1697         /* In case this was called before the toolbar exists: */
1698         if (!(parent_priv->toolbar))
1699                 return;
1700
1701         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1702         
1703         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1704         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1705         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1706
1707         /* Sets current toolbar mode */
1708         priv->current_toolbar_mode = mode;
1709
1710         /* Show and hide toolbar items */
1711         switch (mode) {
1712         case TOOLBAR_MODE_NORMAL:
1713                 if (sort_action) 
1714                         gtk_action_set_visible (sort_action, TRUE);
1715                 if (refresh_action) 
1716                         gtk_action_set_visible (refresh_action, TRUE);
1717                 if (priv->progress_toolitem) {
1718                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1719                         gtk_widget_hide (priv->progress_toolitem);
1720                 }
1721                 if (priv->progress_bar)
1722                         gtk_widget_hide (priv->progress_bar);                   
1723                 
1724                 if (cancel_action)
1725                         gtk_action_set_visible (cancel_action, FALSE);
1726
1727                 /* Hide toolbar if optimized view is enabled */
1728                 if (priv->optimized_view)
1729                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1730                 break;
1731         case TOOLBAR_MODE_TRANSFER:
1732                 if (sort_action)
1733                         gtk_action_set_visible (sort_action, FALSE);
1734                 if (refresh_action)
1735                         gtk_action_set_visible (refresh_action, FALSE);
1736                 if (cancel_action)
1737                         gtk_action_set_visible (cancel_action, TRUE);
1738                 if (priv->progress_toolitem) {
1739                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1740                         gtk_widget_show (priv->progress_toolitem);
1741                 }
1742                 if (priv->progress_bar)
1743                         gtk_widget_show (priv->progress_bar);                   
1744
1745                 /* Show toolbar if it's hiden (optimized view ) */
1746                 if (priv->optimized_view)
1747                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1748                 break;
1749         default:
1750                 g_return_if_reached ();
1751         }
1752 }
1753
1754 static void
1755 cancel_progressbar (GtkToolButton *toolbutton,
1756                     ModestMainWindow *self)
1757 {
1758         GSList *tmp;
1759         ModestMainWindowPrivate *priv;
1760         
1761         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1762
1763         /* Get operation observers and cancel its current operation */
1764         tmp = priv->progress_widgets;
1765         while (tmp) {
1766                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1767                 tmp=g_slist_next(tmp);
1768         }
1769 }
1770
1771 static gboolean
1772 observers_empty (ModestMainWindow *self)
1773 {
1774         GSList *tmp = NULL;
1775         ModestMainWindowPrivate *priv;
1776         gboolean is_empty = TRUE;
1777         guint pending_ops = 0;
1778  
1779         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1780         tmp = priv->progress_widgets;
1781
1782         /* Check all observers */
1783         while (tmp && is_empty)  {
1784                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1785                 is_empty = pending_ops == 0;
1786                 
1787                 tmp = g_slist_next(tmp);
1788         }
1789         
1790         return is_empty;
1791 }
1792
1793 static void
1794 on_queue_changed (ModestMailOperationQueue *queue,
1795                   ModestMailOperation *mail_op,
1796                   ModestMailOperationQueueNotification type,
1797                   ModestMainWindow *self)
1798 {
1799         ModestMainWindowPrivate *priv;
1800         ModestMailOperationTypeOperation op_type;
1801         ModestToolBarModes mode;
1802         GSList *tmp;
1803         gboolean mode_changed = FALSE;
1804 /*      ModestMailOperationStatus status; */
1805
1806         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1807         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1808                
1809         /* Get toolbar mode from operation id*/
1810         op_type = modest_mail_operation_get_type_operation (mail_op);
1811         switch (op_type) {
1812         case MODEST_MAIL_OPERATION_TYPE_SEND:
1813         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1814                 mode = TOOLBAR_MODE_TRANSFER;
1815                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1816                         mode_changed = TRUE;
1817                 break;
1818         default:
1819                 mode = TOOLBAR_MODE_NORMAL;
1820                 
1821         }
1822                 
1823                        
1824         /* Add operation observers and change toolbar if neccessary*/
1825         tmp = priv->progress_widgets;
1826         switch (type) {
1827         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1828                 if (mode == TOOLBAR_MODE_TRANSFER) {
1829                         if (mode_changed)
1830                                 set_toolbar_transfer_mode(self);                    
1831                         while (tmp) {
1832                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1833                                                                       mail_op);
1834                                 tmp = g_slist_next (tmp);
1835                         }
1836                 }
1837                 break;
1838         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1839                 /* Change toolbar mode */
1840                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1841                         while (tmp) {
1842                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1843                                                                          mail_op);
1844                                 tmp = g_slist_next (tmp);
1845                         }
1846                         
1847                         /* If no more operations are being observed, NORMAL mode is enabled again */
1848                         if (observers_empty (self)) {
1849                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1850                                 
1851                         }
1852                 }
1853
1854                 break;
1855         }       
1856
1857 }
1858
1859 static void 
1860 on_show_account_action_activated  (GtkAction *action,
1861                                    gpointer user_data)
1862 {
1863         ModestAccountData *acc_data;
1864         ModestMainWindow *self;
1865         ModestMainWindowPrivate *priv;
1866         ModestAccountMgr *mgr;
1867         const gchar *acc_name;
1868
1869         self = MODEST_MAIN_WINDOW (user_data);
1870         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1871
1872         /* Get account data */
1873         acc_name = gtk_action_get_name (action);
1874         mgr = modest_runtime_get_account_mgr ();
1875         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1876
1877         /* Set the new visible & active account */
1878         if (acc_data->store_account) { 
1879                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1880                                                                              acc_data->store_account->account_name);
1881                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1882         }
1883
1884         /* Free */
1885         modest_account_mgr_free_account_data (mgr, acc_data);
1886 }
1887
1888 static void
1889 refresh_account (const gchar *account_name)
1890 {
1891         ModestWindow *win;
1892
1893         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1894
1895         /* If account_name == NULL, we must update all (option All) */
1896         if (!account_name)
1897                 modest_ui_actions_do_send_receive_all (win);
1898         else
1899                 modest_ui_actions_do_send_receive (account_name, win);
1900         
1901 }
1902
1903 static void 
1904 on_refresh_account_action_activated  (GtkAction *action,
1905                                       gpointer user_data)
1906 {
1907         refresh_account ((const gchar*) user_data);
1908 }
1909
1910 static void
1911 on_send_receive_csm_activated (GtkMenuItem *item,
1912                                gpointer user_data)
1913 {
1914         refresh_account ((const gchar*) user_data);
1915 }
1916