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