* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-main-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
34 #include <tny-list.h>
35 #include <tny-iterator.h>
36 #include <tny-maemo-conic-device.h>
37 #include <tny-error.h>
38 #include "modest-hildon-includes.h"
39 #include "modest-defs.h"
40 #include <string.h>
41 #include "widgets/modest-header-view-priv.h"
42 #include "widgets/modest-main-window.h"
43 #include "widgets/modest-msg-edit-window.h"
44 #include "widgets/modest-account-view-window.h"
45 #include "modest-runtime.h"
46 #include "modest-account-mgr-helpers.h"
47 #include "modest-platform.h"
48 #include "modest-widget-memory.h"
49 #include "modest-window-priv.h"
50 #include "modest-main-window-ui.h"
51 #include "modest-main-window-ui-dimming.h"
52 #include "modest-account-mgr.h"
53 #include "modest-tny-account.h"
54 #include "modest-tny-folder.h"
55 #include "modest-conf.h"
56 #include <modest-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 modest_main_window_disconnect_signals (ModestWindow *self)
832 {       
833         ModestMainWindowPrivate *priv;  
834         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
835
836         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
837         priv->sighandlers = NULL;       
838 }
839
840 static void
841 connect_signals (ModestMainWindow *self)
842 {       
843         ModestWindowPrivate *parent_priv;
844         ModestMainWindowPrivate *priv;
845         GtkWidget *menu;
846         
847         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
848         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
849
850         /* folder view */
851         
852         priv->sighandlers = 
853                 modest_signal_mgr_connect (priv->sighandlers,
854                                            G_OBJECT(priv->folder_view), "key-press-event",
855                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
856         priv->sighandlers = 
857                 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT(priv->folder_view), 
858                                            "folder_selection_changed",
859                                            G_CALLBACK (on_folder_selection_changed), 
860                                            self);
861         priv->sighandlers = 
862                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->folder_view), 
863                                            "folder-display-name-changed",
864                                            G_CALLBACK (modest_ui_actions_on_folder_display_name_changed), 
865                                            self);
866         priv->sighandlers = 
867                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->folder_view), 
868                                            "focus-in-event", 
869                                            G_CALLBACK (on_folder_view_focus_in), 
870                                            self);
871
872         /* Folder view CSM */
873         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
874         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
875         /* header view */
876         priv->sighandlers = 
877                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_selected",
878                                            G_CALLBACK(modest_ui_actions_on_header_selected), self);
879         priv->sighandlers = 
880                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "header_activated",
881                                            G_CALLBACK(modest_ui_actions_on_header_activated), self);
882         priv->sighandlers = 
883                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "item_not_found",
884                                            G_CALLBACK(modest_ui_actions_on_item_not_found), self);
885         priv->sighandlers = 
886                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "key-press-event",
887                                            G_CALLBACK(on_inner_widgets_key_pressed), self);
888         priv->sighandlers = 
889                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), "msg_count_changed",
890                                            G_CALLBACK(on_msg_count_changed), self);
891         priv->sighandlers = 
892                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (priv->header_view), "focus-in-event",
893                                            G_CALLBACK (on_header_view_focus_in), self);
894         priv->sighandlers = 
895                 modest_signal_mgr_connect (priv->sighandlers,
896                                            G_OBJECT (priv->header_view), 
897                                            "updating-msg-list",
898                                            G_CALLBACK (on_updating_msg_list), 
899                                            self);
900         
901         /* Header view CSM */
902         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
903         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
904         
905         /* window */
906         priv->sighandlers = 
907                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT (self), "window-state-event",
908                                            G_CALLBACK (modest_main_window_window_state_event),
909                                            NULL);
910
911         /* Mail Operation Queue */
912         priv->sighandlers = 
913                 modest_signal_mgr_connect (priv->sighandlers,
914                                            G_OBJECT (modest_runtime_get_mail_operation_queue ()),
915                                            "queue-changed", 
916                                            G_CALLBACK (on_queue_changed), self);
917         
918         /* Track changes in the device name */
919         priv->sighandlers = 
920                 modest_signal_mgr_connect (priv->sighandlers,
921                                            G_OBJECT(modest_runtime_get_conf ()),
922                                            "key_changed", 
923                                            G_CALLBACK (on_configuration_key_changed), 
924                                            self);
925         
926         /* Track account changes. We need to refresh the toolbar */
927         priv->sighandlers = 
928                 modest_signal_mgr_connect (priv->sighandlers,
929                                            G_OBJECT (modest_runtime_get_account_store ()),
930                                            "account_inserted", 
931                                            G_CALLBACK (on_account_inserted),
932                                            self);
933         priv->sighandlers = 
934                 modest_signal_mgr_connect (priv->sighandlers,
935                                            G_OBJECT (modest_runtime_get_account_store ()),
936                                            "account_removed", 
937                                            G_CALLBACK (on_account_removed),
938                                            self);
939
940         /* We need to refresh the send & receive menu to change the bold
941          * account when the default account changes. */
942         priv->sighandlers = 
943                 modest_signal_mgr_connect (priv->sighandlers,
944                                            G_OBJECT (modest_runtime_get_account_mgr ()),
945                                            "default_account_changed", 
946                                            G_CALLBACK (on_default_account_changed),
947                                            self);
948
949         /* Account store */
950         priv->sighandlers = 
951                 modest_signal_mgr_connect (priv->sighandlers,
952                                            G_OBJECT (modest_runtime_get_account_store ()),
953                                            "account_changed", 
954                                            G_CALLBACK (on_account_changed),
955                                            self);
956
957         priv->sighandlers = 
958                 modest_signal_mgr_connect (priv->sighandlers,
959                                            G_OBJECT (modest_runtime_get_account_store()), 
960                                            "password_requested",
961                                            G_CALLBACK (modest_ui_actions_on_password_requested), 
962                                            self);
963 }
964
965 static void 
966 on_hildon_program_is_topmost_notify(GObject *self,
967                                     GParamSpec *propert_param, 
968                                     gpointer user_data)
969 {
970         HildonProgram *app = HILDON_PROGRAM (self);
971         
972         /* Note that use of hildon_program_set_can_hibernate() 
973          * is generally referred to as "setting the killable flag", 
974          * though hibernation does not seem equal to death.
975          * murrayc */
976                  
977         if (hildon_program_get_is_topmost (app)) {
978                 /* Prevent hibernation when the progam comes to the foreground,
979                  * because hibernation should only happen when the application 
980                  * is in the background: */
981                 hildon_program_set_can_hibernate (app, FALSE);
982
983                 /* Remove new mail visual notifications */
984                 modest_platform_remove_new_mail_notifications (TRUE);
985         } else {
986                 /* Allow hibernation if the program has gone to the background: */
987                 
988                 /* However, prevent hibernation while the settings are being changed: */
989                 const gboolean hibernation_prevented = 
990                         modest_window_mgr_get_hibernation_is_prevented (
991                                                                         modest_runtime_get_window_mgr ()); 
992         
993                 if (hibernation_prevented)
994                         hildon_program_set_can_hibernate (app, FALSE);
995                 else {
996                         /* Allow hibernation, after saving the state: */
997                         modest_osso_save_state();
998                         hildon_program_set_can_hibernate (app, TRUE);
999                 }
1000         }       
1001 }
1002
1003 static void
1004 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
1005 {
1006         GtkWidget *folder_win = (GtkWidget *) user_data;
1007         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1008         
1009         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
1010         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
1011
1012         gtk_widget_show (GTK_WIDGET (priv->folder_view));
1013
1014         /* Connect signals */
1015         connect_signals (MODEST_MAIN_WINDOW (self));
1016
1017         /* Set account store */
1018         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
1019                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
1020
1021         /* Load previous osso state, for instance if we are being restored from 
1022          * hibernation:  */
1023         modest_osso_load_state ();
1024
1025         /* Restore window & widget settings */  
1026         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
1027
1028         /* Check if accounts exist and show the account wizard if not */
1029         gboolean accounts_exist = 
1030                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
1031
1032         if (!accounts_exist) {
1033                 /* This is necessary to have the main window shown behind the dialog 
1034                 It's an ugly hack... jschmid */
1035                 gtk_widget_show_all(GTK_WIDGET(self));
1036                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
1037         } else {
1038                 GSList *accounts;
1039                 GtkAction *send_receive_all;
1040                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1041                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
1042                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1043                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1044                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts) > 0);
1045                 modest_account_mgr_free_account_names (accounts);
1046                 update_menus (MODEST_MAIN_WINDOW (self));
1047         }
1048 }
1049
1050 static void 
1051 osso_display_event_cb (osso_display_state_t state, 
1052                        gpointer data)
1053 {
1054         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (data);
1055
1056         priv->display_state = state;
1057
1058         /* Stop blinking if the screen becomes on */
1059         if (priv->display_state == OSSO_DISPLAY_ON)
1060                 modest_platform_remove_new_mail_notifications (TRUE);
1061 }
1062
1063 ModestWindow *
1064 modest_main_window_new (void)
1065 {
1066         ModestMainWindow *self = NULL;  
1067         ModestMainWindowPrivate *priv = NULL;
1068         ModestWindowPrivate *parent_priv = NULL;
1069         GtkWidget *folder_win = NULL;
1070         ModestDimmingRulesGroup *window_rules_group = NULL;
1071         GtkActionGroup *action_group = NULL;
1072         GError *error = NULL;
1073         HildonProgram *app;
1074         ModestConf *conf = NULL;
1075         GtkAction *action = NULL;
1076         GdkPixbuf *window_icon;
1077         
1078         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
1079         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1080         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1081
1082         parent_priv->ui_manager = gtk_ui_manager_new();
1083         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
1084
1085         action_group = gtk_action_group_new ("ModestMainWindowActions");
1086         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
1087
1088         window_rules_group = modest_dimming_rules_group_new ("ModestWindowDimmingRules", TRUE);
1089
1090         /* Add common actions */
1091         gtk_action_group_add_actions (action_group,
1092                                       modest_action_entries,
1093                                       G_N_ELEMENTS (modest_action_entries),
1094                                       self);
1095
1096         gtk_action_group_add_actions (action_group,
1097                                       modest_folder_view_action_entries,
1098                                       G_N_ELEMENTS (modest_folder_view_action_entries),
1099                                       self);
1100
1101         gtk_action_group_add_actions (action_group,
1102                                       modest_header_view_action_entries,
1103                                       G_N_ELEMENTS (modest_header_view_action_entries),
1104                                       self);
1105
1106         gtk_action_group_add_toggle_actions (action_group,
1107                                              modest_toggle_action_entries,
1108                                              G_N_ELEMENTS (modest_toggle_action_entries),
1109                                              self);
1110
1111         gtk_action_group_add_toggle_actions (action_group,
1112                                              modest_main_window_toggle_action_entries,
1113                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
1114                                              self);
1115
1116         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
1117         g_object_unref (action_group);
1118
1119         /* Load the UI definition */
1120         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
1121                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
1122         if (error != NULL) {
1123                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
1124                 g_error_free (error);
1125                 error = NULL;
1126         }
1127
1128         /* Add common dimming rules */
1129         modest_dimming_rules_group_add_rules (window_rules_group, 
1130                                               modest_main_window_toolbar_dimming_entries,
1131                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
1132                                               MODEST_WINDOW (self));
1133         modest_dimming_rules_group_add_rules (window_rules_group, 
1134                                               modest_main_window_menu_dimming_entries,
1135                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
1136                                               MODEST_WINDOW (self));
1137
1138         /* Insert dimming rules group for this window */
1139         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, window_rules_group);
1140         g_object_unref (window_rules_group);
1141         
1142         /* Add accelerators */
1143         gtk_window_add_accel_group (GTK_WINDOW (self), 
1144                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
1145
1146         /* Menubar. Update the state of some toggles */
1147         parent_priv->menubar = modest_maemo_utils_get_manager_menubar_as_menu (parent_priv->ui_manager, "/MenuBar");
1148         conf = modest_runtime_get_conf ();
1149         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1150                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
1151         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1152                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR, NULL));
1153         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1154                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
1155         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
1156                                       modest_conf_get_bool (conf, MODEST_CONF_MAIN_WINDOW_SHOW_TOOLBAR_FULLSCREEN, NULL));
1157         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
1158         gtk_widget_show (parent_priv->menubar);
1159
1160         /* Get device name */
1161         modest_maemo_utils_get_device_name ();
1162
1163         /* header view */
1164         priv->header_view =
1165                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
1166         if (!priv->header_view)
1167                 g_printerr ("modest: cannot instantiate header view\n");
1168         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
1169         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
1170                                       MODEST_CONF_HEADER_VIEW_KEY);
1171
1172         /* Other style properties of header view */
1173         g_object_set (G_OBJECT (priv->header_view), 
1174                       "rules-hint", FALSE,
1175                       NULL);
1176         /* gtk_widget_show (priv->header_view); */
1177
1178         /* Empty view */ 
1179         priv->empty_view = create_empty_view ();
1180         gtk_widget_show (priv->empty_view);
1181                  
1182         /* Create scrolled windows */
1183         folder_win = gtk_scrolled_window_new (NULL, NULL);
1184         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
1185         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
1186                                         GTK_POLICY_NEVER,
1187                                         GTK_POLICY_AUTOMATIC);
1188         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
1189                                         GTK_POLICY_NEVER,
1190                                         GTK_POLICY_AUTOMATIC);
1191         /* gtk_widget_show (priv->contents_widget); */
1192
1193         /* paned */
1194         priv->main_paned = gtk_hpaned_new ();
1195         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
1196         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
1197         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
1198
1199         /* putting it all together... */
1200         priv->main_vbox = gtk_vbox_new (FALSE, 6);
1201         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
1202         gtk_widget_show (priv->main_vbox);
1203         
1204         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
1205         
1206         app = hildon_program_get_instance ();
1207         hildon_program_add_window (app, HILDON_WINDOW (self));
1208         
1209         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
1210                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
1211
1212         g_signal_connect (G_OBJECT(self), "show",
1213                           G_CALLBACK (modest_main_window_on_show), folder_win);
1214                 
1215         /* Set window icon */
1216         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
1217         if (window_icon) {
1218                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
1219                 g_object_unref (window_icon);
1220         }
1221
1222         /* Listen for changes in the screen, we don't want to show a
1223            led pattern when the display is on for example */
1224         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
1225                                       osso_display_event_cb,
1226                                       self); 
1227
1228         /* Dont't restore settings here, 
1229          * because it requires a gtk_widget_show(), 
1230          * and we don't want to do that until later,
1231          * so that the UI is not visible for non-menu D-Bus activation.
1232          */
1233
1234         return MODEST_WINDOW(self);
1235 }
1236
1237 void 
1238 modest_main_window_set_style (ModestMainWindow *self, 
1239                               ModestMainWindowStyle style)
1240 {
1241         ModestMainWindowPrivate *priv;
1242         ModestWindowPrivate *parent_priv;
1243         GtkAction *action;
1244         gboolean active;
1245
1246         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1247
1248         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1249         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1250
1251         /* no change -> nothing to do */
1252         if (priv->style == style)
1253                 return;
1254
1255        /* Get toggle button and update the state if needed. This will
1256           happen only when the set_style is not invoked from the UI,
1257           for example when it's called from widget memory */
1258        action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1259        active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1260        if ((active && style == MODEST_MAIN_WINDOW_STYLE_SIMPLE) ||
1261            (!active && style == MODEST_MAIN_WINDOW_STYLE_SPLIT)) {
1262                g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
1263                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), !active);
1264                g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
1265        }
1266
1267         priv->style = style;
1268         switch (style) {
1269         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
1270                 /* Remove main paned */
1271                 g_object_ref (priv->main_paned);
1272                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1273
1274                 /* Reparent the contents widget to the main vbox */
1275                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
1276
1277                 break;
1278         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1279                 /* Remove header view */
1280                 g_object_ref (priv->contents_widget);
1281                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1282
1283                 /* Reparent the main paned */
1284                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1285                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1286
1287                 break;
1288         default:
1289                 g_return_if_reached ();
1290         }
1291
1292         /* Let header view grab the focus if it's being shown */
1293         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1294                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1295         else 
1296                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1297
1298         /* Show changes */
1299         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1300 }
1301
1302 ModestMainWindowStyle
1303 modest_main_window_get_style (ModestMainWindow *self)
1304 {
1305         ModestMainWindowPrivate *priv;
1306
1307         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1308
1309         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1310         return priv->style;
1311 }
1312
1313 static void
1314 toolbar_resize (ModestMainWindow *self)
1315 {
1316         ModestMainWindowPrivate *priv = NULL;
1317         ModestWindowPrivate *parent_priv = NULL;
1318         GtkWidget *widget;
1319         gint static_button_size;
1320         ModestWindowMgr *mgr;
1321
1322         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1323         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1324         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1325
1326         mgr = modest_runtime_get_window_mgr ();
1327         static_button_size = modest_window_mgr_get_fullscreen_mode (mgr)?118:108;
1328
1329         if (parent_priv->toolbar) {
1330                 /* left size buttons */
1331                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageNew");
1332                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1333                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1334                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1335                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarMessageReply");
1336                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1337                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1338                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1339                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarDeleteMessage");
1340                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1341                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1342                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1343                 widget = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToggleFolders");
1344                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), FALSE);
1345                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), FALSE);
1346                 gtk_widget_set_size_request (GTK_WIDGET (widget), static_button_size, -1);
1347                 
1348                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1349                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1350                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1351                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1352                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1353                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->refresh_toolitem), TRUE);
1354                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1355                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->sort_toolitem), TRUE);
1356         }
1357                 
1358 }
1359
1360
1361
1362 static gboolean
1363 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1364 {
1365         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1366                 ModestWindowPrivate *parent_priv;
1367                 ModestWindowMgr *mgr;
1368                 gboolean is_fullscreen;
1369                 GtkAction *fs_toggle_action;
1370                 gboolean active;
1371                 
1372                 mgr = modest_runtime_get_window_mgr ();
1373                 
1374                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1375
1376                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1377                 
1378                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1379                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1380                 if (is_fullscreen != active) {
1381                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1382                 }
1383
1384                 toolbar_resize (MODEST_MAIN_WINDOW (widget));
1385         }
1386
1387         return FALSE;
1388
1389 }
1390
1391 static void 
1392 modest_main_window_show_toolbar (ModestWindow *self,
1393                                  gboolean show_toolbar)
1394 {
1395         ModestMainWindowPrivate *priv = NULL;
1396         ModestWindowPrivate *parent_priv = NULL;        
1397         GtkWidget *reply_button = NULL, *menu = NULL;
1398         GtkWidget *placeholder = NULL;
1399         gint insert_index;
1400         const gchar *action_name;
1401         GtkAction *action;
1402
1403         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1404         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1405         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1406
1407         /* Set optimized view status */
1408         priv->optimized_view = !show_toolbar;
1409
1410         if (!parent_priv->toolbar) {
1411                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1412                                                                   "/ToolBar");
1413                 gtk_widget_set_no_show_all (parent_priv->toolbar, TRUE);
1414
1415                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1416                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1417                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1418                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1419                 toolbar_resize (MODEST_MAIN_WINDOW (self));
1420                 
1421                 /* Add ProgressBar (Transfer toolbar) */ 
1422                 priv->progress_bar = modest_progress_bar_widget_new ();
1423                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1424                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1425                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1426                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1427                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1428                 
1429                 /* Connect cancel 'clicked' signal to abort progress mode */
1430                 g_signal_connect(priv->cancel_toolitem, "clicked",
1431                                  G_CALLBACK(cancel_progressbar),
1432                                  self);
1433                 
1434                 /* Add it to the observers list */
1435                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1436
1437                 /* Add to window */
1438                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1439                                            GTK_TOOLBAR (parent_priv->toolbar));
1440
1441                 /* Set reply button tap and hold menu */
1442                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1443                                                           "/ToolBar/ToolbarMessageReply");
1444                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1445                                                   "/ToolbarReplyCSM");
1446                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1447
1448                 /* Set send & receive button tap and hold menu */
1449                 update_menus (MODEST_MAIN_WINDOW (self));
1450         }
1451         
1452         if (show_toolbar) {
1453                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1454                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1455                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1456
1457                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1458                 if (modest_main_window_transfer_mode_enabled (MODEST_MAIN_WINDOW(self)))
1459                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_TRANSFER);
1460                 else
1461                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1462         } else {
1463                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1464
1465         }
1466
1467         /* Update also the actions (to update the toggles in the
1468            menus), we have to do it manually because some other window
1469            of the same time could have changed it (remember that the
1470            toolbar fullscreen mode is shared by all the windows of the
1471            same type */
1472         if (modest_window_mgr_get_fullscreen_mode (modest_runtime_get_window_mgr ()))
1473                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu";
1474         else
1475                 action_name = "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu";
1476
1477         action = gtk_ui_manager_get_action (parent_priv->ui_manager, action_name);
1478         modest_utils_toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action),
1479                                                             show_toolbar);
1480 }
1481
1482 static void
1483 on_account_inserted (TnyAccountStore *accoust_store,
1484                      TnyAccount *account,
1485                      gpointer user_data)
1486 {
1487         /* Transport accounts and local ones (MMC and the Local
1488            folders account do now cause menu changes */
1489         if (TNY_IS_STORE_ACCOUNT (account) && 
1490             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1491                 update_menus (MODEST_MAIN_WINDOW (user_data));
1492 }
1493
1494 static void
1495 on_default_account_changed (ModestAccountMgr* mgr,
1496                             gpointer user_data)
1497 {
1498         update_menus (MODEST_MAIN_WINDOW (user_data));
1499 }
1500
1501 static void
1502 on_account_removed (TnyAccountStore *accoust_store,
1503                      TnyAccount *account,
1504                      gpointer user_data)
1505 {
1506         /* Transport accounts and local ones (MMC and the Local
1507            folders account do now cause menu changes */
1508         if (TNY_IS_STORE_ACCOUNT (account) && 
1509             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1510                 update_menus (MODEST_MAIN_WINDOW (user_data));
1511 }
1512
1513 static void
1514 on_account_changed (TnyAccountStore *account_store,
1515                     TnyAccount *account,
1516                     gpointer user_data)
1517 {
1518         ModestMainWindow *win = MODEST_MAIN_WINDOW (user_data);
1519         
1520         /* We need to refresh the details widget because it could have changed */
1521         if (modest_main_window_get_contents_style(win) == MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS) {
1522                 modest_main_window_set_contents_style (win, MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS);
1523         }
1524
1525         /* Update the menus as well, the account name could be
1526            changed. Transport accounts and local ones (MMC and the
1527            Local folders account do now cause menu changes */
1528         if (TNY_IS_STORE_ACCOUNT (account) && 
1529             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (account)))
1530                 update_menus (MODEST_MAIN_WINDOW (user_data));
1531 }
1532
1533 /* 
1534  * This function manages the key events used to navigate between
1535  * header and folder views (when the window is in split view)
1536  *
1537  * FROM         KEY        ACTION
1538  * -------------------------------------------------
1539  * HeaderView   GDK_Left   Move focus to folder view
1540  * FolderView   GDK_Right  Move focus to header view
1541  *
1542  * There is no need to scroll to selected row, the widgets will be the
1543  * responsibles of doing that (probably managing the focus-in event
1544  */
1545 static gboolean 
1546 on_inner_widgets_key_pressed (GtkWidget *widget,
1547                               GdkEventKey *event,
1548                               gpointer user_data)
1549 {
1550         ModestMainWindowPrivate *priv;
1551
1552         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1553
1554         /* Do nothing if we're in SIMPLE style */
1555         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1556                 return FALSE;
1557
1558         if (MODEST_IS_HEADER_VIEW (widget)) {
1559                 if (event->keyval == GDK_Left)
1560                         gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1561                 else if ((event->keyval == GDK_Return)||(event->keyval == GDK_KP_Enter)) {
1562                         guint selected_headers = modest_header_view_count_selected_headers (MODEST_HEADER_VIEW (widget));
1563                         if (selected_headers > 1) {
1564                                 hildon_banner_show_information (NULL, NULL, _("mcen_ib_select_one_message"));
1565                                 return TRUE;
1566                         }
1567                 }
1568         } else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1569                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1570
1571         return FALSE;
1572 }
1573
1574 static void
1575 set_alignment (GtkWidget *widget,
1576                gpointer data)
1577 {
1578         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1579         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1580 }
1581
1582 static GtkWidget *
1583 create_empty_view (void)
1584 {
1585         GtkLabel *label = NULL;
1586         GtkWidget *align = NULL;
1587
1588         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1589         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1590         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1591         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1592
1593         return GTK_WIDGET(align);
1594 }
1595
1596 /*
1597  * Free the returned string
1598  */
1599 static gchar *
1600 get_gray_color_markup (GtkWidget *styled_widget)
1601 {
1602         gchar *gray_color_markup = NULL;
1603 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1604         /* Obtain the secondary text color. We need a realized widget, that's why 
1605            we get styled_widget from outside */
1606         GdkColor color;
1607         if (gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color)) 
1608                 gray_color_markup = modest_text_utils_get_color_string (&color);
1609 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
1610         
1611         if (!gray_color_markup) 
1612                 gray_color_markup = g_strdup ("#BBBBBB");
1613
1614         return gray_color_markup;
1615 }
1616
1617 /*
1618  * Free the returned string
1619  */
1620 static gchar*
1621 create_device_name_visual_string (const gchar *device_name,
1622                                   const gchar *gray_color_markup)
1623 {
1624         gchar *tmp, *label;
1625
1626         /* We have to use "" to fill the %s of the translation. We can
1627            not just use the device name because the device name is
1628            shown in a different color, so it could not be included
1629            into the <span> tag */
1630         tmp = g_strdup_printf (_("mcen_fi_localroot_description"), "");
1631         label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s", 
1632                                          gray_color_markup, 
1633                                          tmp, 
1634                                          device_name);
1635         g_free (tmp);
1636
1637         return label;
1638 }
1639
1640 static GtkWidget *
1641 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1642 {
1643         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1644         
1645         GtkWidget *vbox;
1646         GtkWidget *label_w;
1647         gchar *label;
1648         gchar *gray_color_markup;
1649
1650         vbox = gtk_vbox_new (FALSE, 0);
1651
1652         gray_color_markup = get_gray_color_markup (styled_widget);
1653
1654         /* Account description: */
1655         if (modest_tny_account_is_virtual_local_folders (account)
1656                 || (modest_tny_account_is_memory_card_account (account))) {
1657         
1658                 /* Get device name */
1659                 gchar *device_name = NULL;
1660                 if (modest_tny_account_is_virtual_local_folders (account))
1661                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1662                                                       MODEST_CONF_DEVICE_NAME, NULL);
1663                 else
1664                         device_name = g_strdup (tny_account_get_name (account));
1665
1666                 label = create_device_name_visual_string ((const gchar *) device_name, 
1667                                                           (const gchar *) gray_color_markup);
1668                 label_w = gtk_label_new (NULL);
1669                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1670                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1671                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1672                 g_free (device_name);
1673                 g_free (label);
1674         } else {
1675                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1676                         gtk_box_pack_start (GTK_BOX (vbox), 
1677                                 gtk_label_new (tny_account_get_name (account)), 
1678                                 FALSE, FALSE, 0);
1679                 } else {
1680                         /* Other accounts, such as IMAP and POP: */
1681                         
1682                         GString *proto;
1683                         gchar *tmp;
1684         
1685                         /* Put proto in uppercase */
1686                         proto = g_string_new (tny_account_get_proto (account));
1687                         proto = g_string_ascii_up (proto);
1688                         
1689                         /* note: mcen_fi_localroot_description is something like "%s account"
1690                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1691                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1692                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1693                                                          gray_color_markup, tmp, tny_account_get_name (account));
1694                         g_free (tmp);
1695
1696                         label_w = gtk_label_new (NULL);
1697                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1698                         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1699                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1700                         g_string_free (proto, TRUE);
1701                         g_free (label);
1702                 }
1703         }
1704
1705         /* Message count */
1706         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1707         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1708                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1709                                          modest_tny_folder_store_get_message_count (folder_store));
1710         label_w = gtk_label_new (NULL);
1711         gtk_label_set_markup (GTK_LABEL (label_w), label);
1712         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1713         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1714         g_free (label);
1715
1716         /* Folder count */
1717         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1718                                          gray_color_markup, 
1719                                          _("mcen_fi_rootfolder_folders"), 
1720                                          modest_tny_folder_store_get_folder_count (folder_store));
1721         label_w = gtk_label_new (NULL);
1722         gtk_label_set_markup (GTK_LABEL (label_w), label);
1723         gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1724         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1725         g_free (label);
1726
1727         /* Size / Date */
1728         if (modest_tny_account_is_virtual_local_folders (account)
1729                 || modest_tny_account_is_memory_card_account (account)) {
1730
1731                 gchar *size = modest_text_utils_get_display_size (
1732                         modest_tny_folder_store_get_local_size (folder_store));
1733                 
1734                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1735                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1736                                                  size);
1737                 g_free (size);
1738                 
1739                 label_w = gtk_label_new (NULL);
1740                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1741                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1742                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1743                 g_free (label);
1744         } else if (TNY_IS_ACCOUNT(folder_store)) {
1745                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1746                 
1747                 time_t last_updated;
1748                 const gchar *last_updated_string;
1749                 /* Get last updated from configuration */
1750                 last_updated = modest_account_mgr_get_last_updated (modest_runtime_get_account_mgr (), 
1751                                                                     tny_account_get_id (account));
1752
1753                 if (last_updated > 0) 
1754                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1755                 else
1756                         last_updated_string = g_strdup (_("mcen_va_never"));
1757
1758                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1759                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1760                 label_w = gtk_label_new (NULL);
1761                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1762                 gtk_label_set_ellipsize (GTK_LABEL (label_w),  PANGO_ELLIPSIZE_END);
1763                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1764                 g_free (label);
1765         }
1766
1767         g_free (gray_color_markup);
1768
1769         /* Set alignment */
1770         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1771
1772         return vbox;
1773 }
1774
1775 gboolean
1776 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1777 {
1778         ModestMainWindowPrivate *priv = NULL;
1779         
1780         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1781
1782         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1783
1784         return priv->send_receive_in_progress;
1785 }
1786
1787 void 
1788 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1789 {
1790         GtkAction *action = NULL;
1791         GtkWidget *widget = NULL;
1792         ModestMainWindowPrivate *priv = NULL;
1793                 
1794         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1795         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1796         
1797         priv->send_receive_in_progress  = TRUE;
1798
1799         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1800         gtk_action_set_sensitive (action, FALSE);
1801 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1802 /*      gtk_action_set_sensitive (action, FALSE); */
1803         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1804         gtk_widget_set_sensitive (widget, FALSE);
1805
1806
1807 void 
1808 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1809 {
1810         GtkAction *action = NULL;
1811         GtkWidget *widget = NULL;
1812         ModestMainWindowPrivate *priv = NULL;
1813                 
1814         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1815         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1816
1817         priv->send_receive_in_progress  = FALSE;
1818
1819         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1820         gtk_action_set_sensitive (action, TRUE);
1821 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1822 /*      gtk_action_set_sensitive (action, TRUE); */
1823         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1824         gtk_widget_set_sensitive (widget, TRUE);
1825
1826
1827
1828 static void
1829 on_msg_count_changed (ModestHeaderView *header_view,
1830                       TnyFolder *folder,
1831                       TnyFolderChange *change,
1832                       ModestMainWindow *main_window)
1833 {
1834         gboolean folder_empty = FALSE;
1835         gboolean all_marked_as_deleted = FALSE;
1836         ModestMainWindowPrivate *priv;
1837         
1838         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1839         g_return_if_fail (TNY_IS_FOLDER(folder));
1840         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1841
1842         if (change != NULL) {
1843                 TnyFolderChangeChanged changed;
1844
1845                 changed = tny_folder_change_get_changed (change);
1846                 /* If something changes */
1847                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1848                         folder_empty = (tny_folder_change_get_new_all_count (change) == 0);
1849                 else
1850                         folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1851                 
1852                 /* Play a sound (if configured) and make the LED blink  */
1853                 if (changed & TNY_FOLDER_CHANGE_CHANGED_ADDED_HEADERS) {
1854                         modest_platform_on_new_headers_received (NULL, FALSE);
1855                 }
1856                 
1857                 /* Checks header removed  (hide marked as DELETED headers) */
1858                 if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1859                         modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1860                 }
1861         }
1862
1863         /* Check if all messages are marked to be deleted */
1864         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1865         folder_empty = folder_empty || all_marked_as_deleted ;
1866         
1867         /* Set contents style of headers view */
1868         if (folder_empty)  {
1869                 modest_main_window_set_contents_style (main_window,
1870                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1871                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1872         } else {
1873                 modest_main_window_set_contents_style (main_window,
1874                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1875         }
1876 }
1877
1878
1879 void 
1880 modest_main_window_set_contents_style (ModestMainWindow *self, 
1881                                        ModestMainWindowContentsStyle style)
1882 {
1883         ModestMainWindowPrivate *priv;
1884
1885         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1886
1887         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1888
1889         /* We allow to set the same content style than the previously
1890            set if there are details, because it could happen when we're
1891            selecting different accounts consecutively */
1892         if ((priv->contents_style == style) &&
1893             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1894                 return;
1895
1896         /* Remove previous child. Delete it if it was an account
1897            details widget */
1898         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1899         if (content) {
1900                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1901                         g_object_ref (content);
1902                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1903                         g_object_ref (priv->empty_view);
1904                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1905                 }
1906                 
1907                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1908         }
1909
1910         priv->contents_style = style;
1911
1912         switch (priv->contents_style) {
1913         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1914                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1915                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1916                                                       TRUE);
1917                 break;
1918         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1919         {
1920                 /* if we're started without main win, there may not be a folder
1921                  * view. this fixes a GLib-Critical */
1922                 if (priv->folder_view) {
1923                         TnyFolderStore *selected_folderstore = 
1924                                 modest_folder_view_get_selected (priv->folder_view);
1925                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1926                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1927                                                                 TNY_ACCOUNT (selected_folderstore));
1928                                 
1929                                 wrap_in_scrolled_window (priv->contents_widget, 
1930                                                          priv->details_widget);
1931                         }
1932                         g_object_unref (selected_folderstore);
1933                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1934                                                               FALSE);
1935                 }
1936                 break;
1937         }
1938         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1939                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1940                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1941                                                       FALSE);
1942                 break;
1943         default:
1944                 g_return_if_reached ();
1945         }
1946
1947         /* Show */
1948         gtk_widget_show_all (priv->contents_widget);
1949 }
1950
1951 ModestMainWindowContentsStyle
1952 modest_main_window_get_contents_style (ModestMainWindow *self)
1953 {
1954         ModestMainWindowPrivate *priv;
1955
1956         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1957
1958         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1959         return priv->contents_style;
1960 }
1961
1962
1963 static void 
1964 on_configuration_key_changed (ModestConf* conf, 
1965                               const gchar *key, 
1966                               ModestConfEvent event,
1967                               ModestConfNotificationId id, 
1968                               ModestMainWindow *self)
1969 {
1970         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1971         TnyAccount *account = NULL;
1972
1973         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1974                 return;
1975
1976         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1977                 return;
1978
1979         if (priv->folder_view) 
1980                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1981
1982         if (account && TNY_IS_ACCOUNT (account) &&
1983             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1984                 GList *children;
1985                 GtkLabel *label;
1986                 const gchar *device_name;
1987                 gchar *new_text, *gray_color_markup;
1988                 
1989                 /* Get label */
1990                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1991                 label = GTK_LABEL (children->data);
1992                 
1993                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1994                                                       MODEST_CONF_DEVICE_NAME, NULL);
1995
1996                 gray_color_markup = get_gray_color_markup (GTK_WIDGET (self));          
1997                 new_text = create_device_name_visual_string (device_name, gray_color_markup);
1998                 
1999                 gtk_label_set_markup (label, new_text);
2000                 gtk_widget_show (GTK_WIDGET (label));
2001                 
2002                 g_free (gray_color_markup);
2003                 g_free (new_text);
2004                 g_list_free (children);
2005         }
2006         g_object_unref (account);
2007 }
2008
2009 static gboolean
2010 set_toolbar_transfer_mode (ModestMainWindow *self)
2011 {
2012         ModestMainWindowPrivate *priv = NULL;
2013         
2014         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2015
2016         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2017
2018         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
2019         
2020         if (priv->progress_bar_timeout > 0) {
2021                 g_source_remove (priv->progress_bar_timeout);
2022                 priv->progress_bar_timeout = 0;
2023         }
2024
2025         return FALSE;
2026 }
2027
2028 static void 
2029 set_toolbar_mode (ModestMainWindow *self, 
2030                   ModestToolBarModes mode)
2031 {
2032         ModestWindowPrivate *parent_priv = NULL;
2033         ModestMainWindowPrivate *priv = NULL;
2034         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2035         
2036         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2037
2038         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2039         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2040
2041         /* In case this was called before the toolbar exists: */
2042         if (!(parent_priv->toolbar))
2043                 return;
2044
2045         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
2046         
2047         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2048         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2049         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2050
2051         /* Sets current toolbar mode */
2052         priv->current_toolbar_mode = mode;
2053
2054         /* Checks the dimming rules */
2055         modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (self));
2056
2057         /* Show and hide toolbar items */
2058         switch (mode) {
2059         case TOOLBAR_MODE_NORMAL:
2060                 if (sort_action)
2061                         gtk_action_set_visible (sort_action, TRUE);
2062                 if (refresh_action)
2063                         gtk_action_set_visible (refresh_action, TRUE);
2064                 if (priv->progress_toolitem) {
2065                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2066                         gtk_widget_hide (priv->progress_toolitem);
2067                 }
2068                 if (priv->progress_bar)
2069                         gtk_widget_hide (priv->progress_bar);
2070                 
2071                 if (cancel_action)
2072                         gtk_action_set_visible (cancel_action, FALSE);
2073
2074                 /* Hide toolbar if optimized view is enabled */
2075                 if (priv->optimized_view)
2076                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2077                 break;
2078         case TOOLBAR_MODE_TRANSFER:
2079                 if (sort_action)
2080                         gtk_action_set_visible (sort_action, FALSE);
2081                 if (refresh_action)
2082                         gtk_action_set_visible (refresh_action, FALSE);
2083                 if (cancel_action)
2084                         gtk_action_set_visible (cancel_action, TRUE);
2085                 if (priv->progress_bar)
2086                         gtk_widget_show (priv->progress_bar);
2087                 if (priv->progress_toolitem) {
2088                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2089                         gtk_widget_show (priv->progress_toolitem);
2090                 }
2091
2092                 /* Show toolbar if it's hiden (optimized view ) */
2093                 if (priv->optimized_view)
2094                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2095                 break;
2096         default:
2097                 g_return_if_reached ();
2098         }
2099 }
2100
2101 gboolean
2102 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2103 {
2104         ModestMainWindowPrivate *priv;
2105
2106         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2107         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2108
2109         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2110 }
2111
2112 static void
2113 cancel_progressbar (GtkToolButton *toolbutton,
2114                     ModestMainWindow *self)
2115 {
2116         GSList *tmp;
2117         ModestMainWindowPrivate *priv;
2118         
2119         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2120
2121         /* Get operation observers and cancel all the operations */
2122         tmp = priv->progress_widgets;
2123         while (tmp) {
2124                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2125                 tmp=g_slist_next(tmp);
2126         }
2127 }
2128
2129 static gboolean
2130 observers_empty (ModestMainWindow *self)
2131 {
2132         GSList *tmp = NULL;
2133         ModestMainWindowPrivate *priv;
2134         gboolean is_empty = TRUE;
2135         guint pending_ops = 0;
2136  
2137         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2138         tmp = priv->progress_widgets;
2139
2140         /* Check all observers */
2141         while (tmp && is_empty)  {
2142                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2143                 is_empty = pending_ops == 0;
2144                 
2145                 tmp = g_slist_next(tmp);
2146         }
2147         
2148         return is_empty;
2149 }
2150
2151
2152 /**
2153  * Gets the toolbar mode needed for each mail operation. It stores in
2154  * @mode_changed if the toolbar mode has changed or not
2155  */
2156 static ModestToolBarModes
2157 get_toolbar_mode_from_mail_operation (ModestMainWindow *self,
2158                                       ModestMailOperation *mail_op,
2159                                       gboolean *mode_changed)
2160 {
2161         ModestToolBarModes mode;
2162         ModestMainWindowPrivate *priv;
2163
2164         *mode_changed = FALSE;
2165         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2166
2167         /* Get toolbar mode from operation id*/
2168         switch (modest_mail_operation_get_type_operation (mail_op)) {
2169         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2170         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2171                 mode = TOOLBAR_MODE_TRANSFER;
2172                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2173                         *mode_changed = TRUE;
2174                 break;
2175         default:
2176                 mode = TOOLBAR_MODE_NORMAL;             
2177         }
2178         return mode;
2179 }
2180
2181 static void 
2182 on_mail_operation_started (ModestMailOperation *mail_op,
2183                            gpointer user_data)
2184 {
2185         ModestMainWindow *self;
2186         ModestMailOperationTypeOperation op_type;
2187         ModestMainWindowPrivate *priv;
2188         ModestToolBarModes mode;
2189         GSList *tmp;
2190         gboolean mode_changed = FALSE;
2191         TnyAccount *account;
2192
2193         self = MODEST_MAIN_WINDOW (user_data);
2194         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2195
2196         /* Do not show progress for receiving operations if the
2197            account is the local account or the MMC one */
2198         op_type = modest_mail_operation_get_type_operation (mail_op);
2199         account = modest_mail_operation_get_account (mail_op);
2200         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2201                 gboolean is_remote;
2202
2203                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2204                               modest_tny_account_is_memory_card_account (account));
2205                 g_object_unref (account);
2206                 if (!is_remote)
2207                         return;
2208         }
2209                
2210         /* Get toolbar mode from operation id*/
2211         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2212
2213         /* Add operation observers and change toolbar if neccessary*/
2214         tmp = priv->progress_widgets;
2215         if (mode == TOOLBAR_MODE_TRANSFER) {
2216                 if (mode_changed) {
2217                         GObject *source = modest_mail_operation_get_source(mail_op);
2218                         if (G_OBJECT (self) == source) {
2219                                 set_toolbar_transfer_mode(self);
2220                         }
2221                         g_object_unref (source);
2222                 }
2223
2224                 while (tmp) {
2225                         modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2226                                                               mail_op);
2227                         tmp = g_slist_next (tmp);
2228                 }
2229         }
2230 }
2231
2232 static void 
2233 on_mail_operation_finished (ModestMailOperation *mail_op,
2234                             gpointer user_data)
2235 {
2236         ModestToolBarModes mode;
2237         ModestMailOperationTypeOperation op_type;
2238         GSList *tmp = NULL;
2239         ModestMainWindow *self;
2240         gboolean mode_changed;
2241         TnyAccount *account;
2242         ModestMainWindowPrivate *priv;
2243
2244         self = MODEST_MAIN_WINDOW (user_data);
2245         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2246
2247         /* The mail operation was not added to the progress objects if
2248            the account was the local account or the MMC one */
2249         op_type = modest_mail_operation_get_type_operation (mail_op);
2250         account = modest_mail_operation_get_account (mail_op);
2251         if (account && op_type == MODEST_MAIL_OPERATION_TYPE_RECEIVE) {
2252                 gboolean is_remote;
2253
2254                 is_remote = !(modest_tny_account_is_virtual_local_folders (account) ||
2255                               modest_tny_account_is_memory_card_account (account));
2256                 g_object_unref (account);
2257                 if (!is_remote)
2258                         return;
2259         }
2260
2261         /* Get toolbar mode from operation id*/
2262         mode = get_toolbar_mode_from_mail_operation (self, mail_op, &mode_changed);
2263
2264         /* Change toolbar mode */
2265         tmp = priv->progress_widgets;
2266         if (mode == TOOLBAR_MODE_TRANSFER) {                    
2267                 while (tmp) {
2268                         modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2269                                                                  mail_op);
2270                         tmp = g_slist_next (tmp);
2271                 }
2272                 
2273                 /* If no more operations are being observed, NORMAL mode is enabled again */
2274                 if (observers_empty (self)) {
2275                         set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2276                 }
2277         }
2278 }
2279
2280 static void
2281 on_queue_changed (ModestMailOperationQueue *queue,
2282                   ModestMailOperation *mail_op,
2283                   ModestMailOperationQueueNotification type,
2284                   ModestMainWindow *self)
2285 {
2286         ModestMainWindowPrivate *priv;
2287
2288         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2289
2290         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
2291                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2292                                                                G_OBJECT (mail_op),
2293                                                                "operation-started",
2294                                                                G_CALLBACK (on_mail_operation_started),
2295                                                                self);
2296                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
2297                                                                G_OBJECT (mail_op),
2298                                                                "operation-finished",
2299                                                                G_CALLBACK (on_mail_operation_finished),
2300                                                                self);
2301         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
2302                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2303                                                                   G_OBJECT (mail_op),
2304                                                                   "operation-started");
2305                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
2306                                                                   G_OBJECT (mail_op),
2307                                                                   "operation-finished");
2308         }
2309 }
2310
2311 static void
2312 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2313 {
2314         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2315         GtkAction *action;
2316         ModestAccountMgr *mgr;
2317         ModestAccountSettings *settings;
2318         ModestServerAccountSettings *store_settings = NULL;
2319
2320         /* Get account data */
2321         mgr = modest_runtime_get_account_mgr ();
2322         settings = modest_account_mgr_load_account_settings (mgr, acc_name);
2323         if (settings)
2324                 store_settings = modest_account_settings_get_store_settings (settings);
2325
2326         /* Set the new visible & active account */
2327         if (settings && (modest_server_account_settings_get_account_name (store_settings)!= NULL)) { 
2328                 const gchar *account_name;
2329
2330                 account_name = modest_account_settings_get_account_name (settings);
2331
2332                 modest_folder_view_set_account_id_of_visible_server_account 
2333                         (priv->folder_view,
2334                          modest_server_account_settings_get_account_name (store_settings));
2335                 modest_window_set_active_account (MODEST_WINDOW (self), account_name);
2336                 action = gtk_action_group_get_action (priv->view_additions_group, account_name);
2337                 if (action != NULL) {
2338                         if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) {
2339                                 modest_utils_toggle_action_set_active_block_notify (
2340                                         GTK_TOGGLE_ACTION (action),
2341                                         TRUE);
2342                         }
2343                 }
2344         }
2345         
2346         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2347
2348
2349         /* Free */
2350         if (settings) {
2351                 g_object_unref (store_settings);
2352                 g_object_unref (settings);
2353         }
2354 }
2355
2356 /* Make sure that at least one account is "viewed": */
2357 static void
2358 set_at_least_one_account_visible(ModestMainWindow *self)
2359 {
2360         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2361         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2362
2363         if (!(priv->folder_view)) {
2364                 /* It is too early to do this. */
2365                 return; 
2366         }
2367         
2368         const gchar *active_server_account_name = 
2369                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);
2370         
2371         if (!active_server_account_name ||
2372                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2373         {
2374                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2375                 gchar* default_modest_name = modest_account_mgr_get_default_account (account_mgr);
2376                 if (default_modest_name) {
2377                         set_account_visible (self, default_modest_name);
2378                 } else if (first_modest_name) {
2379                         set_account_visible (self, first_modest_name);
2380                 }
2381                 g_free (first_modest_name);
2382                 g_free (default_modest_name);
2383         }
2384 }
2385
2386 static void 
2387 on_show_account_action_toggled  (GtkToggleAction *action,
2388                                    gpointer user_data)
2389 {
2390         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2391
2392         const gchar *acc_name = gtk_action_get_name (GTK_ACTION (action));
2393         if (gtk_toggle_action_get_active (action))
2394                 set_account_visible (self, acc_name);
2395 }
2396
2397 static void
2398 refresh_account (const gchar *account_name)
2399 {
2400         ModestWindow *win;
2401         
2402         /* win must already exists here, obviously */ 
2403         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr (),
2404                                                  FALSE);
2405         if (!win) {
2406                 g_warning ("%s: BUG: no main window!", __FUNCTION__);
2407                 return;
2408         }
2409         
2410         /* If account_name == NULL, we must update all (option All) */
2411         if (!account_name)
2412                 modest_ui_actions_do_send_receive_all (win);
2413         else
2414                 modest_ui_actions_do_send_receive (account_name, win);
2415         
2416 }
2417
2418 static void 
2419 on_refresh_account_action_activated  (GtkAction *action,
2420                                       gpointer user_data)
2421 {
2422         refresh_account ((const gchar*) user_data);
2423 }
2424
2425 static void
2426 on_send_receive_csm_activated (GtkMenuItem *item,
2427                                gpointer user_data)
2428 {
2429         refresh_account ((const gchar*) user_data);
2430 }
2431
2432 static gboolean
2433 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2434 {
2435         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2436
2437         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2438         return FALSE;
2439
2440 }
2441
2442 static gboolean
2443 on_folder_view_focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer userdata)
2444 {
2445         ModestMainWindow *main_window = NULL;
2446         
2447         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2448         main_window = MODEST_MAIN_WINDOW (userdata);
2449         
2450         /* Update window dimming state */
2451         modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (main_window));
2452
2453         return FALSE;
2454 }
2455
2456 static gboolean
2457 on_header_view_focus_in (GtkWidget *widget,
2458                          GdkEventFocus *event,
2459                          gpointer userdata)
2460 {
2461         ModestMainWindow *main_window = NULL;
2462
2463         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2464
2465         main_window = MODEST_MAIN_WINDOW (userdata);
2466
2467         /* Update window dimming state */
2468         modest_ui_actions_check_window_dimming_rules (MODEST_WINDOW (main_window));
2469
2470         return FALSE;
2471 }
2472
2473 static void 
2474 on_folder_selection_changed (ModestFolderView *folder_view,
2475                              TnyFolderStore *folder_store, 
2476                              gboolean selected,
2477                              ModestMainWindow *main_window)
2478 {
2479         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2480         GtkAction *action = NULL;
2481         gboolean show_reply = TRUE;
2482         gboolean show_forward = TRUE;
2483         gboolean show_cancel_send = FALSE;
2484         gboolean show_clipboard = TRUE;
2485         gboolean show_delete = TRUE;
2486
2487         if (selected) {
2488                 if (TNY_IS_ACCOUNT (folder_store)) {
2489                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2490                 } else if (TNY_IS_FOLDER (folder_store)) {
2491                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2492                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2493                                         TNY_FOLDER (folder_store));
2494                                 switch (folder_type) {
2495                                 case TNY_FOLDER_TYPE_DRAFTS:
2496                                         show_clipboard = show_delete = TRUE;
2497                                         show_reply = show_forward = show_cancel_send = FALSE;
2498                                         break;
2499                                 case TNY_FOLDER_TYPE_SENT:
2500                                         show_forward = show_clipboard = show_delete = TRUE;
2501                                         show_reply = show_cancel_send = FALSE;
2502                                         break;
2503                                 case TNY_FOLDER_TYPE_OUTBOX:
2504                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2505                                         show_reply = show_forward = FALSE;
2506                                         break;
2507                                 case TNY_FOLDER_TYPE_INVALID:
2508                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2509                                         break;
2510                                 default:
2511                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2512                                         show_cancel_send = FALSE;
2513                                 }
2514                         } else {
2515                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2516                                 show_cancel_send = FALSE;
2517                         }
2518                 }
2519         }
2520
2521         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2522         gtk_action_set_visible (action, show_reply);
2523         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2524         gtk_action_set_visible (action, show_reply);
2525         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2526         gtk_action_set_visible (action, show_forward);
2527         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2528         gtk_action_set_visible (action, show_cancel_send);
2529         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2530         gtk_action_set_visible (action, show_delete);
2531
2532         /* We finally call to the ui actions handler, after updating properly
2533          * the header view CSM */
2534         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2535 }
2536
2537 gboolean 
2538 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2539                                                    GtkTreeModel *model,
2540                                                    GtkTreeRowReference *row_reference,
2541                                                    ModestMainWindow *self)
2542 {
2543         ModestMainWindowPrivate *priv = NULL;
2544         GtkTreeModel *header_model = NULL;
2545         GtkTreePath *path = NULL;
2546
2547         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2548         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2549         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2550
2551         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2552         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2553
2554         /* Do nothing if we changed the folder in the main view */
2555         if (header_model != model)
2556                 return FALSE;
2557
2558         /* Select the message in the header view */
2559         path = gtk_tree_row_reference_get_path (row_reference);
2560         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2561                                   path, NULL, FALSE);
2562         gtk_tree_path_free (path);
2563
2564         return TRUE;
2565 }
2566
2567 static gboolean
2568 show_updating_banner (gpointer user_data)
2569 {
2570         ModestMainWindowPrivate *priv = NULL;
2571
2572         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2573
2574         if (priv->updating_banner == NULL) {
2575
2576                 /* We're outside the main lock */
2577                 gdk_threads_enter ();
2578                 priv->updating_banner = 
2579                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
2580                                                           _CS ("ckdg_pb_updating"));
2581                 gdk_threads_leave ();
2582         }
2583
2584         /* Remove timeout */
2585         priv->updating_banner_timeout = 0;
2586         return FALSE;
2587 }
2588
2589 /**
2590  * We use this function to show/hide a progress banner showing
2591  * "Updating" while the header view is being filled. We're not showing
2592  * it unless the update takes more than 2 seconds
2593  *
2594  * If starting = TRUE then the refresh is starting, otherwise it means
2595  * that is has just finished
2596  */
2597 static void 
2598 on_updating_msg_list (ModestHeaderView *header_view,
2599                       gboolean starting,
2600                       gpointer user_data)
2601 {
2602         ModestMainWindowPrivate *priv = NULL;
2603
2604         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
2605         
2606         /* Remove old timeout */
2607         if (priv->updating_banner_timeout > 0) {
2608                 g_source_remove (priv->updating_banner_timeout);
2609                 priv->updating_banner_timeout = 0;
2610         }
2611
2612         /* Create a new timeout */
2613         if (starting) {
2614                 priv->updating_banner_timeout = 
2615                         g_timeout_add (2000, show_updating_banner, user_data);
2616         } else {
2617                 /* Remove the banner if exists */
2618                 if (priv->updating_banner) {
2619                         gtk_widget_destroy (priv->updating_banner);
2620                         priv->updating_banner = NULL;
2621                 }
2622         }
2623 }
2624
2625 gboolean
2626 modest_main_window_screen_is_on (ModestMainWindow *self)
2627 {
2628         ModestMainWindowPrivate *priv = NULL;
2629
2630         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2631         
2632         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
2633 }