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