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