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