* check whether folder_view actually exists before calling it;
[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                 break;
1368         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
1369                 /* Remove header view */
1370                 g_object_ref (priv->contents_widget);
1371                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
1372
1373                 /* Reparent the main paned */
1374                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
1375                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
1376
1377                 break;
1378         default:
1379                 g_return_if_reached ();
1380         }
1381
1382         /* Let header view grab the focus if it's being shown */
1383         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1384                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1385         else 
1386                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1387
1388         /* Show changes */
1389         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1390 }
1391
1392 ModestMainWindowStyle
1393 modest_main_window_get_style (ModestMainWindow *self)
1394 {
1395         ModestMainWindowPrivate *priv;
1396
1397         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1398
1399         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1400         return priv->style;
1401 }
1402
1403
1404
1405 static gboolean
1406 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1407 {
1408         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1409                 ModestWindowPrivate *parent_priv;
1410                 ModestWindowMgr *mgr;
1411                 gboolean is_fullscreen;
1412                 GtkAction *fs_toggle_action;
1413                 gboolean active;
1414                 
1415                 mgr = modest_runtime_get_window_mgr ();
1416                 
1417                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1418
1419                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1420                 
1421                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1422                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1423                 if (is_fullscreen != active) {
1424                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1425                 }
1426         }
1427
1428         return FALSE;
1429
1430 }
1431
1432 static void
1433 set_homogeneous (GtkWidget *widget,
1434                  gpointer data)
1435 {
1436         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1437         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1438 }
1439
1440 static void 
1441 modest_main_window_show_toolbar (ModestWindow *self,
1442                                  gboolean show_toolbar)
1443 {
1444         ModestMainWindowPrivate *priv = NULL;
1445         ModestWindowPrivate *parent_priv = NULL;        
1446         GtkWidget *reply_button = NULL, *menu = NULL;
1447         GtkWidget *placeholder = NULL;
1448         gint insert_index;
1449
1450         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1451         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1452         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1453
1454         /* Set optimized view status */
1455         priv->optimized_view = !show_toolbar;
1456
1457         if (!parent_priv->toolbar) {
1458                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1459                                                                   "/ToolBar");
1460
1461                 /* Set homogeneous toolbar */
1462                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1463                                        set_homogeneous, NULL);
1464         
1465                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1466                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1467                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1468                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1469                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1470                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1471                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1472                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1473
1474                 /* Add ProgressBar (Transfer toolbar) */ 
1475                 priv->progress_bar = modest_progress_bar_widget_new ();
1476                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1477                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1478                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1479                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1480                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1481                 
1482                 /* Connect cancel 'clicked' signal to abort progress mode */
1483                 g_signal_connect(priv->cancel_toolitem, "clicked",
1484                                  G_CALLBACK(cancel_progressbar),
1485                                  self);
1486                 
1487                 /* Add it to the observers list */
1488                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1489
1490                 /* Add to window */
1491                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1492                                            GTK_TOOLBAR (parent_priv->toolbar));
1493
1494                 /* Set reply button tap and hold menu */
1495                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1496                                                           "/ToolBar/ToolbarMessageReply");
1497                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1498                                                   "/ToolbarReplyCSM");
1499                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1500
1501                 /* Set send & receive button tap and hold menu */
1502                 update_menus (MODEST_MAIN_WINDOW (self));
1503         }
1504
1505         if (show_toolbar) {
1506                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1507                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1508                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1509
1510                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1511                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1512         } else
1513                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1514
1515 }
1516
1517 static void
1518 on_account_inserted (TnyAccountStore *accoust_store,
1519                      TnyAccount *account,
1520                      gpointer user_data)
1521 {
1522         update_menus (MODEST_MAIN_WINDOW (user_data));
1523 }
1524
1525 static void
1526 on_account_changed (ModestAccountMgr* mgr,
1527                     const gchar* account,
1528                     gpointer user_data)
1529 {
1530         gchar *default_account = modest_account_mgr_get_default_account (modest_runtime_get_account_mgr ());
1531
1532         /* Actually, we only want to know when another account has become
1533          * the default account, but there is no default_account_changed
1534          * signal in ModestAccountMgr. */
1535         if(strcmp(account, default_account) == 0)
1536                 update_menus (MODEST_MAIN_WINDOW (user_data));
1537
1538         g_free (default_account);
1539 }
1540
1541 static void
1542 on_account_removed (TnyAccountStore *accoust_store,
1543                      TnyAccount *account,
1544                      gpointer user_data)
1545 {
1546         update_menus (MODEST_MAIN_WINDOW (user_data));
1547 }
1548
1549 /* 
1550  * This function manages the key events used to navigate between
1551  * header and folder views (when the window is in split view)
1552  *
1553  * FROM         KEY        ACTION
1554  * -------------------------------------------------
1555  * HeaderView   GDK_Left   Move focus to folder view
1556  * FolderView   GDK_Right  Move focus to header view
1557  *
1558  * There is no need to scroll to selected row, the widgets will be the
1559  * responsibles of doing that (probably managing the focus-in event
1560  */
1561 static gboolean 
1562 on_inner_widgets_key_pressed (GtkWidget *widget,
1563                               GdkEventKey *event,
1564                               gpointer user_data)
1565 {
1566         ModestMainWindowPrivate *priv;
1567
1568         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1569
1570         /* Do nothing if we're in SIMPLE style */
1571         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1572                 return FALSE;
1573
1574         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1575                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1576         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1577                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1578
1579         return FALSE;
1580 }
1581
1582 static void
1583 set_alignment (GtkWidget *widget,
1584                gpointer data)
1585 {
1586         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1587         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1588 }
1589
1590 static GtkWidget *
1591 create_empty_view (void)
1592 {
1593         GtkLabel *label = NULL;
1594         GtkWidget *align = NULL;
1595
1596         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1597         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1598         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1599         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1600
1601         return GTK_WIDGET(align);
1602 }
1603
1604 static GtkWidget *
1605 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1606 {
1607         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1608         
1609         GtkWidget *vbox;
1610         GtkWidget *label_w;
1611         gchar *label;
1612         gchar *gray_color_markup;
1613
1614         vbox = gtk_vbox_new (FALSE, 0);
1615
1616         /* Obtain the secondary text color. We need a realized widget, that's why 
1617            we get styled_widget from outside */
1618 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1619         GdkColor color;
1620         gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1621         gray_color_markup = modest_text_utils_get_color_string (&color);
1622 #else
1623         // gray_color_markup is freed below
1624         gray_color_markup = g_strdup ("#BBBBBB");
1625 #endif  
1626         /* Account description: */
1627         
1628         if (modest_tny_account_is_virtual_local_folders (account)
1629                 || (modest_tny_account_is_memory_card_account (account))) {
1630                 gchar *tmp;
1631                 /* Local folders: */
1632         
1633                 /* Get device name */
1634                 gchar *device_name = NULL;
1635                 if (modest_tny_account_is_virtual_local_folders (account))
1636                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1637                                                       MODEST_CONF_DEVICE_NAME, NULL);
1638                 else
1639                         device_name = g_strdup (tny_account_get_name (account));
1640                                                       
1641                 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1642                 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1643                                                  gray_color_markup, tmp, device_name);
1644                 g_free (tmp);
1645                 label_w = gtk_label_new (NULL);
1646                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1647                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1648                 g_free (device_name);
1649                 g_free (label);
1650         } else {
1651                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1652                         gtk_box_pack_start (GTK_BOX (vbox), 
1653                                 gtk_label_new (tny_account_get_name (account)), 
1654                                 FALSE, FALSE, 0);
1655                 } else {
1656                         /* Other accounts, such as IMAP and POP: */
1657                         
1658                         GString *proto;
1659                         gchar *tmp;
1660         
1661                         /* Put proto in uppercase */
1662                         proto = g_string_new (tny_account_get_proto (account));
1663                         proto = g_string_ascii_up (proto);
1664                         
1665                         /* note: mcen_fi_localroot_description is something like "%s account"
1666                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1667                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1668                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1669                                                          gray_color_markup, tmp, tny_account_get_name (account));
1670                         g_free (tmp);
1671
1672                         label_w = gtk_label_new (NULL);
1673                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1674                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1675                         g_string_free (proto, TRUE);
1676                         g_free (label);
1677                 }
1678         }
1679
1680         /* Message count */
1681         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1682         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1683                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1684                                          modest_tny_folder_store_get_message_count (folder_store));
1685         label_w = gtk_label_new (NULL);
1686         gtk_label_set_markup (GTK_LABEL (label_w), label);
1687         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1688         g_free (label);
1689
1690         /* Folder count */
1691         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1692                                          gray_color_markup, 
1693                                          _("mcen_fi_rootfolder_folders"), 
1694                                          modest_tny_folder_store_get_folder_count (folder_store));
1695         label_w = gtk_label_new (NULL);
1696         gtk_label_set_markup (GTK_LABEL (label_w), label);
1697         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1698         g_free (label);
1699
1700         /* Size / Date */
1701         if (modest_tny_account_is_virtual_local_folders (account)
1702                 || modest_tny_account_is_memory_card_account (account)) {
1703
1704                 gchar *size = modest_text_utils_get_display_size (
1705                         modest_tny_folder_store_get_local_size (folder_store));
1706                 
1707                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1708                                                  gray_color_markup, _("mcen_fi_rootfolder_size"),
1709                                                  size);
1710                 g_free (size);
1711                 
1712                 label_w = gtk_label_new (NULL);
1713                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1714                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1715                 g_free (label);
1716         } else if (TNY_IS_ACCOUNT(folder_store)) {
1717                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1718                 
1719                 time_t last_updated;
1720                 gchar *last_updated_string;
1721                 /* Get last updated from configuration */
1722                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1723                                                           tny_account_get_id (account), 
1724                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1725                                                           TRUE);
1726                 if (last_updated > 0) 
1727                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1728                 else
1729                         last_updated_string = g_strdup (_("mcen_va_never"));
1730
1731                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1732                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1733                 label_w = gtk_label_new (NULL);
1734                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1735                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1736                 g_free (last_updated_string);
1737                 g_free (label);
1738         }
1739
1740         g_free (gray_color_markup);
1741
1742         /* Set alignment */
1743         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1744
1745         return vbox;
1746 }
1747
1748 gboolean
1749 modest_main_window_send_receive_in_progress (ModestMainWindow *self)
1750 {
1751         ModestMainWindowPrivate *priv = NULL;
1752         
1753         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1754
1755         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1756
1757         return priv->send_receive_in_progress;
1758 }
1759
1760 void 
1761 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1762 {
1763         GtkAction *action = NULL;
1764         GtkWidget *widget = NULL;
1765         ModestMainWindowPrivate *priv = NULL;
1766                 
1767         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1768         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1769         
1770         priv->send_receive_in_progress  = TRUE;
1771
1772         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1773         gtk_action_set_sensitive (action, FALSE);
1774 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1775 /*      gtk_action_set_sensitive (action, FALSE); */
1776         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1777         gtk_widget_set_sensitive (widget, FALSE);
1778
1779
1780 void 
1781 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1782 {
1783         GtkAction *action = NULL;
1784         GtkWidget *widget = NULL;
1785         ModestMainWindowPrivate *priv = NULL;
1786                 
1787         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1788         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1789
1790         priv->send_receive_in_progress  = FALSE;
1791
1792         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1793         gtk_action_set_sensitive (action, TRUE);
1794 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1795 /*      gtk_action_set_sensitive (action, TRUE); */
1796         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1797         gtk_widget_set_sensitive (widget, TRUE);
1798
1799
1800
1801 static void
1802 _on_msg_count_changed (ModestHeaderView *header_view,
1803                        TnyFolder *folder,
1804                        TnyFolderChange *change,
1805                        ModestMainWindow *main_window)
1806 {
1807         printf ("DEBUG: %s\n", __FUNCTION__);
1808         gboolean folder_empty = FALSE;
1809         gboolean all_marked_as_deleted = FALSE;
1810         TnyFolderChangeChanged changed; 
1811         ModestMainWindowPrivate *priv;
1812         
1813         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1814         g_return_if_fail (TNY_IS_FOLDER(folder));
1815         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1816         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
1817         
1818         changed = tny_folder_change_get_changed (change);
1819         
1820         /* If something changes */
1821         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1822                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1823         else
1824                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1825         
1826         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1827
1828 /*      Check header removed  (hide marked as DELETED headers) */
1829         if (changed & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS) {
1830                 modest_header_view_refilter (MODEST_HEADER_VIEW(priv->header_view));
1831         }
1832
1833         /* Check if all messages are marked to be deleted */
1834         all_marked_as_deleted = modest_header_view_is_empty (header_view);
1835         folder_empty = folder_empty || all_marked_as_deleted ;
1836         
1837         /* Set contents style of headers view */
1838         if (folder_empty)  {
1839                 modest_main_window_set_contents_style (main_window,
1840                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1841                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1842         }
1843         else {
1844                 modest_main_window_set_contents_style (main_window,
1845                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1846         }       
1847 }
1848
1849
1850 void 
1851 modest_main_window_set_contents_style (ModestMainWindow *self, 
1852                                        ModestMainWindowContentsStyle style)
1853 {
1854         ModestMainWindowPrivate *priv;
1855
1856         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1857
1858         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1859
1860         /* We allow to set the same content style than the previously
1861            set if there are details, because it could happen when we're
1862            selecting different accounts consecutively */
1863         if ((priv->contents_style == style) &&
1864             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1865                 return;
1866
1867         /* Remove previous child. Delete it if it was an account
1868            details widget */
1869         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1870         if (content) {
1871                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1872                         g_object_ref (content);
1873                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1874                         g_object_ref (priv->empty_view);
1875                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1876                 }
1877                 
1878                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1879         }
1880
1881         priv->contents_style = style;
1882
1883         switch (priv->contents_style) {
1884         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1885                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1886                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1887                                                       TRUE);
1888                 break;
1889         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1890         {
1891                 /* if we're started without main win, there may not be a folder
1892                  * view. this fixes a GLib-Critical */
1893                 if (priv->folder_view) {
1894                         TnyFolderStore *selected_folderstore = 
1895                                 modest_folder_view_get_selected (priv->folder_view);
1896                         if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1897                                 priv->details_widget = create_details_widget (GTK_WIDGET (self),
1898                                                                 TNY_ACCOUNT (selected_folderstore));
1899                                 
1900                                 wrap_in_scrolled_window (priv->contents_widget, 
1901                                                          priv->details_widget);
1902                         }
1903                         g_object_unref (selected_folderstore);
1904                         modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1905                                                               FALSE);
1906                 }
1907                 break;
1908         }
1909         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1910                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1911                 modest_maemo_set_thumbable_scrollbar (GTK_SCROLLED_WINDOW(priv->contents_widget),
1912                                                       FALSE);
1913                 break;
1914         default:
1915                 g_return_if_reached ();
1916         }
1917
1918         /* Show */
1919         gtk_widget_show_all (priv->contents_widget);
1920 }
1921
1922 ModestMainWindowContentsStyle
1923 modest_main_window_get_contents_style (ModestMainWindow *self)
1924 {
1925         ModestMainWindowPrivate *priv;
1926
1927         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1928
1929         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1930         return priv->contents_style;
1931 }
1932
1933
1934 static void 
1935 on_configuration_key_changed (ModestConf* conf, 
1936                               const gchar *key, 
1937                               ModestConfEvent event,
1938                               ModestConfNotificationId id, 
1939                               ModestMainWindow *self)
1940 {
1941         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1942         TnyAccount *account = NULL;
1943
1944         if (!key || 
1945             priv->notification_id != id ||
1946             strcmp (key, MODEST_CONF_DEVICE_NAME))
1947                 return;
1948
1949         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1950                 return;
1951         if (priv->folder_view) 
1952                 account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1953         if (account && TNY_IS_ACCOUNT (account) &&
1954             strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID) == 0) {
1955                 GList *children;
1956                 GtkLabel *label;
1957                 const gchar *device_name;
1958                 gchar *new_text;
1959                 
1960                 /* Get label */
1961                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1962                 label = GTK_LABEL (children->data);
1963                 
1964                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1965                                                       MODEST_CONF_DEVICE_NAME, NULL);
1966                 
1967                 new_text = g_strdup_printf ("%s: %s",
1968                                             _("mcen_fi_localroot_description"),
1969                                             device_name);
1970                 
1971                 gtk_label_set_text (label, new_text);
1972                 gtk_widget_show (GTK_WIDGET (label));
1973                 
1974                 g_free (new_text);
1975                 g_list_free (children);
1976         }
1977         g_object_unref (account);
1978 }
1979
1980 static gboolean
1981 set_toolbar_transfer_mode (ModestMainWindow *self)
1982 {
1983         ModestMainWindowPrivate *priv = NULL;
1984         
1985         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1986
1987         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1988
1989         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1990         
1991         if (priv->progress_bar_timeout > 0) {
1992                 g_source_remove (priv->progress_bar_timeout);
1993                 priv->progress_bar_timeout = 0;
1994         }
1995
1996         return FALSE;
1997 }
1998
1999 static void 
2000 set_toolbar_mode (ModestMainWindow *self, 
2001                   ModestToolBarModes mode)
2002 {
2003         ModestWindowPrivate *parent_priv = NULL;
2004         ModestMainWindowPrivate *priv = NULL;
2005         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
2006         
2007         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2008
2009         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
2010         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2011
2012         /* In case this was called before the toolbar exists: */
2013         if (!(parent_priv->toolbar))
2014                 return;
2015
2016         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
2017         
2018         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
2019         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
2020         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
2021
2022         /* Sets current toolbar mode */
2023         priv->current_toolbar_mode = mode;
2024
2025         /* Checks the dimming rules */
2026         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (self));
2027
2028         /* Show and hide toolbar items */
2029         switch (mode) {
2030         case TOOLBAR_MODE_NORMAL:
2031                 if (sort_action)
2032                         gtk_action_set_visible (sort_action, TRUE);
2033                 if (refresh_action)
2034                         gtk_action_set_visible (refresh_action, TRUE);
2035                 if (priv->progress_toolitem) {
2036                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
2037                         gtk_widget_hide (priv->progress_toolitem);
2038                 }
2039                 if (priv->progress_bar)
2040                         gtk_widget_hide (priv->progress_bar);
2041                 
2042                 if (cancel_action)
2043                         gtk_action_set_visible (cancel_action, FALSE);
2044
2045                 /* Hide toolbar if optimized view is enabled */
2046                 if (priv->optimized_view)
2047                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
2048                 break;
2049         case TOOLBAR_MODE_TRANSFER:
2050                 if (sort_action)
2051                         gtk_action_set_visible (sort_action, FALSE);
2052                 if (refresh_action)
2053                         gtk_action_set_visible (refresh_action, FALSE);
2054                 if (cancel_action)
2055                         gtk_action_set_visible (cancel_action, TRUE);
2056                 if (priv->progress_toolitem) {
2057                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
2058                         gtk_widget_show (priv->progress_toolitem);
2059                 }
2060                 if (priv->progress_bar)
2061                         gtk_widget_show (priv->progress_bar);
2062
2063                 /* Show toolbar if it's hiden (optimized view ) */
2064                 if (priv->optimized_view)
2065                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
2066                 break;
2067         default:
2068                 g_return_if_reached ();
2069         }
2070 }
2071
2072 gboolean
2073 modest_main_window_transfer_mode_enabled (ModestMainWindow *self)
2074 {
2075         ModestMainWindowPrivate *priv;
2076
2077         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2078         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2079
2080         return priv->current_toolbar_mode == TOOLBAR_MODE_TRANSFER;
2081 }
2082
2083 static void
2084 cancel_progressbar (GtkToolButton *toolbutton,
2085                     ModestMainWindow *self)
2086 {
2087         GSList *tmp;
2088         ModestMainWindowPrivate *priv;
2089         
2090         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2091
2092         /* Get operation observers and cancel all the operations */
2093         tmp = priv->progress_widgets;
2094         while (tmp) {
2095                 modest_progress_object_cancel_all_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2096                 tmp=g_slist_next(tmp);
2097         }
2098 }
2099
2100 static gboolean
2101 observers_empty (ModestMainWindow *self)
2102 {
2103         GSList *tmp = NULL;
2104         ModestMainWindowPrivate *priv;
2105         gboolean is_empty = TRUE;
2106         guint pending_ops = 0;
2107  
2108         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2109         tmp = priv->progress_widgets;
2110
2111         /* Check all observers */
2112         while (tmp && is_empty)  {
2113                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
2114                 is_empty = pending_ops == 0;
2115                 
2116                 tmp = g_slist_next(tmp);
2117         }
2118         
2119         return is_empty;
2120 }
2121
2122 static void
2123 on_queue_changed (ModestMailOperationQueue *queue,
2124                   ModestMailOperation *mail_op,
2125                   ModestMailOperationQueueNotification type,
2126                   ModestMainWindow *self)
2127 {
2128         ModestMainWindowPrivate *priv;
2129         ModestMailOperationTypeOperation op_type;
2130         ModestToolBarModes mode;
2131         GSList *tmp;
2132         gboolean mode_changed = FALSE;
2133
2134         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
2135         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2136                
2137         /* Get toolbar mode from operation id*/
2138         op_type = modest_mail_operation_get_type_operation (mail_op);
2139         switch (op_type) {
2140         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
2141         case MODEST_MAIL_OPERATION_TYPE_OPEN:
2142                 mode = TOOLBAR_MODE_TRANSFER;
2143                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
2144                         mode_changed = TRUE;
2145                 break;
2146         default:
2147                 mode = TOOLBAR_MODE_NORMAL;
2148                 
2149         }
2150                 
2151                        
2152         /* Add operation observers and change toolbar if neccessary*/
2153         tmp = priv->progress_widgets;
2154         switch (type) {
2155         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
2156                 if (mode == TOOLBAR_MODE_TRANSFER) {
2157                         if (mode_changed) {
2158                                 set_toolbar_transfer_mode(self);                    
2159                         }
2160                         while (tmp) {
2161                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2162                                                                       mail_op);
2163                                 tmp = g_slist_next (tmp);
2164                         }
2165                 }
2166                 break;
2167         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
2168                 /* Change toolbar mode */
2169                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
2170                         while (tmp) {
2171                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
2172                                                                          mail_op);
2173                                 tmp = g_slist_next (tmp);
2174                         }
2175                         
2176                         /* If no more operations are being observed, NORMAL mode is enabled again */
2177                         if (observers_empty (self)) {
2178                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);                           
2179                         }
2180                 }
2181
2182                 break;
2183         }       
2184
2185 }
2186
2187 static void
2188 set_account_visible(ModestMainWindow *self, const gchar *acc_name)
2189 {
2190         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2191
2192         /* Get account data */
2193         ModestAccountMgr *mgr = modest_runtime_get_account_mgr ();
2194         ModestAccountData *acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
2195
2196         /* Set the new visible & active account */
2197         if (acc_data && acc_data->store_account) { 
2198                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
2199                                                                              acc_data->store_account->account_name);
2200                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
2201         }
2202         
2203         modest_folder_view_select_first_inbox_or_local (priv->folder_view);
2204
2205         /* Free */
2206         if (acc_data)
2207                 modest_account_mgr_free_account_data (mgr, acc_data);
2208 }
2209
2210 /* Make sure that at least one account is "viewed": */
2211 static void
2212 set_at_least_one_account_visible(ModestMainWindow *self)
2213 {
2214         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
2215         ModestAccountMgr *account_mgr = modest_runtime_get_account_mgr();
2216
2217         if (!(priv->folder_view)) {
2218                 /* It is too early to do this. */
2219                 return; 
2220         }
2221         
2222         const gchar *active_server_account_name = 
2223                 modest_folder_view_get_account_id_of_visible_server_account (priv->folder_view);        
2224         if (!active_server_account_name ||
2225                 !modest_account_mgr_account_exists (account_mgr, active_server_account_name, TRUE))
2226         {
2227                 gchar* first_modest_name = modest_account_mgr_get_first_account_name (account_mgr);
2228                 if (first_modest_name) {
2229                         set_account_visible (self, first_modest_name);
2230                         g_free (first_modest_name);
2231                 }
2232         }
2233 }
2234
2235 static void 
2236 on_show_account_action_activated  (GtkAction *action,
2237                                    gpointer user_data)
2238 {
2239         ModestMainWindow *self = MODEST_MAIN_WINDOW (user_data);
2240
2241         const gchar *acc_name = gtk_action_get_name (action);
2242         set_account_visible (self, acc_name);
2243 }
2244
2245 static void
2246 refresh_account (const gchar *account_name)
2247 {
2248         ModestWindow *win;
2249
2250         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
2251
2252         /* If account_name == NULL, we must update all (option All) */
2253         if (!account_name)
2254                 modest_ui_actions_do_send_receive_all (win);
2255         else
2256                 modest_ui_actions_do_send_receive (account_name, win);
2257         
2258 }
2259
2260 static void 
2261 on_refresh_account_action_activated  (GtkAction *action,
2262                                       gpointer user_data)
2263 {
2264         refresh_account ((const gchar*) user_data);
2265 }
2266
2267 static void
2268 on_send_receive_csm_activated (GtkMenuItem *item,
2269                                gpointer user_data)
2270 {
2271         refresh_account ((const gchar*) user_data);
2272 }
2273
2274 static gboolean
2275 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2276 {
2277         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2278
2279         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2280         return FALSE;
2281
2282 }
2283
2284 static gboolean
2285 on_folder_view_focus_in (GtkWidget *widget,
2286                          GdkEventFocus *event,
2287                          gpointer userdata)
2288 {
2289         ModestMainWindow *main_window = NULL;
2290         
2291         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2292         main_window = MODEST_MAIN_WINDOW (userdata);
2293         
2294         /* Update toolbar dimming state */
2295         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2296
2297         return FALSE;
2298 }
2299
2300 static gboolean
2301 on_header_view_focus_in (GtkWidget *widget,
2302                          GdkEventFocus *event,
2303                          gpointer userdata)
2304 {
2305         ModestMainWindow *main_window = NULL;
2306         ModestMainWindowPrivate *priv = NULL;
2307
2308         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (userdata), FALSE);
2309         main_window = MODEST_MAIN_WINDOW (userdata);
2310         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (main_window);
2311
2312         /* Update toolbar dimming state */
2313         modest_ui_actions_check_toolbar_dimming_rules (MODEST_WINDOW (main_window));
2314
2315         return FALSE;
2316 }
2317
2318 static void 
2319 modest_main_window_on_folder_selection_changed (ModestFolderView *folder_view,
2320                                                 TnyFolderStore *folder_store, 
2321                                                 gboolean selected,
2322                                                 ModestMainWindow *main_window)
2323 {
2324         ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (main_window);
2325         GtkAction *action = NULL;
2326         gboolean show_reply = TRUE;
2327         gboolean show_forward = TRUE;
2328         gboolean show_cancel_send = FALSE;
2329         gboolean show_clipboard = TRUE;
2330         gboolean show_delete = TRUE;
2331
2332         if (selected) {
2333                 if (TNY_IS_ACCOUNT (folder_store)) {
2334                         show_reply = show_forward = show_cancel_send = show_clipboard = show_delete = FALSE;
2335                 } else if (TNY_IS_FOLDER (folder_store)) {
2336                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (folder_store))) {
2337                                 TnyFolderType folder_type = modest_tny_folder_get_local_or_mmc_folder_type (
2338                                         TNY_FOLDER (folder_store));
2339                                 switch (folder_type) {
2340                                 case TNY_FOLDER_TYPE_DRAFTS:
2341                                         show_clipboard = show_delete = TRUE;
2342                                         show_reply = show_forward = show_cancel_send = FALSE;
2343                                         break;
2344                                 case TNY_FOLDER_TYPE_SENT:
2345                                         show_forward = show_clipboard = show_delete = TRUE;
2346                                         show_reply = show_cancel_send = FALSE;
2347                                         break;
2348                                 case TNY_FOLDER_TYPE_OUTBOX:
2349                                         show_clipboard = show_delete = show_cancel_send = TRUE;
2350                                         show_reply = show_forward = FALSE;
2351                                         break;
2352                                 default:
2353                                         show_reply = show_forward = show_clipboard = show_delete = TRUE;
2354                                         show_cancel_send = FALSE;
2355                                 }
2356                         } else {
2357                                 show_reply = show_forward = show_clipboard = show_delete = TRUE;
2358                                 show_cancel_send = FALSE;
2359                         }
2360                 }
2361         }
2362
2363         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReply");
2364         gtk_action_set_visible (action, show_reply);
2365         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMReplyAll");
2366         gtk_action_set_visible (action, show_reply);
2367         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMForward");
2368         gtk_action_set_visible (action, show_forward);
2369         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCancelSending");
2370         gtk_action_set_visible (action, show_cancel_send);
2371         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCut");
2372         gtk_action_set_visible (action, show_clipboard);
2373         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMCopy");
2374         gtk_action_set_visible (action, show_clipboard);
2375         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMPaste");
2376         gtk_action_set_visible (action, show_clipboard);
2377         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/HeaderViewCSM/HeaderViewCSMDelete");
2378         gtk_action_set_visible (action, show_delete);
2379
2380         /* We finally call to the ui actions handler, after updating properly
2381          * the header view CSM */
2382         modest_ui_actions_on_folder_selection_changed (folder_view, folder_store, selected, main_window);
2383
2384 }
2385
2386 gboolean 
2387 modest_main_window_on_msg_view_window_msg_changed (ModestMsgViewWindow *view_window,
2388                                                    GtkTreeModel *model,
2389                                                    GtkTreeRowReference *row_reference,
2390                                                    ModestMainWindow *self)
2391 {
2392         ModestMainWindowPrivate *priv = NULL;
2393         GtkTreeModel *header_model = NULL;
2394         GtkTreePath *path = NULL;
2395
2396         g_return_val_if_fail (MODEST_IS_MSG_VIEW_WINDOW (view_window), FALSE);
2397         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
2398         g_return_val_if_fail (gtk_tree_row_reference_valid (row_reference), FALSE);
2399
2400         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
2401         header_model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->header_view));
2402
2403         /* Do nothing if we changed the folder in the main view */
2404         if (header_model != model)
2405                 return FALSE;
2406
2407         /* Select the message in the header view */
2408         path = gtk_tree_row_reference_get_path (row_reference);
2409         gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->header_view),
2410                                   path, NULL, FALSE);
2411         gtk_tree_path_free (path);
2412
2413         return TRUE;
2414 }
2415