2007-05-16 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_connection_changed (TnyDevice *device, gboolean online, 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         if (online) {
376                 modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
377         }
378 }
379
380
381
382 static void
383 connect_signals (ModestMainWindow *self)
384 {       
385         ModestWindowPrivate *parent_priv;
386         ModestMainWindowPrivate *priv;
387         GtkWidget *menu;
388         
389         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
390         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
391         
392         /* folder view */
393         g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
394                           G_CALLBACK(on_inner_widgets_key_pressed), self);
395         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
396                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
397         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
398                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
399
400         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
401         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
402
403         /* header view */
404 /*      g_signal_connect (G_OBJECT(priv->header_view), "status_update", */
405 /*                        G_CALLBACK(modest_ui_actions_on_header_status_update), self); */
406         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
407                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
408         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
409                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
410         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
411                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
412         g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
413                           G_CALLBACK(on_inner_widgets_key_pressed), self);
414
415         /* window */
416         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
417         g_signal_connect (G_OBJECT (self), "window-state-event",
418                           G_CALLBACK (modest_main_window_window_state_event),
419                           NULL);
420         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
421
422         /* Mail Operation Queue */
423         g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
424                           "queue-changed",
425                           G_CALLBACK (on_queue_changed),
426                           self);
427
428         /* Track changes in the device name */
429         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
430                           "key_changed",
431                           G_CALLBACK (on_configuration_key_changed), 
432                           self);
433
434         /* Track account changes. We need to refresh the toolbar */
435         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
436                           "account_update",
437                           G_CALLBACK (on_account_update),
438                           self);
439
440         /* Account store */
441         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), "password_requested",
442                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
443                           
444         /* Device */
445         g_signal_connect (G_OBJECT(modest_runtime_get_device()), "connection_changed",
446                           G_CALLBACK(on_connection_changed), self);
447 }
448
449 /** Idle handler, to send/receive at startup .*/
450 gboolean
451 sync_accounts_cb (ModestMainWindow *win)
452 {
453         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
454         return FALSE; /* Do not call this idle handler again. */
455 }
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         g_idle_add ((GSourceFunc)sync_accounts_cb, self);
630         
631         HildonProgram *app = hildon_program_get_instance ();
632         hildon_program_add_window (app, HILDON_WINDOW (self));
633         
634         /* Register HildonProgram  signal handlers: */
635         /* These are apparently deprecated, according to the 
636          * "HildonApp/HildonAppView to HildonProgram/HildonWindow migration guide",
637          * though the API reference does not mention that:
638          *
639         g_signal_connect (G_OBJECT(app), "topmost_status_lose",
640                 G_CALLBACK (on_hildon_program_save_state), self);
641         g_signal_connect (G_OBJECT(app), "topmost_status_acquire",
642                 G_CALLBACK (on_hildon_program_status_acquire), self);
643     */
644         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
645                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
646                 
647         /* Load previous osso state, for instance if we are being restored from 
648          * hibernation:  */
649         modest_osso_load_state();
650
651         return MODEST_WINDOW(self);
652 }
653
654 gboolean 
655 modest_main_window_close_all (ModestMainWindow *self)
656 {
657         GtkWidget *note;
658         GtkResponseType response;
659
660         /* Create the confirmation dialog MSG-NOT308 */
661         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
662                                                          _("emev_nc_close_windows"),
663                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
664                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
665                                                          NULL);
666
667         response = gtk_dialog_run (GTK_DIALOG (note));
668         gtk_widget_destroy (GTK_WIDGET (note));
669
670         if (response == GTK_RESPONSE_YES)
671                 return TRUE;
672         else
673                 return FALSE;
674 }
675
676
677 void 
678 modest_main_window_set_style (ModestMainWindow *self, 
679                               ModestMainWindowStyle style)
680 {
681         ModestMainWindowPrivate *priv;
682         ModestWindowPrivate *parent_priv;
683         GtkAction *action;
684
685         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
686
687         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
688         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
689
690         /* no change -> nothing to do */
691         if (priv->style == style)
692                 return;
693
694         /* Get toggle button */
695         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
696
697         priv->style = style;
698
699         switch (style) {
700         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
701                 /* Remove main paned */
702                 g_object_ref (priv->main_paned);
703                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
704
705                 /* Reparent the contents widget to the main vbox */
706                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
707
708                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
709                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
710                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
711
712                 break;
713         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
714                 /* Remove header view */
715                 g_object_ref (priv->contents_widget);
716                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
717
718                 /* Reparent the main paned */
719                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
720                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
721
722                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
723                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
724                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
725
726                 break;
727         default:
728                 g_return_if_reached ();
729         }
730
731         /* Let header view grab the focus if it's being shown */
732         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
733                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
734         else 
735                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
736
737         /* Show changes */
738         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
739 }
740
741 ModestMainWindowStyle
742 modest_main_window_get_style (ModestMainWindow *self)
743 {
744         ModestMainWindowPrivate *priv;
745
746         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
747
748         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
749         return priv->style;
750 }
751
752
753
754 static gboolean
755 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
756 {
757         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
758                 ModestWindowPrivate *parent_priv;
759                 ModestWindowMgr *mgr;
760                 gboolean is_fullscreen;
761                 GtkAction *fs_toggle_action;
762                 gboolean active;
763                 
764                 mgr = modest_runtime_get_window_mgr ();
765                 
766                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
767
768                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
769                 
770                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
771                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
772                 if (is_fullscreen != active) {
773                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
774                 }
775         }
776
777         return FALSE;
778
779 }
780
781 static void
782 set_homogeneous (GtkWidget *widget,
783                  gpointer data)
784 {
785         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
786         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
787 }
788
789 static void 
790 modest_main_window_show_toolbar (ModestWindow *self,
791                                  gboolean show_toolbar)
792 {
793         ModestMainWindowPrivate *priv = NULL;
794         ModestWindowPrivate *parent_priv = NULL;        
795         GtkWidget *reply_button = NULL, *menu = NULL;
796         GtkWidget *placeholder = NULL;
797         gint insert_index;
798
799         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
800         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
801         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
802
803         /* Set optimized view status */
804         priv->optimized_view = !show_toolbar;
805
806         if (!parent_priv->toolbar) {
807                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
808                                                                   "/ToolBar");
809
810                 /* Set homogeneous toolbar */
811                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
812                                        set_homogeneous, NULL);
813         
814                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
815                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
816                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
817                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
818                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
819                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
820                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
821                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
822
823                 /* Add ProgressBar (Transfer toolbar) */ 
824                 priv->progress_bar = modest_progress_bar_widget_new ();
825                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
826                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
827                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
828                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
829                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
830                 
831                 /* Connect cancel 'clicked' signal to abort progress mode */
832                 g_signal_connect(priv->cancel_toolitem, "clicked",
833                                  G_CALLBACK(cancel_progressbar),
834                                  self);
835                 
836                 /* Add it to the observers list */
837                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
838
839                 /* Add to window */
840                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
841                                            GTK_TOOLBAR (parent_priv->toolbar));
842
843                 /* Set reply button tap and hold menu */
844                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
845                                                           "/ToolBar/ToolbarMessageReply");
846                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
847                                                   "/ToolbarReplyCSM");
848                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
849
850                 /* Set send & receive button tap and hold menu */
851                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
852                                    NULL, self);
853         }
854
855         if (show_toolbar) {
856                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
857                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
858                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
859
860                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
861                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
862         } else
863                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
864
865 }
866
867 static gint
868 compare_display_names (ModestAccountData *a,
869                        ModestAccountData *b)
870 {
871         return strcmp (a->display_name, b->display_name);
872 }
873
874 static void 
875 on_account_update (TnyAccountStore *account_store, 
876                    const gchar *account_name,
877                    gpointer user_data)
878 {
879         GSList *account_names, *iter, *accounts;
880         ModestMainWindow *self;
881         ModestMainWindowPrivate *priv;
882         ModestWindowPrivate *parent_priv;
883         ModestAccountMgr *mgr;
884         gint i, num_accounts;                                   
885         GtkActionGroup *action_group;
886         GList *groups;
887         gchar *default_account;
888         GtkWidget *send_receive_button, *item;
889                 
890         self = MODEST_MAIN_WINDOW (user_data);
891         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
892         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
893
894         /* Get enabled account IDs */
895         mgr = modest_runtime_get_account_mgr ();
896         account_names = modest_account_mgr_account_names (mgr, TRUE);
897         iter = account_names;
898         accounts = NULL;
899
900         while (iter) {
901                 ModestAccountData *account_data = 
902                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
903                 accounts = g_slist_prepend (accounts, account_data);
904
905                 iter = iter->next;
906         }
907         g_slist_free (account_names);
908
909         /* Order the list of accounts by its display name */
910         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
911         num_accounts = g_slist_length (accounts);
912
913         /* Delete old send&receive popup items. We can not just do a
914            menu_detach because it does not work well with
915            tap_and_hold */
916         if (priv->accounts_popup)
917                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), (GtkCallback) gtk_widget_destroy, NULL);
918
919         /* Delete old entries in the View menu. Do not free groups, it
920            belongs to Gtk+ */
921         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
922         while (groups) {
923                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
924                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
925                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
926                                                             GTK_ACTION_GROUP (groups->data));
927                         groups = NULL;
928                         /* Remove uis */
929                         if (priv->merge_ids) {
930                                 for (i = 0; i < priv->merge_ids->len; i++)
931                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
932                                 g_byte_array_free (priv->merge_ids, TRUE);
933                         }
934                         /* We need to call this in order to ensure
935                            that the new actions are added in the right
936                            order (alphabetical */
937                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
938                 } else 
939                         groups = g_list_next (groups);
940         }
941         priv->merge_ids = g_byte_array_sized_new (num_accounts);
942
943         /* Get send receive button */
944         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
945                                                           "/ToolBar/ToolbarSendReceive");
946
947         /* Create the menu */
948         if (num_accounts > 1) {
949                 if (!priv->accounts_popup)
950                         priv->accounts_popup = gtk_menu_new ();
951                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
952                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
953                 g_signal_connect (G_OBJECT (item), 
954                                   "activate", 
955                                   G_CALLBACK (on_send_receive_csm_activated),
956                                   NULL);
957                 item = gtk_separator_menu_item_new ();
958                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
959         }
960
961         /* Create a new action group */
962         default_account = modest_account_mgr_get_default_account (mgr);
963         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
964         for (i = 0; i < num_accounts; i++) {
965                 GtkAction *new_action = NULL;
966                 gchar *display_name = NULL;
967                 
968                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
969
970                 /* Create display name. The default account is shown differently */
971                 if (default_account && account_data->account_name && 
972                         !(strcmp (default_account, account_data->account_name) == 0)) {
973                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
974                                                         account_data->display_name);
975                 }
976                 else {
977                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
978                                                         account_data->display_name);
979                 }
980
981                 /* Create action and add it to the action group. The
982                    action name must be the account name, this way we
983                    could know in the handlers the account to show */
984                 if(account_data->account_name) {
985                         new_action = gtk_action_new (account_data->account_name, display_name, NULL, NULL);
986                         gtk_action_group_add_action (action_group, new_action);
987
988                         /* Add ui from account data. We allow 2^9-1 account
989                            changes in a single execution because we're
990                            downcasting the guint to a guint8 in order to use a
991                            GByteArray, it should be enough */
992                         gchar* item_name = g_strconcat (account_data->account_name, "Menu", NULL);
993                         guint8 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
994                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
995                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
996                                                merge_id,
997                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
998                                                item_name,
999                                                account_data->account_name,
1000                                                GTK_UI_MANAGER_MENUITEM,
1001                                                FALSE);
1002         
1003                         /* Connect the action signal "activate" */
1004                         g_signal_connect (G_OBJECT (new_action), 
1005                                           "activate", 
1006                                           G_CALLBACK (on_show_account_action_activated), 
1007                                           self);
1008
1009                         /* Create item and add it to the send&receive CSM */
1010                         /* TODO: Why is this sometimes NULL? murrayc */
1011                         if (priv->accounts_popup) {
1012                                 item = gtk_menu_item_new_with_label (display_name);
1013                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1014                                 g_signal_connect_data (G_OBJECT (item), 
1015                                                        "activate", 
1016                                                        G_CALLBACK (on_send_receive_csm_activated),
1017                                                        g_strdup (account_data->account_name),
1018                                                        (GClosureNotify) g_free,
1019                                                        0);
1020                         }
1021                         
1022                         g_free (item_name);
1023                 }
1024
1025                 /* Frees */
1026                 g_free (display_name);
1027                 modest_account_mgr_free_account_data (mgr, account_data);
1028         }
1029         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1030
1031         if (priv->accounts_popup) {
1032                 /* Mandatory in order to view the menu contents */
1033                 gtk_widget_show_all (priv->accounts_popup);
1034
1035                 /* Setup tap_and_hold just if was not done before*/
1036                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1037                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1038         }
1039
1040         /* Frees */
1041         g_slist_free (accounts);
1042         g_free (default_account);
1043 }
1044
1045 /* 
1046  * This function manages the key events used to navigate between
1047  * header and folder views (when the window is in split view)
1048  *
1049  * FROM         KEY        ACTION
1050  * -------------------------------------------------
1051  * HeaderView   GDK_Left   Move focus to folder view
1052  * FolderView   GDK_Right  Move focus to header view
1053  *
1054  * There is no need to scroll to selected row, the widgets will be the
1055  * responsibles of doing that (probably managing the focus-in event
1056  */
1057 static gboolean 
1058 on_inner_widgets_key_pressed (GtkWidget *widget,
1059                               GdkEventKey *event,
1060                               gpointer user_data)
1061 {
1062         ModestMainWindowPrivate *priv;
1063
1064         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1065
1066         /* Do nothing if we're in SIMPLE style */
1067         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1068                 return FALSE;
1069
1070         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1071                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1072         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1073                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1074
1075         return FALSE;
1076 }
1077
1078 static void
1079 set_alignment (GtkWidget *widget,
1080                gpointer data)
1081 {
1082         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1083         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1084 }
1085
1086 static GtkWidget *
1087 create_details_widget (TnyAccount *account)
1088 {
1089         GtkWidget *vbox;
1090         gchar *label;
1091
1092         vbox = gtk_vbox_new (FALSE, 0);
1093
1094         /* Account description */
1095         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1096                 gchar *device_name;
1097
1098                 /* Get device name */
1099                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1100                                                       MODEST_CONF_DEVICE_NAME, NULL);
1101    
1102                 label = g_strdup_printf ("%s: %s",
1103                                          _("mcen_fi_localroot_description"),
1104                                          device_name);
1105                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1106                 g_free (device_name);
1107                 g_free (label);
1108         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1109                 /* TODO: MMC ? */
1110                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1111         } else {
1112                 GString *proto;
1113
1114                 /* Put proto in uppercase */
1115                 proto = g_string_new (tny_account_get_proto (account));
1116                 proto = g_string_ascii_up (proto);
1117
1118                 label = g_strdup_printf ("%s %s: %s", 
1119                                          proto->str,
1120                                          _("mcen_fi_remoteroot_account"),
1121                                          tny_account_get_name (account));
1122                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1123                 g_string_free (proto, TRUE);
1124                 g_free (label);
1125         }
1126
1127         /* Message count */
1128         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1129                                  modest_tny_account_get_message_count (account));
1130         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1131         g_free (label);
1132
1133         /* Folder count */
1134         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1135                                  modest_tny_account_get_folder_count (account));
1136         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1137         g_free (label);
1138
1139         /* Size / Date */
1140         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1141                 /* FIXME: format size */
1142                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1143                                          modest_tny_account_get_local_size (account));
1144                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1145                 g_free (label);
1146         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1147                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1148         } else {
1149                 time_t last_updated;
1150                 gchar *last_updated_string;
1151                 /* Get last updated from configuration */
1152                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1153                                                           tny_account_get_id (account), 
1154                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1155                                                           TRUE);
1156                 if (last_updated > 0) 
1157                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1158                 else
1159                         last_updated_string = g_strdup (_("FIXME: Never"));
1160
1161                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1162                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1163                 g_free (last_updated_string);
1164                 g_free (label);
1165         }
1166
1167         /* Set alignment */
1168         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1169
1170         return vbox;
1171 }
1172
1173 void 
1174 modest_main_window_set_contents_style (ModestMainWindow *self, 
1175                                        ModestMainWindowContentsStyle style)
1176 {
1177         ModestMainWindowPrivate *priv;
1178         GtkWidget *content;
1179         TnyAccount *account;
1180
1181         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1182
1183         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1184
1185         /* We allow to set the same content style than the previously
1186            set if there are details, because it could happen when we're
1187            selecting different accounts consecutively */
1188         if ((priv->contents_style == style) &&
1189             (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS))
1190                 return;
1191
1192         /* Remove previous child. Delete it if it was an account
1193            details widget */
1194         content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1195         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1196                 g_object_ref (content);
1197         gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1198
1199         priv->contents_style = style;
1200
1201         switch (priv->contents_style) {
1202         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1203                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1204                 break;
1205         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1206                 /* TODO: show here account details */
1207                 account = TNY_ACCOUNT (modest_folder_view_get_selected (priv->folder_view));
1208                 priv->details_widget = create_details_widget (account);
1209
1210                 wrap_in_scrolled_window (priv->contents_widget, 
1211                                          priv->details_widget);
1212                 break;
1213         default:
1214                 g_return_if_reached ();
1215         }
1216
1217         /* Show */
1218         gtk_widget_show_all (priv->contents_widget);
1219 }
1220
1221 static void 
1222 on_configuration_key_changed (ModestConf* conf, 
1223                               const gchar *key, 
1224                               ModestConfEvent event, 
1225                               ModestMainWindow *self)
1226 {
1227         ModestMainWindowPrivate *priv;
1228         TnyAccount *account;
1229
1230         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1231                 return;
1232
1233         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1234
1235         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1236                 return;
1237
1238         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1239         if (TNY_IS_ACCOUNT (account) &&
1240             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1241                 GList *children;
1242                 GtkLabel *label;
1243                 const gchar *device_name;
1244                 gchar *new_text;
1245                 
1246                 /* Get label */
1247                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1248                 label = GTK_LABEL (children->data);
1249                 
1250                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1251                                                       MODEST_CONF_DEVICE_NAME, NULL);
1252                 
1253                 new_text = g_strdup_printf ("%s: %s",
1254                                             _("mcen_fi_localroot_description"),
1255                                             device_name);
1256                 
1257                 gtk_label_set_text (label, new_text);
1258                 gtk_widget_show (GTK_WIDGET (label));
1259                 
1260                 g_free (new_text);
1261                 g_list_free (children);
1262         }
1263 }
1264
1265 static gboolean
1266 set_toolbar_transfer_mode (ModestMainWindow *self)
1267 {
1268         ModestMainWindowPrivate *priv = NULL;
1269         
1270         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1271
1272         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1273
1274         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1275         
1276         if (priv->progress_bar_timeout > 0) {
1277                 g_source_remove (priv->progress_bar_timeout);
1278                 priv->progress_bar_timeout = 0;
1279         }
1280
1281         return FALSE;
1282 }
1283
1284 static void 
1285 set_toolbar_mode (ModestMainWindow *self, 
1286                   ModestToolBarModes mode)
1287 {
1288         ModestWindowPrivate *parent_priv = NULL;
1289         ModestMainWindowPrivate *priv = NULL;
1290         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1291         
1292         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1293
1294         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1295         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1296
1297         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1298         
1299         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1300         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1301         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1302
1303         /* Sets current toolbar mode */
1304         priv->current_toolbar_mode = mode;
1305
1306         /* Show and hide toolbar items */
1307         switch (mode) {
1308         case TOOLBAR_MODE_NORMAL:
1309                 if (sort_action) 
1310                         gtk_action_set_visible (sort_action, TRUE);
1311                 if (refresh_action) 
1312                         gtk_action_set_visible (refresh_action, TRUE);
1313                 if (priv->progress_toolitem) {
1314                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1315                         gtk_widget_hide (priv->progress_toolitem);
1316                 }
1317                 if (priv->progress_bar)
1318                         gtk_widget_hide (priv->progress_bar);                   
1319                 
1320                 if (cancel_action)
1321                         gtk_action_set_visible (cancel_action, FALSE);
1322
1323                 /* Hide toolbar if optimized view is enabled */
1324                 if (priv->optimized_view)
1325                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1326                 break;
1327         case TOOLBAR_MODE_TRANSFER:
1328                 if (sort_action)
1329                         gtk_action_set_visible (sort_action, FALSE);
1330                 if (refresh_action)
1331                         gtk_action_set_visible (refresh_action, FALSE);
1332                 if (cancel_action)
1333                         gtk_action_set_visible (cancel_action, TRUE);
1334                 if (priv->progress_toolitem) {
1335                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1336                         gtk_widget_show (priv->progress_toolitem);
1337                 }
1338                 if (priv->progress_bar)
1339                         gtk_widget_show (priv->progress_bar);                   
1340
1341                 /* Show toolbar if it's hiden (optimized view ) */
1342                 if (priv->optimized_view)
1343                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1344                 break;
1345         default:
1346                 g_return_if_reached ();
1347         }
1348 }
1349
1350 static void
1351 cancel_progressbar (GtkToolButton *toolbutton,
1352                     ModestMainWindow *self)
1353 {
1354         GSList *tmp;
1355         ModestMainWindowPrivate *priv;
1356         
1357         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1358
1359         /* Get operation observers and cancel its current operation */
1360         tmp = priv->progress_widgets;
1361         while (tmp) {
1362                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1363                 tmp=g_slist_next(tmp);
1364         }
1365 }
1366
1367 static gboolean
1368 observers_empty (ModestMainWindow *self)
1369 {
1370         GSList *tmp = NULL;
1371         ModestMainWindowPrivate *priv;
1372         gboolean is_empty = TRUE;
1373         guint pending_ops = 0;
1374  
1375         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1376         tmp = priv->progress_widgets;
1377
1378         /* Check all observers */
1379         while (tmp && is_empty)  {
1380                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1381                 is_empty = pending_ops == 0;
1382                 
1383                 tmp = g_slist_next(tmp);
1384         }
1385         
1386         return is_empty;
1387 }
1388
1389 static void
1390 on_queue_changed (ModestMailOperationQueue *queue,
1391                   ModestMailOperation *mail_op,
1392                   ModestMailOperationQueueNotification type,
1393                   ModestMainWindow *self)
1394 {
1395         ModestMainWindowPrivate *priv;
1396         ModestMailOperationId op_id;
1397         ModestToolBarModes mode;
1398         GSList *tmp;
1399         gboolean mode_changed = FALSE;
1400
1401         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1402         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1403                
1404         /* Get toolbar mode from operation id*/
1405         op_id = modest_mail_operation_get_id (mail_op);
1406         switch (op_id) {
1407         case MODEST_MAIL_OPERATION_ID_SEND:
1408         case MODEST_MAIL_OPERATION_ID_RECEIVE:
1409                 mode = TOOLBAR_MODE_TRANSFER;
1410                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1411                         mode_changed = TRUE;
1412                 break;
1413         default:
1414                 mode = TOOLBAR_MODE_NORMAL;
1415                 
1416         }
1417                 
1418                        
1419         /* Add operation observers and change toolbar if neccessary*/
1420         tmp = priv->progress_widgets;
1421         switch (type) {
1422         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1423                 if (mode == TOOLBAR_MODE_TRANSFER) {
1424                         if (mode_changed)
1425                                 set_toolbar_transfer_mode(self);                    
1426                         while (tmp) {
1427                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1428                                                                       mail_op);
1429                                 tmp = g_slist_next (tmp);
1430                         }
1431                 }
1432                 break;
1433         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1434                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1435                         while (tmp) {
1436                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1437                                                                          mail_op);
1438                                 tmp = g_slist_next (tmp);
1439                         }
1440                         
1441                         /* If no more operations are being observed, NORMAL mode is enabled again */
1442                         if (observers_empty (self)) {
1443                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1444                                 
1445                         }
1446                 }
1447                 break;
1448         }       
1449 }
1450
1451 static void 
1452 on_show_account_action_activated  (GtkAction *action,
1453                                    gpointer user_data)
1454 {
1455         ModestAccountData *acc_data;
1456         ModestMainWindow *self;
1457         ModestMainWindowPrivate *priv;
1458         ModestAccountMgr *mgr;
1459         const gchar *acc_name;
1460
1461         self = MODEST_MAIN_WINDOW (user_data);
1462         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1463
1464         /* Get account data */
1465         acc_name = gtk_action_get_name (action);
1466         mgr = modest_runtime_get_account_mgr ();
1467         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1468
1469         /* Set the new visible & active account */
1470         if (acc_data->store_account) { 
1471                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1472                                                                              acc_data->store_account->account_name);
1473                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1474         }
1475
1476         /* Free */
1477         modest_account_mgr_free_account_data (mgr, acc_data);
1478 }
1479
1480 static void
1481 on_send_receive_csm_activated (GtkMenuItem *item,
1482                                gpointer user_data)
1483 {
1484         ModestWindow *win;
1485
1486         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1487
1488         /* If user_data == NULL, we must update all (CSM option All) */
1489         if (!user_data) {
1490                 modest_ui_actions_do_send_receive_all (win);
1491         } else {
1492                 modest_ui_actions_do_send_receive ((const gchar *)user_data, win);
1493         }
1494 }