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