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