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