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