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