e827044c5115832d72aacd42a22f2ff4c0d49b06
[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 <tny-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
40 #include <string.h>
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-utils.h>
57 #include <modest-maemo-utils.h>
58 #include "modest-tny-platform-factory.h"
59 #include "modest-tny-msg.h"
60 #include "modest-mail-operation.h"
61 #include "modest-icon-names.h"
62 #include "modest-progress-bar-widget.h"
63 #include "modest-text-utils.h"
64 #include "modest-ui-dimming-manager.h"
65 #include "maemo/modest-osso-state-saving.h"
66 #include "modest-text-utils.h"
67 #include "modest-signal-mgr.h"
68
69 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
70
71 #define XALIGN 0.5
72 #define YALIGN 0.0
73 #define XSPACE 1
74 #define YSPACE 0
75
76 /* 'private'/'protected' functions */
77 static void modest_main_window_class_init  (ModestMainWindowClass *klass);
78 static void modest_main_window_init        (ModestMainWindow *obj);
79 static void modest_main_window_finalize    (GObject *obj);
80
81 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
82                                                        GdkEventWindowState *event, 
83                                                        gpointer userdata);
84
85 static void connect_signals (ModestMainWindow *self);
86
87 static void modest_main_window_disconnect_signals (ModestWindow *self);
88
89 static void restore_settings (ModestMainWindow *self, 
90                               gboolean do_folder_view_too);
91
92 static void save_state (ModestWindow *self);
93
94 static void update_menus (ModestMainWindow* self);
95
96 static void modest_main_window_show_toolbar   (ModestWindow *window,
97                                                gboolean show_toolbar);
98
99 static void cancel_progressbar (GtkToolButton *toolbutton,
100                                 ModestMainWindow *self);
101
102 static void on_queue_changed   (ModestMailOperationQueue *queue,
103                                 ModestMailOperation *mail_op,
104                                 ModestMailOperationQueueNotification type,
105                                 ModestMainWindow *self);
106
107 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
108
109 static void on_account_inserted (TnyAccountStore *accoust_store,
110                                  TnyAccount *account,
111                                  gpointer user_data);
112
113 static void on_account_removed  (TnyAccountStore *accoust_store,
114                                  TnyAccount *account,
115                                  gpointer user_data);
116
117 static void on_account_changed  (TnyAccountStore *account_store,
118                                  TnyAccount *account,
119                                  gpointer user_data);
120
121 static void on_default_account_changed (ModestAccountMgr* mgr,
122                                         gpointer user_data);
123
124 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
125                                                GdkEventKey *event,
126                                                gpointer user_data);
127
128 static void on_configuration_key_changed      (ModestConf* conf, 
129                                                const gchar *key, 
130                                                ModestConfEvent event,
131                                                ModestConfNotificationId id,
132                                                ModestMainWindow *self);
133
134 static void set_toolbar_mode                  (ModestMainWindow *self, 
135                                                ModestToolBarModes mode);
136
137 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
138
139 static void on_show_account_action_toggled      (GtkToggleAction *action,
140                                                  gpointer user_data);
141
142 static void on_refresh_account_action_activated   (GtkAction *action,
143                                                    gpointer user_data);
144
145 static void on_send_receive_csm_activated         (GtkMenuItem *item,
146                                                    gpointer user_data);
147
148 static void on_msg_count_changed (ModestHeaderView *header_view,
149                                   TnyFolder *folder,
150                                   TnyFolderChange *change,
151                                   ModestMainWindow *main_window);
152
153 static void modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
154
155
156 static GtkWidget * create_empty_view (void);
157
158 static gboolean  on_folder_view_focus_in (GtkWidget *widget,
159                                           GdkEventFocus *event,
160                                           gpointer userdata);
161
162 static gboolean  on_header_view_focus_in (GtkWidget *widget,
163                                           GdkEventFocus *event,
164                                           gpointer userdata);
165
166 static void      on_folder_selection_changed (ModestFolderView *folder_view,
167                                               TnyFolderStore *folder_store, 
168                                               gboolean selected,
169                                               ModestMainWindow *main_window);
170                                                 
171 static void set_at_least_one_account_visible(ModestMainWindow *self);
172
173 static void on_updating_msg_list (ModestHeaderView *header_view,
174                                   gboolean starting,
175                                   gpointer user_data);
176
177 static gboolean restore_paned_timeout_handler (gpointer *data);
178
179 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
180 struct _ModestMainWindowPrivate {
181         GtkWidget *msg_paned;
182         GtkWidget *main_paned;
183         GtkWidget *main_vbox;
184         GtkWidget *contents_widget;
185         GtkWidget *empty_view;
186
187         /* Progress observers */
188         GtkWidget   *progress_bar;
189         GSList      *progress_widgets;
190
191         /* Tollbar items */
192         GtkWidget   *progress_toolitem;
193         GtkWidget   *cancel_toolitem;
194         GtkWidget   *sort_toolitem;
195         GtkWidget   *refresh_toolitem;
196         ModestToolBarModes current_toolbar_mode;
197
198         /* Merge ids used to add/remove accounts to the ViewMenu*/
199         GByteArray *merge_ids;
200         GtkActionGroup *view_additions_group;
201
202         /* On-demand widgets */
203         GtkWidget *accounts_popup;
204         GtkWidget *details_widget;
205
206         /* Optimized view enabled */
207         gboolean optimized_view;
208
209         /* Optimized view enabled */
210         gboolean send_receive_in_progress;
211
212         ModestHeaderView *header_view;
213         ModestFolderView *folder_view;
214
215         ModestMainWindowStyle style;
216         ModestMainWindowContentsStyle contents_style;
217
218         guint progress_bar_timeout;
219         guint restore_paned_timeout;
220
221         /* Signal handler UIDs */
222         GList *queue_err_signals;
223         GSList *sighandlers;
224
225         /* "Updating" banner for header view */
226         GtkWidget *updating_banner;
227         guint updating_banner_timeout;
228 };
229 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
230                                                 MODEST_TYPE_MAIN_WINDOW, \
231                                                 ModestMainWindowPrivate))
232
233 typedef struct _GetMsgAsyncHelper {
234         ModestMainWindowPrivate *main_window_private;
235         guint action;
236         ModestTnyMsgReplyType reply_type;
237         ModestTnyMsgForwardType forward_type;
238         gchar *from;
239         TnyIterator *iter;
240 } GetMsgAsyncHelper;
241
242
243 /* globals */
244 static GtkWindowClass *parent_class = NULL;
245
246
247 /* Private actions */
248 /* This is the context sensitive menu: */
249 static const GtkActionEntry modest_folder_view_action_entries [] = {
250
251         /* Folder View CSM actions */
252         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
253         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
254         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL,  G_CALLBACK (modest_ui_actions_on_paste)},
255         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
256         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
257         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
258 };
259
260 static const GtkActionEntry modest_header_view_action_entries [] = {
261
262         /* Header View CSM actions */
263         { "HeaderViewCSMOpen",          NULL,  N_("mcen_me_inbox_open"),        NULL,       NULL, G_CALLBACK (modest_ui_actions_on_open) },
264         { "HeaderViewCSMReply",         NULL,  N_("mcen_me_inbox_reply"),       NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply) },
265         { "HeaderViewCSMReplyAll",      NULL,  N_("mcen_me_inbox_replytoall"),  NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
266         { "HeaderViewCSMForward",       NULL,  N_("mcen_me_inbox_forward"),     NULL,      NULL, G_CALLBACK (modest_ui_actions_on_forward) },
267         { "HeaderViewCSMCut",           NULL,  N_("mcen_me_inbox_cut"),         "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
268         { "HeaderViewCSMCopy",          NULL,  N_("mcen_me_inbox_copy"),        "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
269         { "HeaderViewCSMPaste",         NULL,  N_("mcen_me_inbox_paste"),       "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
270         { "HeaderViewCSMDelete",        NULL,  N_("mcen_me_inbox_delete"),      NULL,      NULL, G_CALLBACK (modest_ui_actions_on_delete_message) },
271         { "HeaderViewCSMCancelSending", NULL,  N_("mcen_me_outbox_cancelsend"), NULL,      NULL, G_CALLBACK (modest_ui_actions_cancel_send) },
272         { "HeaderViewCSMHelp",          NULL,  N_("mcen_me_inbox_help"),        NULL,      NULL, G_CALLBACK (modest_ui_actions_on_help) },
273 };
274
275 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
276         { "ToggleFolders",     MODEST_STOCK_SPLIT_VIEW, N_("mcen_me_inbox_hidefolders"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), TRUE },
277 };
278
279 /************************************************************************/
280
281 GType
282 modest_main_window_get_type (void)
283 {
284         static GType my_type = 0;
285         if (!my_type) {
286                 static const GTypeInfo my_info = {
287                         sizeof(ModestMainWindowClass),
288                         NULL,           /* base init */
289                         NULL,           /* base finalize */
290                         (GClassInitFunc) modest_main_window_class_init,
291                         NULL,           /* class finalize */
292                         NULL,           /* class data */
293                         sizeof(ModestMainWindow),
294                         1,              /* n_preallocs */
295                         (GInstanceInitFunc) modest_main_window_init,
296                         NULL
297                 };
298                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
299                                                   "ModestMainWindow",
300                                                   &my_info, 0);
301         }
302         return my_type;
303 }
304
305 static void
306 modest_main_window_class_init (ModestMainWindowClass *klass)
307 {
308         GObjectClass *gobject_class;
309         gobject_class = (GObjectClass*) klass;
310         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
311
312         parent_class            = g_type_class_peek_parent (klass);
313         gobject_class->finalize = modest_main_window_finalize;
314
315         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
316         
317         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
318         modest_window_class->save_state_func = save_state;
319         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
320         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
321         modest_window_class->disconnect_signals_func = modest_main_window_disconnect_signals;
322 }
323
324 static void
325 modest_main_window_init (ModestMainWindow *obj)
326 {
327         ModestMainWindowPrivate *priv;
328
329         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
330
331         priv->queue_err_signals = NULL;
332         priv->msg_paned    = NULL;
333         priv->main_paned   = NULL;      
334         priv->main_vbox    = NULL;
335         priv->header_view  = NULL;
336         priv->folder_view  = NULL;
337         priv->contents_widget  = NULL;
338         priv->accounts_popup  = NULL;
339         priv->details_widget  = NULL;
340         priv->empty_view  = NULL;
341         priv->progress_widgets  = NULL;
342         priv->progress_bar = NULL;
343         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
344         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
345         priv->contents_style  = -1; /* invalid contents style. We need this to select it for the first time */
346         priv->merge_ids = NULL;
347         priv->optimized_view  = FALSE;
348         priv->send_receive_in_progress  = FALSE;
349         priv->progress_bar_timeout = 0;
350         priv->restore_paned_timeout = 0;
351         priv->sighandlers = NULL;
352         priv->updating_banner = NULL;
353         priv->updating_banner_timeout = 0;
354         
355         modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
356                                             GTK_WINDOW(obj),
357                                             "applications_email_mainview");
358 }
359
360 static void
361 modest_main_window_finalize (GObject *obj)
362 {
363         ModestMainWindowPrivate *priv;
364
365         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
366
367         /* Sanity check: shouldn't be needed, the window mgr should
368            call this function before */
369         modest_main_window_disconnect_signals (MODEST_WINDOW (obj));    
370         modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
371         
372         g_slist_free (priv->progress_widgets);
373
374         g_byte_array_free (priv->merge_ids, TRUE);
375
376         if (priv->progress_bar_timeout > 0) {
377                 g_source_remove (priv->progress_bar_timeout);
378                 priv->progress_bar_timeout = 0;
379         }
380
381         if (priv->updating_banner_timeout > 0) {
382                 g_source_remove (priv->updating_banner_timeout);
383                 priv->updating_banner_timeout = 0;
384         }
385
386         if (priv->updating_banner) {
387                 gtk_widget_destroy (priv->updating_banner);
388                 priv->updating_banner = NULL;
389         }
390
391         if (priv->restore_paned_timeout > 0) {
392                 g_source_remove (priv->restore_paned_timeout);
393                 priv->restore_paned_timeout = 0;
394         }
395         
396         G_OBJECT_CLASS(parent_class)->finalize (obj);
397 }
398
399 GtkWidget*
400 modest_main_window_get_child_widget (ModestMainWindow *self,
401                                      ModestMainWindowWidgetType widget_type)
402 {
403         ModestMainWindowPrivate *priv;
404         GtkWidget *widget;
405         
406         g_return_val_if_fail (self, NULL);
407         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_MAIN_WINDOW_WIDGET_TYPE_NUM,
408                               NULL);
409         
410         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
411
412         switch (widget_type) {
413         case MODEST_MAIN_WINDOW_WIDGET_TYPE_HEADER_VIEW:
414                 widget = (GtkWidget*)priv->header_view; break;
415         case MODEST_MAIN_WINDOW_WIDGET_TYPE_FOLDER_VIEW:
416                 widget = (GtkWidget*)priv->folder_view; break;
417         default:
418                 return NULL;
419         }
420
421         return widget ? GTK_WIDGET(widget) : NULL;
422 }
423
424 static gboolean 
425 restore_paned_timeout_handler (gpointer *data)
426 {
427         ModestMainWindow *main_window = MODEST_MAIN_WINDOW (data);
428         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
429         ModestConf *conf;
430
431         /* Timeouts are outside the main lock */
432         gdk_threads_enter ();
433         if (GTK_WIDGET_VISIBLE (main_window)) {
434                 conf = modest_runtime_get_conf ();
435                 modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
436                                               MODEST_CONF_MAIN_PANED_KEY);
437         }
438         gdk_threads_leave ();
439
440         return FALSE;
441 }
442
443
444 static void
445 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
446 {
447         ModestConf *conf;
448         ModestMainWindowPrivate *priv;
449
450         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
451
452         conf = modest_runtime_get_conf ();
453
454         modest_widget_memory_restore (conf, G_OBJECT(self),
455                                       MODEST_CONF_MAIN_WINDOW_KEY);
456
457         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
458                                       MODEST_CONF_HEADER_VIEW_KEY);
459
460         if (do_folder_view_too)
461                 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
462                                       MODEST_CONF_FOLDER_VIEW_KEY);
463
464         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
465                                       MODEST_CONF_MAIN_PANED_KEY);
466
467         g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
468
469         /* We need to force a redraw here in order to get the right
470            position of the horizontal paned separator */
471         gtk_widget_show (GTK_WIDGET (self));
472 }
473
474
475 static void
476 save_state (ModestWindow *window)
477 {
478         ModestConf *conf;
479         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
480         ModestMainWindowPrivate *priv;
481                 
482         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
483         conf = modest_runtime_get_conf ();
484         
485         modest_widget_memory_save (conf,G_OBJECT(self), 
486                                    MODEST_CONF_MAIN_WINDOW_KEY);
487         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
488                                    MODEST_CONF_MAIN_PANED_KEY);
489         //      modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
490         //                         MODEST_CONF_HEADER_VIEW_KEY);
491         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
492                                    MODEST_CONF_FOLDER_VIEW_KEY);
493 }
494
495 static gint
496 compare_display_names (ModestAccountSettings *a,
497                        ModestAccountSettings *b)
498 {
499         return strcmp (modest_account_settings_get_display_name (a),
500                        modest_account_settings_get_display_name (b));
501 }
502
503 static void
504 update_menus (ModestMainWindow* self)
505 {       
506         GSList *account_names, *iter, *accounts;
507         ModestMainWindowPrivate *priv;
508         ModestWindowPrivate *parent_priv;
509         ModestAccountMgr *mgr;
510         gint i, num_accounts;
511         GList *groups;
512         gchar *default_account;
513         const gchar *active_account_name;
514         GtkWidget *send_receive_button, *item;
515         GtkAction *send_receive_all = NULL;
516         GSList *radio_group;
517
518         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
519         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
520
521         /* Get enabled account IDs */
522         mgr = modest_runtime_get_account_mgr ();
523         account_names = modest_account_mgr_account_names (mgr, TRUE);
524         iter = account_names;
525         accounts = NULL;
526
527         while (iter) {
528                 ModestAccountSettings *settings = 
529                         modest_account_mgr_load_account_settings (mgr, (gchar*) iter->data);
530                 accounts = g_slist_prepend (accounts, settings);
531
532                 iter = iter->next;
533         }
534         modest_account_mgr_free_account_names (account_names);
535         account_names = NULL;
536
537         /* Order the list of accounts by its display name */
538         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
539         num_accounts = g_slist_length (accounts);
540
541         send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
542                                                       "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
543         gtk_action_set_visible (send_receive_all, num_accounts > 0);
544
545         /* Delete old send&receive popup items. We can not just do a
546            menu_detach because it does not work well with
547            tap_and_hold */
548         if (priv->accounts_popup)
549                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
550                                        (GtkCallback) gtk_widget_destroy, NULL);
551
552         /* Delete old entries in the View menu. Do not free groups, it
553            belongs to Gtk+ */
554         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
555         while (groups) {
556                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
557                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
558                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
559                                                             GTK_ACTION_GROUP (groups->data));
560                         groups = NULL;
561                         /* Remove uis */
562                         if (priv->merge_ids) {
563                                 for (i = 0; i < priv->merge_ids->len; i++)
564                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
565                                 g_byte_array_free (priv->merge_ids, TRUE);
566                         }
567                         /* We need to call this in order to ensure
568                            that the new actions are added in the right
569                            order (alphabetical) */
570                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
571                 } else 
572                         groups = g_list_next (groups);
573         }
574         priv->merge_ids = g_byte_array_sized_new (num_accounts);
575
576         /* Get send receive button */
577         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
578                                                           "/ToolBar/ToolbarSendReceive");
579
580         /* Create the menu */
581         if (num_accounts > 1) {
582                 if (!priv->accounts_popup)
583                         priv->accounts_popup = gtk_menu_new ();
584                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
585                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
586                 g_signal_connect (G_OBJECT (item), 
587                                   "activate", 
588                                   G_CALLBACK (on_send_receive_csm_activated),
589                                   NULL);
590                 item = gtk_separator_menu_item_new ();
591                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
592         }
593
594         /* Create a new action group */
595         default_account = modest_account_mgr_get_default_account (mgr);
596         active_account_name = modest_window_get_active_account (MODEST_WINDOW (self));
597         
598         if (!active_account_name) 
599                 modest_window_set_active_account (MODEST_WINDOW (self), default_account);
600         
601         priv->view_additions_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
602         radio_group = NULL;
603         for (i = 0; i < num_accounts; i++) {
604                 gchar *display_name = NULL;     
605                 const gchar *account_name;
606                 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
607
608                 if (!settings) {
609                         g_warning ("%s: BUG: account_data == NULL", __FUNCTION__);
610                         continue;
611                 }
612                 account_name = modest_account_settings_get_account_name (settings);
613         
614                 if (default_account && account_name && 
615                     !(strcmp (default_account, account_name) == 0)) {
616                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
617                                                         modest_account_settings_get_display_name (settings));
618                 } else {
619                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
620                                                         modest_account_settings_get_display_name (settings));
621                 }
622                 
623                 /* Create action and add it to the action group. The
624                    action name must be the account name, this way we
625                    could know in the handlers the account to show */
626                 if (settings && account_name) {
627                         gchar* item_name, *refresh_action_name;
628                         guint8 merge_id = 0;
629                         GtkAction *view_account_action, *refresh_account_action;
630
631                         view_account_action = GTK_ACTION (gtk_radio_action_new (account_name,
632                                                                                 display_name, NULL, NULL, 0));
633                         gtk_action_group_add_action (priv->view_additions_group, view_account_action);
634                         gtk_radio_action_set_group (GTK_RADIO_ACTION (view_account_action), radio_group);
635                         radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (view_account_action));
636
637                         if (active_account_name) {
638                                 if (active_account_name && account_name && 
639                                     (strcmp (active_account_name, account_name) == 0)) {
640                                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (view_account_action), TRUE);
641                                 }
642                         }
643
644                         /* Add ui from account data. We allow 2^9-1 account
645                            changes in a single execution because we're
646                            downcasting the guint to a guint8 in order to use a
647                            GByteArray. It should be enough. */
648                         item_name = g_strconcat (account_name, "Menu", NULL);
649                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
650                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
651                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
652                                                merge_id,
653                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
654                                                item_name,
655                                                account_name,
656                                                GTK_UI_MANAGER_MENUITEM,
657                                                FALSE);
658
659                         /* Connect the action signal "activate" */
660                         g_signal_connect_after (G_OBJECT (view_account_action),
661                                                 "toggled",
662                                                 G_CALLBACK (on_show_account_action_toggled),
663                                                 self);
664
665                         /* Create the items for the Tools->Send&Receive submenu */
666                         refresh_action_name = g_strconcat ("SendReceive", account_name, NULL);
667                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
668                                                                  display_name, NULL, NULL);
669                         gtk_action_group_add_action (priv->view_additions_group, refresh_account_action);
670
671                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
672                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
673                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
674                                                merge_id,
675                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
676                                                item_name,
677                                                refresh_action_name,
678                                                GTK_UI_MANAGER_MENUITEM,
679                                                FALSE);
680                         g_free (refresh_action_name);
681
682                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
683                                                "activate", 
684                                                G_CALLBACK (on_refresh_account_action_activated), 
685                                                g_strdup (account_name),
686                                                (GClosureNotify) g_free,
687                                                0);
688
689                         /* Create item and add it to the send&receive
690                            CSM. If there is only one account then
691                            it'll be no menu */
692                         if (priv->accounts_popup) {
693                                 GtkWidget *label = gtk_label_new(NULL);
694                                 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
695                                 if (default_account && (strcmp(account_name, default_account) == 0))
696                                 {
697                                         gchar *escaped = g_markup_printf_escaped ("<b>%s</b>", display_name);
698                                         gtk_label_set_markup (GTK_LABEL (label), escaped);
699                                         g_free (escaped);
700                                 }
701                                 else
702                                 {
703                                         gtk_label_set_text (GTK_LABEL (label), display_name);
704                                 }
705
706                                 item = gtk_menu_item_new ();
707                                 gtk_container_add (GTK_CONTAINER (item), label);
708
709                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
710                                 g_signal_connect_data (G_OBJECT (item), 
711                                                        "activate", 
712                                                        G_CALLBACK (on_send_receive_csm_activated),
713                                                        g_strdup (account_name),
714                                                        (GClosureNotify) g_free,
715                                                        0);
716                         }
717                         g_free (item_name);
718                 }
719
720                 /* Frees */
721                 g_free (display_name);
722         }
723
724         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, priv->view_additions_group, 1);
725
726         /* We cannot do this in the loop above because this relies on the action
727          * group being inserted. This makes the default account appear in bold.
728          * I agree it is a rather ugly way, but I don't see another possibility. armin. */
729         for (i = 0; i < num_accounts; i++) {
730                 ModestAccountSettings *settings = (ModestAccountSettings *) g_slist_nth_data (accounts, i);
731                 const gchar *account_name;
732
733                 account_name = modest_account_settings_get_account_name (settings);
734
735                 if(account_name && default_account &&
736                    strcmp (account_name, default_account) == 0) {
737                         gchar *item_name = g_strconcat (account_name, "Menu", NULL);
738
739                         gchar *path = g_strconcat ("/MenuBar/ViewMenu/ViewMenuAdditions/", item_name, NULL);
740                         GtkWidget *item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
741                         g_free(path);
742
743                         if (item) {
744                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
745                                 if (GTK_IS_LABEL (child)) {
746                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
747                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
748                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
749                                         g_free (bold_name);
750                                 }
751                         }
752                         
753                         path = g_strconcat("/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions/", item_name, NULL);
754                         item = gtk_ui_manager_get_widget (parent_priv->ui_manager, path);
755                         g_free (path);
756
757                         if (item) {
758                                 GtkWidget *child = gtk_bin_get_child (GTK_BIN (item));
759                                 if (GTK_IS_LABEL (child)) {
760                                         const gchar *cur_name = gtk_label_get_text (GTK_LABEL (child));
761                                         gchar *bold_name = g_markup_printf_escaped("<b>%s</b>", cur_name);
762                                         gtk_label_set_markup (GTK_LABEL (child), bold_name);
763                                         g_free (bold_name);
764                                 }
765                         }
766
767                         g_free(item_name);
768                 }
769
770                 g_object_unref (settings);
771         }
772
773         if (priv->accounts_popup) {
774                 /* Mandatory in order to view the menu contents */
775                 gtk_widget_show_all (priv->accounts_popup);
776
777                 /* Setup tap_and_hold just if was not done before*/
778                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
779                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
780         }
781
782         /* Frees */
783         g_slist_free (accounts);
784         g_free (default_account);
785
786
787         /* Make sure that at least one account is viewed if there are any 
788          * accounts, for instance when adding the first account: */
789         set_at_least_one_account_visible (self);
790 }
791
792 static void
793 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
794 {
795         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
796                 gtk_scrolled_window_add_with_viewport
797                         (GTK_SCROLLED_WINDOW(win), widget);
798         else
799                 gtk_container_add (GTK_CONTAINER(win),
800                                    widget);
801 }
802
803
804 typedef struct {
805         TnySendQueue *queue;
806         guint signal;
807 } QueueErrorSignal;
808
809 static void
810 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
811 {
812         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
813
814         GList *oerrsignals = priv->queue_err_signals;
815         while (oerrsignals) {
816                 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
817                 g_signal_handler_disconnect (esignal->queue, esignal->signal);
818                 g_slice_free (QueueErrorSignal, esignal);
819                 oerrsignals = g_list_next (oerrsignals);
820         }
821         g_list_free (priv->queue_err_signals);
822         priv->queue_err_signals = NULL;
823 }
824
825
826 static void
827 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
828 {
829         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
830
831         /* Update dimmed */     
832         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
833 }
834
835 static void
836 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
837 {
838         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
839
840         /* Update visibility */
841
842         /* Update dimmed */     
843         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
844 }
845
846 static void
847 modest_main_window_disconnect_signals (ModestWindow *self)
848 {       
849         ModestMainWindowPrivate *priv;  
850         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
851
852         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
853         priv->sighandlers = NULL;       
854 }
855
856 static void
857 connect_signals (ModestMainWindow *self)
858 {       
859         ModestWindowPrivate *parent_priv;
860         ModestMainWindowPrivate *priv;
861         GtkWidget *menu;
862         
863         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
864         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
865
866         /* folder view */
867         
868         priv->sighandlers = 
869                 modest_signal_mgr_connect (priv->sighandlers,
870                                            G_OBJECT(priv->folder_view), "key-press-event",
871                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
872         priv->sighandlers = 
873                 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), 
874                                            "folder_selection_changed",
875                                            G_CALLBACK (on_folder_selection_changed), 
876                                            self);
877         priv->sighandlers = 
878                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), 
879                                            "folder-display-name-changed",
880                                            G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), 
881                                            self);
882         priv->sighandlers = 
883                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), 
884                                            "focus-in-event", 
885                                            G_CALLBACK (on_folder_view_focus_in), 
886                                            self);
887
888         /* Folder view CSM */
889         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
890         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
891         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
892                                                        G_CALLBACK(_folder_view_csm_menu_activated),
893                                                        self);
894         /* header view */
895         priv->sighandlers = 
896                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
897                                            G_CALLBACK(modest_ui_actions_on_header_selected), self);
898         priv->sighandlers = 
899                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
900                                            G_CALLBACK(modest_ui_actions_on_header_activated), self);
901         priv->sighandlers = 
902                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
903                                            G_CALLBACK(modest_ui_actions_on_item_not_found), self);
904         priv->sighandlers = 
905                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
906                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
907         priv->sighandlers = 
908                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
909                                            G_CALLBACK(on_msg_count_changed), self);
910         priv->sighandlers = 
911                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
912                                            G_CALLBACK (on_header_view_focus_in), self);
913         priv->sighandlers = 
914                 modest_signal_mgr_connect (priv->sighandlers,
915                                            G_OBJECT (priv->header_view), 
916                                            "updating-msg-list",
917                                            G_CALLBACK (on_updating_msg_list), 
918                                            self);
919         
920         /* Header view CSM */
921         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
922         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
923         priv->sighandlers = 
924                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "tap-and-hold",
925                                            G_CALLBACK(_header_view_csm_menu_activated),
926                                            self);
927         
928         /* window */
929         priv->sighandlers = 
930                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
931                                            G_CALLBACK (modest_main_window_window_state_event),
932                                            NULL);
933
934         /* Mail Operation Queue */
935         priv->sighandlers = 
936                 modest_signal_mgr_connect (priv->sighandlers,
937                                            G_OBJECT (modest_runtime_get_mail_operation_queue ()),
938                                            "queue-changed", 
939                                            G_CALLBACK (on_queue_changed), self);
940         
941         /* Track changes in the device name */
942         priv->sighandlers = 
943                 modest_signal_mgr_connect (priv->sighandlers,
944                                            G_OBJECT(modest_runtime_get_conf ()),
945                                            "key_changed", 
946                                            G_CALLBACK (on_configuration_key_changed), 
947                                            self);
948         
949         /* Track account changes. We need to refresh the toolbar */
950         priv->sighandlers = 
951                 modest_signal_mgr_connect (priv->sighandlers,
952                                            G_OBJECT (modest_runtime_get_account_store ()),
953                                            "account_inserted", 
954                                            G_CALLBACK (on_account_inserted),
955                                            self);
956         priv->sighandlers = 
957                 modest_signal_mgr_connect (priv->sighandlers,
958                                            G_OBJECT (modest_runtime_get_account_store ()),
959                                            "account_removed", 
960                                            G_CALLBACK (on_account_removed),
961                                            self);
962
963         /* We need to refresh the send & receive menu to change the bold
964          * account when the default account changes. */
965         priv->sighandlers = 
966                 modest_signal_mgr_connect (priv->sighandlers,
967                                            G_OBJECT (modest_runtime_get_account_mgr ()),
968                                            "default_account_changed", 
969                                            G_CALLBACK (on_default_account_changed),
970                                            self);
971
972         /* Account store */
973         priv->sighandlers = 
974                 modest_signal_mgr_connect (priv->sighandlers,
975                                            G_OBJECT (modest_runtime_get_account_store ()),
976                                            "account_changed", 
977                                            G_CALLBACK (on_account_changed),
978                                            self);
979
980         priv->sighandlers = 
981                 modest_signal_mgr_connect (priv->sighandlers,
982                                            G_OBJECT (modest_runtime_get_account_store()), 
983                                            "password_requested",
984                                            G_CALLBACK (modest_ui_actions_on_password_requested), 
985                                            self);
986 }
987
988 #if 0
989 /** Idle handler, to send/receive at startup .*/
990 gboolean
991 sync_accounts_cb (ModestMainWindow *win)
992 {
993         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
994         return FALSE; /* Do not call this idle handler again. */
995 }
996 #endif
997
998 static void 
999 on_hildon_program_is_topmost_notify(GObject *self,
1000                                     GParamSpec *propert_param, gpointer user_data)
1001 {
1002         HildonProgram *app = HILDON_PROGRAM (self);
1003         
1004         /*
1005         ModestWindow* self = MODEST_WINDOW(user_data);
1006         */
1007         
1008         /* Note that use of hildon_program_set_can_hibernate() 
1009          * is generally referred to as "setting the killable flag", 
1010          * though hibernation does not seem equal to death.
1011          * murrayc */
1012                  
1013         if (hildon_program_get_is_topmost (app)) {
1014                 /* Prevent hibernation when the progam comes to the foreground,
1015                  * because hibernation should only happen when the application 
1016                  * is in the background: */
1017                 hildon_program_set_can_hibernate (app, FALSE);
1018         } else {
1019                 /* Allow hibernation if the program has gone to the background: */
1020                 
1021                 /* However, prevent hibernation while the settings are being changed: */
1022                 const gboolean hibernation_prevented = 
1023                         modest_window_mgr_get_hibernation_is_prevented (
1024         modest_runtime_get_window_mgr ()); 
1025         
1026                 if (hibernation_prevented)
1027                         hildon_program_set_can_hibernate (app, FALSE);
1028                 else {
1029                         /* Allow hibernation, after saving the state: */
1030                         modest_osso_save_state();
1031                         hildon_program_set_can_hibernate (app, TRUE);
1032                 }
1033         }
1034         
1035 }
1036
1037 static void
1038 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1039 {
1040         GtkWidget *folder_win = (GtkWidget *) user_data;
1041         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1042         
1043         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1044         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1045
1046         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1047
1048         /* Connect signals */
1049         connect_signals (MODEST_MAIN_WINDOW (self));
1050
1051         /* Set account store */
1052         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1053                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1054
1055         /* Load previous osso state, for instance if we are being restored from 
1056          * hibernation:  */
1057         modest_osso_load_state ();
1058
1059         /* Restore window & widget settings */  
1060         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1061
1062         /* Check if accounts exist and show the account wizard if not */
1063         gboolean accounts_exist = 
1064                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1065
1066         if (!accounts_exist) {
1067                 /* This is necessary to have the main window shown behind the dialog 
1068                 It's an ugly hack... jschmid */
1069                 gtk_widget_show_all(GTK_WIDGET(self));
1070                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1071         } else {
1072                 GSList *accounts;
1073                 GtkAction *send_receive_all;
1074                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1075                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1076                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1077                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1078                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 0);
1079                 modest_account_mgr_free_account_names (accounts);
1080                 update_menus (MODEST_MAIN_WINDOW (self));
1081         }
1082 }
1083
1084 ModestWindow *
1085 modest_main_window_new (void)
1086 {
1087         ModestMainWindow *self = NULL;  
1088         ModestMainWindowPrivate *priv = NULL;
1089         ModestWindowPrivate *parent_priv = NULL;
1090         GtkWidget *folder_win = NULL;
1091         ModestDimmingRulesGroup *menu_rules_group = NULL;
1092         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1093         GtkActionGroup *action_group = NULL;
1094         GError *error = NULL;
1095         HildonProgram *app;
1096         ModestConf *conf = NULL;
1097         GtkAction *action = NULL;
1098         GdkPixbuf *window_icon;
1099         
1100         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1101         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1102         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1103
1104         parent_priv->ui_manager = gtk_ui_manager_new();
1105         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1106
1107         action_group = gtk_action_group_new ("ModestMainWindowActions");
1108         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1109
1110         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules", FALSE);
1111         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules", TRUE);
1112
1113         /* Add common actions */
1114         gtk_action_group_add_actions (action_group,
1115                                       modest_action_entries,
1116                                       G_N_ELEMENTS (modest_action_entries),
1117                                       self);
1118
1119         gtk_action_group_add_actions (action_group,
1120                                       modest_folder_view_action_entries,
1121                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1122                                       self);
1123
1124         gtk_action_group_add_actions (action_group,
1125                                       modest_header_view_action_entries,
1126                                       G_N_ELEMENTS (modest_header_view_action_entries),
1127                                       self);
1128
1129         gtk_action_group_add_toggle_actions (action_group,
1130                                              modest_toggle_action_entries,
1131                                              G_N_ELEMENTS (modest_toggle_action_entries),
1132                                              self);
1133
1134         gtk_action_group_add_toggle_actions (action_group,
1135                                              modest_main_window_toggle_action_entries,
1136                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1137                                              self);
1138
1139         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1140         g_object_unref (action_group);
1141
1142         /* Load the UI definition */
1143         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1144                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1145         if (error != NULL) {
1146                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1147                 g_error_free (error);
1148                 error = NULL;
1149         }
1150
1151         /* Add common dimming rules */
1152         modest_dimming_rules_group_add_rules (menu_rules_group, 
1153                                               modest_main_window_menu_dimming_entries,
1154                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1155                                               MODEST_WINDOW (self));
1156         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1157                                               modest_main_window_toolbar_dimming_entries,
1158                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1159                                               MODEST_WINDOW (self));
1160
1161         /* Insert dimming rules group for this window */
1162         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1163         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1164         g_object_unref (menu_rules_group);
1165         g_object_unref (toolbar_rules_group);
1166         
1167         /* Add accelerators */
1168         gtk_window_add_accel_group (GTK_WINDOW (self), 
1169                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1170
1171         /* Menubar. Update the state of some toggles */
1172         parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1173         conf = modest_runtime_get_conf ();
1174         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1175                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1176         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1177                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1178         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1179                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1180         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1181                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1182         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1183         gtk_widget_show (parent_priv->menubar);
1184
1185         /* Get device name */
1186         modest_maemo_utils_get_device_name ();
1187
1188         /* header view */
1189         priv->header_view =
1190                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1191         if (!priv->header_view)
1192                 g_printerr ("modest: cannot instantiate header view\n");
1193         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1194         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1195                                       MODEST_CONF_HEADER_VIEW_KEY);
1196
1197         /* Other style properties of header view */
1198         g_object_set (G_OBJECT (priv->header_view), 
1199                       "rules-hint", FALSE,
1200                       NULL);
1201         /* gtk_widget_show (priv->header_view); */
1202
1203         /* Empty view */ 
1204         priv->empty_view = create_empty_view ();
1205         gtk_widget_show (priv->empty_view);
1206                  
1207         /* Create scrolled windows */
1208         folder_win = gtk_scrolled_window_new (NULL, NULL);
1209         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1210         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1211                                         GTK_POLICY_NEVER,
1212                                         GTK_POLICY_AUTOMATIC);
1213         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1214                                         GTK_POLICY_NEVER,
1215                                         GTK_POLICY_AUTOMATIC);
1216         /* gtk_widget_show (priv->contents_widget); */
1217
1218         /* paned */
1219         priv->main_paned = gtk_hpaned_new ();
1220         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1221         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1222         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1223
1224         /* putting it all together... */
1225         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1226         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1227         gtk_widget_show (priv->main_vbox);
1228         
1229         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1230         
1231         app = hildon_program_get_instance ();
1232         hildon_program_add_window (app, HILDON_WINDOW (self));
1233         
1234         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1235                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1236
1237         g_signal_connect (G_OBJECT(self), "show",
1238                           G_CALLBACK (modest_main_window_on_show), folder_win);
1239                 
1240         /* Set window icon */
1241         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1242         if (window_icon) {
1243                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1244                 g_object_unref (window_icon);
1245         }
1246
1247         /* Dont't restore settings here, 
1248          * because it requires a gtk_widget_show(), 
1249          * and we don't want to do that until later,
1250          * so that the UI is not visible for non-menu D-Bus activation.
1251          */
1252         /* restore_settings (MODEST_MAIN_WINDOW(self), FALSE); */
1253
1254         return MODEST_WINDOW(self);
1255 }
1256
1257 void 
1258 modest_main_window_set_style (ModestMainWindow *self, 
1259                               ModestMainWindowStyle style)
1260 {
1261         ModestMainWindowPrivate *priv;
1262         ModestWindowPrivate *parent_priv;
1263         GtkAction *action;
1264         gboolean active;
1265
1266         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1267
1268         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1269         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1270
1271         /* no change -> nothing to do */
1272         if (priv->style == style)
1273                 return;
1274
1275        /* Get toggle button and update the state if needed. This will
1276           happen only when the set_style is not invoked from the UI,
1277           for example when it's called from widget memory */
1278        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1279        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1280        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1281            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1282                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1283                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1284                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1285        }
1286
1287         priv->style = style;
1288         switch (style) {
1289         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1290                 /* Remove main paned */
1291                 g_object_ref (priv->main_paned);
1292                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1293
1294                 /* Reparent the contents widget to the main vbox */
1295                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1296
1297                 break;
1298         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1299                 /* Remove header view */
1300                 g_object_ref (priv->contents_widget);
1301                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1302
1303                 /* Reparent the main paned */
1304                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1305                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1306
1307                 break;
1308         default:
1309                 g_return_if_reached ();
1310         }
1311
1312         /* Let header view grab the focus if it's being shown */
1313         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1314                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1315         else 
1316                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1317
1318         /* Show changes */
1319         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1320 }
1321
1322 ModestMainWindowStyle
1323 modest_main_window_get_style (ModestMainWindow *self)
1324 {
1325         ModestMainWindowPrivate *priv;
1326
1327         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1328
1329         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1330         return priv->style;
1331 }
1332
1333 static void
1334 toolbar_resize (ModestMainWindow *self)
1335 {
1336         ModestMainWindowPrivate *priv = NULL;
1337         ModestWindowPrivate *parent_priv = NULL;
1338         GtkWidget *widget;
1339         gint static_button_size;
1340         ModestWindowMgr *mgr;
1341
1342         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1343         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1344         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1345
1346         mgr = modest_runtime_get_window_mgr ();
1347         static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1348
1349         if (parent_priv->toolbar) {
1350                 /* left size buttons */
1351                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1352                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1353                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1354                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1355                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1356                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1357                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1358                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1359                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1360                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1361                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1362                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1363                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1364                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1365                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1366                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1367                 
1368                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1369                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1370                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1371                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1372                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1373                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1374                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1375                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1376         }
1377                 
1378 }
1379
1380
1381
1382 static gboolean
1383 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1384 {
1385         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1386                 ModestWindowPrivate *parent_priv;
1387                 ModestWindowMgr *mgr;
1388                 gboolean is_fullscreen;
1389                 GtkAction *fs_toggle_action;
1390                 gboolean active;
1391                 
1392                 mgr = modest_runtime_get_window_mgr ();
1393                 
1394                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1395
1396                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1397                 
1398                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1399                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1400                 if (is_fullscreen != active) {
1401                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1402                 }
1403
1404                 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1405         }
1406
1407         return FALSE;
1408
1409 }
1410
1411 static void 
1412 modest_main_window_show_toolbar (ModestWindow *self,
1413                                  gboolean show_toolbar)
1414 {
1415         ModestMainWindowPrivate *priv = NULL;
1416         ModestWindowPrivate *parent_priv = NULL;        
1417         GtkWidget *reply_button = NULL, *menu = NULL;
1418         GtkWidget *placeholder = NULL;
1419         gint insert_index;
1420         const gchar *action_name;
1421         GtkAction *action;
1422
1423         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1424         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1425         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1426
1427         /* Set optimized view status */
1428         priv->optimized_view = !show_toolbar;
1429
1430         if (!parent_priv->toolbar) {
1431                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1432                                                                   "/ToolBar");
1433                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1434
1435                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1436                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1437                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1438                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1439                 toolbar_resize (MODEST_MAIN_WINDOW (self));
1440                 
1441                 /* Add ProgressBar (Transfer toolbar) */ 
1442                 priv->progress_bar = modest_progress_bar_widget_new ();
1443                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1444                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1445                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1446                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1447                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1448                 
1449                 /* Connect cancel 'clicked' signal to abort progress mode */
1450                 g_signal_connect(priv->cancel_toolitem, "clicked",
1451                                  G_CALLBACK(cancel_progressbar),
1452                                  self);
1453                 
1454                 /* Add it to the observers list */
1455                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1456
1457                 /* Add to window */
1458                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1459                                            GTK_TOOLBAR (parent_priv->toolbar));
1460
1461                 /* Set reply button tap and hold menu */
1462                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1463                                                           "/ToolBar/ToolbarMessageReply");
1464                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1465                                                   "/ToolbarReplyCSM");
1466                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1467
1468                 /* Set send & receive button tap and hold menu */
1469                 update_menus (MODEST_MAIN_WINDOW (self));
1470         }
1471         
1472         if (show_toolbar) {
1473                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1474                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1475                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1476
1477                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1478                 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1479                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1480                 else
1481                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1482         } else {
1483                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1484
1485         }
1486
1487         /* Update also the actions (to update the toggles in the
1488            menus), we have to do it manually because some other window
1489            of the same time could have changed it (remember that the
1490            toolbar fullscreen mode is shared by all the windows of the
1491            same type */
1492         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1493                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1494         else
1495                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1496
1497         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1498         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1499                                                             show_toolbar);
1500 }
1501
1502 static void
1503 on_account_inserted (TnyAccountStore *accoust_store,
1504                      TnyAccount *account,
1505                      gpointer user_data)
1506 {
1507         update_menus (MODEST_MAIN_WINDOW (user_data));
1508 }
1509
1510 static void
1511 on_default_account_changed (ModestAccountMgr* mgr,
1512                             gpointer user_data)
1513 {
1514         update_menus (MODEST_MAIN_WINDOW (user_data));
1515 }
1516
1517 static void
1518 on_account_removed (TnyAccountStore *accoust_store,
1519                      TnyAccount *account,
1520                      gpointer user_data)
1521 {
1522         update_menus (MODEST_MAIN_WINDOW (user_data));
1523 }
1524
1525 static void
1526 on_account_changed (TnyAccountStore *account_store,
1527                     TnyAccount *account,
1528                     gpointer user_data)
1529 {
1530         ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1531         
1532         /* We need to refresh the details widget because it could have changed */
1533         if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS) {
1534                 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1535         }
1536
1537         /* Update the menus as well, the account name could be changed */
1538         update_menus (MODEST_MAIN_WINDOW (user_data));
1539 }
1540
1541 /* 
1542  * This function manages the key events used to navigate between
1543  * header and folder views (when the window is in split view)
1544  *
1545  * FROM         KEY        ACTION
1546  * -------------------------------------------------
1547  * HeaderView   GDK_Left   Move focus to folder view
1548  * FolderView   GDK_Right  Move focus to header view
1549  *
1550  * There is no need to scroll to selected row, the widgets will be the
1551  * responsibles of doing that (probably managing the focus-in event
1552  */
1553 static gboolean 
1554 on_inner_widgets_key_pressed (GtkWidget *widget,
1555                               GdkEventKey *event,
1556                               gpointer user_data)
1557 {
1558         ModestMainWindowPrivate *priv;
1559
1560         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1561
1562         /* Do nothing if we're in SIMPLE style */
1563         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1564                 return FALSE;
1565
1566         if (MODEST_IS_HEADER_VIEW (widget)) {
1567                 if (event->keyval == GDK_Left)
1568                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1569                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1570                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1571                         if (selected_headers > 1) {
1572                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1573                                 return TRUE;
1574                         }
1575                 }
1576         } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1577                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1578
1579         return FALSE;
1580 }
1581
1582 static void
1583 set_alignment (GtkWidget *widget,
1584                gpointer data)
1585 {
1586         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1587         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1588 }
1589
1590 static GtkWidget *
1591 create_empty_view (void)
1592 {
1593         GtkLabel *label = NULL;
1594         GtkWidget *align = NULL;
1595
1596         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1597         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1598         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1599         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1600
1601         return GTK_WIDGET(align);
1602 }
1603
1604 /*
1605  * Free the returned string
1606  */
1607 static gchar *
1608 get_gray_color_markup (GtkWidget *styled_widget)
1609 {
1610         gchar *gray_color_markup = NULL;
1611 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1612         /* Obtain the secondary text color. We need a realized widget, that's why 
1613            we get styled_widget from outside */
1614         GdkColor color;
1615         if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color)) 
1616                 gray_color_markup = modest_text_utils_get_color_string (&color);
1617 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1618         
1619         if (!gray_color_markup) 
1620                 gray_color_markup = g_strdup ("#BBBBBB");
1621
1622         return gray_color_markup;
1623 }
1624
1625 /*
1626  * Free the returned string
1627  */
1628 static gchar*
1629 create_device_name_visual_string (const gchar *device_name,
1630                                   const gchar *gray_color_markup)
1631 {
1632         gchar *tmp, *label;
1633
1634         /* We have to use "" to fill the %s of the translation. We can
1635            not just use the device name because the device name is
1636            shown in a different color, so it could not be included
1637            into the <span> tag */
1638         tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1639         label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s", 
1640                                          gray_color_markup, 
1641                                          tmp, 
1642                                          device_name);
1643         g_free (tmp);
1644
1645         return label;
1646 }
1647
1648 static GtkWidget *
1649 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1650 {
1651         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1652         
1653         GtkWidget *vbox;
1654         GtkWidget *label_w;
1655         gchar *label;
1656         gchar *gray_color_markup;
1657
1658         vbox = gtk_vbox_new (FALSE, 0);
1659
1660         gray_color_markup = get_gray_color_markup (styled_widget);
1661
1662         /* Account description: */
1663         if (modest_tny_account_is_virtual_local_folders (account)
1664                 || (modest_tny_account_is_memory_card_account (account))) {
1665         
1666                 /* Get device name */
1667                 gchar *device_name = NULL;
1668                 if (modest_tny_account_is_virtual_local_folders (account))
1669                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1670                                                       MODEST_CONF_DEVICE_NAME, NULL);
1671                 else
1672                         device_name = g_strdup (tny_account_get_name (account));
1673
1674                 label = create_device_name_visual_string ((const gchar *) device_name, 
1675                                                           (const gchar *) gray_color_markup);
1676                 label_w = gtk_label_new (NULL);
1677                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1678                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1679                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1680                 g_free (device_name);
1681                 g_free (label);
1682         } else {
1683                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1684                         gtk_box_pack_start (GTK_BOX (vbox), 
1685                                 gtk_label_new (tny_account_get_name (account)), 
1686                                 FALSE, FALSE, 0);
1687                 } else {
1688                         /* Other accounts, such as IMAP and POP: */
1689                         
1690                         GString *proto;
1691                         gchar *tmp;
1692         
1693                         /* Put proto in uppercase */
1694                         proto = g_string_new (tny_account_get_proto (account));
1695                         proto = g_string_ascii_up (proto);
1696                         
1697                         /* note: mcen_fi_localroot_description is something like "%s account"
1698                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1699                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1700                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1701                                                          gray_color_markup, tmp, tny_account_get_name (account));
1702                         g_free (tmp);
1703
1704                         label_w = gtk_label_new (NULL);
1705                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1706                         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1707                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1708                         g_string_free (proto, TRUE);
1709                         g_free (label);
1710                 }
1711         }
1712
1713         /* Message count */
1714         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1715         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1716                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1717                                          modest_tny_folder_store_get_message_count (folder_store));
1718         label_w = gtk_label_new (NULL);
1719         gtk_label_set_markup (GTK_LABEL (label_w), label);
1720         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1721         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1722         g_free (label);
1723
1724         /* Folder count */
1725         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1726                                          gray_color_markup, 
1727                                          _("mcen_fi_rootfolder_folders"), 
1728                                          modest_tny_folder_store_get_folder_count (folder_store));
1729         label_w = gtk_label_new (NULL);
1730         gtk_label_set_markup (GTK_LABEL (label_w), label);
1731         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1732         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1733         g_free (label);
1734
1735         /* Size / Date */
1736         if (modest_tny_account_is_virtual_local_folders (account)
1737                 || modest_tny_account_is_memory_card_account (account)) {
1738
1739                 gchar *size = modest_text_utils_get_display_size (
1740                         modest_tny_folder_store_get_local_size (folder_store));
1741                 
1742                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1743                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1744                                                  size);
1745                 g_free (size);
1746                 
1747                 label_w = gtk_label_new (NULL);
1748                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1749                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1750                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1751                 g_free (label);
1752         } else if (TNY_IS_ACCOUNT(folder_store)) {
1753                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1754                 
1755                 time_t last_updated;
1756                 const gchar *last_updated_string;
1757                 /* Get last updated from configuration */
1758                 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (), 
1759                                                                     tny_account_get_id (account));
1760
1761                 if (last_updated > 0) 
1762                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1763                 else
1764                         last_updated_string = g_strdup (_("mcen_va_never"));
1765
1766                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1767                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1768                 label_w = gtk_label_new (NULL);
1769                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1770                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1771                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1772                 g_free (label);
1773         }
1774
1775         g_free (gray_color_markup);
1776
1777         /* Set alignment */
1778         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1779
1780         return vbox;
1781 }
1782
1783 gboolean
1784 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1785 {
1786         ModestMainWindowPrivate *priv = NULL;
1787         
1788         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1789
1790         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1791
1792         return priv->send_receive_in_progress;
1793 }
1794
1795 void 
1796 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1797 {
1798         GtkAction *action = NULL;
1799         GtkWidget *widget = NULL;
1800         ModestMainWindowPrivate *priv = NULL;
1801                 
1802         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1803         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1804         
1805         priv->send_receive_in_progress  = TRUE;
1806
1807         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1808         gtk_action_set_sensitive (action, FALSE);
1809 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1810 /*      gtk_action_set_sensitive (action, FALSE); */
1811         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1812         gtk_widget_set_sensitive (widget, FALSE);
1813
1814
1815 void 
1816 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1817 {
1818         GtkAction *action = NULL;
1819         GtkWidget *widget = NULL;
1820         ModestMainWindowPrivate *priv = NULL;
1821                 
1822         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1823         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1824
1825         priv->send_receive_in_progress  = FALSE;
1826
1827         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1828         gtk_action_set_sensitive (action, TRUE);
1829 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1830 /*      gtk_action_set_sensitive (action, TRUE); */
1831         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1832         gtk_widget_set_sensitive (widget, TRUE);
1833
1834
1835
1836 static void
1837 on_msg_count_changed (ModestHeaderView *header_view,
1838                       TnyFolder *folder,
1839                       TnyFolderChange *change,
1840                       ModestMainWindow *main_window)
1841 {
1842         gboolean folder_empty = FALSE;
1843         gboolean all_marked_as_deleted = FALSE;
1844         TnyFolderChangeChanged changed; 
1845         ModestMainWindowPrivate *priv;
1846         
1847         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1848         g_return_if_fail (TNY_IS_FOLDER(folder));
1849         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1850         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1851         
1852         changed = tny_folder_change_get_changed (change);
1853         
1854         /* If something changes */
1855         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1856                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1857         else
1858                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1859         
1860 /*      Check header removed  (hide marked as DELETED headers) */
1861         if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1862                 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1863         }
1864
1865         /* Check if all messages are marked to be deleted */
1866         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1867         folder_empty = folder_empty || all_marked_as_deleted ;
1868         
1869         /* Set contents style of headers view */
1870         if (folder_empty)  {
1871                 modest_main_window_set_contents_style (main_window,
1872                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1873                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1874         }
1875         else {
1876                 modest_main_window_set_contents_style (main_window,
1877                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1878         }       
1879 }
1880
1881
1882 void 
1883 modest_main_window_set_contents_style (ModestMainWindow *self, 
1884                                        ModestMainWindowContentsStyle style)
1885 {
1886         ModestMainWindowPrivate *priv;
1887
1888         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1889
1890         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1891
1892         /* We allow to set the same content style than the previously
1893            set if there are details, because it could happen when we're
1894            selecting different accounts consecutively */
1895         if ((priv->contents_style == style) &&
1896             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1897                 return;
1898
1899         /* Remove previous child. Delete it if it was an account
1900            details widget */
1901         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1902         if (content) {
1903                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1904                         g_object_ref (content);
1905                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1906                         g_object_ref (priv->empty_view);
1907                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1908                 }
1909                 
1910                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1911         }
1912
1913         priv->contents_style = style;
1914
1915         switch (priv->contents_style) {
1916         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1917                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1918                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1919                                                       TRUE);
1920                 break;
1921         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1922         {
1923                 /* if we're started without main win, there may not be a folder
1924                  * view. this fixes a GLib-Critical */
1925                 if (priv->folder_view) {
1926                         TnyFolderStore *selected_folderstore = 
1927                                 modest_folder_view_get_selected (priv->folder_view);
1928                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1929                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1930                                                                 TNY_ACCOUNT (selected_folderstore));
1931                                 
1932                                 wrap_in_scrolled_window (priv->contents_widget, 
1933                                                          priv->details_widget);
1934                         }
1935                         g_object_unref (selected_folderstore);
1936                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1937                                                               FALSE);
1938                 }
1939                 break;
1940         }
1941         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1942                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1943                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1944                                                       FALSE);
1945                 break;
1946         default:
1947                 g_return_if_reached ();
1948         }
1949
1950         /* Show */
1951         gtk_widget_show_all (priv->contents_widget);
1952 }
1953
1954 ModestMainWindowContentsStyle
1955 modest_main_window_get_contents_style (ModestMainWindow *self)
1956 {
1957         ModestMainWindowPrivate *priv;
1958
1959         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1960
1961         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1962         return priv->contents_style;
1963 }
1964
1965
1966 static void 
1967 on_configuration_key_changed (ModestConf* conf, 
1968                               const gchar *key, 
1969                               ModestConfEvent event,
1970                               ModestConfNotificationId id, 
1971                               ModestMainWindow *self)
1972 {
1973         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1974         TnyAccount *account = NULL;
1975
1976         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1977                 return;
1978
1979         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1980                 return;
1981
1982         if (priv->folder_view) 
1983                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1984
1985         if (account && TNY_IS_ACCOUNT (account) &&
1986             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1987                 GList *children;
1988                 GtkLabel *label;
1989                 const gchar *device_name;
1990                 gchar *new_text, *gray_color_markup;
1991                 
1992                 /* Get label */
1993                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1994                 label = GTK_LABEL (children->data);
1995                 
1996                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1997                                                       MODEST_CONF_DEVICE_NAME, NULL);
1998
1999                 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));          
2000                 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2001                 
2002                 gtk_label_set_markup (label, new_text);
2003                 gtk_widget_show (GTK_WIDGET (label));
2004                 
2005                 g_free (gray_color_markup);
2006                 g_free (new_text);
2007                 g_list_free (children);
2008         }
2009         g_object_unref (account);
2010 }
2011
2012 static gboolean
2013 set_toolbar_transfer_mode (ModestMainWindow *self)
2014 {
2015         ModestMainWindowPrivate *priv = NULL;
2016         
2017         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2018
2019         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2020
2021         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2022         
2023         if (priv->progress_bar_timeout > 0) {
2024                 g_source_remove (priv->progress_bar_timeout);
2025                 priv->progress_bar_timeout = 0;
2026         }
2027
2028         return FALSE;
2029 }
2030
2031 static void 
2032 set_toolbar_mode (ModestMainWindow *self, 
2033                   ModestToolBarModes mode)
2034 {
2035         ModestWindowPrivate *parent_priv = NULL;
2036         ModestMainWindowPrivate *priv = NULL;
2037         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2038         
2039         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2040
2041         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2042         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2043
2044         /* In case this was called before the toolbar exists: */
2045         if (!(parent_priv->toolbar))
2046                 return;
2047
2048         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
2049         
2050         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2051         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2052         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2053
2054         /* Sets current toolbar mode */
2055         priv->current_toolbar_mode = mode;
2056
2057         /* Checks the dimming rules */
2058         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2059
2060         /* Show and hide toolbar items */
2061         switch (mode) {
2062         case TOOLBAR_MODE_NORMAL:
2063                 if (sort_action)
2064                         gtk_action_set_visible (sort_action, TRUE);
2065                 if (refresh_action)
2066                         gtk_action_set_visible (refresh_action, TRUE);
2067                 if (priv->progress_toolitem) {
2068                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2069                         gtk_widget_hide (priv->progress_toolitem);
2070                 }
2071                 if (priv->progress_bar)
2072                         gtk_widget_hide (priv->progress_bar);
2073                 
2074                 if (cancel_action)
2075                         gtk_action_set_visible (cancel_action, FALSE);
2076
2077                 /* Hide toolbar if optimized view is enabled */
2078                 if (priv->optimized_view)
2079                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2080                 break;
2081         case TOOLBAR_MODE_TRANSFER:
2082                 if (sort_action)
2083                         gtk_action_set_visible (sort_action, FALSE);
2084                 if (refresh_action)
2085                         gtk_action_set_visible (refresh_action, FALSE);
2086                 if (cancel_action)
2087                         gtk_action_set_visible (cancel_action, TRUE);
2088                 if (priv->progress_bar)
2089                         gtk_widget_show (priv->progress_bar);
2090                 if (priv->progress_toolitem) {
2091                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2092                         gtk_widget_show (priv->progress_toolitem);
2093                 }
2094
2095                 /* Show toolbar if it's hiden (optimized view ) */
2096                 if (priv->optimized_view)
2097                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2098                 break;
2099         default:
2100                 g_return_if_reached ();
2101         }
2102 }
2103
2104 gboolean
2105 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2106 {
2107         ModestMainWindowPrivate *priv;
2108
2109         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2110         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2111
2112         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2113 }
2114
2115 static void
2116 cancel_progressbar (GtkToolButton *toolbutton,
2117                     ModestMainWindow *self)
2118 {
2119         GSList *tmp;
2120         ModestMainWindowPrivate *priv;
2121         
2122         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2123
2124         /* Get operation observers and cancel all the operations */
2125         tmp = priv->progress_widgets;
2126         while (tmp) {
2127                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2128                 tmp=g_slist_next(tmp);
2129         }
2130 }
2131
2132 static gboolean
2133 observers_empty (ModestMainWindow *self)
2134 {
2135         GSList *tmp = NULL;
2136         ModestMainWindowPrivate *priv;
2137         gboolean is_empty = TRUE;
2138         guint pending_ops = 0;
2139  
2140         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2141         tmp = priv->progress_widgets;
2142
2143         /* Check all observers */
2144         while (tmp && is_empty)  {
2145                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2146                 is_empty = pending_ops == 0;
2147                 
2148                 tmp = g_slist_next(tmp);
2149         }
2150         
2151         return is_empty;
2152 }
2153
2154
2155 /**
2156  * Gets the toolbar mode needed for each mail operation. It stores in
2157  * @mode_changed if the toolbar mode has changed or not
2158  */
2159 static ModestToolBarModes
2160 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2161                                       ModestMailOperation *mail_op,
2162                                       gboolean *mode_changed)
2163 {
2164         ModestToolBarModes mode;
2165         ModestMainWindowPrivate *priv;
2166
2167         *mode_changed = FALSE;
2168         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2169
2170         /* Get toolbar mode from operation id*/
2171         switch (modest_mail_operation_get_type_operation (mail_op)) {
2172         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2173         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2174                 mode = TOOLBAR_MODE_TRANSFER;
2175                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2176                         *mode_changed = TRUE;
2177                 break;
2178         default:
2179                 mode = TOOLBAR_MODE_NORMAL;             
2180         }
2181         return mode;
2182 }
2183
2184 static void 
2185 on_mail_operation_started (ModestMailOperation *mail_op,
2186                            gpointer user_data)
2187 {
2188         ModestMainWindow *self;
2189         ModestMailOperationTypeOperation op_type;
2190         ModestMainWindowPrivate *priv;
2191         ModestToolBarModes mode;
2192         GSList *tmp;
2193         gboolean mode_changed = FALSE;
2194         TnyAccount *account;
2195
2196         self = MODEST_MAIN_WINDOW (user_data);
2197         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2198
2199         /* Do not show progress for receiving operations if the
2200            account is the local account or the MMC one */
2201         op_type = modest_mail_operation_get_type_operation (mail_op);
2202         account = modest_mail_operation_get_account (mail_op);
2203         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2204                 gboolean is_remote;
2205
2206                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2207                               modest_tny_account_is_memory_card_account (account));
2208                 g_object_unref (account);
2209                 if (!is_remote)
2210                         return;
2211         }
2212                
2213         /* Get toolbar mode from operation id*/
2214         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2215
2216         /* Add operation observers and change toolbar if neccessary*/
2217         tmp = priv->progress_widgets;
2218         if (mode == TOOLBAR_MODE_TRANSFER) {
2219                 if (mode_changed && (G_OBJECT (self) == modest_mail_operation_get_source(mail_op)))
2220                         set_toolbar_transfer_mode(self);                    
2221
2222                 while (tmp) {
2223                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2224                                                               mail_op);
2225                         tmp = g_slist_next (tmp);
2226                 }
2227         }
2228 }
2229
2230 static void 
2231 on_mail_operation_finished (ModestMailOperation *mail_op,
2232                             gpointer user_data)
2233 {
2234         ModestToolBarModes mode;
2235         ModestMailOperationTypeOperation op_type;
2236         GSList *tmp = NULL;
2237         ModestMainWindow *self;
2238         gboolean mode_changed;
2239         TnyAccount *account;
2240         ModestMainWindowPrivate *priv;
2241
2242         self = MODEST_MAIN_WINDOW (user_data);
2243         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2244
2245         /* The mail operation was not added to the progress objects if
2246            the account was the local account or the MMC one */
2247         op_type = modest_mail_operation_get_type_operation (mail_op);
2248         account = modest_mail_operation_get_account (mail_op);
2249         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2250                 gboolean is_remote;
2251
2252                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2253                               modest_tny_account_is_memory_card_account (account));
2254                 g_object_unref (account);
2255                 if (!is_remote)
2256                         return;
2257         }
2258
2259         /* Get toolbar mode from operation id*/
2260         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2261
2262         /* Change toolbar mode */
2263         tmp = priv->progress_widgets;
2264         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2265                 while (tmp) {
2266                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2267                                                                  mail_op);
2268                         tmp = g_slist_next (tmp);
2269                 }
2270                 
2271                 /* If no more operations are being observed, NORMAL mode is enabled again */
2272                 if (observers_empty (self)) {
2273                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2274                 }
2275         }
2276 }
2277
2278 static void
2279 on_queue_changed (ModestMailOperationQueue *queue,
2280                   ModestMailOperation *mail_op,
2281                   ModestMailOperationQueueNotification type,
2282                   ModestMainWindow *self)
2283 {
2284         ModestMainWindowPrivate *priv;
2285
2286         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2287
2288         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2289                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2290                                                                G_OBJECT (mail_op),
2291                                                                "operation-started",
2292                                                                G_CALLBACK (on_mail_operation_started),
2293                                                                self);
2294                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2295                                                                G_OBJECT (mail_op),
2296                                                                "operation-finished",
2297                                                                G_CALLBACK (on_mail_operation_finished),
2298                                                                self);
2299         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2300                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2301                                                                   G_OBJECT (mail_op),
2302                                                                   "operation-started");
2303                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2304                                                                   G_OBJECT (mail_op),
2305                                                                   "operation-finished");
2306         }
2307 }
2308
2309 static void
2310 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2311 {
2312         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2313         GtkAction *action;
2314         ModestAccountMgr *mgr;
2315         ModestAccountSettings *settings;
2316         ModestServerAccountSettings *store_settings = NULL;
2317
2318         /* Get account data */
2319         mgr = modest_runtime_get_account_mgr ();
2320         settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2321         if (settings)
2322                 store_settings = modest_account_settings_get_store_settings (settings);
2323
2324         /* Set the new visible & active account */
2325         if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) { 
2326                 const gchar *account_name;
2327
2328                 account_name = modest_account_settings_get_account_name (settings);
2329
2330                 modest_folder_view_set_account_id_of_visible_server_account 
2331                         (priv->folder_view,
2332                          modest_server_account_settings_get_account_name (store_settings));
2333                 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2334                 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2335                 if (action != NULL) {
2336                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2337                                 modest_utils_toggle_action_set_active_block_notify (
2338                                         GTK_TOGGLE_ACTION (action),
2339                                         TRUE);
2340                         }
2341                 }
2342         }
2343         
2344         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2345
2346
2347         /* Free */
2348         if (settings) {
2349                 g_object_unref (store_settings);
2350                 g_object_unref (settings);
2351         }
2352 }
2353
2354 /* Make sure that at least one account is "viewed": */
2355 static void
2356 set_at_least_one_account_visible(ModestMainWindow *self)
2357 {
2358         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2359         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2360
2361         if (!(priv->folder_view)) {
2362                 /* It is too early to do this. */
2363                 return; 
2364         }
2365         
2366         const gchar *active_server_account_name = 
2367                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2368         
2369         if (!active_server_account_name ||
2370                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2371         {
2372                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2373                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2374                 if (default_modest_name) {
2375                         set_account_visible (self, default_modest_name);
2376                 } else if (first_modest_name) {
2377                         set_account_visible (self, first_modest_name);
2378                 }
2379                 g_free (first_modest_name);
2380                 g_free (default_modest_name);
2381         }
2382 }
2383
2384 static void 
2385 on_show_account_action_toggled  (GtkToggleAction *action,
2386                                    gpointer user_data)
2387 {
2388         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2389
2390         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2391         if (gtk_toggle_action_get_active (action))
2392                 set_account_visible (self, acc_name);
2393 }
2394
2395 static void
2396 refresh_account (const gchar *account_name)
2397 {
2398         ModestWindow *win;
2399         
2400         /* win must already exists here, obviously */ 
2401         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2402                                                  FALSE);
2403         if (!win) {
2404                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2405                 return;
2406         }
2407         
2408         /* If account_name == NULL, we must update all (option All) */
2409         if (!account_name)
2410                 modest_ui_actions_do_send_receive_all (win);
2411         else
2412                 modest_ui_actions_do_send_receive (account_name, win);
2413         
2414 }
2415
2416 static void 
2417 on_refresh_account_action_activated  (GtkAction *action,
2418                                       gpointer user_data)
2419 {
2420         refresh_account ((const gchar*) user_data);
2421 }
2422
2423 static void
2424 on_send_receive_csm_activated (GtkMenuItem *item,
2425                                gpointer user_data)
2426 {
2427         refresh_account ((const gchar*) user_data);
2428 }
2429
2430 static gboolean
2431 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2432 {
2433         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2434
2435         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2436         return FALSE;
2437
2438 }
2439
2440 static gboolean
2441 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2442 {
2443         ModestMainWindow *main_window = NULL;
2444         
2445         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2446         main_window = MODEST_MAIN_WINDOW (userdata);
2447         
2448         /* Update toolbar dimming state */
2449         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2450
2451         return FALSE;
2452 }
2453
2454 static gboolean
2455 on_header_view_focus_in (GtkWidget *widget,
2456                          GdkEventFocus *event,
2457                          gpointer userdata)
2458 {
2459         ModestMainWindow *main_window = NULL;
2460
2461         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2462
2463         main_window = MODEST_MAIN_WINDOW (userdata);
2464
2465         /* Update toolbar dimming state */
2466         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2467
2468         return FALSE;
2469 }
2470
2471 static void 
2472 on_folder_selection_changed (ModestFolderView *folder_view,
2473                              TnyFolderStore *folder_store, 
2474                              gboolean selected,
2475                              ModestMainWindow *main_window)
2476 {
2477         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2478         GtkAction *action = NULL;
2479         gboolean show_reply = TRUE;
2480         gboolean show_forward = TRUE;
2481         gboolean show_cancel_send = FALSE;
2482         gboolean show_clipboard = TRUE;
2483         gboolean show_delete = TRUE;
2484
2485         if (selected) {
2486                 if (TNY_IS_ACCOUNT (folder_store)) {
2487                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2488                 } else if (TNY_IS_FOLDER (folder_store)) {
2489                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2490                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2491                                         TNY_FOLDER (folder_store));
2492                                 switch (folder_type) {
2493                                 case TNY_FOLDER_TYPE_DRAFTS:
2494                                         show_clipboard = show_delete = TRUE;
2495                                         show_reply = show_forward = show_cancel_send = FALSE;
2496                                         break;
2497                                 case TNY_FOLDER_TYPE_SENT:
2498                                         show_forward = show_clipboard = show_delete = TRUE;
2499                                         show_reply = show_cancel_send = FALSE;
2500                                         break;
2501                                 case TNY_FOLDER_TYPE_OUTBOX:
2502                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2503                                         show_reply = show_forward = FALSE;
2504                                         break;
2505                                 case TNY_FOLDER_TYPE_INVALID:
2506                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2507                                         break;
2508                                 default:
2509                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2510                                         show_cancel_send = FALSE;
2511                                 }
2512                         } else {
2513                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2514                                 show_cancel_send = FALSE;
2515                         }
2516                 }
2517         }
2518
2519         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2520         gtk_action_set_visible (action, show_reply);
2521         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2522         gtk_action_set_visible (action, show_reply);
2523         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2524         gtk_action_set_visible (action, show_forward);
2525         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2526         gtk_action_set_visible (action, show_cancel_send);
2527         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2528         gtk_action_set_visible (action, show_delete);
2529
2530         /* We finally call to the ui actions handler, after updating properly
2531          * the header view CSM */
2532         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2533 }
2534
2535 gboolean 
2536 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2537                                                    GtkTreeModel *model,
2538                                                    GtkTreeRowReference *row_reference,
2539                                                    ModestMainWindow *self)
2540 {
2541         ModestMainWindowPrivate *priv = NULL;
2542         GtkTreeModel *header_model = NULL;
2543         GtkTreePath *path = NULL;
2544
2545         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2546         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2547         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2548
2549         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2550         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2551
2552         /* Do nothing if we changed the folder in the main view */
2553         if (header_model != model)
2554                 return FALSE;
2555
2556         /* Select the message in the header view */
2557         path = gtk_tree_row_reference_get_path (row_reference);
2558         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2559                                   path, NULL, FALSE);
2560         gtk_tree_path_free (path);
2561
2562         return TRUE;
2563 }
2564
2565 static gboolean
2566 show_updating_banner (gpointer user_data)
2567 {
2568         ModestMainWindowPrivate *priv = NULL;
2569
2570         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2571
2572         if (priv->updating_banner == NULL) {
2573
2574                 /* We're outside the main lock */
2575                 gdk_threads_enter ();
2576                 priv->updating_banner = 
2577                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2578                                                           _CS ("ckdg_pb_updating"));
2579                 gdk_threads_leave ();
2580         }
2581
2582         /* Remove timeout */
2583         priv->updating_banner_timeout = 0;
2584         return FALSE;
2585 }
2586
2587 /**
2588  * We use this function to show/hide a progress banner showing
2589  * "Updating" while the header view is being filled. We're not showing
2590  * it unless the update takes more than 2 seconds
2591  *
2592  * If starting = TRUE then the refresh is starting, otherwise it means
2593  * that is has just finished
2594  */
2595 static void 
2596 on_updating_msg_list (ModestHeaderView *header_view,
2597                       gboolean starting,
2598                       gpointer user_data)
2599 {
2600         ModestMainWindowPrivate *priv = NULL;
2601
2602         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2603         
2604         /* Remove old timeout */
2605         if (priv->updating_banner_timeout > 0) {
2606                 g_source_remove (priv->updating_banner_timeout);
2607                 priv->updating_banner_timeout = 0;
2608         }
2609
2610         /* Create a new timeout */
2611         if (starting) {
2612                 priv->updating_banner_timeout = 
2613                         g_timeout_add (2000, show_updating_banner, user_data);
2614         } else {
2615                 /* Remove the banner if exists */
2616                 if (priv->updating_banner) {
2617                         gtk_widget_destroy (priv->updating_banner);
2618                         priv->updating_banner = NULL;
2619                 }
2620         }
2621 }