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