25e7e1d0d27795a82369f03f78a45abe646039be
[modest] / src / hildon2 / 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 "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         
1118         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1119         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1120
1121         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1122
1123         /* Connect signals */
1124         connect_signals (MODEST_MAIN_WINDOW (self));
1125
1126         /* Set account store */
1127         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1128                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1129
1130         /* Load previous osso state, for instance if we are being restored from 
1131          * hibernation:  */
1132         modest_osso_load_state ();
1133
1134         /* Restore window & widget settings */  
1135         priv->wait_for_settings = TRUE;
1136         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1137         priv->wait_for_settings = FALSE;
1138
1139         /* Check if accounts exist and show the account wizard if not */
1140         gboolean accounts_exist = 
1141                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1142
1143         if (!accounts_exist) {
1144                 /* This is necessary to have the main window shown behind the dialog 
1145                 It's an ugly hack... jschmid */
1146                 gtk_widget_show_all(GTK_WIDGET(self));
1147                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1148         } else {
1149                 update_menus (MODEST_MAIN_WINDOW (self));
1150         }
1151
1152         /* Never call this function again (NOTE that it could happen
1153            as we hide the main window instead of closing it while
1154            there are operations ongoing) and free the helper */
1155         g_signal_handler_disconnect (self, helper->handler_id);
1156         g_slice_free (ShowHelper, helper);
1157 }
1158
1159 static void 
1160 osso_display_event_cb (osso_display_state_t state, 
1161                        gpointer data)
1162 {
1163         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1164
1165         priv->display_state = state;
1166
1167         /* Stop blinking if the screen becomes on */
1168         if (priv->display_state == OSSO_DISPLAY_ON)
1169                 modest_platform_remove_new_mail_notifications (TRUE);
1170 }
1171
1172 ModestWindow *
1173 modest_main_window_new (void)
1174 {
1175         ModestMainWindow *self = NULL;  
1176         ModestMainWindowPrivate *priv = NULL;
1177         ModestWindowPrivate *parent_priv = NULL;
1178         GtkWidget *folder_win = NULL;
1179         ModestDimmingRulesGroup *menu_rules_group = NULL;
1180         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
1181         GtkActionGroup *action_group = NULL;
1182         GError *error = NULL;
1183         HildonProgram *app;
1184         GdkPixbuf *window_icon;
1185         ShowHelper *helper;
1186         
1187         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1188         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1189         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1190
1191         parent_priv->ui_manager = gtk_ui_manager_new();
1192         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1193
1194         action_group = gtk_action_group_new ("ModestMainWindowActions");
1195         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1196
1197         menu_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_MENU, FALSE);
1198         toolbar_rules_group = modest_dimming_rules_group_new (MODEST_DIMMING_RULES_TOOLBAR, TRUE);
1199
1200         /* Add common actions */
1201         gtk_action_group_add_actions (action_group,
1202                                       modest_action_entries,
1203                                       G_N_ELEMENTS (modest_action_entries),
1204                                       self);
1205
1206         gtk_action_group_add_actions (action_group,
1207                                       modest_folder_view_action_entries,
1208                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1209                                       self);
1210
1211         gtk_action_group_add_actions (action_group,
1212                                       modest_header_view_action_entries,
1213                                       G_N_ELEMENTS (modest_header_view_action_entries),
1214                                       self);
1215
1216         gtk_action_group_add_toggle_actions (action_group,
1217                                              modest_toggle_action_entries,
1218                                              G_N_ELEMENTS (modest_toggle_action_entries),
1219                                              self);
1220
1221         gtk_action_group_add_toggle_actions (action_group,
1222                                              modest_main_window_toggle_action_entries,
1223                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1224                                              self);
1225
1226         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1227         g_object_unref (action_group);
1228
1229         /* Load the UI definition */
1230         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1231                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1232         if (error != NULL) {
1233                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1234                 g_error_free (error);
1235                 error = NULL;
1236         }
1237
1238         /* Add common dimming rules */
1239         modest_dimming_rules_group_add_rules (menu_rules_group, 
1240                                               modest_main_window_menu_dimming_entries,
1241                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1242                                               MODEST_WINDOW (self));
1243         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
1244                                               modest_main_window_toolbar_dimming_entries,
1245                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1246                                               MODEST_WINDOW (self));
1247
1248         /* Insert dimming rules group for this window */
1249         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
1250         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
1251         g_object_unref (menu_rules_group);
1252         g_object_unref (toolbar_rules_group);
1253         
1254         /* Add accelerators */
1255         gtk_window_add_accel_group (GTK_WINDOW (self), 
1256                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1257
1258         /* Menubar. Update the state of some toggles */
1259         parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1260         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1261         gtk_widget_show (parent_priv->menubar);
1262
1263         /* Get device name */
1264         modest_maemo_utils_get_device_name ();
1265
1266         /* header view */
1267         priv->header_view =
1268                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1269         g_object_ref (priv->header_view);
1270         if (!priv->header_view)
1271                 g_printerr ("modest: cannot instantiate header view\n");
1272         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1273         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1274                                       MODEST_CONF_HEADER_VIEW_KEY);
1275
1276         /* Other style properties of header view */
1277         g_object_set (G_OBJECT (priv->header_view), 
1278                       "rules-hint", FALSE,
1279                       NULL);
1280         /* gtk_widget_show (priv->header_view); */
1281
1282         /* Empty view */ 
1283         priv->empty_view = create_empty_view ();
1284         gtk_widget_show (priv->empty_view);
1285         g_object_ref (priv->empty_view);
1286                  
1287         /* Create scrolled windows */
1288         folder_win = gtk_scrolled_window_new (NULL, NULL);
1289         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1290         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1291                                         GTK_POLICY_NEVER,
1292                                         GTK_POLICY_AUTOMATIC);
1293         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1294                                         GTK_POLICY_NEVER,
1295                                         GTK_POLICY_AUTOMATIC);
1296         /* gtk_widget_show (priv->contents_widget); */
1297
1298         /* paned */
1299         priv->main_paned = gtk_hpaned_new ();
1300         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1301         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1302         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1303
1304         /* putting it all together... */
1305         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1306         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1307         gtk_widget_show (priv->main_vbox);
1308         
1309         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1310         
1311         app = hildon_program_get_instance ();
1312         hildon_program_add_window (app, HILDON_WINDOW (self));
1313         
1314         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1315                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1316
1317         /* Connect to "show" action. We delay the creation of some
1318            elements until that moment */
1319         helper = g_slice_new0 (ShowHelper);
1320         helper->folder_win = folder_win;
1321         helper->handler_id = g_signal_connect (G_OBJECT(self), "show",
1322                                                G_CALLBACK (modest_main_window_on_show), 
1323                                                helper);
1324         
1325         /* Set window icon */
1326         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1327         if (window_icon) {
1328                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1329                 g_object_unref (window_icon);
1330         }
1331
1332         /* Listen for changes in the screen, we don't want to show a
1333            led pattern when the display is on for example */
1334         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1335                                       osso_display_event_cb,
1336                                       self); 
1337
1338         /* Dont't restore settings here, 
1339          * because it requires a gtk_widget_show(), 
1340          * and we don't want to do that until later,
1341          * so that the UI is not visible for non-menu D-Bus activation.
1342          */
1343
1344         return MODEST_WINDOW(self);
1345 }
1346
1347 void 
1348 modest_main_window_set_style (ModestMainWindow *self, 
1349                               ModestMainWindowStyle style)
1350 {
1351         ModestMainWindowPrivate *priv;
1352         ModestWindowPrivate *parent_priv;
1353         GtkAction *action;
1354         gboolean active;
1355         GtkTreeSelection *sel;
1356         GList *rows, *list;
1357         
1358         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1359
1360         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1361         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1362
1363         /* no change -> nothing to do */
1364         if (priv->style == style)
1365                 return;
1366
1367        /* Get toggle button and update the state if needed. This will
1368           happen only when the set_style is not invoked from the UI,
1369           for example when it's called from widget memory */
1370        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1371        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1372        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1373            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1374                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1375                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1376                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1377        }
1378
1379        /* We need to store the selection because it's lost when the
1380           widget is reparented */
1381        sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1382        rows = gtk_tree_selection_get_selected_rows (sel, NULL);
1383
1384         priv->style = style;
1385         switch (style) {
1386         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1387
1388                 if (!priv->wait_for_settings)
1389                         modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT (priv->main_paned),
1390                                                    MODEST_CONF_MAIN_PANED_KEY);
1391                 /* Remove main paned */
1392                 g_object_ref (priv->main_paned);
1393                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1394
1395                 /* Reparent the contents widget to the main vbox */
1396                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1397
1398                 break;
1399         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1400                 /* Remove header view */
1401                 g_object_ref (priv->contents_widget);
1402                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1403
1404                 /* Reparent the main paned */
1405                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1406                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1407
1408                 g_timeout_add (500, (GSourceFunc) restore_paned_timeout_handler, self);
1409
1410                 break;
1411         default:
1412                 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1413                 g_list_free (rows);
1414                 g_return_if_reached ();
1415         }
1416
1417         /* Reselect the previously selected folders. We disable the
1418            dimming rules execution during that time because there is
1419            no need to work out it again and it could take a lot of
1420            time if all the headers are selected */
1421         list = rows;
1422         modest_window_disable_dimming (MODEST_WINDOW (self));
1423         while (list) {
1424                 gtk_tree_selection_select_path (sel, (GtkTreePath *) list->data);
1425                 list = g_list_next (list);
1426         }
1427         modest_window_enable_dimming (MODEST_WINDOW (self));
1428
1429         /* Free */
1430         g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
1431         g_list_free (rows);
1432
1433         /* Let header view grab the focus if it's being shown */
1434         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS) {
1435                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1436         } else {
1437                 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SPLIT)
1438                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1439                 else
1440                         gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1441         }
1442
1443         /* Check dimming rules */
1444         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
1445         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
1446
1447         /* Show changes */
1448         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1449 }
1450
1451 ModestMainWindowStyle
1452 modest_main_window_get_style (ModestMainWindow *self)
1453 {
1454         ModestMainWindowPrivate *priv;
1455
1456         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1457
1458         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1459         return priv->style;
1460 }
1461
1462 static void
1463 toolbar_resize (ModestMainWindow *self)
1464 {
1465         ModestMainWindowPrivate *priv = NULL;
1466         ModestWindowPrivate *parent_priv = NULL;
1467         GtkWidget *widget;
1468         gint static_button_size;
1469         ModestWindowMgr *mgr;
1470
1471         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1472         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1473         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1474
1475         mgr = modest_runtime_get_window_mgr ();
1476         static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1477
1478         if (parent_priv->toolbar) {
1479                 /* left size buttons */
1480                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1481                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1482                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1483                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1484                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
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/ToolbarDeleteMessage");
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/ToggleFolders");
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                 
1497                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1498                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1499                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1500                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1501                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1502                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1503                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1504                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1505         }
1506                 
1507 }
1508
1509
1510
1511 static gboolean
1512 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1513 {
1514         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1515                 ModestWindowPrivate *parent_priv;
1516                 ModestWindowMgr *mgr;
1517                 gboolean is_fullscreen;
1518                 GtkAction *fs_toggle_action;
1519                 gboolean active;
1520                 
1521                 mgr = modest_runtime_get_window_mgr ();
1522                 
1523                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1524
1525                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1526                 
1527                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1528                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1529                 if (is_fullscreen != active) {
1530                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1531                 }
1532
1533                 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1534         }
1535
1536         return FALSE;
1537
1538 }
1539
1540 static void 
1541 modest_main_window_show_toolbar (ModestWindow *self,
1542                                  gboolean show_toolbar)
1543 {
1544         ModestMainWindowPrivate *priv = NULL;
1545         ModestWindowPrivate *parent_priv = NULL;        
1546         GtkWidget *reply_button = NULL, *menu = NULL;
1547         GtkWidget *placeholder = NULL;
1548         gint insert_index;
1549
1550         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1551         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1552         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1553
1554         /* Set optimized view status */
1555         priv->optimized_view = !show_toolbar;
1556
1557         if (!parent_priv->toolbar) {
1558                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1559                                                                   "/ToolBar");
1560                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1561
1562                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1563                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1564                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1565                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1566                 toolbar_resize (MODEST_MAIN_WINDOW (self));
1567                 
1568                 /* Add ProgressBar (Transfer toolbar) */ 
1569                 priv->progress_bar = modest_progress_bar_new ();
1570                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1571                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1572                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1573                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1574                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1575                 
1576                 /* Connect cancel 'clicked' signal to abort progress mode */
1577                 g_signal_connect(priv->cancel_toolitem, "clicked",
1578                                  G_CALLBACK(cancel_progressbar),
1579                                  self);
1580                 
1581                 /* Add it to the observers list */
1582                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1583
1584                 /* Add to window */
1585                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1586                                            GTK_TOOLBAR (parent_priv->toolbar));
1587
1588                 /* Set reply button tap and hold menu */
1589                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1590                                                           "/ToolBar/ToolbarMessageReply");
1591                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1592                                                   "/ToolbarReplyCSM");
1593                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1594
1595                 /* Set send & receive button tap and hold menu */
1596                 update_menus (MODEST_MAIN_WINDOW (self));
1597         }
1598         
1599         if (show_toolbar) {
1600                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1601                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1602                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1603
1604                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1605                 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1606                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1607                 else
1608                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1609         } else {
1610                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1611
1612         }
1613 }
1614
1615 static void
1616 on_account_inserted (TnyAccountStore *accoust_store,
1617                      TnyAccount *account,
1618                      gpointer user_data)
1619 {
1620         /* Transport accounts and local ones (MMC and the Local
1621            folders account do now cause menu changes */
1622         if (TNY_IS_STORE_ACCOUNT (account) && 
1623             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account))) {
1624                 /* Update menus */
1625                 update_menus (MODEST_MAIN_WINDOW (user_data));
1626         }
1627 }
1628
1629 static void
1630 on_default_account_changed (ModestAccountMgr* mgr,
1631                             gpointer user_data)
1632 {
1633         update_menus (MODEST_MAIN_WINDOW (user_data));
1634 }
1635
1636 static void
1637 on_account_removed (TnyAccountStore *accoust_store,
1638                      TnyAccount *account,
1639                      gpointer user_data)
1640 {
1641         /* Transport accounts and local ones (MMC and the Local
1642            folders account do now cause menu changes */
1643         if (TNY_IS_STORE_ACCOUNT (account) && 
1644             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1645                 update_menus (MODEST_MAIN_WINDOW (user_data));
1646 }
1647
1648 static void
1649 on_account_changed (TnyAccountStore *account_store,
1650                     TnyAccount *account,
1651                     gpointer user_data)
1652 {
1653         ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1654
1655         /* Transport accounts and local ones (MMC and the Local
1656            folders account do now cause menu changes */
1657         if (TNY_IS_STORE_ACCOUNT (account)) {
1658                 /* We need to refresh the details widget because it could have changed */
1659                 if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1660                         modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1661
1662                 /* Update the menus as well, name could change */
1663                 if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1664                         update_menus (MODEST_MAIN_WINDOW (user_data));
1665         }
1666 }
1667
1668 /* 
1669  * This function manages the key events used to navigate between
1670  * header and folder views (when the window is in split view)
1671  *
1672  * FROM         KEY        ACTION
1673  * -------------------------------------------------
1674  * HeaderView   GDK_Left   Move focus to folder view
1675  * FolderView   GDK_Right  Move focus to header view
1676  *
1677  * There is no need to scroll to selected row, the widgets will be the
1678  * responsibles of doing that (probably managing the focus-in event
1679  */
1680 static gboolean 
1681 on_inner_widgets_key_pressed (GtkWidget *widget,
1682                               GdkEventKey *event,
1683                               gpointer user_data)
1684 {
1685         ModestMainWindowPrivate *priv;
1686
1687         if (event->type == GDK_KEY_RELEASE)
1688                 return FALSE;
1689
1690         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1691
1692         /* Do nothing if we're in SIMPLE style */
1693         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1694                 return FALSE;
1695
1696         if (MODEST_IS_HEADER_VIEW (widget)) {
1697                 if (event->keyval == GDK_Left)
1698                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1699                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1700                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1701                         if (selected_headers > 1) {
1702                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1703                                 return TRUE;
1704                         } else {
1705                                 GtkTreePath * cursor_path;
1706                                 gtk_tree_view_get_cursor (GTK_TREE_VIEW (widget), &cursor_path, NULL);
1707                                 if (cursor_path == NULL) {
1708                                         GtkTreeSelection *selection;
1709                                         GList *list;
1710                                         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1711                                         list = gtk_tree_selection_get_selected_rows (selection, NULL);
1712
1713                                         if (list != NULL)
1714                                                 gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget), (GtkTreePath *) list->data, NULL, FALSE);
1715                                         g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1716                                         g_list_free (list);
1717                                 }
1718                         }
1719                 }
1720         } else if (MODEST_IS_FOLDER_VIEW (widget) && (event->keyval == GDK_Right || event->keyval == GDK_Left)) {
1721 #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
1722                 GtkTreePath *selected_path = NULL;
1723                 GtkTreePath *start_path = NULL;
1724                 GtkTreePath *end_path = NULL;
1725                 GList *selected;
1726                 GtkTreeSelection *selection;
1727
1728                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
1729                 selected = gtk_tree_selection_get_selected_rows (selection, NULL);
1730                 if (selected != NULL) {
1731                         selected_path = (GtkTreePath *) selected->data;
1732                         if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (priv->header_view),
1733                                                              &start_path,
1734                                                              &end_path)) {
1735                                 
1736                                 if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
1737                                     (gtk_tree_path_compare (end_path, selected_path) != 1)) {
1738                                         
1739                                         /* Scroll to first path */
1740                                         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->header_view),
1741                                                                       selected_path,
1742                                                                       NULL,
1743                                                                       TRUE,
1744                                                                       0.5,
1745                                                                       0.0);
1746                                 }
1747                         }
1748                         if (start_path)
1749                                 gtk_tree_path_free (start_path);
1750                         if (end_path)
1751                                 gtk_tree_path_free (end_path);
1752                         g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
1753                         g_list_free (selected);
1754                 }
1755 #endif /* GTK_CHECK_VERSION */
1756                         /* fix scroll */
1757                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1758         }
1759
1760         return FALSE;
1761 }
1762
1763 static void
1764 set_alignment (GtkWidget *widget,
1765                gpointer data)
1766 {
1767         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1768         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1769 }
1770
1771 static GtkWidget *
1772 create_empty_view (void)
1773 {
1774         GtkLabel *label = NULL;
1775         GtkWidget *align = NULL;
1776
1777         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1778         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1779         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1780         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1781
1782         return GTK_WIDGET(align);
1783 }
1784
1785 /*
1786  * Free the returned string
1787  */
1788 static gchar *
1789 get_gray_color_markup (GtkWidget *styled_widget)
1790 {
1791         gchar *gray_color_markup = NULL;
1792 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1793         /* Obtain the secondary text color. We need a realized widget, that's why 
1794            we get styled_widget from outside */
1795         GdkColor color;
1796         if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color)) 
1797                 gray_color_markup = modest_text_utils_get_color_string (&color);
1798 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1799         
1800         if (!gray_color_markup) 
1801                 gray_color_markup = g_strdup ("#BBBBBB");
1802
1803         return gray_color_markup;
1804 }
1805
1806 /*
1807  * Free the returned string
1808  */
1809 static gchar*
1810 create_device_name_visual_string (const gchar *device_name,
1811                                   const gchar *gray_color_markup)
1812 {
1813         gchar *tmp, *label;
1814
1815         /* We have to use "" to fill the %s of the translation. We can
1816            not just use the device name because the device name is
1817            shown in a different color, so it could not be included
1818            into the <span> tag */
1819         tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1820         label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s", 
1821                                          gray_color_markup, 
1822                                          tmp, 
1823                                          device_name);
1824         g_free (tmp);
1825
1826         return label;
1827 }
1828
1829 typedef struct
1830 {
1831         GtkWidget *count_label;
1832         GtkWidget *msg_count_label;
1833         GtkWidget *size_label;
1834         gchar *color_markup;
1835 } DetailsWidgets;
1836
1837 static gchar *
1838 create_uint_label (const gchar *markup,
1839                    const gchar *name,
1840                    guint count)
1841 {
1842         return g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", markup, name, count);
1843 }
1844
1845 static gchar *
1846 create_gchar_label (const gchar *markup,
1847                     const gchar *name,
1848                     gchar *count)
1849 {
1850         return g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", markup, name, count);
1851 }
1852
1853 static void
1854 update_folder_stats_status_cb (ModestFolderStats stats,
1855                                gpointer user_data)
1856 {
1857         DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1858         gchar *label, *tmp;
1859
1860         label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_folders"), stats.folders);
1861         gtk_label_set_markup (GTK_LABEL (widgets->count_label), label);
1862         g_free (label);
1863
1864         label = create_uint_label (widgets->color_markup, _("mcen_fi_rootfolder_messages"), stats.msg_count);
1865         gtk_label_set_markup (GTK_LABEL (widgets->msg_count_label), label);
1866         g_free (label);
1867
1868         if (widgets->size_label) {
1869                 tmp = modest_text_utils_get_display_size (stats.local_size);
1870                 label = create_gchar_label (widgets->color_markup, _("mcen_fi_rootfolder_size"), tmp);
1871                 gtk_label_set_markup (GTK_LABEL (widgets->size_label), label);
1872                 g_free (label);
1873                 g_free (tmp);
1874         }
1875 }
1876
1877 static void
1878 update_folder_stats_cb (ModestFolderStats stats,
1879                         gpointer user_data)
1880 {
1881         DetailsWidgets *widgets = (DetailsWidgets *) user_data;
1882
1883         /* refresh data */
1884         update_folder_stats_status_cb (stats, user_data);
1885
1886         /* frees. Note that the widgets could have been destroyed but
1887            we still keep a reference */
1888         g_free (widgets->color_markup);
1889         if (widgets->count_label)
1890                 g_object_unref (widgets->count_label);
1891         if (widgets->msg_count_label)
1892                 g_object_unref (widgets->msg_count_label);
1893         if (widgets->size_label)
1894         g_object_unref (widgets->size_label);
1895         g_slice_free (DetailsWidgets, widgets);
1896 }
1897
1898 static GtkWidget *
1899 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1900 {
1901         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1902         
1903         GtkWidget *vbox;
1904         GtkWidget *label_w;
1905         gchar *label;
1906         gchar *gray_color_markup;
1907         DetailsWidgets *widgets;
1908
1909         vbox = gtk_vbox_new (FALSE, 0);
1910         widgets = g_slice_new0 (DetailsWidgets);
1911
1912         gray_color_markup = get_gray_color_markup (styled_widget);
1913         widgets->color_markup = g_strdup (gray_color_markup);
1914
1915         /* Account description: */
1916         if (modest_tny_account_is_virtual_local_folders (account)
1917                 || (modest_tny_account_is_memory_card_account (account))) {
1918         
1919                 /* Get device name */
1920                 gchar *device_name = NULL;
1921                 if (modest_tny_account_is_virtual_local_folders (account))
1922                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1923                                                       MODEST_CONF_DEVICE_NAME, NULL);
1924                 else
1925                         device_name = g_strdup (tny_account_get_name (account));
1926
1927                 label = create_device_name_visual_string ((const gchar *) device_name, 
1928                                                           (const gchar *) gray_color_markup);
1929                 label_w = gtk_label_new (NULL);
1930                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1931                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1932                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1933                 g_free (device_name);
1934                 g_free (label);
1935         } else {
1936                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1937                         gtk_box_pack_start (GTK_BOX (vbox), 
1938                                 gtk_label_new (tny_account_get_name (account)), 
1939                                 FALSE, FALSE, 0);
1940                 } else {
1941                         /* Other accounts, such as IMAP and POP: */
1942                         
1943                         GString *proto;
1944                         gchar *tmp;
1945         
1946                         /* Put proto in uppercase */
1947                         proto = g_string_new (tny_account_get_proto (account));
1948                         proto = g_string_ascii_up (proto);
1949                         
1950                         /* note: mcen_fi_localroot_description is something like "%s account"
1951                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1952                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1953                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1954                                                          gray_color_markup, tmp, tny_account_get_name (account));
1955                         g_free (tmp);
1956
1957                         label_w = gtk_label_new (NULL);
1958                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1959                         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1960                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1961                         g_string_free (proto, TRUE);
1962                         g_free (label);
1963                 }
1964         }
1965
1966         /* Message count */
1967         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1968         label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_messages"), 0);
1969         label_w = gtk_label_new (NULL);
1970         gtk_label_set_markup (GTK_LABEL (label_w), label);
1971         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1972         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1973         g_free (label);
1974
1975         widgets->msg_count_label = g_object_ref (label_w);
1976
1977         /* Folder count */
1978         label = create_uint_label (gray_color_markup, _("mcen_fi_rootfolder_folders"), 0);
1979         label_w = gtk_label_new (NULL);
1980         gtk_label_set_markup (GTK_LABEL (label_w), label);
1981         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1982         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1983         g_free (label);
1984
1985         widgets->count_label = g_object_ref (label_w);
1986
1987         /* Size / Date */
1988         if (modest_tny_account_is_virtual_local_folders (account)
1989                 || modest_tny_account_is_memory_card_account (account)) {
1990
1991                 label = create_gchar_label (gray_color_markup, _("mcen_fi_rootfolder_size"), "0");
1992                 
1993                 label_w = gtk_label_new (NULL);
1994                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1995                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1996                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1997                 g_free (label);
1998
1999                 widgets->size_label = g_object_ref (label_w);
2000
2001         } else if (TNY_IS_ACCOUNT(folder_store)) {
2002                 TnyAccount *account = TNY_ACCOUNT(folder_store);
2003                 
2004                 time_t last_updated;
2005                 const gchar *last_updated_string;
2006                 /* Get last updated from configuration */
2007                 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (), 
2008                                                                     tny_account_get_id (account));
2009
2010                 if (last_updated > 0) 
2011                         last_updated_string = modest_text_utils_get_display_date(last_updated);
2012                 else
2013                         last_updated_string = g_strdup (_("mcen_va_never"));
2014
2015                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
2016                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
2017                 label_w = gtk_label_new (NULL);
2018                 gtk_label_set_markup (GTK_LABEL (label_w), label);
2019                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
2020                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
2021                 g_free (label);
2022         }
2023
2024         g_free (gray_color_markup);
2025
2026         /* Refresh folder stats asynchronously */
2027         modest_tny_folder_store_get_folder_stats (TNY_FOLDER_STORE (account),
2028                                                   update_folder_stats_cb,
2029                                                   update_folder_stats_status_cb,
2030                                                   widgets);
2031
2032         /* Set alignment */
2033         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
2034
2035         return vbox;
2036 }
2037
2038 gboolean
2039 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
2040 {
2041         ModestMainWindowPrivate *priv = NULL;
2042         
2043         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2044
2045         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2046
2047         return priv->send_receive_in_progress;
2048 }
2049
2050 void 
2051 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
2052 {
2053         GtkAction *action = NULL;
2054         GtkWidget *widget = NULL;
2055         ModestMainWindowPrivate *priv = NULL;
2056                 
2057         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2058         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2059         
2060         priv->send_receive_in_progress  = TRUE;
2061
2062         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
2063         gtk_action_set_sensitive (action, FALSE);
2064 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
2065 /*      gtk_action_set_sensitive (action, FALSE); */
2066         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
2067         gtk_widget_set_sensitive (widget, FALSE);
2068
2069
2070 void 
2071 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
2072 {
2073         GtkAction *action = NULL;
2074         GtkWidget *widget = NULL;
2075         ModestMainWindowPrivate *priv = NULL;
2076                 
2077         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2078         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2079
2080         priv->send_receive_in_progress  = FALSE;
2081
2082         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
2083         gtk_action_set_sensitive (action, TRUE);
2084 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
2085 /*      gtk_action_set_sensitive (action, TRUE); */
2086         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
2087         gtk_widget_set_sensitive (widget, TRUE);
2088
2089
2090
2091 static void
2092 on_msg_count_changed (ModestHeaderView *header_view,
2093                       TnyFolder *folder,
2094                       TnyFolderChange *change,
2095                       ModestMainWindow *main_window)
2096 {
2097         gboolean refilter = FALSE;
2098         gboolean folder_empty = FALSE;
2099         gboolean all_marked_as_deleted = FALSE;
2100         ModestMainWindowPrivate *priv;
2101
2102         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
2103         g_return_if_fail (TNY_IS_FOLDER(folder));
2104         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2105
2106         if (change != NULL) {
2107                 TnyFolderChangeChanged changed;
2108
2109                 changed = tny_folder_change_get_changed (change);
2110                 /* If something changes */
2111                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
2112                         folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
2113                 else
2114                         folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2115
2116                 /* Play a sound (if configured) and make the LED blink  */
2117                 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
2118                         modest_platform_push_email_notification ();
2119                 }
2120
2121                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
2122                         refilter = TRUE;
2123         } else {
2124                 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (folder))) == 0);
2125         }
2126
2127         /* Check if all messages are marked to be deleted */
2128         all_marked_as_deleted = modest_header_view_is_empty (header_view);
2129         folder_empty = folder_empty || all_marked_as_deleted;
2130
2131         /* Set contents style of headers view */
2132         if (folder_empty)  {
2133                 modest_main_window_set_contents_style (main_window,
2134                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
2135                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
2136         } else {
2137                 modest_main_window_set_contents_style (main_window,
2138                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
2139         }
2140
2141         if (refilter)
2142                 modest_header_view_refilter (header_view);
2143 }
2144
2145
2146 void 
2147 modest_main_window_set_contents_style (ModestMainWindow *self, 
2148                                        ModestMainWindowContentsStyle style)
2149 {
2150         ModestMainWindowPrivate *priv;
2151
2152         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2153
2154         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2155
2156         /* We allow to set the same content style than the previously
2157            set if there are details, because it could happen when we're
2158            selecting different accounts consecutively */
2159         if ((priv->contents_style == style) &&
2160             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
2161                 return;
2162
2163         /* Remove previous child. Delete it if it was an account
2164            details widget */
2165         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
2166         if (content) {
2167                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
2168                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
2169                 }
2170                 
2171                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
2172         }
2173
2174         priv->contents_style = style;
2175
2176         switch (priv->contents_style) {
2177         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
2178                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
2179                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2180                                                       TRUE);
2181                 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2182                         gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
2183                 break;
2184         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
2185         {
2186                 /* if we're started without main win, there may not be a folder
2187                  * view. this fixes a GLib-Critical */
2188                 if (priv->folder_view) {
2189                         TnyFolderStore *selected_folderstore = 
2190                                 modest_folder_view_get_selected (priv->folder_view);
2191                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
2192                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
2193                                                                 TNY_ACCOUNT (selected_folderstore));
2194                                 
2195                                 wrap_in_scrolled_window (priv->contents_widget, 
2196                                                          priv->details_widget);
2197                         }
2198                         if (selected_folderstore)
2199                                 g_object_unref (selected_folderstore);
2200                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2201                                                               FALSE);
2202                 }
2203                 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2204                         gtk_widget_grab_focus (GTK_WIDGET (priv->details_widget));
2205                 break;
2206         }
2207         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
2208                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
2209                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
2210                                                       FALSE);
2211                 if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
2212                         gtk_widget_grab_focus (GTK_WIDGET (priv->empty_view));
2213                 break;
2214         default:
2215                 g_return_if_reached ();
2216         }
2217
2218         /* Show */
2219         gtk_widget_show_all (priv->contents_widget);
2220 }
2221
2222 ModestMainWindowContentsStyle
2223 modest_main_window_get_contents_style (ModestMainWindow *self)
2224 {
2225         ModestMainWindowPrivate *priv;
2226
2227         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
2228
2229         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2230         return priv->contents_style;
2231 }
2232
2233
2234 static void 
2235 on_configuration_key_changed (ModestConf* conf, 
2236                               const gchar *key, 
2237                               ModestConfEvent event,
2238                               ModestConfNotificationId id, 
2239                               ModestMainWindow *self)
2240 {
2241         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2242         TnyAccount *account = NULL;
2243
2244         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
2245                 return;
2246
2247         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
2248                 return;
2249
2250         if (priv->folder_view) 
2251                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
2252
2253         if (account && TNY_IS_ACCOUNT (account) &&
2254             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
2255                 GList *children;
2256                 GtkLabel *label;
2257                 const gchar *device_name;
2258                 gchar *new_text, *gray_color_markup;
2259                 
2260                 /* Get label */
2261                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
2262                 label = GTK_LABEL (children->data);
2263                 
2264                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
2265                                                       MODEST_CONF_DEVICE_NAME, NULL);
2266
2267                 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));          
2268                 new_text = create_device_name_visual_string (device_name, gray_color_markup);
2269                 
2270                 gtk_label_set_markup (label, new_text);
2271                 gtk_widget_show (GTK_WIDGET (label));
2272                 
2273                 g_free (gray_color_markup);
2274                 g_free (new_text);
2275                 g_list_free (children);
2276         }
2277         g_object_unref (account);
2278 }
2279
2280 static gboolean
2281 set_toolbar_transfer_mode (ModestMainWindow *self)
2282 {
2283         ModestMainWindowPrivate *priv = NULL;
2284         
2285         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2286
2287         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2288
2289         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2290         
2291         if (priv->progress_bar_timeout > 0) {
2292                 g_source_remove (priv->progress_bar_timeout);
2293                 priv->progress_bar_timeout = 0;
2294         }
2295
2296         return FALSE;
2297 }
2298
2299 static void 
2300 set_toolbar_mode (ModestMainWindow *self, 
2301                   ModestToolBarModes mode)
2302 {
2303         ModestWindowPrivate *parent_priv = NULL;
2304         ModestMainWindowPrivate *priv = NULL;
2305         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2306         
2307         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2308
2309         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2310         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2311
2312         /* In case this was called before the toolbar exists: */
2313         if (!(parent_priv->toolbar))
2314                 return;
2315
2316         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
2317         
2318         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2319         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2320         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2321
2322         /* Sets current toolbar mode */
2323         priv->current_toolbar_mode = mode;
2324
2325         /* Checks the dimming rules */
2326         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2327         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2328
2329         /* Show and hide toolbar items */
2330         switch (mode) {
2331         case TOOLBAR_MODE_NORMAL:
2332                 if (sort_action)
2333                         gtk_action_set_visible (sort_action, TRUE);
2334                 if (refresh_action)
2335                         gtk_action_set_visible (refresh_action, TRUE);
2336                 if (priv->progress_toolitem) {
2337                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2338                         gtk_widget_hide (priv->progress_toolitem);
2339                 }
2340                 if (priv->progress_bar)
2341                         gtk_widget_hide (priv->progress_bar);
2342                 
2343                 if (cancel_action)
2344                         gtk_action_set_visible (cancel_action, FALSE);
2345
2346                 /* Hide toolbar if optimized view is enabled */
2347                 if (priv->optimized_view)
2348                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2349                 break;
2350         case TOOLBAR_MODE_TRANSFER:
2351                 if (sort_action)
2352                         gtk_action_set_visible (sort_action, FALSE);
2353                 if (refresh_action)
2354                         gtk_action_set_visible (refresh_action, FALSE);
2355                 if (cancel_action)
2356                         gtk_action_set_visible (cancel_action, TRUE);
2357                 if (priv->progress_bar)
2358                         gtk_widget_show (priv->progress_bar);
2359                 if (priv->progress_toolitem) {
2360                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2361                         gtk_widget_show (priv->progress_toolitem);
2362                 }
2363
2364                 /* Show toolbar if it's hiden (optimized view ) */
2365                 if (priv->optimized_view)
2366                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2367                 break;
2368         default:
2369                 g_return_if_reached ();
2370         }
2371 }
2372
2373 gboolean
2374 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2375 {
2376         ModestMainWindowPrivate *priv;
2377
2378         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2379         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2380
2381         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2382 }
2383
2384 static void
2385 cancel_progressbar (GtkToolButton *toolbutton,
2386                     ModestMainWindow *self)
2387 {
2388         GSList *tmp;
2389         ModestMainWindowPrivate *priv;
2390         
2391         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2392
2393         /* Get operation observers and cancel all the operations */
2394         tmp = priv->progress_widgets;
2395         while (tmp) {
2396                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2397                 tmp=g_slist_next(tmp);
2398         }
2399 }
2400
2401 static gboolean
2402 observers_empty (ModestMainWindow *self)
2403 {
2404         GSList *tmp = NULL;
2405         ModestMainWindowPrivate *priv;
2406         gboolean is_empty = TRUE;
2407         guint pending_ops = 0;
2408  
2409         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2410         tmp = priv->progress_widgets;
2411
2412         /* Check all observers */
2413         while (tmp && is_empty)  {
2414                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2415                 is_empty = pending_ops == 0;
2416                 
2417                 tmp = g_slist_next(tmp);
2418         }
2419         
2420         return is_empty;
2421 }
2422
2423
2424 /**
2425  * Gets the toolbar mode needed for each mail operation. It stores in
2426  * @mode_changed if the toolbar mode has changed or not
2427  */
2428 static ModestToolBarModes
2429 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2430                                       ModestMailOperation *mail_op,
2431                                       gboolean *mode_changed)
2432 {
2433         ModestToolBarModes mode;
2434         ModestMainWindowPrivate *priv;
2435
2436         *mode_changed = FALSE;
2437         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2438
2439         /* Get toolbar mode from operation id*/
2440         switch (modest_mail_operation_get_type_operation (mail_op)) {
2441         case MODEST_MAIL_OPERATION_TYPE_SEND_AND_RECEIVE:
2442         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2443                 mode = TOOLBAR_MODE_TRANSFER;
2444                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2445                         *mode_changed = TRUE;
2446                 break;
2447         default:
2448                 mode = TOOLBAR_MODE_NORMAL;             
2449         }
2450         return mode;
2451 }
2452
2453 static void 
2454 on_mail_operation_started (ModestMailOperation *mail_op,
2455                            gpointer user_data)
2456 {
2457         ModestMainWindow *self;
2458         ModestMailOperationTypeOperation op_type;
2459         ModestMainWindowPrivate *priv;
2460         ModestToolBarModes mode;
2461         GSList *tmp;
2462         gboolean mode_changed = FALSE;
2463         TnyAccount *account = NULL;
2464
2465         self = MODEST_MAIN_WINDOW (user_data);
2466         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2467
2468         /* Do not show progress for receiving operations if the
2469            account is the local account or the MMC one */
2470         op_type = modest_mail_operation_get_type_operation (mail_op);
2471         account = modest_mail_operation_get_account (mail_op);
2472         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2473                 gboolean is_remote;
2474
2475                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2476                               modest_tny_account_is_memory_card_account (account));
2477                 if (!is_remote) {
2478                         g_object_unref (account);
2479                         return;
2480                 }
2481
2482                 /* Show information banner. Remove old timeout */
2483                 if (priv->opening_banner_timeout > 0) {
2484                         g_source_remove (priv->opening_banner_timeout);
2485                         priv->opening_banner_timeout = 0;
2486                 }
2487                 /* Create a new timeout */
2488                 priv->opening_banner_timeout = 
2489                         g_timeout_add (2000, show_opening_banner, self);
2490         }
2491
2492         /* Not every mail operation has account, noop does not */
2493         if (account)
2494                 g_object_unref (account);
2495                
2496         /* Get toolbar mode from operation id*/
2497         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2498
2499         /* Add operation observers and change toolbar if neccessary*/
2500         tmp = priv->progress_widgets;
2501         if (mode == TOOLBAR_MODE_TRANSFER) {
2502                 if (mode_changed) {
2503                         GObject *source = modest_mail_operation_get_source(mail_op);
2504                         if (G_OBJECT (self) == source) {
2505                                 set_toolbar_transfer_mode(self);
2506                         }
2507                         g_object_unref (source);
2508                 }
2509
2510                 while (tmp) {
2511                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2512                                                               mail_op);
2513                         tmp = g_slist_next (tmp);
2514                 }
2515         }
2516
2517         /* Update the main menu as well, we need to explicitely do
2518            this in order to enable/disable accelerators */
2519         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
2520 }
2521
2522 static void 
2523 on_mail_operation_finished (ModestMailOperation *mail_op,
2524                             gpointer user_data)
2525 {
2526         ModestToolBarModes mode;
2527         ModestMailOperationTypeOperation op_type;
2528         GSList *tmp = NULL;
2529         ModestMainWindow *self;
2530         gboolean mode_changed;
2531         TnyAccount *account = NULL;
2532         ModestMainWindowPrivate *priv;
2533
2534         self = MODEST_MAIN_WINDOW (user_data);
2535         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2536
2537         /* The mail operation was not added to the progress objects if
2538            the account was the local account or the MMC one */
2539         op_type = modest_mail_operation_get_type_operation (mail_op);
2540         account = modest_mail_operation_get_account (mail_op);
2541         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_OPEN) {
2542                 gboolean is_remote;
2543
2544                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2545                               modest_tny_account_is_memory_card_account (account));
2546                 if (!is_remote) {
2547                         g_object_unref (account);
2548                         return;
2549                 }
2550
2551                 /* Remove old timeout */
2552                 if (priv->opening_banner_timeout > 0) {
2553                         g_source_remove (priv->opening_banner_timeout);
2554                         priv->opening_banner_timeout = 0;
2555                 }
2556
2557                 /* Remove the banner if exists */
2558                 if (priv->opening_banner) {
2559                         gtk_widget_destroy (priv->opening_banner);
2560                         priv->opening_banner = NULL;
2561                 }
2562         }
2563
2564         /* Not every mail operation has account, noop does not */
2565         if (account)
2566                 g_object_unref (account);
2567
2568         /* Get toolbar mode from operation id*/
2569         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2570
2571         /* Change toolbar mode */
2572         tmp = priv->progress_widgets;
2573         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2574                 while (tmp) {
2575                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2576                                                                  mail_op);
2577                         tmp = g_slist_next (tmp);
2578                 }
2579                 
2580                 /* If no more operations are being observed, NORMAL mode is enabled again */
2581                 if (observers_empty (self)) {
2582                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2583                 }
2584         }
2585 }
2586
2587 static void
2588 on_queue_changed (ModestMailOperationQueue *queue,
2589                   ModestMailOperation *mail_op,
2590                   ModestMailOperationQueueNotification type,
2591                   ModestMainWindow *self)
2592 {
2593         ModestMainWindowPrivate *priv;
2594
2595         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2596
2597         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2598                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2599                                                                G_OBJECT (mail_op),
2600                                                                "operation-started",
2601                                                                G_CALLBACK (on_mail_operation_started),
2602                                                                self);
2603                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2604                                                                G_OBJECT (mail_op),
2605                                                                "operation-finished",
2606                                                                G_CALLBACK (on_mail_operation_finished),
2607                                                                self);
2608         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2609                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2610                                                                   G_OBJECT (mail_op),
2611                                                                   "operation-started");
2612                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2613                                                                   G_OBJECT (mail_op),
2614                                                                   "operation-finished");
2615         }
2616 }
2617
2618 static void
2619 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2620 {
2621         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2622         GtkAction *action;
2623         ModestAccountMgr *mgr;
2624         ModestAccountSettings *settings;
2625         ModestServerAccountSettings *store_settings = NULL;
2626
2627         /* Get account data */
2628         mgr = modest_runtime_get_account_mgr ();
2629         settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2630         if (settings)
2631                 store_settings = modest_account_settings_get_store_settings (settings);
2632
2633         /* Set the new visible & active account */
2634         if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) { 
2635                 const gchar *account_name;
2636
2637                 account_name = modest_account_settings_get_account_name (settings);
2638
2639                 modest_folder_view_set_account_id_of_visible_server_account 
2640                         (priv->folder_view,
2641                          modest_server_account_settings_get_account_name (store_settings));
2642                 modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2643                 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2644
2645                 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2646                 if (action != NULL) {
2647                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2648                                 modest_utils_toggle_action_set_active_block_notify (
2649                                         GTK_TOGGLE_ACTION (action),
2650                                         TRUE);
2651                         }
2652                 }
2653         }
2654         
2655         /* Free */
2656         if (settings) {
2657                 g_object_unref (store_settings);
2658                 g_object_unref (settings);
2659         }
2660 }
2661
2662 /* Make sure that at least one account is "viewed": */
2663 static void
2664 set_at_least_one_account_visible(ModestMainWindow *self)
2665 {
2666         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2667         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2668
2669         if (!(priv->folder_view)) {
2670                 /* It is too early to do this. */
2671                 return; 
2672         }
2673         
2674         const gchar *active_server_account_name = 
2675                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2676         
2677         if (!active_server_account_name ||
2678                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2679         {
2680                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2681                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2682                 if (default_modest_name) {
2683                         set_account_visible (self, default_modest_name);
2684                 } else if (first_modest_name) {
2685                         set_account_visible (self, first_modest_name);
2686                 }
2687                 g_free (first_modest_name);
2688                 g_free (default_modest_name);
2689         }
2690 }
2691
2692 static void 
2693 on_show_account_action_toggled  (GtkToggleAction *action,
2694                                    gpointer user_data)
2695 {
2696         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2697
2698         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2699         if (gtk_toggle_action_get_active (action))
2700                 set_account_visible (self, acc_name);
2701 }
2702
2703 static void
2704 refresh_account (const gchar *account_name)
2705 {
2706         ModestWindow *win;
2707         
2708         /* win must already exists here, obviously */ 
2709         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2710                                                  FALSE);
2711         if (!win) {
2712                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2713                 return;
2714         }
2715         
2716         /* If account_name == NULL, we must update all (option All) */
2717         if (!account_name)
2718                 modest_ui_actions_do_send_receive_all (win, TRUE, TRUE, TRUE);
2719         else
2720                 modest_ui_actions_do_send_receive (account_name, TRUE, TRUE, TRUE, win);
2721         
2722 }
2723
2724 static void 
2725 on_refresh_account_action_activated  (GtkAction *action,
2726                                       gpointer user_data)
2727 {
2728         refresh_account ((const gchar*) user_data);
2729 }
2730
2731 static void
2732 on_send_receive_csm_activated (GtkMenuItem *item,
2733                                gpointer user_data)
2734 {
2735         refresh_account ((const gchar*) user_data);
2736 }
2737
2738 static gboolean
2739 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2740 {
2741         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2742
2743         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2744         return FALSE;
2745
2746 }
2747
2748 static gboolean
2749 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2750 {
2751         ModestMainWindow *main_window = NULL;
2752         
2753         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2754         main_window = MODEST_MAIN_WINDOW (userdata);
2755         
2756         /* Update toolbar dimming state */
2757         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2758         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2759
2760         return FALSE;
2761 }
2762
2763 static gboolean
2764 on_header_view_focus_in (GtkWidget *widget,
2765                          GdkEventFocus *event,
2766                          gpointer userdata)
2767 {
2768         ModestMainWindow *main_window = NULL;
2769
2770         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2771
2772         main_window = MODEST_MAIN_WINDOW (userdata);
2773
2774         /* Update toolbar dimming state */
2775         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2776         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (main_window));
2777
2778         return FALSE;
2779 }
2780
2781 static void 
2782 on_folder_selection_changed (ModestFolderView *folder_view,
2783                              TnyFolderStore *folder_store, 
2784                              gboolean selected,
2785                              ModestMainWindow *main_window)
2786 {
2787         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2788         GtkAction *action = NULL;
2789         gboolean show_reply = TRUE;
2790         gboolean show_forward = TRUE;
2791         gboolean show_cancel_send = FALSE;
2792         gboolean show_clipboard = TRUE;
2793         gboolean show_delete = TRUE;
2794
2795         if (selected) {
2796                 if (TNY_IS_ACCOUNT (folder_store)) {
2797                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2798                 } else if (TNY_IS_FOLDER (folder_store)) {
2799                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2800                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2801                                         TNY_FOLDER (folder_store));
2802                                 switch (folder_type) {
2803                                 case TNY_FOLDER_TYPE_DRAFTS:
2804                                         show_clipboard = show_delete = TRUE;
2805                                         show_reply = show_forward = show_cancel_send = FALSE;
2806                                         break;
2807                                 case TNY_FOLDER_TYPE_SENT:
2808                                         show_forward = show_clipboard = show_delete = TRUE;
2809                                         show_reply = show_cancel_send = FALSE;
2810                                         break;
2811                                 case TNY_FOLDER_TYPE_OUTBOX:
2812                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2813                                         show_reply = show_forward = FALSE;
2814                                         break;
2815                                 case TNY_FOLDER_TYPE_INVALID:
2816                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2817                                         break;
2818                                 default:
2819                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2820                                         show_cancel_send = FALSE;
2821                                 }
2822                         } else {
2823                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2824                                 show_cancel_send = FALSE;
2825                         }
2826                 }
2827         }
2828
2829         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2830         gtk_action_set_visible (action, show_reply);
2831         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2832         gtk_action_set_visible (action, show_reply);
2833         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2834         gtk_action_set_visible (action, show_forward);
2835         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2836         gtk_action_set_visible (action, show_cancel_send);
2837         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2838         gtk_action_set_visible (action, show_delete);
2839
2840         /* We finally call to the ui actions handler, after updating properly
2841          * the header view CSM */
2842         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2843 }
2844
2845 gboolean 
2846 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2847                                                    GtkTreeModel *model,
2848                                                    GtkTreeRowReference *row_reference,
2849                                                    ModestMainWindow *self)
2850 {
2851         ModestMainWindowPrivate *priv = NULL;
2852         GtkTreeModel *header_model = NULL;
2853         GtkTreePath *path = NULL;
2854
2855         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2856         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2857         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2858
2859         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2860         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2861
2862         /* Do nothing if we changed the folder in the main view */
2863         if (header_model != model)
2864                 return FALSE;
2865
2866         /* Select the message in the header view */
2867         path = gtk_tree_row_reference_get_path (row_reference);
2868         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2869                                   path, NULL, FALSE);
2870         gtk_tree_path_free (path);
2871
2872         return TRUE;
2873 }
2874
2875 static void
2876 updating_banner_destroyed (gpointer data,
2877                            GObject *where_the_object_was)
2878 {
2879         ModestMainWindowPrivate *priv = NULL;
2880
2881         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
2882
2883         priv->updating_banner = NULL;
2884 }
2885
2886 static gboolean
2887 show_updating_banner (gpointer user_data)
2888 {
2889         ModestMainWindowPrivate *priv = NULL;
2890
2891         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2892
2893         if (priv->updating_banner == NULL) {
2894
2895                 /* We're outside the main lock */
2896                 gdk_threads_enter ();
2897                 priv->updating_banner = 
2898                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2899                                                           _CS ("ckdg_pb_updating"));
2900
2901                 /* We need this because banners in Maemo could be
2902                    destroyed by dialogs so we need to properly update
2903                    our reference to it */
2904                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
2905                                    updating_banner_destroyed,
2906                                    user_data);
2907                 gdk_threads_leave ();
2908         }
2909
2910         /* Remove timeout */
2911         priv->updating_banner_timeout = 0;
2912         return FALSE;
2913 }
2914
2915 /**
2916  * We use this function to show/hide a progress banner showing
2917  * "Updating" while the header view is being filled. We're not showing
2918  * it unless the update takes more than 2 seconds
2919  *
2920  * If starting = TRUE then the refresh is starting, otherwise it means
2921  * that is has just finished
2922  */
2923 static void 
2924 on_updating_msg_list (ModestHeaderView *header_view,
2925                       gboolean starting,
2926                       gpointer user_data)
2927 {
2928         ModestMainWindowPrivate *priv = NULL;
2929
2930         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2931         
2932         /* Remove old timeout */
2933         if (priv->updating_banner_timeout > 0) {
2934                 g_source_remove (priv->updating_banner_timeout);
2935                 priv->updating_banner_timeout = 0;
2936         }
2937
2938         /* Create a new timeout */
2939         if (starting) {
2940                 priv->updating_banner_timeout = 
2941                         g_timeout_add (2000, show_updating_banner, user_data);
2942         } else {
2943                 /* Remove the banner if exists */
2944                 if (priv->updating_banner) {
2945                         gtk_widget_destroy (priv->updating_banner);
2946                         priv->updating_banner = NULL;
2947                 }
2948         }
2949 }
2950
2951 gboolean
2952 modest_main_window_screen_is_on (ModestMainWindow *self)
2953 {
2954         ModestMainWindowPrivate *priv = NULL;
2955
2956         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW(self), FALSE);
2957
2958         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2959         
2960         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2961 }
2962
2963 static void
2964 remove_banners (ModestMainWindow *window)
2965 {
2966         ModestMainWindowPrivate *priv;
2967
2968         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (window);
2969
2970         if (priv->opening_banner_timeout > 0) {
2971                 g_source_remove (priv->opening_banner_timeout);
2972                 priv->opening_banner_timeout = 0;
2973         }
2974
2975         if (priv->opening_banner != NULL) {
2976                 gtk_widget_destroy (priv->opening_banner);
2977                 priv->opening_banner = NULL;
2978         }
2979         
2980         if (priv->updating_banner_timeout > 0) {
2981                 g_source_remove (priv->updating_banner_timeout);
2982                 priv->updating_banner_timeout = 0;
2983         }
2984
2985         if (priv->updating_banner != NULL) {
2986                 gtk_widget_destroy (priv->updating_banner);
2987                 priv->updating_banner = NULL;
2988         }       
2989 }
2990
2991
2992 static void
2993 on_window_hide (GObject    *gobject,
2994                 GParamSpec *arg1,
2995                 gpointer    user_data)
2996 {
2997         g_return_if_fail (MODEST_IS_MAIN_WINDOW (gobject));
2998
2999         if (!GTK_WIDGET_VISIBLE (gobject)) {
3000                 TnyFolderStore *folder_store;
3001                 ModestMainWindowPrivate *priv;
3002                 
3003                 /* Remove the currently shown banners */
3004                 remove_banners (MODEST_MAIN_WINDOW (gobject));
3005
3006                 /* Force the folder view to sync the currently selected folder
3007                    to save the read/unread status and to expunge messages */
3008                 priv = MODEST_MAIN_WINDOW_GET_PRIVATE (gobject);
3009                 folder_store = modest_folder_view_get_selected (priv->folder_view);
3010                 if (TNY_IS_FOLDER (folder_store)) {
3011                         ModestMailOperation *mail_op;
3012                         
3013                         mail_op = modest_mail_operation_new (NULL);
3014                         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3015                                                          mail_op);
3016                         modest_mail_operation_sync_folder (mail_op, TNY_FOLDER (folder_store), FALSE);
3017                         g_object_unref (mail_op);
3018                         g_object_unref (folder_store);
3019                 }
3020         }
3021 }
3022
3023 static void
3024 on_window_destroy (GtkObject *widget, 
3025                    gpointer user_data)
3026 {
3027         g_return_if_fail (MODEST_IS_MAIN_WINDOW (widget));
3028
3029         remove_banners (MODEST_MAIN_WINDOW (widget));
3030 }
3031
3032 static void
3033 opening_banner_destroyed (gpointer data,
3034                            GObject *where_the_object_was)
3035 {
3036         ModestMainWindowPrivate *priv = NULL;
3037
3038         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
3039
3040         priv->opening_banner = NULL;
3041 }
3042
3043 static gboolean
3044 show_opening_banner (gpointer user_data)
3045 {
3046         ModestMainWindowPrivate *priv = NULL;
3047
3048         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
3049
3050         if (priv->opening_banner == NULL) {
3051
3052                 /* We're outside the main lock */
3053                 gdk_threads_enter ();
3054                 priv->opening_banner = 
3055                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
3056                                                           _("mail_me_opening"));
3057
3058                 /* We need this because banners in Maemo could be
3059                    destroyed by dialogs so we need to properly update
3060                    our reference to it */
3061                 g_object_weak_ref (G_OBJECT (priv->opening_banner),
3062                                    opening_banner_destroyed,
3063                                    user_data);
3064
3065                 /* We need this because banners in Maemo could be
3066                    destroyed by dialogs so we need to properly update
3067                    our reference to it */
3068                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
3069                                    updating_banner_destroyed,
3070                                    user_data);
3071                 gdk_threads_leave ();
3072         }
3073
3074         /* Remove timeout */
3075         priv->opening_banner_timeout = 0;
3076         return FALSE;
3077 }