2007-05-04 Murray Cumming <murrayc@murrayc.com>
[modest] / src / maemo / modest-main-window.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <glib/gi18n.h>
31 #include <gtk/gtktreeviewcolumn.h>
32 #include <tny-account-store-view.h>
33 #include <tny-simple-list.h>
34 #include "modest-hildon-includes.h"
35 #include "modest-defs.h"
36 #include <string.h>
37
38 #include "widgets/modest-main-window.h"
39 #include "widgets/modest-msg-edit-window.h"
40 #include "widgets/modest-account-view-window.h"
41 #include "modest-runtime.h"
42 #include "modest-account-mgr-helpers.h"
43 #include "modest-platform.h"
44 #include "modest-widget-memory.h"
45 #include "modest-window-priv.h"
46 #include "modest-main-window-ui.h"
47 #include "modest-account-mgr.h"
48 #include "modest-tny-account.h"
49 #include "modest-conf.h"
50 #include <modest-maemo-utils.h>
51 #include "modest-tny-platform-factory.h"
52 #include "modest-tny-msg.h"
53 #include "modest-mail-operation.h"
54 #include "modest-icon-names.h"
55 #include "modest-progress-bar-widget.h"
56 #include <hildon-widgets/hildon-program.h>
57 #include "maemo/modest-osso-state-saving.h"
58
59 /* 'private'/'protected' functions */
60 static void modest_main_window_class_init    (ModestMainWindowClass *klass);
61 static void modest_main_window_init          (ModestMainWindow *obj);
62 static void modest_main_window_finalize      (GObject *obj);
63 static gboolean modest_main_window_window_state_event (GtkWidget *widget, 
64                                                            GdkEventWindowState *event, 
65                                                            gpointer userdata);
66
67 static void connect_signals (ModestMainWindow *self);
68 static void restore_sizes (ModestMainWindow *self);
69 static void save_sizes (ModestMainWindow *self);
70
71 static void modest_main_window_show_toolbar   (ModestWindow *window,
72                                                gboolean show_toolbar);
73
74 static void cancel_progressbar (GtkToolButton *toolbutton,
75                                 ModestMainWindow *self);
76
77 static void         on_queue_changed                     (ModestMailOperationQueue *queue,
78                                                           ModestMailOperation *mail_op,
79                                                           ModestMailOperationQueueNotification type,
80                                                           ModestMainWindow *self);
81
82 static void on_account_update                 (TnyAccountStore *account_store, 
83                                                gchar *account_name,
84                                                gpointer user_data);
85
86 static gboolean on_inner_widgets_key_pressed  (GtkWidget *widget,
87                                                GdkEventKey *event,
88                                                gpointer user_data);
89
90 static void on_configuration_key_changed      (ModestConf* conf, 
91                                                const gchar *key, 
92                                                ModestConfEvent event, 
93                                                ModestMainWindow *self);
94
95 static void 
96 set_toolbar_mode (ModestMainWindow *self, 
97                   ModestToolBarModes mode);
98
99 /* list my signals */
100 enum {
101         /* MY_SIGNAL_1, */
102         /* MY_SIGNAL_2, */
103         LAST_SIGNAL
104 };
105
106
107 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
108 struct _ModestMainWindowPrivate {
109         GtkWidget *msg_paned;
110         GtkWidget *main_paned;
111         GtkWidget *main_vbox;
112         GtkWidget *contents_widget;
113
114         /* Progress observers */
115         GtkWidget        *progress_bar;
116         GSList           *progress_widgets;
117
118         /* Tollbar items */
119         GtkWidget   *progress_toolitem;
120         GtkWidget   *cancel_toolitem;
121         GtkWidget   *sort_toolitem;
122         GtkWidget   *refresh_toolitem;
123         ModestToolBarModes current_toolbar_mode;
124
125         /* On-demand widgets */
126         GtkWidget *accounts_popup;
127         GtkWidget *details_widget;
128
129
130         ModestHeaderView *header_view;
131         ModestFolderView *folder_view;
132
133         ModestMainWindowStyle style;
134         ModestMainWindowContentsStyle contents_style;
135 };
136 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
137                                                 MODEST_TYPE_MAIN_WINDOW, \
138                                                 ModestMainWindowPrivate))
139
140 typedef struct _GetMsgAsyncHelper {
141         ModestMainWindowPrivate *main_window_private;
142         guint action;
143         ModestTnyMsgReplyType reply_type;
144         ModestTnyMsgForwardType forward_type;
145         gchar *from;
146         TnyIterator *iter;
147 } GetMsgAsyncHelper;
148
149
150 /* globals */
151 static GtkWindowClass *parent_class = NULL;
152
153
154 /* Private actions */
155 static const GtkActionEntry modest_folder_view_action_entries [] = {
156
157         /* Folder View CSM actions */
158         { "FolderViewCSMNewFolder", NULL, N_("FIXME: New Folder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_new_folder) },
159         { "FolderViewCSMRenameFolder", NULL, N_("mcen_me_user_renamefolder"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_rename_folder) },
160         { "FolderViewCSMPasteMsgs", NULL, N_("FIXME: Paste"), NULL, NULL, NULL },
161         { "FolderViewCSMDeleteFolder", NULL, N_("FIXME: Delete"), NULL, NULL, G_CALLBACK (modest_ui_actions_on_delete_folder) },
162         { "FolderViewCSMSearchMessages", NULL, N_("mcen_me_inbox_search"), NULL, NULL, NULL },
163         { "FolderViewCSMHelp", NULL, N_("mcen_me_inbox_help"), NULL, NULL, NULL },
164 };
165
166
167 static const GtkToggleActionEntry modest_main_window_toggle_action_entries [] = {
168         { "ToolbarToggleView", MODEST_STOCK_SPLIT_VIEW, N_("gqn_toolb_rss_fldonoff"), "<CTRL>t", NULL, G_CALLBACK (modest_ui_actions_toggle_folders_view), FALSE },
169 };
170
171
172 /************************************************************************/
173
174 GType
175 modest_main_window_get_type (void)
176 {
177         static GType my_type = 0;
178         if (!my_type) {
179                 static const GTypeInfo my_info = {
180                         sizeof(ModestMainWindowClass),
181                         NULL,           /* base init */
182                         NULL,           /* base finalize */
183                         (GClassInitFunc) modest_main_window_class_init,
184                         NULL,           /* class finalize */
185                         NULL,           /* class data */
186                         sizeof(ModestMainWindow),
187                         1,              /* n_preallocs */
188                         (GInstanceInitFunc) modest_main_window_init,
189                         NULL
190                 };
191                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
192                                                   "ModestMainWindow",
193                                                   &my_info, 0);
194         }
195         return my_type;
196 }
197
198 static void
199 modest_main_window_class_init (ModestMainWindowClass *klass)
200 {
201         GObjectClass *gobject_class;
202         gobject_class = (GObjectClass*) klass;
203         ModestWindowClass *modest_window_class;
204
205         modest_window_class = (ModestWindowClass *) klass;
206
207         parent_class            = g_type_class_peek_parent (klass);
208         gobject_class->finalize = modest_main_window_finalize;
209
210         modest_window_class->show_toolbar_func = modest_main_window_show_toolbar;
211
212         g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
213 }
214
215 static void
216 modest_main_window_init (ModestMainWindow *obj)
217 {
218         ModestMainWindowPrivate *priv;
219
220         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
221
222         priv->msg_paned    = NULL;
223         priv->main_paned   = NULL;      
224         priv->main_vbox    = NULL;
225         priv->header_view  = NULL;
226         priv->folder_view  = NULL;
227         priv->contents_widget  = NULL;
228         priv->accounts_popup  = NULL;
229         priv->details_widget  = NULL;
230
231         priv->progress_widgets  = NULL;
232         priv->progress_bar = NULL;
233         priv->current_toolbar_mode = TOOLBAR_MODE_NORMAL;
234
235         priv->style  = MODEST_MAIN_WINDOW_STYLE_SPLIT;
236         priv->contents_style  = MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS;
237 }
238
239 static void
240 modest_main_window_finalize (GObject *obj)
241 {
242         ModestMainWindowPrivate *priv;
243
244         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
245
246         g_slist_free (priv->progress_widgets);
247
248         G_OBJECT_CLASS(parent_class)->finalize (obj);
249 }
250
251 GtkWidget*
252 modest_main_window_get_child_widget (ModestMainWindow *self,
253                                      ModestWidgetType widget_type)
254 {
255         ModestMainWindowPrivate *priv;
256         GtkWidget *widget;
257         
258         g_return_val_if_fail (self, NULL);
259         g_return_val_if_fail (widget_type >= 0 && widget_type < MODEST_WIDGET_TYPE_NUM,
260                               NULL);
261         
262         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
263
264         switch (widget_type) {
265         case MODEST_WIDGET_TYPE_HEADER_VIEW:
266                 widget = (GtkWidget*)priv->header_view; break;
267         case MODEST_WIDGET_TYPE_FOLDER_VIEW:
268                 widget = (GtkWidget*)priv->folder_view; break;
269         default:
270                 return NULL;
271         }
272
273         return widget ? GTK_WIDGET(widget) : NULL;
274 }
275
276
277
278 static void
279 restore_sizes (ModestMainWindow *self)
280 {
281         ModestConf *conf;
282         ModestMainWindowPrivate *priv;
283
284         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
285
286         conf = modest_runtime_get_conf ();
287         
288         modest_widget_memory_restore (conf, G_OBJECT(priv->main_paned),
289                                       MODEST_CONF_MAIN_PANED_KEY);
290         modest_widget_memory_restore (conf, G_OBJECT(priv->header_view),
291                                       MODEST_CONF_HEADER_VIEW_KEY);
292         modest_widget_memory_restore (conf, G_OBJECT(self), 
293                                       MODEST_CONF_MAIN_WINDOW_KEY);
294 }
295
296
297 static void
298 save_sizes (ModestMainWindow *self)
299 {
300         ModestConf *conf;
301         ModestMainWindowPrivate *priv;
302                 
303         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
304         conf = modest_runtime_get_conf ();
305         
306         modest_widget_memory_save (conf,G_OBJECT(self), 
307                                    MODEST_CONF_MAIN_WINDOW_KEY);
308         modest_widget_memory_save (conf, G_OBJECT(priv->main_paned), 
309                                    MODEST_CONF_MAIN_PANED_KEY);
310         modest_widget_memory_save (conf, G_OBJECT(priv->header_view), 
311                                    MODEST_CONF_HEADER_VIEW_KEY);
312 }
313
314 static void
315 wrap_in_scrolled_window (GtkWidget *win, GtkWidget *widget)
316 {
317         if (!gtk_widget_set_scroll_adjustments (widget, NULL, NULL))
318                 gtk_scrolled_window_add_with_viewport
319                         (GTK_SCROLLED_WINDOW(win), widget);
320         else
321                 gtk_container_add (GTK_CONTAINER(win),
322                                    widget);
323 }
324
325
326 static gboolean
327 on_delete_event (GtkWidget *widget, GdkEvent  *event, ModestMainWindow *self)
328 {
329         save_sizes (self);
330         return FALSE;
331 }
332
333
334 static void
335 on_connection_changed (TnyDevice *device, gboolean online, ModestMainWindow *self)
336 {
337         /* When going online, do the equivalent of pressing the send/receive button, 
338          * as per the specification:
339          * (without the check for >0 accounts, though that is not specified): */
340         if (online) {
341                 do_send_receive (MODEST_WINDOW (self));
342         }
343 }
344
345
346
347 static void
348 connect_signals (ModestMainWindow *self)
349 {       
350         ModestWindowPrivate *parent_priv;
351         ModestMainWindowPrivate *priv;
352         GtkWidget *menu;
353         
354         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
355         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
356         
357         /* folder view */
358         g_signal_connect (G_OBJECT(priv->folder_view), "key-press-event",
359                           G_CALLBACK(on_inner_widgets_key_pressed), self);
360         g_signal_connect (G_OBJECT(priv->folder_view), "folder_selection_changed",
361                           G_CALLBACK(modest_ui_actions_on_folder_selection_changed), self);
362         g_signal_connect (G_OBJECT(priv->folder_view), "folder-display-name-changed",
363                           G_CALLBACK(modest_ui_actions_on_folder_display_name_changed), self);
364
365         menu = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/FolderViewCSM");
366         gtk_widget_tap_and_hold_setup (GTK_WIDGET (priv->folder_view), menu, NULL, 0);
367
368         /* header view */
369 /*      g_signal_connect (G_OBJECT(priv->header_view), "status_update", */
370 /*                        G_CALLBACK(modest_ui_actions_on_header_status_update), self); */
371         g_signal_connect (G_OBJECT(priv->header_view), "header_selected",
372                           G_CALLBACK(modest_ui_actions_on_header_selected), self);
373         g_signal_connect (G_OBJECT(priv->header_view), "header_activated",
374                           G_CALLBACK(modest_ui_actions_on_header_activated), self);
375         g_signal_connect (G_OBJECT(priv->header_view), "item_not_found",
376                           G_CALLBACK(modest_ui_actions_on_item_not_found), self);
377         g_signal_connect (G_OBJECT(priv->header_view), "key-press-event",
378                           G_CALLBACK(on_inner_widgets_key_pressed), self);
379
380         /* window */
381         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
382         g_signal_connect (G_OBJECT (self), "window-state-event",
383                           G_CALLBACK (modest_main_window_window_state_event),
384                           NULL);
385         g_signal_connect (G_OBJECT(self), "delete-event", G_CALLBACK(on_delete_event), self);
386
387         /* Mail Operation Queue */
388         g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
389                           "queue-changed",
390                           G_CALLBACK (on_queue_changed),
391                           self);
392
393         /* Track changes in the device name */
394         g_signal_connect (G_OBJECT(modest_runtime_get_conf ()),
395                           "key_changed",
396                           G_CALLBACK (on_configuration_key_changed), 
397                           self);
398
399         /* Track account changes. We need to refresh the toolbar */
400         g_signal_connect (G_OBJECT (modest_runtime_get_account_store ()),
401                           "account_update",
402                           G_CALLBACK (on_account_update),
403                           self);
404
405         /* Device */
406         g_signal_connect (G_OBJECT(modest_runtime_get_device()), "connection_changed",
407                           G_CALLBACK(on_connection_changed), self);
408 }
409
410 /** Idle handler, to send/receive at startup .*/
411 gboolean
412 sync_accounts_cb (ModestMainWindow *win)
413 {
414         do_send_receive (MODEST_WINDOW(win));
415         return FALSE; /* Do not call this idle handler again. */
416 }
417
418 static void on_hildon_program_is_topmost_notify(GObject *self,
419         GParamSpec *propert_param, gpointer user_data)
420 {
421         HildonProgram *app = HILDON_PROGRAM (self);
422         
423         /*
424         ModestWindow* self = MODEST_WINDOW(user_data);
425         */
426         
427         /* Note that use of hildon_program_set_can_hibernate() 
428          * is generally referred to as "setting the killable flag", 
429          * though hibernation does not seem equal to death.
430          * murrayc */
431                  
432         if (hildon_program_get_is_topmost (app)) {
433                 /* Prevent hibernation when the progam comes to the foreground,
434                  * because hibernation should only happen when the application 
435                  * is in the background: */
436                 hildon_program_set_can_hibernate (app, FALSE);
437         } else {
438                 /* Allow hibernation if the program has gone to the background: */
439                 
440                 /* However, prevent hibernation while the settings are being changed: */
441                 gboolean settings_dialog_is_open = FALSE;
442                 
443                 if (settings_dialog_is_open)
444                         hildon_program_set_can_hibernate (app, FALSE);
445                 else {
446                         
447                         /* Allow hibernation, after saving the state: */
448                         modest_osso_save_state();
449                         hildon_program_set_can_hibernate (app, TRUE);
450                 }
451         }
452         
453 }
454
455
456
457 ModestWindow*
458 modest_main_window_new (void)
459 {
460         ModestMainWindow *self; 
461         ModestMainWindowPrivate *priv;
462         ModestWindowPrivate *parent_priv;
463         GtkWidget *folder_win;
464         GtkActionGroup *action_group;
465         GError *error = NULL;
466         TnyFolderStoreQuery *query;
467         GdkPixbuf *window_icon;
468         ModestConf *conf;
469         GtkAction *action;
470
471         self  = MODEST_MAIN_WINDOW(g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL));
472         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
473         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
474
475         parent_priv->ui_manager = gtk_ui_manager_new();
476         action_group = gtk_action_group_new ("ModestMainWindowActions");
477         gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
478
479         /* Add common actions */
480         gtk_action_group_add_actions (action_group,
481                                       modest_action_entries,
482                                       G_N_ELEMENTS (modest_action_entries),
483                                       self);
484
485         gtk_action_group_add_actions (action_group,
486                                       modest_folder_view_action_entries,
487                                       G_N_ELEMENTS (modest_folder_view_action_entries),
488                                       self);
489
490         gtk_action_group_add_toggle_actions (action_group,
491                                              modest_toggle_action_entries,
492                                              G_N_ELEMENTS (modest_toggle_action_entries),
493                                              self);
494
495         gtk_action_group_add_toggle_actions (action_group,
496                                              modest_main_window_toggle_action_entries,
497                                              G_N_ELEMENTS (modest_main_window_toggle_action_entries),
498                                              self);
499
500         gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0);
501         g_object_unref (action_group);
502
503         /* Load the UI definition */
504         gtk_ui_manager_add_ui_from_file (parent_priv->ui_manager,
505                                          MODEST_UIDIR "modest-main-window-ui.xml", &error);
506         if (error != NULL) {
507                 g_warning ("Could not merge modest-ui.xml: %s", error->message);
508                 g_error_free (error);
509                 error = NULL;
510         }
511
512         /* Add accelerators */
513         gtk_window_add_accel_group (GTK_WINDOW (self), 
514                                     gtk_ui_manager_get_accel_group (parent_priv->ui_manager));
515
516         /* Menubar. Update the state of some toggles */
517         parent_priv->menubar = modest_maemo_utils_menubar_to_menu (parent_priv->ui_manager);
518         conf = modest_runtime_get_conf ();
519         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
520                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarNormalScreenMenu");
521         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
522                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR, NULL));
523         action = gtk_ui_manager_get_action (parent_priv->ui_manager, 
524                                             "/MenuBar/ViewMenu/ViewShowToolbarMainMenu/ViewShowToolbarFullScreenMenu");
525         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
526                                       modest_conf_get_bool (conf, MODEST_CONF_SHOW_TOOLBAR_FULLSCREEN, NULL));
527         hildon_window_set_menu (HILDON_WINDOW (self), GTK_MENU (parent_priv->menubar));
528
529         /* folder view */
530         query = tny_folder_store_query_new ();
531         tny_folder_store_query_add_item (query, NULL,
532                                          TNY_FOLDER_STORE_QUERY_OPTION_SUBSCRIBED);
533         priv->folder_view = MODEST_FOLDER_VIEW(modest_folder_view_new (query));
534         if (!priv->folder_view)
535                 g_printerr ("modest: cannot instantiate folder view\n");
536         g_object_unref (G_OBJECT (query));
537         modest_folder_view_set_style (priv->folder_view,
538                                       MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
539
540         /* Get device name */
541         modest_maemo_utils_get_device_name ();
542
543         /* header view */
544         priv->header_view  =
545                 MODEST_HEADER_VIEW(modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_DETAILS));
546         if (!priv->header_view)
547                 g_printerr ("modest: cannot instantiate header view\n");
548         modest_header_view_set_style (priv->header_view, MODEST_HEADER_VIEW_STYLE_TWOLINES);
549         
550         /* Create scrolled windows */
551         folder_win = gtk_scrolled_window_new (NULL, NULL);
552         priv->contents_widget = gtk_scrolled_window_new (NULL, NULL);
553         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (folder_win),
554                                         GTK_POLICY_NEVER,
555                                         GTK_POLICY_AUTOMATIC);
556         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->contents_widget),
557                                         GTK_POLICY_NEVER,
558                                         GTK_POLICY_AUTOMATIC);
559
560         wrap_in_scrolled_window (folder_win, GTK_WIDGET(priv->folder_view));
561         wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET(priv->header_view));
562
563         /* paned */
564         priv->main_paned = gtk_hpaned_new ();
565         gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
566         gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->contents_widget);
567         gtk_widget_show (GTK_WIDGET(priv->header_view));
568         gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
569
570         /* putting it all together... */
571         priv->main_vbox = gtk_vbox_new (FALSE, 6);
572         gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->main_paned, TRUE, TRUE,0);
573
574         gtk_container_add (GTK_CONTAINER(self), priv->main_vbox);
575         restore_sizes (MODEST_MAIN_WINDOW(self));
576
577         /* Set window icon */
578         window_icon = modest_platform_get_icon (MODEST_APP_ICON);
579         gtk_window_set_icon (GTK_WINDOW (self), window_icon);
580         
581         /* Connect signals */
582         connect_signals (self);
583
584         /* Set account store */
585         tny_account_store_view_set_account_store (TNY_ACCOUNT_STORE_VIEW (priv->folder_view),
586                                                   TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()));
587
588         /* do send & receive when we are idle */
589         g_idle_add ((GSourceFunc)sync_accounts_cb, self);
590         
591
592         HildonProgram *app = hildon_program_get_instance ();
593         hildon_program_add_window (app, HILDON_WINDOW (self));
594         
595         /* Register HildonProgram  signal handlers: */
596         /* These are apparently deprecated, according to the 
597          * "HildonApp/HildonAppView to HildonProgram/HildonWindow migration guide",
598          * though the API reference does not mention that:
599          *
600         g_signal_connect (G_OBJECT(app), "topmost_status_lose",
601                 G_CALLBACK (on_hildon_program_save_state), self);
602         g_signal_connect (G_OBJECT(app), "topmost_status_acquire",
603                 G_CALLBACK (on_hildon_program_status_acquire), self);
604     */
605         g_signal_connect (G_OBJECT(app), "notify::is-topmost",
606                 G_CALLBACK (on_hildon_program_is_topmost_notify), self);
607                 
608         /* Load previous osso state, for instance if we are being restored from 
609          * hibernation:  */
610         modest_osso_load_state();
611
612         return MODEST_WINDOW(self);
613 }
614
615 gboolean 
616 modest_main_window_close_all (ModestMainWindow *self)
617 {
618         GtkWidget *note;
619         GtkResponseType response;
620
621         /* Create the confirmation dialog MSG-NOT308 */
622         note = hildon_note_new_confirmation_add_buttons (GTK_WINDOW (self),
623                                                          _("emev_nc_close_windows"),
624                                                          _("mcen_bd_yes"), GTK_RESPONSE_YES,
625                                                          _("mcen_bd_no"), GTK_RESPONSE_NO,
626                                                          NULL);
627
628         response = gtk_dialog_run (GTK_DIALOG (note));
629         gtk_widget_destroy (GTK_WIDGET (note));
630
631         if (response == GTK_RESPONSE_YES)
632                 return TRUE;
633         else
634                 return FALSE;
635 }
636
637
638 void 
639 modest_main_window_set_style (ModestMainWindow *self, 
640                               ModestMainWindowStyle style)
641 {
642         ModestMainWindowPrivate *priv;
643         ModestWindowPrivate *parent_priv;
644         GtkAction *action;
645
646         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
647
648         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
649         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
650
651         /* no change -> nothing to do */
652         if (priv->style == style)
653                 return;
654
655         /* Get toggle button */
656         action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarToggleView");
657
658         priv->style = style;
659
660         switch (style) {
661         case MODEST_MAIN_WINDOW_STYLE_SIMPLE:
662                 /* Remove main paned */
663                 g_object_ref (priv->main_paned);
664                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
665
666                 /* Reparent the contents widget to the main vbox */
667                 gtk_widget_reparent (priv->contents_widget, priv->main_vbox);
668
669                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
670                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
671                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
672
673                 break;
674         case MODEST_MAIN_WINDOW_STYLE_SPLIT:
675                 /* Remove header view */
676                 g_object_ref (priv->contents_widget);
677                 gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->contents_widget);
678
679                 /* Reparent the main paned */
680                 gtk_paned_add2 (GTK_PANED (priv->main_paned), priv->contents_widget);
681                 gtk_container_add (GTK_CONTAINER (priv->main_vbox), priv->main_paned);
682
683                 g_signal_handlers_block_by_func (action, modest_ui_actions_toggle_folders_view, self);
684                 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE);
685                 g_signal_handlers_unblock_by_func (action, modest_ui_actions_toggle_folders_view, self);
686
687                 break;
688         default:
689                 g_return_if_reached ();
690         }
691
692         /* Let header view grab the focus if it's being shown */
693         if (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS)
694                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
695         else 
696                 gtk_widget_grab_focus (GTK_WIDGET (priv->contents_widget));
697
698         /* Show changes */
699         gtk_widget_show_all (GTK_WIDGET (priv->main_vbox));
700 }
701
702 ModestMainWindowStyle
703 modest_main_window_get_style (ModestMainWindow *self)
704 {
705         ModestMainWindowPrivate *priv;
706
707         g_return_val_if_fail (MODEST_IS_MAIN_WINDOW (self), -1);
708
709         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
710         return priv->style;
711 }
712
713
714
715 static gboolean
716 modest_main_window_window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer userdata)
717 {
718         if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
719                 ModestWindowPrivate *parent_priv;
720                 ModestWindowMgr *mgr;
721                 gboolean is_fullscreen;
722                 GtkAction *fs_toggle_action;
723                 gboolean active;
724                 
725                 mgr = modest_runtime_get_window_mgr ();
726                 
727                 is_fullscreen = modest_window_mgr_get_fullscreen_mode (mgr);
728
729                 parent_priv = MODEST_WINDOW_GET_PRIVATE (widget);
730                 
731                 fs_toggle_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/MenuBar/ViewMenu/ViewToggleFullscreenMenu");
732                 active = (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (fs_toggle_action)))?1:0;
733                 if (is_fullscreen != active) {
734                         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (fs_toggle_action), is_fullscreen);
735                 }
736         }
737
738         return FALSE;
739
740 }
741
742 static void
743 set_homogeneous (GtkWidget *widget,
744                  gpointer data)
745 {
746         gtk_tool_item_set_expand (GTK_TOOL_ITEM (widget), TRUE);
747         gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (widget), TRUE);
748 }
749
750 static void 
751 modest_main_window_show_toolbar (ModestWindow *self,
752                                  gboolean show_toolbar)
753 {
754         ModestMainWindowPrivate *priv = NULL;
755         ModestWindowPrivate *parent_priv = NULL;        
756         GtkWidget *reply_button = NULL, *menu = NULL;
757         GtkWidget *placeholder = NULL;
758         gint insert_index;
759
760         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
761         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
762
763         if (!parent_priv->toolbar && show_toolbar) {
764                 parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
765                                                                   "/ToolBar");
766
767                 /* Set homogeneous toolbar */
768                 gtk_container_foreach (GTK_CONTAINER (parent_priv->toolbar), 
769                                        set_homogeneous, NULL);
770         
771                 priv->progress_toolitem = GTK_WIDGET (gtk_tool_item_new ());
772                 priv->cancel_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
773                 priv->refresh_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
774                 priv->sort_toolitem = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
775                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
776                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
777                 gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
778                 gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->cancel_toolitem), FALSE);
779
780                 /* Add ProgressBar (Transfer toolbar) */ 
781                 priv->progress_bar = modest_progress_bar_widget_new ();
782                 gtk_widget_set_no_show_all (priv->progress_bar, TRUE);
783                 placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/ProgressBarView");
784                 insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(placeholder));
785                 gtk_container_add (GTK_CONTAINER (priv->progress_toolitem), priv->progress_bar);
786                 gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (priv->progress_toolitem), insert_index);
787                 
788                 /* Connect cancel 'clicked' signal to abort progress mode */
789                 g_signal_connect(priv->cancel_toolitem, "clicked",
790                                  G_CALLBACK(cancel_progressbar),
791                                  self);
792                 
793                 /* Add it to the observers list */
794                 priv->progress_widgets = g_slist_prepend(priv->progress_widgets, priv->progress_bar);
795
796                 /* Add to window */
797                 hildon_window_add_toolbar (HILDON_WINDOW (self), 
798                                            GTK_TOOLBAR (parent_priv->toolbar));
799
800                 /* Set reply button tap and hold menu */
801                 reply_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
802                                                           "/ToolBar/ToolbarMessageReply");
803                 menu = gtk_ui_manager_get_widget (parent_priv->ui_manager,
804                                                   "/ToolbarReplyCSM");
805                 gtk_widget_tap_and_hold_setup (GTK_WIDGET (reply_button), menu, NULL, 0);
806
807                 /* Set send & receive button tap and hold menu */
808                 on_account_update (TNY_ACCOUNT_STORE (modest_runtime_get_account_store ()),
809                                    NULL, self);
810         }
811
812         /* TODO: Why is this sometimes NULL? murrayc */
813         if (parent_priv->toolbar) {
814                 if (show_toolbar) {
815                         /* Quick hack: this prevents toolbar icons "dance" when progress bar show status is changed */
816                         /* TODO: resize mode migth be GTK_RESIZE_QUEUE, in order to avoid unneccesary shows */
817                         gtk_container_set_resize_mode (GTK_CONTAINER(parent_priv->toolbar), GTK_RESIZE_IMMEDIATE);
818
819                         gtk_widget_show (GTK_WIDGET (parent_priv->toolbar));
820                         set_toolbar_mode (MODEST_MAIN_WINDOW(self), TOOLBAR_MODE_NORMAL);
821                 } else
822                         gtk_widget_hide (GTK_WIDGET (parent_priv->toolbar));
823         }
824 }
825
826 /*
827  * TODO: modify the menu dynamically. Add handlers to each item of the
828  * menu when created
829  */
830 static void 
831 on_account_update (TnyAccountStore *account_store, 
832                    gchar *accout_name,
833                    gpointer user_data)
834 {
835         ModestMainWindow *self;
836         ModestMainWindowPrivate *priv;
837         ModestWindowPrivate *parent_priv;
838         TnyList *account_list;
839         GtkWidget *item, *send_receive_button;
840         TnyIterator *iter;
841         ModestAccountMgr *mgr;
842         gchar *default_account;
843
844         self = MODEST_MAIN_WINDOW (user_data);
845         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (self);
846         parent_priv = MODEST_WINDOW_GET_PRIVATE (self);
847
848         /* If there is no toolbar then exit */
849         if (!parent_priv->toolbar)
850                 return;
851
852         if (priv->accounts_popup && gtk_menu_get_attach_widget (GTK_MENU (priv->accounts_popup)) ) {
853                 /* gtk_menu_detach will also unreference the popup, 
854                  * so we can forget about this instance, and create a new one later:
855                  */
856                 gtk_menu_detach (GTK_MENU (priv->accounts_popup));
857                 priv->accounts_popup = NULL;
858         }
859
860         /* Get accounts */
861         account_list = tny_simple_list_new ();
862         tny_account_store_get_accounts (account_store, 
863                                         account_list, 
864                                         TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
865
866         /* If there is only one account do not show any menu */
867         if (tny_list_get_length (account_list) <= 1)
868                 goto free;
869         
870         /* Get send receive button */
871         send_receive_button = gtk_ui_manager_get_widget (parent_priv->ui_manager, 
872                                                           "/ToolBar/ToolbarSendReceive");
873
874         /* Create the menu */
875         priv->accounts_popup = gtk_menu_new ();
876         item = gtk_menu_item_new_with_label (_("mcen_me_toolbar_sendreceive_all"));
877         gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
878         item = gtk_separator_menu_item_new ();
879         gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
880
881         iter = tny_list_create_iterator (account_list);
882         mgr = modest_runtime_get_account_mgr ();
883         default_account = modest_account_mgr_get_default_account (mgr);
884
885         do {
886                 TnyAccount *acc = NULL;
887                 const gchar *acc_name = NULL;
888
889                 /* Create tool item */
890                 acc = TNY_ACCOUNT (tny_iterator_get_current (iter));
891                 if (acc)
892                         acc_name = tny_account_get_name (acc);
893
894                 /* Create display name */
895                 gchar *display_name = NULL;
896                 if (acc_name) {
897                         if (default_account && !(strcmp (default_account, acc_name) == 0))
898                                 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), acc_name);
899                         else
900                                 display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_mailbox_n"), acc_name);
901                 }
902                 else
903                 {
904                         /* TODO: This probably should never happen: */
905                         display_name = g_strdup_printf (_("mcen_me_toolbar_sendreceive_default"), "");
906                 }
907                 
908
909                 item = gtk_menu_item_new_with_label (display_name);
910
911                 /* Free */
912                 g_free (display_name);
913                 g_object_unref (acc);
914
915                 /* Append item */
916                 gtk_menu_shell_append (GTK_MENU_SHELL (priv->accounts_popup), GTK_WIDGET (item));
917
918                 /* Go to next */
919                 tny_iterator_next (iter);
920
921         } while (!tny_iterator_is_done (iter));
922
923         g_object_unref (iter);
924
925         /* Mandatory in order to view the menu contents */
926         gtk_widget_show_all (priv->accounts_popup);
927
928         /* Setup tap_and_hold */
929         gtk_widget_tap_and_hold_setup (send_receive_button, priv->accounts_popup, NULL, 0);
930
931  free:
932
933         /* Free */
934         g_object_unref (account_list);
935 }
936
937 /* 
938  * This function manages the key events used to navigate between
939  * header and folder views (when the window is in split view)
940  *
941  * FROM         KEY        ACTION
942  * -------------------------------------------------
943  * HeaderView   GDK_Left   Move focus to folder view
944  * FolderView   GDK_Right  Move focus to header view
945  *
946  * There is no need to scroll to selected row, the widgets will be the
947  * responsibles of doing that (probably managing the focus-in event
948  */
949 static gboolean 
950 on_inner_widgets_key_pressed (GtkWidget *widget,
951                               GdkEventKey *event,
952                               gpointer user_data)
953 {
954         ModestMainWindowPrivate *priv;
955
956         priv = MODEST_MAIN_WINDOW_GET_PRIVATE (user_data);
957
958         /* Do nothing if we're in SIMPLE style */
959         if (priv->style == MODEST_MAIN_WINDOW_STYLE_SIMPLE)
960                 return FALSE;
961
962         if (MODEST_IS_HEADER_VIEW (widget) && event->keyval == GDK_Left)
963                 gtk_widget_grab_focus (GTK_WIDGET (priv->folder_view));
964         else if (MODEST_IS_FOLDER_VIEW (widget) && event->keyval == GDK_Right)
965                 gtk_widget_grab_focus (GTK_WIDGET (priv->header_view));
966
967         return FALSE;
968 }
969
970 static void
971 set_alignment (GtkWidget *widget,
972                gpointer data)
973 {
974         gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
975         gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
976 }
977
978 static GtkWidget *
979 create_details_widget (TnyAccount *account)
980 {
981         GtkWidget *vbox;
982         gchar *label;
983
984         vbox = gtk_vbox_new (FALSE, 0);
985
986         /* Account description */
987         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
988                 gchar *device_name;
989
990                 /* Get device name */
991                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
992                                                       MODEST_CONF_DEVICE_NAME, NULL);
993    
994                 label = g_strdup_printf ("%s: %s",
995                                          _("mcen_fi_localroot_description"),
996                                          device_name);
997                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
998                 g_free (device_name);
999                 g_free (label);
1000         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1001                 /* TODO: MMC ? */
1002                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1003         } else {
1004                 GString *proto;
1005
1006                 /* Put proto in uppercase */
1007                 proto = g_string_new (tny_account_get_proto (account));
1008                 proto = g_string_ascii_up (proto);
1009
1010                 label = g_strdup_printf ("%s %s: %s", 
1011                                          proto->str,
1012                                          _("mcen_fi_remoteroot_account"),
1013                                          tny_account_get_name (account));
1014                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1015                 g_string_free (proto, TRUE);
1016                 g_free (label);
1017         }
1018
1019         /* Message count */
1020         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_messages"), 
1021                                  modest_tny_account_get_message_count (account));
1022         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1023         g_free (label);
1024
1025         /* Folder count */
1026         label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_folders"), 
1027                                  modest_tny_account_get_folder_count (account));
1028         gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1029         g_free (label);
1030
1031         /* Size / Date */
1032         if (!strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1033                 /* FIXME: format size */
1034                 label = g_strdup_printf ("%s: %d", _("mcen_fi_rootfolder_size"), 
1035                                          modest_tny_account_get_local_size (account));
1036                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1037                 g_free (label);
1038         } else if (!strcmp (tny_account_get_id (account), MODEST_MMC_ACCOUNT_ID)) {
1039                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new ("FIXME: MMC ?"), FALSE, FALSE, 0);
1040         } else {
1041                 label = g_strdup_printf ("%s: %s", _("mcen_ti_lastupdated"), "08/08/08");
1042                 gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (label), FALSE, FALSE, 0);
1043                 g_free (label);
1044         }
1045
1046         /* Set alignment */
1047         gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) set_alignment, NULL);
1048
1049         return vbox;
1050 }
1051
1052 void 
1053 modest_main_window_set_contents_style (ModestMainWindow *self, 
1054                                        ModestMainWindowContentsStyle style)
1055 {
1056         ModestMainWindowPrivate *priv;
1057         GtkWidget *content;
1058         TnyAccount *account;
1059
1060         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1061
1062         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1063
1064         /* We allow to set the same content style than the previously
1065            set if there are details, because it could happen when we're
1066            selecting different accounts consecutively */
1067         if ((priv->contents_style == style) &&
1068             (priv->contents_style == MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS))
1069                 return;
1070
1071         /* Remove previous child. Delete it if it was an account
1072            details widget */
1073         content = gtk_bin_get_child (GTK_BIN (priv->contents_widget));
1074         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1075                 g_object_ref (content);
1076         gtk_container_remove (GTK_CONTAINER (priv->contents_widget), content);
1077
1078         priv->contents_style = style;
1079
1080         switch (priv->contents_style) {
1081         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_HEADERS:
1082                 wrap_in_scrolled_window (priv->contents_widget, GTK_WIDGET (priv->header_view));
1083                 break;
1084         case MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS:
1085                 /* TODO: show here account details */
1086                 account = TNY_ACCOUNT (modest_folder_view_get_selected (priv->folder_view));
1087                 priv->details_widget = create_details_widget (account);
1088
1089                 wrap_in_scrolled_window (priv->contents_widget, 
1090                                          priv->details_widget);
1091                 break;
1092         default:
1093                 g_return_if_reached ();
1094         }
1095
1096         /* Show */
1097         gtk_widget_show_all (priv->contents_widget);
1098 }
1099
1100 static void 
1101 on_configuration_key_changed (ModestConf* conf, 
1102                               const gchar *key, 
1103                               ModestConfEvent event, 
1104                               ModestMainWindow *self)
1105 {
1106         ModestMainWindowPrivate *priv;
1107         TnyAccount *account;
1108
1109         if (!key || strcmp (key, MODEST_CONF_DEVICE_NAME))
1110                 return;
1111
1112         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1113
1114         if (priv->contents_style != MODEST_MAIN_WINDOW_CONTENTS_STYLE_DETAILS)
1115                 return;
1116
1117         account = (TnyAccount *) modest_folder_view_get_selected (priv->folder_view);
1118         if (TNY_IS_ACCOUNT (account) &&
1119             !strcmp (tny_account_get_id (account), MODEST_LOCAL_FOLDERS_ACCOUNT_ID)) {
1120                 GList *children;
1121                 GtkLabel *label;
1122                 const gchar *device_name;
1123                 gchar *new_text;
1124                 
1125                 /* Get label */
1126                 children = gtk_container_get_children (GTK_CONTAINER (priv->details_widget));
1127                 label = GTK_LABEL (children->data);
1128                 
1129                 device_name = modest_conf_get_string (modest_runtime_get_conf(),
1130                                                       MODEST_CONF_DEVICE_NAME, NULL);
1131                 
1132                 new_text = g_strdup_printf ("%s: %s",
1133                                             _("mcen_fi_localroot_description"),
1134                                             device_name);
1135                 
1136                 gtk_label_set_text (label, new_text);
1137                 gtk_widget_show (GTK_WIDGET (label));
1138                 
1139                 g_free (new_text);
1140                 g_list_free (children);
1141         }
1142 }
1143
1144 static void 
1145 set_toolbar_mode (ModestMainWindow *self, 
1146                   ModestToolBarModes mode)
1147 {
1148         ModestWindowPrivate *parent_priv;
1149         ModestMainWindowPrivate *priv;
1150         GtkAction *sort_action, *refresh_action, *cancel_action;
1151
1152         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1153
1154         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
1155         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1156         
1157         sort_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSort");
1158         refresh_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarSendReceive");
1159         cancel_action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ToolbarCancel");
1160
1161         /* Sets current toolbar mode */
1162         priv->current_toolbar_mode = mode;
1163
1164         /* Show and hide toolbar items */
1165         switch (mode) {
1166         case TOOLBAR_MODE_NORMAL:
1167                 if (sort_action) 
1168                         gtk_action_set_visible (sort_action, TRUE);
1169                 if (refresh_action) 
1170                         gtk_action_set_visible (refresh_action, TRUE);
1171                 if (priv->progress_toolitem) {
1172                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), FALSE);
1173                         gtk_widget_hide (priv->progress_toolitem);
1174                 }
1175                 if (priv->progress_bar)
1176                         gtk_widget_hide (priv->progress_bar);                   
1177                 
1178                 if (cancel_action)
1179                         gtk_action_set_visible (cancel_action, FALSE);
1180                 break;
1181         case TOOLBAR_MODE_TRANSFER:
1182                 if (sort_action)
1183                         gtk_action_set_visible (sort_action, FALSE);
1184                 if (refresh_action)
1185                         gtk_action_set_visible (refresh_action, FALSE);
1186                 if (cancel_action)
1187                         gtk_action_set_visible (cancel_action, TRUE);
1188                 if (priv->progress_toolitem) {
1189                         gtk_tool_item_set_expand (GTK_TOOL_ITEM (priv->progress_toolitem), TRUE);
1190                         gtk_widget_show (priv->progress_toolitem);
1191                 }
1192                 if (priv->progress_bar)
1193                         gtk_widget_show (priv->progress_bar);                   
1194                 break;
1195         default:
1196                 g_return_if_reached ();
1197         }
1198
1199         gtk_widget_show_all (GTK_WIDGET (self));
1200 }
1201
1202 static void
1203 cancel_progressbar (GtkToolButton *toolbutton,
1204                     ModestMainWindow *self)
1205 {
1206         GSList *tmp;
1207         ModestMainWindowPrivate *priv;
1208         
1209         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1210
1211         /* Get operation observers and cancel its current operation */
1212         tmp = priv->progress_widgets;
1213         while (tmp) {
1214                 modest_progress_object_cancel_current_operation (MODEST_PROGRESS_OBJECT(tmp->data));
1215                 tmp=g_slist_next(tmp);
1216         }
1217 }
1218
1219 static gboolean
1220 observers_empty (ModestMainWindow *self)
1221 {
1222         GSList *tmp = NULL;
1223         ModestMainWindowPrivate *priv;
1224         gboolean is_empty = TRUE;
1225         guint pending_ops = 0;
1226  
1227         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1228         tmp = priv->progress_widgets;
1229
1230         /* Check all observers */
1231         while (tmp && is_empty)  {
1232                 pending_ops = modest_progress_object_num_pending_operations (MODEST_PROGRESS_OBJECT(tmp->data));
1233                 is_empty = pending_ops == 0;
1234                 
1235                 tmp = g_slist_next(tmp);
1236         }
1237         
1238         return is_empty;
1239 }
1240
1241 static void
1242 on_queue_changed (ModestMailOperationQueue *queue,
1243                   ModestMailOperation *mail_op,
1244                   ModestMailOperationQueueNotification type,
1245                   ModestMainWindow *self)
1246 {
1247         ModestMainWindowPrivate *priv;
1248         ModestMailOperationId op_id;
1249         ModestToolBarModes mode;
1250         GSList *tmp;
1251         gboolean mode_changed = FALSE;
1252
1253         g_return_if_fail (MODEST_IS_MAIN_WINDOW (self));
1254         priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
1255                
1256         /* Get toolbar mode from operation id*/
1257         op_id = modest_mail_operation_get_id (mail_op);
1258         switch (op_id) {
1259         case MODEST_MAIL_OPERATION_ID_SEND:
1260         case MODEST_MAIL_OPERATION_ID_RECEIVE:
1261                 mode = TOOLBAR_MODE_TRANSFER;
1262                 if (priv->current_toolbar_mode == TOOLBAR_MODE_NORMAL)
1263                         mode_changed = TRUE;
1264                 break;
1265         default:
1266                 mode = TOOLBAR_MODE_NORMAL;
1267                 
1268         }
1269                 
1270                        
1271         /* Add operation observers and change toolbar if neccessary*/
1272         tmp = priv->progress_widgets;
1273         switch (type) {
1274         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED:
1275                 if (mode_changed)
1276                         set_toolbar_mode (self, mode);
1277                 if (mode == TOOLBAR_MODE_TRANSFER) {
1278                         while (tmp) {
1279                                 modest_progress_object_add_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1280                                                                       mail_op);
1281                                 tmp = g_slist_next (tmp);
1282                         }
1283                 }
1284                 break;
1285         case MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED:
1286                 if (mode == TOOLBAR_MODE_TRANSFER) {
1287                         while (tmp) {
1288                                 modest_progress_object_remove_operation (MODEST_PROGRESS_OBJECT (tmp->data),
1289                                                                          mail_op);
1290                                 tmp = g_slist_next (tmp);
1291                         }
1292                         
1293                         /* If no more operations are being observed, NORMAL mode is enabled again */
1294                         if (observers_empty (self))
1295                                 set_toolbar_mode (self, TOOLBAR_MODE_NORMAL);
1296                 }
1297                 break;
1298         }       
1299 }