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