* modest-mail-operation.c:
[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), TRUE);
806                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
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 = NULL;
953                 gchar *display_name = NULL;
954                 
955                 account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
956
957                 /* Create display name. The default account is shown differently */
958                 if (default_account && account_data->account_name && 
959                         !(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                 }
963                 else {
964                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
965                                                         account_data->display_name);
966                 }
967
968                 /* Create action and add it to the action group. The
969                    action name must be the account name, this way we
970                    could know in the handlers the account to show */
971                 if(account_data->account_name) {
972                         new_action = gtk_action_new (account_data->account_name, display_name, NULL, NULL);
973                         gtk_action_group_add_action (action_group, new_action);
974
975                         /* Add ui from account data. We allow 2^9-1 account
976                            changes in a single execution because we're
977                            downcasting the guint to a guint8 in order to use a
978                            GByteArray, it should be enough */
979                         gchar* item_name = g_strconcat (account_data->account_name, "Menu");
980                         guint8 merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
981                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
982                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
983                                                merge_id,
984                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
985                                                item_name,
986                                                account_data->account_name,
987                                                GTK_UI_MANAGER_MENUITEM,
988                                                FALSE);
989         
990                         /* Connect the action signal "activate" */
991                         g_signal_connect (G_OBJECT (new_action), 
992                                           "activate", 
993                                           G_CALLBACK (on_show_account_action_activated), 
994                                           self);
995
996                         /* Create item and add it to the send&receive CSM */
997                         /* TODO: Why is this sometimes NULL? murrayc */
998                         if (priv->accounts_popup) {
999                                 item = gtk_menu_item_new_with_label (display_name);
1000                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1001                                 g_signal_connect_data (G_OBJECT (item), 
1002                                                        "activate", 
1003                                                        G_CALLBACK (on_send_receive_csm_activated),
1004                                                        g_strdup (account_data->account_name),
1005                                                        (GClosureNotify) g_free,
1006                                                        0);
1007                         }
1008                         
1009                         g_free (item_name);
1010                 }
1011
1012                 /* Frees */
1013                 g_free (display_name);
1014                 modest_account_mgr_free_account_data (mgr, account_data);
1015         }
1016         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1017
1018         if (priv->accounts_popup) {
1019                 /* Mandatory in order to view the menu contents */
1020                 gtk_widget_show_all (priv->accounts_popup);
1021
1022                 /* Setup tap_and_hold just if was not done before*/
1023                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1024                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1025         }
1026
1027         /* Frees */
1028         g_slist_free (accounts);
1029         g_free (default_account);
1030 }
1031
1032 /* 
1033  * This function manages the key events used to navigate between
1034  * header and folder views (when the window is in split view)
1035  *
1036  * FROM         KEY        ACTION
1037  * -------------------------------------------------
1038  * HeaderView   GDK_Left   Move focus to folder view
1039  * FolderView   GDK_Right  Move focus to header view
1040  *
1041  * There is no need to scroll to selected row, the widgets will be the
1042  * responsibles of doing that (probably managing the focus-in event
1043  */
1044 static gboolean 
1045 on_inner_widgets_key_pressed (GtkWidget *widget,
1046                               GdkEventKey *event,
1047                               gpointer user_data)
1048 {
1049         ModestMainWindowPrivate *priv;
1050
1051         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1052
1053         /* Do nothing if we're in SIMPLE style */
1054         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1055                 return FALSE;
1056
1057         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1058                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1059         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1060                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1061
1062         return FALSE;
1063 }
1064
1065 static void
1066 set_alignment (GtkWidget *widget,
1067                gpointer data)
1068 {
1069         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1070         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1071 }
1072
1073 static GtkWidget *
1074 create_details_widget (TnyAccount *account)
1075 {
1076         GtkWidget *vbox;
1077         gchar *label;
1078
1079         vbox = gtk_vbox_new (FALSE, 0);
1080
1081         /* Account description */
1082         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1083                 gchar *device_name;
1084
1085                 /* Get device name */
1086                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1087                                                       MODEST_CONF_DEVICE_NAME, NULL);
1088    
1089                 label = g_strdup_printf ("%s: %s",
1090                                          _("mcen_fi_localroot_description"),
1091                                          device_name);
1092                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1093                 g_free (device_name);
1094                 g_free (label);
1095         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1096                 /* TODO: MMC ? */
1097                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1098         } else {
1099                 GString *proto;
1100
1101                 /* Put proto in uppercase */
1102                 proto = g_string_new (tny_account_get_proto (account));
1103                 proto = g_string_ascii_up (proto);
1104
1105                 label = g_strdup_printf ("%s %s: %s", 
1106                                          proto->str,
1107                                          _("mcen_fi_remoteroot_account"),
1108                                          tny_account_get_name (account));
1109                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1110                 g_string_free (proto, TRUE);
1111                 g_free (label);
1112         }
1113
1114         /* Message count */
1115         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1116                                  modest_tny_account_get_message_count (account));
1117         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1118         g_free (label);
1119
1120         /* Folder count */
1121         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1122                                  modest_tny_account_get_folder_count (account));
1123         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1124         g_free (label);
1125
1126         /* Size / Date */
1127         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1128                 /* FIXME: format size */
1129                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1130                                          modest_tny_account_get_local_size (account));
1131                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1132                 g_free (label);
1133         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1134                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1135         } else {
1136                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), "08/08/08");
1137                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1138                 g_free (label);
1139         }
1140
1141         /* Set alignment */
1142         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1143
1144         return vbox;
1145 }
1146
1147 void 
1148 modest_main_window_set_contents_style (ModestMainWindow *self, 
1149                                        ModestMainWindowContentsStyle style)
1150 {
1151         ModestMainWindowPrivate *priv;
1152         GtkWidget *content;
1153         TnyAccount *account;
1154
1155         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1156
1157         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1158
1159         /* We allow to set the same content style than the previously
1160            set if there are details, because it could happen when we're
1161            selecting different accounts consecutively */
1162         if ((priv->contents_style == style) &&
1163             (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS))
1164                 return;
1165
1166         /* Remove previous child. Delete it if it was an account
1167            details widget */
1168         content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1169         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1170                 g_object_ref (content);
1171         gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1172
1173         priv->contents_style = style;
1174
1175         switch (priv->contents_style) {
1176         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1177                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1178                 break;
1179         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1180                 /* TODO: show here account details */
1181                 account = TNY_ACCOUNT (modest_folder_view_get_selected (priv->folder_view));
1182                 priv->details_widget = create_details_widget (account);
1183
1184                 wrap_in_scrolled_window (priv->contents_widget, 
1185                                          priv->details_widget);
1186                 break;
1187         default:
1188                 g_return_if_reached ();
1189         }
1190
1191         /* Show */
1192         gtk_widget_show_all (priv->contents_widget);
1193 }
1194
1195 static void 
1196 on_configuration_key_changed (ModestConf* conf, 
1197                               const gchar *key, 
1198                               ModestConfEvent event, 
1199                               ModestMainWindow *self)
1200 {
1201         ModestMainWindowPrivate *priv;
1202         TnyAccount *account;
1203
1204         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1205                 return;
1206
1207         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1208
1209         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1210                 return;
1211
1212         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1213         if (TNY_IS_ACCOUNT (account) &&
1214             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1215                 GList *children;
1216                 GtkLabel *label;
1217                 const gchar *device_name;
1218                 gchar *new_text;
1219                 
1220                 /* Get label */
1221                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1222                 label = GTK_LABEL (children->data);
1223                 
1224                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1225                                                       MODEST_CONF_DEVICE_NAME, NULL);
1226                 
1227                 new_text = g_strdup_printf ("%s: %s",
1228                                             _("mcen_fi_localroot_description"),
1229                                             device_name);
1230                 
1231                 gtk_label_set_text (label, new_text);
1232                 gtk_widget_show (GTK_WIDGET (label));
1233                 
1234                 g_free (new_text);
1235                 g_list_free (children);
1236         }
1237 }
1238
1239 static void 
1240 set_toolbar_mode (ModestMainWindow *self, 
1241                   ModestToolBarModes mode)
1242 {
1243         ModestWindowPrivate *parent_priv = NULL;
1244         ModestMainWindowPrivate *priv = NULL;
1245         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1246         
1247         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1248
1249         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1250         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1251
1252         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1253         
1254         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1255         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1256         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1257
1258         /* Sets current toolbar mode */
1259         priv->current_toolbar_mode = mode;
1260
1261         /* Show and hide toolbar items */
1262         switch (mode) {
1263         case TOOLBAR_MODE_NORMAL:
1264                 if (sort_action) 
1265                         gtk_action_set_visible (sort_action, TRUE);
1266                 if (refresh_action) 
1267                         gtk_action_set_visible (refresh_action, TRUE);
1268                 if (priv->progress_toolitem) {
1269                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1270                         gtk_widget_hide (priv->progress_toolitem);
1271                 }
1272                 if (priv->progress_bar)
1273                         gtk_widget_hide (priv->progress_bar);                   
1274                 
1275                 if (cancel_action)
1276                         gtk_action_set_visible (cancel_action, FALSE);
1277
1278                 /* Hide toolbar if optimized view is enabled */
1279                 if (priv->optimized_view)
1280                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1281                 break;
1282         case TOOLBAR_MODE_TRANSFER:
1283                 if (sort_action)
1284                         gtk_action_set_visible (sort_action, FALSE);
1285                 if (refresh_action)
1286                         gtk_action_set_visible (refresh_action, FALSE);
1287                 if (cancel_action)
1288                         gtk_action_set_visible (cancel_action, TRUE);
1289                 if (priv->progress_toolitem) {
1290                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1291                         gtk_widget_show (priv->progress_toolitem);
1292                 }
1293                 if (priv->progress_bar)
1294                         gtk_widget_show (priv->progress_bar);                   
1295
1296                 /* Show toolbar if it's hiden (optimized view ) */
1297                 if (priv->optimized_view)
1298                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1299                 break;
1300         default:
1301                 g_return_if_reached ();
1302         }
1303 }
1304
1305 static void
1306 cancel_progressbar (GtkToolButton *toolbutton,
1307                     ModestMainWindow *self)
1308 {
1309         GSList *tmp;
1310         ModestMainWindowPrivate *priv;
1311         
1312         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1313
1314         /* Get operation observers and cancel its current operation */
1315         tmp = priv->progress_widgets;
1316         while (tmp) {
1317                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1318                 tmp=g_slist_next(tmp);
1319         }
1320 }
1321
1322 static gboolean
1323 observers_empty (ModestMainWindow *self)
1324 {
1325         GSList *tmp = NULL;
1326         ModestMainWindowPrivate *priv;
1327         gboolean is_empty = TRUE;
1328         guint pending_ops = 0;
1329  
1330         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1331         tmp = priv->progress_widgets;
1332
1333         /* Check all observers */
1334         while (tmp && is_empty)  {
1335                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1336                 is_empty = pending_ops == 0;
1337                 
1338                 tmp = g_slist_next(tmp);
1339         }
1340         
1341         return is_empty;
1342 }
1343
1344 static void
1345 on_queue_changed (ModestMailOperationQueue *queue,
1346                   ModestMailOperation *mail_op,
1347                   ModestMailOperationQueueNotification type,
1348                   ModestMainWindow *self)
1349 {
1350         ModestMainWindowPrivate *priv;
1351         ModestMailOperationId op_id;
1352         ModestToolBarModes mode;
1353         GSList *tmp;
1354         gboolean mode_changed = FALSE;
1355
1356         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1357         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1358                
1359         /* Get toolbar mode from operation id*/
1360         op_id = modest_mail_operation_get_id (mail_op);
1361         switch (op_id) {
1362         case MODEST_MAIL_OPERATION_ID_SEND:
1363         case MODEST_MAIL_OPERATION_ID_RECEIVE:
1364                 mode = TOOLBAR_MODE_TRANSFER;
1365                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1366                         mode_changed = TRUE;
1367                 break;
1368         default:
1369                 mode = TOOLBAR_MODE_NORMAL;
1370                 
1371         }
1372                 
1373                        
1374         /* Add operation observers and change toolbar if neccessary*/
1375         tmp = priv->progress_widgets;
1376         switch (type) {
1377         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1378                 if (mode_changed)
1379                         set_toolbar_mode (self, mode);
1380                 if (mode == TOOLBAR_MODE_TRANSFER) {
1381                         while (tmp) {
1382                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1383                                                                       mail_op);
1384                                 tmp = g_slist_next (tmp);
1385                         }
1386                 }
1387                 break;
1388         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1389                 if (mode == TOOLBAR_MODE_TRANSFER) {
1390
1391                         while (tmp) {
1392                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1393                                                                          mail_op);
1394                                 tmp = g_slist_next (tmp);
1395                         }
1396
1397                         /* If no more operations are being observed, NORMAL mode is enabled again */
1398                         if (observers_empty (self))
1399                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1400                 }
1401                 break;
1402         }       
1403 }
1404
1405 static void 
1406 on_show_account_action_activated  (GtkAction *action,
1407                                    gpointer user_data)
1408 {
1409         ModestAccountData *acc_data;
1410         ModestMainWindow *self;
1411         ModestMainWindowPrivate *priv;
1412         ModestAccountMgr *mgr;
1413         const gchar *acc_name;
1414
1415         self = MODEST_MAIN_WINDOW (user_data);
1416         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1417
1418         /* Get account data */
1419         acc_name = gtk_action_get_name (action);
1420         mgr = modest_runtime_get_account_mgr ();
1421         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1422
1423         /* Set the new visible & active account */
1424         if (acc_data->store_account) { 
1425                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1426                                                                              acc_data->store_account->account_name);
1427         }
1428
1429         /* Free */
1430         modest_account_mgr_free_account_data (mgr, acc_data);
1431 }
1432
1433 static void
1434 on_send_receive_csm_activated (GtkMenuItem *item,
1435                                gpointer user_data)
1436 {
1437         ModestWindow *win;
1438
1439         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1440
1441         /* If user_data == NULL, we must update all (CSM option All) */
1442         if (!user_data) {
1443                 modest_ui_actions_do_send_receive_all (win);
1444         } else {
1445                 modest_ui_actions_do_send_receive ((const gchar *)user_data, win);
1446         }
1447 }