Add proper window title to ModestHeaderWindow
[modest] / src / hildon2 / modest-header-window.c
1 /* Copyright (c) 2008, 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 <modest-header-window.h>
31 #include <modest-osso-state-saving.h>
32 #include <libosso.h>
33 #include <hildon/hildon-pannable-area.h>
34 #include <modest-window-mgr.h>
35 #include <modest-window-priv.h>
36 #include <modest-signal-mgr.h>
37 #include <modest-runtime.h>
38 #include <modest-platform.h>
39 #include <modest-maemo-utils.h>
40 #include <modest-icon-names.h>
41 #include <modest-ui-constants.h>
42 #include <modest-account-mgr.h>
43 #include <modest-account-mgr-helpers.h>
44 #include <modest-defs.h>
45 #include <modest-widget-memory.h>
46 #include <modest-ui-actions.h>
47 #include <modest-platform.h>
48 #include <modest-text-utils.h>
49 #include <hildon/hildon-button.h>
50 #include <hildon/hildon-program.h>
51 #include <hildon/hildon-banner.h>
52 #include <modest-ui-dimming-rules.h>
53 #include <modest-tny-folder.h>
54
55 typedef enum {
56         CONTENTS_STATE_NONE = 0,
57         CONTENTS_STATE_EMPTY = 1,
58         CONTENTS_STATE_HEADERS = 2
59 } ContentsState;
60
61 typedef enum {
62         EDIT_MODE_COMMAND_MOVE = 1,
63         EDIT_MODE_COMMAND_DELETE = 2,
64 } EditModeCommand;
65
66 typedef struct _ModestHeaderWindowPrivate ModestHeaderWindowPrivate;
67 struct _ModestHeaderWindowPrivate {
68
69         GtkWidget *header_view;
70         GtkWidget *empty_view;
71         GtkWidget *contents_view;
72         GtkWidget *top_vbox;
73
74         /* state bar */
75         ContentsState contents_state;
76
77         TnyFolder *folder;
78
79         /* autoscroll */
80         gboolean autoscroll;
81
82         /* banners */
83         GtkWidget *updating_banner;
84         guint updating_banner_timeout;
85
86         /* signals */
87         GSList *sighandlers;
88         gulong queue_change_handler;
89
90         /* Display state */
91         osso_display_state_t display_state;
92
93         /* progress hint */
94         gboolean progress_hint;
95 };
96 #define MODEST_HEADER_WINDOW_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE((o), \
97                                                                           MODEST_TYPE_HEADER_WINDOW, \
98                                                                           ModestHeaderWindowPrivate))
99
100 /* 'private'/'protected' functions */
101 static void modest_header_window_class_init  (ModestHeaderWindowClass *klass);
102 static void modest_header_window_init        (ModestHeaderWindow *obj);
103 static void modest_header_window_finalize    (GObject *obj);
104
105 static void connect_signals (ModestHeaderWindow *self);
106 static void modest_header_window_disconnect_signals (ModestWindow *self);
107
108 static void setup_menu (ModestHeaderWindow *self);
109 static GtkWidget *create_empty_view (void);
110 static GtkWidget *create_header_view (ModestWindow *progress_window,
111                                       TnyFolder *folder);
112
113 static void update_view (ModestHeaderWindow *self,
114                          TnyFolderChange *change);
115 static void set_contents_state (ModestHeaderWindow *window, 
116                                 ContentsState state);
117
118 static void on_msg_count_changed (ModestHeaderView *header_view,
119                                   TnyFolder *folder,
120                                   TnyFolderChange *change,
121                                   ModestHeaderWindow *header_window);
122 static void on_header_activated (ModestHeaderView *header_view,
123                                  TnyHeader *header,
124                                  GtkTreePath *path,
125                                  ModestHeaderWindow *header_window);
126 static void on_updating_msg_list (ModestHeaderView *header_view,
127                                   gboolean starting,
128                                   gpointer user_data);
129 static void set_delete_edit_mode (GtkButton *button,
130                                   ModestHeaderWindow *self);
131 static void set_moveto_edit_mode (GtkButton *button,
132                                   ModestHeaderWindow *self);
133 static gboolean on_expose_event(GtkTreeView *header_view,
134                                 GdkEventExpose *event,
135                                 gpointer user_data);
136 static void on_vertical_movement (HildonPannableArea *area,
137                                   HildonMovementDirection direction,
138                                   gdouble x, gdouble y, gpointer user_data);
139 static void set_progress_hint    (ModestHeaderWindow *self, 
140                                   gboolean enabled);
141 static void on_queue_changed    (ModestMailOperationQueue *queue,
142                                  ModestMailOperation *mail_op,
143                                  ModestMailOperationQueueNotification type,
144                                  ModestHeaderWindow *self);
145 static void modest_header_window_show_toolbar   (ModestWindow *window,
146                                                  gboolean show_toolbar);
147 static void modest_header_window_pack_toolbar (ModestHildon2Window *self,
148                                                GtkPackType pack_type,
149                                                GtkWidget *toolbar);
150
151
152 /* globals */
153 static GtkWindowClass *parent_class = NULL;
154
155 #define EMPTYVIEW_XALIGN 0.5
156 #define EMPTYVIEW_YALIGN 0.0
157 #define EMPTYVIEW_XSPACE 1.0
158 #define EMPTYVIEW_YSPACE 0.0
159
160
161
162 /************************************************************************/
163
164 GType
165 modest_header_window_get_type (void)
166 {
167         static GType my_type = 0;
168         if (!my_type) {
169                 static const GTypeInfo my_info = {
170                         sizeof(ModestHeaderWindowClass),
171                         NULL,           /* base init */
172                         NULL,           /* base finalize */
173                         (GClassInitFunc) modest_header_window_class_init,
174                         NULL,           /* class finalize */
175                         NULL,           /* class data */
176                         sizeof(ModestHeaderWindow),
177                         1,              /* n_preallocs */
178                         (GInstanceInitFunc) modest_header_window_init,
179                         NULL
180                 };
181                 my_type = g_type_register_static (MODEST_TYPE_HILDON2_WINDOW,
182                                                   "ModestHeaderWindow",
183                                                   &my_info, 0);
184         }
185         return my_type;
186 }
187
188 static void
189 modest_header_window_class_init (ModestHeaderWindowClass *klass)
190 {
191         GObjectClass *gobject_class;
192         gobject_class = (GObjectClass*) klass;
193         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
194         ModestHildon2WindowClass *modest_hildon2_window_class = (ModestHildon2WindowClass *) klass;
195
196         parent_class            = g_type_class_peek_parent (klass);
197         gobject_class->finalize = modest_header_window_finalize;
198
199         g_type_class_add_private (gobject_class, sizeof(ModestHeaderWindowPrivate));
200         
201         modest_window_class->show_toolbar_func = modest_header_window_show_toolbar;
202         modest_window_class->disconnect_signals_func = modest_header_window_disconnect_signals;
203         modest_hildon2_window_class->pack_toolbar_func = modest_header_window_pack_toolbar;
204 }
205
206 static void
207 modest_header_window_init (ModestHeaderWindow *obj)
208 {
209         ModestHeaderWindowPrivate *priv;
210
211         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(obj);
212
213         priv->sighandlers = NULL;
214         priv->display_state = OSSO_DISPLAY_ON;
215         
216         priv->header_view = NULL;
217         priv->empty_view = NULL;
218         priv->top_vbox = NULL;
219         priv->contents_view = NULL;
220         priv->contents_state = CONTENTS_STATE_NONE;
221         priv->folder = NULL;
222         priv->updating_banner = NULL;
223         priv->updating_banner_timeout = 0;
224         priv->autoscroll = TRUE;
225         priv->progress_hint = FALSE;
226         priv->queue_change_handler = 0;
227         
228         modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
229                                             GTK_WINDOW(obj),
230                                             "applications_email_headerview");
231 }
232
233 static void
234 modest_header_window_finalize (GObject *obj)
235 {
236         ModestHeaderWindowPrivate *priv;
237
238         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(obj);
239
240         g_object_unref (priv->header_view);
241         g_object_unref (priv->empty_view);
242         g_object_unref (priv->folder);
243
244         /* Sanity check: shouldn't be needed, the window mgr should
245            call this function before */
246         modest_header_window_disconnect_signals (MODEST_WINDOW (obj));  
247
248         if (priv->updating_banner_timeout > 0) {
249                 g_source_remove (priv->updating_banner_timeout);
250                 priv->updating_banner_timeout = 0;
251         }
252         if (priv->updating_banner) {
253                 gtk_widget_destroy (priv->updating_banner);
254                 priv->updating_banner = NULL;
255         }
256
257         G_OBJECT_CLASS(parent_class)->finalize (obj);
258 }
259
260 static void
261 modest_header_window_disconnect_signals (ModestWindow *self)
262 {       
263         ModestHeaderWindowPrivate *priv;        
264         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
265
266         if (g_signal_handler_is_connected (G_OBJECT (modest_runtime_get_mail_operation_queue ()), 
267                                            priv->queue_change_handler))
268                 g_signal_handler_disconnect (G_OBJECT (modest_runtime_get_mail_operation_queue ()), 
269                                              priv->queue_change_handler);
270
271         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
272         priv->sighandlers = NULL;
273
274 }
275
276 static void
277 connect_signals (ModestHeaderWindow *self)
278 {       
279         ModestHeaderWindowPrivate *priv;
280         
281         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
282
283         /* header view */
284
285         priv->sighandlers = 
286                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), 
287                                            "msg_count_changed",
288                                            G_CALLBACK(on_msg_count_changed), self);
289         priv->sighandlers =
290                 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT (priv->header_view),
291                                            "header-activated",
292                                            G_CALLBACK (on_header_activated), self);
293         priv->sighandlers = 
294                 modest_signal_mgr_connect (priv->sighandlers,
295                                            G_OBJECT (priv->header_view), 
296                                            "updating-msg-list",
297                                            G_CALLBACK (on_updating_msg_list), 
298                                            self);
299         priv->sighandlers =
300                 modest_signal_mgr_connect (priv->sighandlers,
301                                            G_OBJECT (priv->header_view),
302                                            "expose-event",
303                                            G_CALLBACK (on_expose_event),
304                                            self);
305
306         priv->sighandlers =
307                 modest_signal_mgr_connect (priv->sighandlers,
308                                            G_OBJECT (priv->contents_view), 
309                                            "vertical-movement", 
310                                            G_CALLBACK (on_vertical_movement), 
311                                            self);
312
313         /* Mail Operation Queue */
314         priv->queue_change_handler =
315                 g_signal_connect (G_OBJECT (modest_runtime_get_mail_operation_queue ()),
316                                   "queue-changed",
317                                   G_CALLBACK (on_queue_changed),
318                                   self);
319 }
320
321 static void 
322 osso_display_event_cb (osso_display_state_t state, 
323                        gpointer data)
324 {
325         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (data);
326
327         priv->display_state = state;
328
329         /* Stop blinking if the screen becomes on */
330         if (priv->display_state == OSSO_DISPLAY_ON)
331                 modest_platform_remove_new_mail_notifications (TRUE);
332 }
333
334 static GtkWidget *
335 create_header_view (ModestWindow *progress_window, TnyFolder *folder)
336 {
337         GtkWidget *header_view;
338
339         header_view  = modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_TWOLINES);
340         modest_header_view_set_folder (MODEST_HEADER_VIEW (header_view), folder, 
341                                        TRUE, progress_window, NULL, NULL);
342         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(header_view),
343                                       MODEST_CONF_HEADER_VIEW_KEY);
344
345         return header_view;
346 }
347
348 static GtkWidget *
349 create_empty_view (void)
350 {
351         GtkWidget *label = NULL;
352         GtkWidget *align = NULL;
353
354         align = gtk_alignment_new(EMPTYVIEW_XALIGN, EMPTYVIEW_YALIGN, EMPTYVIEW_XSPACE, EMPTYVIEW_YSPACE);
355         label = gtk_label_new (_("mcen_ia_nomessages"));
356         gtk_widget_show (label);
357         gtk_widget_show (align);
358         gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);  
359         gtk_container_add (GTK_CONTAINER (align), label);
360
361         return align;
362 }
363
364 static void
365 on_vertical_movement (HildonPannableArea *area,
366                       HildonMovementDirection direction,
367                       gdouble x, gdouble y, gpointer user_data)
368 {
369         ModestHeaderWindow *self = (ModestHeaderWindow *) user_data;
370         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
371
372         priv->autoscroll = FALSE;
373 }
374
375
376 ModestWindow *
377 modest_header_window_new (TnyFolder *folder)
378 {
379         ModestHeaderWindow *self = NULL;        
380         ModestHeaderWindowPrivate *priv = NULL;
381         HildonProgram *app;
382         GdkPixbuf *window_icon;
383         
384         self  = MODEST_HEADER_WINDOW(g_object_new(MODEST_TYPE_HEADER_WINDOW, NULL));
385         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
386
387         priv->folder = g_object_ref (folder);
388
389         priv->contents_view = hildon_pannable_area_new ();
390
391         priv->header_view  = create_header_view (MODEST_WINDOW (self), folder);
392         priv->empty_view = create_empty_view ();
393         g_object_ref (priv->header_view);
394         g_object_ref (priv->empty_view);
395         setup_menu (self);
396
397         priv->top_vbox = gtk_vbox_new (FALSE, 0);
398         gtk_box_pack_end (GTK_BOX (priv->top_vbox), priv->contents_view, TRUE, TRUE, 0);
399
400         gtk_container_add (GTK_CONTAINER (self), priv->top_vbox);
401
402         gtk_widget_show (priv->contents_view);
403         gtk_widget_show (priv->top_vbox);
404
405         connect_signals (MODEST_HEADER_WINDOW (self));
406
407         update_view (self, NULL);
408
409         /* Load previous osso state, for instance if we are being restored from 
410          * hibernation:  */
411         modest_osso_load_state ();
412
413         /* Get device name */
414         modest_maemo_utils_get_device_name ();
415
416         app = hildon_program_get_instance ();
417         hildon_program_add_window (app, HILDON_WINDOW (self));
418         
419         /* Set window icon */
420         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
421         if (window_icon) {
422                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
423                 g_object_unref (window_icon);
424         }
425
426         /* Set window title */
427         if (TNY_IS_FOLDER (folder)) {
428                 gchar *folder_name;
429
430                 folder_name = modest_tny_folder_get_display_name (folder);
431                 gtk_window_set_title (GTK_WINDOW (self), folder_name);
432                 g_free (folder_name);
433         }
434
435         /* Listen for changes in the screen, we don't want to show a
436            led pattern when the display is on for example */
437         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
438                                       osso_display_event_cb,
439                                       self); 
440
441         /* Dont't restore settings here, 
442          * because it requires a gtk_widget_show(), 
443          * and we don't want to do that until later,
444          * so that the UI is not visible for non-menu D-Bus activation.
445          */
446
447         /* setup edit modes */
448         modest_hildon2_window_register_edit_mode (MODEST_HILDON2_WINDOW (self), EDIT_MODE_COMMAND_DELETE,
449                                                   _("TODO: Select messages to delete"), _("TODO: Delete"),
450                                                   GTK_TREE_VIEW (priv->header_view),
451                                                   GTK_SELECTION_MULTIPLE,
452                                                   EDIT_MODE_CALLBACK (modest_ui_actions_on_edit_mode_delete_message));
453         modest_hildon2_window_register_edit_mode (MODEST_HILDON2_WINDOW (self), EDIT_MODE_COMMAND_MOVE,
454                                                   _("TODO: Select messages to move"), _("TODO: Move"),
455                                                   GTK_TREE_VIEW (priv->header_view),
456                                                   GTK_SELECTION_MULTIPLE,
457                                                   EDIT_MODE_CALLBACK (modest_ui_actions_on_edit_mode_move_to));
458
459         return MODEST_WINDOW(self);
460 }
461
462 gboolean
463 modest_header_window_screen_is_on (ModestHeaderWindow *self)
464 {
465         ModestHeaderWindowPrivate *priv = NULL;
466
467         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW(self), FALSE);
468
469         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
470         
471         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
472 }
473
474 ModestHeaderView *
475 modest_header_window_get_header_view (ModestHeaderWindow *self)
476 {
477         ModestHeaderWindowPrivate *priv = NULL;
478
479         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW(self), FALSE);
480
481         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
482         
483         return MODEST_HEADER_VIEW (priv->header_view);
484 }
485
486 static void setup_menu (ModestHeaderWindow *self)
487 {
488         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
489
490         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_moveto"),
491                                            APP_MENU_CALLBACK (set_moveto_edit_mode),
492                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_delete));
493         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_delete"),
494                                            APP_MENU_CALLBACK (set_delete_edit_mode),
495                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_move_to));
496         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_messagedetails"),
497                                            APP_MENU_CALLBACK (modest_ui_actions_on_details),
498                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_details));
499         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_sort"),
500                                            APP_MENU_CALLBACK (modest_ui_actions_on_sort),
501                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_sort));
502         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_viewer_newemail"),
503                                            APP_MENU_CALLBACK (modest_ui_actions_on_new_msg),
504                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_new_msg));
505         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_inbox_sendandreceive"),
506                                            APP_MENU_CALLBACK (modest_ui_actions_on_send_receive),
507                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_send_receive));
508         modest_hildon2_window_add_to_menu (MODEST_HILDON2_WINDOW (self), _("mcen_me_outbox_cancelsend"),
509                                            APP_MENU_CALLBACK (modest_ui_actions_cancel_send),
510                                            MODEST_DIMMING_CALLBACK (modest_ui_dimming_rules_on_cancel_sending_all));
511 }
512
513 static void 
514 update_view (ModestHeaderWindow *self,
515              TnyFolderChange *change)
516 {
517         ModestHeaderWindowPrivate *priv = NULL;
518         gboolean refilter = FALSE;
519         gboolean folder_empty = FALSE;
520         gboolean all_marked_as_deleted = FALSE;
521
522         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
523         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
524         g_return_if_fail (priv->folder);
525
526         if (change != NULL) {
527                 TnyFolderChangeChanged changed;
528
529                 changed = tny_folder_change_get_changed (change);
530                 /* If something changes */
531                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
532                         folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
533                 else
534                         folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (priv->folder))) == 0);
535
536                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
537                         refilter = TRUE;
538         } else {
539                 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (priv->folder))) == 0);
540         }
541
542         /* Check if all messages are marked to be deleted */
543         all_marked_as_deleted = modest_header_view_is_empty (MODEST_HEADER_VIEW (priv->header_view));
544         folder_empty = folder_empty || all_marked_as_deleted;
545
546         /* Set style of headers view */
547         set_contents_state (self, folder_empty?CONTENTS_STATE_EMPTY:CONTENTS_STATE_HEADERS);
548
549         if (refilter)
550                 modest_header_view_refilter (MODEST_HEADER_VIEW (priv->header_view));
551 }
552
553 static void 
554 set_contents_state (ModestHeaderWindow *self, 
555                     ContentsState state)
556 {
557         ModestHeaderWindowPrivate *priv = NULL;
558
559         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
560         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
561
562         if (priv->contents_state == state)
563                 return;
564
565         /* Remove from container the old content */
566         switch (priv->contents_state) {
567         case CONTENTS_STATE_EMPTY:
568                 gtk_container_remove (GTK_CONTAINER (priv->contents_view), priv->empty_view);
569                 break;
570         case CONTENTS_STATE_HEADERS:
571                 gtk_container_remove (GTK_CONTAINER (priv->contents_view), priv->header_view);
572                 break;
573         case CONTENTS_STATE_NONE:
574                 break;
575         }
576
577         /* Add the new content */
578         switch (state) {
579         case CONTENTS_STATE_EMPTY:
580                 gtk_container_add (GTK_CONTAINER (priv->contents_view), priv->empty_view);
581                 gtk_widget_show (priv->empty_view);
582                 break;
583         case CONTENTS_STATE_HEADERS:
584                 gtk_container_add (GTK_CONTAINER (priv->contents_view), priv->header_view);
585                 gtk_widget_show (priv->header_view);
586                 break;
587         case CONTENTS_STATE_NONE:
588                 break;
589         }
590         priv->contents_state = state;
591         
592 }
593
594 static void
595 on_msg_count_changed (ModestHeaderView *header_view,
596                       TnyFolder *folder,
597                       TnyFolderChange *change,
598                       ModestHeaderWindow *header_window)
599 {       
600         g_return_if_fail (MODEST_IS_HEADER_WINDOW (header_window));
601         
602         update_view (MODEST_HEADER_WINDOW (header_window), change);
603 }
604
605 static void 
606 on_header_activated (ModestHeaderView *header_view,
607                      TnyHeader *header,
608                      GtkTreePath *path,
609                      ModestHeaderWindow *header_window)
610 {
611         modest_ui_actions_on_header_activated (header_view, header, path, MODEST_WINDOW (header_window));
612 }
613
614 static void
615 updating_banner_destroyed (gpointer data,
616                            GObject *where_the_object_was)
617 {
618         ModestHeaderWindowPrivate *priv = NULL;
619
620         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (data);
621
622         priv->updating_banner = NULL;
623 }
624
625 static gboolean
626 show_updating_banner (gpointer user_data)
627 {
628         ModestHeaderWindowPrivate *priv = NULL;
629
630         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (user_data);
631
632         if (priv->updating_banner == NULL) {
633
634                 /* We're outside the main lock */
635                 gdk_threads_enter ();
636                 priv->updating_banner = 
637                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
638                                                           _CS ("ckdg_pb_updating"));
639
640                 /* We need this because banners in Maemo could be
641                    destroyed by dialogs so we need to properly update
642                    our reference to it */
643                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
644                                    updating_banner_destroyed,
645                                    user_data);
646                 gdk_threads_leave ();
647         }
648
649         /* Remove timeout */
650         priv->updating_banner_timeout = 0;
651         return FALSE;
652 }
653
654 /**
655  * We use this function to show/hide a progress banner showing
656  * "Updating" while the header view is being filled. We're not showing
657  * it unless the update takes more than 2 seconds
658  *
659  * If starting = TRUE then the refresh is starting, otherwise it means
660  * that is has just finished
661  */
662 static void 
663 on_updating_msg_list (ModestHeaderView *header_view,
664                       gboolean starting,
665                       gpointer user_data)
666 {
667         ModestHeaderWindowPrivate *priv = NULL;
668
669         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (user_data);
670         
671         /* Remove old timeout */
672         if (priv->updating_banner_timeout > 0) {
673                 g_source_remove (priv->updating_banner_timeout);
674                 priv->updating_banner_timeout = 0;
675         }
676
677         /* Create a new timeout */
678         if (starting) {
679                 priv->updating_banner_timeout = 
680                         g_timeout_add (2000, show_updating_banner, user_data);
681         } else {
682                 /* Remove the banner if exists */
683                 if (priv->updating_banner) {
684                         gtk_widget_destroy (priv->updating_banner);
685                         priv->updating_banner = NULL;
686                 }
687         }
688 }
689
690 static void
691 set_delete_edit_mode (GtkButton *button,
692                       ModestHeaderWindow *self)
693 {
694         modest_hildon2_window_set_edit_mode (MODEST_HILDON2_WINDOW (self), EDIT_MODE_COMMAND_DELETE);
695 }
696
697 static void
698 set_moveto_edit_mode (GtkButton *button,
699                     ModestHeaderWindow *self)
700 {
701         modest_hildon2_window_set_edit_mode (MODEST_HILDON2_WINDOW (self), EDIT_MODE_COMMAND_MOVE);
702 }
703
704 static gboolean 
705 on_expose_event(GtkTreeView *header_view,
706                 GdkEventExpose *event,
707                 gpointer user_data)
708 {
709         ModestHeaderWindow *self = (ModestHeaderWindow *) user_data;
710         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
711
712         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (self), FALSE);
713
714         if (priv->autoscroll)
715                 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (priv->contents_view), 0.0, 0.0);
716
717         return FALSE;
718 }
719
720 static gboolean
721 set_toolbar_transfer_mode (ModestHeaderWindow *self)
722 {
723         ModestHeaderWindowPrivate *priv = NULL;
724         
725         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (self), FALSE);
726
727         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
728
729         set_progress_hint (self, TRUE);
730         
731         return FALSE;
732 }
733
734 static void 
735 set_progress_hint (ModestHeaderWindow *self, 
736                    gboolean enabled)
737 {
738         ModestWindowPrivate *parent_priv;
739         ModestHeaderWindowPrivate *priv;
740
741         g_return_if_fail (MODEST_IS_HEADER_WINDOW (self));
742
743         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
744         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
745                         
746         /* Sets current progress hint */
747         priv->progress_hint = enabled;
748
749         if (GTK_WIDGET_VISIBLE (self)) {
750                 hildon_gtk_window_set_progress_indicator (GTK_WINDOW (self), enabled?1:0);
751         }
752
753 }
754
755 gboolean 
756 modest_header_window_toolbar_on_transfer_mode     (ModestHeaderWindow *self)
757 {
758         ModestHeaderWindowPrivate *priv= NULL; 
759
760         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (self), FALSE);
761         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
762
763         return priv->progress_hint;
764 }
765
766 static void
767 modest_header_window_show_toolbar (ModestWindow *self,
768                                    gboolean show_toolbar)
769 {
770         ModestHeaderWindowPrivate *priv = NULL;
771         ModestWindowPrivate *parent_priv;
772
773         parent_priv = MODEST_WINDOW_GET_PRIVATE(self);
774         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
775
776         if (modest_header_window_transfer_mode_enabled (MODEST_HEADER_WINDOW (self))) 
777                 set_progress_hint (MODEST_HEADER_WINDOW (self), TRUE);
778         else
779                 set_progress_hint (MODEST_HEADER_WINDOW (self), FALSE);
780 }
781
782 gboolean 
783 modest_header_window_transfer_mode_enabled (ModestHeaderWindow *self)
784 {
785         ModestHeaderWindowPrivate *priv;
786         
787         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (self), FALSE);   
788         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
789
790         return priv->progress_hint;
791 }
792
793 static void 
794 on_mail_operation_started (ModestMailOperation *mail_op,
795                            gpointer user_data)
796 {
797         ModestHeaderWindow *self;
798         ModestMailOperationTypeOperation op_type;
799         GObject *source = NULL;
800
801         self = MODEST_HEADER_WINDOW (user_data);
802         op_type = modest_mail_operation_get_type_operation (mail_op);
803         source = modest_mail_operation_get_source(mail_op);
804         if (G_OBJECT (self) == source) {
805                 set_toolbar_transfer_mode(self);
806         }
807         g_object_unref (source);
808 }
809
810 static void 
811 on_mail_operation_finished (ModestMailOperation *mail_op,
812                             gpointer user_data)
813 {
814         ModestHeaderWindow *self;
815         ModestMailOperationTypeOperation op_type;
816         GSList *operations = NULL;
817         ModestMailOperationQueue *queue;
818
819         self = MODEST_HEADER_WINDOW (user_data);
820         op_type = modest_mail_operation_get_type_operation (mail_op);
821
822         queue = modest_runtime_get_mail_operation_queue ();
823         operations = modest_mail_operation_queue_get_by_source (queue, user_data);
824
825         /* There should be at least the current one */
826         if (!operations)
827                 g_return_if_reached ();
828
829         /* Don't disable the progress hint if there are more pending
830            operations from this window */
831         if (g_slist_length (operations) == 1)
832                 set_progress_hint (self, FALSE);
833
834         g_slist_free (operations);
835         modest_ui_actions_check_menu_dimming_rules (MODEST_WINDOW (self));
836 }
837
838 static void
839 on_queue_changed (ModestMailOperationQueue *queue,
840                   ModestMailOperation *mail_op,
841                   ModestMailOperationQueueNotification type,
842                   ModestHeaderWindow *self)
843 {
844         ModestHeaderWindowPrivate *priv;
845
846         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
847
848         /* If this operations was created by another window, do nothing */
849         if (!modest_mail_operation_is_mine (mail_op, G_OBJECT(self))) 
850                 return;
851
852         if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_ADDED) {
853                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
854                                                                G_OBJECT (mail_op),
855                                                                "operation-started",
856                                                                G_CALLBACK (on_mail_operation_started),
857                                                                self);
858                 priv->sighandlers = modest_signal_mgr_connect (priv->sighandlers,
859                                                                G_OBJECT (mail_op),
860                                                                "operation-finished",
861                                                                G_CALLBACK (on_mail_operation_finished),
862                                                                self);
863         } else if (type == MODEST_MAIL_OPERATION_QUEUE_OPERATION_REMOVED) {
864                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
865                                                                   G_OBJECT (mail_op),
866                                                                   "operation-started");
867                 priv->sighandlers = modest_signal_mgr_disconnect (priv->sighandlers,
868                                                                   G_OBJECT (mail_op),
869                                                                   "operation-finished");
870         }
871 }
872
873 static void
874 modest_header_window_pack_toolbar (ModestHildon2Window *self,
875                                    GtkPackType pack_type,
876                                    GtkWidget *toolbar)
877 {
878         ModestHeaderWindowPrivate *priv;
879
880         g_return_if_fail (MODEST_IS_HEADER_WINDOW (self));
881         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
882
883         if (pack_type == GTK_PACK_START) {
884                 gtk_box_pack_start (GTK_BOX (priv->top_vbox), toolbar, FALSE, FALSE, 0);
885         } else {
886                 gtk_box_pack_end (GTK_BOX (priv->top_vbox), toolbar, FALSE, FALSE, 0);
887         }
888 }