Unselect all in header window tree selection on setting edit mode
[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 <hildon/hildon-edit-toolbar.h>
35 #include <modest-window-mgr.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
53 typedef enum {
54         CONTENTS_STATE_NONE = 0,
55         CONTENTS_STATE_EMPTY = 1,
56         CONTENTS_STATE_HEADERS = 2
57 } ContentsState;
58
59 typedef enum {
60         EDIT_MODE_COMMAND_NONE = 0,
61         EDIT_MODE_COMMAND_MOVE = 1,
62         EDIT_MODE_COMMAND_DELETE = 2,
63 } EditModeCommand;
64
65 typedef struct _ModestHeaderWindowPrivate ModestHeaderWindowPrivate;
66 struct _ModestHeaderWindowPrivate {
67
68         GtkWidget *header_view;
69         GtkWidget *empty_view;
70         GtkWidget *contents_view;
71         GtkWidget *top_vbox;
72         GtkWidget *edit_toolbar;
73
74         /* state bar */
75         ContentsState contents_state;
76         gboolean edit_mode;
77         EditModeCommand edit_command;
78
79         TnyFolder *folder;
80
81         /* autoscroll */
82         gboolean autoscroll;
83
84         /* banners */
85         GtkWidget *updating_banner;
86         guint updating_banner_timeout;
87
88         /* signals */
89         GSList *sighandlers;
90
91         /* Display state */
92         osso_display_state_t display_state;
93 };
94 #define MODEST_HEADER_WINDOW_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE((o), \
95                                                                           MODEST_TYPE_HEADER_WINDOW, \
96                                                                           ModestHeaderWindowPrivate))
97
98 /* 'private'/'protected' functions */
99 static void modest_header_window_class_init  (ModestHeaderWindowClass *klass);
100 static void modest_header_window_init        (ModestHeaderWindow *obj);
101 static void modest_header_window_finalize    (GObject *obj);
102
103 static void connect_signals (ModestHeaderWindow *self);
104 static void modest_header_window_disconnect_signals (ModestWindow *self);
105
106 static gboolean on_zoom_minus_plus_not_implemented (ModestWindow *window);
107 static void add_to_menu (ModestHeaderWindow *self,
108                          HildonAppMenu *menu,
109                          gchar *label,
110                          GCallback callback);
111 static void setup_menu (ModestHeaderWindow *self);
112 static GtkWidget *create_empty_view (void);
113 static GtkWidget *create_header_view (ModestWindow *progress_window,
114                                       TnyFolder *folder);
115
116 static void update_view (ModestHeaderWindow *self,
117                          TnyFolderChange *change);
118 static void set_contents_state (ModestHeaderWindow *window, 
119                                 ContentsState state);
120
121 static void on_msg_count_changed (ModestHeaderView *header_view,
122                                   TnyFolder *folder,
123                                   TnyFolderChange *change,
124                                   ModestHeaderWindow *header_window);
125 static void on_header_activated (ModestHeaderView *header_view,
126                                  TnyHeader *header,
127                                  GtkTreePath *path,
128                                  ModestHeaderWindow *header_window);
129 static void on_updating_msg_list (ModestHeaderView *header_view,
130                                   gboolean starting,
131                                   gpointer user_data);
132 static void set_edit_mode (ModestHeaderWindow *self,
133                            EditModeCommand command);
134 static void edit_toolbar_button_clicked (HildonEditToolbar *toolbar,
135                                          ModestHeaderWindow *self);
136 static void edit_toolbar_arrow_clicked (HildonEditToolbar *toolbar,
137                                         ModestHeaderWindow *self);
138 static void set_delete_edit_mode (GtkButton *button,
139                                   ModestHeaderWindow *self);
140 static void set_moveto_edit_mode (GtkButton *button,
141                                   ModestHeaderWindow *self);
142 static gboolean on_expose_event(GtkTreeView *header_view,
143                                 GdkEventExpose *event,
144                                 gpointer user_data);
145 static void on_vertical_movement (HildonPannableArea *area,
146                                   HildonMovementDirection direction,
147                                   gdouble x, gdouble y, gpointer user_data);
148
149 /* globals */
150 static GtkWindowClass *parent_class = NULL;
151
152 #define EMPTYVIEW_XALIGN 0.5
153 #define EMPTYVIEW_YALIGN 0.0
154 #define EMPTYVIEW_XSPACE 1.0
155 #define EMPTYVIEW_YSPACE 0.0
156
157
158
159 /************************************************************************/
160
161 GType
162 modest_header_window_get_type (void)
163 {
164         static GType my_type = 0;
165         if (!my_type) {
166                 static const GTypeInfo my_info = {
167                         sizeof(ModestHeaderWindowClass),
168                         NULL,           /* base init */
169                         NULL,           /* base finalize */
170                         (GClassInitFunc) modest_header_window_class_init,
171                         NULL,           /* class finalize */
172                         NULL,           /* class data */
173                         sizeof(ModestHeaderWindow),
174                         1,              /* n_preallocs */
175                         (GInstanceInitFunc) modest_header_window_init,
176                         NULL
177                 };
178                 my_type = g_type_register_static (MODEST_TYPE_WINDOW,
179                                                   "ModestHeaderWindow",
180                                                   &my_info, 0);
181         }
182         return my_type;
183 }
184
185 static void
186 modest_header_window_class_init (ModestHeaderWindowClass *klass)
187 {
188         GObjectClass *gobject_class;
189         gobject_class = (GObjectClass*) klass;
190         ModestWindowClass *modest_window_class = (ModestWindowClass *) klass;
191
192         parent_class            = g_type_class_peek_parent (klass);
193         gobject_class->finalize = modest_header_window_finalize;
194
195         g_type_class_add_private (gobject_class, sizeof(ModestHeaderWindowPrivate));
196         
197         modest_window_class->zoom_minus_func = on_zoom_minus_plus_not_implemented;
198         modest_window_class->zoom_plus_func = on_zoom_minus_plus_not_implemented;
199         modest_window_class->disconnect_signals_func = modest_header_window_disconnect_signals;
200 }
201
202 static void
203 modest_header_window_init (ModestHeaderWindow *obj)
204 {
205         ModestHeaderWindowPrivate *priv;
206
207         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(obj);
208
209         priv->sighandlers = NULL;
210         priv->display_state = OSSO_DISPLAY_ON;
211         
212         priv->header_view = NULL;
213         priv->empty_view = NULL;
214         priv->top_vbox = NULL;
215         priv->edit_mode = FALSE;
216         priv->edit_command = EDIT_MODE_COMMAND_NONE;
217         priv->edit_toolbar = NULL;
218         priv->contents_view = NULL;
219         priv->contents_state = CONTENTS_STATE_NONE;
220         priv->folder = NULL;
221         priv->updating_banner = NULL;
222         priv->updating_banner_timeout = 0;
223         priv->autoscroll = TRUE;
224         
225         modest_window_mgr_register_help_id (modest_runtime_get_window_mgr(),
226                                             GTK_WINDOW(obj),
227                                             "applications_email_headerview");
228 }
229
230 static void
231 modest_header_window_finalize (GObject *obj)
232 {
233         ModestHeaderWindowPrivate *priv;
234
235         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(obj);
236
237         g_object_unref (priv->header_view);
238         g_object_unref (priv->empty_view);
239         g_object_unref (priv->folder);
240
241         /* Sanity check: shouldn't be needed, the window mgr should
242            call this function before */
243         modest_header_window_disconnect_signals (MODEST_WINDOW (obj));  
244
245         if (priv->updating_banner_timeout > 0) {
246                 g_source_remove (priv->updating_banner_timeout);
247                 priv->updating_banner_timeout = 0;
248         }
249         if (priv->updating_banner) {
250                 gtk_widget_destroy (priv->updating_banner);
251                 priv->updating_banner = NULL;
252         }
253
254         G_OBJECT_CLASS(parent_class)->finalize (obj);
255 }
256
257 static void
258 modest_header_window_disconnect_signals (ModestWindow *self)
259 {       
260         ModestHeaderWindowPrivate *priv;        
261         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
262
263         modest_signal_mgr_disconnect_all_and_destroy (priv->sighandlers);
264         priv->sighandlers = NULL;       
265 }
266
267 static void
268 connect_signals (ModestHeaderWindow *self)
269 {       
270         ModestHeaderWindowPrivate *priv;
271         
272         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
273
274         /* header view */
275
276         priv->sighandlers = 
277                 modest_signal_mgr_connect (priv->sighandlers,G_OBJECT(priv->header_view), 
278                                            "msg_count_changed",
279                                            G_CALLBACK(on_msg_count_changed), self);
280         priv->sighandlers =
281                 modest_signal_mgr_connect (priv->sighandlers, G_OBJECT (priv->header_view),
282                                            "header-activated",
283                                            G_CALLBACK (on_header_activated), self);
284         priv->sighandlers = 
285                 modest_signal_mgr_connect (priv->sighandlers,
286                                            G_OBJECT (priv->header_view), 
287                                            "updating-msg-list",
288                                            G_CALLBACK (on_updating_msg_list), 
289                                            self);
290         priv->sighandlers =
291                 modest_signal_mgr_connect (priv->sighandlers,
292                                            G_OBJECT (priv->header_view),
293                                            "expose-event",
294                                            G_CALLBACK (on_expose_event),
295                                            self);
296
297         priv->sighandlers =
298                 modest_signal_mgr_connect (priv->sighandlers,
299                                            G_OBJECT (priv->contents_view), 
300                                            "vertical-movement", 
301                                            G_CALLBACK (on_vertical_movement), 
302                                            self);
303
304         /* TODO: connect header view activate */
305
306         /* window */
307
308         /* we don't register this in sighandlers, as it should be run after disconnecting all signals,
309          * in destroy stage */
310
311         
312 }
313
314 static void 
315 osso_display_event_cb (osso_display_state_t state, 
316                        gpointer data)
317 {
318         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (data);
319
320         priv->display_state = state;
321
322         /* Stop blinking if the screen becomes on */
323         if (priv->display_state == OSSO_DISPLAY_ON)
324                 modest_platform_remove_new_mail_notifications (TRUE);
325 }
326
327 static GtkWidget *
328 create_header_view (ModestWindow *progress_window, TnyFolder *folder)
329 {
330         GtkWidget *header_view;
331
332         header_view  = modest_header_view_new (NULL, MODEST_HEADER_VIEW_STYLE_TWOLINES);
333         modest_header_view_set_folder (MODEST_HEADER_VIEW (header_view), folder, 
334                                        TRUE, progress_window, NULL, NULL);
335         modest_widget_memory_restore (modest_runtime_get_conf (), G_OBJECT(header_view),
336                                       MODEST_CONF_HEADER_VIEW_KEY);
337
338         return header_view;
339 }
340
341 static GtkWidget *
342 create_empty_view (void)
343 {
344         GtkWidget *label = NULL;
345         GtkWidget *align = NULL;
346
347         align = gtk_alignment_new(EMPTYVIEW_XALIGN, EMPTYVIEW_YALIGN, EMPTYVIEW_XSPACE, EMPTYVIEW_YSPACE);
348         label = gtk_label_new (_("mcen_ia_nomessages"));
349         gtk_widget_show (label);
350         gtk_widget_show (align);
351         gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);  
352         gtk_container_add (GTK_CONTAINER (align), label);
353
354         return align;
355 }
356
357 static void
358 on_vertical_movement (HildonPannableArea *area,
359                       HildonMovementDirection direction,
360                       gdouble x, gdouble y, gpointer user_data)
361 {
362         ModestHeaderWindow *self = (ModestHeaderWindow *) user_data;
363         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
364
365         priv->autoscroll = FALSE;
366 }
367
368
369 ModestWindow *
370 modest_header_window_new (TnyFolder *folder)
371 {
372         ModestHeaderWindow *self = NULL;        
373         ModestHeaderWindowPrivate *priv = NULL;
374         HildonProgram *app;
375         GdkPixbuf *window_icon;
376         
377         self  = MODEST_HEADER_WINDOW(g_object_new(MODEST_TYPE_HEADER_WINDOW, NULL));
378         priv = MODEST_HEADER_WINDOW_GET_PRIVATE(self);
379
380         priv->folder = g_object_ref (folder);
381
382         priv->contents_view = hildon_pannable_area_new ();
383
384         priv->header_view  = create_header_view (MODEST_WINDOW (self), folder);
385         priv->empty_view = create_empty_view ();
386         g_object_ref (priv->header_view);
387         g_object_ref (priv->empty_view);
388         setup_menu (self);
389
390         priv->top_vbox = gtk_vbox_new (FALSE, 0);
391         gtk_box_pack_end (GTK_BOX (priv->top_vbox), priv->contents_view, TRUE, TRUE, 0);
392
393         gtk_container_add (GTK_CONTAINER (self), priv->top_vbox);
394
395         gtk_widget_show (priv->contents_view);
396         gtk_widget_show (priv->top_vbox);
397
398         connect_signals (MODEST_HEADER_WINDOW (self));
399
400         update_view (self, NULL);
401
402         /* Load previous osso state, for instance if we are being restored from 
403          * hibernation:  */
404         modest_osso_load_state ();
405
406         /* Get device name */
407         modest_maemo_utils_get_device_name ();
408
409         app = hildon_program_get_instance ();
410         hildon_program_add_window (app, HILDON_WINDOW (self));
411         
412         /* Set window icon */
413         window_icon = modest_platform_get_icon (MODEST_APP_ICON, MODEST_ICON_SIZE_BIG);
414         if (window_icon) {
415                 gtk_window_set_icon (GTK_WINDOW (self), window_icon);
416                 g_object_unref (window_icon);
417         }
418
419         /* Listen for changes in the screen, we don't want to show a
420            led pattern when the display is on for example */
421         osso_hw_set_display_event_cb (modest_maemo_utils_get_osso_context (),
422                                       osso_display_event_cb,
423                                       self); 
424
425         /* Dont't restore settings here, 
426          * because it requires a gtk_widget_show(), 
427          * and we don't want to do that until later,
428          * so that the UI is not visible for non-menu D-Bus activation.
429          */
430
431         return MODEST_WINDOW(self);
432 }
433
434 static gboolean
435 on_zoom_minus_plus_not_implemented (ModestWindow *window)
436 {
437         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (window), FALSE);
438
439         hildon_banner_show_information (NULL, NULL, dgettext("hildon-common-strings", "ckct_ib_cannot_zoom_here"));
440         return FALSE;
441
442 }
443
444 gboolean
445 modest_header_window_screen_is_on (ModestHeaderWindow *self)
446 {
447         ModestHeaderWindowPrivate *priv = NULL;
448
449         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW(self), FALSE);
450
451         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
452         
453         return (priv->display_state == OSSO_DISPLAY_ON) ? TRUE : FALSE;
454 }
455
456 ModestHeaderView *
457 modest_header_window_get_header_view (ModestHeaderWindow *self)
458 {
459         ModestHeaderWindowPrivate *priv = NULL;
460
461         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW(self), FALSE);
462
463         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
464         
465         return MODEST_HEADER_VIEW (priv->header_view);
466 }
467
468 static void add_to_menu (ModestHeaderWindow *self,
469                          HildonAppMenu *menu,
470                          gchar *label,
471                          GCallback callback)
472 {
473         GtkWidget *button;
474
475         button = gtk_button_new_with_label (label);
476         g_signal_connect_after (G_OBJECT (button), "clicked",
477                                 callback, (gpointer) self);
478         hildon_app_menu_append (menu, GTK_BUTTON (button));
479 }
480
481 static void setup_menu (ModestHeaderWindow *self)
482 {
483         ModestHeaderWindowPrivate *priv = NULL;
484         GtkWidget *app_menu;
485
486         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
487
488         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
489
490         app_menu = hildon_app_menu_new ();
491
492         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_viewer_newemail"),
493                      G_CALLBACK (modest_ui_actions_on_new_msg));
494         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_inbox_sendandreceive"),
495                      G_CALLBACK (modest_ui_actions_on_send_receive));
496         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_inbox_messagedetails"),
497                      G_CALLBACK (modest_ui_actions_on_details));
498         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_inbox_sort"),
499                      G_CALLBACK (modest_ui_actions_on_sort));
500         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_inbox_delete"),
501                      G_CALLBACK (set_delete_edit_mode));
502         add_to_menu (self, HILDON_APP_MENU (app_menu), _("mcen_me_inbox_moveto"),
503                      G_CALLBACK (set_moveto_edit_mode));
504
505         hildon_stackable_window_set_main_menu (HILDON_STACKABLE_WINDOW (self), 
506                                                HILDON_APP_MENU (app_menu));
507 }
508
509 static void 
510 update_view (ModestHeaderWindow *self,
511              TnyFolderChange *change)
512 {
513         ModestHeaderWindowPrivate *priv = NULL;
514         gboolean refilter = FALSE;
515         gboolean folder_empty = FALSE;
516         gboolean all_marked_as_deleted = FALSE;
517
518         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
519         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
520         g_return_if_fail (priv->folder);
521
522         if (change != NULL) {
523                 TnyFolderChangeChanged changed;
524
525                 changed = tny_folder_change_get_changed (change);
526                 /* If something changes */
527                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_ALL_COUNT)
528                         folder_empty = (((guint) tny_folder_change_get_new_all_count (change)) == 0);
529                 else
530                         folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (priv->folder))) == 0);
531
532                 if ((changed) & TNY_FOLDER_CHANGE_CHANGED_EXPUNGED_HEADERS)
533                         refilter = TRUE;
534         } else {
535                 folder_empty = (((guint) tny_folder_get_all_count (TNY_FOLDER (priv->folder))) == 0);
536         }
537
538         /* Check if all messages are marked to be deleted */
539         all_marked_as_deleted = modest_header_view_is_empty (MODEST_HEADER_VIEW (priv->header_view));
540         folder_empty = folder_empty || all_marked_as_deleted;
541
542         /* Set style of headers view */
543         set_contents_state (self, folder_empty?CONTENTS_STATE_EMPTY:CONTENTS_STATE_HEADERS);
544
545         if (refilter)
546                 modest_header_view_refilter (MODEST_HEADER_VIEW (priv->header_view));
547 }
548
549 static void 
550 set_contents_state (ModestHeaderWindow *self, 
551                     ContentsState state)
552 {
553         ModestHeaderWindowPrivate *priv = NULL;
554
555         g_return_if_fail (MODEST_IS_HEADER_WINDOW(self));
556         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
557
558         if (priv->contents_state == state)
559                 return;
560
561         /* Remove from container the old content */
562         switch (priv->contents_state) {
563         case CONTENTS_STATE_EMPTY:
564                 gtk_container_remove (GTK_CONTAINER (priv->contents_view), priv->empty_view);
565                 break;
566         case CONTENTS_STATE_HEADERS:
567                 gtk_container_remove (GTK_CONTAINER (priv->contents_view), priv->header_view);
568                 break;
569         case CONTENTS_STATE_NONE:
570                 break;
571         }
572
573         /* Add the new content */
574         switch (state) {
575         case CONTENTS_STATE_EMPTY:
576                 gtk_container_add (GTK_CONTAINER (priv->contents_view), priv->empty_view);
577                 gtk_widget_show (priv->empty_view);
578                 break;
579         case CONTENTS_STATE_HEADERS:
580                 gtk_container_add (GTK_CONTAINER (priv->contents_view), priv->header_view);
581                 gtk_widget_show (priv->header_view);
582                 break;
583         case CONTENTS_STATE_NONE:
584                 break;
585         }
586         priv->contents_state = state;
587         
588 }
589
590 static void
591 on_msg_count_changed (ModestHeaderView *header_view,
592                       TnyFolder *folder,
593                       TnyFolderChange *change,
594                       ModestHeaderWindow *header_window)
595 {       
596         g_return_if_fail (MODEST_IS_HEADER_WINDOW (header_window));
597         
598         update_view (MODEST_HEADER_WINDOW (header_window), change);
599 }
600
601 static void 
602 on_header_activated (ModestHeaderView *header_view,
603                      TnyHeader *header,
604                      GtkTreePath *path,
605                      ModestHeaderWindow *header_window)
606 {
607         modest_ui_actions_on_header_activated (header_view, header, path, MODEST_WINDOW (header_window));
608 }
609
610 static void
611 updating_banner_destroyed (gpointer data,
612                            GObject *where_the_object_was)
613 {
614         ModestHeaderWindowPrivate *priv = NULL;
615
616         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (data);
617
618         priv->updating_banner = NULL;
619 }
620
621 static gboolean
622 show_updating_banner (gpointer user_data)
623 {
624         ModestHeaderWindowPrivate *priv = NULL;
625
626         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (user_data);
627
628         if (priv->updating_banner == NULL) {
629
630                 /* We're outside the main lock */
631                 gdk_threads_enter ();
632                 priv->updating_banner = 
633                         modest_platform_animation_banner (GTK_WIDGET (user_data), NULL,
634                                                           _CS ("ckdg_pb_updating"));
635
636                 /* We need this because banners in Maemo could be
637                    destroyed by dialogs so we need to properly update
638                    our reference to it */
639                 g_object_weak_ref (G_OBJECT (priv->updating_banner),
640                                    updating_banner_destroyed,
641                                    user_data);
642                 gdk_threads_leave ();
643         }
644
645         /* Remove timeout */
646         priv->updating_banner_timeout = 0;
647         return FALSE;
648 }
649
650 /**
651  * We use this function to show/hide a progress banner showing
652  * "Updating" while the header view is being filled. We're not showing
653  * it unless the update takes more than 2 seconds
654  *
655  * If starting = TRUE then the refresh is starting, otherwise it means
656  * that is has just finished
657  */
658 static void 
659 on_updating_msg_list (ModestHeaderView *header_view,
660                       gboolean starting,
661                       gpointer user_data)
662 {
663         ModestHeaderWindowPrivate *priv = NULL;
664
665         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (user_data);
666         
667         /* Remove old timeout */
668         if (priv->updating_banner_timeout > 0) {
669                 g_source_remove (priv->updating_banner_timeout);
670                 priv->updating_banner_timeout = 0;
671         }
672
673         /* Create a new timeout */
674         if (starting) {
675                 priv->updating_banner_timeout = 
676                         g_timeout_add (2000, show_updating_banner, user_data);
677         } else {
678                 /* Remove the banner if exists */
679                 if (priv->updating_banner) {
680                         gtk_widget_destroy (priv->updating_banner);
681                         priv->updating_banner = NULL;
682                 }
683         }
684 }
685
686 static void
687 set_edit_mode (ModestHeaderWindow *self,
688                EditModeCommand command)
689 {
690         ModestHeaderWindowPrivate *priv;
691
692         priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
693         if (priv->edit_toolbar) {
694                 gtk_widget_destroy (priv->edit_toolbar);
695                 priv->edit_toolbar = NULL;
696         }
697
698         if (command == EDIT_MODE_COMMAND_NONE) {
699                 if (priv->edit_mode) {
700                         priv->edit_mode = FALSE;
701                         priv->edit_command = command;
702                         g_object_set (G_OBJECT (priv->header_view), 
703                                       "hildon-ui-mode", HILDON_UI_MODE_NORMAL, 
704                                       NULL);
705                         gtk_widget_queue_resize (priv->header_view);
706                         gtk_window_unfullscreen (GTK_WINDOW (self));
707                 }
708         } else {
709                 if (!priv->edit_mode) {
710                         GtkTreeSelection *selection;
711
712                         g_object_set (G_OBJECT (priv->header_view),
713                                       "hildon-ui-mode", HILDON_UI_MODE_EDIT,
714                                       NULL);
715                         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->header_view));
716                         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
717                         gtk_tree_selection_unselect_all (selection);
718
719                         priv->edit_mode = TRUE;
720                         priv->edit_command = command;
721
722                         /* Setup toolbar */
723                         priv->edit_toolbar = hildon_edit_toolbar_new ();
724                         switch (command) {
725                         case EDIT_MODE_COMMAND_DELETE:
726                                 hildon_edit_toolbar_set_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
727                                                                _("TODO: Select messages to delete"));
728                                 hildon_edit_toolbar_set_button_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
729                                                                       _("TODO: Delete"));
730                                 break;
731                         case EDIT_MODE_COMMAND_MOVE:
732                                 hildon_edit_toolbar_set_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
733                                                                _("TODO: Select messages to move"));
734                                 hildon_edit_toolbar_set_button_label (HILDON_EDIT_TOOLBAR (priv->edit_toolbar),
735                                                                       _("TODO: Move"));
736                                 break;
737                         case EDIT_MODE_COMMAND_NONE:
738                                 g_assert ("Shouldn't reach");
739                         }
740                         gtk_box_pack_start (GTK_BOX (priv->top_vbox), priv->edit_toolbar, FALSE, FALSE, 0);
741                         g_signal_connect (G_OBJECT (priv->edit_toolbar), "button-clicked",
742                                           G_CALLBACK (edit_toolbar_button_clicked), (gpointer) self);
743                         g_signal_connect (G_OBJECT (priv->edit_toolbar), "arrow-clicked",
744                                           G_CALLBACK (edit_toolbar_arrow_clicked), (gpointer) self);
745                         gtk_widget_show (priv->edit_toolbar);
746
747                         gtk_widget_queue_resize (priv->header_view);
748                         gtk_window_fullscreen (GTK_WINDOW (self));
749                 }
750         }
751 }
752
753 static void
754 edit_toolbar_button_clicked (HildonEditToolbar *toolbar,
755                              ModestHeaderWindow *self)
756 {
757         set_edit_mode (self, EDIT_MODE_COMMAND_NONE);
758 }
759
760 static void
761 edit_toolbar_arrow_clicked (HildonEditToolbar *toolbar,
762                             ModestHeaderWindow *self)
763 {
764         set_edit_mode (self, EDIT_MODE_COMMAND_NONE);
765 }
766
767 static void
768 set_delete_edit_mode (GtkButton *button,
769                       ModestHeaderWindow *self)
770 {
771         set_edit_mode (self, EDIT_MODE_COMMAND_DELETE);
772 }
773
774 static void
775 set_moveto_edit_mode (GtkButton *button,
776                     ModestHeaderWindow *self)
777 {
778         set_edit_mode (self, EDIT_MODE_COMMAND_MOVE);
779 }
780
781 static gboolean 
782 on_expose_event(GtkTreeView *header_view,
783                 GdkEventExpose *event,
784                 gpointer user_data)
785 {
786         ModestHeaderWindow *self = (ModestHeaderWindow *) user_data;
787         ModestHeaderWindowPrivate *priv = MODEST_HEADER_WINDOW_GET_PRIVATE (self);
788
789         g_return_val_if_fail (MODEST_IS_HEADER_WINDOW (self), FALSE);
790
791         if (priv->autoscroll)
792                 hildon_pannable_area_jump_to (HILDON_PANNABLE_AREA (priv->contents_view), 0.0, 0.0);
793
794         return FALSE;
795 }