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