2007-06-29 Murray Cumming <murrayc@murrayc-desktop>
[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-maemo-conic-device.h>
35 #include "modest-hildon-includes.h"
36 #include "modest-defs.h"
37 #include <string.h>
38
39 #include "widgets/modest-main-window.h"
40 #include "widgets/modest-msg-edit-window.h"
41 #include "widgets/modest-account-view-window.h"
42 #include "modest-runtime.h"
43 #include "modest-account-mgr-helpers.h"
44 #include "modest-platform.h"
45 #include "modest-widget-memory.h"
46 #include "modest-window-priv.h"
47 #include "modest-main-window-ui.h"
48 #include "modest-main-window-ui-dimming.h"
49 #include "modest-account-mgr.h"
50 #include "modest-tny-account.h"
51 #include "modest-conf.h"
52 #include <modest-maemo-utils.h>
53 #include "modest-tny-platform-factory.h"
54 #include "modest-tny-msg.h"
55 #include "modest-mail-operation.h"
56 #include "modest-icon-names.h"
57 #include "modest-progress-bar-widget.h"
58 #include "modest-text-utils.h"
59 #include "modest-ui-dimming-manager.h"
60 #include "maemo/modest-osso-state-saving.h"
61
62 #ifdef MODEST_HAVE_HILDON0_WIDGETS
63 #include <hildon-widgets/hildon-program.h>
64 #else
65 #include <hildon/hildon-program.h>
66 #endif /*MODEST_HAVE_HILDON0_WIDGETS*/
67
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
69
70 #define XALIGN 0.5
71 #define YALIGN 0.0
72 #define XSPACE 1
73 #define YSPACE 0
74
75 /* 'private'/'protected' functions */
76 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
77 static void modest_main_window_init          (ModestMainWindow *obj);
78 static void modest_main_window_finalize      (GObject *obj);
79 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
80                                                            GdkEventWindowState *event, 
81                                                            gpointer userdata);
82
83 static void connect_signals (ModestMainWindow *self);
84
85 static void restore_settings (ModestMainWindow *self, gboolean do_folder_view_too);
86 static void save_state (ModestWindow *self);
87
88 static void modest_main_window_show_toolbar   (ModestWindow *window,
89                                                gboolean show_toolbar);
90
91 static void cancel_progressbar (GtkToolButton *toolbutton,
92                                 ModestMainWindow *self);
93
94 static void         on_queue_changed                     (ModestMailOperationQueue *queue,
95                                                           ModestMailOperation *mail_op,
96                                                           ModestMailOperationQueueNotification type,
97                                                           ModestMainWindow *self);
98
99 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
100
101 static void on_account_update                 (TnyAccountStore *account_store, 
102                                                const gchar *account_name,
103                                                gpointer user_data);
104
105 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
106                                                GdkEventKey *event,
107                                                gpointer user_data);
108
109 static void on_configuration_key_changed      (ModestConf* conf, 
110                                                const gchar *key, 
111                                                ModestConfEvent event, 
112                                                ModestMainWindow *self);
113
114 static void set_toolbar_mode                  (ModestMainWindow *self, 
115                                                ModestToolBarModes mode);
116
117 static gboolean set_toolbar_transfer_mode     (ModestMainWindow *self); 
118
119 static void on_show_account_action_activated      (GtkAction *action,
120                                                    gpointer user_data);
121
122 static void on_refresh_account_action_activated   (GtkAction *action,
123                                                    gpointer user_data);
124
125 static void on_send_receive_csm_activated         (GtkMenuItem *item,
126                                                    gpointer user_data);
127
128 static void
129 _on_msg_count_changed (ModestHeaderView *header_view,
130                        TnyFolder *folder,
131                        TnyFolderChange *change,
132                        ModestMainWindow *main_window);
133
134 static void
135 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self);
136
137
138 static GtkWidget * create_empty_view (void);
139
140
141 /* list my signals */
142 enum {
143         /* MY_SIGNAL_1, */
144         /* MY_SIGNAL_2, */
145         LAST_SIGNAL
146 };
147
148 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
149 struct _ModestMainWindowPrivate {
150         GtkWidget *msg_paned;
151         GtkWidget *main_paned;
152         GtkWidget *main_vbox;
153         GtkWidget *contents_widget;
154         GtkWidget *empty_view;
155
156         /* Progress observers */
157         GtkWidget        *progress_bar;
158         GSList           *progress_widgets;
159
160         /* Tollbar items */
161         GtkWidget   *progress_toolitem;
162         GtkWidget   *cancel_toolitem;
163         GtkWidget   *sort_toolitem;
164         GtkWidget   *refresh_toolitem;
165         ModestToolBarModes current_toolbar_mode;
166
167         /* Merge ids used to add/remove accounts to the ViewMenu*/
168         GByteArray *merge_ids;
169
170         /* On-demand widgets */
171         GtkWidget *accounts_popup;
172         GtkWidget *details_widget;
173
174         /* Optimized view enabled */
175         gboolean optimized_view;
176
177         /* Optimized view enabled */
178         gboolean send_receive_in_progress;
179
180         ModestHeaderView *header_view;
181         ModestFolderView *folder_view;
182
183         ModestMainWindowStyle style;
184         ModestMainWindowContentsStyle contents_style;
185
186         guint progress_bar_timeout;
187
188         /* Signal handler UIDs */
189         gint queue_changed_handler_uid; 
190         GList *queue_err_signals;
191 };
192 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
193                                                 MODEST_TYPE_MAIN_WINDOW, \
194                                                 ModestMainWindowPrivate))
195
196 typedef struct _GetMsgAsyncHelper {
197         ModestMainWindowPrivate *main_window_private;
198         guint action;
199         ModestTnyMsgReplyType reply_type;
200         ModestTnyMsgForwardType forward_type;
201         gchar *from;
202         TnyIterator *iter;
203 } GetMsgAsyncHelper;
204
205
206 /* globals */
207 static GtkWindowClass *parent_class = NULL;
208
209
210 /* Private actions */
211 /* This is the context sensitive menu: */
212 static const GtkActionEntry modest_folder_view_action_entries [] = {
213
214         /* Folder View CSM actions */
215         { "FolderViewCSMNewFolder", NULL, N_("mcen_ti_new_folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
216         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
217         { "FolderViewCSMPasteMsgs", NULL, N_("mcen_me_inbox_paste"), NULL, NULL,  G_CALLBACK (modest_ui_actions_on_paste)},
218         { "FolderViewCSMDeleteFolder", NULL, N_("mcen_me_inbox_delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
219         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_search_messages) },
220         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_help) },
221 };
222
223 static const GtkActionEntry modest_header_view_action_entries [] = {
224
225         /* Header View CSM actions */
226         { "HeaderViewCSMOpen",          NULL,  N_("mcen_me_inbox_open"),        NULL,       NULL, G_CALLBACK (modest_ui_actions_on_open) },
227         { "HeaderViewCSMReply",         NULL,  N_("mcen_me_inbox_reply"),       NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply) },
228         { "HeaderViewCSMReplyAll",      NULL,  N_("mcen_me_inbox_replytoall"),  NULL,      NULL, G_CALLBACK (modest_ui_actions_on_reply_all) },
229         { "HeaderViewCSMForward",       NULL,  N_("mcen_me_inbox_forward"),     NULL,      NULL, G_CALLBACK (modest_ui_actions_on_forward) },
230         { "HeaderViewCSMCut",           NULL,  N_("mcen_me_inbox_cut"),         "<CTRL>X", NULL, G_CALLBACK (modest_ui_actions_on_cut) },
231         { "HeaderViewCSMCopy",          NULL,  N_("mcen_me_inbox_copy"),        "<CTRL>C", NULL, G_CALLBACK (modest_ui_actions_on_copy) },
232         { "HeaderViewCSMPaste",         NULL,  N_("mcen_me_inbox_paste"),       "<CTRL>V", NULL, G_CALLBACK (modest_ui_actions_on_paste) },
233         { "HeaderViewCSMDelete",        NULL,  N_("mcen_me_inbox_delete"),      NULL,      NULL, G_CALLBACK (modest_ui_actions_on_delete) },
234         { "HeaderViewCSMCancelSending", NULL,  N_("mcen_me_outbox_cancelsend"), NULL,      NULL, NULL },
235         { "HeaderViewCSMHelp",          NULL,  N_("mcen_me_inbox_help"),        NULL,      NULL, G_CALLBACK (modest_ui_actions_on_help) },
236 };
237
238 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
239         { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
240 };
241
242 /************************************************************************/
243
244 GType
245 modest_main_window_get_type (void)
246 {
247         static GType my_type = 0;
248         if (!my_type) {
249                 static const GTypeInfo my_info = {
250                         sizeof(ModestMainWindowClass),
251                         NULL,           /* base init */
252                         NULL,           /* base finalize */
253                         (GClassInitFunc) modest_main_window_class_init,
254                         NULL,           /* class finalize */
255                         NULL,           /* class data */
256                         sizeof(ModestMainWindow),
257                         1,              /* n_preallocs */
258                         (GInstanceInitFunc) modest_main_window_init,
259                         NULL
260                 };
261                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
262                                                   "ModestMainWindow",
263                                                   &my_info, 0);
264         }
265         return my_type;
266 }
267
268 static void
269 modest_main_window_class_init (ModestMainWindowClass *klass)
270 {
271         GObjectClass *gobject_class;
272         gobject_class = (GObjectClass*) klass;
273         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
274
275         parent_class            = g_type_class_peek_parent (klass);
276         gobject_class->finalize = modest_main_window_finalize;
277
278         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
279         
280         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
281         modest_window_class->save_state_func = save_state;
282         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
283         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
284 }
285
286 static void
287 modest_main_window_init (ModestMainWindow *obj)
288 {
289         ModestMainWindowPrivate *priv;
290
291         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
292
293         priv->queue_err_signals = NULL;
294         priv->msg_paned    = NULL;
295         priv->main_paned   = NULL;      
296         priv->main_vbox    = NULL;
297         priv->header_view  = NULL;
298         priv->folder_view  = NULL;
299         priv->contents_widget  = NULL;
300         priv->accounts_popup  = NULL;
301         priv->details_widget  = NULL;
302         priv->empty_view  = NULL;
303         priv->progress_widgets  = NULL;
304         priv->progress_bar = NULL;
305         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
306         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
307         priv->contents_style  = -1; /* invalid contents style. We need this to select it for the first time */
308         priv->merge_ids = NULL;
309         priv->optimized_view  = FALSE;
310         priv->send_receive_in_progress  = FALSE;
311         priv->progress_bar_timeout = 0;
312         priv->queue_changed_handler_uid = 0;
313 }
314
315 static void
316 modest_main_window_finalize (GObject *obj)
317 {
318         ModestMainWindowPrivate *priv;
319
320         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
321
322         modest_main_window_cleanup_queue_error_signals ((ModestMainWindow *) obj);
323
324         g_slist_free (priv->progress_widgets);
325
326         g_byte_array_free (priv->merge_ids, TRUE);
327
328         if (priv->progress_bar_timeout > 0) {
329                 g_source_remove (priv->progress_bar_timeout);
330                 priv->progress_bar_timeout = 0;
331         }
332
333         /* Disconnect signal handlers */
334         if (priv->queue_changed_handler_uid)
335                 g_signal_handler_disconnect (modest_runtime_get_mail_operation_queue (),
336                                              priv->queue_changed_handler_uid);
337
338         G_OBJECT_CLASS(parent_class)->finalize (obj);
339 }
340
341 GtkWidget*
342 modest_main_window_get_child_widget (ModestMainWindow *self,
343                                      ModestWidgetType widget_type)
344 {
345         ModestMainWindowPrivate *priv;
346         GtkWidget *widget;
347         
348         g_return_val_if_fail (self, NULL);
349         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
350                               NULL);
351         
352         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
353
354         switch (widget_type) {
355         case MODEST_WIDGET_TYPE_HEADER_VIEW:
356                 widget = (GtkWidget*)priv->header_view; break;
357         case MODEST_WIDGET_TYPE_FOLDER_VIEW:
358                 widget = (GtkWidget*)priv->folder_view; break;
359         default:
360                 return NULL;
361         }
362
363         return widget ? GTK_WIDGET(widget) : NULL;
364 }
365
366
367 static void
368 restore_settings (ModestMainWindow *self, gboolean do_folder_view_too)
369 {
370         ModestConf *conf;
371         ModestMainWindowPrivate *priv;
372
373         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
374
375         conf = modest_runtime_get_conf ();
376
377         modest_widget_memory_restore (conf, G_OBJECT(self),
378                                       MODEST_CONF_MAIN_WINDOW_KEY);
379
380         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
381                                       MODEST_CONF_HEADER_VIEW_KEY);
382
383         if (do_folder_view_too)
384                 modest_widget_memory_restore (conf, G_OBJECT(priv->folder_view),
385                                       MODEST_CONF_FOLDER_VIEW_KEY);
386
387         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
388                                       MODEST_CONF_MAIN_PANED_KEY);
389
390         /* We need to force a redraw here in order to get the right
391            position of the horizontal paned separator */
392         gtk_widget_show (GTK_WIDGET (self));
393 }
394
395
396 static void
397 save_state (ModestWindow *window)
398 {
399         ModestConf *conf;
400         ModestMainWindow* self = MODEST_MAIN_WINDOW(window);
401         ModestMainWindowPrivate *priv;
402                 
403         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
404         conf = modest_runtime_get_conf ();
405         
406         modest_widget_memory_save (conf,G_OBJECT(self), 
407                                    MODEST_CONF_MAIN_WINDOW_KEY);
408         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
409                                    MODEST_CONF_MAIN_PANED_KEY);
410         //      modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
411         //                         MODEST_CONF_HEADER_VIEW_KEY);
412         modest_widget_memory_save (conf, G_OBJECT(priv->folder_view), 
413                                    MODEST_CONF_FOLDER_VIEW_KEY);
414 }
415
416 static void
417 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
418 {
419         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
420                 gtk_scrolled_window_add_with_viewport
421                         (GTK_SCROLLED_WINDOW(win), widget);
422         else
423                 gtk_container_add (GTK_CONTAINER(win),
424                                    widget);
425 }
426
427
428 static gboolean
429 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
430 {
431         modest_window_save_state (MODEST_WINDOW(self));
432         return FALSE;
433 }
434
435 typedef struct
436 {
437         ModestMainWindow *self;
438         TnySendQueue *queue;
439         TnyHeader *header;
440 } OnResponseInfo;
441
442 static void
443 on_response (GtkDialog *dialog, gint arg1, gpointer user_data)
444 {
445         OnResponseInfo *info = (OnResponseInfo *) user_data;
446         ModestMainWindow *self = info->self;
447         TnyHeader *header = info->header;
448         TnySendQueue *queue = info->queue;
449
450         if (arg1 == GTK_RESPONSE_YES) {
451                 TnyFolder *outbox = tny_send_queue_get_outbox (queue);
452                 tny_folder_remove_msg (outbox, header, NULL);
453                 tny_folder_sync (outbox, TRUE, NULL);
454                 g_object_unref (outbox);
455         }
456
457         g_object_unref (queue);
458         g_object_unref (header);
459         g_object_unref (self);
460
461         gtk_widget_destroy (GTK_WIDGET (dialog));
462         g_slice_free (OnResponseInfo, info);
463 }
464
465
466 static void
467 on_sendqueue_error_happened (TnySendQueue *self, TnyHeader *header, TnyMsg *msg, GError *err, ModestMainWindow *user_data)
468 {
469         if (header) {
470                 gchar *str = g_strdup_printf ("%s. Do you want to remove the message (%s)?",
471                         err->message, tny_header_get_subject (header));
472                 OnResponseInfo *info = g_slice_new (OnResponseInfo);
473                 GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (user_data), 0,
474                         GTK_MESSAGE_ERROR, GTK_BUTTONS_YES_NO, str);
475                 g_free (str);
476                 info->queue = g_object_ref (self);
477                 info->self = g_object_ref (user_data);
478                 info->header = g_object_ref (header);
479                 g_signal_connect (G_OBJECT (dialog), "response",
480                         G_CALLBACK (on_response), info);
481                 gtk_widget_show_all (dialog);
482         }
483 }
484
485 typedef struct {
486         TnySendQueue *queue;
487         guint signal;
488 } QueueErrorSignal;
489
490 static void
491 modest_main_window_cleanup_queue_error_signals (ModestMainWindow *self)
492 {
493         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
494
495         GList *oerrsignals = priv->queue_err_signals;
496         while (oerrsignals) {
497                 QueueErrorSignal *esignal = (QueueErrorSignal *) oerrsignals->data;
498                 g_signal_handler_disconnect (esignal->queue, esignal->signal);
499                 g_slice_free (QueueErrorSignal, esignal);
500                 oerrsignals = g_list_next (oerrsignals);
501         }
502         g_list_free (priv->queue_err_signals);
503         priv->queue_err_signals = NULL;
504 }
505
506 static void
507 on_account_store_connecting_finished (TnyAccountStore *store, ModestMainWindow *self)
508 {
509         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
510
511         /* When going online, do the equivalent of pressing the send/receive button, 
512          * as per the specification:
513          * (without the check for >0 accounts, though that is not specified): */
514
515         TnyDevice *device = tny_account_store_get_device (store);
516
517         /* modest_folder_view_update_model (MODEST_FOLDER_VIEW (priv->folder_view), store); */
518         
519         /* Check that we are really online.
520          * This signal should not be emitted when we are not connected, 
521          * but it seems to happen sometimes: */
522          if (!tny_device_is_online (device))
523                 return;
524                 
525         const gchar *iap_id = tny_maemo_conic_device_get_current_iap_id (TNY_MAEMO_CONIC_DEVICE (device));
526         printf ("DEBUG: %s: connection id=%s\n", __FUNCTION__, iap_id);
527         
528         /* Stop the existing send queues: */
529         modest_runtime_remove_all_send_queues ();
530         
531         /* Create the send queues again, using the appropriate transport accounts 
532          * for this new connection.
533          * This could be the first time that they are created if this is the first 
534          * connection. */
535         /* TODO: Does this really destroy the TnySendQueues and their threads
536          * We do not want 2 TnySendQueues to exist with the same underlying 
537          * outbox directory. */
538
539         modest_main_window_cleanup_queue_error_signals (self);
540
541         GSList *account_names = modest_account_mgr_account_names (
542                 modest_runtime_get_account_mgr(), 
543                 TRUE /* enabled accounts only */);
544         GSList *iter = account_names;
545         while (iter) {
546                 const gchar *account_name = (const gchar*)(iter->data);
547                         if (account_name) {
548                         TnyTransportAccount *account = TNY_TRANSPORT_ACCOUNT (
549                                 modest_tny_account_store_get_transport_account_for_open_connection
550                                                  (modest_runtime_get_account_store(), account_name));
551                         if (account) {
552                                 /* Q: Is this the first location where the send-queues are requested? */
553                                 QueueErrorSignal *esignal = g_slice_new (QueueErrorSignal);
554                                 printf ("debug: %s:\n  Transport account for %s: %s\n", __FUNCTION__, account_name, 
555                                         tny_account_get_id(TNY_ACCOUNT(account)));
556                                 esignal->queue = TNY_SEND_QUEUE (modest_runtime_get_send_queue (account));
557                                 esignal->signal = g_signal_connect (G_OBJECT (esignal->queue), "error-happened",
558                                         G_CALLBACK (on_sendqueue_error_happened), self);
559                                 priv->queue_err_signals = g_list_prepend (priv->queue_err_signals, esignal);
560                         }
561                 }
562                 
563                 iter = g_slist_next (iter);
564         }
565
566         modest_account_mgr_free_account_names (account_names);
567         account_names = NULL;
568         
569         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (self));
570 }
571
572 static void
573 _folder_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
574 {
575         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
576
577         /* Update dimmed */     
578         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
579 }
580
581 static void
582 _header_view_csm_menu_activated (GtkWidget *widget, gpointer user_data)
583 {
584         g_return_if_fail (MODEST_IS_MAIN_WINDOW (user_data));
585
586         /* Update visibility */
587
588         /* Update dimmed */     
589         modest_window_check_dimming_rules_group (MODEST_WINDOW (user_data), "ModestMenuDimmingRules");  
590 }
591
592 static void
593 connect_signals (ModestMainWindow *self)
594 {       
595         ModestWindowPrivate *parent_priv;
596         ModestMainWindowPrivate *priv;
597         GtkWidget *menu;
598         
599         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
600         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
601
602         /* folder view */
603         g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
604                           G_CALLBACK(on_inner_widgets_key_pressed), self);
605         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
606                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
607         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
608                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
609
610         /* Folder view CSM */
611         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
612         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
613         g_signal_connect (G_OBJECT(priv->folder_view), "tap-and-hold",
614                           G_CALLBACK(_folder_view_csm_menu_activated),
615                           self);
616         /* header view */
617         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
618                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
619         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
620                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
621         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
622                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
623         g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
624                           G_CALLBACK(on_inner_widgets_key_pressed), self);
625         g_signal_connect (G_OBJECT(priv->header_view), "msg_count_changed",
626                           G_CALLBACK(_on_msg_count_changed), self);
627
628         /* Header view CSM */
629         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/HeaderViewCSM");
630         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->header_view), menu, NULL, 0);
631         g_signal_connect (G_OBJECT(priv->header_view), "tap-and-hold",
632                           G_CALLBACK(_header_view_csm_menu_activated),
633                           self);
634         
635         /* window */
636         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
637         g_signal_connect (G_OBJECT (self), "window-state-event",
638                           G_CALLBACK (modest_main_window_window_state_event),
639                           NULL);
640         
641         /* Mail Operation Queue */
642         priv->queue_changed_handler_uid = 
643                 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
644                                   "queue-changed", G_CALLBACK (on_queue_changed), self);
645
646         /* Track changes in the device name */
647         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
648                           "key_changed", G_CALLBACK (on_configuration_key_changed), 
649                           self);
650
651         /* Track account changes. We need to refresh the toolbar */
652         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
653                           "account_update", G_CALLBACK (on_account_update),
654                           self);
655
656         /* Account store */
657         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), 
658                           "password_requested",
659                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
660                           
661         /* Device */
662         g_signal_connect (G_OBJECT(modest_runtime_get_account_store()), 
663                           "connecting-finished",
664                           G_CALLBACK(on_account_store_connecting_finished), self);
665 }
666
667 #if 0
668 /** Idle handler, to send/receive at startup .*/
669 gboolean
670 sync_accounts_cb (ModestMainWindow *win)
671 {
672         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
673         return FALSE; /* Do not call this idle handler again. */
674 }
675 #endif
676
677 static void on_hildon_program_is_topmost_notify(GObject *self,
678         GParamSpec *propert_param, gpointer user_data)
679 {
680         HildonProgram *app = HILDON_PROGRAM (self);
681         
682         /*
683         ModestWindow* self = MODEST_WINDOW(user_data);
684         */
685         
686         /* Note that use of hildon_program_set_can_hibernate() 
687          * is generally referred to as "setting the killable flag", 
688          * though hibernation does not seem equal to death.
689          * murrayc */
690                  
691         if (hildon_program_get_is_topmost (app)) {
692                 /* Prevent hibernation when the progam comes to the foreground,
693                  * because hibernation should only happen when the application 
694                  * is in the background: */
695                 hildon_program_set_can_hibernate (app, FALSE);
696         } else {
697                 /* Allow hibernation if the program has gone to the background: */
698                 
699                 /* However, prevent hibernation while the settings are being changed: */
700                 const gboolean hibernation_prevented = 
701                         modest_window_mgr_get_hibernation_is_prevented (
702         modest_runtime_get_window_mgr ()); 
703         
704                 if (hibernation_prevented)
705                         hildon_program_set_can_hibernate (app, FALSE);
706                 else {
707                         /* Allow hibernation, after saving the state: */
708                         modest_osso_save_state();
709                         hildon_program_set_can_hibernate (app, TRUE);
710                 }
711         }
712         
713 }
714
715 static void
716 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
717 {
718         GtkWidget *folder_win = (GtkWidget *) user_data;
719         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
720         
721         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
722         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
723 /*      wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
724
725         gtk_widget_show (GTK_WIDGET (priv->folder_view));
726
727         /* Connect signals */
728         connect_signals ((ModestMainWindow*)self);
729
730         /* Set account store */
731         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
732                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
733
734         /* Load previous osso state, for instance if we are being restored from 
735          * hibernation:  */
736         modest_osso_load_state ();
737
738         /* Restore window & widget settings */
739         
740         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
741
742         /* Check if accounts exist and show the account wizard if not */
743         gboolean accounts_exist = 
744                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
745
746         if (!accounts_exist) {
747                 /* This is necessary to have the main window shown behind the dialog 
748                 It's an ugly hack... jschmid */
749                 gtk_widget_show_all(GTK_WIDGET(self));
750                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
751         } else {
752                 GSList *accounts;
753                 GtkAction *send_receive_all;
754                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
755                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
756                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
757                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
758                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts));
759                 modest_account_mgr_free_account_names (accounts);
760         }
761
762
763 }
764
765 ModestWindow *
766 modest_main_window_new (void)
767 {
768         ModestMainWindow *self = NULL;  
769         ModestMainWindowPrivate *priv = NULL;
770         ModestWindowPrivate *parent_priv = NULL;
771         GtkWidget *folder_win = NULL;
772         ModestDimmingRulesGroup *menu_rules_group = NULL;
773         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
774         GtkActionGroup *action_group = NULL;
775         GError *error = NULL;
776         GdkPixbuf *window_icon = NULL; 
777         ModestConf *conf = NULL;
778         GtkAction *action = NULL;
779
780         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
781         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
782         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
783
784         parent_priv->ui_manager = gtk_ui_manager_new();
785         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
786
787         action_group = gtk_action_group_new ("ModestMainWindowActions");
788         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
789
790         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules");
791         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules");
792
793         /* Add common actions */
794         gtk_action_group_add_actions (action_group,
795                                       modest_action_entries,
796                                       G_N_ELEMENTS (modest_action_entries),
797                                       self);
798
799         gtk_action_group_add_actions (action_group,
800                                       modest_folder_view_action_entries,
801                                       G_N_ELEMENTS (modest_folder_view_action_entries),
802                                       self);
803
804         gtk_action_group_add_actions (action_group,
805                                       modest_header_view_action_entries,
806                                       G_N_ELEMENTS (modest_header_view_action_entries),
807                                       self);
808
809         gtk_action_group_add_toggle_actions (action_group,
810                                              modest_toggle_action_entries,
811                                              G_N_ELEMENTS (modest_toggle_action_entries),
812                                              self);
813
814         gtk_action_group_add_toggle_actions (action_group,
815                                              modest_main_window_toggle_action_entries,
816                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
817                                              self);
818
819         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
820         g_object_unref (action_group);
821
822         /* Load the UI definition */
823         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
824                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
825         if (error != NULL) {
826                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
827                 g_error_free (error);
828                 error = NULL;
829         }
830
831         /* Add common dimming rules */
832         modest_dimming_rules_group_add_rules (menu_rules_group, 
833                                               modest_main_window_menu_dimming_entries,
834                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
835                                               self);
836         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
837                                               modest_main_window_toolbar_dimming_entries,
838                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
839                                               self);
840
841         /* Insert dimming rules group for this window */
842         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
843         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
844         g_object_unref (menu_rules_group);
845         g_object_unref (toolbar_rules_group);
846         
847         /* Add accelerators */
848         gtk_window_add_accel_group (GTK_WINDOW (self), 
849                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
850
851         /* Menubar. Update the state of some toggles */
852         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
853         conf = modest_runtime_get_conf ();
854         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
855                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
856         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
857                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
858         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
859                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
860         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
861                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
862         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
863
864         /* Get device name */
865         modest_maemo_utils_get_device_name ();
866
867         /* header view */
868         priv->header_view =
869                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
870         if (!priv->header_view)
871                 g_printerr ("modest: cannot instantiate header view\n");
872         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
873         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
874                                       MODEST_CONF_HEADER_VIEW_KEY);
875
876         /* Empty view */ 
877         priv->empty_view = create_empty_view ();
878                  
879         /* Create scrolled windows */
880         folder_win = gtk_scrolled_window_new (NULL, NULL);
881         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
882         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
883                                         GTK_POLICY_NEVER,
884                                         GTK_POLICY_AUTOMATIC);
885         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
886                                         GTK_POLICY_NEVER,
887                                         GTK_POLICY_AUTOMATIC);
888
889         /* paned */
890         priv->main_paned = gtk_hpaned_new ();
891         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
892         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
893         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
894
895         /* putting it all together... */
896         priv->main_vbox = gtk_vbox_new (FALSE, 6);
897         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
898
899         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
900
901         /* Set window icon */
902         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
903         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
904         
905         HildonProgram *app = hildon_program_get_instance ();
906         hildon_program_add_window (app, HILDON_WINDOW (self));
907         
908         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
909                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
910
911         g_signal_connect (G_OBJECT(self), "show",
912                           G_CALLBACK (modest_main_window_on_show), folder_win);
913                 
914
915         restore_settings (MODEST_MAIN_WINDOW(self), FALSE);
916
917         return MODEST_WINDOW(self);
918 }
919
920 gboolean 
921 modest_main_window_close_all (ModestMainWindow *self)
922 {
923         GtkWidget *note;
924         GtkResponseType response;
925
926         /* Create the confirmation dialog MSG-NOT308 */
927         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
928                                                          _("emev_nc_close_windows"),
929                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
930                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
931                                                          NULL);
932
933         response = gtk_dialog_run (GTK_DIALOG (note));
934         gtk_widget_destroy (GTK_WIDGET (note));
935
936         if (response == GTK_RESPONSE_YES)
937                 return TRUE;
938         else
939                 return FALSE;
940 }
941
942
943 void 
944 modest_main_window_set_style (ModestMainWindow *self, 
945                               ModestMainWindowStyle style)
946 {
947         ModestMainWindowPrivate *priv;
948         ModestWindowPrivate *parent_priv;
949         GtkAction *action;
950
951         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
952
953         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
954         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
955
956         /* no change -> nothing to do */
957         if (priv->style == style)
958                 return;
959
960         /* Get toggle button */
961         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
962
963         priv->style = style;
964         switch (style) {
965         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
966                 /* Remove main paned */
967                 g_object_ref (priv->main_paned);
968                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
969
970                 /* Reparent the contents widget to the main vbox */
971                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
972
973                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
974                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
975                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
976
977                 break;
978         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
979                 /* Remove header view */
980                 g_object_ref (priv->contents_widget);
981                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
982
983                 /* Reparent the main paned */
984                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
985                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
986
987                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
988                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
989                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
990
991                 break;
992         default:
993                 g_return_if_reached ();
994         }
995
996         /* Let header view grab the focus if it's being shown */
997         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
998                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
999         else 
1000                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1001
1002         /* Show changes */
1003         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1004 }
1005
1006 ModestMainWindowStyle
1007 modest_main_window_get_style (ModestMainWindow *self)
1008 {
1009         ModestMainWindowPrivate *priv;
1010
1011         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1012
1013         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1014         return priv->style;
1015 }
1016
1017
1018
1019 static gboolean
1020 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1021 {
1022         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1023                 ModestWindowPrivate *parent_priv;
1024                 ModestWindowMgr *mgr;
1025                 gboolean is_fullscreen;
1026                 GtkAction *fs_toggle_action;
1027                 gboolean active;
1028                 
1029                 mgr = modest_runtime_get_window_mgr ();
1030                 
1031                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1032
1033                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1034                 
1035                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1036                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1037                 if (is_fullscreen != active) {
1038                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1039                 }
1040         }
1041
1042         return FALSE;
1043
1044 }
1045
1046 static void
1047 set_homogeneous (GtkWidget *widget,
1048                  gpointer data)
1049 {
1050         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1051         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1052 }
1053
1054 static void 
1055 modest_main_window_show_toolbar (ModestWindow *self,
1056                                  gboolean show_toolbar)
1057 {
1058         ModestMainWindowPrivate *priv = NULL;
1059         ModestWindowPrivate *parent_priv = NULL;        
1060         GtkWidget *reply_button = NULL, *menu = NULL;
1061         GtkWidget *placeholder = NULL;
1062         gint insert_index;
1063
1064         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1065         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1066         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1067
1068         /* Set optimized view status */
1069         priv->optimized_view = !show_toolbar;
1070
1071         if (!parent_priv->toolbar) {
1072                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1073                                                                   "/ToolBar");
1074
1075                 /* Set homogeneous toolbar */
1076                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1077                                        set_homogeneous, NULL);
1078         
1079                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1080                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1081                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1082                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1083                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1084                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1085                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1086                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1087
1088                 /* Add ProgressBar (Transfer toolbar) */ 
1089                 priv->progress_bar = modest_progress_bar_widget_new ();
1090                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1091                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1092                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1093                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1094                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1095                 
1096                 /* Connect cancel 'clicked' signal to abort progress mode */
1097                 g_signal_connect(priv->cancel_toolitem, "clicked",
1098                                  G_CALLBACK(cancel_progressbar),
1099                                  self);
1100                 
1101                 /* Add it to the observers list */
1102                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1103
1104                 /* Add to window */
1105                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1106                                            GTK_TOOLBAR (parent_priv->toolbar));
1107
1108                 /* Set reply button tap and hold menu */
1109                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1110                                                           "/ToolBar/ToolbarMessageReply");
1111                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1112                                                   "/ToolbarReplyCSM");
1113                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1114
1115                 /* Set send & receive button tap and hold menu */
1116                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1117                                    NULL, self);
1118         }
1119
1120         if (show_toolbar) {
1121                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1122                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1123                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1124
1125                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1126                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1127         } else
1128                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1129
1130 }
1131
1132 static gint
1133 compare_display_names (ModestAccountData *a,
1134                        ModestAccountData *b)
1135 {
1136         return strcmp (a->display_name, b->display_name);
1137 }
1138
1139 static void 
1140 on_account_update (TnyAccountStore *account_store, 
1141                    const gchar *account_name,
1142                    gpointer user_data)
1143 {
1144         GSList *account_names, *iter, *accounts;
1145         ModestMainWindow *self;
1146         ModestMainWindowPrivate *priv;
1147         ModestWindowPrivate *parent_priv;
1148         ModestAccountMgr *mgr;
1149         gint i, num_accounts;                                   
1150         GtkActionGroup *action_group;
1151         GList *groups;
1152         gchar *default_account;
1153         GtkWidget *send_receive_button, *item;
1154         GtkAction *send_receive_all = NULL;
1155                 
1156         self = MODEST_MAIN_WINDOW (user_data);
1157         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1158         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1159
1160         /* Get enabled account IDs */
1161         mgr = modest_runtime_get_account_mgr ();
1162         account_names = modest_account_mgr_account_names (mgr, TRUE);
1163         iter = account_names;
1164         accounts = NULL;
1165
1166         while (iter) {
1167                 ModestAccountData *account_data = 
1168                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1169                 accounts = g_slist_prepend (accounts, account_data);
1170
1171                 iter = iter->next;
1172         }
1173         modest_account_mgr_free_account_names (account_names);
1174         account_names = NULL;
1175
1176         /* Order the list of accounts by its display name */
1177         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1178         num_accounts = g_slist_length (accounts);
1179
1180         send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1181                                                       "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1182         gtk_action_set_visible (send_receive_all, num_accounts > 1);
1183
1184         /* Delete old send&receive popup items. We can not just do a
1185            menu_detach because it does not work well with
1186            tap_and_hold */
1187         if (priv->accounts_popup)
1188                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
1189                                        (GtkCallback) gtk_widget_destroy, NULL);
1190
1191         /* Delete old entries in the View menu. Do not free groups, it
1192            belongs to Gtk+ */
1193         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1194         while (groups) {
1195                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1196                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1197                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
1198                                                             GTK_ACTION_GROUP (groups->data));
1199                         groups = NULL;
1200                         /* Remove uis */
1201                         if (priv->merge_ids) {
1202                                 for (i = 0; i < priv->merge_ids->len; i++)
1203                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1204                                 g_byte_array_free (priv->merge_ids, TRUE);
1205                         }
1206                         /* We need to call this in order to ensure
1207                            that the new actions are added in the right
1208                            order (alphabetical */
1209                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1210                 } else 
1211                         groups = g_list_next (groups);
1212         }
1213         priv->merge_ids = g_byte_array_sized_new (num_accounts);
1214
1215         /* Get send receive button */
1216         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1217                                                           "/ToolBar/ToolbarSendReceive");
1218
1219         /* Create the menu */
1220         if (num_accounts > 1) {
1221                 if (!priv->accounts_popup)
1222                         priv->accounts_popup = gtk_menu_new ();
1223                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1224                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1225                 g_signal_connect (G_OBJECT (item), 
1226                                   "activate", 
1227                                   G_CALLBACK (on_send_receive_csm_activated),
1228                                   NULL);
1229                 item = gtk_separator_menu_item_new ();
1230                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1231         }
1232
1233         /* Create a new action group */
1234         default_account = modest_account_mgr_get_default_account (mgr);
1235         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1236         for (i = 0; i < num_accounts; i++) {
1237                 gchar *display_name = NULL;
1238                 
1239                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1240
1241                 /* Create display name. The default account is shown differently */
1242                 if (default_account && account_data->account_name && 
1243                         !(strcmp (default_account, account_data->account_name) == 0)) {
1244                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
1245                                                         account_data->display_name);
1246                 }
1247                 else {
1248                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
1249                                                         account_data->display_name);
1250                 }
1251
1252                 /* Create action and add it to the action group. The
1253                    action name must be the account name, this way we
1254                    could know in the handlers the account to show */
1255                 if(account_data->account_name) {
1256                         gchar* item_name, *refresh_action_name;
1257                         guint8 merge_id;
1258                         GtkAction *view_account_action, *refresh_account_action;
1259
1260                         view_account_action = gtk_action_new (account_data->account_name,
1261                                                               display_name, NULL, NULL);
1262                         gtk_action_group_add_action (action_group, view_account_action);
1263
1264                         /* Add ui from account data. We allow 2^9-1 account
1265                            changes in a single execution because we're
1266                            downcasting the guint to a guint8 in order to use a
1267                            GByteArray, it should be enough */
1268                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1269                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1270                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1271                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
1272                                                merge_id,
1273                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
1274                                                item_name,
1275                                                account_data->account_name,
1276                                                GTK_UI_MANAGER_MENUITEM,
1277                                                FALSE);
1278         
1279                         /* Connect the action signal "activate" */
1280                         g_signal_connect (G_OBJECT (view_account_action),
1281                                           "activate",
1282                                           G_CALLBACK (on_show_account_action_activated),
1283                                           self);
1284
1285                         /* Create the items for the Tools->Send&Receive submenu */
1286                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1287                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
1288                                                                  display_name, NULL, NULL);
1289                         gtk_action_group_add_action (action_group, refresh_account_action);
1290
1291                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1292                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1293                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
1294                                                merge_id,
1295                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1296                                                item_name,
1297                                                refresh_action_name,
1298                                                GTK_UI_MANAGER_MENUITEM,
1299                                                FALSE);
1300                         g_free (refresh_action_name);
1301
1302                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
1303                                                "activate", 
1304                                                G_CALLBACK (on_refresh_account_action_activated), 
1305                                                g_strdup (account_data->account_name),
1306                                                (GClosureNotify) g_free,
1307                                                0);
1308
1309                         /* Create item and add it to the send&receive
1310                            CSM. If there is only one account then
1311                            it'll be no menu */
1312                         if (priv->accounts_popup) {
1313                                 item = gtk_menu_item_new_with_label (display_name);
1314                                 gtk_menu_shell_prepend (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1315                                 g_signal_connect_data (G_OBJECT (item), 
1316                                                        "activate", 
1317                                                        G_CALLBACK (on_send_receive_csm_activated),
1318                                                        g_strdup (account_data->account_name),
1319                                                        (GClosureNotify) g_free,
1320                                                        0);
1321                         }
1322                         g_free (item_name);
1323                 }
1324
1325                 /* Frees */
1326                 g_free (display_name);
1327                 modest_account_mgr_free_account_data (mgr, account_data);
1328         }
1329         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1330
1331         if (priv->accounts_popup) {
1332                 /* Mandatory in order to view the menu contents */
1333                 gtk_widget_show_all (priv->accounts_popup);
1334
1335                 /* Setup tap_and_hold just if was not done before*/
1336                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1337                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1338         }
1339
1340         /* Frees */
1341         g_slist_free (accounts);
1342         g_free (default_account);
1343 }
1344
1345 /* 
1346  * This function manages the key events used to navigate between
1347  * header and folder views (when the window is in split view)
1348  *
1349  * FROM         KEY        ACTION
1350  * -------------------------------------------------
1351  * HeaderView   GDK_Left   Move focus to folder view
1352  * FolderView   GDK_Right  Move focus to header view
1353  *
1354  * There is no need to scroll to selected row, the widgets will be the
1355  * responsibles of doing that (probably managing the focus-in event
1356  */
1357 static gboolean 
1358 on_inner_widgets_key_pressed (GtkWidget *widget,
1359                               GdkEventKey *event,
1360                               gpointer user_data)
1361 {
1362         ModestMainWindowPrivate *priv;
1363
1364         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1365
1366         /* Do nothing if we're in SIMPLE style */
1367         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1368                 return FALSE;
1369
1370         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1371                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1372         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1373                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1374
1375         return FALSE;
1376 }
1377
1378 static void
1379 set_alignment (GtkWidget *widget,
1380                gpointer data)
1381 {
1382         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1383         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1384 }
1385
1386 static GtkWidget *
1387 create_empty_view (void)
1388 {
1389         GtkLabel *label = NULL;
1390         GtkWidget *align = NULL;
1391
1392         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1393         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1394         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1395         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1396
1397         return GTK_WIDGET(align);
1398 }
1399
1400 static GtkWidget *
1401 create_details_widget (GtkWidget *styled_widget, TnyAccount *account)
1402 {
1403         /* TODO: Clean up this function. It's a mess, with lots of copy/paste. murrayc. */
1404         
1405         GtkWidget *vbox;
1406         GtkWidget *label_w;
1407         gchar *label;
1408         gchar *gray_color_markup;
1409
1410         vbox = gtk_vbox_new (FALSE, 0);
1411
1412         /* Obtain the secondary text color. We need a realized widget, that's why 
1413            we get styled_widget from outside */
1414 #ifndef MODEST_HAVE_HILDON0_WIDGETS
1415         GdkColor color;
1416         gtk_style_lookup_color (styled_widget->style, "SecondaryTextColor", &color);
1417         gray_color_markup = modest_text_utils_get_color_string (&color);
1418 #else
1419         // gray_color_markup is freed below
1420         gray_color_markup = g_strdup ("#BBBBBB");
1421 #endif  
1422         /* Account description: */
1423         
1424         if (modest_tny_account_is_virtual_local_folders (account)
1425                 || (modest_tny_account_is_memory_card_account (account))) {
1426                 gchar *tmp;
1427                 /* Local folders: */
1428         
1429                 /* Get device name */
1430                 gchar *device_name = NULL;
1431                 if (modest_tny_account_is_virtual_local_folders (account))
1432                         device_name = modest_conf_get_string (modest_runtime_get_conf(),
1433                                                       MODEST_CONF_DEVICE_NAME, NULL);
1434                 else
1435                         device_name = g_strdup (tny_account_get_name (account));
1436                                                       
1437                 tmp = g_strdup_printf (_("mcen_fi_localroot_description"), ""); //TODO: Why the ""?
1438                 label = g_markup_printf_escaped ("<span color='%s'>%s</span>%s",
1439                                                  gray_color_markup, tmp, device_name);
1440                 g_free (tmp);
1441                 label_w = gtk_label_new (NULL);
1442                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1443                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1444                 g_free (device_name);
1445                 g_free (label);
1446         } else {
1447                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1448                         gtk_box_pack_start (GTK_BOX (vbox), 
1449                                 gtk_label_new (tny_account_get_name (account)), 
1450                                 FALSE, FALSE, 0);
1451                 } else {
1452                         /* Other accounts, such as IMAP and POP: */
1453                         
1454                         GString *proto;
1455                         gchar *tmp;
1456         
1457                         /* Put proto in uppercase */
1458                         proto = g_string_new (tny_account_get_proto (account));
1459                         proto = g_string_ascii_up (proto);
1460                         
1461                         /* note: mcen_fi_localroot_description is something like "%s account"
1462                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1463                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1464                         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1465                                                          gray_color_markup, tmp, tny_account_get_name (account));
1466                         g_free (tmp);
1467
1468                         label_w = gtk_label_new (NULL);
1469                         gtk_label_set_markup (GTK_LABEL (label_w), label);
1470                         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1471                         g_string_free (proto, TRUE);
1472                         g_free (label);
1473                 }
1474         }
1475
1476         /* Message count */
1477         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1478         label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1479                                          gray_color_markup, _("mcen_fi_rootfolder_messages"), 
1480                                          modest_tny_folder_store_get_message_count (folder_store));
1481         label_w = gtk_label_new (NULL);
1482         gtk_label_set_markup (GTK_LABEL (label_w), label);
1483         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1484         g_free (label);
1485
1486         /* Folder count */
1487         label = g_markup_printf_escaped ("<span color='%s'>%s</span>: %d", 
1488                                          gray_color_markup, 
1489                                          _("mcen_fi_rootfolder_folders"), 
1490                                          modest_tny_folder_store_get_folder_count (folder_store));
1491         label_w = gtk_label_new (NULL);
1492         gtk_label_set_markup (GTK_LABEL (label_w), label);
1493         gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1494         g_free (label);
1495
1496         /* Size / Date */
1497         if (modest_tny_account_is_virtual_local_folders (account)
1498                 || modest_tny_account_is_memory_card_account (account)) {
1499                 /* FIXME: format size */
1500                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %d", 
1501                                                  gray_color_markup, _("mcen_fi_rootfolder_size"), 
1502                                                  modest_tny_folder_store_get_local_size (folder_store));
1503                 label_w = gtk_label_new (NULL);
1504                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1505                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1506                 g_free (label);
1507         } else if (TNY_IS_ACCOUNT(folder_store)) {
1508                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1509                 
1510                 time_t last_updated;
1511                 gchar *last_updated_string;
1512                 /* Get last updated from configuration */
1513                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1514                                                           tny_account_get_id (account), 
1515                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1516                                                           TRUE);
1517                 if (last_updated > 0) 
1518                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1519                 else
1520                         last_updated_string = g_strdup (_("mcen_va_never"));
1521
1522                 label = g_markup_printf_escaped ("<span color='%s'>%s:</span> %s", 
1523                                                  gray_color_markup, _("mcen_ti_lastupdated"), last_updated_string);
1524                 label_w = gtk_label_new (NULL);
1525                 gtk_label_set_markup (GTK_LABEL (label_w), label);
1526                 gtk_box_pack_start (GTK_BOX (vbox), label_w, FALSE, FALSE, 0);
1527                 g_free (last_updated_string);
1528                 g_free (label);
1529         }
1530
1531         g_free (gray_color_markup);
1532
1533         /* Set alignment */
1534         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1535
1536         return vbox;
1537 }
1538
1539 void 
1540 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1541 {
1542         GtkAction *action = NULL;
1543         GtkWidget *widget = NULL;
1544
1545         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1546
1547         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1548         gtk_action_set_sensitive (action, FALSE);
1549 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1550 /*      gtk_action_set_sensitive (action, FALSE); */
1551         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1552         gtk_widget_set_sensitive (widget, FALSE);
1553
1554
1555 void 
1556 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1557 {
1558         GtkAction *action = NULL;
1559         GtkWidget *widget = NULL;
1560
1561         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1562
1563         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1564         gtk_action_set_sensitive (action, TRUE);
1565 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1566 /*      gtk_action_set_sensitive (action, TRUE); */
1567         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1568         gtk_widget_set_sensitive (widget, TRUE);
1569
1570
1571
1572 static void
1573 _on_msg_count_changed (ModestHeaderView *header_view,
1574                        TnyFolder *folder,
1575                        TnyFolderChange *change,
1576                        ModestMainWindow *main_window)
1577 {
1578         printf ("DEBUG: %s\n", __FUNCTION__);
1579         gboolean folder_empty = FALSE;
1580         TnyFolderChangeChanged changed;
1581         
1582         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1583         g_return_if_fail (TNY_IS_FOLDER(folder));
1584         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1585         
1586         changed = tny_folder_change_get_changed (change);
1587         
1588         /* If something changes */
1589         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1590                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1591         else
1592                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1593         
1594         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1595
1596         /* Set contents style of headers view */
1597         if (folder_empty)  {
1598                 modest_main_window_set_contents_style (main_window,
1599                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1600         }
1601         else {
1602                 modest_main_window_set_contents_style (main_window,
1603                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1604         }       
1605 }
1606
1607 void 
1608 modest_main_window_set_contents_style (ModestMainWindow *self, 
1609                                        ModestMainWindowContentsStyle style)
1610 {
1611         ModestMainWindowPrivate *priv;
1612
1613         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1614
1615         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1616
1617         /* We allow to set the same content style than the previously
1618            set if there are details, because it could happen when we're
1619            selecting different accounts consecutively */
1620         if ((priv->contents_style == style) &&
1621             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1622                 return;
1623
1624         /* Remove previous child. Delete it if it was an account
1625            details widget */
1626         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1627         if (content) {
1628                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1629                         g_object_ref (content);
1630                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1631                         g_object_ref (priv->empty_view);
1632                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1633                 }
1634                 
1635                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1636         }
1637
1638         priv->contents_style = style;
1639
1640         switch (priv->contents_style) {
1641         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1642                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1643                 break;
1644         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1645         {
1646                 TnyFolderStore *selected_folderstore = 
1647                         modest_folder_view_get_selected (priv->folder_view);
1648                 if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1649                   priv->details_widget = create_details_widget (GTK_WIDGET (self),
1650                                                                 TNY_ACCOUNT (selected_folderstore));
1651
1652                         wrap_in_scrolled_window (priv->contents_widget, 
1653                                          priv->details_widget);
1654                 }
1655                 g_object_unref (selected_folderstore);
1656                 break;
1657         }
1658         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1659                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1660                 break;
1661         default:
1662                 g_return_if_reached ();
1663         }
1664
1665         /* Show */
1666         gtk_widget_show_all (priv->contents_widget);
1667 }
1668
1669 ModestMainWindowContentsStyle
1670 modest_main_window_get_contents_style (ModestMainWindow *self)
1671 {
1672         ModestMainWindowPrivate *priv;
1673
1674         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1675
1676         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1677         return priv->contents_style;
1678 }
1679
1680
1681 static void 
1682 on_configuration_key_changed (ModestConf* conf, 
1683                               const gchar *key, 
1684                               ModestConfEvent event, 
1685                               ModestMainWindow *self)
1686 {
1687         ModestMainWindowPrivate *priv;
1688         TnyAccount *account;
1689
1690         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1691                 return;
1692
1693         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1694
1695         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1696                 return;
1697
1698         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1699         if (TNY_IS_ACCOUNT (account) &&
1700             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1701                 GList *children;
1702                 GtkLabel *label;
1703                 const gchar *device_name;
1704                 gchar *new_text;
1705                 
1706                 /* Get label */
1707                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1708                 label = GTK_LABEL (children->data);
1709                 
1710                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1711                                                       MODEST_CONF_DEVICE_NAME, NULL);
1712                 
1713                 new_text = g_strdup_printf ("%s: %s",
1714                                             _("mcen_fi_localroot_description"),
1715                                             device_name);
1716                 
1717                 gtk_label_set_text (label, new_text);
1718                 gtk_widget_show (GTK_WIDGET (label));
1719                 
1720                 g_free (new_text);
1721                 g_list_free (children);
1722         }
1723         g_object_unref (account);
1724 }
1725
1726 static gboolean
1727 set_toolbar_transfer_mode (ModestMainWindow *self)
1728 {
1729         ModestMainWindowPrivate *priv = NULL;
1730         
1731         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1732
1733         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1734
1735         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1736         
1737         if (priv->progress_bar_timeout > 0) {
1738                 g_source_remove (priv->progress_bar_timeout);
1739                 priv->progress_bar_timeout = 0;
1740         }
1741
1742         return FALSE;
1743 }
1744
1745 static void 
1746 set_toolbar_mode (ModestMainWindow *self, 
1747                   ModestToolBarModes mode)
1748 {
1749         ModestWindowPrivate *parent_priv = NULL;
1750         ModestMainWindowPrivate *priv = NULL;
1751         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1752         
1753         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1754
1755         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1756         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1757
1758         /* In case this was called before the toolbar exists: */
1759         if (!(parent_priv->toolbar))
1760                 return;
1761
1762         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1763         
1764         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1765         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1766         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1767
1768         /* Sets current toolbar mode */
1769         priv->current_toolbar_mode = mode;
1770
1771         /* Show and hide toolbar items */
1772         switch (mode) {
1773         case TOOLBAR_MODE_NORMAL:
1774 /*              if (sort_action)  */
1775 /*                      gtk_action_set_visible (sort_action, TRUE); */
1776 /*              if (refresh_action)  */
1777 /*                      gtk_action_set_visible (refresh_action, TRUE); */
1778 /*              if (priv->progress_toolitem) { */
1779 /*                      gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE); */
1780 /*                      gtk_widget_hide (priv->progress_toolitem); */
1781 /*              } */
1782 /*              if (priv->progress_bar) */
1783 /*                      gtk_widget_hide (priv->progress_bar); */
1784                 
1785 /*              if (cancel_action) */
1786 /*                      gtk_action_set_visible (cancel_action, FALSE); */
1787                 if (priv->sort_toolitem)
1788                         gtk_widget_show (priv->sort_toolitem);
1789                 
1790                 if (priv->refresh_toolitem)
1791                         gtk_widget_show (priv->refresh_toolitem);
1792                         
1793                 if (priv->progress_toolitem)
1794                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1795                 if (priv->progress_bar)
1796                         gtk_widget_hide (priv->progress_bar);
1797                         
1798                 if (priv->cancel_toolitem)
1799                         gtk_widget_hide (priv->cancel_toolitem);
1800
1801                 /* Hide toolbar if optimized view is enabled */
1802                 if (priv->optimized_view)
1803                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1804                 break;
1805         case TOOLBAR_MODE_TRANSFER:
1806 /*              if (sort_action) */
1807 /*                      gtk_action_set_visible (sort_action, FALSE); */
1808 /*              if (refresh_action) */
1809 /*                      gtk_action_set_visible (refresh_action, FALSE); */
1810 /*              if (cancel_action) */
1811 /*                      gtk_action_set_visible (cancel_action, TRUE); */
1812 /*              if (priv->progress_toolitem) { */
1813 /*                      gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE); */
1814 /*                      gtk_widget_show (priv->progress_toolitem); */
1815 /*              } */
1816 /*              if (priv->progress_bar) */
1817 /*                      gtk_widget_show (priv->progress_bar); */
1818
1819                 if (priv->sort_toolitem)
1820                         gtk_widget_hide (priv->sort_toolitem);
1821                 
1822                 if (priv->refresh_toolitem)
1823                         gtk_widget_hide (priv->refresh_toolitem);
1824                 
1825                 if (priv->progress_toolitem)
1826                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1827                 if (priv->progress_bar)
1828                         gtk_widget_show (priv->progress_bar);
1829                         
1830                 if (priv->cancel_toolitem)
1831                         gtk_widget_show (priv->cancel_toolitem);
1832
1833                 /* Show toolbar if it's hiden (optimized view ) */
1834                 if (priv->optimized_view)
1835                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1836                 break;
1837         default:
1838                 g_return_if_reached ();
1839         }
1840 }
1841
1842 static void
1843 cancel_progressbar (GtkToolButton *toolbutton,
1844                     ModestMainWindow *self)
1845 {
1846         GSList *tmp;
1847         ModestMainWindowPrivate *priv;
1848         
1849         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1850
1851         /* Get operation observers and cancel its current operation */
1852         tmp = priv->progress_widgets;
1853         while (tmp) {
1854                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1855                 tmp=g_slist_next(tmp);
1856         }
1857 }
1858
1859 static gboolean
1860 observers_empty (ModestMainWindow *self)
1861 {
1862         GSList *tmp = NULL;
1863         ModestMainWindowPrivate *priv;
1864         gboolean is_empty = TRUE;
1865         guint pending_ops = 0;
1866  
1867         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1868         tmp = priv->progress_widgets;
1869
1870         /* Check all observers */
1871         while (tmp && is_empty)  {
1872                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1873                 is_empty = pending_ops == 0;
1874                 
1875                 tmp = g_slist_next(tmp);
1876         }
1877         
1878         return is_empty;
1879 }
1880
1881 static void
1882 on_queue_changed (ModestMailOperationQueue *queue,
1883                   ModestMailOperation *mail_op,
1884                   ModestMailOperationQueueNotification type,
1885                   ModestMainWindow *self)
1886 {
1887         ModestMainWindowPrivate *priv;
1888         ModestMailOperationTypeOperation op_type;
1889         ModestToolBarModes mode;
1890         GSList *tmp;
1891         gboolean mode_changed = FALSE;
1892 /*      ModestMailOperationStatus status; */
1893
1894         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1895         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1896                
1897         /* Get toolbar mode from operation id*/
1898         op_type = modest_mail_operation_get_type_operation (mail_op);
1899         switch (op_type) {
1900         case MODEST_MAIL_OPERATION_TYPE_SEND:
1901         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1902         case MODEST_MAIL_OPERATION_TYPE_OPEN:
1903                 mode = TOOLBAR_MODE_TRANSFER;
1904                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1905                         mode_changed = TRUE;
1906                 break;
1907         default:
1908                 mode = TOOLBAR_MODE_NORMAL;
1909                 
1910         }
1911                 
1912                        
1913         /* Add operation observers and change toolbar if neccessary*/
1914         tmp = priv->progress_widgets;
1915         switch (type) {
1916         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1917                 if (mode == TOOLBAR_MODE_TRANSFER) {
1918                         if (mode_changed)
1919                                 set_toolbar_transfer_mode(self);                    
1920                         while (tmp) {
1921                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1922                                                                       mail_op);
1923                                 tmp = g_slist_next (tmp);
1924                         }
1925                 }
1926                 break;
1927         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1928                 /* Change toolbar mode */
1929                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1930                         while (tmp) {
1931                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1932                                                                          mail_op);
1933                                 tmp = g_slist_next (tmp);
1934                         }
1935                         
1936                         /* If no more operations are being observed, NORMAL mode is enabled again */
1937                         if (observers_empty (self)) {
1938                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1939                                 
1940                         }
1941                 }
1942
1943                 break;
1944         }       
1945
1946 }
1947
1948 static void 
1949 on_show_account_action_activated  (GtkAction *action,
1950                                    gpointer user_data)
1951 {
1952         ModestAccountData *acc_data;
1953         ModestMainWindow *self;
1954         ModestMainWindowPrivate *priv;
1955         ModestAccountMgr *mgr;
1956         const gchar *acc_name;
1957
1958         self = MODEST_MAIN_WINDOW (user_data);
1959         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1960
1961         /* Get account data */
1962         acc_name = gtk_action_get_name (action);
1963         mgr = modest_runtime_get_account_mgr ();
1964         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1965
1966         /* Set the new visible & active account */
1967         if (acc_data->store_account) { 
1968                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1969                                                                              acc_data->store_account->account_name);
1970                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1971         }
1972
1973         /* Free */
1974         modest_account_mgr_free_account_data (mgr, acc_data);
1975 }
1976
1977 static void
1978 refresh_account (const gchar *account_name)
1979 {
1980         ModestWindow *win;
1981
1982         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1983
1984         /* If account_name == NULL, we must update all (option All) */
1985         if (!account_name)
1986                 modest_ui_actions_do_send_receive_all (win);
1987         else
1988                 modest_ui_actions_do_send_receive (account_name, win);
1989         
1990 }
1991
1992 static void 
1993 on_refresh_account_action_activated  (GtkAction *action,
1994                                       gpointer user_data)
1995 {
1996         refresh_account ((const gchar*) user_data);
1997 }
1998
1999 static void
2000 on_send_receive_csm_activated (GtkMenuItem *item,
2001                                gpointer user_data)
2002 {
2003         refresh_account ((const gchar*) user_data);
2004 }
2005
2006 static gboolean
2007 on_zoom_minus_plus_not_implemented (ModestWindow *window)
2008 {
2009         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
2010
2011         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
2012         return FALSE;
2013
2014 }