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