If no connection is available and bs embedded image is not fetched, show
[modest] / src / widgets / modest-folder-view.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <glib/gi18n.h>
31 #include <string.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <tny-account-store-view.h>
34 #include <tny-gtk-account-list-model.h>
35 #include <tny-gtk-folder-list-store.h>
36 #include <tny-gtk-folder-store-tree-model.h>
37 #include <tny-gtk-header-list-model.h>
38 #include <tny-merge-folder.h>
39 #include <tny-folder.h>
40 #include <tny-folder-store-observer.h>
41 #include <tny-account-store.h>
42 #include <tny-account.h>
43 #include <tny-folder.h>
44 #include <tny-camel-folder.h>
45 #include <tny-simple-list.h>
46 #include <tny-camel-account.h>
47 #include <modest-defs.h>
48 #include <modest-tny-account.h>
49 #include <modest-tny-folder.h>
50 #include <modest-tny-local-folders-account.h>
51 #include <modest-tny-outbox-account.h>
52 #include <modest-marshal.h>
53 #include <modest-icon-names.h>
54 #include <modest-tny-account-store.h>
55 #include <modest-tny-local-folders-account.h>
56 #include <modest-text-utils.h>
57 #include <modest-runtime.h>
58 #include "modest-folder-view.h"
59 #include <modest-platform.h>
60 #include <modest-widget-memory.h>
61 #include <modest-ui-actions.h>
62 #include "modest-dnd.h"
63 #include "modest-ui-constants.h"
64 #include "widgets/modest-window.h"
65 #include <modest-account-protocol.h>
66
67 /* Folder view drag types */
68 const GtkTargetEntry folder_view_drag_types[] =
69 {
70         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
71         { GTK_TREE_PATH_AS_STRING_LIST, GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
72 };
73
74 /* Default icon sizes for Fremantle style are different */
75 #ifdef MODEST_TOOLKIT_HILDON2
76 #define FOLDER_ICON_SIZE MODEST_ICON_SIZE_BIG
77 #else
78 #define FOLDER_ICON_SIZE MODEST_ICON_SIZE_SMALL
79 #endif
80
81 /* Column names depending on we use list store or tree store */
82 #ifdef MODEST_TOOLKIT_HILDON2
83 #define NAME_COLUMN TNY_GTK_FOLDER_LIST_STORE_NAME_COLUMN
84 #define UNREAD_COLUMN TNY_GTK_FOLDER_LIST_STORE_UNREAD_COLUMN
85 #define ALL_COLUMN TNY_GTK_FOLDER_LIST_STORE_ALL_COLUMN
86 #define TYPE_COLUMN TNY_GTK_FOLDER_LIST_STORE_TYPE_COLUMN
87 #define INSTANCE_COLUMN TNY_GTK_FOLDER_LIST_STORE_INSTANCE_COLUMN
88 #else
89 #define NAME_COLUMN TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN
90 #define UNREAD_COLUMN TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN
91 #define ALL_COLUMN TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN
92 #define TYPE_COLUMN TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN
93 #define INSTANCE_COLUMN TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN
94 #endif
95
96 /* 'private'/'protected' functions */
97 static void modest_folder_view_class_init  (ModestFolderViewClass *klass);
98 static void modest_folder_view_init        (ModestFolderView *obj);
99 static void modest_folder_view_finalize    (GObject *obj);
100 static void modest_folder_view_dispose     (GObject *obj);
101
102 static void         tny_account_store_view_init (gpointer g,
103                                                  gpointer iface_data);
104
105 static void         modest_folder_view_set_account_store (TnyAccountStoreView *self,
106                                                           TnyAccountStore     *account_store);
107
108 static void         on_selection_changed   (GtkTreeSelection *sel,
109                                             gpointer data);
110
111 static void         on_row_activated       (GtkTreeView *treeview,
112                                             GtkTreePath *path,
113                                             GtkTreeViewColumn *column,
114                                             gpointer userdata);
115
116 static void         on_account_removed     (TnyAccountStore *self,
117                                             TnyAccount *account,
118                                             gpointer user_data);
119
120 static void         on_account_inserted    (TnyAccountStore *self,
121                                             TnyAccount *account,
122                                             gpointer user_data);
123
124 static void         on_account_changed    (TnyAccountStore *self,
125                                             TnyAccount *account,
126                                             gpointer user_data);
127
128 static gint         cmp_rows               (GtkTreeModel *tree_model,
129                                             GtkTreeIter *iter1,
130                                             GtkTreeIter *iter2,
131                                             gpointer user_data);
132
133 static gboolean     filter_row             (GtkTreeModel *model,
134                                             GtkTreeIter *iter,
135                                             gpointer data);
136
137 static gboolean     on_key_pressed         (GtkWidget *self,
138                                             GdkEventKey *event,
139                                             gpointer user_data);
140
141 static void         on_configuration_key_changed  (ModestConf* conf,
142                                                    const gchar *key,
143                                                    ModestConfEvent event,
144                                                    ModestConfNotificationId notification_id,
145                                                    ModestFolderView *self);
146
147 /* DnD functions */
148 static void         on_drag_data_get       (GtkWidget *widget,
149                                             GdkDragContext *context,
150                                             GtkSelectionData *selection_data,
151                                             guint info,
152                                             guint time,
153                                             gpointer data);
154
155 static void         on_drag_data_received  (GtkWidget *widget,
156                                             GdkDragContext *context,
157                                             gint x,
158                                             gint y,
159                                             GtkSelectionData *selection_data,
160                                             guint info,
161                                             guint time,
162                                             gpointer data);
163
164 static gboolean     on_drag_motion         (GtkWidget      *widget,
165                                             GdkDragContext *context,
166                                             gint            x,
167                                             gint            y,
168                                             guint           time,
169                                             gpointer        user_data);
170
171 static void         expand_root_items (ModestFolderView *self);
172
173 static gint         expand_row_timeout     (gpointer data);
174
175 static void         setup_drag_and_drop    (GtkTreeView *self);
176
177 static gboolean     _clipboard_set_selected_data (ModestFolderView *folder_view,
178                                                   gboolean delete);
179
180 static void         _clear_hidding_filter (ModestFolderView *folder_view);
181
182 #ifndef MODEST_TOOLKIT_HILDON2
183 static void         on_row_inserted_maybe_select_folder (GtkTreeModel     *tree_model,
184                                                          GtkTreePath      *path,
185                                                          GtkTreeIter      *iter,
186                                                          ModestFolderView *self);
187 #endif
188
189 static void         on_display_name_changed (ModestAccountMgr *self,
190                                              const gchar *account,
191                                              gpointer user_data);
192 static void         update_style (ModestFolderView *self);
193 static void         on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata);
194 static gint         get_cmp_pos (TnyFolderType t, TnyFolder *folder_store);
195 static gboolean     inbox_is_special (TnyFolderStore *folder_store);
196
197 static gboolean     get_inner_models        (ModestFolderView *self,
198                                              GtkTreeModel **filter_model,
199                                              GtkTreeModel **sort_model,
200                                              GtkTreeModel **tny_model);
201 #ifdef MODEST_TOOLKIT_HILDON2
202 static void on_activity_changed (TnyGtkFolderListStore *store,
203                                  gboolean activity,
204                                  ModestFolderView *folder_view);
205 #endif
206
207 enum {
208         FOLDER_SELECTION_CHANGED_SIGNAL,
209         FOLDER_DISPLAY_NAME_CHANGED_SIGNAL,
210         FOLDER_ACTIVATED_SIGNAL,
211         VISIBLE_ACCOUNT_CHANGED_SIGNAL,
212         ACTIVITY_CHANGED_SIGNAL,
213         LAST_SIGNAL
214 };
215
216 typedef struct _ModestFolderViewPrivate ModestFolderViewPrivate;
217 struct _ModestFolderViewPrivate {
218         TnyAccountStore      *account_store;
219         TnyFolderStore       *cur_folder_store;
220
221         TnyFolder            *folder_to_select; /* folder to select after the next update */
222
223         gulong                changed_signal;
224         gulong                account_inserted_signal;
225         gulong                account_removed_signal;
226         gulong                account_changed_signal;
227         gulong                conf_key_signal;
228         gulong                display_name_changed_signal;
229
230         /* not unref this object, its a singlenton */
231         ModestEmailClipboard *clipboard;
232
233         /* Filter tree model */
234         gchar **hidding_ids;
235         guint n_selected;
236         ModestFolderViewFilter filter;
237
238         TnyFolderStoreQuery  *query;
239         gboolean              do_refresh;
240         guint                 timer_expander;
241
242         gchar                *local_account_name;
243         gchar                *visible_account_id;
244         gchar                *mailbox;
245         ModestFolderViewStyle style;
246         ModestFolderViewCellStyle cell_style;
247         gboolean show_message_count;
248
249         gboolean  reselect; /* we use this to force a reselection of the INBOX */
250         gboolean  show_non_move;
251         TnyList   *list_to_move;
252         gboolean  reexpand; /* next time we expose, we'll expand all root folders */
253
254         GtkCellRenderer *messages_renderer;
255
256         gulong                outbox_deleted_handler;
257
258         GSList   *signal_handlers;
259         GdkColor active_color;
260 };
261 #define MODEST_FOLDER_VIEW_GET_PRIVATE(o)                       \
262         (G_TYPE_INSTANCE_GET_PRIVATE((o),                       \
263                                      MODEST_TYPE_FOLDER_VIEW,   \
264                                      ModestFolderViewPrivate))
265 /* globals */
266 static GObjectClass *parent_class = NULL;
267
268 static guint signals[LAST_SIGNAL] = {0};
269
270 GType
271 modest_folder_view_get_type (void)
272 {
273         static GType my_type = 0;
274         if (!my_type) {
275                 static const GTypeInfo my_info = {
276                         sizeof(ModestFolderViewClass),
277                         NULL,           /* base init */
278                         NULL,           /* base finalize */
279                         (GClassInitFunc) modest_folder_view_class_init,
280                         NULL,           /* class finalize */
281                         NULL,           /* class data */
282                         sizeof(ModestFolderView),
283                         1,              /* n_preallocs */
284                         (GInstanceInitFunc) modest_folder_view_init,
285                         NULL
286                 };
287
288                 static const GInterfaceInfo tny_account_store_view_info = {
289                         (GInterfaceInitFunc) tny_account_store_view_init, /* interface_init */
290                         NULL,         /* interface_finalize */
291                         NULL          /* interface_data */
292                 };
293
294
295                 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
296                                                   "ModestFolderView",
297                                                   &my_info, 0);
298
299                 g_type_add_interface_static (my_type,
300                                              TNY_TYPE_ACCOUNT_STORE_VIEW,
301                                              &tny_account_store_view_info);
302         }
303         return my_type;
304 }
305
306 static void
307 modest_folder_view_class_init (ModestFolderViewClass *klass)
308 {
309         GObjectClass *gobject_class;
310         GtkTreeViewClass *treeview_class;
311         gobject_class = (GObjectClass*) klass;
312         treeview_class = (GtkTreeViewClass*) klass;
313
314         parent_class            = g_type_class_peek_parent (klass);
315         gobject_class->finalize = modest_folder_view_finalize;
316         gobject_class->dispose  = modest_folder_view_dispose;
317
318         g_type_class_add_private (gobject_class,
319                                   sizeof(ModestFolderViewPrivate));
320
321         signals[FOLDER_SELECTION_CHANGED_SIGNAL] =
322                 g_signal_new ("folder_selection_changed",
323                               G_TYPE_FROM_CLASS (gobject_class),
324                               G_SIGNAL_RUN_FIRST,
325                               G_STRUCT_OFFSET (ModestFolderViewClass,
326                                                folder_selection_changed),
327                               NULL, NULL,
328                               modest_marshal_VOID__POINTER_BOOLEAN,
329                               G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
330
331         /*
332          * This signal is emitted whenever the currently selected
333          * folder display name is computed. Note that the name could
334          * be different to the folder name, because we could append
335          * the unread messages count to the folder name to build the
336          * folder display name
337          */
338         signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL] =
339                 g_signal_new ("folder-display-name-changed",
340                               G_TYPE_FROM_CLASS (gobject_class),
341                               G_SIGNAL_RUN_FIRST,
342                               G_STRUCT_OFFSET (ModestFolderViewClass,
343                                                folder_display_name_changed),
344                               NULL, NULL,
345                               g_cclosure_marshal_VOID__STRING,
346                               G_TYPE_NONE, 1, G_TYPE_STRING);
347
348         signals[FOLDER_ACTIVATED_SIGNAL] =
349                 g_signal_new ("folder_activated",
350                               G_TYPE_FROM_CLASS (gobject_class),
351                               G_SIGNAL_RUN_FIRST,
352                               G_STRUCT_OFFSET (ModestFolderViewClass,
353                                                folder_activated),
354                               NULL, NULL,
355                               g_cclosure_marshal_VOID__POINTER,
356                               G_TYPE_NONE, 1, G_TYPE_POINTER);
357
358         /*
359          * Emitted whenever the visible account changes
360          */
361         signals[VISIBLE_ACCOUNT_CHANGED_SIGNAL] =
362                 g_signal_new ("visible-account-changed",
363                               G_TYPE_FROM_CLASS (gobject_class),
364                               G_SIGNAL_RUN_FIRST,
365                               G_STRUCT_OFFSET (ModestFolderViewClass,
366                                                visible_account_changed),
367                               NULL, NULL,
368                               g_cclosure_marshal_VOID__STRING,
369                               G_TYPE_NONE, 1, G_TYPE_STRING);
370
371         /*
372          * Emitted when the underlying GtkListStore is updating data
373          */
374         signals[ACTIVITY_CHANGED_SIGNAL] =
375                 g_signal_new ("activity-changed",
376                               G_TYPE_FROM_CLASS (gobject_class),
377                               G_SIGNAL_RUN_FIRST,
378                               G_STRUCT_OFFSET (ModestFolderViewClass,
379                                                activity_changed),
380                               NULL, NULL,
381                               g_cclosure_marshal_VOID__BOOLEAN,
382                               G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
383
384         treeview_class->select_cursor_parent = NULL;
385
386 #ifdef MODEST_TOOLKIT_HILDON2
387         gtk_rc_parse_string ("class \"ModestFolderView\" style \"fremantle-touchlist\"");
388         
389 #endif
390
391 }
392
393 /* Retrieves the filter, sort and tny models of the folder view. If
394    any of these does not exist then it returns FALSE */
395 static gboolean
396 get_inner_models (ModestFolderView *self, 
397                   GtkTreeModel **filter_model,
398                   GtkTreeModel **sort_model,
399                   GtkTreeModel **tny_model)
400 {
401         GtkTreeModel *s_model, *f_model, *t_model;
402
403         f_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
404         if (!GTK_IS_TREE_MODEL_FILTER(f_model)) {
405                 g_debug ("%s: emtpy model or not filter model", __FUNCTION__);
406                 return FALSE;
407         }
408
409         s_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (f_model));
410         if (!GTK_IS_TREE_MODEL_SORT(s_model)) {
411                 g_warning ("BUG: %s: not a valid sort model", __FUNCTION__);
412                 return FALSE;
413         }
414
415         t_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (s_model));
416
417         /* Assign values */
418         if (filter_model)
419                 *filter_model = f_model;
420         if (sort_model)
421                 *sort_model = s_model;
422         if (tny_model)
423                 *tny_model = t_model;
424
425         return TRUE;
426 }
427
428 /* Simplify checks for NULLs: */
429 static gboolean
430 strings_are_equal (const gchar *a, const gchar *b)
431 {
432         if (!a && !b)
433                 return TRUE;
434         if (a && b)
435         {
436                 return (strcmp (a, b) == 0);
437         }
438         else
439                 return FALSE;
440 }
441
442 static gboolean
443 on_model_foreach_set_name(GtkTreeModel *model, GtkTreePath *path,  GtkTreeIter *iter, gpointer data)
444 {
445         GObject *instance = NULL;
446
447         gtk_tree_model_get (model, iter,
448                             INSTANCE_COLUMN, &instance,
449                             -1);
450
451         if (!instance)
452                 return FALSE; /* keep walking */
453
454         if (!TNY_IS_ACCOUNT (instance)) {
455                 g_object_unref (instance);
456                 return FALSE; /* keep walking */
457         }
458
459         /* Check if this is the looked-for account: */
460         TnyAccount *this_account = TNY_ACCOUNT (instance);
461         TnyAccount *account = TNY_ACCOUNT (data);
462
463         const gchar *this_account_id = tny_account_get_id(this_account);
464         const gchar *account_id = tny_account_get_id(account);
465         g_object_unref (instance);
466         instance = NULL;
467
468         /* printf ("DEBUG: %s: this_account_id=%s, account_id=%s\n", __FUNCTION__, this_account_id, account_id); */
469         if (strings_are_equal(this_account_id, account_id)) {
470                 /* Tell the model that the data has changed, so that
471                  * it calls the cell_data_func callbacks again: */
472                 /* TODO: This does not seem to actually cause the new string to be shown: */
473                 gtk_tree_model_row_changed (model, path, iter);
474
475                 return TRUE; /* stop walking */
476         }
477
478         return FALSE; /* keep walking */
479 }
480
481 typedef struct
482 {
483         ModestFolderView *self;
484         gchar *previous_name;
485 } GetMmcAccountNameData;
486
487 static void
488 on_get_mmc_account_name (TnyStoreAccount* account, gpointer user_data)
489 {
490         /* printf ("DEBU1G: %s: account name=%s\n", __FUNCTION__, tny_account_get_name (TNY_ACCOUNT(account))); */
491
492         GetMmcAccountNameData *data = (GetMmcAccountNameData*)user_data;
493
494         if (!strings_are_equal (
495                 tny_account_get_name(TNY_ACCOUNT(account)),
496                 data->previous_name)) {
497
498                 /* Tell the model that the data has changed, so that
499                  * it calls the cell_data_func callbacks again: */
500                 ModestFolderView *self = data->self;
501                 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
502                 if (model)
503                         gtk_tree_model_foreach(model, on_model_foreach_set_name, account);
504         }
505
506         g_free (data->previous_name);
507         g_slice_free (GetMmcAccountNameData, data);
508 }
509
510 static void
511 convert_parent_folders_to_dots (gchar **item_name)
512 {
513         gint n_parents = 0;
514         gint n_inbox_parents = 0;
515         gchar *c;
516         gchar *path_start;
517         gchar *last_separator;
518
519         if (item_name == NULL)
520                 return;
521
522         path_start = *item_name;
523         for (c = *item_name; *c != '\0'; c++) {
524                 if (g_str_has_prefix (c, MODEST_FOLDER_PATH_SEPARATOR)) {
525                         gchar *compare;
526                         if (c != path_start) {
527                                 compare = g_strndup (path_start, c - path_start);
528                                 compare = g_strstrip (compare);
529                                 if (g_ascii_strcasecmp (compare, "inbox") == 0) {
530                                         n_inbox_parents++;
531                                 }
532                                 g_free (compare);
533                         }
534                         n_parents++;
535                         path_start = c + 1;
536                 }
537         }
538
539         last_separator = g_strrstr (*item_name, MODEST_FOLDER_PATH_SEPARATOR);
540         if (last_separator != NULL) {
541                 last_separator = last_separator + strlen (MODEST_FOLDER_PATH_SEPARATOR);
542         }
543
544         if (n_parents > 0) {
545                 GString *buffer;
546                 gint i;
547
548                 buffer = g_string_new ("");
549                 for (i = 0; i < n_parents - n_inbox_parents; i++) {
550                         buffer = g_string_append (buffer, MODEST_FOLDER_DOT);
551                 }
552                 buffer = g_string_append (buffer, last_separator);
553                 g_free (*item_name);
554                 *item_name = g_string_free (buffer, FALSE);
555         }
556
557 }
558
559 static void
560 format_compact_style (gchar **item_name,
561                       GObject *instance,
562                       const gchar *mailbox,
563                       gboolean bold,
564                       gboolean multiaccount,
565                       gboolean *use_markup)
566 {
567         TnyFolder *folder;
568         gboolean is_special;
569         TnyFolderType folder_type;
570
571         if (!TNY_IS_FOLDER (instance))
572                 return;
573
574         folder = (TnyFolder *) instance;
575
576         folder_type = tny_folder_get_folder_type (folder);
577         is_special = (get_cmp_pos (folder_type, folder)!= 4);
578
579         if (mailbox) {
580                 /* Remove mailbox prefix if any */
581                 gchar *prefix = g_strconcat (mailbox, MODEST_FOLDER_PATH_SEPARATOR, NULL);
582                 if (g_str_has_prefix (*item_name, prefix)) {
583                         gchar *new_item_name = g_strdup (*item_name + strlen (prefix));
584                         g_free (*item_name);
585                         *item_name = new_item_name;
586                 }
587         }
588
589         if (!is_special || multiaccount) {
590                 TnyAccount *account = tny_folder_get_account (folder);
591                 const gchar *folder_name;
592                 gboolean concat_folder_name = FALSE;
593                 GString *buffer;
594
595                 /* Should not happen */
596                 if (account == NULL)
597                         return;
598
599                 /* convert parent folders to dots */
600                 convert_parent_folders_to_dots  (item_name);
601
602                 folder_name = tny_folder_get_name (folder);
603                 if (g_str_has_suffix (*item_name, folder_name)) {
604                         gchar *offset = g_strrstr (*item_name, folder_name);
605                         *offset = '\0';
606                         concat_folder_name = TRUE;
607                 }
608
609                 buffer = g_string_new ("");
610
611                 buffer = g_string_append (buffer, *item_name);
612                 if (concat_folder_name) {
613                         if (!is_special && folder_type == TNY_FOLDER_TYPE_DRAFTS) {
614                                 buffer = g_string_append (buffer, folder_name);
615                                 /* TODO: append a sensitive string to the remote drafts to
616                                  * be able to know it's the remote one */
617 /*                              buffer = g_string_append (buffer, " (TODO:remote)"); */
618                         } else {
619                                 buffer = g_string_append (buffer, folder_name);
620                         }
621                 }
622                 g_free (*item_name);
623                 g_object_unref (account);
624
625                 *item_name = g_string_free (buffer, FALSE);
626                 *use_markup = FALSE;
627         } else {
628                 *use_markup = FALSE;
629         }
630 }
631
632 static void
633 replace_special_folder_prefix (gchar **item_name)
634 {
635         const gchar *separator;
636         gchar *prefix;
637
638         if (item_name == NULL || *item_name == NULL || **item_name == '\0')
639                 return;
640         separator = g_strstr_len (*item_name, -1, MODEST_FOLDER_PATH_SEPARATOR);
641         if (separator == NULL)
642                 return;
643
644         prefix = g_strndup (*item_name, separator - *item_name);
645         g_strstrip (prefix);
646
647         if (prefix && *prefix != '\0') {
648                 TnyFolderType folder_type;
649                 gchar *new_name;
650                 gchar *downcase;
651
652                 downcase = g_utf8_strdown (prefix, -1);
653                 g_free (prefix);
654                 prefix = downcase;
655
656                 if (strcmp (downcase, "inbox") == 0) {
657                         folder_type = TNY_FOLDER_TYPE_INBOX;
658                         new_name = g_strconcat (_("mcen_me_folder_inbox"), separator, NULL);
659                         g_free (*item_name);
660                         *item_name = new_name;
661                 } else {
662                         folder_type = modest_local_folder_info_get_type (prefix);
663                         switch (folder_type) {
664                         case TNY_FOLDER_TYPE_INBOX:
665                         case TNY_FOLDER_TYPE_ARCHIVE:
666                                 new_name = g_strconcat (modest_local_folder_info_get_type_display_name (folder_type), separator, NULL);
667                                 g_free (*item_name);
668                                 *item_name = new_name;
669                                 break;
670                         default:
671                                 break;
672                         }
673                 }
674         }
675         g_free (prefix);
676 }
677
678 static void
679 text_cell_data  (GtkTreeViewColumn *column,
680                  GtkCellRenderer *renderer,
681                  GtkTreeModel *tree_model,
682                  GtkTreeIter *iter,
683                  gpointer data)
684 {
685         ModestFolderViewPrivate *priv;
686         GObject *rendobj = (GObject *) renderer;
687         gchar *fname = NULL;
688         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
689         GObject *instance = NULL;
690         gboolean use_markup = FALSE;
691
692         gtk_tree_model_get (tree_model, iter,
693                             NAME_COLUMN, &fname,
694                             TYPE_COLUMN, &type,
695                             INSTANCE_COLUMN, &instance,
696                             -1);
697         if (!fname || !instance)
698                 goto end;
699
700         ModestFolderView *self = MODEST_FOLDER_VIEW (data);
701         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (self);
702
703         gchar *item_name = NULL;
704         gint item_weight = 400;
705
706         if (type != TNY_FOLDER_TYPE_ROOT) {
707                 gint number = 0;
708                 gboolean drafts;
709                 gboolean is_local;
710
711                 is_local = modest_tny_folder_is_local_folder (TNY_FOLDER (instance)) ||
712                         modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance));
713
714                 if (is_local) {
715                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (instance));
716                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
717                                 g_free (fname);
718                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
719                         }
720                 } else {
721                         /* Sometimes an special folder is reported by the server as
722                            NORMAL, like some versions of Dovecot */
723                         if (type == TNY_FOLDER_TYPE_NORMAL ||
724                             type == TNY_FOLDER_TYPE_UNKNOWN) {
725                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
726                         }
727                 }
728
729                 /* note: we cannot reliably get the counts from the
730                  * tree model, we need to use explicit calls on
731                  * tny_folder for some reason. Select the number to
732                  * show: the unread or unsent messages. in case of
733                  * outbox/drafts, show all */
734                 if (is_local && ((type == TNY_FOLDER_TYPE_DRAFTS) ||
735                                  (type == TNY_FOLDER_TYPE_OUTBOX) ||
736                                  (type == TNY_FOLDER_TYPE_MERGE))) { /* _OUTBOX actually returns _MERGE... */
737                         number = tny_folder_get_all_count (TNY_FOLDER(instance));
738                         drafts = TRUE;
739                 } else {
740                         number = tny_folder_get_unread_count (TNY_FOLDER(instance));
741                         drafts = FALSE;
742                 }
743
744                 if (priv->cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT) {
745                         item_name = g_strdup (fname);
746                         if (number > 0) {
747                                 item_weight = 800;
748                         } else {
749                                 item_weight = 400;
750                         }
751                 } else {
752                         /* Use bold font style if there are unread or unset messages */
753                         if (number > 0) {
754                                 if (priv->show_message_count) {
755                                         item_name = g_strdup_printf ("%s (%d)", fname, number);
756                                 } else {
757                                         item_name = g_strdup (fname);
758                                 }
759                                 item_weight = 800;
760                         } else {
761                                 item_name = g_strdup (fname);
762                                 item_weight = 400;
763                         }
764                 }
765
766         } else if (TNY_IS_ACCOUNT (instance)) {
767                 /* If it's a server account */
768                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (instance))) {
769                         item_name = g_strdup (priv->local_account_name);
770                         item_weight = 800;
771                 } else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance))) {
772                         /* fname is only correct when the items are first
773                          * added to the model, not when the account is
774                          * changed later, so get the name from the account
775                          * instance: */
776                         item_name = g_strdup (tny_account_get_name (TNY_ACCOUNT (instance)));
777                         item_weight = 800;
778                 } else {
779                         item_name = g_strdup (fname);
780                         item_weight = 800;
781                 }
782         }
783
784         /* Convert INBOX */
785         if (type == TNY_FOLDER_TYPE_INBOX &&
786             g_str_has_suffix (fname, "Inbox")) {
787                 g_free (item_name);
788                 item_name = g_strdup (_("mcen_me_folder_inbox"));
789         }
790
791         if (!item_name)
792                 item_name = g_strdup ("unknown");
793
794         if (priv->cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT) {
795                 gboolean multiaccount;
796
797                 multiaccount = (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ALL);
798                 /* Convert item_name to markup */
799                 format_compact_style (&item_name, instance, priv->mailbox,
800                                       item_weight == 800, 
801                                       multiaccount, &use_markup);
802         } else {
803                 replace_special_folder_prefix (&item_name);
804         }
805
806         if (item_name && item_weight) {
807                 /* Set the name in the treeview cell: */
808                 if (priv->cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT && item_weight == 800 && 
809                     (priv->active_color.red != 0 || priv->active_color.blue != 0 || priv->active_color.green != 0)) {
810                         g_object_set (rendobj, 
811                                       "text", item_name, 
812                                       "weight-set", FALSE,
813                                       "foreground-set", TRUE,
814                                       "foreground-gdk", &(priv->active_color),
815                                       NULL);
816                 } else {
817                         g_object_set (rendobj, 
818                                       "text", item_name,
819                                       "foreground-set", FALSE,
820                                       "weight-set", TRUE, 
821                                       "weight", item_weight,
822                                       NULL);
823                 }
824
825                 /* Notify display name observers */
826                 /* TODO: What listens for this signal, and how can it use only the new name? */
827                 if (((GObject *) priv->cur_folder_store) == instance) {
828                         g_signal_emit (G_OBJECT(self),
829                                                signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
830                                                item_name);
831                 }
832                 g_free (item_name);
833
834         }
835
836         /* If it is a Memory card account, make sure that we have the correct name.
837          * This function will be trigerred again when the name has been retrieved: */
838         if (TNY_IS_STORE_ACCOUNT (instance) &&
839                 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance))) {
840
841                 /* Get the account name asynchronously: */
842                 GetMmcAccountNameData *callback_data =
843                         g_slice_new0(GetMmcAccountNameData);
844                 callback_data->self = self;
845
846                 const gchar *name = tny_account_get_name (TNY_ACCOUNT(instance));
847                 if (name)
848                         callback_data->previous_name = g_strdup (name);
849
850                 modest_tny_account_get_mmc_account_name (TNY_STORE_ACCOUNT (instance),
851                                                          on_get_mmc_account_name, callback_data);
852         }
853  end:
854         if (instance)
855                 g_object_unref (G_OBJECT (instance));
856         if (fname)
857                 g_free (fname);
858 }
859
860 static void
861 messages_cell_data  (GtkTreeViewColumn *column,
862                  GtkCellRenderer *renderer,
863                  GtkTreeModel *tree_model,
864                  GtkTreeIter *iter,
865                  gpointer data)
866 {
867         ModestFolderView *self; 
868         ModestFolderViewPrivate *priv;
869         GObject *rendobj = (GObject *) renderer;
870         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
871         GObject *instance = NULL;
872         gchar *item_name = NULL;
873
874         gtk_tree_model_get (tree_model, iter,
875                             TYPE_COLUMN, &type,
876                             INSTANCE_COLUMN, &instance,
877                             -1);
878         if (!instance)
879                 goto end;
880
881         self = MODEST_FOLDER_VIEW (data);
882         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (self);
883
884
885         if (type != TNY_FOLDER_TYPE_ROOT) {
886                 gint number = 0;
887                 gboolean drafts;
888                 gboolean is_local;
889
890                 is_local = modest_tny_folder_is_local_folder (TNY_FOLDER (instance)) ||
891                         modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance));
892
893                 if (is_local) {
894                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (instance));
895                 } else {
896                         /* Sometimes an special folder is reported by the server as
897                            NORMAL, like some versions of Dovecot */
898                         if (type == TNY_FOLDER_TYPE_NORMAL ||
899                             type == TNY_FOLDER_TYPE_UNKNOWN) {
900                                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
901                         }
902                 }
903
904                 /* note: we cannot reliably get the counts from the tree model, we need
905                  * to use explicit calls on tny_folder for some reason.
906                  */
907                 /* Select the number to show: the unread or unsent messages. in case of outbox/drafts, show all */
908                 if (is_local && ((type == TNY_FOLDER_TYPE_DRAFTS) ||
909                                  (type == TNY_FOLDER_TYPE_OUTBOX) ||
910                                  (type == TNY_FOLDER_TYPE_MERGE))) { /* _OUTBOX actually returns _MERGE... */
911                         number = tny_folder_get_all_count (TNY_FOLDER(instance));
912                         drafts = TRUE;
913                 } else {
914                         number = tny_folder_get_unread_count (TNY_FOLDER(instance));
915                         drafts = FALSE;
916                 }
917
918                 if ((priv->cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT) && (number > 0)) {
919                         item_name =
920                                 g_strdup_printf (ngettext ((drafts) ? "mcen_ti_message" : "mcen_va_new_message",
921                                                            (drafts) ? "mcen_ti_messages" : "mcen_va_new_messages",
922                                                            number), number);
923                 }
924         }
925
926         if (!item_name)
927                 item_name = g_strdup ("");
928
929         if (item_name) {
930                 /* Set the name in the treeview cell: */
931                 g_object_set (rendobj,"text", item_name, NULL);
932
933                 g_free (item_name);
934
935         }
936
937  end:
938         if (instance)
939                 g_object_unref (G_OBJECT (instance));
940 }
941
942
943 typedef struct {
944         GdkPixbuf *pixbuf;
945         GdkPixbuf *pixbuf_open;
946         GdkPixbuf *pixbuf_close;
947 } ThreePixbufs;
948
949
950 static inline GdkPixbuf *
951 get_composite_pixbuf (const gchar *icon_name,
952                       const gint size,
953                       GdkPixbuf *base_pixbuf)
954 {
955         GdkPixbuf *emblem, *retval = NULL;
956
957         emblem = modest_platform_get_icon (icon_name, size);
958         if (emblem) {
959                 retval = gdk_pixbuf_copy (base_pixbuf);
960                 gdk_pixbuf_composite (emblem, retval, 0, 0,
961                                       MIN (gdk_pixbuf_get_width (emblem),
962                                            gdk_pixbuf_get_width (retval)),
963                                       MIN (gdk_pixbuf_get_height (emblem),
964                                            gdk_pixbuf_get_height (retval)),
965                                                   0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
966                 g_object_unref (emblem);
967         }
968         return retval;
969 }
970
971 static inline ThreePixbufs *
972 get_composite_icons (const gchar *icon_code,
973                      GdkPixbuf **pixbuf,
974                      GdkPixbuf **pixbuf_open,
975                      GdkPixbuf **pixbuf_close)
976 {
977         ThreePixbufs *retval;
978
979         if (pixbuf && !*pixbuf) {
980                 GdkPixbuf *icon;
981                 icon = modest_platform_get_icon (icon_code, FOLDER_ICON_SIZE);
982                 if (icon) {
983                         *pixbuf = gdk_pixbuf_copy (icon);
984                 } else {
985                         *pixbuf = NULL;
986                 }
987         }
988
989         if (pixbuf_open && !*pixbuf_open && pixbuf && *pixbuf)
990                 *pixbuf_open = get_composite_pixbuf ("qgn_list_gene_fldr_exp",
991                                                      FOLDER_ICON_SIZE,
992                                                      *pixbuf);
993
994         if (pixbuf_close && !*pixbuf_close && pixbuf && *pixbuf)
995                 *pixbuf_close = get_composite_pixbuf ("qgn_list_gene_fldr_clp",
996                                                       FOLDER_ICON_SIZE,
997                                                       *pixbuf);
998
999         retval = g_slice_new0 (ThreePixbufs);
1000         if (pixbuf && *pixbuf)
1001                 retval->pixbuf = g_object_ref (*pixbuf);
1002         else
1003                 retval->pixbuf = NULL;
1004         if (pixbuf_open && *pixbuf_open)
1005                 retval->pixbuf_open = g_object_ref (*pixbuf_open);
1006         else
1007                 retval->pixbuf_open = NULL;
1008         if (pixbuf_close && *pixbuf_close)
1009                 retval->pixbuf_close = g_object_ref (*pixbuf_close);
1010         else
1011                 retval->pixbuf_close = NULL;
1012
1013         return retval;
1014 }
1015
1016 static inline ThreePixbufs *
1017 get_account_protocol_pixbufs (ModestFolderView *folder_view,
1018                               ModestProtocolType protocol_type,
1019                               GObject *object)
1020 {
1021         ModestProtocol *protocol;
1022         const GdkPixbuf *pixbuf = NULL;
1023         ModestFolderViewPrivate *priv;
1024
1025         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
1026
1027         protocol = modest_protocol_registry_get_protocol_by_type (modest_runtime_get_protocol_registry (),
1028                                                                   protocol_type);
1029
1030         if (MODEST_IS_ACCOUNT_PROTOCOL (protocol)) {
1031                 pixbuf = modest_account_protocol_get_icon (MODEST_ACCOUNT_PROTOCOL (protocol), 
1032                                                            priv->filter & MODEST_FOLDER_VIEW_FILTER_SHOW_ONLY_MAILBOXES?
1033                                                            MODEST_ACCOUNT_PROTOCOL_ICON_MAILBOX:
1034                                                            MODEST_ACCOUNT_PROTOCOL_ICON_FOLDER,
1035                                                            object, FOLDER_ICON_SIZE);
1036         }
1037
1038         if (pixbuf) {
1039                 ThreePixbufs *retval;
1040                 retval = g_slice_new0 (ThreePixbufs);
1041                 retval->pixbuf = g_object_ref ((GObject *) pixbuf);
1042                 retval->pixbuf_open = g_object_ref ((GObject *) pixbuf);
1043                 retval->pixbuf_close = g_object_ref ((GObject *) pixbuf);
1044                 return retval;
1045         } else {
1046                 return NULL;
1047         }
1048 }
1049
1050 static inline ThreePixbufs*
1051 get_folder_icons (ModestFolderView *folder_view, TnyFolderType type, GObject *instance)
1052 {
1053         TnyAccount *account = NULL;
1054         static GdkPixbuf *inbox_pixbuf = NULL, *outbox_pixbuf = NULL,
1055                 *junk_pixbuf = NULL, *sent_pixbuf = NULL,
1056                 *trash_pixbuf = NULL, *draft_pixbuf = NULL,
1057                 *normal_pixbuf = NULL, *anorm_pixbuf = NULL, *mmc_pixbuf = NULL,
1058                 *ammc_pixbuf = NULL, *avirt_pixbuf = NULL;
1059
1060         static GdkPixbuf *inbox_pixbuf_open = NULL, *outbox_pixbuf_open = NULL,
1061                 *junk_pixbuf_open = NULL, *sent_pixbuf_open = NULL,
1062                 *trash_pixbuf_open = NULL, *draft_pixbuf_open = NULL,
1063                 *normal_pixbuf_open = NULL, *anorm_pixbuf_open = NULL, *mmc_pixbuf_open = NULL,
1064                 *ammc_pixbuf_open = NULL, *avirt_pixbuf_open = NULL;
1065
1066         static GdkPixbuf *inbox_pixbuf_close = NULL, *outbox_pixbuf_close = NULL,
1067                 *junk_pixbuf_close = NULL, *sent_pixbuf_close = NULL,
1068                 *trash_pixbuf_close = NULL, *draft_pixbuf_close = NULL,
1069                 *normal_pixbuf_close = NULL, *anorm_pixbuf_close = NULL, *mmc_pixbuf_close = NULL,
1070                 *ammc_pixbuf_close = NULL, *avirt_pixbuf_close = NULL;
1071
1072         ThreePixbufs *retval = NULL;
1073
1074         if (TNY_IS_ACCOUNT (instance)) {
1075                 account = g_object_ref (instance);
1076         } else if (TNY_IS_FOLDER (instance) && !TNY_IS_MERGE_FOLDER (instance)) {
1077                 account = tny_folder_get_account (TNY_FOLDER (instance));
1078         }
1079
1080         if (account) {
1081                 ModestProtocolType account_store_protocol;
1082
1083                 account_store_protocol = modest_tny_account_get_protocol_type (account);
1084                 retval = get_account_protocol_pixbufs (folder_view, account_store_protocol, instance);
1085                 g_object_unref (account);
1086         }
1087
1088         if (retval)
1089                 return retval;
1090
1091         /* Sometimes an special folder is reported by the server as
1092            NORMAL, like some versions of Dovecot */
1093         if (type == TNY_FOLDER_TYPE_NORMAL ||
1094             type == TNY_FOLDER_TYPE_UNKNOWN) {
1095                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
1096         }
1097
1098         /* It's not enough with check the folder type. We need to
1099            ensure that we're not giving a special folder icon to a
1100            normal folder with the same name than a special folder */
1101         if (TNY_IS_FOLDER (instance) &&
1102             get_cmp_pos (type, TNY_FOLDER (instance)) ==  4)
1103                 type = TNY_FOLDER_TYPE_NORMAL;
1104
1105         /* Remote folders should not be treated as special folders */
1106         if (TNY_IS_FOLDER_STORE (instance) &&
1107             !TNY_IS_ACCOUNT (instance) &&
1108             type != TNY_FOLDER_TYPE_INBOX &&
1109             modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (instance))) {
1110 #ifdef MODEST_TOOLKIT_HILDON2
1111                 return get_composite_icons (MODEST_FOLDER_ICON_REMOTE_FOLDER,
1112                                             &anorm_pixbuf,
1113                                             &anorm_pixbuf_open,
1114                                             &anorm_pixbuf_close);
1115 #else
1116                 return get_composite_icons (MODEST_FOLDER_ICON_NORMAL,
1117                                             &normal_pixbuf,
1118                                             &normal_pixbuf_open,
1119                                             &normal_pixbuf_close);
1120 #endif
1121         }
1122
1123         switch (type) {
1124
1125         case TNY_FOLDER_TYPE_INVALID:
1126                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1127                 break;
1128
1129         case TNY_FOLDER_TYPE_ROOT:
1130                 if (TNY_IS_ACCOUNT (instance)) {
1131
1132                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (instance))) {
1133                                 retval = get_composite_icons (MODEST_FOLDER_ICON_LOCAL_FOLDERS,
1134                                                               &avirt_pixbuf,
1135                                                               &avirt_pixbuf_open,
1136                                                               &avirt_pixbuf_close);
1137                         } else {
1138                                 const gchar *account_id = tny_account_get_id (TNY_ACCOUNT (instance));
1139
1140                                 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1141                                         retval = get_composite_icons (MODEST_FOLDER_ICON_MMC,
1142                                                                       &ammc_pixbuf,
1143                                                                       &ammc_pixbuf_open,
1144                                                                       &ammc_pixbuf_close);
1145                                 } else {
1146                                         retval = get_composite_icons (MODEST_FOLDER_ICON_ACCOUNT,
1147                                                                       &anorm_pixbuf,
1148                                                                       &anorm_pixbuf_open,
1149                                                                       &anorm_pixbuf_close);
1150                                 }
1151                         }
1152                 }
1153                 break;
1154         case TNY_FOLDER_TYPE_INBOX:
1155                 retval = get_composite_icons (MODEST_FOLDER_ICON_INBOX,
1156                                               &inbox_pixbuf,
1157                                               &inbox_pixbuf_open,
1158                                               &inbox_pixbuf_close);
1159                 break;
1160         case TNY_FOLDER_TYPE_OUTBOX:
1161                 retval = get_composite_icons (MODEST_FOLDER_ICON_OUTBOX,
1162                                               &outbox_pixbuf,
1163                                               &outbox_pixbuf_open,
1164                                               &outbox_pixbuf_close);
1165                 break;
1166         case TNY_FOLDER_TYPE_JUNK:
1167                 retval = get_composite_icons (MODEST_FOLDER_ICON_JUNK,
1168                                               &junk_pixbuf,
1169                                               &junk_pixbuf_open,
1170                                               &junk_pixbuf_close);
1171                 break;
1172         case TNY_FOLDER_TYPE_SENT:
1173                 retval = get_composite_icons (MODEST_FOLDER_ICON_SENT,
1174                                               &sent_pixbuf,
1175                                               &sent_pixbuf_open,
1176                                               &sent_pixbuf_close);
1177                 break;
1178         case TNY_FOLDER_TYPE_TRASH:
1179                 retval = get_composite_icons (MODEST_FOLDER_ICON_TRASH,
1180                                               &trash_pixbuf,
1181                                               &trash_pixbuf_open,
1182                                               &trash_pixbuf_close);
1183                 break;
1184         case TNY_FOLDER_TYPE_DRAFTS:
1185                 retval = get_composite_icons (MODEST_FOLDER_ICON_DRAFTS,
1186                                               &draft_pixbuf,
1187                                               &draft_pixbuf_open,
1188                                               &draft_pixbuf_close);
1189                 break;
1190         case TNY_FOLDER_TYPE_ARCHIVE:
1191                 retval = get_composite_icons (MODEST_FOLDER_ICON_MMC_FOLDER,
1192                                               &mmc_pixbuf,
1193                                               &mmc_pixbuf_open,
1194                                               &mmc_pixbuf_close);
1195                 break;
1196         case TNY_FOLDER_TYPE_NORMAL:
1197         default:
1198                 /* Memory card folders could have an special icon */
1199                 if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance))) {
1200                         retval = get_composite_icons (MODEST_FOLDER_ICON_MMC_FOLDER,
1201                                                       &mmc_pixbuf,
1202                                                       &mmc_pixbuf_open,
1203                                                       &mmc_pixbuf_close);
1204                 } else {
1205                         retval = get_composite_icons (MODEST_FOLDER_ICON_NORMAL,
1206                                                       &normal_pixbuf,
1207                                                       &normal_pixbuf_open,
1208                                                       &normal_pixbuf_close);
1209                 }
1210                 break;
1211         }
1212
1213         return retval;
1214 }
1215
1216 static void
1217 free_pixbufs (ThreePixbufs *pixbufs)
1218 {
1219         if (pixbufs->pixbuf)
1220                 g_object_unref (pixbufs->pixbuf);
1221         if (pixbufs->pixbuf_open)
1222                 g_object_unref (pixbufs->pixbuf_open);
1223         if (pixbufs->pixbuf_close)
1224                 g_object_unref (pixbufs->pixbuf_close);
1225         g_slice_free (ThreePixbufs, pixbufs);
1226 }
1227
1228 static void
1229 icon_cell_data  (GtkTreeViewColumn *column,
1230                  GtkCellRenderer *renderer,
1231                  GtkTreeModel *tree_model,
1232                  GtkTreeIter *iter,
1233                  gpointer data)
1234 {
1235         GObject *rendobj = NULL, *instance = NULL;
1236         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1237         gboolean has_children;
1238         ThreePixbufs *pixbufs;
1239         ModestFolderView *folder_view = (ModestFolderView *) data;
1240
1241         rendobj = (GObject *) renderer;
1242
1243         gtk_tree_model_get (tree_model, iter,
1244                             TYPE_COLUMN, &type,
1245                             INSTANCE_COLUMN, &instance,
1246                             -1);
1247
1248         if (!instance)
1249                 return;
1250
1251         has_children = gtk_tree_model_iter_has_child (tree_model, iter);
1252         pixbufs = get_folder_icons (folder_view, type, instance);
1253         g_object_unref (instance);
1254
1255         /* Set pixbuf */
1256         g_object_set (rendobj, "pixbuf", pixbufs->pixbuf, NULL);
1257
1258         if (has_children) {
1259                 g_object_set (rendobj, "pixbuf-expander-open", pixbufs->pixbuf_open, NULL);
1260                 g_object_set (rendobj, "pixbuf-expander-closed", pixbufs->pixbuf_close, NULL);
1261         }
1262
1263         free_pixbufs (pixbufs);
1264 }
1265
1266 static void
1267 add_columns (GtkWidget *treeview)
1268 {
1269         GtkTreeViewColumn *column;
1270         GtkCellRenderer *renderer;
1271         GtkTreeSelection *sel;
1272         ModestFolderViewPrivate *priv;
1273
1274         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(treeview);
1275
1276         /* Create column */
1277         column = gtk_tree_view_column_new ();
1278
1279         /* Set icon and text render function */
1280         renderer = gtk_cell_renderer_pixbuf_new();
1281 #ifdef MODEST_TOOLKIT_HILDON2
1282         g_object_set (renderer,
1283                       "xpad", MODEST_MARGIN_DEFAULT,
1284                       "ypad", MODEST_MARGIN_DEFAULT,
1285                       NULL);
1286 #endif
1287         gtk_tree_view_column_pack_start (column, renderer, FALSE);
1288         gtk_tree_view_column_set_cell_data_func(column, renderer,
1289                                                 icon_cell_data, treeview, NULL);
1290
1291         renderer = gtk_cell_renderer_text_new();
1292         g_object_set (renderer, 
1293 #ifdef MODEST_TOOLKIT_HILDON2
1294                       "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
1295                       "ypad", MODEST_MARGIN_DEFAULT,
1296                       "xpad", MODEST_MARGIN_DEFAULT,
1297 #else
1298                       "ellipsize", PANGO_ELLIPSIZE_END,
1299 #endif
1300                       "ellipsize-set", TRUE, NULL);
1301         gtk_tree_view_column_pack_start (column, renderer, TRUE);
1302         gtk_tree_view_column_set_cell_data_func(column, renderer,
1303                                                 text_cell_data, treeview, NULL);
1304
1305         priv->messages_renderer = gtk_cell_renderer_text_new ();
1306         g_object_set (priv->messages_renderer, 
1307 #ifdef MODEST_TOOLKIT_HILDON2
1308                       "yalign", 0.5,
1309                       "ypad", MODEST_MARGIN_DEFAULT,
1310                       "xpad", MODEST_MARGIN_DOUBLE,
1311 #else
1312                       "scale", PANGO_SCALE_X_SMALL,
1313                       "scale-set", TRUE,
1314 #endif
1315                       "alignment", PANGO_ALIGN_RIGHT,
1316                       "align-set", TRUE,
1317                       "xalign", 1.0,
1318                       NULL);
1319         gtk_tree_view_column_pack_start (column, priv->messages_renderer, FALSE);
1320         gtk_tree_view_column_set_cell_data_func(column, priv->messages_renderer,
1321                                                 messages_cell_data, treeview, NULL);
1322
1323         /* Set selection mode */
1324         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
1325         gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
1326
1327         /* Set treeview appearance */
1328         gtk_tree_view_column_set_spacing (column, 2);
1329         gtk_tree_view_column_set_resizable (column, TRUE);
1330         gtk_tree_view_column_set_fixed_width (column, TRUE);
1331         gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
1332         gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
1333
1334         /* Add column */
1335         gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
1336 }
1337
1338 static void
1339 modest_folder_view_init (ModestFolderView *obj)
1340 {
1341         ModestFolderViewPrivate *priv;
1342         ModestConf *conf;
1343
1344         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
1345
1346         priv->timer_expander = 0;
1347         priv->account_store  = NULL;
1348         priv->query          = NULL;
1349         priv->do_refresh     = TRUE;
1350         priv->style          = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
1351         priv->cur_folder_store   = NULL;
1352         priv->visible_account_id = NULL;
1353         priv->mailbox = NULL;
1354         priv->folder_to_select = NULL;
1355         priv->outbox_deleted_handler = 0;
1356         priv->reexpand = TRUE;
1357         priv->signal_handlers = 0;
1358
1359         /* Initialize the local account name */
1360         conf = modest_runtime_get_conf();
1361         priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
1362
1363         /* Init email clipboard */
1364         priv->clipboard = modest_runtime_get_email_clipboard ();
1365         priv->hidding_ids = NULL;
1366         priv->n_selected = 0;
1367         priv->filter = MODEST_FOLDER_VIEW_FILTER_NONE;
1368         priv->reselect = FALSE;
1369         priv->show_non_move = TRUE;
1370         priv->list_to_move = NULL;
1371         priv->show_message_count = TRUE;
1372
1373         /* Build treeview */
1374         add_columns (GTK_WIDGET (obj));
1375
1376         /* Setup drag and drop */
1377         setup_drag_and_drop (GTK_TREE_VIEW(obj));
1378
1379         /* Connect signals */
1380         g_signal_connect (G_OBJECT (obj),
1381                           "key-press-event",
1382                           G_CALLBACK (on_key_pressed), NULL);
1383
1384         priv->display_name_changed_signal =
1385                 g_signal_connect (modest_runtime_get_account_mgr (),
1386                                   "display_name_changed",
1387                                   G_CALLBACK (on_display_name_changed),
1388                                   obj);
1389
1390         /*
1391          * Track changes in the local account name (in the device it
1392          * will be the device name)
1393          */
1394         priv->conf_key_signal = g_signal_connect (G_OBJECT(conf),
1395                                                   "key_changed",
1396                                                   G_CALLBACK(on_configuration_key_changed),
1397                                                   obj);
1398
1399         gdk_color_parse ("000", &priv->active_color);
1400
1401         update_style (obj);
1402         g_signal_connect (G_OBJECT (obj), "notify::style", 
1403                           G_CALLBACK (on_notify_style), (gpointer) obj);
1404 }
1405
1406 static void
1407 tny_account_store_view_init (gpointer g, gpointer iface_data)
1408 {
1409         TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
1410
1411         klass->set_account_store = modest_folder_view_set_account_store;
1412 }
1413
1414 static void
1415 modest_folder_view_dispose (GObject *obj)
1416 {
1417         ModestFolderViewPrivate *priv;
1418         GtkTreeModel *model = NULL;
1419
1420         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (obj);
1421
1422         get_inner_models (MODEST_FOLDER_VIEW (obj),
1423                           NULL, NULL, &model);
1424
1425 #ifdef MODEST_TOOLKIT_HILDON2
1426         if (priv->signal_handlers) {
1427                 modest_signal_mgr_disconnect_all_and_destroy (priv->signal_handlers);
1428                 priv->signal_handlers = NULL;
1429         }
1430 #endif
1431
1432         /* Free external references */
1433         if (priv->account_store) {
1434                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1435                                              priv->account_inserted_signal);
1436                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1437                                              priv->account_removed_signal);
1438                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1439                                              priv->account_changed_signal);
1440                 g_object_unref (G_OBJECT(priv->account_store));
1441                 priv->account_store = NULL;
1442         }
1443
1444         if (priv->query) {
1445                 g_object_unref (G_OBJECT (priv->query));
1446                 priv->query = NULL;
1447         }
1448
1449         if (priv->folder_to_select) {
1450                 g_object_unref (G_OBJECT(priv->folder_to_select));
1451                 priv->folder_to_select = NULL;
1452         }
1453
1454         if (priv->cur_folder_store) {
1455                 g_object_unref (priv->cur_folder_store);
1456                 priv->cur_folder_store = NULL;
1457         }
1458
1459         if (priv->list_to_move) {
1460                 g_object_unref (priv->list_to_move);
1461                 priv->list_to_move = NULL;
1462         }
1463
1464         G_OBJECT_CLASS(parent_class)->dispose (obj);
1465 }
1466
1467 static void
1468 modest_folder_view_finalize (GObject *obj)
1469 {
1470         ModestFolderViewPrivate *priv;
1471         GtkTreeSelection    *sel;
1472         TnyAccount *local_account;
1473
1474         g_return_if_fail (obj);
1475
1476         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
1477
1478         if (priv->timer_expander != 0) {
1479                 g_source_remove (priv->timer_expander);
1480                 priv->timer_expander = 0;
1481         }
1482
1483         local_account = (TnyAccount *)
1484                 modest_tny_account_store_get_local_folders_account (modest_runtime_get_account_store ());
1485         if (local_account) {
1486                 if (g_signal_handler_is_connected (local_account,
1487                                                    priv->outbox_deleted_handler))
1488                         g_signal_handler_disconnect (local_account,
1489                                                      priv->outbox_deleted_handler);
1490                 g_object_unref (local_account);
1491         }
1492
1493         if (g_signal_handler_is_connected (modest_runtime_get_account_mgr (), 
1494                                            priv->display_name_changed_signal)) {
1495                 g_signal_handler_disconnect (modest_runtime_get_account_mgr (),
1496                                              priv->display_name_changed_signal);
1497                 priv->display_name_changed_signal = 0;
1498         }
1499
1500         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
1501         if (sel)
1502                 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
1503
1504         g_free (priv->local_account_name);
1505         g_free (priv->visible_account_id);
1506         g_free (priv->mailbox);
1507
1508         if (priv->conf_key_signal) {
1509                 g_signal_handler_disconnect (modest_runtime_get_conf (),
1510                                              priv->conf_key_signal);
1511                 priv->conf_key_signal = 0;
1512         }
1513
1514         /* Clear hidding array created by cut operation */
1515         _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
1516
1517         gdk_color_parse ("000", &priv->active_color);
1518
1519         G_OBJECT_CLASS(parent_class)->finalize (obj);
1520 }
1521
1522
1523 static void
1524 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
1525 {
1526         ModestFolderViewPrivate *priv;
1527         TnyDevice *device;
1528
1529         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1530         g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
1531
1532         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1533         device = tny_account_store_get_device (account_store);
1534
1535         if (G_UNLIKELY (priv->account_store)) {
1536
1537                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
1538                                                    priv->account_inserted_signal))
1539                         g_signal_handler_disconnect (G_OBJECT (priv->account_store),
1540                                                      priv->account_inserted_signal);
1541                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
1542                                                    priv->account_removed_signal))
1543                         g_signal_handler_disconnect (G_OBJECT (priv->account_store),
1544                                                      priv->account_removed_signal);
1545                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
1546                                                    priv->account_changed_signal))
1547                         g_signal_handler_disconnect (G_OBJECT (priv->account_store),
1548                                                      priv->account_changed_signal);
1549                 g_object_unref (G_OBJECT (priv->account_store));
1550         }
1551
1552         priv->account_store = g_object_ref (G_OBJECT (account_store));
1553
1554         priv->account_removed_signal =
1555                 g_signal_connect (G_OBJECT(account_store), "account_removed",
1556                                   G_CALLBACK (on_account_removed), self);
1557
1558         priv->account_inserted_signal =
1559                 g_signal_connect (G_OBJECT(account_store), "account_inserted",
1560                                   G_CALLBACK (on_account_inserted), self);
1561
1562         priv->account_changed_signal =
1563                 g_signal_connect (G_OBJECT(account_store), "account_changed",
1564                                   G_CALLBACK (on_account_changed), self);
1565
1566         modest_folder_view_update_model (MODEST_FOLDER_VIEW (self), account_store);
1567         priv->reselect = FALSE;
1568         modest_folder_view_select_first_inbox_or_local (MODEST_FOLDER_VIEW (self));
1569
1570         g_object_unref (G_OBJECT (device));
1571 }
1572
1573 static void
1574 on_outbox_deleted_cb (ModestTnyLocalFoldersAccount *local_account,
1575                       gpointer user_data)
1576 {
1577         ModestFolderView *self;
1578         GtkTreeModel *model, *filter_model;
1579         TnyFolder *outbox;
1580
1581         self = MODEST_FOLDER_VIEW (user_data);
1582
1583         if (!get_inner_models (self, &filter_model, NULL, &model))
1584                 return;
1585
1586         /* Remove outbox from model */
1587         outbox = modest_tny_local_folders_account_get_merged_outbox (local_account);
1588         tny_list_remove (TNY_LIST (model), G_OBJECT (outbox));
1589         g_object_unref (outbox);
1590
1591         /* Refilter view */
1592         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1593 }
1594
1595 static void
1596 on_account_inserted (TnyAccountStore *account_store,
1597                      TnyAccount *account,
1598                      gpointer user_data)
1599 {
1600         ModestFolderViewPrivate *priv;
1601         GtkTreeModel *model, *filter_model;
1602
1603         /* Ignore transport account insertions, we're not showing them
1604            in the folder view */
1605         if (TNY_IS_TRANSPORT_ACCOUNT (account))
1606                 return;
1607
1608         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data);
1609
1610
1611         /* If we're adding a new account, and there is no previous
1612            one, we need to select the visible server account */
1613         if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
1614             !priv->visible_account_id)
1615                 modest_widget_memory_restore (modest_runtime_get_conf(),
1616                                               G_OBJECT (user_data),
1617                                               MODEST_CONF_FOLDER_VIEW_KEY);
1618
1619
1620         /* Get models */
1621         if (!get_inner_models (MODEST_FOLDER_VIEW (user_data),
1622                                &filter_model, NULL, &model))
1623                 return;
1624
1625         /* Insert the account in the model */
1626         tny_list_append (TNY_LIST (model), G_OBJECT (account));
1627
1628         /* When the model is a list store (plain representation) the
1629            outbox is not a child of any account so we have to manually
1630            delete it because removing the local folders account won't
1631            delete it (because tny_folder_get_account() is not defined
1632            for a merge folder */
1633         if (TNY_IS_GTK_FOLDER_LIST_STORE (model) &&
1634             MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (account)) {
1635
1636                 priv->outbox_deleted_handler =
1637                         g_signal_connect (account,
1638                                           "outbox-deleted",
1639                                           G_CALLBACK (on_outbox_deleted_cb),
1640                                           user_data);
1641         }
1642
1643         /* Refilter the model */
1644         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1645 }
1646
1647
1648 static gboolean
1649 same_account_selected (ModestFolderView *self,
1650                        TnyAccount *account)
1651 {
1652         ModestFolderViewPrivate *priv;
1653         gboolean same_account = FALSE;
1654
1655         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1656
1657         if (priv->cur_folder_store) {
1658                 TnyAccount *selected_folder_account = NULL;
1659
1660                 if (TNY_IS_FOLDER (priv->cur_folder_store)) {
1661                         selected_folder_account =
1662                                 modest_tny_folder_get_account (TNY_FOLDER (priv->cur_folder_store));
1663                 } else {
1664                         selected_folder_account =
1665                                 TNY_ACCOUNT (g_object_ref (priv->cur_folder_store));
1666                 }
1667
1668                 if (selected_folder_account == account)
1669                         same_account = TRUE;
1670
1671                 g_object_unref (selected_folder_account);
1672         }
1673         return same_account;
1674 }
1675
1676 /**
1677  *
1678  * Selects the first inbox or the local account in an idle
1679  */
1680 static gboolean
1681 on_idle_select_first_inbox_or_local (gpointer user_data)
1682 {
1683         ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
1684
1685         gdk_threads_enter ();
1686         modest_folder_view_select_first_inbox_or_local (self);
1687         gdk_threads_leave ();
1688
1689         return FALSE;
1690 }
1691
1692 static void
1693 on_account_changed (TnyAccountStore *account_store,
1694                     TnyAccount *tny_account,
1695                     gpointer user_data)
1696 {
1697         ModestFolderView *self;
1698         ModestFolderViewPrivate *priv;
1699         GtkTreeModel *model, *filter_model;
1700         GtkTreeSelection *sel;
1701         gboolean same_account;
1702
1703         /* Ignore transport account insertions, we're not showing them
1704            in the folder view */
1705         if (TNY_IS_TRANSPORT_ACCOUNT (tny_account))
1706                 return;
1707
1708         self = MODEST_FOLDER_VIEW (user_data);
1709         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data);
1710
1711         /* Get the inner model */
1712         if (!get_inner_models (MODEST_FOLDER_VIEW (user_data),
1713                                &filter_model, NULL, &model))
1714                 return;
1715
1716         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data));
1717
1718         /* Invalidate the cur_folder_store only if the selected folder
1719            belongs to the account that is being removed */
1720         same_account = same_account_selected (self, tny_account);
1721         if (same_account) {
1722                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1723                 gtk_tree_selection_unselect_all (sel);
1724         }
1725
1726         /* Remove the account from the model */
1727         tny_list_remove (TNY_LIST (model), G_OBJECT (tny_account));
1728
1729         /* Insert the account in the model */
1730         tny_list_append (TNY_LIST (model), G_OBJECT (tny_account));
1731
1732         /* Refilter the model */
1733         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1734
1735         /* Select the first INBOX if the currently selected folder
1736            belongs to the account that is being deleted */
1737         if (same_account && !MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (tny_account))
1738                 g_idle_add (on_idle_select_first_inbox_or_local, self);
1739 }
1740
1741 static void
1742 on_account_removed (TnyAccountStore *account_store,
1743                     TnyAccount *account,
1744                     gpointer user_data)
1745 {
1746         ModestFolderView *self = NULL;
1747         ModestFolderViewPrivate *priv;
1748         GtkTreeModel *model, *filter_model;
1749         GtkTreeSelection *sel = NULL;
1750         gboolean same_account = FALSE;
1751
1752         /* Ignore transport account removals, we're not showing them
1753            in the folder view */
1754         if (TNY_IS_TRANSPORT_ACCOUNT (account))
1755                 return;
1756
1757         if (!MODEST_IS_FOLDER_VIEW(user_data)) {
1758                 g_warning ("BUG: %s: not a valid folder view", __FUNCTION__);
1759                 return;
1760         }
1761
1762         self = MODEST_FOLDER_VIEW (user_data);
1763         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1764
1765         /* Invalidate the cur_folder_store only if the selected folder
1766            belongs to the account that is being removed */
1767         same_account = same_account_selected (self, account);
1768         if (same_account) {
1769                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1770                 gtk_tree_selection_unselect_all (sel);
1771         }
1772
1773         /* Invalidate row to select only if the folder to select
1774            belongs to the account that is being removed*/
1775         if (priv->folder_to_select) {
1776                 TnyAccount *folder_to_select_account = NULL;
1777
1778                 folder_to_select_account = tny_folder_get_account (priv->folder_to_select);
1779                 if (folder_to_select_account == account) {
1780                         modest_folder_view_disable_next_folder_selection (self);
1781                         g_object_unref (priv->folder_to_select);
1782                         priv->folder_to_select = NULL;
1783                 }
1784                 g_object_unref (folder_to_select_account);
1785         }
1786
1787         if (!get_inner_models (MODEST_FOLDER_VIEW (user_data),
1788                                &filter_model, NULL, &model))
1789                 return;
1790
1791         /* Disconnect the signal handler */
1792         if (TNY_IS_GTK_FOLDER_LIST_STORE (model) &&
1793             MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (account)) {
1794                 if (g_signal_handler_is_connected (account,
1795                                                    priv->outbox_deleted_handler))
1796                         g_signal_handler_disconnect (account,
1797                                                      priv->outbox_deleted_handler);
1798         }
1799
1800         /* Remove the account from the model */
1801         tny_list_remove (TNY_LIST (model), G_OBJECT (account));
1802
1803         /* If the removed account is the currently viewed one then
1804            clear the configuration value. The new visible account will be the default account */
1805         if (priv->visible_account_id &&
1806             !strcmp (priv->visible_account_id, tny_account_get_id (account))) {
1807
1808                 /* Clear the current visible account_id */
1809                 modest_folder_view_set_account_id_of_visible_server_account (self, NULL);
1810                 modest_folder_view_set_mailbox (self, NULL);
1811
1812                 /* Call the restore method, this will set the new visible account */
1813                 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
1814                                               MODEST_CONF_FOLDER_VIEW_KEY);
1815         }
1816
1817         /* Refilter the model */
1818         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1819
1820         /* Select the first INBOX if the currently selected folder
1821            belongs to the account that is being deleted */
1822         if (same_account)
1823                 g_idle_add (on_idle_select_first_inbox_or_local, self);
1824 }
1825
1826 void
1827 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
1828 {
1829         GtkTreeViewColumn *col;
1830
1831         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
1832
1833         col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
1834         if (!col) {
1835                 g_printerr ("modest: failed get column for title\n");
1836                 return;
1837         }
1838
1839         gtk_tree_view_column_set_title (col, title);
1840         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
1841                                            title != NULL);
1842 }
1843
1844 static gboolean
1845 modest_folder_view_on_map (ModestFolderView *self,
1846                            GdkEventExpose *event,
1847                            gpointer data)
1848 {
1849         ModestFolderViewPrivate *priv;
1850
1851         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1852
1853         /* This won't happen often */
1854         if (G_UNLIKELY (priv->reselect)) {
1855                 /* Select the first inbox or the local account if not found */
1856
1857                 /* TODO: this could cause a lock at startup, so we
1858                    comment it for the moment. We know that this will
1859                    be a bug, because the INBOX is not selected, but we
1860                    need to rewrite some parts of Modest to avoid the
1861                    deathlock situation */
1862                 /* TODO: check if this is still the case */
1863                 priv->reselect = FALSE;
1864                 modest_folder_view_select_first_inbox_or_local (self);
1865                 /* Notify the display name observers */
1866                 g_signal_emit (G_OBJECT(self),
1867                                signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1868                                NULL);
1869         }
1870
1871         if (priv->reexpand) {
1872                 expand_root_items (self);
1873                 priv->reexpand = FALSE;
1874         }
1875
1876         return FALSE;
1877 }
1878
1879 GtkWidget*
1880 modest_folder_view_new (TnyFolderStoreQuery *query)
1881 {
1882         return modest_folder_view_new_full (query, TRUE);
1883 }
1884
1885 GtkWidget*
1886 modest_folder_view_new_full (TnyFolderStoreQuery *query, gboolean do_refresh)
1887 {
1888         GObject *self;
1889         ModestFolderViewPrivate *priv;
1890         GtkTreeSelection *sel;
1891
1892         self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, 
1893 #ifdef MODEST_TOOLKIT_HILDON2
1894                                        "hildon-ui-mode", HILDON_UI_MODE_NORMAL,
1895 #endif
1896                                        NULL));
1897         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1898
1899         if (query)
1900                 priv->query = g_object_ref (query);
1901
1902         priv->do_refresh = do_refresh;
1903
1904         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
1905         priv->changed_signal = g_signal_connect (sel, "changed",
1906                                                  G_CALLBACK (on_selection_changed), self);
1907
1908         g_signal_connect (self, "row-activated", G_CALLBACK (on_row_activated), self);
1909
1910         g_signal_connect (self, "expose-event", G_CALLBACK (modest_folder_view_on_map), NULL);
1911
1912         return GTK_WIDGET(self);
1913 }
1914
1915 /* this feels dirty; any other way to expand all the root items? */
1916 static void
1917 expand_root_items (ModestFolderView *self)
1918 {
1919         GtkTreePath *path;
1920         GtkTreeModel *model;
1921         GtkTreeIter iter;
1922
1923         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1924         path = gtk_tree_path_new_first ();
1925
1926         /* all folders should have child items, so.. */
1927         do {
1928                 gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE);
1929                 gtk_tree_path_next (path);
1930         } while (gtk_tree_model_get_iter (model, &iter, path));
1931
1932         gtk_tree_path_free (path);
1933 }
1934
1935 static gboolean
1936 is_parent_of (TnyFolder *a, TnyFolder *b)
1937 {
1938         const gchar *a_id;
1939         gboolean retval = FALSE;
1940
1941         a_id = tny_folder_get_id (a);
1942         if (a_id) {
1943                 gchar *string_to_match;
1944                 const gchar *b_id;
1945
1946                 string_to_match = g_strconcat (a_id, "/", NULL);
1947                 b_id = tny_folder_get_id (b);
1948                 retval = g_str_has_prefix (b_id, string_to_match);
1949                 g_free (string_to_match);
1950         }
1951         
1952         return retval;
1953 }
1954
1955 typedef struct _ForeachFolderInfo {
1956         gchar *needle;
1957         gboolean found;
1958 } ForeachFolderInfo;
1959
1960 static gboolean 
1961 foreach_folder_with_id (GtkTreeModel *model,
1962                         GtkTreePath *path,
1963                         GtkTreeIter *iter,
1964                         gpointer data)
1965 {
1966         ForeachFolderInfo *info;
1967         GObject *instance;
1968
1969         info = (ForeachFolderInfo *) data;
1970         gtk_tree_model_get (model, iter,
1971                             INSTANCE_COLUMN, &instance,
1972                             -1);
1973
1974         if (TNY_IS_FOLDER (instance)) {
1975                 const gchar *id;
1976                 gchar *collate;
1977                 id = tny_folder_get_id (TNY_FOLDER (instance));
1978                 if (id) {
1979                         collate = g_utf8_collate_key (id, -1);
1980                         info->found = !strcmp (info->needle, collate);
1981                         g_free (collate);
1982                 }
1983         }
1984
1985         if (instance)
1986                 g_object_unref (instance);
1987
1988         return info->found;
1989         
1990 }
1991
1992
1993 static gboolean
1994 has_folder_with_id (ModestFolderView *self, const gchar *id)
1995 {
1996         GtkTreeModel *model;
1997         ForeachFolderInfo info = {NULL, FALSE};
1998
1999         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2000         info.needle = g_utf8_collate_key (id, -1);
2001         
2002         gtk_tree_model_foreach (model, foreach_folder_with_id, &info);
2003         g_free (info.needle);
2004
2005         return info.found;
2006 }
2007
2008 static gboolean
2009 has_child_with_name_of (ModestFolderView *self, TnyFolder *a, TnyFolder *b)
2010 {
2011         const gchar *a_id;
2012         gboolean retval = FALSE;
2013
2014         a_id = tny_folder_get_id (a);
2015         if (a_id) {
2016                 const gchar *b_id;
2017                 b_id = tny_folder_get_id (b);
2018                 
2019                 if (b_id) {
2020                         const gchar *last_bar;
2021                         gchar *string_to_match;
2022                         last_bar = g_strrstr (b_id, "/");
2023                         if (last_bar)
2024                                 last_bar++;
2025                         else
2026                                 last_bar = b_id;
2027                         string_to_match = g_strconcat (a_id, "/", last_bar, NULL);
2028                         retval = has_folder_with_id (self, string_to_match);
2029                         g_free (string_to_match);
2030                 }
2031         }
2032
2033         return retval;
2034 }
2035
2036 static gboolean
2037 check_move_to_this_folder_valid (ModestFolderView *self, TnyFolder *folder)
2038 {
2039         ModestFolderViewPrivate *priv;
2040         TnyIterator *iterator;
2041         gboolean retval = TRUE;
2042
2043         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
2044         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2045
2046         for (iterator = tny_list_create_iterator (priv->list_to_move);
2047              retval && !tny_iterator_is_done (iterator);
2048              tny_iterator_next (iterator)) {
2049                 GObject *instance;
2050                 instance = tny_iterator_get_current (iterator);
2051                 if (instance == (GObject *) folder) {
2052                         retval = FALSE;
2053                 } else if (TNY_IS_FOLDER (instance)) {
2054                         retval = !is_parent_of (TNY_FOLDER (instance), folder);
2055                         if (retval) {
2056                                 retval = !has_child_with_name_of (self, folder, TNY_FOLDER (instance));
2057                         }
2058                 }
2059                 g_object_unref (instance);
2060         }
2061         g_object_unref (iterator);
2062
2063         return retval;
2064 }
2065
2066
2067 /*
2068  * We use this function to implement the
2069  * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
2070  * account in this case, and the local folders.
2071  */
2072 static gboolean
2073 filter_row (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
2074 {
2075         ModestFolderViewPrivate *priv;
2076         gboolean retval = TRUE;
2077         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2078         GObject *instance = NULL;
2079         const gchar *id = NULL;
2080         guint i;
2081         gboolean found = FALSE;
2082         gboolean cleared = FALSE;
2083         ModestTnyFolderRules rules = 0;
2084         gchar *fname;
2085
2086         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE);
2087         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
2088
2089         gtk_tree_model_get (model, iter,
2090                             NAME_COLUMN, &fname,
2091                             TYPE_COLUMN, &type,
2092                             INSTANCE_COLUMN, &instance,
2093                             -1);
2094
2095         /* Do not show if there is no instance, this could indeed
2096            happen when the model is being modified while it's being
2097            drawn. This could occur for example when moving folders
2098            using drag&drop */
2099         if (!instance) {
2100                 g_free (fname);
2101                 return FALSE;
2102         }
2103
2104         if (TNY_IS_ACCOUNT (instance)) {
2105                 TnyAccount *acc = TNY_ACCOUNT (instance);
2106                 const gchar *account_id = tny_account_get_id (acc);
2107
2108                 /* If it isn't a special folder,
2109                  * don't show it unless it is the visible account: */
2110                 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
2111                     !modest_tny_account_is_virtual_local_folders (acc) &&
2112                     strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
2113
2114                         /* Show only the visible account id */
2115                         if (priv->visible_account_id) {
2116                                 if (strcmp (account_id, priv->visible_account_id))
2117                                         retval = FALSE;
2118                         } else {
2119                                 retval = FALSE;
2120                         }
2121                 }
2122
2123                 /* Never show these to the user. They are merged into one folder
2124                  * in the local-folders account instead: */
2125                 if (retval && MODEST_IS_TNY_OUTBOX_ACCOUNT (acc))
2126                         retval = FALSE;
2127         } else {
2128                 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE) {
2129                         /* Only show special folders for current account if needed */
2130                         if (TNY_IS_FOLDER (instance) && !TNY_IS_MERGE_FOLDER (instance)) {
2131                                 TnyAccount *account;
2132
2133                                 account = tny_folder_get_account (TNY_FOLDER (instance));
2134
2135                                 if (TNY_IS_ACCOUNT (account)) {
2136                                         const gchar *account_id = tny_account_get_id (account);
2137
2138                                         if (!modest_tny_account_is_virtual_local_folders (account) &&
2139                                             strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
2140                                                 /* Show only the visible account id */
2141                                                 if (priv->visible_account_id) {
2142                                                   if (strcmp (account_id, priv->visible_account_id)) {
2143                                                           retval = FALSE;
2144                                                   } else if (priv->mailbox) {
2145                                                           /* Filter mailboxes */
2146                                                           if (!g_str_has_prefix (fname, priv->mailbox)) {
2147                                                                   retval = FALSE;
2148                                                           } else if (!strcmp (fname, priv->mailbox)) {
2149                                                                   /* Hide mailbox parent */
2150                                                                   retval = FALSE;
2151                                                           }
2152                                                   }
2153                                                 }
2154                                         }
2155                                                 g_object_unref (account);
2156                                 }
2157                         }
2158
2159                 }
2160         }
2161
2162         /* Check hiding (if necessary) */
2163         cleared = modest_email_clipboard_cleared (priv->clipboard);
2164         if ((retval) && (!cleared) && (TNY_IS_FOLDER (instance))) {
2165                 id = tny_folder_get_id (TNY_FOLDER(instance));
2166                 if (priv->hidding_ids != NULL)
2167                         for (i=0; i < priv->n_selected && !found; i++)
2168                                 if (priv->hidding_ids[i] != NULL && id != NULL)
2169                                         found = (!strcmp (priv->hidding_ids[i], id));
2170
2171                 retval = !found;
2172         }
2173
2174         /* If this is a move to dialog, hide Sent, Outbox and Drafts
2175         folder as no message can be move there according to UI specs */
2176         if (retval && !priv->show_non_move) {
2177                 if (priv->list_to_move && 
2178                     tny_list_get_length (priv->list_to_move) > 0 &&
2179                     TNY_IS_FOLDER (instance)) {
2180                         retval = check_move_to_this_folder_valid (MODEST_FOLDER_VIEW (data), TNY_FOLDER (instance));
2181                 }
2182                 if (retval && TNY_IS_FOLDER (instance) && 
2183                     modest_tny_folder_is_local_folder (TNY_FOLDER (instance))) {
2184                         switch (type) {
2185                         case TNY_FOLDER_TYPE_OUTBOX:
2186                         case TNY_FOLDER_TYPE_SENT:
2187                         case TNY_FOLDER_TYPE_DRAFTS:
2188                                 retval = FALSE;
2189                                 break;
2190                         case TNY_FOLDER_TYPE_UNKNOWN:
2191                         case TNY_FOLDER_TYPE_NORMAL:
2192                                 type = modest_tny_folder_guess_folder_type(TNY_FOLDER(instance));
2193                                 if (type == TNY_FOLDER_TYPE_INVALID)
2194                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
2195                                 
2196                                 if (type == TNY_FOLDER_TYPE_OUTBOX ||
2197                                     type == TNY_FOLDER_TYPE_SENT
2198                                     || type == TNY_FOLDER_TYPE_DRAFTS)
2199                                         retval = FALSE;
2200                                 break;
2201                         default:
2202                                 break;
2203                         }
2204                 }
2205                 if (retval && TNY_IS_ACCOUNT (instance) &&
2206                     modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (instance))) {
2207                         ModestProtocolType protocol_type;
2208
2209                         protocol_type = modest_tny_account_get_protocol_type (TNY_ACCOUNT (instance));
2210                         retval  = !modest_protocol_registry_protocol_type_has_tag
2211                                 (modest_runtime_get_protocol_registry (),
2212                                  protocol_type,
2213                                  MODEST_PROTOCOL_REGISTRY_STORE_FORBID_INCOMING_XFERS);
2214                 }
2215         }
2216
2217         /* apply special filters */
2218         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_ACCOUNTS)) {
2219                 if (TNY_IS_ACCOUNT (instance))
2220                         return FALSE;
2221         }
2222
2223         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_FOLDERS)) {
2224                 if (TNY_IS_FOLDER (instance))
2225                         return FALSE;
2226         }
2227
2228         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_LOCAL_FOLDERS)) {
2229                 if (TNY_IS_ACCOUNT (instance)) {
2230                         if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (instance)))
2231                                 return FALSE;
2232                 } else if (TNY_IS_FOLDER (instance)) {
2233                         if (modest_tny_folder_is_local_folder (TNY_FOLDER (instance)))
2234                                 return FALSE;
2235                 }
2236         }
2237
2238         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_MCC_FOLDERS)) {
2239                 if (TNY_IS_ACCOUNT (instance)) {
2240                         if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance)))
2241                                 return FALSE;
2242                 } else if (TNY_IS_FOLDER (instance)) {
2243                         if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance)))
2244                                 return FALSE;
2245                 }
2246         }
2247
2248         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_SHOW_ONLY_MAILBOXES)) {
2249                 /* A mailbox is a fake folder with an @ in the middle of the name */
2250                 if (!TNY_IS_FOLDER (instance) ||
2251                     !(tny_folder_get_caps (TNY_FOLDER (instance)) & TNY_FOLDER_CAPS_NOSELECT)) {
2252                         return FALSE;
2253                 } else {
2254                         const gchar *folder_name;
2255                         folder_name = tny_folder_get_name (TNY_FOLDER (instance));
2256                         if (!folder_name || strchr (folder_name, '@') == NULL)
2257                                 return FALSE;
2258                 }
2259                 
2260         }
2261
2262         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_CAN_HAVE_FOLDERS)) {
2263                 if (TNY_IS_FOLDER (instance)) {
2264                         /* Check folder rules */
2265                         ModestTnyFolderRules rules;
2266
2267                         rules = modest_tny_folder_get_rules (TNY_FOLDER (instance));
2268                         retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE);
2269                 } else if (TNY_IS_ACCOUNT (instance)) {
2270                         if (modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (instance))) {
2271                                 retval = FALSE;
2272                         } else {
2273                                 retval = TRUE;
2274                         }
2275                 }
2276         }
2277
2278         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_MANDATORY_FOLDERS)) {
2279                 if (TNY_IS_FOLDER (instance)) {
2280                         TnyFolderType guess_type;
2281
2282                         if (TNY_FOLDER_TYPE_NORMAL) {
2283                                 guess_type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
2284                         } else {
2285                                 guess_type = type;
2286                         }
2287
2288                         switch (type) {
2289                         case TNY_FOLDER_TYPE_OUTBOX:
2290                         case TNY_FOLDER_TYPE_SENT:
2291                         case TNY_FOLDER_TYPE_DRAFTS:
2292                         case TNY_FOLDER_TYPE_ARCHIVE:
2293                         case TNY_FOLDER_TYPE_INBOX:
2294                                 retval = FALSE;
2295                                 break;
2296                         case TNY_FOLDER_TYPE_UNKNOWN:
2297                         case TNY_FOLDER_TYPE_NORMAL:
2298                                 break;
2299                         default:
2300                                 break;
2301                         }
2302
2303                 } else if (TNY_IS_ACCOUNT (instance)) {
2304                         retval = FALSE;
2305                 }
2306         }
2307
2308         if (retval && TNY_IS_FOLDER (instance)) {
2309                 rules = modest_tny_folder_get_rules (TNY_FOLDER (instance));
2310         }
2311
2312         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_DELETABLE)) {
2313                 if (TNY_IS_FOLDER (instance)) {
2314                         retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE);
2315                 } else if (TNY_IS_ACCOUNT (instance)) {
2316                         retval = FALSE;
2317                 }
2318         }
2319
2320         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_RENAMEABLE)) {
2321                 if (TNY_IS_FOLDER (instance)) {
2322                         retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE);
2323                 } else if (TNY_IS_ACCOUNT (instance)) {
2324                         retval = FALSE;
2325                 }
2326         }
2327
2328         if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_MOVEABLE)) {
2329                 if (TNY_IS_FOLDER (instance)) {
2330                         retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE);
2331                 } else if (TNY_IS_ACCOUNT (instance)) {
2332                         retval = FALSE;
2333                 }
2334         }
2335
2336         /* Free */
2337         g_object_unref (instance);
2338         g_free (fname);
2339
2340         return retval;
2341 }
2342
2343
2344 gboolean
2345 modest_folder_view_update_model (ModestFolderView *self,
2346                                  TnyAccountStore *account_store)
2347 {
2348         ModestFolderViewPrivate *priv;
2349         GtkTreeModel *model;
2350         GtkTreeModel *filter_model = NULL, *sortable = NULL;
2351
2352         g_return_val_if_fail (self && MODEST_IS_FOLDER_VIEW (self), FALSE);
2353         g_return_val_if_fail (account_store && MODEST_IS_TNY_ACCOUNT_STORE(account_store),
2354                               FALSE);
2355
2356         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2357
2358         /* Notify that there is no folder selected */
2359         g_signal_emit (G_OBJECT(self),
2360                        signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
2361                        NULL, FALSE);
2362         if (priv->cur_folder_store) {
2363                 g_object_unref (priv->cur_folder_store);
2364                 priv->cur_folder_store = NULL;
2365         }
2366
2367         /* FIXME: the local accounts are not shown when the query
2368            selects only the subscribed folders */
2369 #ifdef MODEST_TOOLKIT_HILDON2
2370         TnyGtkFolderListStoreFlags flags;
2371         flags = TNY_GTK_FOLDER_LIST_STORE_FLAG_SHOW_PATH;
2372         if (priv->do_refresh)
2373                 flags |= TNY_GTK_FOLDER_LIST_STORE_FLAG_DELAYED_REFRESH;
2374         else
2375                 flags |= TNY_GTK_FOLDER_LIST_STORE_FLAG_NO_REFRESH;
2376         model = tny_gtk_folder_list_store_new_with_flags (NULL, 
2377                                                           flags);
2378         tny_gtk_folder_list_store_set_path_separator (TNY_GTK_FOLDER_LIST_STORE (model),
2379                                                       MODEST_FOLDER_PATH_SEPARATOR);
2380 #else
2381         model = tny_gtk_folder_store_tree_model_new (NULL);
2382 #endif
2383
2384         /* When the model is a list store (plain representation) the
2385            outbox is not a child of any account so we have to manually
2386            delete it because removing the local folders account won't
2387            delete it (because tny_folder_get_account() is not defined
2388            for a merge folder */
2389         if (TNY_IS_GTK_FOLDER_LIST_STORE (model)) {
2390                 TnyAccount *account;
2391                 ModestTnyAccountStore *acc_store;
2392
2393                 acc_store = modest_runtime_get_account_store ();
2394                 account = modest_tny_account_store_get_local_folders_account (acc_store);
2395
2396                 if (g_signal_handler_is_connected (account,
2397                                                    priv->outbox_deleted_handler))
2398                         g_signal_handler_disconnect (account,
2399                                                      priv->outbox_deleted_handler);
2400
2401                 priv->outbox_deleted_handler =
2402                         g_signal_connect (account,
2403                                           "outbox-deleted",
2404                                           G_CALLBACK (on_outbox_deleted_cb),
2405                                           self);
2406                 g_object_unref (account);
2407         }
2408
2409        if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ALL) {
2410                /* Get the accounts */
2411                tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
2412                                                TNY_LIST (model),
2413                                                TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
2414        } else {
2415                if (priv->visible_account_id) {
2416                        TnyAccount *account;
2417
2418                        /* Add local folders account */
2419                        account = modest_tny_account_store_get_local_folders_account ((ModestTnyAccountStore *) account_store);
2420
2421                        if (account) {
2422                                tny_list_append (TNY_LIST (model), (GObject *) account);
2423                                g_object_unref (account);
2424                        }
2425
2426                        account = modest_tny_account_store_get_mmc_folders_account ((ModestTnyAccountStore *) account_store);
2427
2428                        if (account) {
2429                                tny_list_append (TNY_LIST (model), (GObject *) account);
2430                                g_object_unref (account);
2431                        }
2432
2433                        /* Add visible account */
2434                        account = modest_tny_account_store_get_tny_account_by ((ModestTnyAccountStore *) account_store,
2435                                                                               MODEST_TNY_ACCOUNT_STORE_QUERY_ID,
2436                                                                               priv->visible_account_id);
2437                        if (account) {
2438                                tny_list_append (TNY_LIST (model), (GObject *) account);
2439                                g_object_unref (account);
2440                        } else {
2441                                g_warning ("You need to set an account first");
2442                                g_object_unref (model);
2443                                return FALSE;
2444                        }
2445                } else {
2446                        g_warning ("You need to set an account first");
2447                        g_object_unref (model);
2448                        return FALSE;
2449                }
2450        }
2451
2452         sortable = gtk_tree_model_sort_new_with_model (model);
2453         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
2454                                               NAME_COLUMN,
2455                                               GTK_SORT_ASCENDING);
2456         gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
2457                                          NAME_COLUMN,
2458                                          cmp_rows, NULL, NULL);
2459
2460         /* Create filter model */
2461         filter_model = gtk_tree_model_filter_new (sortable, NULL);
2462         gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
2463                                                 filter_row,
2464                                                 self,
2465                                                 NULL);
2466
2467         GtkTreeModel *old_tny_model = NULL;
2468         if (get_inner_models (self, NULL, NULL, &old_tny_model)) {
2469                 if (priv->signal_handlers > 0) {
2470                         priv->signal_handlers = modest_signal_mgr_disconnect (priv->signal_handlers,
2471                                                                               G_OBJECT (old_tny_model), 
2472                                                                               "activity-changed");
2473                 }
2474         }
2475
2476         /* Set new model */
2477         gtk_tree_view_set_model (GTK_TREE_VIEW(self), filter_model);
2478 #ifndef MODEST_TOOLKIT_HILDON2
2479         g_signal_connect (G_OBJECT(filter_model), "row-inserted",
2480                           (GCallback) on_row_inserted_maybe_select_folder, self);
2481 #endif
2482
2483 #ifdef MODEST_TOOLKIT_HILDON2
2484         priv->signal_handlers = modest_signal_mgr_connect (priv->signal_handlers,
2485                                                            G_OBJECT (model),
2486                                                            "activity-changed",
2487                                                            G_CALLBACK (on_activity_changed),
2488                                                            self);
2489 #endif
2490
2491         g_object_unref (model);
2492         g_object_unref (filter_model);
2493         g_object_unref (sortable);
2494
2495         /* Force a reselection of the INBOX next time the widget is shown */
2496         priv->reselect = TRUE;
2497
2498         return TRUE;
2499 }
2500
2501
2502 static void
2503 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
2504 {
2505         GtkTreeModel *model = NULL;
2506         TnyFolderStore *folder = NULL;
2507         GtkTreeIter iter;
2508         ModestFolderView *tree_view = NULL;
2509         ModestFolderViewPrivate *priv = NULL;
2510         gboolean selected = FALSE;
2511
2512         g_return_if_fail (sel);
2513         g_return_if_fail (user_data);
2514
2515         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
2516
2517         selected = gtk_tree_selection_get_selected (sel, &model, &iter);
2518
2519         tree_view = MODEST_FOLDER_VIEW (user_data);
2520
2521         if (selected) {
2522                 gtk_tree_model_get (model, &iter,
2523                                     INSTANCE_COLUMN, &folder,
2524                                     -1);
2525
2526                 /* If the folder is the same do not notify */
2527                 if (folder && priv->cur_folder_store == folder) {
2528                         g_object_unref (folder);
2529                         return;
2530                 }
2531         }
2532
2533         /* Current folder was unselected */
2534         if (priv->cur_folder_store) {
2535                 /* We must do this firstly because a libtinymail-camel
2536                    implementation detail. If we issue the signal
2537                    before doing the sync_async, then that signal could
2538                    cause (and it actually does it) a free of the
2539                    summary of the folder (because the main window will
2540                    clear the headers view */
2541 #ifndef MODEST_TOOLKIT_HILDON2
2542                 if (TNY_IS_FOLDER(priv->cur_folder_store))
2543                         tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
2544                                                FALSE, NULL, NULL, NULL);
2545 #endif
2546
2547                 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
2548                        priv->cur_folder_store, FALSE);
2549
2550                 g_object_unref (priv->cur_folder_store);
2551                 priv->cur_folder_store = NULL;
2552         }
2553
2554         /* New current references */
2555         priv->cur_folder_store = folder;
2556
2557         /* New folder has been selected. Do not notify if there is
2558            nothing new selected */
2559         if (selected) {
2560                 g_signal_emit (G_OBJECT(tree_view),
2561                                signals[FOLDER_SELECTION_CHANGED_SIGNAL],
2562                                0, priv->cur_folder_store, TRUE);
2563         }
2564 }
2565
2566 static void
2567 on_row_activated (GtkTreeView *treeview,
2568                   GtkTreePath *treepath,
2569                   GtkTreeViewColumn *column,
2570                   gpointer user_data)
2571 {
2572         GtkTreeModel *model = NULL;
2573         TnyFolderStore *folder = NULL;
2574         GtkTreeIter iter;
2575         ModestFolderView *self = NULL;
2576         ModestFolderViewPrivate *priv = NULL;
2577
2578         g_return_if_fail (treeview);
2579         g_return_if_fail (user_data);
2580
2581         self = MODEST_FOLDER_VIEW (user_data);
2582         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
2583
2584         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2585
2586         if (!gtk_tree_model_get_iter (model, &iter, treepath))
2587                 return;
2588
2589         gtk_tree_model_get (model, &iter,
2590                             INSTANCE_COLUMN, &folder,
2591                             -1);
2592
2593         g_signal_emit (G_OBJECT(self),
2594                        signals[FOLDER_ACTIVATED_SIGNAL],
2595                        0, folder);
2596
2597 #ifdef MODEST_TOOLKIT_HILDON2
2598         HildonUIMode ui_mode;
2599         g_object_get (G_OBJECT (self), "hildon-ui-mode", &ui_mode, NULL);
2600         if (ui_mode == HILDON_UI_MODE_NORMAL) {
2601                 if (priv->cur_folder_store)
2602                         g_object_unref (priv->cur_folder_store);
2603                 priv->cur_folder_store = g_object_ref (folder);
2604         }
2605 #endif
2606
2607         g_object_unref (folder);
2608 }
2609
2610 TnyFolderStore *
2611 modest_folder_view_get_selected (ModestFolderView *self)
2612 {
2613         ModestFolderViewPrivate *priv;
2614
2615         g_return_val_if_fail (self && MODEST_IS_FOLDER_VIEW(self), NULL);
2616
2617         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2618         if (priv->cur_folder_store)
2619                 g_object_ref (priv->cur_folder_store);
2620
2621         return priv->cur_folder_store;
2622 }
2623
2624 static gint
2625 get_cmp_rows_type_pos (GObject *folder)
2626 {
2627         /* Remote accounts -> Local account -> MMC account .*/
2628         /* 0, 1, 2 */
2629
2630         if (TNY_IS_ACCOUNT (folder) &&
2631                 modest_tny_account_is_virtual_local_folders (
2632                         TNY_ACCOUNT (folder))) {
2633                 return 1;
2634         } else if (TNY_IS_ACCOUNT (folder)) {
2635                 TnyAccount *account = TNY_ACCOUNT (folder);
2636                 const gchar *account_id = tny_account_get_id (account);
2637                 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
2638                         return 2;
2639                 else
2640                         return 0;
2641         }
2642         else {
2643                 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
2644                 return -1; /* Should never happen */
2645         }
2646 }
2647
2648 static gboolean
2649 inbox_is_special (TnyFolderStore *folder_store)
2650 {
2651         gboolean is_special = TRUE;
2652
2653         if (TNY_IS_FOLDER (folder_store)) {
2654                 const gchar *id;
2655                 gchar *downcase;
2656                 gchar *last_bar;
2657                 gchar *last_inbox_bar;
2658
2659                 id = tny_folder_get_id (TNY_FOLDER (folder_store));
2660                 downcase = g_utf8_strdown (id, -1);
2661                 last_bar = g_strrstr (downcase, "/");
2662                 if (last_bar) {
2663                         last_inbox_bar = g_strrstr  (downcase, "inbox/");
2664                         if ((last_inbox_bar == NULL) || (last_inbox_bar + 5 != last_bar))
2665                                 is_special = FALSE;
2666                 } else {
2667                         is_special = FALSE;
2668                 }
2669                 g_free (downcase);
2670         }
2671         return is_special;
2672 }
2673
2674 static gint
2675 get_cmp_pos (TnyFolderType t, TnyFolder *folder_store)
2676 {
2677         TnyAccount *account;
2678         gboolean is_special;
2679         /* Inbox, Outbox, Drafts, Sent, User */
2680         /* 0, 1, 2, 3, 4 */
2681
2682         if (!TNY_IS_FOLDER (folder_store))
2683                 return 4;
2684         switch (t) {
2685         case TNY_FOLDER_TYPE_INBOX:
2686         {
2687                 account = tny_folder_get_account (folder_store);
2688                 is_special = (get_cmp_rows_type_pos (G_OBJECT (account)) == 0);
2689
2690                 /* In inbox case we need to know if the inbox is really the top
2691                  * inbox of the account, or if it's a submailbox inbox. To do
2692                  * this we'll apply an heuristic rule: Find last "/" and check
2693                  * if it's preceeded by another Inbox */
2694                 is_special = is_special && !inbox_is_special (TNY_FOLDER_STORE (folder_store));
2695                 g_object_unref (account);
2696                 return is_special?0:4;
2697         }
2698         break;
2699         case TNY_FOLDER_TYPE_OUTBOX:
2700                 return (TNY_IS_MERGE_FOLDER (folder_store))?2:4;
2701                 break;
2702         case TNY_FOLDER_TYPE_DRAFTS:
2703         {
2704                 account = tny_folder_get_account (folder_store);
2705                 is_special = (get_cmp_rows_type_pos (G_OBJECT (account)) == 1);
2706                 g_object_unref (account);
2707                 return is_special?1:4;
2708         }
2709         break;
2710         case TNY_FOLDER_TYPE_SENT:
2711         {
2712                 account = tny_folder_get_account (folder_store);
2713                 is_special = (get_cmp_rows_type_pos (G_OBJECT (account)) == 1);
2714                 g_object_unref (account);
2715                 return is_special?3:4;
2716         }
2717         break;
2718         default:
2719                 return 4;
2720         }
2721 }
2722
2723 static gint
2724 compare_account_names (TnyAccount *a1, TnyAccount *a2)
2725 {
2726         const gchar *a1_name, *a2_name;
2727
2728         a1_name = tny_account_get_name (a1);
2729         a2_name = tny_account_get_name (a2);
2730
2731         return modest_text_utils_utf8_strcmp (a1_name, a2_name, TRUE);
2732 }
2733
2734 static gint
2735 compare_accounts (TnyFolderStore *s1, TnyFolderStore *s2)
2736 {
2737         TnyAccount *a1 = NULL, *a2 = NULL;
2738         gint cmp;
2739
2740         if (TNY_IS_ACCOUNT (s1)) {
2741                 a1 = TNY_ACCOUNT (g_object_ref (s1));
2742         } else if (!TNY_IS_MERGE_FOLDER (s1)) {
2743                 a1 = tny_folder_get_account (TNY_FOLDER (s1));
2744         }
2745
2746         if (TNY_IS_ACCOUNT (s2)) {
2747                 a2 = TNY_ACCOUNT (g_object_ref (s2));
2748         } else  if (!TNY_IS_MERGE_FOLDER (s2)) {
2749                 a2 = tny_folder_get_account (TNY_FOLDER (s2));
2750         }
2751
2752         if (!a1 || !a2) {
2753                 if (!a1 && !a2)
2754                         cmp = 0;
2755                 else if (!a1)
2756                         cmp = 1;
2757                 else
2758                         cmp = -1;
2759                 goto finish;
2760         }
2761
2762         if (a1 == a2) {
2763                 cmp = 0;
2764                 goto finish;
2765         }
2766         /* First we sort with the type of account */
2767         cmp = get_cmp_rows_type_pos (G_OBJECT (a1)) - get_cmp_rows_type_pos (G_OBJECT (a2));
2768         if (cmp != 0)
2769                 goto finish;
2770
2771         cmp = compare_account_names (a1, a2);
2772
2773 finish:
2774         if (a1)
2775                 g_object_unref (a1);
2776         if (a2)
2777                 g_object_unref (a2);
2778
2779         return cmp;
2780 }
2781
2782 static gint
2783 compare_accounts_first (TnyFolderStore *s1, TnyFolderStore *s2)
2784 {
2785         gint is_account1, is_account2;
2786
2787         is_account1 = TNY_IS_ACCOUNT (s1)?1:0;
2788         is_account2 = TNY_IS_ACCOUNT (s2)?1:0;
2789
2790         return is_account2 - is_account1;
2791 }
2792
2793 static gint
2794 compare_folders (const gchar *name1, const gchar *name2)
2795 {
2796         const gchar *separator1, *separator2;
2797         const gchar *next1, *next2;
2798         gchar *top1, *top2;
2799         gint cmp;
2800
2801         if (name1 == NULL || name1[0] == '\0')
2802                 return -1;
2803         if (name2 == NULL || name2[0] == '\0')
2804                 return 1;
2805
2806         separator1 = strstr (name1, MODEST_FOLDER_PATH_SEPARATOR);
2807         if (separator1) {
2808                 top1 = g_strndup (name1, separator1 - name1);
2809         } else {
2810                 top1 = g_strdup (name1);
2811         }
2812
2813         separator2 = strstr (name2, MODEST_FOLDER_PATH_SEPARATOR);
2814         if (separator2) {
2815                 top2 = g_strndup (name2, separator2 - name2);
2816         } else {
2817                 top2 = g_strdup (name2);
2818         }
2819
2820
2821         cmp = modest_text_utils_utf8_strcmp (top1, top2, TRUE);
2822         g_free (top1);
2823         g_free (top2);
2824
2825         if (cmp != 0)
2826                 return cmp;
2827
2828         if (separator1 == NULL && separator2 == NULL)
2829                 return 0;
2830
2831         next1 = (separator1 != NULL)?separator1 + strlen (MODEST_FOLDER_PATH_SEPARATOR):NULL;
2832         next2 = (separator2 != NULL)?separator2 + strlen (MODEST_FOLDER_PATH_SEPARATOR):NULL;
2833
2834         return compare_folders (next1, next2);
2835 }
2836
2837
2838 /*
2839  * This function orders the mail accounts according to these rules:
2840  * 1st - remote accounts
2841  * 2nd - local account
2842  * 3rd - MMC account
2843  */
2844 static gint
2845 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
2846           gpointer user_data)
2847 {
2848         gint cmp = 0;
2849         gchar *name1 = NULL;
2850         gchar *name2 = NULL;
2851         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2852         TnyFolderType type2 = TNY_FOLDER_TYPE_UNKNOWN;
2853         GObject *folder1 = NULL;
2854         GObject *folder2 = NULL;
2855
2856         gtk_tree_model_get (tree_model, iter1,
2857                             NAME_COLUMN, &name1,
2858                             TYPE_COLUMN, &type,
2859                             INSTANCE_COLUMN, &folder1,
2860                             -1);
2861         gtk_tree_model_get (tree_model, iter2,
2862                             NAME_COLUMN, &name2,
2863                             TYPE_COLUMN, &type2,
2864                             INSTANCE_COLUMN, &folder2,
2865                             -1);
2866
2867         /* Return if we get no folder. This could happen when folder
2868            operations are happening. The model is updated after the
2869            folder copy/move actually occurs, so there could be
2870            situations where the model to be drawn is not correct */
2871         if (!folder1 || !folder2)
2872                 goto finish;
2873
2874         /* Sort by type. First the special folders, then the archives */
2875         cmp = get_cmp_pos (type, (TnyFolder *) folder1) - get_cmp_pos (type2, (TnyFolder *) folder2);
2876         if (cmp != 0)
2877                 goto finish;
2878
2879         /* Now we sort using the account of each folder */
2880         if (TNY_IS_FOLDER_STORE (folder1) && 
2881             TNY_IS_FOLDER_STORE (folder2)) {
2882                 cmp = compare_accounts (TNY_FOLDER_STORE (folder1), TNY_FOLDER_STORE (folder2));
2883                 if (cmp != 0)
2884                         goto finish;
2885
2886                 /* Each group is preceeded by its account */
2887                 cmp = compare_accounts_first (TNY_FOLDER_STORE (folder1), TNY_FOLDER_STORE (folder2));
2888                 if (cmp != 0)
2889                         goto finish;
2890         }
2891
2892         /* Pure sort by name */
2893         cmp = compare_folders (name1, name2);
2894  finish:
2895         if (folder1)
2896                 g_object_unref(G_OBJECT(folder1));
2897         if (folder2)
2898                 g_object_unref(G_OBJECT(folder2));
2899
2900         g_free (name1);
2901         g_free (name2);
2902
2903         return cmp;
2904 }
2905
2906 /*****************************************************************************/
2907 /*                        DRAG and DROP stuff                                */
2908 /*****************************************************************************/
2909 /*
2910  * This function fills the #GtkSelectionData with the row and the
2911  * model that has been dragged. It's called when this widget is a
2912  * source for dnd after the event drop happened
2913  */
2914 static void
2915 on_drag_data_get (GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data,
2916                   guint info, guint time, gpointer data)
2917 {
2918         GtkTreeSelection *selection;
2919         GtkTreeModel *model;
2920         GtkTreeIter iter;
2921         GtkTreePath *source_row;
2922
2923         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
2924         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
2925
2926                 source_row = gtk_tree_model_get_path (model, &iter);
2927                 gtk_tree_set_row_drag_data (selection_data,
2928                                             model,
2929                                             source_row);
2930
2931                 gtk_tree_path_free (source_row);
2932         }
2933 }
2934
2935 typedef struct _DndHelper {
2936         ModestFolderView *folder_view;
2937         gboolean delete_source;
2938         GtkTreePath *source_row;
2939 } DndHelper;
2940
2941 static void
2942 dnd_helper_destroyer (DndHelper *helper)
2943 {
2944         /* Free the helper */
2945         gtk_tree_path_free (helper->source_row);
2946         g_slice_free (DndHelper, helper);
2947 }
2948
2949 static void
2950 xfer_folder_cb (ModestMailOperation *mail_op,
2951                 TnyFolder *new_folder,
2952                 gpointer user_data)
2953 {
2954         if (new_folder) {
2955                 /* Select the folder */
2956                 modest_folder_view_select_folder (MODEST_FOLDER_VIEW (user_data),
2957                                                   new_folder, FALSE);
2958         }
2959 }
2960
2961
2962 /* get the folder for the row the treepath refers to. */
2963 /* folder must be unref'd */
2964 static TnyFolderStore *
2965 tree_path_to_folder (GtkTreeModel *model, GtkTreePath *path)
2966 {
2967         GtkTreeIter iter;
2968         TnyFolderStore *folder = NULL;
2969
2970         if (gtk_tree_model_get_iter (model,&iter, path))
2971                 gtk_tree_model_get (model, &iter,
2972                                     INSTANCE_COLUMN, &folder,
2973                                     -1);
2974         return folder;
2975 }
2976
2977
2978 /*
2979  * This function is used by drag_data_received_cb to manage drag and
2980  * drop of a header, i.e, and drag from the header view to the folder
2981  * view.
2982  */
2983 static void
2984 drag_and_drop_from_header_view (GtkTreeModel *source_model,
2985                                 GtkTreeModel *dest_model,
2986                                 GtkTreePath  *dest_row,
2987                                 GtkSelectionData *selection_data)
2988 {
2989         TnyList *headers = NULL;
2990         TnyFolder *folder = NULL, *src_folder = NULL;
2991         TnyFolderType folder_type;
2992         GtkTreeIter source_iter, dest_iter;
2993         ModestWindowMgr *mgr = NULL;
2994         ModestWindow *main_win = NULL;
2995         gchar **uris, **tmp;
2996
2997         /* Build the list of headers */
2998         mgr = modest_runtime_get_window_mgr ();
2999         headers = tny_simple_list_new ();
3000         uris = modest_dnd_selection_data_get_paths (selection_data);
3001         tmp = uris;
3002
3003         while (*tmp != NULL) {
3004                 TnyHeader *header;
3005                 GtkTreePath *path;
3006                 gboolean first = TRUE;
3007
3008                 /* Get header */
3009                 path = gtk_tree_path_new_from_string (*tmp);
3010                 gtk_tree_model_get_iter (source_model, &source_iter, path);
3011                 gtk_tree_model_get (source_model, &source_iter,
3012                                     TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
3013                                     &header, -1);
3014
3015                 /* Do not enable d&d of headers already opened */
3016                 if (!modest_window_mgr_find_registered_header(mgr, header, NULL))
3017                         tny_list_append (headers, G_OBJECT (header));
3018
3019                 if (G_UNLIKELY (first)) {
3020                         src_folder = tny_header_get_folder (header);
3021                         first = FALSE;
3022                 }
3023
3024                 /* Free and go on */
3025                 gtk_tree_path_free (path);
3026                 g_object_unref (header);
3027                 tmp++;
3028         }
3029         g_strfreev (uris);
3030
3031         /* This could happen ig we perform a d&d very quickly over the
3032            same row that row could dissapear because message is
3033            transferred */
3034         if (!TNY_IS_FOLDER (src_folder))
3035                 goto cleanup;
3036
3037         /* Get the target folder */
3038         gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
3039         gtk_tree_model_get (dest_model, &dest_iter,
3040                             INSTANCE_COLUMN,
3041                             &folder, -1);
3042
3043         if (!folder || !TNY_IS_FOLDER(folder)) {
3044 /*              g_warning ("%s: not a valid target folder (%p)", __FUNCTION__, folder); */
3045                 goto cleanup;
3046         }
3047
3048         folder_type = modest_tny_folder_guess_folder_type (folder);
3049         if (folder_type == TNY_FOLDER_TYPE_INVALID) {
3050 /*              g_warning ("%s: invalid target folder", __FUNCTION__); */
3051                 goto cleanup;  /* cannot move messages there */
3052         }
3053
3054         if (modest_tny_folder_get_rules((TNY_FOLDER(folder))) & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3055 /*              g_warning ("folder not writable"); */
3056                 goto cleanup; /* verboten! */
3057         }
3058
3059         /* Ask for confirmation to move */
3060         main_win = modest_window_mgr_get_main_window (mgr, FALSE); /* don't create */
3061         if (!main_win) {
3062                 g_warning ("%s: BUG: no main window found", __FUNCTION__);
3063                 goto cleanup;
3064         }
3065
3066         /* Transfer messages */
3067         modest_ui_actions_transfer_messages_helper (GTK_WINDOW (main_win), src_folder,
3068                                                     headers, folder);
3069
3070         /* Frees */
3071 cleanup:
3072         if (G_IS_OBJECT (src_folder))
3073                 g_object_unref (src_folder);
3074         if (G_IS_OBJECT(folder))
3075                 g_object_unref (G_OBJECT (folder));
3076         if (G_IS_OBJECT(headers))
3077                 g_object_unref (headers);
3078 }
3079
3080 typedef struct {
3081         TnyFolderStore *src_folder;
3082         TnyFolderStore *dst_folder;
3083         ModestFolderView *folder_view;
3084         DndHelper *helper;
3085 } DndFolderInfo;
3086
3087 static void
3088 dnd_folder_info_destroyer (DndFolderInfo *info)
3089 {
3090         if (info->src_folder)
3091                 g_object_unref (info->src_folder);
3092         if (info->dst_folder)
3093                 g_object_unref (info->dst_folder);
3094         g_slice_free (DndFolderInfo, info);
3095 }
3096
3097 static void
3098 dnd_on_connection_failed_destroyer (DndFolderInfo *info,
3099                                     GtkWindow *parent_window,
3100                                     TnyAccount *account)
3101 {
3102         /* Show error */
3103         modest_ui_actions_on_account_connection_error (parent_window, account);
3104
3105         /* Free the helper & info */
3106         dnd_helper_destroyer (info->helper);
3107         dnd_folder_info_destroyer (info);
3108 }
3109
3110 static void
3111 drag_and_drop_from_folder_view_src_folder_performer (gboolean canceled,
3112                                                      GError *err,
3113                                                      GtkWindow *parent_window,
3114                                                      TnyAccount *account,
3115                                                      gpointer user_data)
3116 {
3117         DndFolderInfo *info = NULL;
3118         ModestMailOperation *mail_op;
3119
3120         info = (DndFolderInfo *) user_data;
3121
3122         if (err || canceled) {
3123                 dnd_on_connection_failed_destroyer (info, parent_window, account);
3124                 return;
3125         }
3126
3127         /* Do the mail operation */
3128         mail_op = modest_mail_operation_new_with_error_handling ((GObject *) parent_window,
3129                                                                  modest_ui_actions_move_folder_error_handler,
3130                                                                  info->src_folder, NULL);
3131
3132         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
3133                                          mail_op);
3134
3135         /* Transfer the folder */
3136         modest_mail_operation_xfer_folder (mail_op,
3137                                            TNY_FOLDER (info->src_folder),
3138                                            info->dst_folder,
3139                                            info->helper->delete_source,
3140                                            xfer_folder_cb,
3141                                            info->helper->folder_view);
3142
3143         /* Frees */
3144         g_object_unref (G_OBJECT (mail_op));
3145         dnd_helper_destroyer (info->helper);
3146         dnd_folder_info_destroyer (info);
3147 }
3148
3149
3150 static void
3151 drag_and_drop_from_folder_view_dst_folder_performer (gboolean canceled,
3152                                                      GError *err,
3153                                                      GtkWindow *parent_window,
3154                                                      TnyAccount *account,
3155                                                      gpointer user_data)
3156 {
3157         DndFolderInfo *info = NULL;
3158
3159         info = (DndFolderInfo *) user_data;
3160
3161         if (err || canceled) {
3162                 dnd_on_connection_failed_destroyer (info, parent_window, account);
3163                 return;
3164         }
3165
3166         /* Connect to source folder and perform the copy/move */
3167         modest_platform_connect_if_remote_and_perform (NULL, TRUE,
3168                                                        info->src_folder,
3169                                                        drag_and_drop_from_folder_view_src_folder_performer,
3170                                                        info);
3171 }
3172
3173 /*
3174  * This function is used by drag_data_received_cb to manage drag and
3175  * drop of a folder, i.e, and drag from the folder view to the same
3176  * folder view.
3177  */
3178 static void
3179 drag_and_drop_from_folder_view (GtkTreeModel     *source_model,
3180                                 GtkTreeModel     *dest_model,
3181                                 GtkTreePath      *dest_row,
3182                                 GtkSelectionData *selection_data,
3183                                 DndHelper        *helper)
3184 {
3185         GtkTreeIter dest_iter, iter;
3186         TnyFolderStore *dest_folder = NULL;
3187         TnyFolderStore *folder = NULL;
3188         gboolean forbidden = FALSE;
3189         ModestWindow *win;
3190         DndFolderInfo *info = NULL;
3191
3192         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE); /* don't create */
3193         if (!win) {
3194                 g_warning ("%s: BUG: no main window", __FUNCTION__);
3195                 dnd_helper_destroyer (helper);
3196                 return;
3197         }
3198
3199         if (!forbidden) {
3200                 /* check the folder rules for the destination */
3201                 folder = tree_path_to_folder (dest_model, dest_row);
3202                 if (TNY_IS_FOLDER(folder)) {
3203                         ModestTnyFolderRules rules =
3204                                 modest_tny_folder_get_rules (TNY_FOLDER (folder));
3205                         forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE;
3206                 } else if (TNY_IS_FOLDER_STORE(folder)) {
3207                         /* enable local root as destination for folders */
3208                         if (!MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (folder) &&
3209                             !modest_tny_account_is_memory_card_account (TNY_ACCOUNT (folder)))
3210                                 forbidden = TRUE;
3211                 }
3212                 g_object_unref (folder);
3213         }
3214         if (!forbidden) {
3215                 /* check the folder rules for the source */
3216                 folder = tree_path_to_folder (source_model, helper->source_row);
3217                 if (TNY_IS_FOLDER(folder)) {
3218                         ModestTnyFolderRules rules =
3219                                 modest_tny_folder_get_rules (TNY_FOLDER (folder));
3220                         forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE;
3221                 } else
3222                         forbidden = TRUE;
3223                 g_object_unref (folder);
3224         }
3225
3226
3227         /* Check if the drag is possible */
3228         if (forbidden || !gtk_tree_path_compare (helper->source_row, dest_row)) {
3229                 /* Show error */
3230                 modest_platform_run_information_dialog ((GtkWindow *) win, 
3231                                                         _("mail_in_ui_folder_move_target_error"), 
3232                                                         FALSE);
3233                 /* Restore the previous selection */
3234                 folder = tree_path_to_folder (source_model, helper->source_row);
3235                 if (folder) {
3236                         if (TNY_IS_FOLDER (folder))
3237                                 modest_folder_view_select_folder (helper->folder_view, 
3238                                                                   TNY_FOLDER (folder), FALSE);
3239                         g_object_unref (folder);
3240                 }
3241                 dnd_helper_destroyer (helper);
3242                 return;
3243         }
3244
3245         /* Get data */
3246         gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
3247         gtk_tree_model_get (dest_model, &dest_iter,
3248                             INSTANCE_COLUMN,
3249                             &dest_folder, -1);
3250         gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
3251         gtk_tree_model_get (source_model, &iter,
3252                             INSTANCE_COLUMN,
3253                             &folder, -1);
3254
3255         /* Create the info for the performer */
3256         info = g_slice_new0 (DndFolderInfo);
3257         info->src_folder = g_object_ref (folder);
3258         info->dst_folder = g_object_ref (dest_folder);
3259         info->helper = helper;
3260
3261         /* Connect to the destination folder and perform the copy/move */
3262         modest_platform_connect_if_remote_and_perform (GTK_WINDOW (win), TRUE,
3263                                                        dest_folder,
3264                                                        drag_and_drop_from_folder_view_dst_folder_performer,
3265                                                        info);
3266
3267         /* Frees */
3268         g_object_unref (dest_folder);
3269         g_object_unref (folder);
3270 }
3271
3272 /*
3273  * This function receives the data set by the "drag-data-get" signal
3274  * handler. This information comes within the #GtkSelectionData. This
3275  * function will manage both the drags of folders of the treeview and
3276  * drags of headers of the header view widget.
3277  */
3278 static void
3279 on_drag_data_received (GtkWidget *widget,
3280                        GdkDragContext *context,
3281                        gint x,
3282                        gint y,
3283                        GtkSelectionData *selection_data,
3284                        guint target_type,
3285                        guint time,
3286                        gpointer data)
3287 {
3288         GtkWidget *source_widget;
3289         GtkTreeModel *dest_model, *source_model;
3290         GtkTreePath *source_row, *dest_row;
3291         GtkTreeViewDropPosition pos;
3292         gboolean delete_source = FALSE;
3293         gboolean success = FALSE;
3294
3295         /* Do not allow further process */
3296         g_signal_stop_emission_by_name (widget, "drag-data-received");
3297         source_widget = gtk_drag_get_source_widget (context);
3298
3299         /* Get the action */
3300         if (context->action == GDK_ACTION_MOVE) {
3301                 delete_source = TRUE;
3302
3303                 /* Notify that there is no folder selected. We need to
3304                    do this in order to update the headers view (and
3305                    its monitors, because when moving, the old folder
3306                    won't longer exist. We can not wait for the end of
3307                    the operation, because the operation won't start if
3308                    the folder is in use */
3309                 if (source_widget == widget) {
3310                         GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
3311                         gtk_tree_selection_unselect_all (sel);
3312                 }
3313         }
3314
3315         /* Check if the get_data failed */
3316         if (selection_data == NULL || selection_data->length < 0)
3317                 goto end;
3318
3319         /* Select the destination model */
3320         dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
3321
3322         /* Get the path to the destination row. Can not call
3323            gtk_tree_view_get_drag_dest_row() because the source row
3324            is not selected anymore */
3325         gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
3326                                            &dest_row, &pos);
3327
3328         /* Only allow drops IN other rows */
3329         if (!dest_row ||
3330             pos == GTK_TREE_VIEW_DROP_BEFORE ||
3331             pos == GTK_TREE_VIEW_DROP_AFTER)
3332                 goto end;
3333
3334         success = TRUE;
3335         /* Drags from the header view */
3336         if (source_widget != widget) {
3337                 source_model = gtk_tree_view_get_model (GTK_TREE_VIEW (source_widget));
3338
3339                 drag_and_drop_from_header_view (source_model,
3340                                                 dest_model,
3341                                                 dest_row,
3342                                                 selection_data);
3343         } else {
3344                 DndHelper *helper = NULL;
3345
3346                 /* Get the source model and row */
3347                 gtk_tree_get_row_drag_data (selection_data,
3348                                             &source_model,
3349                                             &source_row);
3350
3351                 /* Create the helper */
3352                 helper = g_slice_new0 (DndHelper);
3353                 helper->delete_source = delete_source;
3354                 helper->source_row = gtk_tree_path_copy (source_row);
3355                 helper->folder_view = MODEST_FOLDER_VIEW (widget);
3356
3357                 drag_and_drop_from_folder_view (source_model,
3358                                                 dest_model,
3359                                                 dest_row,
3360                                                 selection_data,
3361                                                 helper);
3362
3363                 gtk_tree_path_free (source_row);
3364         }
3365
3366         /* Frees */
3367         gtk_tree_path_free (dest_row);
3368
3369  end:
3370         /* Finish the drag and drop */
3371         gtk_drag_finish (context, success, FALSE, time);
3372 }
3373
3374 /*
3375  * We define a "drag-drop" signal handler because we do not want to
3376  * use the default one, because the default one always calls
3377  * gtk_drag_finish and we prefer to do it in the "drag-data-received"
3378  * signal handler, because there we have all the information available
3379  * to know if the dnd was a success or not.
3380  */
3381 static gboolean
3382 drag_drop_cb (GtkWidget      *widget,
3383               GdkDragContext *context,
3384               gint            x,
3385               gint            y,
3386               guint           time,
3387               gpointer        user_data)
3388 {
3389         gpointer target;
3390
3391         if (!context->targets)
3392                 return FALSE;
3393
3394         /* Check if we're dragging a folder row */
3395         target = gtk_drag_dest_find_target (widget, context, NULL);
3396
3397         /* Request the data from the source. */
3398         gtk_drag_get_data(widget, context, target, time);
3399
3400     return TRUE;
3401 }
3402
3403 /*
3404  * This function expands a node of a tree view if it's not expanded
3405  * yet. Not sure why it needs the threads stuff, but gtk+`example code
3406  * does that, so that's why they're here.
3407  */
3408 static gint
3409 expand_row_timeout (gpointer data)
3410 {
3411         GtkTreeView *tree_view = data;
3412         GtkTreePath *dest_path = NULL;
3413         GtkTreeViewDropPosition pos;
3414         gboolean result = FALSE;
3415
3416         gdk_threads_enter ();
3417
3418         gtk_tree_view_get_drag_dest_row (tree_view,
3419                                          &dest_path,
3420                                          &pos);
3421
3422         if (dest_path &&
3423             (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
3424              pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
3425                 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
3426                 gtk_tree_path_free (dest_path);
3427         }
3428         else {
3429                 if (dest_path)
3430                         gtk_tree_path_free (dest_path);
3431
3432                 result = TRUE;
3433         }
3434
3435         gdk_threads_leave ();
3436
3437         return result;
3438 }
3439
3440 /*
3441  * This function is called whenever the pointer is moved over a widget
3442  * while dragging some data. It installs a timeout that will expand a
3443  * node of the treeview if not expanded yet. This function also calls
3444  * gdk_drag_status in order to set the suggested action that will be
3445  * used by the "drag-data-received" signal handler to know if we
3446  * should do a move or just a copy of the data.
3447  */
3448 static gboolean
3449 on_drag_motion (GtkWidget      *widget,
3450                 GdkDragContext *context,
3451                 gint            x,
3452                 gint            y,
3453                 guint           time,
3454                 gpointer        user_data)
3455 {
3456         GtkTreeViewDropPosition pos;
3457         GtkTreePath *dest_row;
3458         GtkTreeModel *dest_model;
3459         ModestFolderViewPrivate *priv;
3460         GdkDragAction suggested_action;
3461         gboolean valid_location = FALSE;
3462         TnyFolderStore *folder = NULL;
3463
3464         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
3465
3466         if (priv->timer_expander != 0) {
3467                 g_source_remove (priv->timer_expander);
3468                 priv->timer_expander = 0;
3469         }
3470
3471         gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
3472                                            x, y,
3473                                            &dest_row,
3474                                            &pos);
3475
3476         /* Do not allow drops between folders */
3477         if (!dest_row ||
3478             pos == GTK_TREE_VIEW_DROP_BEFORE ||
3479             pos == GTK_TREE_VIEW_DROP_AFTER) {
3480                 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
3481                 gdk_drag_status(context, 0, time);
3482                 valid_location = FALSE;
3483                 goto out;
3484         } else {
3485                 valid_location = TRUE;
3486         }
3487
3488         /* Check that the destination folder is writable */
3489         dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
3490         folder = tree_path_to_folder (dest_model, dest_row);
3491         if (folder && TNY_IS_FOLDER (folder)) {
3492                 ModestTnyFolderRules rules = modest_tny_folder_get_rules(TNY_FOLDER (folder));
3493
3494                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
3495                         valid_location = FALSE;
3496                         goto out;
3497                 }
3498         }
3499
3500         /* Expand the selected row after 1/2 second */
3501         if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
3502                 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
3503         }
3504         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
3505
3506         /* Select the desired action. By default we pick MOVE */
3507         suggested_action = GDK_ACTION_MOVE;
3508
3509         if (context->actions == GDK_ACTION_COPY)
3510             gdk_drag_status(context, GDK_ACTION_COPY, time);
3511         else if (context->actions == GDK_ACTION_MOVE)
3512             gdk_drag_status(context, GDK_ACTION_MOVE, time);
3513         else if (context->actions & suggested_action)
3514             gdk_drag_status(context, suggested_action, time);
3515         else
3516             gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
3517
3518  out:
3519         if (folder)
3520                 g_object_unref (folder);
3521         if (dest_row) {
3522                 gtk_tree_path_free (dest_row);
3523         }
3524         g_signal_stop_emission_by_name (widget, "drag-motion");
3525
3526         return valid_location;
3527 }
3528
3529 /*
3530  * This function sets the treeview as a source and a target for dnd
3531  * events. It also connects all the requirede signals.
3532  */
3533 static void
3534 setup_drag_and_drop (GtkTreeView *self)
3535 {
3536         /* Set up the folder view as a dnd destination. Set only the
3537            highlight flag, otherwise gtk will have a different
3538            behaviour */
3539 #ifdef MODEST_TOOLKIT_HILDON2
3540         return;
3541 #endif
3542         gtk_drag_dest_set (GTK_WIDGET (self),
3543                            GTK_DEST_DEFAULT_HIGHLIGHT,
3544                            folder_view_drag_types,
3545                            G_N_ELEMENTS (folder_view_drag_types),
3546                            GDK_ACTION_MOVE | GDK_ACTION_COPY);
3547
3548         g_signal_connect (G_OBJECT (self),
3549                           "drag_data_received",
3550                           G_CALLBACK (on_drag_data_received),
3551                           NULL);
3552
3553
3554         /* Set up the treeview as a dnd source */
3555         gtk_drag_source_set (GTK_WIDGET (self),
3556                              GDK_BUTTON1_MASK,
3557                              folder_view_drag_types,
3558                              G_N_ELEMENTS (folder_view_drag_types),
3559                              GDK_ACTION_MOVE | GDK_ACTION_COPY);
3560
3561         g_signal_connect (G_OBJECT (self),
3562                           "drag_motion",
3563                           G_CALLBACK (on_drag_motion),
3564                           NULL);
3565
3566         g_signal_connect (G_OBJECT (self),
3567                           "drag_data_get",
3568                           G_CALLBACK (on_drag_data_get),
3569                           NULL);
3570
3571         g_signal_connect (G_OBJECT (self),
3572                           "drag_drop",
3573                           G_CALLBACK (drag_drop_cb),
3574                           NULL);
3575 }
3576
3577 /*
3578  * This function manages the navigation through the folders using the
3579  * keyboard or the hardware keys in the device
3580  */
3581 static gboolean
3582 on_key_pressed (GtkWidget *self,
3583                 GdkEventKey *event,
3584                 gpointer user_data)
3585 {
3586         GtkTreeSelection *selection;
3587         GtkTreeIter iter;
3588         GtkTreeModel *model;
3589         gboolean retval = FALSE;
3590
3591         /* Up and Down are automatically managed by the treeview */
3592         if (event->keyval == GDK_Return) {
3593                 /* Expand/Collapse the selected row */
3594                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
3595                 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
3596                         GtkTreePath *path;
3597
3598                         path = gtk_tree_model_get_path (model, &iter);
3599
3600                         if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
3601                                 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
3602                         else
3603                                 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
3604                         gtk_tree_path_free (path);
3605                 }
3606                 /* No further processing */
3607                 retval = TRUE;
3608         }
3609
3610         return retval;
3611 }
3612
3613 /*
3614  * We listen to the changes in the local folder account name key,
3615  * because we want to show the right name in the view. The local
3616  * folder account name corresponds to the device name in the Maemo
3617  * version. We do this because we do not want to query gconf on each
3618  * tree view refresh. It's better to cache it and change whenever
3619  * necessary.
3620  */
3621 static void
3622 on_configuration_key_changed (ModestConf* conf,
3623                               const gchar *key,
3624                               ModestConfEvent event,
3625                               ModestConfNotificationId id,
3626                               ModestFolderView *self)
3627 {
3628         ModestFolderViewPrivate *priv;
3629
3630
3631         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
3632         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
3633
3634         if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
3635                 g_free (priv->local_account_name);
3636
3637                 if (event == MODEST_CONF_EVENT_KEY_UNSET)
3638                         priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
3639                 else
3640                         priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
3641                                                                            MODEST_CONF_DEVICE_NAME, NULL);
3642
3643                 /* Force a redraw */
3644 #if GTK_CHECK_VERSION(2, 8, 0)
3645                 GtkTreeViewColumn * tree_column;
3646
3647                 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
3648                                                         NAME_COLUMN);
3649                 gtk_tree_view_column_queue_resize (tree_column);
3650 #else
3651                 gtk_widget_queue_draw (GTK_WIDGET (self));
3652 #endif
3653         }
3654 }
3655
3656 void
3657 modest_folder_view_set_style (ModestFolderView *self,
3658                               ModestFolderViewStyle style)
3659 {
3660         ModestFolderViewPrivate *priv;
3661
3662         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
3663         g_return_if_fail (style == MODEST_FOLDER_VIEW_STYLE_SHOW_ALL ||
3664                           style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE);
3665
3666         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
3667
3668
3669         priv->style = style;
3670 }
3671
3672 void
3673 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
3674                                                              const gchar *account_id)
3675 {
3676         ModestFolderViewPrivate *priv;
3677         GtkTreeModel *model;
3678
3679         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
3680
3681         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
3682
3683         /* This will be used by the filter_row callback,
3684          * to decided which rows to show: */
3685         if (priv->visible_account_id) {
3686                 g_free (priv->visible_account_id);
3687                 priv->visible_account_id = NULL;
3688         }
3689         if (account_id)
3690                 priv->visible_account_id = g_strdup (account_id);
3691
3692         /* Refilter */
3693         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
3694         if (GTK_IS_TREE_MODEL_FILTER (model))
3695                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
3696         else
3697                 modest_folder_view_update_model(self,
3698                                                 (TnyAccountStore *) modest_runtime_get_account_store());
3699
3700         /* Save settings to gconf */
3701         modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
3702                                    MODEST_CONF_FOLDER_VIEW_KEY);
3703
3704         /* Notify observers */
3705         g_signal_emit (G_OBJECT(self),
3706                        signals[VISIBLE_ACCOUNT_CHANGED_SIGNAL], 0,
3707                        account_id);
3708 }
3709
3710 const gchar *
3711 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
3712 {
3713         ModestFolderViewPrivate *priv;
3714
3715         g_return_val_if_fail (self && MODEST_IS_FOLDER_VIEW(self), NULL);
3716
3717         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
3718
3719         return (const gchar *) priv->visible_account_id;
3720 }
3721
3722 static gboolean
3723 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
3724 {
3725         do {
3726                 GtkTreeIter child;
3727                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
3728
3729                 gtk_tree_model_get (model, iter,
3730                                     TYPE_COLUMN,
3731                                     &type, -1);
3732
3733                 gboolean result = FALSE;
3734                 if (type == TNY_FOLDER_TYPE_INBOX) {
3735                         result = TRUE;
3736                 }
3737                 if (result) {
3738                         *inbox_iter = *iter;
3739                         return TRUE;
3740                 }
3741
3742                 if (gtk_tree_model_iter_children (model, &child, iter)) {
3743                         if (find_inbox_iter (model, &child, inbox_iter))
3744                                 return TRUE;
3745                 }
3746
3747         } while (gtk_tree_model_iter_next (model, iter));
3748
3749         return FALSE;
3750 }
3751
3752
3753
3754
3755 void
3756 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
3757 {
3758 #ifndef MODEST_TOOLKIT_HILDON2
3759         GtkTreeModel *model;
3760         GtkTreeIter iter, inbox_iter;
3761         GtkTreeSelection *sel;
3762         GtkTreePath *path = NULL;
3763
3764         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
3765
3766         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
3767         if (!model)
3768                 return;
3769
3770         expand_root_items (self);
3771         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
3772
3773         if (!gtk_tree_model_get_iter_first (model, &iter)) {
3774                 g_warning ("%s: model is empty", __FUNCTION__);
3775                 return;
3776         }
3777
3778         if (find_inbox_iter (model, &iter, &inbox_iter))
3779                 path = gtk_tree_model_get_path (model, &inbox_iter);
3780         else
3781                 path = gtk_tree_path_new_first ();
3782
3783         /* Select the row and free */
3784         gtk_tree_view_set_cursor (GTK_TREE_VIEW (self), path, NULL, FALSE);
3785         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self), path, NULL, FALSE, 0.0, 0.0);
3786         gtk_tree_path_free (path);
3787
3788         /* set focus */
3789         gtk_widget_grab_focus (GTK_WIDGET(self));
3790 #endif
3791 }
3792
3793
3794 /* recursive */
3795 static gboolean
3796 find_folder_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *folder_iter,
3797                   TnyFolder* folder)
3798 {
3799         do {
3800                 GtkTreeIter child;
3801                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
3802                 TnyFolder* a_folder;
3803                 gchar *name = NULL;
3804
3805                 gtk_tree_model_get (model, iter,
3806                                     INSTANCE_COLUMN, &a_folder,
3807                                     NAME_COLUMN, &name,
3808                                     TYPE_COLUMN, &type,
3809                                     -1);
3810                 g_free (name);
3811
3812                 if (folder == a_folder) {
3813                         g_object_unref (a_folder);
3814                         *folder_iter = *iter;
3815                         return TRUE;
3816                 }
3817                 g_object_unref (a_folder);
3818
3819                 if (gtk_tree_model_iter_children (model, &child, iter)) {
3820                         if (find_folder_iter (model, &child, folder_iter, folder))
3821                                 return TRUE;
3822                 }
3823
3824         } while (gtk_tree_model_iter_next (model, iter));
3825
3826         return FALSE;
3827 }
3828
3829 #ifndef MODEST_TOOLKIT_HILDON2
3830 static void
3831 on_row_inserted_maybe_select_folder (GtkTreeModel *tree_model,
3832                                      GtkTreePath *path,
3833                                      GtkTreeIter *iter,
3834                                      ModestFolderView *self)
3835 {
3836         ModestFolderViewPrivate *priv = NULL;
3837         GtkTreeSelection *sel;
3838         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
3839         GObject *instance = NULL;
3840
3841         if (!MODEST_IS_FOLDER_VIEW(self))
3842                 return;
3843
3844         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
3845
3846         priv->reexpand = TRUE;
3847
3848         gtk_tree_model_get (tree_model, iter,
3849                             TYPE_COLUMN, &type,
3850                             INSTANCE_COLUMN, &instance,
3851                             -1);
3852
3853         if (!instance)
3854                 return;
3855
3856         if (type == TNY_FOLDER_TYPE_INBOX && priv->folder_to_select == NULL) {
3857                 priv->folder_to_select = g_object_ref (instance);
3858         }
3859         g_object_unref (instance);
3860
3861         if (priv->folder_to_select) {
3862
3863                 if (!modest_folder_view_select_folder (self, priv->folder_to_select,
3864                                                        FALSE)) {
3865                         GtkTreePath *path;
3866                         path = gtk_tree_model_get_path (tree_model, iter);
3867                         gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
3868
3869                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
3870
3871                         gtk_tree_selection_select_iter (sel, iter);
3872                         gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
3873
3874                         gtk_tree_path_free (path);
3875                 }
3876
3877                 /* Disable next */
3878                 modest_folder_view_disable_next_folder_selection (self);
3879
3880                 /* Refilter the model */
3881                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (tree_model));
3882         }
3883 }
3884 #endif
3885
3886 void
3887 modest_folder_view_disable_next_folder_selection (ModestFolderView *self)
3888 {
3889         ModestFolderViewPrivate *priv;
3890
3891         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
3892
3893         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
3894
3895         if (priv->folder_to_select)
3896                 g_object_unref(priv->folder_to_select);
3897
3898         priv->folder_to_select = NULL;
3899 }
3900
3901 gboolean
3902 modest_folder_view_select_folder (ModestFolderView *self, TnyFolder *folder,
3903                                   gboolean after_change)
3904 {
3905         GtkTreeModel *model;
3906         GtkTreeIter iter, folder_iter;
3907         GtkTreeSelection *sel;
3908         ModestFolderViewPrivate *priv = NULL;
3909
3910         g_return_val_if_fail (self && MODEST_IS_FOLDER_VIEW (self), FALSE);
3911         g_return_val_if_fail (folder && TNY_IS_FOLDER (folder), FALSE);
3912
3913         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
3914
3915         if (after_change) {
3916                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
3917                 gtk_tree_selection_unselect_all (sel);
3918
3919                 if (priv->folder_to_select)
3920                         g_object_unref(priv->folder_to_select);
3921                 priv->folder_to_select = TNY_FOLDER(g_object_ref(folder));
3922                 return TRUE;
3923         }
3924
3925         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
3926         if (!model)
3927                 return FALSE;
3928
3929
3930         /* Refilter the model, before selecting the folder */
3931         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
3932
3933         if (!gtk_tree_model_get_iter_first (model, &iter)) {
3934                 g_warning ("%s: model is empty", __FUNCTION__);
3935                 return FALSE;
3936         }
3937
3938         if (find_folder_iter (model, &iter, &folder_iter, folder)) {
3939                 GtkTreePath *path;
3940
3941                 path = gtk_tree_model_get_path (model, &folder_iter);
3942                 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
3943
3944                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
3945                 gtk_tree_selection_select_iter (sel, &folder_iter);
3946                 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
3947
3948                 gtk_tree_path_free (path);
3949                 return TRUE;
3950         }
3951         return FALSE;
3952 }
3953
3954
3955 void
3956 modest_folder_view_copy_selection (ModestFolderView *self)
3957 {
3958         g_return_if_fail (self && MODEST_IS_FOLDER_VIEW(self));
3959
3960         /* Copy selection */
3961         _clipboard_set_selected_data (self, FALSE);
3962 }
3963
3964 void
3965 modest_folder_view_cut_selection (ModestFolderView *folder_view)
3966 {
3967         ModestFolderViewPrivate *priv = NULL;
3968         GtkTreeModel *model = NULL;
3969         const gchar **hidding = NULL;
3970         guint i, n_selected;
3971
3972         g_return_if_fail (folder_view && MODEST_IS_FOLDER_VIEW (folder_view));
3973         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
3974
3975         /* Copy selection */
3976         if (!_clipboard_set_selected_data (folder_view, TRUE))
3977                 return;
3978
3979         /* Get hidding ids */
3980         hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected);
3981
3982         /* Clear hidding array created by previous cut operation */
3983         _clear_hidding_filter (MODEST_FOLDER_VIEW (folder_view));
3984
3985         /* Copy hidding array */
3986         priv->n_selected = n_selected;
3987         priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected);
3988         for (i=0; i < n_selected; i++)
3989                 priv->hidding_ids[i] = g_strdup(hidding[i]);
3990
3991         /* Hide cut folders */
3992         model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
3993         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
3994 }
3995
3996 void
3997 modest_folder_view_copy_model (ModestFolderView *folder_view_src,
3998                                ModestFolderView *folder_view_dst)
3999 {
4000         GtkTreeModel *filter_model = NULL;
4001         GtkTreeModel *model = NULL;
4002         GtkTreeModel *new_filter_model = NULL;
4003         GtkTreeModel *old_tny_model = NULL;
4004         GtkTreeModel *new_tny_model = NULL;
4005         ModestFolderViewPrivate *dst_priv;
4006
4007         g_return_if_fail (folder_view_src && MODEST_IS_FOLDER_VIEW (folder_view_src));
4008         g_return_if_fail (folder_view_dst && MODEST_IS_FOLDER_VIEW (folder_view_dst));
4009
4010         dst_priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view_dst);
4011         if (!get_inner_models (folder_view_src, NULL, NULL, &new_tny_model))
4012                 new_tny_model = NULL;
4013
4014         /* Get src model*/
4015         if (get_inner_models (folder_view_dst, NULL, NULL, &old_tny_model)) {
4016                 modest_signal_mgr_disconnect (dst_priv->signal_handlers,
4017                                               G_OBJECT (old_tny_model),
4018                                               "activity-changed");
4019         }
4020         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view_src));
4021         model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(filter_model));
4022
4023         /* Build new filter model */
4024         new_filter_model = gtk_tree_model_filter_new (model, NULL);
4025         gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_filter_model),
4026                                                 filter_row,
4027                                                 folder_view_dst,
4028                                                 NULL);
4029
4030
4031
4032         /* Set copied model */
4033         gtk_tree_view_set_model (GTK_TREE_VIEW (folder_view_dst), new_filter_model);
4034 #ifndef MODEST_TOOLKIT_HILDON2
4035         dst_priv->signal_handlers = modest_signal_mgr_connect (dst_priv->signal_handlers,
4036                                                                G_OBJECT(new_filter_model), "row-inserted",
4037                                                                (GCallback) on_row_inserted_maybe_select_folder,
4038                                                                folder_view_dst);
4039 #endif
4040 #ifdef MODEST_TOOLKIT_HILDON2
4041         if (new_tny_model) {
4042                 dst_priv->signal_handlers = modest_signal_mgr_connect (dst_priv->signal_handlers,
4043                                                                        G_OBJECT (new_tny_model),
4044                                                                        "activity-changed",
4045                                                                        G_CALLBACK (on_activity_changed),
4046                                                                        folder_view_dst);
4047         }
4048 #endif
4049
4050         /* Free */
4051         g_object_unref (new_filter_model);
4052 }
4053
4054 void
4055 modest_folder_view_show_non_move_folders (ModestFolderView *folder_view,
4056                                           gboolean show)
4057 {
4058         GtkTreeModel *model = NULL;
4059         ModestFolderViewPrivate* priv;
4060
4061         g_return_if_fail (folder_view && MODEST_IS_FOLDER_VIEW (folder_view));
4062
4063         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
4064         priv->show_non_move = show;
4065 /*      modest_folder_view_update_model(folder_view, */
4066 /*                                      TNY_ACCOUNT_STORE(modest_runtime_get_account_store())); */
4067
4068         /* Hide special folders */
4069         model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
4070         if (GTK_IS_TREE_MODEL_FILTER (model)) {
4071                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
4072         }
4073 }
4074
4075 void
4076 modest_folder_view_show_message_count (ModestFolderView *folder_view,
4077                                           gboolean show)
4078 {
4079         ModestFolderViewPrivate* priv;
4080
4081         g_return_if_fail (folder_view && MODEST_IS_FOLDER_VIEW (folder_view));
4082
4083         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
4084         priv->show_message_count = show;
4085
4086         g_object_set (G_OBJECT (priv->messages_renderer),
4087                       "visible", (priv->cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT && priv->show_message_count),
4088                       NULL);
4089 }
4090
4091 /* Returns FALSE if it did not selected anything */
4092 static gboolean
4093 _clipboard_set_selected_data (ModestFolderView *folder_view,
4094                               gboolean delete)
4095 {
4096         ModestFolderViewPrivate *priv = NULL;
4097         TnyFolderStore *folder = NULL;
4098         gboolean retval = FALSE;
4099
4100         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (folder_view), FALSE);
4101         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
4102
4103         /* Set selected data on clipboard   */
4104         g_return_val_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard), FALSE);
4105         folder = modest_folder_view_get_selected (folder_view);
4106
4107         /* Do not allow to select an account */
4108         if (TNY_IS_FOLDER (folder)) {
4109                 modest_email_clipboard_set_data (priv->clipboard, TNY_FOLDER(folder), NULL, delete);
4110                 retval = TRUE;
4111         }
4112
4113         /* Free */
4114         g_object_unref (folder);
4115
4116         return retval;
4117 }
4118
4119 static void
4120 _clear_hidding_filter (ModestFolderView *folder_view)
4121 {
4122         ModestFolderViewPrivate *priv;
4123         guint i;
4124
4125         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
4126         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
4127
4128         if (priv->hidding_ids != NULL) {
4129                 for (i=0; i < priv->n_selected; i++)
4130                         g_free (priv->hidding_ids[i]);
4131                 g_free(priv->hidding_ids);
4132         }
4133 }
4134
4135
4136 static void
4137 on_display_name_changed (ModestAccountMgr *mgr,
4138                          const gchar *account,
4139                          gpointer user_data)
4140 {
4141         ModestFolderView *self;
4142
4143         self = MODEST_FOLDER_VIEW (user_data);
4144
4145         /* Force a redraw */
4146 #if GTK_CHECK_VERSION(2, 8, 0)
4147         GtkTreeViewColumn * tree_column;
4148
4149         tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
4150                                                 NAME_COLUMN);
4151         gtk_tree_view_column_queue_resize (tree_column);
4152 #else
4153         gtk_widget_queue_draw (GTK_WIDGET (self));
4154 #endif
4155 }
4156
4157 void 
4158 modest_folder_view_set_cell_style (ModestFolderView *self,
4159                                    ModestFolderViewCellStyle cell_style)
4160 {
4161         ModestFolderViewPrivate *priv = NULL;
4162
4163         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4164         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4165
4166         priv->cell_style = cell_style;
4167
4168         g_object_set (G_OBJECT (priv->messages_renderer),
4169                       "visible", (cell_style == MODEST_FOLDER_VIEW_CELL_STYLE_COMPACT && priv->show_message_count),
4170                       NULL);
4171         
4172         gtk_widget_queue_draw (GTK_WIDGET (self));
4173 }
4174
4175 static void
4176 update_style (ModestFolderView *self)
4177 {
4178         ModestFolderViewPrivate *priv;
4179         GdkColor style_color, style_active_color;
4180         PangoAttrList *attr_list;
4181         GtkStyle *style;
4182         PangoAttribute *attr;
4183
4184         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4185         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4186
4187         /* Set color */
4188
4189         attr_list = pango_attr_list_new ();
4190         if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
4191                 gdk_color_parse ("grey", &style_color);
4192         }
4193         attr = pango_attr_foreground_new (style_color.red, style_color.green, style_color.blue);
4194         pango_attr_list_insert (attr_list, attr);
4195         
4196         /* set font */
4197         style = gtk_rc_get_style_by_paths (gtk_widget_get_settings
4198                                            (GTK_WIDGET(self)),
4199                                            "SmallSystemFont", NULL,
4200                                            G_TYPE_NONE);
4201         if (style) {
4202                 attr = pango_attr_font_desc_new (pango_font_description_copy
4203                                                  (style->font_desc));
4204                 pango_attr_list_insert (attr_list, attr);
4205
4206                 g_object_set (G_OBJECT (priv->messages_renderer),
4207                               "foreground-gdk", &style_color,
4208                               "foreground-set", TRUE,
4209                               "attributes", attr_list,
4210                               NULL);
4211                 pango_attr_list_unref (attr_list);
4212         }
4213
4214         if (gtk_style_lookup_color (GTK_WIDGET (self)->style, "ActiveTextColor", &style_active_color)) {
4215                 priv->active_color = style_active_color;
4216         } else {
4217                 gdk_color_parse ("000", &(priv->active_color));
4218         }
4219 }
4220
4221 static void 
4222 on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata)
4223 {
4224         if (strcmp ("style", spec->name) == 0) {
4225                 update_style (MODEST_FOLDER_VIEW (obj));
4226                 gtk_widget_queue_draw (GTK_WIDGET (obj));
4227         } 
4228 }
4229
4230 void 
4231 modest_folder_view_set_filter (ModestFolderView *self,
4232                                ModestFolderViewFilter filter)
4233 {
4234         ModestFolderViewPrivate *priv;
4235         GtkTreeModel *filter_model;
4236
4237         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4238         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4239
4240         priv->filter |= filter;
4241
4242         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
4243         if (GTK_IS_TREE_MODEL_FILTER(filter_model)) {
4244                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));  
4245         }
4246 }
4247
4248 void 
4249 modest_folder_view_unset_filter (ModestFolderView *self,
4250                                  ModestFolderViewFilter filter)
4251 {
4252         ModestFolderViewPrivate *priv;
4253         GtkTreeModel *filter_model;
4254
4255         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4256         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4257
4258         priv->filter &= ~filter;
4259
4260         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
4261         if (GTK_IS_TREE_MODEL_FILTER(filter_model)) {
4262                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));  
4263         }
4264 }
4265
4266 gboolean
4267 modest_folder_view_any_folder_fulfils_rules (ModestFolderView *self,
4268                                              ModestTnyFolderRules rules)
4269 {
4270         GtkTreeModel *filter_model;
4271         GtkTreeIter iter;
4272         gboolean fulfil = FALSE;
4273
4274         if (!get_inner_models (self, &filter_model, NULL, NULL))
4275                 return FALSE;
4276
4277         if (!gtk_tree_model_get_iter_first (filter_model, &iter))
4278                 return FALSE;
4279
4280         do {
4281                 TnyFolderStore *folder;
4282
4283                 gtk_tree_model_get (filter_model, &iter, INSTANCE_COLUMN, &folder, -1);
4284                 if (folder) {
4285                         if (TNY_IS_FOLDER (folder)) {
4286                                 ModestTnyFolderRules folder_rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
4287                                 /* Folder rules are negative: non_writable, non_deletable... */
4288                                 if (!(folder_rules & rules))
4289                                         fulfil = TRUE;
4290                         }
4291                         g_object_unref (folder);
4292                 }
4293
4294         } while (gtk_tree_model_iter_next (filter_model, &iter) && !fulfil);
4295
4296         return fulfil;
4297 }
4298
4299 void 
4300 modest_folder_view_set_list_to_move (ModestFolderView *self,
4301                                      TnyList *list)
4302 {
4303         ModestFolderViewPrivate *priv;
4304
4305         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4306         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4307
4308         if (priv->list_to_move)
4309                 g_object_unref (priv->list_to_move);
4310
4311         if (list)
4312                 g_object_ref (list);
4313
4314         priv->list_to_move = list;
4315 }
4316
4317 void
4318 modest_folder_view_set_mailbox (ModestFolderView *self, const gchar *mailbox)
4319 {
4320         ModestFolderViewPrivate *priv;
4321
4322         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
4323         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4324
4325         if (priv->mailbox)
4326                 g_free (priv->mailbox);
4327
4328         priv->mailbox = g_strdup (mailbox);
4329
4330         /* Notify observers */
4331         g_signal_emit (G_OBJECT(self),
4332                        signals[VISIBLE_ACCOUNT_CHANGED_SIGNAL], 0,
4333                        priv->visible_account_id);
4334 }
4335
4336 const gchar *
4337 modest_folder_view_get_mailbox (ModestFolderView *self)
4338 {
4339         ModestFolderViewPrivate *priv;
4340
4341         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), NULL);
4342         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4343
4344         return (const gchar *) priv->mailbox;
4345 }
4346
4347 gboolean 
4348 modest_folder_view_get_activity (ModestFolderView *self)
4349 {
4350         ModestFolderViewPrivate *priv;
4351         GtkTreeModel *inner_model;
4352
4353         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
4354         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
4355         g_return_val_if_fail (get_inner_models (self, NULL, NULL, &inner_model), FALSE);
4356
4357         if (TNY_IS_GTK_FOLDER_LIST_STORE (inner_model)) {
4358                 return tny_gtk_folder_list_store_get_activity (TNY_GTK_FOLDER_LIST_STORE (inner_model));
4359         } else {
4360                 return FALSE;
4361         }
4362 }
4363
4364 #ifdef MODEST_TOOLKIT_HILDON2
4365 static void
4366 on_activity_changed (TnyGtkFolderListStore *store,
4367                      gboolean activity,
4368                      ModestFolderView *folder_view)
4369 {
4370         ModestFolderViewPrivate *priv;
4371
4372         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
4373         g_return_if_fail (TNY_IS_GTK_FOLDER_LIST_STORE (store));
4374         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
4375
4376         g_signal_emit (G_OBJECT (folder_view), signals[ACTIVITY_CHANGED_SIGNAL], 0,
4377                        activity);
4378 }
4379 #endif
4380
4381 TnyList *
4382 modest_folder_view_get_model_tny_list (ModestFolderView *self)
4383 {
4384         GtkTreeModel *model;
4385         TnyList *ret_value;
4386
4387         ret_value = NULL;
4388         model = NULL;
4389
4390         if (get_inner_models (MODEST_FOLDER_VIEW (self), NULL, NULL, (GtkTreeModel **) &model)) {
4391                 ret_value = TNY_LIST (model);
4392                 g_object_ref (ret_value);
4393         }
4394
4395         return ret_value;
4396
4397 }