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