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