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