* Now on opening from main window the account, it just sets the proper account in...
[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         GtkWidget *folder_window;
2103
2104         folder_window = GTK_WIDGET (modest_folder_window_new (NULL));
2105         modest_window_mgr_register_window (modest_runtime_get_window_mgr (), 
2106                                            MODEST_WINDOW (folder_window),
2107                                            MODEST_WINDOW (self));
2108         gtk_widget_show (folder_window);
2109
2110         /* Get account data */
2111         mgr = modest_runtime_get_account_mgr ();
2112         settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2113         if (settings)
2114                 store_settings = modest_account_settings_get_store_settings (settings);
2115
2116         /* Set the new visible & active account */
2117         if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) { 
2118                 const gchar *account_name;
2119
2120                 account_name = modest_account_settings_get_account_name (settings);
2121
2122                 modest_folder_view_set_account_id_of_visible_server_account 
2123                         (priv->folder_view,
2124                          modest_server_account_settings_get_account_name (store_settings));
2125                 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2126                 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2127
2128                 modest_folder_window_set_account (MODEST_FOLDER_WINDOW (folder_window), acc_name);
2129
2130                 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2131                 if (action != NULL) {
2132                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2133                                 modest_utils_toggle_action_set_active_block_notify (
2134                                         GTK_TOGGLE_ACTION (action),
2135                                         TRUE);
2136                         }
2137                 }
2138         }
2139         
2140         /* Free */
2141         if (settings) {
2142                 g_object_unref (store_settings);
2143                 g_object_unref (settings);
2144         }
2145
2146 }
2147
2148 /* Make sure that at least one account is "viewed": */
2149 static void
2150 set_at_least_one_account_visible(ModestMainWindow *self)
2151 {
2152         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2153         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2154
2155         if (!(priv->folder_view)) {
2156                 /* It is too early to do this. */
2157                 return; 
2158         }
2159         
2160         const gchar *active_server_account_name = 
2161                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2162         
2163         if (!active_server_account_name ||
2164                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2165         {
2166                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2167                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2168                 if (default_modest_name) {
2169                         set_account_visible (self, default_modest_name);
2170                 } else if (first_modest_name) {
2171                         set_account_visible (self, first_modest_name);
2172                 }
2173                 g_free (first_modest_name);
2174                 g_free (default_modest_name);
2175         }
2176 }
2177
2178 static void 
2179 on_show_account_action_toggled  (GtkToggleAction *action,
2180                                    gpointer user_data)
2181 {
2182         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2183
2184         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2185         if (gtk_toggle_action_get_active (action))
2186                 set_account_visible (self, acc_name);
2187 }
2188
2189 static void
2190 refresh_account (const gchar *account_name)
2191 {
2192         ModestWindow *win;
2193         
2194         /* win must already exists here, obviously */ 
2195         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2196                                                  FALSE);
2197         if (!win) {
2198                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2199                 return;
2200         }
2201         
2202         /* If account_name == NULL, we must update all (option All) */
2203         if (!account_name)
2204                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2205         else
2206                 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2207         
2208 }
2209
2210 static void 
2211 on_refresh_account_action_activated  (GtkAction *action,
2212                                       gpointer user_data)
2213 {
2214         refresh_account ((const gchar*) user_data);
2215 }
2216
2217 static void
2218 on_send_receive_csm_activated (GtkMenuItem *item,
2219                                gpointer user_data)
2220 {
2221         refresh_account ((const gchar*) user_data);
2222 }
2223
2224 static gboolean
2225 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2226 {
2227         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2228
2229         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2230         return FALSE;
2231
2232 }
2233
2234 static gboolean
2235 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2236 {
2237         ModestMainWindow *main_window = NULL;
2238         
2239         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2240         main_window = MODEST_MAIN_WINDOW (userdata);
2241         
2242         /* Update toolbar dimming state */
2243         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2244         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2245
2246         return FALSE;
2247 }
2248
2249 static gboolean
2250 on_header_view_focus_in (GtkWidget *widget,
2251                          GdkEventFocus *event,
2252                          gpointer userdata)
2253 {
2254         ModestMainWindow *main_window = NULL;
2255
2256         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2257
2258         main_window = MODEST_MAIN_WINDOW (userdata);
2259
2260         /* Update toolbar dimming state */
2261         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2262         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2263
2264         return FALSE;
2265 }
2266
2267 static void 
2268 on_folder_selection_changed (ModestFolderView *folder_view,
2269                              TnyFolderStore *folder_store, 
2270                              gboolean selected,
2271                              ModestMainWindow *main_window)
2272 {
2273         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2274         GtkAction *action = NULL;
2275         gboolean show_reply = TRUE;
2276         gboolean show_forward = TRUE;
2277         gboolean show_cancel_send = FALSE;
2278         gboolean show_clipboard = TRUE;
2279         gboolean show_delete = TRUE;
2280
2281         if (selected) {
2282                 if (TNY_IS_ACCOUNT (folder_store)) {
2283                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2284                 } else if (TNY_IS_FOLDER (folder_store)) {
2285                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2286                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2287                                         TNY_FOLDER (folder_store));
2288                                 switch (folder_type) {
2289                                 case TNY_FOLDER_TYPE_DRAFTS:
2290                                         show_clipboard = show_delete = TRUE;
2291                                         show_reply = show_forward = show_cancel_send = FALSE;
2292                                         break;
2293                                 case TNY_FOLDER_TYPE_SENT:
2294                                         show_forward = show_clipboard = show_delete = TRUE;
2295                                         show_reply = show_cancel_send = FALSE;
2296                                         break;
2297                                 case TNY_FOLDER_TYPE_OUTBOX:
2298                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2299                                         show_reply = show_forward = FALSE;
2300                                         break;
2301                                 case TNY_FOLDER_TYPE_INVALID:
2302                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2303                                         break;
2304                                 default:
2305                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2306                                         show_cancel_send = FALSE;
2307                                 }
2308                         } else {
2309                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2310                                 show_cancel_send = FALSE;
2311                         }
2312                 }
2313         }
2314
2315         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2316         gtk_action_set_visible (action, show_reply);
2317         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2318         gtk_action_set_visible (action, show_reply);
2319         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2320         gtk_action_set_visible (action, show_forward);
2321         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2322         gtk_action_set_visible (action, show_cancel_send);
2323         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2324         gtk_action_set_visible (action, show_delete);
2325
2326 }
2327
2328 gboolean 
2329 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2330                                                    GtkTreeModel *model,
2331                                                    GtkTreeRowReference *row_reference,
2332                                                    ModestMainWindow *self)
2333 {
2334         ModestMainWindowPrivate *priv = NULL;
2335         GtkTreeModel *header_model = NULL;
2336         GtkTreePath *path = NULL;
2337
2338         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2339         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2340         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2341
2342         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2343         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2344
2345         /* Do nothing if we changed the folder in the main view */
2346         if (header_model != model)
2347                 return FALSE;
2348
2349         /* Select the message in the header view */
2350         path = gtk_tree_row_reference_get_path (row_reference);
2351         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2352                                   path, NULL, FALSE);
2353         gtk_tree_path_free (path);
2354
2355         return TRUE;
2356 }
2357
2358 static void
2359 updating_banner_destroyed (gpointer data,
2360                            GObject *where_the_object_was)
2361 {
2362         ModestMainWindowPrivate *priv = NULL;
2363
2364         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2365
2366         priv->updating_banner = NULL;
2367 }
2368
2369 static gboolean
2370 show_updating_banner (gpointer user_data)
2371 {
2372         ModestMainWindowPrivate *priv = NULL;
2373
2374         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2375
2376         if (priv->updating_banner == NULL) {
2377
2378                 /* We're outside the main lock */
2379                 gdk_threads_enter ();
2380                 priv->updating_banner = 
2381                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2382                                                           _CS ("ckdg_pb_updating"));
2383
2384                 /* We need this because banners in Maemo could be
2385                    destroyed by dialogs so we need to properly update
2386                    our reference to it */
2387                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2388                                    updating_banner_destroyed,
2389                                    user_data);
2390                 gdk_threads_leave ();
2391         }
2392
2393         /* Remove timeout */
2394         priv->updating_banner_timeout = 0;
2395         return FALSE;
2396 }
2397
2398 /**
2399  * We use this function to show/hide a progress banner showing
2400  * "Updating" while the header view is being filled. We're not showing
2401  * it unless the update takes more than 2 seconds
2402  *
2403  * If starting = TRUE then the refresh is starting, otherwise it means
2404  * that is has just finished
2405  */
2406 static void 
2407 on_updating_msg_list (ModestHeaderView *header_view,
2408                       gboolean starting,
2409                       gpointer user_data)
2410 {
2411         ModestMainWindowPrivate *priv = NULL;
2412
2413         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2414         
2415         /* Remove old timeout */
2416         if (priv->updating_banner_timeout > 0) {
2417                 g_source_remove (priv->updating_banner_timeout);
2418                 priv->updating_banner_timeout = 0;
2419         }
2420
2421         /* Create a new timeout */
2422         if (starting) {
2423                 priv->updating_banner_timeout = 
2424                         g_timeout_add (2000, show_updating_banner, user_data);
2425         } else {
2426                 /* Remove the banner if exists */
2427                 if (priv->updating_banner) {
2428                         gtk_widget_destroy (priv->updating_banner);
2429                         priv->updating_banner = NULL;
2430                 }
2431         }
2432 }
2433
2434 static void on_folder_view_row_activated (GtkTreeView *tree_view,
2435                                           GtkTreePath *tree_path,
2436                                           GtkTreeViewColumn *column,
2437                                           gpointer userdata)
2438 {
2439         GtkTreeModel  *model;
2440         GtkTreeIter iter;
2441         TnyFolderStore *folder_store = NULL;
2442         ModestMainWindow *self = (ModestMainWindow *) userdata;
2443         ModestMainWindowPrivate *priv = NULL;
2444
2445         g_return_if_fail (MODEST_IS_MAIN_WINDOW(self));
2446         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2447
2448         model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
2449
2450         if (gtk_tree_model_get_iter (model, &iter, tree_path)) {
2451                 gtk_tree_model_get (model, &iter,
2452                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder_store,
2453                                     -1);
2454                 if (folder_store && TNY_IS_FOLDER (folder_store)) {
2455                         modest_header_view_set_folder (MODEST_HEADER_VIEW (priv->header_view), 
2456                                                        TNY_FOLDER (folder_store), TRUE,
2457                                                        NULL, NULL);
2458                         modest_main_window_set_contents_style (MODEST_MAIN_WINDOW (self),
2459                                                                MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2460                         modest_widget_memory_restore (modest_runtime_get_conf (), 
2461                                                       G_OBJECT(priv->header_view),
2462                                                       MODEST_CONF_HEADER_VIEW_KEY);
2463                         on_msg_count_changed (MODEST_HEADER_VIEW (priv->header_view), TNY_FOLDER (folder_store), NULL, self);
2464                 }
2465
2466                 if (folder_store)
2467                         g_object_unref (folder_store);
2468         }
2469
2470         g_message ("FOLDER VIEW CELL ACTIVATED");
2471         
2472 }
2473
2474 gboolean
2475 modest_main_window_screen_is_on (ModestMainWindow *self)
2476 {
2477         ModestMainWindowPrivate *priv = NULL;
2478
2479         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2480
2481         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2482         
2483         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2484 }
2485
2486 static void
2487 remove_banners (ModestMainWindow *window)
2488 {
2489         ModestMainWindowPrivate *priv;
2490
2491         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2492
2493         if (priv->opening_banner_timeout > 0) {
2494                 g_source_remove (priv->opening_banner_timeout);
2495                 priv->opening_banner_timeout = 0;
2496         }
2497
2498         if (priv->opening_banner != NULL) {
2499                 gtk_widget_destroy (priv->opening_banner);
2500                 priv->opening_banner = NULL;
2501         }
2502         
2503         if (priv->updating_banner_timeout > 0) {
2504                 g_source_remove (priv->updating_banner_timeout);
2505                 priv->updating_banner_timeout = 0;
2506         }
2507
2508         if (priv->updating_banner != NULL) {
2509                 gtk_widget_destroy (priv->updating_banner);
2510                 priv->updating_banner = NULL;
2511         }       
2512 }
2513
2514
2515 static void
2516 on_window_hide (GObject    *gobject,
2517                 GParamSpec *arg1,
2518                 gpointer    user_data)
2519 {
2520         g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
2521
2522         if (!GTK_WIDGET_VISIBLE (gobject)) {
2523                 TnyFolderStore *folder_store;
2524                 ModestMainWindowPrivate *priv;
2525                 
2526                 /* Remove the currently shown banners */
2527                 remove_banners (MODEST_MAIN_WINDOW (gobject));
2528
2529                 /* Force the folder view to sync the currently selected folder
2530                    to save the read/unread status and to expunge messages */
2531                 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
2532                 folder_store = modest_folder_view_get_selected (priv->folder_view);
2533                 if (TNY_IS_FOLDER (folder_store)) {
2534                         ModestMailOperation *mail_op;
2535                         
2536                         mail_op = modest_mail_operation_new (NULL);
2537                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2538                                                          mail_op);
2539                         modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
2540                         g_object_unref (mail_op);
2541                         g_object_unref (folder_store);
2542                 }
2543         }
2544 }
2545
2546 static void
2547 on_window_destroy (GtkObject *widget, 
2548                    gpointer user_data)
2549 {
2550         g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
2551
2552         remove_banners (MODEST_MAIN_WINDOW (widget));
2553 }
2554
2555 static void
2556 opening_banner_destroyed (gpointer data,
2557                            GObject *where_the_object_was)
2558 {
2559         ModestMainWindowPrivate *priv = NULL;
2560
2561         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2562
2563         priv->opening_banner = NULL;
2564 }
2565
2566 static gboolean
2567 show_opening_banner (gpointer user_data)
2568 {
2569         ModestMainWindowPrivate *priv = NULL;
2570
2571         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2572
2573         if (priv->opening_banner == NULL) {
2574
2575                 /* We're outside the main lock */
2576                 gdk_threads_enter ();
2577                 priv->opening_banner = 
2578                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2579                                                           _("mail_me_opening"));
2580
2581                 /* We need this because banners in Maemo could be
2582                    destroyed by dialogs so we need to properly update
2583                    our reference to it */
2584                 g_object_weak_ref (G_OBJECT (priv->opening_banner),
2585                                    opening_banner_destroyed,
2586                                    user_data);
2587
2588                 /* We need this because banners in Maemo could be
2589                    destroyed by dialogs so we need to properly update
2590                    our reference to it */
2591                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2592                                    updating_banner_destroyed,
2593                                    user_data);
2594                 gdk_threads_leave ();
2595         }
2596
2597         /* Remove timeout */
2598         priv->opening_banner_timeout = 0;
2599         return FALSE;
2600 }