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