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