* src/maemo/modest-msg-edit-window.c:
[modest] / src / maemo / modest-main-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
34 #include <tny-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_HILDON_VERSION_0
63 #include <hildon-widgets/hildon-program.h>
64 #else
65 #include <hildon/hildon-program.h>
66 #endif /*MODEST_HILDON_VERSION_0*/
67
68 #define MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS "ModestMainWindowActionAdditions"
69
70 #define XALIGN 0.5
71 #define YALIGN 0.5
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         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
641         
642         /* Mail Operation Queue */
643         priv->queue_changed_handler_uid = 
644                 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
645                                   "queue-changed", G_CALLBACK (on_queue_changed), self);
646
647         /* Track changes in the device name */
648         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
649                           "key_changed", G_CALLBACK (on_configuration_key_changed), 
650                           self);
651
652         /* Track account changes. We need to refresh the toolbar */
653         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
654                           "account_update", G_CALLBACK (on_account_update),
655                           self);
656
657         /* Account store */
658         g_signal_connect (G_OBJECT (modest_runtime_get_account_store()), 
659                           "password_requested",
660                           G_CALLBACK (modest_ui_actions_on_password_requested), self);
661                           
662         /* Device */
663         g_signal_connect (G_OBJECT(modest_runtime_get_account_store()), 
664                           "connecting-finished",
665                           G_CALLBACK(on_account_store_connecting_finished), self);
666 }
667
668 #if 0
669 /** Idle handler, to send/receive at startup .*/
670 gboolean
671 sync_accounts_cb (ModestMainWindow *win)
672 {
673         modest_ui_actions_do_send_receive (NULL, MODEST_WINDOW (win));
674         return FALSE; /* Do not call this idle handler again. */
675 }
676 #endif
677
678 static void on_hildon_program_is_topmost_notify(GObject *self,
679         GParamSpec *propert_param, gpointer user_data)
680 {
681         HildonProgram *app = HILDON_PROGRAM (self);
682         
683         /*
684         ModestWindow* self = MODEST_WINDOW(user_data);
685         */
686         
687         /* Note that use of hildon_program_set_can_hibernate() 
688          * is generally referred to as "setting the killable flag", 
689          * though hibernation does not seem equal to death.
690          * murrayc */
691                  
692         if (hildon_program_get_is_topmost (app)) {
693                 /* Prevent hibernation when the progam comes to the foreground,
694                  * because hibernation should only happen when the application 
695                  * is in the background: */
696                 hildon_program_set_can_hibernate (app, FALSE);
697         } else {
698                 /* Allow hibernation if the program has gone to the background: */
699                 
700                 /* However, prevent hibernation while the settings are being changed: */
701                 const gboolean hibernation_prevented = 
702                         modest_window_mgr_get_hibernation_is_prevented (
703         modest_runtime_get_window_mgr ()); 
704         
705                 if (hibernation_prevented)
706                         hildon_program_set_can_hibernate (app, FALSE);
707                 else {
708                         /* Allow hibernation, after saving the state: */
709                         modest_osso_save_state();
710                         hildon_program_set_can_hibernate (app, TRUE);
711                 }
712         }
713         
714 }
715
716 static void
717 modest_main_window_on_show (GtkWidget *self, gpointer user_data)
718 {
719         GtkWidget *folder_win = (GtkWidget *) user_data;
720         ModestMainWindowPrivate *priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
721         
722         priv->folder_view = MODEST_FOLDER_VIEW (modest_platform_create_folder_view (NULL));
723         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
724 /*      wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view)); */
725
726         gtk_widget_show (GTK_WIDGET (priv->folder_view));
727
728         /* Connect signals */
729         connect_signals ((ModestMainWindow*)self);
730
731         /* Set account store */
732         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
733                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
734
735         /* Load previous osso state, for instance if we are being restored from 
736          * hibernation:  */
737         modest_osso_load_state ();
738
739         /* Restore window & widget settings */
740         
741         restore_settings (MODEST_MAIN_WINDOW(self), TRUE);
742
743         /* Check if accounts exist and show the account wizard if not */
744         gboolean accounts_exist = 
745                 modest_account_mgr_has_accounts(modest_runtime_get_account_mgr(), TRUE);
746
747         if (!accounts_exist) {
748                 /* This is necessary to have the main window shown behind the dialog 
749                 It's an ugly hack... jschmid */
750                 gtk_widget_show_all(GTK_WIDGET(self));
751                 modest_ui_actions_on_accounts (NULL, MODEST_WINDOW(self));
752         } else {
753                 GSList *accounts;
754                 GtkAction *send_receive_all;
755                 ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
756                 accounts = modest_account_mgr_account_names (modest_runtime_get_account_mgr (), TRUE);
757                 send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
758                                                               "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
759                 gtk_action_set_visible (send_receive_all, g_slist_length (accounts));
760                 modest_account_mgr_free_account_names (accounts);
761         }
762
763
764 }
765
766 ModestWindow *
767 modest_main_window_new (void)
768 {
769         ModestMainWindow *self = NULL;  
770         ModestMainWindowPrivate *priv = NULL;
771         ModestWindowPrivate *parent_priv = NULL;
772         GtkWidget *folder_win = NULL;
773         ModestDimmingRulesGroup *menu_rules_group = NULL;
774         ModestDimmingRulesGroup *toolbar_rules_group = NULL;
775         GtkActionGroup *action_group = NULL;
776         GError *error = NULL;
777         GdkPixbuf *window_icon = NULL; 
778         ModestConf *conf = NULL;
779         GtkAction *action = NULL;
780
781         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
782         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
783         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
784
785         parent_priv->ui_manager = gtk_ui_manager_new();
786         parent_priv->ui_dimming_manager = modest_ui_dimming_manager_new();
787
788         action_group = gtk_action_group_new ("ModestMainWindowActions");
789         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
790
791         menu_rules_group = modest_dimming_rules_group_new ("ModestMenuDimmingRules");
792         toolbar_rules_group = modest_dimming_rules_group_new ("ModestToolbarDimmingRules");
793
794         /* Add common actions */
795         gtk_action_group_add_actions (action_group,
796                                       modest_action_entries,
797                                       G_N_ELEMENTS (modest_action_entries),
798                                       self);
799
800         gtk_action_group_add_actions (action_group,
801                                       modest_folder_view_action_entries,
802                                       G_N_ELEMENTS (modest_folder_view_action_entries),
803                                       self);
804
805         gtk_action_group_add_actions (action_group,
806                                       modest_header_view_action_entries,
807                                       G_N_ELEMENTS (modest_header_view_action_entries),
808                                       self);
809
810         gtk_action_group_add_toggle_actions (action_group,
811                                              modest_toggle_action_entries,
812                                              G_N_ELEMENTS (modest_toggle_action_entries),
813                                              self);
814
815         gtk_action_group_add_toggle_actions (action_group,
816                                              modest_main_window_toggle_action_entries,
817                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
818                                              self);
819
820         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
821         g_object_unref (action_group);
822
823         /* Load the UI definition */
824         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
825                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
826         if (error != NULL) {
827                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
828                 g_error_free (error);
829                 error = NULL;
830         }
831
832         /* Add common dimming rules */
833         modest_dimming_rules_group_add_rules (menu_rules_group, 
834                                               modest_main_window_menu_dimming_entries,
835                                               G_N_ELEMENTS (modest_main_window_menu_dimming_entries),
836                                               self);
837         modest_dimming_rules_group_add_rules (toolbar_rules_group, 
838                                               modest_main_window_toolbar_dimming_entries,
839                                               G_N_ELEMENTS (modest_main_window_toolbar_dimming_entries),
840                                               self);
841
842         /* Insert dimming rules group for this window */
843         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, menu_rules_group);
844         modest_ui_dimming_manager_insert_rules_group (parent_priv->ui_dimming_manager, toolbar_rules_group);
845         g_object_unref (menu_rules_group);
846         g_object_unref (toolbar_rules_group);
847         
848         /* Add accelerators */
849         gtk_window_add_accel_group (GTK_WINDOW (self), 
850                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
851
852         /* Menubar. Update the state of some toggles */
853         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
854         conf = modest_runtime_get_conf ();
855         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
856                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
857         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
858                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
859         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
860                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
861         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
862                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
863         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
864
865         /* Get device name */
866         modest_maemo_utils_get_device_name ();
867
868         /* header view */
869         priv->header_view =
870                 MODEST_HEADER_VIEW (modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
871         if (!priv->header_view)
872                 g_printerr ("modest: cannot instantiate header view\n");
873         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
874         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(priv->header_view),
875                                       MODEST_CONF_HEADER_VIEW_KEY);
876
877         /* Empty view */ 
878         priv->empty_view = create_empty_view ();
879                  
880         /* Create scrolled windows */
881         folder_win = gtk_scrolled_window_new (NULL, NULL);
882         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
883         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
884                                         GTK_POLICY_NEVER,
885                                         GTK_POLICY_AUTOMATIC);
886         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
887                                         GTK_POLICY_NEVER,
888                                         GTK_POLICY_AUTOMATIC);
889
890         /* paned */
891         priv->main_paned = gtk_hpaned_new ();
892         gtk_paned_pack1 (GTK_PANED(priv->main_paned), folder_win, TRUE, TRUE);
893         gtk_paned_pack2 (GTK_PANED(priv->main_paned), priv->contents_widget, TRUE, TRUE);
894         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
895
896         /* putting it all together... */
897         priv->main_vbox = gtk_vbox_new (FALSE, 6);
898         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
899
900         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
901
902         /* Set window icon */
903         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
904         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
905         
906         HildonProgram *app = hildon_program_get_instance ();
907         hildon_program_add_window (app, HILDON_WINDOW (self));
908         
909         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
910                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
911
912         g_signal_connect (G_OBJECT(self), "show",
913                           G_CALLBACK (modest_main_window_on_show), folder_win);
914                 
915
916         restore_settings (MODEST_MAIN_WINDOW(self), FALSE);
917
918         return MODEST_WINDOW(self);
919 }
920
921 gboolean 
922 modest_main_window_close_all (ModestMainWindow *self)
923 {
924         GtkWidget *note;
925         GtkResponseType response;
926
927         /* Create the confirmation dialog MSG-NOT308 */
928         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
929                                                          _("emev_nc_close_windows"),
930                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
931                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
932                                                          NULL);
933
934         response = gtk_dialog_run (GTK_DIALOG (note));
935         gtk_widget_destroy (GTK_WIDGET (note));
936
937         if (response == GTK_RESPONSE_YES)
938                 return TRUE;
939         else
940                 return FALSE;
941 }
942
943
944 void 
945 modest_main_window_set_style (ModestMainWindow *self, 
946                               ModestMainWindowStyle style)
947 {
948         ModestMainWindowPrivate *priv;
949         ModestWindowPrivate *parent_priv;
950         GtkAction *action;
951
952         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
953
954         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
955         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
956
957         /* no change -> nothing to do */
958         if (priv->style == style)
959                 return;
960
961         /* Get toggle button */
962         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
963
964         priv->style = style;
965         switch (style) {
966         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
967                 /* Remove main paned */
968                 g_object_ref (priv->main_paned);
969                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
970
971                 /* Reparent the contents widget to the main vbox */
972                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
973
974                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
975                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
976                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
977
978                 break;
979         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
980                 /* Remove header view */
981                 g_object_ref (priv->contents_widget);
982                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
983
984                 /* Reparent the main paned */
985                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
986                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
987
988                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
989                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
990                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
991
992                 break;
993         default:
994                 g_return_if_reached ();
995         }
996
997         /* Let header view grab the focus if it's being shown */
998         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
999                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1000         else 
1001                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
1002
1003         /* Show changes */
1004         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
1005 }
1006
1007 ModestMainWindowStyle
1008 modest_main_window_get_style (ModestMainWindow *self)
1009 {
1010         ModestMainWindowPrivate *priv;
1011
1012         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1013
1014         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1015         return priv->style;
1016 }
1017
1018
1019
1020 static gboolean
1021 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
1022 {
1023         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1024                 ModestWindowPrivate *parent_priv;
1025                 ModestWindowMgr *mgr;
1026                 gboolean is_fullscreen;
1027                 GtkAction *fs_toggle_action;
1028                 gboolean active;
1029                 
1030                 mgr = modest_runtime_get_window_mgr ();
1031                 
1032                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
1033
1034                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
1035                 
1036                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
1037                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
1038                 if (is_fullscreen != active) {
1039                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
1040                 }
1041         }
1042
1043         return FALSE;
1044
1045 }
1046
1047 static void
1048 set_homogeneous (GtkWidget *widget,
1049                  gpointer data)
1050 {
1051         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
1052         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
1053 }
1054
1055 static void 
1056 modest_main_window_show_toolbar (ModestWindow *self,
1057                                  gboolean show_toolbar)
1058 {
1059         ModestMainWindowPrivate *priv = NULL;
1060         ModestWindowPrivate *parent_priv = NULL;        
1061         GtkWidget *reply_button = NULL, *menu = NULL;
1062         GtkWidget *placeholder = NULL;
1063         gint insert_index;
1064
1065         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1066         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1067         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1068
1069         /* Set optimized view status */
1070         priv->optimized_view = !show_toolbar;
1071
1072         if (!parent_priv->toolbar) {
1073                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1074                                                                   "/ToolBar");
1075
1076                 /* Set homogeneous toolbar */
1077                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
1078                                        set_homogeneous, NULL);
1079         
1080                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
1081                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1082                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1083                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1084                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1085                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1086                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1087                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
1088
1089                 /* Add ProgressBar (Transfer toolbar) */ 
1090                 priv->progress_bar = modest_progress_bar_widget_new ();
1091                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
1092                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
1093                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
1094                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
1095                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
1096                 
1097                 /* Connect cancel 'clicked' signal to abort progress mode */
1098                 g_signal_connect(priv->cancel_toolitem, "clicked",
1099                                  G_CALLBACK(cancel_progressbar),
1100                                  self);
1101                 
1102                 /* Add it to the observers list */
1103                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
1104
1105                 /* Add to window */
1106                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
1107                                            GTK_TOOLBAR (parent_priv->toolbar));
1108
1109                 /* Set reply button tap and hold menu */
1110                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
1111                                                           "/ToolBar/ToolbarMessageReply");
1112                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1113                                                   "/ToolbarReplyCSM");
1114                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
1115
1116                 /* Set send & receive button tap and hold menu */
1117                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
1118                                    NULL, self);
1119         }
1120
1121         if (show_toolbar) {
1122                 /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */ 
1123                 /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
1124                 gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
1125
1126                 gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1127                 set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
1128         } else
1129                 gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
1130
1131 }
1132
1133 static gint
1134 compare_display_names (ModestAccountData *a,
1135                        ModestAccountData *b)
1136 {
1137         return strcmp (a->display_name, b->display_name);
1138 }
1139
1140 static void 
1141 on_account_update (TnyAccountStore *account_store, 
1142                    const gchar *account_name,
1143                    gpointer user_data)
1144 {
1145         GSList *account_names, *iter, *accounts;
1146         ModestMainWindow *self;
1147         ModestMainWindowPrivate *priv;
1148         ModestWindowPrivate *parent_priv;
1149         ModestAccountMgr *mgr;
1150         gint i, num_accounts;                                   
1151         GtkActionGroup *action_group;
1152         GList *groups;
1153         gchar *default_account;
1154         GtkWidget *send_receive_button, *item;
1155         GtkAction *send_receive_all = NULL;
1156                 
1157         self = MODEST_MAIN_WINDOW (user_data);
1158         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
1159         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
1160
1161         /* Get enabled account IDs */
1162         mgr = modest_runtime_get_account_mgr ();
1163         account_names = modest_account_mgr_account_names (mgr, TRUE);
1164         iter = account_names;
1165         accounts = NULL;
1166
1167         while (iter) {
1168                 ModestAccountData *account_data = 
1169                         modest_account_mgr_get_account_data (mgr, (gchar*) iter->data);
1170                 accounts = g_slist_prepend (accounts, account_data);
1171
1172                 iter = iter->next;
1173         }
1174         modest_account_mgr_free_account_names (account_names);
1175         account_names = NULL;
1176
1177         /* Order the list of accounts by its display name */
1178         accounts = g_slist_sort (accounts, (GCompareFunc) compare_display_names);
1179         num_accounts = g_slist_length (accounts);
1180
1181         send_receive_all = gtk_ui_manager_get_action (parent_priv->ui_manager, 
1182                                                       "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu");
1183         gtk_action_set_visible (send_receive_all, num_accounts > 1);
1184
1185         /* Delete old send&receive popup items. We can not just do a
1186            menu_detach because it does not work well with
1187            tap_and_hold */
1188         if (priv->accounts_popup)
1189                 gtk_container_foreach (GTK_CONTAINER (priv->accounts_popup), 
1190                                        (GtkCallback) gtk_widget_destroy, NULL);
1191
1192         /* Delete old entries in the View menu. Do not free groups, it
1193            belongs to Gtk+ */
1194         groups = gtk_ui_manager_get_action_groups (parent_priv->ui_manager);
1195         while (groups) {
1196                 if (!strcmp (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS,
1197                              gtk_action_group_get_name (GTK_ACTION_GROUP (groups->data)))) {
1198                         gtk_ui_manager_remove_action_group (parent_priv->ui_manager, 
1199                                                             GTK_ACTION_GROUP (groups->data));
1200                         groups = NULL;
1201                         /* Remove uis */
1202                         if (priv->merge_ids) {
1203                                 for (i = 0; i < priv->merge_ids->len; i++)
1204                                         gtk_ui_manager_remove_ui (parent_priv->ui_manager, priv->merge_ids->data[i]);
1205                                 g_byte_array_free (priv->merge_ids, TRUE);
1206                         }
1207                         /* We need to call this in order to ensure
1208                            that the new actions are added in the right
1209                            order (alphabetical */
1210                         gtk_ui_manager_ensure_update (parent_priv->ui_manager);
1211                 } else 
1212                         groups = g_list_next (groups);
1213         }
1214         priv->merge_ids = g_byte_array_sized_new (num_accounts);
1215
1216         /* Get send receive button */
1217         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager,
1218                                                           "/ToolBar/ToolbarSendReceive");
1219
1220         /* Create the menu */
1221         if (num_accounts > 1) {
1222                 if (!priv->accounts_popup)
1223                         priv->accounts_popup = gtk_menu_new ();
1224                 item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
1225                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1226                 g_signal_connect (G_OBJECT (item), 
1227                                   "activate", 
1228                                   G_CALLBACK (on_send_receive_csm_activated),
1229                                   NULL);
1230                 item = gtk_separator_menu_item_new ();
1231                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1232         }
1233
1234         /* Create a new action group */
1235         default_account = modest_account_mgr_get_default_account (mgr);
1236         action_group = gtk_action_group_new (MODEST_MAIN_WINDOW_ACTION_GROUP_ADDITIONS);
1237         for (i = 0; i < num_accounts; i++) {
1238                 gchar *display_name = NULL;
1239                 
1240                 ModestAccountData *account_data = (ModestAccountData *) g_slist_nth_data (accounts, i);
1241
1242                 /* Create display name. The default account is shown differently */
1243                 if (default_account && account_data->account_name && 
1244                         !(strcmp (default_account, account_data->account_name) == 0)) {
1245                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), 
1246                                                         account_data->display_name);
1247                 }
1248                 else {
1249                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), 
1250                                                         account_data->display_name);
1251                 }
1252
1253                 /* Create action and add it to the action group. The
1254                    action name must be the account name, this way we
1255                    could know in the handlers the account to show */
1256                 if(account_data->account_name) {
1257                         gchar* item_name, *refresh_action_name;
1258                         guint8 merge_id;
1259                         GtkAction *view_account_action, *refresh_account_action;
1260
1261                         view_account_action = gtk_action_new (account_data->account_name,
1262                                                               display_name, NULL, NULL);
1263                         gtk_action_group_add_action (action_group, view_account_action);
1264
1265                         /* Add ui from account data. We allow 2^9-1 account
1266                            changes in a single execution because we're
1267                            downcasting the guint to a guint8 in order to use a
1268                            GByteArray, it should be enough */
1269                         item_name = g_strconcat (account_data->account_name, "Menu", NULL);
1270                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1271                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1272                         gtk_ui_manager_add_ui (parent_priv->ui_manager,
1273                                                merge_id,
1274                                                "/MenuBar/ViewMenu/ViewMenuAdditions",
1275                                                item_name,
1276                                                account_data->account_name,
1277                                                GTK_UI_MANAGER_MENUITEM,
1278                                                FALSE);
1279         
1280                         /* Connect the action signal "activate" */
1281                         g_signal_connect (G_OBJECT (view_account_action),
1282                                           "activate",
1283                                           G_CALLBACK (on_show_account_action_activated),
1284                                           self);
1285
1286                         /* Create the items for the Tools->Send&Receive submenu */
1287                         refresh_action_name = g_strconcat ("SendReceive", account_data->account_name, NULL);
1288                         refresh_account_action = gtk_action_new ((const gchar*) refresh_action_name, 
1289                                                                  display_name, NULL, NULL);
1290                         gtk_action_group_add_action (action_group, refresh_account_action);
1291
1292                         merge_id = (guint8) gtk_ui_manager_new_merge_id (parent_priv->ui_manager);
1293                         priv->merge_ids = g_byte_array_append (priv->merge_ids, &merge_id, 1);
1294                         gtk_ui_manager_add_ui (parent_priv->ui_manager, 
1295                                                merge_id,
1296                                                "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions",
1297                                                item_name,
1298                                                refresh_action_name,
1299                                                GTK_UI_MANAGER_MENUITEM,
1300                                                FALSE);
1301                         g_free (refresh_action_name);
1302
1303                         g_signal_connect_data (G_OBJECT (refresh_account_action), 
1304                                                "activate", 
1305                                                G_CALLBACK (on_refresh_account_action_activated), 
1306                                                g_strdup (account_data->account_name),
1307                                                (GClosureNotify) g_free,
1308                                                0);
1309
1310                         /* Create item and add it to the send&receive
1311                            CSM. If there is only one account then
1312                            it'll be no menu */
1313                         if (priv->accounts_popup) {
1314                                 item = gtk_menu_item_new_with_label (display_name);
1315                                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
1316                                 g_signal_connect_data (G_OBJECT (item), 
1317                                                        "activate", 
1318                                                        G_CALLBACK (on_send_receive_csm_activated),
1319                                                        g_strdup (account_data->account_name),
1320                                                        (GClosureNotify) g_free,
1321                                                        0);
1322                         }
1323                         g_free (item_name);
1324                 }
1325
1326                 /* Frees */
1327                 g_free (display_name);
1328                 modest_account_mgr_free_account_data (mgr, account_data);
1329         }
1330         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 1);
1331
1332         if (priv->accounts_popup) {
1333                 /* Mandatory in order to view the menu contents */
1334                 gtk_widget_show_all (priv->accounts_popup);
1335
1336                 /* Setup tap_and_hold just if was not done before*/
1337                 if (!gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)))
1338                         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
1339         }
1340
1341         /* Frees */
1342         g_slist_free (accounts);
1343         g_free (default_account);
1344 }
1345
1346 /* 
1347  * This function manages the key events used to navigate between
1348  * header and folder views (when the window is in split view)
1349  *
1350  * FROM         KEY        ACTION
1351  * -------------------------------------------------
1352  * HeaderView   GDK_Left   Move focus to folder view
1353  * FolderView   GDK_Right  Move focus to header view
1354  *
1355  * There is no need to scroll to selected row, the widgets will be the
1356  * responsibles of doing that (probably managing the focus-in event
1357  */
1358 static gboolean 
1359 on_inner_widgets_key_pressed (GtkWidget *widget,
1360                               GdkEventKey *event,
1361                               gpointer user_data)
1362 {
1363         ModestMainWindowPrivate *priv;
1364
1365         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
1366
1367         /* Do nothing if we're in SIMPLE style */
1368         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
1369                 return FALSE;
1370
1371         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
1372                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
1373         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
1374                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
1375
1376         return FALSE;
1377 }
1378
1379 static void
1380 set_alignment (GtkWidget *widget,
1381                gpointer data)
1382 {
1383         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
1384         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
1385 }
1386
1387 static GtkWidget *
1388 create_empty_view (void)
1389 {
1390         GtkLabel *label = NULL;
1391         GtkWidget *align = NULL;
1392
1393         align = gtk_alignment_new(XALIGN, YALIGN, XSPACE, YSPACE);
1394         label = GTK_LABEL(gtk_label_new (_("mcen_ia_nomessages")));
1395         gtk_label_set_justify (label, GTK_JUSTIFY_CENTER);      
1396         gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET(label));
1397
1398         return GTK_WIDGET(align);
1399 }
1400
1401 static GtkWidget *
1402 create_details_widget (TnyAccount *account)
1403 {
1404         GtkWidget *vbox;
1405         gchar *label;
1406
1407         vbox = gtk_vbox_new (FALSE, 0);
1408
1409         /* Account description: */
1410         
1411         if (modest_tny_account_is_virtual_local_folders (account)) {
1412                 /* Local folders: */
1413         
1414                 /* Get device name */
1415                 gchar *device_name = modest_conf_get_string (modest_runtime_get_conf(),
1416                                                       MODEST_CONF_DEVICE_NAME, NULL);
1417    
1418                 label = g_strdup_printf (_("mcen_fi_localroot_description"),
1419                                          device_name);
1420                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1421                 g_free (device_name);
1422                 g_free (label);
1423         } else {
1424                 if(!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1425                         gtk_box_pack_start (GTK_BOX (vbox), 
1426                                 gtk_label_new (tny_account_get_name (account)), 
1427                                 FALSE, FALSE, 0);
1428                 } else {
1429                         /* Other accounts, such as IMAP and POP: */
1430                         
1431                         GString *proto;
1432                         gchar *tmp;
1433         
1434                         /* Put proto in uppercase */
1435                         proto = g_string_new (tny_account_get_proto (account));
1436                         proto = g_string_ascii_up (proto);
1437                         
1438                         /* note: mcen_fi_localroot_description is something like "%s account"
1439                          * however, we should display "%s account: %s"... therefore, ugly tmp */
1440                         tmp   = g_strdup_printf (_("mcen_fi_remoteroot_account"),proto->str);
1441                         label = g_strdup_printf ("%s: %s", tmp,tny_account_get_name (account));
1442                         g_free (tmp);
1443
1444                         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1445                         g_string_free (proto, TRUE);
1446                         g_free (label);
1447                 }
1448         }
1449
1450         /* Message count */
1451         TnyFolderStore *folder_store = TNY_FOLDER_STORE (account);
1452         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1453                                  modest_tny_folder_store_get_message_count (folder_store));
1454         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1455         g_free (label);
1456
1457         /* Folder count */
1458         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1459                                  modest_tny_folder_store_get_folder_count (folder_store));
1460         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1461         g_free (label);
1462
1463         /* Size / Date */
1464         if (modest_tny_account_is_virtual_local_folders (account)) {
1465                 /* FIXME: format size */
1466                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1467                                          modest_tny_folder_store_get_local_size (folder_store));
1468                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1469                 g_free (label);
1470         } else if (TNY_IS_ACCOUNT(folder_store)) {
1471                 TnyAccount *account = TNY_ACCOUNT(folder_store);
1472                 
1473                 time_t last_updated;
1474                 gchar *last_updated_string;
1475                 /* Get last updated from configuration */
1476                 last_updated = modest_account_mgr_get_int (modest_runtime_get_account_mgr (), 
1477                                                           tny_account_get_id (account), 
1478                                                           MODEST_ACCOUNT_LAST_UPDATED, 
1479                                                           TRUE);
1480                 if (last_updated > 0) 
1481                         last_updated_string = modest_text_utils_get_display_date(last_updated);
1482                 else
1483                         last_updated_string = g_strdup (_("mcen_va_never"));
1484
1485                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), last_updated_string);
1486                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1487                 g_free (last_updated_string);
1488                 g_free (label);
1489         }
1490
1491         /* Set alignment */
1492         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1493
1494         return vbox;
1495 }
1496
1497 void 
1498 modest_main_window_notify_send_receive_initied (ModestMainWindow *self)
1499 {
1500         GtkAction *action = NULL;
1501         GtkWidget *widget = NULL;
1502
1503         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1504
1505         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1506         gtk_action_set_sensitive (action, FALSE);
1507 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu"); */
1508 /*      gtk_action_set_sensitive (action, FALSE); */
1509         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1510         gtk_widget_set_sensitive (widget, FALSE);
1511
1512
1513 void 
1514 modest_main_window_notify_send_receive_completed (ModestMainWindow *self)
1515 {
1516         GtkAction *action = NULL;
1517         GtkWidget *widget = NULL;
1518
1519         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1520
1521         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveAllMenu"); 
1522         gtk_action_set_sensitive (action, TRUE);
1523 /*         action = modest_window_get_action (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsSendReceiveCancelSendingMenu");     */
1524 /*      gtk_action_set_sensitive (action, TRUE); */
1525         widget = modest_window_get_action_widget (MODEST_WINDOW(self), "/MenuBar/ToolsMenu/ToolsSendReceiveMainMenu/ToolsMenuAdditions");       
1526         gtk_widget_set_sensitive (widget, TRUE);
1527
1528
1529
1530 static void
1531 _on_msg_count_changed (ModestHeaderView *header_view,
1532                        TnyFolder *folder,
1533                        TnyFolderChange *change,
1534                        ModestMainWindow *main_window)
1535 {
1536         printf ("DEBUG: %s\n", __FUNCTION__);
1537         gboolean folder_empty = FALSE;
1538         TnyFolderChangeChanged changed;
1539         
1540         g_return_if_fail (MODEST_IS_MAIN_WINDOW (main_window));
1541         g_return_if_fail (TNY_IS_FOLDER(folder));
1542         g_return_if_fail (TNY_IS_FOLDER_CHANGE(change));
1543         
1544         changed = tny_folder_change_get_changed (change);
1545         
1546         /* If something changes */
1547         if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
1548                 folder_empty = (tny_folder_change_get_new_all_count (change) == 0);     
1549         else
1550                 folder_empty = (tny_folder_get_all_count (TNY_FOLDER (folder)) == 0);
1551         
1552         printf ("DEBUG: %s: folder_empty=%d\n", __FUNCTION__, folder_empty);
1553
1554         /* Set contents style of headers view */
1555         if (folder_empty)  {
1556                 modest_main_window_set_contents_style (main_window,
1557                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY);
1558         }
1559         else {
1560                 modest_main_window_set_contents_style (main_window,
1561                                                        MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS);
1562         }
1563         
1564 }
1565
1566 void 
1567 modest_main_window_set_contents_style (ModestMainWindow *self, 
1568                                        ModestMainWindowContentsStyle style)
1569 {
1570         ModestMainWindowPrivate *priv;
1571
1572         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1573
1574         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1575
1576         /* We allow to set the same content style than the previously
1577            set if there are details, because it could happen when we're
1578            selecting different accounts consecutively */
1579         if ((priv->contents_style == style) &&
1580             (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS))
1581                 return;
1582
1583         /* Remove previous child. Delete it if it was an account
1584            details widget */
1585         GtkWidget *content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1586         if (content) {
1587                 if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
1588                         g_object_ref (content);
1589                 else if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY) {
1590                         g_object_ref (priv->empty_view);
1591                         gtk_container_remove (GTK_CONTAINER (content), priv->empty_view);
1592                 }
1593                 
1594                 gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1595         }
1596
1597         priv->contents_style = style;
1598
1599         switch (priv->contents_style) {
1600         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1601                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1602                 break;
1603         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1604         {
1605                 TnyFolderStore *selected_folderstore = 
1606                         modest_folder_view_get_selected (priv->folder_view);
1607                 if (TNY_IS_ACCOUNT (selected_folderstore)) {    
1608                         priv->details_widget = create_details_widget (
1609                                 TNY_ACCOUNT (selected_folderstore));
1610
1611                         wrap_in_scrolled_window (priv->contents_widget, 
1612                                          priv->details_widget);
1613                 }
1614                 g_object_unref (selected_folderstore);
1615                 break;
1616         }
1617         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_EMPTY:
1618                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->empty_view));
1619                 break;
1620         default:
1621                 g_return_if_reached ();
1622         }
1623
1624         /* Show */
1625         gtk_widget_show_all (priv->contents_widget);
1626 }
1627
1628 ModestMainWindowContentsStyle
1629 modest_main_window_get_contents_style (ModestMainWindow *self)
1630 {
1631         ModestMainWindowPrivate *priv;
1632
1633         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
1634
1635         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1636         return priv->contents_style;
1637 }
1638
1639
1640 static void 
1641 on_configuration_key_changed (ModestConf* conf, 
1642                               const gchar *key, 
1643                               ModestConfEvent event, 
1644                               ModestMainWindow *self)
1645 {
1646         ModestMainWindowPrivate *priv;
1647         TnyAccount *account;
1648
1649         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1650                 return;
1651
1652         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1653
1654         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1655                 return;
1656
1657         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1658         if (TNY_IS_ACCOUNT (account) &&
1659             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1660                 GList *children;
1661                 GtkLabel *label;
1662                 const gchar *device_name;
1663                 gchar *new_text;
1664                 
1665                 /* Get label */
1666                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1667                 label = GTK_LABEL (children->data);
1668                 
1669                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1670                                                       MODEST_CONF_DEVICE_NAME, NULL);
1671                 
1672                 new_text = g_strdup_printf ("%s: %s",
1673                                             _("mcen_fi_localroot_description"),
1674                                             device_name);
1675                 
1676                 gtk_label_set_text (label, new_text);
1677                 gtk_widget_show (GTK_WIDGET (label));
1678                 
1679                 g_free (new_text);
1680                 g_list_free (children);
1681         }
1682         g_object_unref (account);
1683 }
1684
1685 static gboolean
1686 set_toolbar_transfer_mode (ModestMainWindow *self)
1687 {
1688         ModestMainWindowPrivate *priv = NULL;
1689         
1690         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), FALSE);
1691
1692         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1693
1694         set_toolbar_mode (self, TOOLBAR_MODE_TRANSFER);
1695         
1696         if (priv->progress_bar_timeout > 0) {
1697                 g_source_remove (priv->progress_bar_timeout);
1698                 priv->progress_bar_timeout = 0;
1699         }
1700
1701         return FALSE;
1702 }
1703
1704 static void 
1705 set_toolbar_mode (ModestMainWindow *self, 
1706                   ModestToolBarModes mode)
1707 {
1708         ModestWindowPrivate *parent_priv = NULL;
1709         ModestMainWindowPrivate *priv = NULL;
1710         GtkAction *sort_action = NULL, *refresh_action = NULL, *cancel_action = NULL;
1711         
1712         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1713
1714         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1715         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1716
1717         /* In case this was called before the toolbar exists: */
1718         if (!(parent_priv->toolbar))
1719                 return;
1720
1721         g_return_if_fail (GTK_IS_TOOLBAR(parent_priv->toolbar)); 
1722         
1723         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1724         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1725         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1726
1727         /* Sets current toolbar mode */
1728         priv->current_toolbar_mode = mode;
1729
1730         /* Show and hide toolbar items */
1731         switch (mode) {
1732         case TOOLBAR_MODE_NORMAL:
1733                 if (sort_action) 
1734                         gtk_action_set_visible (sort_action, TRUE);
1735                 if (refresh_action) 
1736                         gtk_action_set_visible (refresh_action, TRUE);
1737                 if (priv->progress_toolitem) {
1738                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1739                         gtk_widget_hide (priv->progress_toolitem);
1740                 }
1741                 if (priv->progress_bar)
1742                         gtk_widget_hide (priv->progress_bar);                   
1743                 
1744                 if (cancel_action)
1745                         gtk_action_set_visible (cancel_action, FALSE);
1746
1747                 /* Hide toolbar if optimized view is enabled */
1748                 if (priv->optimized_view)
1749                         gtk_widget_hide (GTK_WIDGET(parent_priv->toolbar));
1750                 break;
1751         case TOOLBAR_MODE_TRANSFER:
1752                 if (sort_action)
1753                         gtk_action_set_visible (sort_action, FALSE);
1754                 if (refresh_action)
1755                         gtk_action_set_visible (refresh_action, FALSE);
1756                 if (cancel_action)
1757                         gtk_action_set_visible (cancel_action, TRUE);
1758                 if (priv->progress_toolitem) {
1759                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1760                         gtk_widget_show (priv->progress_toolitem);
1761                 }
1762                 if (priv->progress_bar)
1763                         gtk_widget_show (priv->progress_bar);                   
1764
1765                 /* Show toolbar if it's hiden (optimized view ) */
1766                 if (priv->optimized_view)
1767                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
1768                 break;
1769         default:
1770                 g_return_if_reached ();
1771         }
1772 }
1773
1774 static void
1775 cancel_progressbar (GtkToolButton *toolbutton,
1776                     ModestMainWindow *self)
1777 {
1778         GSList *tmp;
1779         ModestMainWindowPrivate *priv;
1780         
1781         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1782
1783         /* Get operation observers and cancel its current operation */
1784         tmp = priv->progress_widgets;
1785         while (tmp) {
1786                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1787                 tmp=g_slist_next(tmp);
1788         }
1789 }
1790
1791 static gboolean
1792 observers_empty (ModestMainWindow *self)
1793 {
1794         GSList *tmp = NULL;
1795         ModestMainWindowPrivate *priv;
1796         gboolean is_empty = TRUE;
1797         guint pending_ops = 0;
1798  
1799         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1800         tmp = priv->progress_widgets;
1801
1802         /* Check all observers */
1803         while (tmp && is_empty)  {
1804                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1805                 is_empty = pending_ops == 0;
1806                 
1807                 tmp = g_slist_next(tmp);
1808         }
1809         
1810         return is_empty;
1811 }
1812
1813 static void
1814 on_queue_changed (ModestMailOperationQueue *queue,
1815                   ModestMailOperation *mail_op,
1816                   ModestMailOperationQueueNotification type,
1817                   ModestMainWindow *self)
1818 {
1819         ModestMainWindowPrivate *priv;
1820         ModestMailOperationTypeOperation op_type;
1821         ModestToolBarModes mode;
1822         GSList *tmp;
1823         gboolean mode_changed = FALSE;
1824 /*      ModestMailOperationStatus status; */
1825
1826         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1827         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1828                
1829         /* Get toolbar mode from operation id*/
1830         op_type = modest_mail_operation_get_type_operation (mail_op);
1831         switch (op_type) {
1832         case MODEST_MAIL_OPERATION_TYPE_SEND:
1833         case MODEST_MAIL_OPERATION_TYPE_RECEIVE:
1834                 mode = TOOLBAR_MODE_TRANSFER;
1835                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1836                         mode_changed = TRUE;
1837                 break;
1838         default:
1839                 mode = TOOLBAR_MODE_NORMAL;
1840                 
1841         }
1842                 
1843                        
1844         /* Add operation observers and change toolbar if neccessary*/
1845         tmp = priv->progress_widgets;
1846         switch (type) {
1847         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1848                 if (mode == TOOLBAR_MODE_TRANSFER) {
1849                         if (mode_changed)
1850                                 set_toolbar_transfer_mode(self);                    
1851                         while (tmp) {
1852                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1853                                                                       mail_op);
1854                                 tmp = g_slist_next (tmp);
1855                         }
1856                 }
1857                 break;
1858         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1859                 /* Change toolbar mode */
1860                 if (mode == TOOLBAR_MODE_TRANSFER) {                    
1861                         while (tmp) {
1862                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1863                                                                          mail_op);
1864                                 tmp = g_slist_next (tmp);
1865                         }
1866                         
1867                         /* If no more operations are being observed, NORMAL mode is enabled again */
1868                         if (observers_empty (self)) {
1869                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1870                                 
1871                         }
1872                 }
1873
1874                 break;
1875         }       
1876
1877 }
1878
1879 static void 
1880 on_show_account_action_activated  (GtkAction *action,
1881                                    gpointer user_data)
1882 {
1883         ModestAccountData *acc_data;
1884         ModestMainWindow *self;
1885         ModestMainWindowPrivate *priv;
1886         ModestAccountMgr *mgr;
1887         const gchar *acc_name;
1888
1889         self = MODEST_MAIN_WINDOW (user_data);
1890         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1891
1892         /* Get account data */
1893         acc_name = gtk_action_get_name (action);
1894         mgr = modest_runtime_get_account_mgr ();
1895         acc_data = modest_account_mgr_get_account_data (mgr, acc_name);
1896
1897         /* Set the new visible & active account */
1898         if (acc_data->store_account) { 
1899                 modest_folder_view_set_account_id_of_visible_server_account (priv->folder_view,
1900                                                                              acc_data->store_account->account_name);
1901                 modest_window_set_active_account (MODEST_WINDOW (self), acc_data->account_name);
1902         }
1903
1904         /* Free */
1905         modest_account_mgr_free_account_data (mgr, acc_data);
1906 }
1907
1908 static void
1909 refresh_account (const gchar *account_name)
1910 {
1911         ModestWindow *win;
1912
1913         win = MODEST_WINDOW (modest_window_mgr_get_main_window (modest_runtime_get_window_mgr ()));
1914
1915         /* If account_name == NULL, we must update all (option All) */
1916         if (!account_name)
1917                 modest_ui_actions_do_send_receive_all (win);
1918         else
1919                 modest_ui_actions_do_send_receive (account_name, win);
1920         
1921 }
1922
1923 static void 
1924 on_refresh_account_action_activated  (GtkAction *action,
1925                                       gpointer user_data)
1926 {
1927         refresh_account ((const gchar*) user_data);
1928 }
1929
1930 static void
1931 on_send_receive_csm_activated (GtkMenuItem *item,
1932                                gpointer user_data)
1933 {
1934         refresh_account ((const gchar*) user_data);
1935 }
1936
1937 static gboolean
1938 on_zoom_minus_plus_not_implemented (ModestWindow *window)
1939 {
1940         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (window), FALSE);
1941
1942         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
1943         return FALSE;
1944
1945 }