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