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