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