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