* Window manager mimics the way close should work if main window implements the three...
[modest] / src / hildon2 / modest-main-window.c
1 /* Copyright (c) 2006, y2008 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-folder-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 CSM */
904         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
905         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
906         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "tap-and-hold",
907                                                        G_CALLBACK(_folder_view_csm_menu_activated),
908                                                        self);
909
910         /* folder view row activated */
911         priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), "row-activated",
912                                                        G_CALLBACK(on_folder_view_row_activated),
913                                                        self);
914
915         /* header view */
916         priv->sighandlers = 
917                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
918                                            G_CALLBACK(modest_ui_actions_on_header_selected), self);
919         priv->sighandlers = 
920                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
921                                            G_CALLBACK(modest_ui_actions_on_header_activated), self);
922         priv->sighandlers = 
923                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
924                                            G_CALLBACK(modest_ui_actions_on_item_not_found), self);
925         priv->sighandlers = 
926                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
927                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
928         priv->sighandlers = 
929                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
930                                            G_CALLBACK(on_msg_count_changed), self);
931         priv->sighandlers = 
932                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
933                                            G_CALLBACK (on_header_view_focus_in), self);
934         priv->sighandlers = 
935                 modest_signal_mgr_connect (priv->sighandlers,
936                                            G_OBJECT (priv->header_view), 
937                                            "updating-msg-list",
938                                            G_CALLBACK (on_updating_msg_list), 
939                                            self);
940         
941         /* window */
942         /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
943          * in destroy stage */
944         g_signal_connect (G_OBJECT (self), "destroy", G_CALLBACK (on_window_destroy), NULL);
945
946         g_signal_connect (G_OBJECT (self), "notify::visible", G_CALLBACK (on_window_hide), NULL);
947
948         /* Mail Operation Queue */
949         priv->sighandlers = 
950                 modest_signal_mgr_connect (priv->sighandlers,
951                                            G_OBJECT (modest_runtime_get_mail_operation_queue ()),
952                                            "queue-changed", 
953                                            G_CALLBACK (on_queue_changed), self);
954         
955         /* Track changes in the device name */
956         priv->sighandlers = 
957                 modest_signal_mgr_connect (priv->sighandlers,
958                                            G_OBJECT(modest_runtime_get_conf ()),
959                                            "key_changed", 
960                                            G_CALLBACK (on_configuration_key_changed), 
961                                            self);
962         
963         /* Track account changes. We need to refresh the toolbar */
964         priv->sighandlers = 
965                 modest_signal_mgr_connect (priv->sighandlers,
966                                            G_OBJECT (modest_runtime_get_account_store ()),
967                                            "account_inserted", 
968                                            G_CALLBACK (on_account_inserted),
969                                            self);
970         priv->sighandlers = 
971                 modest_signal_mgr_connect (priv->sighandlers,
972                                            G_OBJECT (modest_runtime_get_account_store ()),
973                                            "account_removed", 
974                                            G_CALLBACK (on_account_removed),
975                                            self);
976
977         /* We need to refresh the send & receive menu to change the bold
978          * account when the default account changes. */
979         priv->sighandlers = 
980                 modest_signal_mgr_connect (priv->sighandlers,
981                                            G_OBJECT (modest_runtime_get_account_mgr ()),
982                                            "default_account_changed", 
983                                            G_CALLBACK (on_default_account_changed),
984                                            self);
985
986         /* Account store */
987         priv->sighandlers = 
988                 modest_signal_mgr_connect (priv->sighandlers,
989                                            G_OBJECT (modest_runtime_get_account_store ()),
990                                            "account_changed", 
991                                            G_CALLBACK (on_account_changed),
992                                            self);
993 }
994
995 static void 
996 on_hildon_program_is_topmost_notify(GObject *self,
997                                     GParamSpec *propert_param, 
998                                     gpointer user_data)
999 {
1000         HildonProgram *app = HILDON_PROGRAM (self);
1001         
1002         /* Note that use of hildon_program_set_can_hibernate() 
1003          * is generally referred to as "setting the killable flag", 
1004          * though hibernation does not seem equal to death.
1005          * murrayc */
1006                  
1007         if (hildon_program_get_is_topmost (app)) {
1008                 /* Prevent hibernation when the progam comes to the foreground,
1009                  * because hibernation should only happen when the application 
1010                  * is in the background: */
1011                 hildon_program_set_can_hibernate (app, FALSE);
1012
1013                 /* Remove new mail visual notifications */
1014                 modest_platform_remove_new_mail_notifications (TRUE);
1015         } else {
1016                 /* Allow hibernation if the program has gone to the background: */
1017                 
1018                 /* However, prevent hibernation while the settings are being changed: */
1019                 const gboolean hibernation_prevented = 
1020                         modest_window_mgr_get_hibernation_is_prevented (
1021                                                                         modest_runtime_get_window_mgr ()); 
1022         
1023                 if (hibernation_prevented)
1024                         hildon_program_set_can_hibernate (app, FALSE);
1025                 else {
1026                         /* Allow hibernation, after saving the state: */
1027                         modest_osso_save_state();
1028                         hildon_program_set_can_hibernate (app, TRUE);
1029                 }
1030         }       
1031 }
1032
1033 typedef struct
1034 {
1035         gulong handler_id;
1036 } ShowHelper;
1037
1038 static void
1039 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1040 {
1041         ShowHelper *helper = (ShowHelper *) user_data;
1042         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1043         
1044         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1045         modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self), 
1046                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS);
1047         gtk_tree_view_expand_all (GTK_TREE_VIEW (priv->folder_view));
1048
1049         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1050
1051         /* Connect signals */
1052         connect_signals (MODEST_MAIN_WINDOW (self));
1053
1054         /* Set account store */
1055         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1056                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1057
1058         /* Load previous osso state, for instance if we are being restored from 
1059          * hibernation:  */
1060         modest_osso_load_state ();
1061
1062         /* Restore window & widget settings */  
1063         priv->wait_for_settings = TRUE;
1064         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1065         priv->wait_for_settings = FALSE;
1066
1067         /* Check if accounts exist and show the account wizard if not */
1068         gboolean accounts_exist = 
1069                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1070
1071         if (!accounts_exist) {
1072                 /* This is necessary to have the main window shown behind the dialog 
1073                 It's an ugly hack... jschmid */
1074                 gtk_widget_show_all(GTK_WIDGET(self));
1075                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1076         } else {
1077                 update_menus (MODEST_MAIN_WINDOW (self));
1078         }
1079
1080         /* Never call this function again (NOTE that it could happen
1081            as we hide the main window instead of closing it while
1082            there are operations ongoing) and free the helper */
1083         g_signal_handler_disconnect (self, helper->handler_id);
1084         g_slice_free (ShowHelper, helper);
1085 }
1086
1087 static void 
1088 osso_display_event_cb (osso_display_state_t state, 
1089                        gpointer data)
1090 {
1091         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1092
1093         priv->display_state = state;
1094
1095         /* Stop blinking if the screen becomes on */
1096         if (priv->display_state == OSSO_DISPLAY_ON)
1097                 modest_platform_remove_new_mail_notifications (TRUE);
1098 }
1099
1100 ModestWindow *
1101 modest_main_window_new (void)
1102 {
1103         ModestMainWindow *self = NULL;  
1104         ModestMainWindowPrivate *priv = NULL;
1105         ModestWindowPrivate *parent_priv = NULL;
1106         ModestDimmingRulesGroup *menu_rules_group = NULL;
1107         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1108         GtkActionGroup *action_group = NULL;
1109         GError *error = NULL;
1110         HildonProgram *app;
1111         GdkPixbuf *window_icon;
1112         ShowHelper *helper;
1113         
1114         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1115         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1116         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1117
1118         parent_priv->ui_manager = gtk_ui_manager_new();
1119         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1120
1121         action_group = gtk_action_group_new ("ModestMainWindowActions");
1122         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1123
1124         menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1125         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1126
1127         /* Add common actions */
1128         gtk_action_group_add_actions (action_group,
1129                                       modest_action_entries,
1130                                       G_N_ELEMENTS (modest_action_entries),
1131                                       self);
1132
1133         gtk_action_group_add_actions (action_group,
1134                                       modest_folder_view_action_entries,
1135                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1136                                       self);
1137
1138         gtk_action_group_add_actions (action_group,
1139                                       modest_header_view_action_entries,
1140                                       G_N_ELEMENTS (modest_header_view_action_entries),
1141                                       self);
1142
1143         gtk_action_group_add_toggle_actions (action_group,
1144                                              modest_main_window_toggle_action_entries,
1145                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1146                                              self);
1147
1148         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1149         g_object_unref (action_group);
1150
1151         /* Load the UI definition */
1152         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1153                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1154         if (error != NULL) {
1155                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1156                 g_error_free (error);
1157                 error = NULL;
1158         }
1159
1160         /* Add common dimming rules */
1161         modest_dimming_rules_group_add_rules (menu_rules_group, 
1162                                               modest_main_window_menu_dimming_entries,
1163                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1164                                               MODEST_WINDOW (self));
1165         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1166                                               modest_main_window_toolbar_dimming_entries,
1167                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1168                                               MODEST_WINDOW (self));
1169
1170         /* Insert dimming rules group for this window */
1171         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1172         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1173         g_object_unref (menu_rules_group);
1174         g_object_unref (toolbar_rules_group);
1175         
1176         /* Add accelerators */
1177         gtk_window_add_accel_group (GTK_WINDOW (self), 
1178                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1179
1180         /* Menubar. Update the state of some toggles */
1181         parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1182         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1183         gtk_widget_show (parent_priv->menubar);
1184
1185         /* Get device name */
1186         modest_maemo_utils_get_device_name ();
1187
1188         /* header view */
1189         priv->header_view =
1190                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1191         g_object_ref (priv->header_view);
1192         if (!priv->header_view)
1193                 g_printerr ("modest: cannot instantiate header view\n");
1194         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1195         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1196                                       MODEST_CONF_HEADER_VIEW_KEY);
1197
1198         /* Other style properties of header view */
1199         g_object_set (G_OBJECT (priv->header_view), 
1200                       "rules-hint", FALSE,
1201                       NULL);
1202         /* gtk_widget_show (priv->header_view); */
1203
1204         /* Empty view */ 
1205         priv->empty_view = create_empty_view ();
1206         gtk_widget_show (priv->empty_view);
1207         g_object_ref (priv->empty_view);
1208                  
1209         /* Create scrolled windows */
1210         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1211         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1212                                         GTK_POLICY_NEVER,
1213                                         GTK_POLICY_AUTOMATIC);
1214         /* gtk_widget_show (priv->contents_widget); */
1215
1216         /* putting it all together... */
1217         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1218         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->contents_widget, TRUE, TRUE,0);
1219         gtk_widget_show (priv->main_vbox);
1220         
1221         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1222         
1223         app = hildon_program_get_instance ();
1224         hildon_program_add_window (app, HILDON_WINDOW (self));
1225         
1226         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1227                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1228
1229         /* Connect to "show" action. We delay the creation of some
1230            elements until that moment */
1231         helper = g_slice_new0 (ShowHelper);
1232         helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1233                                                G_CALLBACK (modest_main_window_on_show), 
1234                                                helper);
1235         
1236         /* Set window icon */
1237         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1238         if (window_icon) {
1239                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1240                 g_object_unref (window_icon);
1241         }
1242
1243         /* Listen for changes in the screen, we don't want to show a
1244            led pattern when the display is on for example */
1245         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1246                                       osso_display_event_cb,
1247                                       self); 
1248
1249         /* Dont't restore settings here, 
1250          * because it requires a gtk_widget_show(), 
1251          * and we don't want to do that until later,
1252          * so that the UI is not visible for non-menu D-Bus activation.
1253          */
1254
1255         return MODEST_WINDOW(self);
1256 }
1257
1258 void 
1259 modest_main_window_set_style (ModestMainWindow *self, 
1260                               ModestMainWindowStyle style)
1261 {
1262         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1263
1264         /* We only provide simple style */
1265         return;
1266 }
1267
1268 ModestMainWindowStyle
1269 modest_main_window_get_style (ModestMainWindow *self)
1270 {
1271         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1272
1273         return MODEST_MAIN_WINDOW_STYLE_SIMPLE;
1274 }
1275
1276 static void
1277 toolbar_resize (ModestMainWindow *self)
1278 {
1279         ModestMainWindowPrivate *priv = NULL;
1280         ModestWindowPrivate *parent_priv = NULL;
1281         GtkWidget *widget;
1282         gint static_button_size;
1283         ModestWindowMgr *mgr;
1284
1285         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1286         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1287         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1288
1289         mgr = modest_runtime_get_window_mgr ();
1290         static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1291
1292         if (parent_priv->toolbar) {
1293                 /* left size buttons */
1294                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1295                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1296                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1297                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1298                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1299                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1300                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1301                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1302                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1303                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1304                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1305                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1306                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1307                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1308                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1309                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1310                 
1311                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1312                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1313                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1314                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1315                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1316                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1317                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1318                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1319         }
1320                 
1321 }
1322
1323 static void 
1324 modest_main_window_show_toolbar (ModestWindow *self,
1325                                  gboolean show_toolbar)
1326 {
1327         ModestMainWindowPrivate *priv = NULL;
1328         ModestWindowPrivate *parent_priv = NULL;        
1329         GtkWidget *reply_button = NULL, *menu = NULL;
1330         GtkWidget *placeholder = NULL;
1331         gint insert_index;
1332
1333         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1334         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1335         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1336
1337         /* Set optimized view status */
1338         priv->optimized_view = !show_toolbar;
1339
1340         if (!parent_priv->toolbar) {
1341                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1342                                                                   "/ToolBar");
1343                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1344
1345                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1346                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1347                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1348                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1349                 toolbar_resize (MODEST_MAIN_WINDOW (self));
1350                 
1351                 /* Add ProgressBar (Transfer toolbar) */ 
1352                 priv->progress_bar = modest_progress_bar_new ();
1353                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1354                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1355                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1356                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1357                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1358                 
1359                 /* Connect cancel 'clicked' signal to abort progress mode */
1360                 g_signal_connect(priv->cancel_toolitem, "clicked",
1361                                  G_CALLBACK(cancel_progressbar),
1362                                  self);
1363                 
1364                 /* Add it to the observers list */
1365                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1366
1367                 /* Add to window */
1368                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1369                                            GTK_TOOLBAR (parent_priv->toolbar));
1370
1371                 /* Set reply button tap and hold menu */
1372                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1373                                                           "/ToolBar/ToolbarMessageReply");
1374                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1375                                                   "/ToolbarReplyCSM");
1376                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1377
1378                 /* Set send & receive button tap and hold menu */
1379                 update_menus (MODEST_MAIN_WINDOW (self));
1380         }
1381         
1382         if (show_toolbar) {
1383                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1384                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1385                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1386
1387                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1388                 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1389                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1390                 else
1391                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1392         } else {
1393                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1394
1395         }
1396 }
1397
1398 static void
1399 on_account_inserted (TnyAccountStore *accoust_store,
1400                      TnyAccount *account,
1401                      gpointer user_data)
1402 {
1403         /* Transport accounts and local ones (MMC and the Local
1404            folders account do now cause menu changes */
1405         if (TNY_IS_STORE_ACCOUNT (account) && 
1406             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1407                 /* Update menus */
1408                 update_menus (MODEST_MAIN_WINDOW (user_data));
1409         }
1410 }
1411
1412 static void
1413 on_default_account_changed (ModestAccountMgr* mgr,
1414                             gpointer user_data)
1415 {
1416         update_menus (MODEST_MAIN_WINDOW (user_data));
1417 }
1418
1419 static void
1420 on_account_removed (TnyAccountStore *accoust_store,
1421                      TnyAccount *account,
1422                      gpointer user_data)
1423 {
1424         /* Transport accounts and local ones (MMC and the Local
1425            folders account do now cause menu changes */
1426         if (TNY_IS_STORE_ACCOUNT (account) && 
1427             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1428                 update_menus (MODEST_MAIN_WINDOW (user_data));
1429 }
1430
1431 static void
1432 on_account_changed (TnyAccountStore *account_store,
1433                     TnyAccount *account,
1434                     gpointer user_data)
1435 {
1436         ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1437
1438         /* Transport accounts and local ones (MMC and the Local
1439            folders account do now cause menu changes */
1440         if (TNY_IS_STORE_ACCOUNT (account)) {
1441                 /* Update the menus as well, name could change */
1442                 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1443                         update_menus (MODEST_MAIN_WINDOW (win));
1444         }
1445 }
1446
1447 /* 
1448  * This function manages the key events used to navigate between
1449  * header and folder views (when the window is in split view)
1450  *
1451  * FROM         KEY        ACTION
1452  * -------------------------------------------------
1453  * HeaderView   GDK_Left   Move focus to folder view
1454  * FolderView   GDK_Right  Move focus to header view
1455  *
1456  * There is no need to scroll to selected row, the widgets will be the
1457  * responsibles of doing that (probably managing the focus-in event
1458  */
1459 static gboolean 
1460 on_inner_widgets_key_pressed (GtkWidget *widget,
1461                               GdkEventKey *event,
1462                               gpointer user_data)
1463 {
1464         ModestMainWindowPrivate *priv;
1465
1466         if (event->type == GDK_KEY_RELEASE)
1467                 return FALSE;
1468
1469         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1470
1471         /* Do nothing if we're in SIMPLE style */
1472         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1473                 return FALSE;
1474
1475         if (MODEST_IS_HEADER_VIEW (widget)) {
1476                 if (event->keyval == GDK_Left)
1477                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1478                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1479                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1480                         if (selected_headers > 1) {
1481                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1482                                 return TRUE;
1483                         } else {
1484                                 GtkTreePath * cursor_path;
1485                                 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1486                                 if (cursor_path == NULL) {
1487                                         GtkTreeSelection *selection;
1488                                         GList *list;
1489                                         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1490                                         list = gtk_tree_selection_get_selected_rows (selection, NULL);
1491
1492                                         if (list != NULL)
1493                                                 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1494                                         g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1495                                         g_list_free (list);
1496                                 }
1497                         }
1498                 }
1499         } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1500 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1501                 GtkTreePath *selected_path = NULL;
1502                 GtkTreePath *start_path = NULL;
1503                 GtkTreePath *end_path = NULL;
1504                 GList *selected;
1505                 GtkTreeSelection *selection;
1506
1507                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1508                 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1509                 if (selected != NULL) {
1510                         selected_path = (GtkTreePath *) selected->data;
1511                         if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1512                                                              &start_path,
1513                                                              &end_path)) {
1514                                 
1515                                 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1516                                     (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1517                                         
1518                                         /* Scroll to first path */
1519                                         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1520                                                                       selected_path,
1521                                                                       NULL,
1522                                                                       TRUE,
1523                                                                       0.5,
1524                                                                       0.0);
1525                                 }
1526                         }
1527                         if (start_path)
1528                                 gtk_tree_path_free (start_path);
1529                         if (end_path)
1530                                 gtk_tree_path_free (end_path);
1531                         g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1532                         g_list_free (selected);
1533                 }
1534 #endif /* GTK_CHECK_VERSION */
1535                         /* fix scroll */
1536                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1537         }
1538
1539         return FALSE;
1540 }
1541
1542 static GtkWidget *
1543 create_empty_view (void)
1544 {
1545         GtkLabel *label = NULL;
1546         GtkWidget *align = NULL;
1547
1548         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1549         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1550         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1551         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1552
1553         return GTK_WIDGET(align);
1554 }
1555
1556
1557 gboolean
1558 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1559 {
1560         ModestMainWindowPrivate *priv = NULL;
1561         
1562         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1563
1564         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1565
1566         return priv->send_receive_in_progress;
1567 }
1568
1569 void 
1570 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1571 {
1572         GtkAction *action = NULL;
1573         GtkWidget *widget = NULL;
1574         ModestMainWindowPrivate *priv = NULL;
1575                 
1576         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1577         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1578         
1579         priv->send_receive_in_progress  = TRUE;
1580
1581         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1582         gtk_action_set_sensitive (action, FALSE);
1583 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1584 /*      gtk_action_set_sensitive (action, FALSE); */
1585         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1586         gtk_widget_set_sensitive (widget, FALSE);
1587
1588
1589 void 
1590 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1591 {
1592         GtkAction *action = NULL;
1593         GtkWidget *widget = NULL;
1594         ModestMainWindowPrivate *priv = NULL;
1595
1596         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1597         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1598
1599         priv->send_receive_in_progress  = FALSE;
1600
1601         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1602         gtk_action_set_sensitive (action, TRUE);
1603 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1604 /*      gtk_action_set_sensitive (action, TRUE); */
1605         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");
1606         gtk_widget_set_sensitive (widget, TRUE);
1607 }
1608
1609
1610 static void
1611 on_msg_count_changed (ModestHeaderView *header_view,
1612                       TnyFolder *folder,
1613                       TnyFolderChange *change,
1614                       ModestMainWindow *main_window)
1615 {
1616         gboolean refilter = FALSE;
1617         gboolean folder_empty = FALSE;
1618         gboolean all_marked_as_deleted = FALSE;
1619         ModestMainWindowPrivate *priv;
1620
1621         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1622         g_return_if_fail (TNY_IS_FOLDER(folder));
1623         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1624
1625         if (change != NULL) {
1626                 TnyFolderChangeChanged changed;
1627
1628                 changed = tny_folder_change_get_changed (change);
1629                 /* If something changes */
1630                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1631                         folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
1632                 else
1633                         folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1634
1635                 /* Play a sound (if configured) and make the LED blink  */
1636                 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1637                         modest_platform_push_email_notification ();
1638                 }
1639
1640                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
1641                         refilter = TRUE;
1642         } else {
1643                 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
1644         }
1645
1646         /* Check if all messages are marked to be deleted */
1647         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1648         folder_empty = folder_empty || all_marked_as_deleted;
1649
1650         /* Set contents style of headers view */
1651         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY ||
1652             priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1653                 if (folder_empty)  {
1654                         modest_main_window_set_contents_style (main_window,
1655                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1656                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1657                 } else {
1658                         modest_main_window_set_contents_style (main_window,
1659                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1660                 }
1661         }
1662
1663         if (refilter)
1664                 modest_header_view_refilter (header_view);
1665 }
1666
1667
1668 void 
1669 modest_main_window_set_contents_style (ModestMainWindow *self, 
1670                                        ModestMainWindowContentsStyle style)
1671 {
1672         ModestMainWindowPrivate *priv;
1673
1674         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1675
1676         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1677
1678         /* We allow to set the same content style than the previously
1679            set if there are details, because it could happen when we're
1680            selecting different accounts consecutively */
1681         if ((priv->contents_style == style) &&
1682             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1683                 return;
1684
1685         /* Remove previous child. Delete it if it was an account
1686            details widget */
1687         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1688         if (content) {
1689                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1690                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1691                 }
1692                 
1693                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1694         }
1695
1696         priv->contents_style = style;
1697
1698         switch (priv->contents_style) {
1699         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_FOLDERS:
1700                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->folder_view));
1701                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1702                                                       TRUE);
1703                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1704                 break;
1705         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1706                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1707                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1708                                                       TRUE);
1709                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1710                 gtk_widget_show (GTK_WIDGET (priv->header_view));
1711                 break;
1712         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1713                 g_message ("This view is not supported in Fremantle style");
1714                 break;
1715         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1716                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1717                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1718                                                       FALSE);
1719                 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1720                         gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
1721                 break;
1722         default:
1723                 g_return_if_reached ();
1724         }
1725
1726         /* Show */
1727         gtk_widget_show_all (priv->contents_widget);
1728 }
1729
1730 ModestMainWindowContentsStyle
1731 modest_main_window_get_contents_style (ModestMainWindow *self)
1732 {
1733         ModestMainWindowPrivate *priv;
1734
1735         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1736
1737         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1738         return priv->contents_style;
1739 }
1740
1741
1742 static void 
1743 on_configuration_key_changed (ModestConf* conf, 
1744                               const gchar *key, 
1745                               ModestConfEvent event,
1746                               ModestConfNotificationId id, 
1747                               ModestMainWindow *self)
1748 {
1749         /* TODO: remove this handler. Now we don't support details view, 
1750          *  so this must be removed */
1751
1752         return;
1753 }
1754
1755 static gboolean
1756 set_toolbar_transfer_mode (ModestMainWindow *self)
1757 {
1758         ModestMainWindowPrivate *priv = NULL;
1759         
1760         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1761
1762         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1763
1764         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1765         
1766         if (priv->progress_bar_timeout > 0) {
1767                 g_source_remove (priv->progress_bar_timeout);
1768                 priv->progress_bar_timeout = 0;
1769         }
1770
1771         return FALSE;
1772 }
1773
1774 static void 
1775 set_toolbar_mode (ModestMainWindow *self, 
1776                   ModestToolBarModes mode)
1777 {
1778         ModestWindowPrivate *parent_priv = NULL;
1779         ModestMainWindowPrivate *priv = NULL;
1780         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1781         
1782         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1783
1784         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1785         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1786
1787         /* In case this was called before the toolbar exists: */
1788         if (!(parent_priv->toolbar))
1789                 return;
1790
1791         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1792         
1793         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1794         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1795         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1796
1797         /* Sets current toolbar mode */
1798         priv->current_toolbar_mode = mode;
1799
1800         /* Checks the dimming rules */
1801         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1802         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1803
1804         /* Show and hide toolbar items */
1805         switch (mode) {
1806         case TOOLBAR_MODE_NORMAL:
1807                 if (sort_action)
1808                         gtk_action_set_visible (sort_action, TRUE);
1809                 if (refresh_action)
1810                         gtk_action_set_visible (refresh_action, TRUE);
1811                 if (priv->progress_toolitem) {
1812                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1813                         gtk_widget_hide (priv->progress_toolitem);
1814                 }
1815                 if (priv->progress_bar)
1816                         gtk_widget_hide (priv->progress_bar);
1817                 
1818                 if (cancel_action)
1819                         gtk_action_set_visible (cancel_action, FALSE);
1820
1821                 /* Hide toolbar if optimized view is enabled */
1822                 if (priv->optimized_view)
1823                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1824                 break;
1825         case TOOLBAR_MODE_TRANSFER:
1826                 if (sort_action)
1827                         gtk_action_set_visible (sort_action, FALSE);
1828                 if (refresh_action)
1829                         gtk_action_set_visible (refresh_action, FALSE);
1830                 if (cancel_action)
1831                         gtk_action_set_visible (cancel_action, TRUE);
1832                 if (priv->progress_bar)
1833                         gtk_widget_show (priv->progress_bar);
1834                 if (priv->progress_toolitem) {
1835                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1836                         gtk_widget_show (priv->progress_toolitem);
1837                 }
1838
1839                 /* Show toolbar if it's hiden (optimized view ) */
1840                 if (priv->optimized_view)
1841                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1842                 break;
1843         default:
1844                 g_return_if_reached ();
1845         }
1846 }
1847
1848 gboolean
1849 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
1850 {
1851         ModestMainWindowPrivate *priv;
1852
1853         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1854         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1855
1856         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
1857 }
1858
1859 static void
1860 cancel_progressbar (GtkToolButton *toolbutton,
1861                     ModestMainWindow *self)
1862 {
1863         GSList *tmp;
1864         ModestMainWindowPrivate *priv;
1865         
1866         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1867
1868         /* Get operation observers and cancel all the operations */
1869         tmp = priv->progress_widgets;
1870         while (tmp) {
1871                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1872                 tmp=g_slist_next(tmp);
1873         }
1874 }
1875
1876 static gboolean
1877 observers_empty (ModestMainWindow *self)
1878 {
1879         GSList *tmp = NULL;
1880         ModestMainWindowPrivate *priv;
1881         gboolean is_empty = TRUE;
1882         guint pending_ops = 0;
1883  
1884         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1885         tmp = priv->progress_widgets;
1886
1887         /* Check all observers */
1888         while (tmp && is_empty)  {
1889                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1890                 is_empty = pending_ops == 0;
1891                 
1892                 tmp = g_slist_next(tmp);
1893         }
1894         
1895         return is_empty;
1896 }
1897
1898
1899 /**
1900  * Gets the toolbar mode needed for each mail operation. It stores in
1901  * @mode_changed if the toolbar mode has changed or not
1902  */
1903 static ModestToolBarModes
1904 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
1905                                       ModestMailOperation *mail_op,
1906                                       gboolean *mode_changed)
1907 {
1908         ModestToolBarModes mode;
1909         ModestMainWindowPrivate *priv;
1910
1911         *mode_changed = FALSE;
1912         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1913
1914         /* Get toolbar mode from operation id*/
1915         switch (modest_mail_operation_get_type_operation (mail_op)) {
1916         case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
1917         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1918                 mode = TOOLBAR_MODE_TRANSFER;
1919                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1920                         *mode_changed = TRUE;
1921                 break;
1922         default:
1923                 mode = TOOLBAR_MODE_NORMAL;             
1924         }
1925         return mode;
1926 }
1927
1928 static void 
1929 on_mail_operation_started (ModestMailOperation *mail_op,
1930                            gpointer user_data)
1931 {
1932         ModestMainWindow *self;
1933         ModestMailOperationTypeOperation op_type;
1934         ModestMainWindowPrivate *priv;
1935         ModestToolBarModes mode;
1936         GSList *tmp;
1937         gboolean mode_changed = FALSE;
1938         TnyAccount *account = NULL;
1939
1940         self = MODEST_MAIN_WINDOW (user_data);
1941         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1942
1943         /* Do not show progress for receiving operations if the
1944            account is the local account or the MMC one */
1945         op_type = modest_mail_operation_get_type_operation (mail_op);
1946         account = modest_mail_operation_get_account (mail_op);
1947         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
1948                 gboolean is_remote;
1949
1950                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
1951                               modest_tny_account_is_memory_card_account (account));
1952                 if (!is_remote) {
1953                         g_object_unref (account);
1954                         return;
1955                 }
1956
1957                 /* Show information banner. Remove old timeout */
1958                 if (priv->opening_banner_timeout > 0) {
1959                         g_source_remove (priv->opening_banner_timeout);
1960                         priv->opening_banner_timeout = 0;
1961                 }
1962                 /* Create a new timeout */
1963                 priv->opening_banner_timeout = 
1964                         g_timeout_add (2000, show_opening_banner, self);
1965         }
1966
1967         /* Not every mail operation has account, noop does not */
1968         if (account)
1969                 g_object_unref (account);
1970                
1971         /* Get toolbar mode from operation id*/
1972         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
1973
1974         /* Add operation observers and change toolbar if neccessary*/
1975         tmp = priv->progress_widgets;
1976         if (mode == TOOLBAR_MODE_TRANSFER) {
1977                 if (mode_changed) {
1978                         GObject *source = modest_mail_operation_get_source(mail_op);
1979                         if (G_OBJECT (self) == source) {
1980                                 set_toolbar_transfer_mode(self);
1981                         }
1982                         g_object_unref (source);
1983                 }
1984
1985                 while (tmp) {
1986                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1987                                                               mail_op);
1988                         tmp = g_slist_next (tmp);
1989                 }
1990         }
1991
1992         /* Update the main menu as well, we need to explicitely do
1993            this in order to enable/disable accelerators */
1994         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1995 }
1996
1997 static void 
1998 on_mail_operation_finished (ModestMailOperation *mail_op,
1999                             gpointer user_data)
2000 {
2001         ModestToolBarModes mode;
2002         ModestMailOperationTypeOperation op_type;
2003         GSList *tmp = NULL;
2004         ModestMainWindow *self;
2005         gboolean mode_changed;
2006         TnyAccount *account = NULL;
2007         ModestMainWindowPrivate *priv;
2008
2009         self = MODEST_MAIN_WINDOW (user_data);
2010         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2011
2012         /* The mail operation was not added to the progress objects if
2013            the account was the local account or the MMC one */
2014         op_type = modest_mail_operation_get_type_operation (mail_op);
2015         account = modest_mail_operation_get_account (mail_op);
2016         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2017                 gboolean is_remote;
2018
2019                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2020                               modest_tny_account_is_memory_card_account (account));
2021                 if (!is_remote) {
2022                         g_object_unref (account);
2023                         return;
2024                 }
2025
2026                 /* Remove old timeout */
2027                 if (priv->opening_banner_timeout > 0) {
2028                         g_source_remove (priv->opening_banner_timeout);
2029                         priv->opening_banner_timeout = 0;
2030                 }
2031
2032                 /* Remove the banner if exists */
2033                 if (priv->opening_banner) {
2034                         gtk_widget_destroy (priv->opening_banner);
2035                         priv->opening_banner = NULL;
2036                 }
2037         }
2038
2039         /* Not every mail operation has account, noop does not */
2040         if (account)
2041                 g_object_unref (account);
2042
2043         /* Get toolbar mode from operation id*/
2044         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2045
2046         /* Change toolbar mode */
2047         tmp = priv->progress_widgets;
2048         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2049                 while (tmp) {
2050                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2051                                                                  mail_op);
2052                         tmp = g_slist_next (tmp);
2053                 }
2054                 
2055                 /* If no more operations are being observed, NORMAL mode is enabled again */
2056                 if (observers_empty (self)) {
2057                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2058                 }
2059         }
2060 }
2061
2062 static void
2063 on_queue_changed (ModestMailOperationQueue *queue,
2064                   ModestMailOperation *mail_op,
2065                   ModestMailOperationQueueNotification type,
2066                   ModestMainWindow *self)
2067 {
2068         ModestMainWindowPrivate *priv;
2069
2070         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2071
2072         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2073                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2074                                                                G_OBJECT (mail_op),
2075                                                                "operation-started",
2076                                                                G_CALLBACK (on_mail_operation_started),
2077                                                                self);
2078                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2079                                                                G_OBJECT (mail_op),
2080                                                                "operation-finished",
2081                                                                G_CALLBACK (on_mail_operation_finished),
2082                                                                self);
2083         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2084                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2085                                                                   G_OBJECT (mail_op),
2086                                                                   "operation-started");
2087                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2088                                                                   G_OBJECT (mail_op),
2089                                                                   "operation-finished");
2090         }
2091 }
2092
2093 static void
2094 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2095 {
2096         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2097         GtkAction *action;
2098         ModestAccountMgr *mgr;
2099         ModestAccountSettings *settings;
2100         ModestServerAccountSettings *store_settings = NULL;
2101
2102         /* Get account data */
2103         mgr = modest_runtime_get_account_mgr ();
2104         settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2105         if (settings)
2106                 store_settings = modest_account_settings_get_store_settings (settings);
2107
2108         /* Set the new visible & active account */
2109         if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) { 
2110                 const gchar *account_name;
2111
2112                 account_name = modest_account_settings_get_account_name (settings);
2113
2114                 modest_folder_view_set_account_id_of_visible_server_account 
2115                         (priv->folder_view,
2116                          modest_server_account_settings_get_account_name (store_settings));
2117                 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2118                 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2119
2120                 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2121                 if (action != NULL) {
2122                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2123                                 modest_utils_toggle_action_set_active_block_notify (
2124                                         GTK_TOGGLE_ACTION (action),
2125                                         TRUE);
2126                         }
2127                 }
2128         }
2129         
2130         /* Free */
2131         if (settings) {
2132                 g_object_unref (store_settings);
2133                 g_object_unref (settings);
2134         }
2135
2136         GtkWidget *folder_window;
2137
2138         folder_window = GTK_WIDGET (modest_folder_window_new (NULL));
2139         modest_window_mgr_register_window (modest_runtime_get_window_mgr (), 
2140                                            MODEST_WINDOW (folder_window),
2141                                            MODEST_WINDOW (self));
2142         gtk_widget_show (folder_window);
2143 }
2144
2145 /* Make sure that at least one account is "viewed": */
2146 static void
2147 set_at_least_one_account_visible(ModestMainWindow *self)
2148 {
2149         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2150         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2151
2152         if (!(priv->folder_view)) {
2153                 /* It is too early to do this. */
2154                 return; 
2155         }
2156         
2157         const gchar *active_server_account_name = 
2158                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2159         
2160         if (!active_server_account_name ||
2161                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2162         {
2163                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2164                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2165                 if (default_modest_name) {
2166                         set_account_visible (self, default_modest_name);
2167                 } else if (first_modest_name) {
2168                         set_account_visible (self, first_modest_name);
2169                 }
2170                 g_free (first_modest_name);
2171                 g_free (default_modest_name);
2172         }
2173 }
2174
2175 static void 
2176 on_show_account_action_toggled  (GtkToggleAction *action,
2177                                    gpointer user_data)
2178 {
2179         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2180
2181         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2182         if (gtk_toggle_action_get_active (action))
2183                 set_account_visible (self, acc_name);
2184 }
2185
2186 static void
2187 refresh_account (const gchar *account_name)
2188 {
2189         ModestWindow *win;
2190         
2191         /* win must already exists here, obviously */ 
2192         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2193                                                  FALSE);
2194         if (!win) {
2195                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2196                 return;
2197         }
2198         
2199         /* If account_name == NULL, we must update all (option All) */
2200         if (!account_name)
2201                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2202         else
2203                 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2204         
2205 }
2206
2207 static void 
2208 on_refresh_account_action_activated  (GtkAction *action,
2209                                       gpointer user_data)
2210 {
2211         refresh_account ((const gchar*) user_data);
2212 }
2213
2214 static void
2215 on_send_receive_csm_activated (GtkMenuItem *item,
2216                                gpointer user_data)
2217 {
2218         refresh_account ((const gchar*) user_data);
2219 }
2220
2221 static gboolean
2222 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2223 {
2224         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2225
2226         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2227         return FALSE;
2228
2229 }
2230
2231 static gboolean
2232 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2233 {
2234         ModestMainWindow *main_window = NULL;
2235         
2236         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2237         main_window = MODEST_MAIN_WINDOW (userdata);
2238         
2239         /* Update toolbar dimming state */
2240         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2241         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2242
2243         return FALSE;
2244 }
2245
2246 static gboolean
2247 on_header_view_focus_in (GtkWidget *widget,
2248                          GdkEventFocus *event,
2249                          gpointer userdata)
2250 {
2251         ModestMainWindow *main_window = NULL;
2252
2253         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2254
2255         main_window = MODEST_MAIN_WINDOW (userdata);
2256
2257         /* Update toolbar dimming state */
2258         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2259         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2260
2261         return FALSE;
2262 }
2263
2264 static void 
2265 on_folder_selection_changed (ModestFolderView *folder_view,
2266                              TnyFolderStore *folder_store, 
2267                              gboolean selected,
2268                              ModestMainWindow *main_window)
2269 {
2270         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2271         GtkAction *action = NULL;
2272         gboolean show_reply = TRUE;
2273         gboolean show_forward = TRUE;
2274         gboolean show_cancel_send = FALSE;
2275         gboolean show_clipboard = TRUE;
2276         gboolean show_delete = TRUE;
2277
2278         if (selected) {
2279                 if (TNY_IS_ACCOUNT (folder_store)) {
2280                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2281                 } else if (TNY_IS_FOLDER (folder_store)) {
2282                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2283                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2284                                         TNY_FOLDER (folder_store));
2285                                 switch (folder_type) {
2286                                 case TNY_FOLDER_TYPE_DRAFTS:
2287                                         show_clipboard = show_delete = TRUE;
2288                                         show_reply = show_forward = show_cancel_send = FALSE;
2289                                         break;
2290                                 case TNY_FOLDER_TYPE_SENT:
2291                                         show_forward = show_clipboard = show_delete = TRUE;
2292                                         show_reply = show_cancel_send = FALSE;
2293                                         break;
2294                                 case TNY_FOLDER_TYPE_OUTBOX:
2295                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2296                                         show_reply = show_forward = FALSE;
2297                                         break;
2298                                 case TNY_FOLDER_TYPE_INVALID:
2299                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2300                                         break;
2301                                 default:
2302                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2303                                         show_cancel_send = FALSE;
2304                                 }
2305                         } else {
2306                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2307                                 show_cancel_send = FALSE;
2308                         }
2309                 }
2310         }
2311
2312         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2313         gtk_action_set_visible (action, show_reply);
2314         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2315         gtk_action_set_visible (action, show_reply);
2316         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2317         gtk_action_set_visible (action, show_forward);
2318         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2319         gtk_action_set_visible (action, show_cancel_send);
2320         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2321         gtk_action_set_visible (action, show_delete);
2322
2323 }
2324
2325 gboolean 
2326 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2327                                                    GtkTreeModel *model,
2328                                                    GtkTreeRowReference *row_reference,
2329                                                    ModestMainWindow *self)
2330 {
2331         ModestMainWindowPrivate *priv = NULL;
2332         GtkTreeModel *header_model = NULL;
2333         GtkTreePath *path = NULL;
2334
2335         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2336         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2337         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2338
2339         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2340         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2341
2342         /* Do nothing if we changed the folder in the main view */
2343         if (header_model != model)
2344                 return FALSE;
2345
2346         /* Select the message in the header view */
2347         path = gtk_tree_row_reference_get_path (row_reference);
2348         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2349                                   path, NULL, FALSE);
2350         gtk_tree_path_free (path);
2351
2352         return TRUE;
2353 }
2354
2355 static void
2356 updating_banner_destroyed (gpointer data,
2357                            GObject *where_the_object_was)
2358 {
2359         ModestMainWindowPrivate *priv = NULL;
2360
2361         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2362
2363         priv->updating_banner = NULL;
2364 }
2365
2366 static gboolean
2367 show_updating_banner (gpointer user_data)
2368 {
2369         ModestMainWindowPrivate *priv = NULL;
2370
2371         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2372
2373         if (priv->updating_banner == NULL) {
2374
2375                 /* We're outside the main lock */
2376                 gdk_threads_enter ();
2377                 priv->updating_banner = 
2378                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2379                                                           _CS ("ckdg_pb_updating"));
2380
2381                 /* We need this because banners in Maemo could be
2382                    destroyed by dialogs so we need to properly update
2383                    our reference to it */
2384                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2385                                    updating_banner_destroyed,
2386                                    user_data);
2387                 gdk_threads_leave ();
2388         }
2389
2390         /* Remove timeout */
2391         priv->updating_banner_timeout = 0;
2392         return FALSE;
2393 }
2394
2395 /**
2396  * We use this function to show/hide a progress banner showing
2397  * "Updating" while the header view is being filled. We're not showing
2398  * it unless the update takes more than 2 seconds
2399  *
2400  * If starting = TRUE then the refresh is starting, otherwise it means
2401  * that is has just finished
2402  */
2403 static void 
2404 on_updating_msg_list (ModestHeaderView *header_view,
2405                       gboolean starting,
2406                       gpointer user_data)
2407 {
2408         ModestMainWindowPrivate *priv = NULL;
2409
2410         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2411         
2412         /* Remove old timeout */
2413         if (priv->updating_banner_timeout > 0) {
2414                 g_source_remove (priv->updating_banner_timeout);
2415                 priv->updating_banner_timeout = 0;
2416         }
2417
2418         /* Create a new timeout */
2419         if (starting) {
2420                 priv->updating_banner_timeout = 
2421                         g_timeout_add (2000, show_updating_banner, user_data);
2422         } else {
2423                 /* Remove the banner if exists */
2424                 if (priv->updating_banner) {
2425                         gtk_widget_destroy (priv->updating_banner);
2426                         priv->updating_banner = NULL;
2427                 }
2428         }
2429 }
2430
2431 static void on_folder_view_row_activated (GtkTreeView *tree_view,
2432                                           GtkTreePath *tree_path,
2433                                           GtkTreeViewColumn *column,
2434                                           gpointer userdata)
2435 {
2436         GtkTreeModel  *model;
2437         GtkTreeIter iter;
2438         TnyFolderStore *folder_store = NULL;
2439         ModestMainWindow *self = (ModestMainWindow *) userdata;
2440         ModestMainWindowPrivate *priv = NULL;
2441
2442         g_return_if_fail (MODEST_IS_MAIN_WINDOW(self));
2443         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2444
2445         model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
2446
2447         if (gtk_tree_model_get_iter (model, &iter, tree_path)) {
2448                 gtk_tree_model_get (model, &iter,
2449                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder_store,
2450                                     -1);
2451                 if (folder_store && TNY_IS_FOLDER (folder_store)) {
2452                         modest_header_view_set_folder (MODEST_HEADER_VIEW (priv->header_view), 
2453                                                        TNY_FOLDER (folder_store), TRUE,
2454                                                        NULL, NULL);
2455                         modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
2456                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2457                         modest_widget_memory_restore (modest_runtime_get_conf (), 
2458                                                       G_OBJECT(priv->header_view),
2459                                                       MODEST_CONF_HEADER_VIEW_KEY);
2460                         on_msg_count_changed (MODEST_HEADER_VIEW (priv->header_view), TNY_FOLDER (folder_store), NULL, self);
2461                 }
2462
2463                 if (folder_store)
2464                         g_object_unref (folder_store);
2465         }
2466
2467         g_message ("FOLDER VIEW CELL ACTIVATED");
2468         
2469 }
2470
2471 gboolean
2472 modest_main_window_screen_is_on (ModestMainWindow *self)
2473 {
2474         ModestMainWindowPrivate *priv = NULL;
2475
2476         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2477
2478         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2479         
2480         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2481 }
2482
2483 static void
2484 remove_banners (ModestMainWindow *window)
2485 {
2486         ModestMainWindowPrivate *priv;
2487
2488         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2489
2490         if (priv->opening_banner_timeout > 0) {
2491                 g_source_remove (priv->opening_banner_timeout);
2492                 priv->opening_banner_timeout = 0;
2493         }
2494
2495         if (priv->opening_banner != NULL) {
2496                 gtk_widget_destroy (priv->opening_banner);
2497                 priv->opening_banner = NULL;
2498         }
2499         
2500         if (priv->updating_banner_timeout > 0) {
2501                 g_source_remove (priv->updating_banner_timeout);
2502                 priv->updating_banner_timeout = 0;
2503         }
2504
2505         if (priv->updating_banner != NULL) {
2506                 gtk_widget_destroy (priv->updating_banner);
2507                 priv->updating_banner = NULL;
2508         }       
2509 }
2510
2511
2512 static void
2513 on_window_hide (GObject    *gobject,
2514                 GParamSpec *arg1,
2515                 gpointer    user_data)
2516 {
2517         g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
2518
2519         if (!GTK_WIDGET_VISIBLE (gobject)) {
2520                 TnyFolderStore *folder_store;
2521                 ModestMainWindowPrivate *priv;
2522                 
2523                 /* Remove the currently shown banners */
2524                 remove_banners (MODEST_MAIN_WINDOW (gobject));
2525
2526                 /* Force the folder view to sync the currently selected folder
2527                    to save the read/unread status and to expunge messages */
2528                 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
2529                 folder_store = modest_folder_view_get_selected (priv->folder_view);
2530                 if (TNY_IS_FOLDER (folder_store)) {
2531                         ModestMailOperation *mail_op;
2532                         
2533                         mail_op = modest_mail_operation_new (NULL);
2534                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2535                                                          mail_op);
2536                         modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
2537                         g_object_unref (mail_op);
2538                         g_object_unref (folder_store);
2539                 }
2540         }
2541 }
2542
2543 static void
2544 on_window_destroy (GtkObject *widget, 
2545                    gpointer user_data)
2546 {
2547         g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
2548
2549         remove_banners (MODEST_MAIN_WINDOW (widget));
2550 }
2551
2552 static void
2553 opening_banner_destroyed (gpointer data,
2554                            GObject *where_the_object_was)
2555 {
2556         ModestMainWindowPrivate *priv = NULL;
2557
2558         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2559
2560         priv->opening_banner = NULL;
2561 }
2562
2563 static gboolean
2564 show_opening_banner (gpointer user_data)
2565 {
2566         ModestMainWindowPrivate *priv = NULL;
2567
2568         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2569
2570         if (priv->opening_banner == NULL) {
2571
2572                 /* We're outside the main lock */
2573                 gdk_threads_enter ();
2574                 priv->opening_banner = 
2575                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2576                                                           _("mail_me_opening"));
2577
2578                 /* We need this because banners in Maemo could be
2579                    destroyed by dialogs so we need to properly update
2580                    our reference to it */
2581                 g_object_weak_ref (G_OBJECT (priv->opening_banner),
2582                                    opening_banner_destroyed,
2583                                    user_data);
2584
2585                 /* We need this because banners in Maemo could be
2586                    destroyed by dialogs so we need to properly update
2587                    our reference to it */
2588                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2589                                    updating_banner_destroyed,
2590                                    user_data);
2591                 gdk_threads_leave ();
2592         }
2593
2594         /* Remove timeout */
2595         priv->opening_banner_timeout = 0;
2596         return FALSE;
2597 }