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