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