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