* Added new msg received notification support
[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 "modest-hildon-includes.h"
35 #include "modest-defs.h"
36 #include <string.h>
37
38 #include "widgets/modest-main-window.h"
39 #include "widgets/modest-msg-edit-window.h"
40 #include "widgets/modest-account-view-window.h"
41 #include "modest-runtime.h"
42 #include "modest-account-mgr-helpers.h"
43 #include "modest-platform.h"
44 #include "modest-widget-memory.h"
45 #include "modest-window-priv.h"
46 #include "modest-main-window-ui.h"
47 #include "modest-account-mgr.h"
48 #include "modest-tny-account.h"
49 #include "modest-conf.h"
50 #include <modest-maemo-utils.h>
51 #include "modest-tny-platform-factory.h"
52 #include "modest-tny-msg.h"
53 #include "modest-mail-operation.h"
54 #include "modest-icon-names.h"
55 #include "modest-progress-bar-widget.h"
56 #include "maemo/modest-osso-state-saving.h"
57
58 #ifdef MODEST_HILDON_VERSION_0
59 #include <hildon-widgets/hildon-program.h>
60 #else
61 #include <hildon/hildon-program.h>
62 #endif /*MODEST_HILDON_VERSION_0*/
63
64 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
65
66 /* 'private'/'protected' functions */
67 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
68 static void modest_main_window_init          (ModestMainWindow *obj);
69 static void modest_main_window_finalize      (GObject *obj);
70 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
71                                                            GdkEventWindowState *event, 
72                                                            gpointer userdata);
73
74 static void connect_signals (ModestMainWindow *self);
75
76 static void restore_settings (ModestMainWindow *self);
77 static void save_state (ModestWindow *self);
78
79 static void modest_main_window_show_toolbar   (ModestWindow *window,
80                                                gboolean show_toolbar);
81
82 static void cancel_progressbar (GtkToolButton *toolbutton,
83                                 ModestMainWindow *self);
84
85 static void         on_queue_changed                     (ModestMailOperationQueue *queue,
86                                                           ModestMailOperation *mail_op,
87                                                           ModestMailOperationQueueNotification type,
88                                                           ModestMainWindow *self);
89
90 static void on_account_update                 (TnyAccountStore *account_store, 
91                                                const gchar *account_name,
92                                                gpointer user_data);
93
94 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
95                                                GdkEventKey *event,
96                                                gpointer user_data);
97
98 static void on_configuration_key_changed      (ModestConf* conf, 
99                                                const gchar *key, 
100                                                ModestConfEvent event, 
101                                                ModestMainWindow *self);
102
103 static void set_toolbar_mode                  (ModestMainWindow *self, 
104                                                ModestToolBarModes mode);
105
106 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
107
108 static void on_show_account_action_activated  (GtkAction *action,
109                                                gpointer user_data);
110
111 static void on_send_receive_csm_activated     (GtkMenuItem *item,
112                                                gpointer user_data);
113 /* list my signals */
114 enum {
115         /* MY_SIGNAL_1, */
116         /* MY_SIGNAL_2, */
117         LAST_SIGNAL
118 };
119
120
121 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
122 struct _ModestMainWindowPrivate {
123         GtkWidget *msg_paned;
124         GtkWidget *main_paned;
125         GtkWidget *main_vbox;
126         GtkWidget *contents_widget;
127
128         /* Progress observers */
129         GtkWidget        *progress_bar;
130         GSList           *progress_widgets;
131
132         /* Tollbar items */
133         GtkWidget   *progress_toolitem;
134         GtkWidget   *cancel_toolitem;
135         GtkWidget   *sort_toolitem;
136         GtkWidget   *refresh_toolitem;
137         ModestToolBarModes current_toolbar_mode;
138
139         /* Merge ids used to add/remove accounts to the ViewMenu*/
140         GByteArray *merge_ids;
141
142         /* On-demand widgets */
143         GtkWidget *accounts_popup;
144         GtkWidget *details_widget;
145
146         /* Optimized view enabled */
147         gboolean optimized_view;
148
149         ModestHeaderView *header_view;
150         ModestFolderView *folder_view;
151
152         ModestMainWindowStyle style;
153         ModestMainWindowContentsStyle contents_style;
154
155         guint progress_bar_timeout;
156
157 };
158 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
159                                                 MODEST_TYPE_MAIN_WINDOW, \
160                                                 ModestMainWindowPrivate))
161
162 typedef struct _GetMsgAsyncHelper {
163         ModestMainWindowPrivate *main_window_private;
164         guint action;
165         ModestTnyMsgReplyType reply_type;
166         ModestTnyMsgForwardType forward_type;
167         gchar *from;
168         TnyIterator *iter;
169 } GetMsgAsyncHelper;
170
171
172 /* globals */
173 static GtkWindowClass *parent_class = NULL;
174
175
176 /* Private actions */
177 static const GtkActionEntry modest_folder_view_action_entries [] = {
178
179         /* Folder View CSM actions */
180         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
181         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
182         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL, NULL },
183         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
184         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, NULL },
185         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, NULL },
186 };
187
188
189 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
190         { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
191 };
192
193 /************************************************************************/
194
195 GType
196 modest_main_window_get_type (void)
197 {
198         static GType my_type = 0;
199         if (!my_type) {
200                 static const GTypeInfo my_info = {
201                         sizeof(ModestMainWindowClass),
202                         NULL,           /* base init */
203                         NULL,           /* base finalize */
204                         (GClassInitFunc) modest_main_window_class_init,
205                         NULL,           /* class finalize */
206                         NULL,           /* class data */
207                         sizeof(ModestMainWindow),
208                         1,              /* n_preallocs */
209                         (GInstanceInitFunc) modest_main_window_init,
210                         NULL
211                 };
212                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
213                                                   "ModestMainWindow",
214                                                   &my_info, 0);
215         }
216         return my_type;
217 }
218
219 static void
220 modest_main_window_class_init (ModestMainWindowClass *klass)
221 {
222         GObjectClass *gobject_class;
223         gobject_class = (GObjectClass*) klass;
224         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
225
226         parent_class            = g_type_class_peek_parent (klass);
227         gobject_class->finalize = modest_main_window_finalize;
228
229         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
230         
231         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
232         modest_window_class->save_state_func = save_state;
233 }
234
235 static void
236 modest_main_window_init (ModestMainWindow *obj)
237 {
238         ModestMainWindowPrivate *priv;
239
240         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
241
242         priv->msg_paned    = NULL;
243         priv->main_paned   = NULL;      
244         priv->main_vbox    = NULL;
245         priv->header_view  = NULL;
246         priv->folder_view  = NULL;
247         priv->contents_widget  = NULL;
248         priv->accounts_popup  = NULL;
249         priv->details_widget  = NULL;
250
251         priv->progress_widgets  = NULL;
252         priv->progress_bar = NULL;
253         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
254
255         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
256         priv->contents_style  = MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS;
257
258         priv->merge_ids = NULL;
259
260         priv->optimized_view  = FALSE;
261         priv->progress_bar_timeout = 0;
262 }
263
264 static void
265 modest_main_window_finalize (GObject *obj)
266 {
267         ModestMainWindowPrivate *priv;
268
269         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
270
271         g_slist_free (priv->progress_widgets);
272
273         g_byte_array_free (priv->merge_ids, TRUE);
274
275         if (priv->progress_bar_timeout > 0) {
276                 g_source_remove (priv->progress_bar_timeout);
277                 priv->progress_bar_timeout = 0;
278         }
279
280         G_OBJECT_CLASS(parent_class)->finalize (obj);
281 }
282
283 GtkWidget*
284 modest_main_window_get_child_widget (ModestMainWindow *self,
285                                      ModestWidgetType widget_type)
286 {
287         ModestMainWindowPrivate *priv;
288         GtkWidget *widget;
289         
290         g_return_val_if_fail (self, NULL);
291         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
292                               NULL);
293         
294         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
295
296         switch (widget_type) {
297         case MODEST_WIDGET_TYPE_HEADER_VIEW:
298                 widget = (GtkWidget*)priv->header_view; break;
299         case MODEST_WIDGET_TYPE_FOLDER_VIEW:
300                 widget = (GtkWidget*)priv->folder_view; break;
301         default:
302                 return NULL;
303         }
304
305         return widget ? GTK_WIDGET(widget) : NULL;
306 }
307
308
309
310 static void
311 restore_settings (ModestMainWindow *self)
312 {
313         ModestConf *conf;
314         ModestMainWindowPrivate *priv;
315
316         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
317
318         conf = modest_runtime_get_conf ();
319         
320         modest_widget_memory_restore (conf, G_OBJECT(self), 
321                                       MODEST_CONF_MAIN_WINDOW_KEY);
322         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
323                                       MODEST_CONF_MAIN_PANED_KEY);
324         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
325                                       MODEST_CONF_HEADER_VIEW_KEY);
326 }
327
328
329 static void
330 save_state (ModestWindow *window)
331 {
332         ModestConf *conf;
333         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
334         ModestMainWindowPrivate *priv;
335                 
336         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
337         conf = modest_runtime_get_conf ();
338         
339         modest_widget_memory_save (conf,G_OBJECT(self), 
340                                    MODEST_CONF_MAIN_WINDOW_KEY);
341         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
342                                    MODEST_CONF_MAIN_PANED_KEY);
343         modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
344                                    MODEST_CONF_HEADER_VIEW_KEY);
345 }
346
347 static void
348 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
349 {
350         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
351                 gtk_scrolled_window_add_with_viewport
352                         (GTK_SCROLLED_WINDOW(win), widget);
353         else
354                 gtk_container_add (GTK_CONTAINER(win),
355                                    widget);
356 }
357
358
359 static gboolean
360 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
361 {
362         modest_window_save_state (MODEST_WINDOW(self));
363         return FALSE;
364 }
365
366
367 static void
368 on_connection_changed (TnyDevice *device, gboolean online, ModestMainWindow *self)
369 {
370         /* When going online, do the equivalent of pressing the send/receive button, 
371          * as per the specification:
372          * (without the check for >0 accounts, though that is not specified): */
373         if (online) {
374                 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
375         }
376 }
377
378
379
380 static void
381 connect_signals (ModestMainWindow *self)
382 {       
383         ModestWindowPrivate *parent_priv;
384         ModestMainWindowPrivate *priv;
385         GtkWidget *menu;
386         
387         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
388         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
389         
390         /* folder view */
391         g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
392                           G_CALLBACK(on_inner_widgets_key_pressed), self);
393         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
394                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
395         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
396                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
397
398         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
399         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
400
401         /* header view */
402 /*      g_signal_connect (G_OBJECT(priv->header_view), "status_update", */
403 /*                        G_CALLBACK(modest_ui_actions_on_header_status_update), self); */
404         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
405                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
406         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
407                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
408         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
409                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
410         g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
411                           G_CALLBACK(on_inner_widgets_key_pressed), self);
412
413         /* window */
414         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
415         g_signal_connect (G_OBJECT (self), "window-state-event",
416                           G_CALLBACK (modest_main_window_window_state_event),
417                           NULL);
418         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
419
420         /* Mail Operation Queue */
421         g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
422                           "queue-changed",
423                           G_CALLBACK (on_queue_changed),
424                           self);
425
426         /* Track changes in the device name */
427         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
428                           "key_changed",
429                           G_CALLBACK (on_configuration_key_changed), 
430                           self);
431
432         /* Track account changes. We need to refresh the toolbar */
433         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
434                           "account_update",
435                           G_CALLBACK (on_account_update),
436                           self);
437
438         /* Account store */
439         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), "password_requested",
440                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
441                           
442         /* Device */
443         g_signal_connect (G_OBJECT(modest_runtime_get_device()), "connection_changed",
444                           G_CALLBACK(on_connection_changed), self);
445 }
446
447 /** Idle handler, to send/receive at startup .*/
448 gboolean
449 sync_accounts_cb (ModestMainWindow *win)
450 {
451         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
452         return FALSE; /* Do not call this idle handler again. */
453 }
454
455 static void on_hildon_program_is_topmost_notify(GObject *self,
456         GParamSpec *propert_param, gpointer user_data)
457 {
458         HildonProgram *app = HILDON_PROGRAM (self);
459         
460         /*
461         ModestWindow* self = MODEST_WINDOW(user_data);
462         */
463         
464         /* Note that use of hildon_program_set_can_hibernate() 
465          * is generally referred to as "setting the killable flag", 
466          * though hibernation does not seem equal to death.
467          * murrayc */
468                  
469         if (hildon_program_get_is_topmost (app)) {
470                 /* Prevent hibernation when the progam comes to the foreground,
471                  * because hibernation should only happen when the application 
472                  * is in the background: */
473                 hildon_program_set_can_hibernate (app, FALSE);
474         } else {
475                 /* Allow hibernation if the program has gone to the background: */
476                 
477                 /* However, prevent hibernation while the settings are being changed: */
478                 const gboolean hibernation_prevented = 
479                         modest_window_mgr_get_hibernation_is_prevented (
480         modest_runtime_get_window_mgr ()); 
481         
482                 if (hibernation_prevented)
483                         hildon_program_set_can_hibernate (app, FALSE);
484                 else {
485                         /* Allow hibernation, after saving the state: */
486                         modest_osso_save_state();
487                         hildon_program_set_can_hibernate (app, TRUE);
488                 }
489         }
490         
491 }
492
493
494
495 ModestWindow*
496 modest_main_window_new (void)
497 {
498         ModestMainWindow *self; 
499         ModestMainWindowPrivate *priv;
500         ModestWindowPrivate *parent_priv;
501         GtkWidget *folder_win;
502         GtkActionGroup *action_group;
503         GError *error = NULL;
504         TnyFolderStoreQuery *query;
505         GdkPixbuf *window_icon;
506         ModestConf *conf;
507         GtkAction *action;
508
509         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
510         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
511         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
512
513         parent_priv->ui_manager = gtk_ui_manager_new();
514         action_group = gtk_action_group_new ("ModestMainWindowActions");
515         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
516
517         /* Add common actions */
518         gtk_action_group_add_actions (action_group,
519                                       modest_action_entries,
520                                       G_N_ELEMENTS (modest_action_entries),
521                                       self);
522
523         gtk_action_group_add_actions (action_group,
524                                       modest_folder_view_action_entries,
525                                       G_N_ELEMENTS (modest_folder_view_action_entries),
526                                       self);
527
528         gtk_action_group_add_toggle_actions (action_group,
529                                              modest_toggle_action_entries,
530                                              G_N_ELEMENTS (modest_toggle_action_entries),
531                                              self);
532
533         gtk_action_group_add_toggle_actions (action_group,
534                                              modest_main_window_toggle_action_entries,
535                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
536                                              self);
537
538         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
539         g_object_unref (action_group);
540
541         /* Load the UI definition */
542         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
543                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
544         if (error != NULL) {
545                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
546                 g_error_free (error);
547                 error = NULL;
548         }
549
550         /* Add accelerators */
551         gtk_window_add_accel_group (GTK_WINDOW (self), 
552                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
553
554         /* Menubar. Update the state of some toggles */
555         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
556         conf = modest_runtime_get_conf ();
557         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
558                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
559         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
560                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
561         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
562                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
563         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
564                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
565         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
566
567         /* Get device name */
568         modest_maemo_utils_get_device_name ();
569
570         /* folder view */
571         query = tny_folder_store_query_new ();
572         tny_folder_store_query_add_item (query, NULL,
573                                          TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
574         priv->folder_view = MODEST_FOLDER_VIEW(modest_folder_view_new (query));
575         if (!priv->folder_view)
576                 g_printerr ("modest: cannot instantiate folder view\n");
577         g_object_unref (G_OBJECT (query));
578         modest_folder_view_set_style (priv->folder_view,
579                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
580
581         /* header view */
582         priv->header_view  =
583                 MODEST_HEADER_VIEW(modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
584         if (!priv->header_view)
585                 g_printerr ("modest: cannot instantiate header view\n");
586         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
587         
588         /* Create scrolled windows */
589         folder_win = gtk_scrolled_window_new (NULL, NULL);
590         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
591         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
592                                         GTK_POLICY_NEVER,
593                                         GTK_POLICY_AUTOMATIC);
594         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
595                                         GTK_POLICY_NEVER,
596                                         GTK_POLICY_AUTOMATIC);
597
598         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
599         wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view));
600
601         /* paned */
602         priv->main_paned = gtk_hpaned_new ();
603         gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
604         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->contents_widget);
605         gtk_widget_show (GTK_WIDGET(priv->header_view));
606         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
607
608         /* putting it all together... */
609         priv->main_vbox = gtk_vbox_new (FALSE, 6);
610         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
611
612         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
613         restore_settings (MODEST_MAIN_WINDOW(self));
614
615         /* Set window icon */
616         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
617         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
618         
619         /* Connect signals */
620         connect_signals (self);
621
622         /* Set account store */
623         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
624                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
625
626         /* do send & receive when we are idle */
627         g_idle_add ((GSourceFunc)sync_accounts_cb, self);
628         
629         HildonProgram *app = hildon_program_get_instance ();
630         hildon_program_add_window (app, HILDON_WINDOW (self));
631         
632         /* Register HildonProgram  signal handlers: */
633         /* These are apparently deprecated, according to the 
634          * "HildonApp/HildonAppView to HildonProgram/HildonWindow migration guide",
635          * though the API reference does not mention that:
636          *
637         g_signal_connect (G_OBJECT(app), "topmost_status_lose",
638                 G_CALLBACK (on_hildon_program_save_state), self);
639         g_signal_connect (G_OBJECT(app), "topmost_status_acquire",
640                 G_CALLBACK (on_hildon_program_status_acquire), self);
641     */
642         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
643                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
644                 
645         /* Load previous osso state, for instance if we are being restored from 
646          * hibernation:  */
647         modest_osso_load_state();
648
649         return MODEST_WINDOW(self);
650 }
651
652 gboolean 
653 modest_main_window_close_all (ModestMainWindow *self)
654 {
655         GtkWidget *note;
656         GtkResponseType response;
657
658         /* Create the confirmation dialog MSG-NOT308 */
659         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
660                                                          _("emev_nc_close_windows"),
661                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
662                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
663                                                          NULL);
664
665         response = gtk_dialog_run (GTK_DIALOG (note));
666         gtk_widget_destroy (GTK_WIDGET (note));
667
668         if (response == GTK_RESPONSE_YES)
669                 return TRUE;
670         else
671                 return FALSE;
672 }
673
674
675 void 
676 modest_main_window_set_style (ModestMainWindow *self, 
677                               ModestMainWindowStyle style)
678 {
679         ModestMainWindowPrivate *priv;
680         ModestWindowPrivate *parent_priv;
681         GtkAction *action;
682
683         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
684
685         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
686         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
687
688         /* no change -> nothing to do */
689         if (priv->style == style)
690                 return;
691
692         /* Get toggle button */
693         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
694
695         priv->style = style;
696
697         switch (style) {
698         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
699                 /* Remove main paned */
700                 g_object_ref (priv->main_paned);
701                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
702
703                 /* Reparent the contents widget to the main vbox */
704                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
705
706                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
707                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
708                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
709
710                 break;
711         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
712                 /* Remove header view */
713                 g_object_ref (priv->contents_widget);
714                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
715
716                 /* Reparent the main paned */
717                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
718                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
719
720                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
721                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
722                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
723
724                 break;
725         default:
726                 g_return_if_reached ();
727         }
728
729         /* Let header view grab the focus if it's being shown */
730         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
731                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
732         else 
733                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
734
735         /* Show changes */
736         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
737 }
738
739 ModestMainWindowStyle
740 modest_main_window_get_style (ModestMainWindow *self)
741 {
742         ModestMainWindowPrivate *priv;
743
744         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
745
746         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
747         return priv->style;
748 }
749
750
751
752 static gboolean
753 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
754 {
755         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
756                 ModestWindowPrivate *parent_priv;
757                 ModestWindowMgr *mgr;
758                 gboolean is_fullscreen;
759                 GtkAction *fs_toggle_action;
760                 gboolean active;
761                 
762                 mgr = modest_runtime_get_window_mgr ();
763                 
764                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
765
766                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
767                 
768                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
769                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
770                 if (is_fullscreen != active) {
771                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
772                 }
773         }
774
775         return FALSE;
776
777 }
778
779 static void
780 set_homogeneous (GtkWidget *widget,
781                  gpointer data)
782 {
783         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
784         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
785 }
786
787 static void 
788 modest_main_window_show_toolbar (ModestWindow *self,
789                                  gboolean show_toolbar)
790 {
791         ModestMainWindowPrivate *priv = NULL;
792         ModestWindowPrivate *parent_priv = NULL;        
793         GtkWidget *reply_button = NULL, *menu = NULL;
794         GtkWidget *placeholder = NULL;
795         gint insert_index;
796
797         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
798         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
799         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
800
801         /* Set optimized view status */
802         priv->optimized_view = !show_toolbar;
803
804         if (!parent_priv->toolbar) {
805                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
806                                                                   "/ToolBar");
807
808                 /* Set homogeneous toolbar */
809                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
810                                        set_homogeneous, NULL);
811         
812                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
813                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
814                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
815                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
816                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
817                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
818                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
819                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
820
821                 /* Add ProgressBar (Transfer toolbar) */ 
822                 priv->progress_bar = modest_progress_bar_widget_new ();
823                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
824                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
825                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
826                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
827                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
828                 
829                 /* Connect cancel 'clicked' signal to abort progress mode */
830                 g_signal_connect(priv->cancel_toolitem, "clicked",
831                                  G_CALLBACK(cancel_progressbar),
832                                  self);
833                 
834                 /* Add it to the observers list */
835                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
836
837                 /* Add to window */
838                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
839                                            GTK_TOOLBAR (parent_priv->toolbar));
840
841                 /* Set reply button tap and hold menu */
842                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
843                                                           "/ToolBar/ToolbarMessageReply");
844                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
845                                                   "/ToolbarReplyCSM");
846                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
847
848                 /* Set send & receive button tap and hold menu */
849                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
850                                    NULL, self);
851         }
852
853         if (show_toolbar) {
854                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
855                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
856                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
857
858                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
859                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
860         } else
861                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
862
863 }
864
865 static gint
866 compare_display_names (ModestAccountData *a,
867                        ModestAccountData *b)
868 {
869         return strcmp (a->display_name, b->display_name);
870 }
871
872 static void 
873 on_account_update (TnyAccountStore *account_store, 
874                    const gchar *account_name,
875                    gpointer user_data)
876 {
877         GSList *account_names, *iter, *accounts;
878         ModestMainWindow *self;
879         ModestMainWindowPrivate *priv;
880         ModestWindowPrivate *parent_priv;
881         ModestAccountMgr *mgr;
882         gint i, num_accounts;                                   
883         GtkActionGroup *action_group;
884         GList *groups;
885         gchar *default_account;
886         GtkWidget *send_receive_button, *item;
887                 
888         self = MODEST_MAIN_WINDOW (user_data);
889         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
890         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
891
892         /* Get enabled account IDs */
893         mgr = modest_runtime_get_account_mgr ();
894         account_names = modest_account_mgr_account_names (mgr, TRUE);
895         iter = account_names;
896         accounts = NULL;
897
898         while (iter) {
899                 ModestAccountData *account_data = 
900                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
901                 accounts = g_slist_prepend (accounts, account_data);
902
903                 iter = iter->next;
904         }
905         g_slist_free (account_names);
906
907         /* Order the list of accounts by its display name */
908         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
909         num_accounts = g_slist_length (accounts);
910
911         /* Delete old send&receive popup items. We can not just do a
912            menu_detach because it does not work well with
913            tap_and_hold */
914         if (priv->accounts_popup)
915                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), (GtkCallback) gtk_widget_destroy, NULL);
916
917         /* Delete old entries in the View menu. Do not free groups, it
918            belongs to Gtk+ */
919         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
920         while (groups) {
921                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
922                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
923                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
924                                                             GTK_ACTION_GROUP (groups->data));
925                         groups = NULL;
926                         /* Remove uis */
927                         if (priv->merge_ids) {
928                                 for (i = 0; i < priv->merge_ids->len; i++)
929                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
930                                 g_byte_array_free (priv->merge_ids, TRUE);
931                         }
932                         /* We need to call this in order to ensure
933                            that the new actions are added in the right
934                            order (alphabetical */
935                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
936                 } else 
937                         groups = g_list_next (groups);
938         }
939         priv->merge_ids = g_byte_array_sized_new (num_accounts);
940
941         /* Get send receive button */
942         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
943                                                           "/ToolBar/ToolbarSendReceive");
944
945         /* Create the menu */
946         if (num_accounts > 1) {
947                 if (!priv->accounts_popup)
948                         priv->accounts_popup = gtk_menu_new ();
949                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
950                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
951                 g_signal_connect (G_OBJECT (item), 
952                                   "activate", 
953                                   G_CALLBACK (on_send_receive_csm_activated),
954                                   NULL);
955                 item = gtk_separator_menu_item_new ();
956                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
957         }
958
959         /* Create a new action group */
960         default_account = modest_account_mgr_get_default_account (mgr);
961         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
962         for (i = 0; i < num_accounts; i++) {
963                 GtkAction *new_action = NULL;
964                 gchar *display_name = NULL;
965                 
966                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
967
968                 /* Create display name. The default account is shown differently */
969                 if (default_account && account_data->account_name && 
970                         !(strcmp (default_account, account_data->account_name) == 0)) {
971                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
972                                                         account_data->display_name);
973                 }
974                 else {
975                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
976                                                         account_data->display_name);
977                 }
978
979                 /* Create action and add it to the action group. The
980                    action name must be the account name, this way we
981                    could know in the handlers the account to show */
982                 if(account_data->account_name) {
983                         new_action = gtk_action_new (account_data->account_name, display_name, NULL, NULL);
984                         gtk_action_group_add_action (action_group, new_action);
985
986                         /* Add ui from account data. We allow 2^9-1 account
987                            changes in a single execution because we're
988                            downcasting the guint to a guint8 in order to use a
989                            GByteArray, it should be enough */
990                         gchar* item_name = g_strconcat (account_data->account_name, "Menu", NULL);
991                         guint8 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
992                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
993                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
994                                                merge_id,
995                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
996                                                item_name,
997                                                account_data->account_name,
998                                                GTK_UI_MANAGER_MENUITEM,
999                                                FALSE);
1000         
1001                         /* Connect the action signal "activate" */
1002                         g_signal_connect (G_OBJECT (new_action), 
1003                                           "activate", 
1004                                           G_CALLBACK (on_show_account_action_activated), 
1005                                           self);
1006
1007                         /* Create item and add it to the send&receive CSM */
1008                         /* TODO: Why is this sometimes NULL? murrayc */
1009                         if (priv->accounts_popup) {
1010                                 item = gtk_menu_item_new_with_label (display_name);
1011                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1012                                 g_signal_connect_data (G_OBJECT (item), 
1013                                                        "activate", 
1014                                                        G_CALLBACK (on_send_receive_csm_activated),
1015                                                        g_strdup (account_data->account_name),
1016                                                        (GClosureNotify) g_free,
1017                                                        0);
1018                         }
1019                         
1020                         g_free (item_name);
1021                 }
1022
1023                 /* Frees */
1024                 g_free (display_name);
1025                 modest_account_mgr_free_account_data (mgr, account_data);
1026         }
1027         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1028
1029         if (priv->accounts_popup) {
1030                 /* Mandatory in order to view the menu contents */
1031                 gtk_widget_show_all (priv->accounts_popup);
1032
1033                 /* Setup tap_and_hold just if was not done before*/
1034                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1035                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1036         }
1037
1038         /* Frees */
1039         g_slist_free (accounts);
1040         g_free (default_account);
1041 }
1042
1043 /* 
1044  * This function manages the key events used to navigate between
1045  * header and folder views (when the window is in split view)
1046  *
1047  * FROM         KEY        ACTION
1048  * -------------------------------------------------
1049  * HeaderView   GDK_Left   Move focus to folder view
1050  * FolderView   GDK_Right  Move focus to header view
1051  *
1052  * There is no need to scroll to selected row, the widgets will be the
1053  * responsibles of doing that (probably managing the focus-in event
1054  */
1055 static gboolean 
1056 on_inner_widgets_key_pressed (GtkWidget *widget,
1057                               GdkEventKey *event,
1058                               gpointer user_data)
1059 {
1060         ModestMainWindowPrivate *priv;
1061
1062         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1063
1064         /* Do nothing if we're in SIMPLE style */
1065         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1066                 return FALSE;
1067
1068         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1069                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1070         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1071                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1072
1073         return FALSE;
1074 }
1075
1076 static void
1077 set_alignment (GtkWidget *widget,
1078                gpointer data)
1079 {
1080         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1081         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1082 }
1083
1084 static GtkWidget *
1085 create_details_widget (TnyAccount *account)
1086 {
1087         GtkWidget *vbox;
1088         gchar *label;
1089
1090         vbox = gtk_vbox_new (FALSE, 0);
1091
1092         /* Account description */
1093         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1094                 gchar *device_name;
1095
1096                 /* Get device name */
1097                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1098                                                       MODEST_CONF_DEVICE_NAME, NULL);
1099    
1100                 label = g_strdup_printf ("%s: %s",
1101                                          _("mcen_fi_localroot_description"),
1102                                          device_name);
1103                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1104                 g_free (device_name);
1105                 g_free (label);
1106         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1107                 /* TODO: MMC ? */
1108                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1109         } else {
1110                 GString *proto;
1111
1112                 /* Put proto in uppercase */
1113                 proto = g_string_new (tny_account_get_proto (account));
1114                 proto = g_string_ascii_up (proto);
1115
1116                 label = g_strdup_printf ("%s %s: %s", 
1117                                          proto->str,
1118                                          _("mcen_fi_remoteroot_account"),
1119                                          tny_account_get_name (account));
1120                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1121                 g_string_free (proto, TRUE);
1122                 g_free (label);
1123         }
1124
1125         /* Message count */
1126         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1127                                  modest_tny_account_get_message_count (account));
1128         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1129         g_free (label);
1130
1131         /* Folder count */
1132         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1133                                  modest_tny_account_get_folder_count (account));
1134         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1135         g_free (label);
1136
1137         /* Size / Date */
1138         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1139                 /* FIXME: format size */
1140                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1141                                          modest_tny_account_get_local_size (account));
1142                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1143                 g_free (label);
1144         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1145                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1146         } else {
1147                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), "08/08/08");
1148                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1149                 g_free (label);
1150         }
1151
1152         /* Set alignment */
1153         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1154
1155         return vbox;
1156 }
1157
1158 void 
1159 modest_main_window_set_contents_style (ModestMainWindow *self, 
1160                                        ModestMainWindowContentsStyle style)
1161 {
1162         ModestMainWindowPrivate *priv;
1163         GtkWidget *content;
1164         TnyAccount *account;
1165
1166         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1167
1168         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1169
1170         /* We allow to set the same content style than the previously
1171            set if there are details, because it could happen when we're
1172            selecting different accounts consecutively */
1173         if ((priv->contents_style == style) &&
1174             (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS))
1175                 return;
1176
1177         /* Remove previous child. Delete it if it was an account
1178            details widget */
1179         content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1180         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1181                 g_object_ref (content);
1182         gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1183
1184         priv->contents_style = style;
1185
1186         switch (priv->contents_style) {
1187         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1188                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1189                 break;
1190         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1191                 /* TODO: show here account details */
1192                 account = TNY_ACCOUNT (modest_folder_view_get_selected (priv->folder_view));
1193                 priv->details_widget = create_details_widget (account);
1194
1195                 wrap_in_scrolled_window (priv->contents_widget, 
1196                                          priv->details_widget);
1197                 break;
1198         default:
1199                 g_return_if_reached ();
1200         }
1201
1202         /* Show */
1203         gtk_widget_show_all (priv->contents_widget);
1204 }
1205
1206 static void 
1207 on_configuration_key_changed (ModestConf* conf, 
1208                               const gchar *key, 
1209                               ModestConfEvent event, 
1210                               ModestMainWindow *self)
1211 {
1212         ModestMainWindowPrivate *priv;
1213         TnyAccount *account;
1214
1215         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1216                 return;
1217
1218         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1219
1220         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1221                 return;
1222
1223         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1224         if (TNY_IS_ACCOUNT (account) &&
1225             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1226                 GList *children;
1227                 GtkLabel *label;
1228                 const gchar *device_name;
1229                 gchar *new_text;
1230                 
1231                 /* Get label */
1232                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1233                 label = GTK_LABEL (children->data);
1234                 
1235                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1236                                                       MODEST_CONF_DEVICE_NAME, NULL);
1237                 
1238                 new_text = g_strdup_printf ("%s: %s",
1239                                             _("mcen_fi_localroot_description"),
1240                                             device_name);
1241                 
1242                 gtk_label_set_text (label, new_text);
1243                 gtk_widget_show (GTK_WIDGET (label));
1244                 
1245                 g_free (new_text);
1246                 g_list_free (children);
1247         }
1248 }
1249
1250 static gboolean
1251 set_toolbar_transfer_mode (ModestMainWindow *self)
1252 {
1253         ModestMainWindowPrivate *priv = NULL;
1254         
1255         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1256
1257         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1258
1259         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1260         
1261         if (priv->progress_bar_timeout > 0) {
1262                 g_source_remove (priv->progress_bar_timeout);
1263                 priv->progress_bar_timeout = 0;
1264         }
1265
1266         return FALSE;
1267 }
1268
1269 static void 
1270 set_toolbar_mode (ModestMainWindow *self, 
1271                   ModestToolBarModes mode)
1272 {
1273         ModestWindowPrivate *parent_priv = NULL;
1274         ModestMainWindowPrivate *priv = NULL;
1275         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1276         
1277         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1278
1279         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1280         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1281
1282         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1283         
1284         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1285         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1286         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1287
1288         /* Sets current toolbar mode */
1289         priv->current_toolbar_mode = mode;
1290
1291         /* Show and hide toolbar items */
1292         switch (mode) {
1293         case TOOLBAR_MODE_NORMAL:
1294                 if (sort_action) 
1295                         gtk_action_set_visible (sort_action, TRUE);
1296                 if (refresh_action) 
1297                         gtk_action_set_visible (refresh_action, TRUE);
1298                 if (priv->progress_toolitem) {
1299                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1300                         gtk_widget_hide (priv->progress_toolitem);
1301                 }
1302                 if (priv->progress_bar)
1303                         gtk_widget_hide (priv->progress_bar);                   
1304                 
1305                 if (cancel_action)
1306                         gtk_action_set_visible (cancel_action, FALSE);
1307
1308                 /* Hide toolbar if optimized view is enabled */
1309                 if (priv->optimized_view)
1310                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1311                 break;
1312         case TOOLBAR_MODE_TRANSFER:
1313                 if (sort_action)
1314                         gtk_action_set_visible (sort_action, FALSE);
1315                 if (refresh_action)
1316                         gtk_action_set_visible (refresh_action, FALSE);
1317                 if (cancel_action)
1318                         gtk_action_set_visible (cancel_action, TRUE);
1319                 if (priv->progress_toolitem) {
1320                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1321                         gtk_widget_show (priv->progress_toolitem);
1322                 }
1323                 if (priv->progress_bar)
1324                         gtk_widget_show (priv->progress_bar);                   
1325
1326                 /* Show toolbar if it's hiden (optimized view ) */
1327                 if (priv->optimized_view)
1328                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1329                 break;
1330         default:
1331                 g_return_if_reached ();
1332         }
1333 }
1334
1335 static void
1336 cancel_progressbar (GtkToolButton *toolbutton,
1337                     ModestMainWindow *self)
1338 {
1339         GSList *tmp;
1340         ModestMainWindowPrivate *priv;
1341         
1342         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1343
1344         /* Get operation observers and cancel its current operation */
1345         tmp = priv->progress_widgets;
1346         while (tmp) {
1347                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1348                 tmp=g_slist_next(tmp);
1349         }
1350 }
1351
1352 static gboolean
1353 observers_empty (ModestMainWindow *self)
1354 {
1355         GSList *tmp = NULL;
1356         ModestMainWindowPrivate *priv;
1357         gboolean is_empty = TRUE;
1358         guint pending_ops = 0;
1359  
1360         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1361         tmp = priv->progress_widgets;
1362
1363         /* Check all observers */
1364         while (tmp && is_empty)  {
1365                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1366                 is_empty = pending_ops == 0;
1367                 
1368                 tmp = g_slist_next(tmp);
1369         }
1370         
1371         return is_empty;
1372 }
1373
1374 static void
1375 on_queue_changed (ModestMailOperationQueue *queue,
1376                   ModestMailOperation *mail_op,
1377                   ModestMailOperationQueueNotification type,
1378                   ModestMainWindow *self)
1379 {
1380         ModestMainWindowPrivate *priv;
1381         ModestMailOperationId op_id;
1382         ModestToolBarModes mode;
1383         GSList *tmp;
1384         gboolean mode_changed = FALSE;
1385
1386         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1387         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1388                
1389         /* Get toolbar mode from operation id*/
1390         op_id = modest_mail_operation_get_id (mail_op);
1391         switch (op_id) {
1392         case MODEST_MAIL_OPERATION_ID_SEND:
1393         case MODEST_MAIL_OPERATION_ID_RECEIVE:
1394                 mode = TOOLBAR_MODE_TRANSFER;
1395                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1396                         mode_changed = TRUE;
1397                 break;
1398         default:
1399                 mode = TOOLBAR_MODE_NORMAL;
1400                 
1401         }
1402                 
1403                        
1404         /* Add operation observers and change toolbar if neccessary*/
1405         tmp = priv->progress_widgets;
1406         switch (type) {
1407         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1408                 if (mode == TOOLBAR_MODE_TRANSFER) {
1409                         if (mode_changed)
1410                                 priv->progress_bar_timeout = g_timeout_add (2000, 
1411                                                                             (GSourceFunc) set_toolbar_transfer_mode, 
1412                                                                             self);                  
1413                         while (tmp) {
1414                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1415                                                                       mail_op);
1416                                 tmp = g_slist_next (tmp);
1417                         }
1418                 }
1419                 break;
1420         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1421                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1422                         while (tmp) {
1423                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1424                                                                          mail_op);
1425                                 tmp = g_slist_next (tmp);
1426                         }
1427                         
1428                         /* If no more operations are being observed, NORMAL mode is enabled again */
1429                         if (observers_empty (self)) {
1430                                 if (priv->progress_bar_timeout > 0) {
1431                                         g_source_remove (priv->progress_bar_timeout);
1432                                         priv->progress_bar_timeout = 0;
1433                                 }
1434                                 else 
1435                                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1436
1437                         }
1438                 }
1439                 break;
1440         }       
1441 }
1442
1443 static void 
1444 on_show_account_action_activated  (GtkAction *action,
1445                                    gpointer user_data)
1446 {
1447         ModestAccountData *acc_data;
1448         ModestMainWindow *self;
1449         ModestMainWindowPrivate *priv;
1450         ModestAccountMgr *mgr;
1451         const gchar *acc_name;
1452
1453         self = MODEST_MAIN_WINDOW (user_data);
1454         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1455
1456         /* Get account data */
1457         acc_name = gtk_action_get_name (action);
1458         mgr = modest_runtime_get_account_mgr ();
1459         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1460
1461         /* Set the new visible & active account */
1462         if (acc_data->store_account) { 
1463                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1464                                                                              acc_data->store_account->account_name);
1465         }
1466
1467         /* Free */
1468         modest_account_mgr_free_account_data (mgr, acc_data);
1469 }
1470
1471 static void
1472 on_send_receive_csm_activated (GtkMenuItem *item,
1473                                gpointer user_data)
1474 {
1475         ModestWindow *win;
1476
1477         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1478
1479         /* If user_data == NULL, we must update all (CSM option All) */
1480         if (!user_data) {
1481                 modest_ui_actions_do_send_receive_all (win);
1482         } else {
1483                 modest_ui_actions_do_send_receive ((const gchar *)user_data, win);
1484         }
1485 }