* Added "queue-empty" signal to the mail operation queue
[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-store-tree-model.h>
36 #include <tny-gtk-header-list-model.h>
37 #include <tny-folder.h>
38 #include <tny-folder-store-observer.h>
39 #include <tny-account-store.h>
40 #include <tny-account.h>
41 #include <tny-folder.h>
42 #include <tny-camel-folder.h>
43 #include <tny-simple-list.h>
44 #include <tny-camel-account.h>
45 #include <modest-tny-account.h>
46 #include <modest-tny-folder.h>
47 #include <modest-tny-local-folders-account.h>
48 #include <modest-tny-outbox-account.h>
49 #include <modest-marshal.h>
50 #include <modest-icon-names.h>
51 #include <modest-tny-account-store.h>
52 #include <modest-text-utils.h>
53 #include <modest-runtime.h>
54 #include "modest-folder-view.h"
55 #include <modest-platform.h>
56 #include <modest-widget-memory.h>
57 #include <modest-ui-actions.h>
58 #include "modest-dnd.h"
59 #include "widgets/modest-window.h"
60
61 /* Folder view drag types */
62 const GtkTargetEntry folder_view_drag_types[] =
63 {
64         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
65         { GTK_TREE_PATH_AS_STRING_LIST, GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
66 };
67
68 /* 'private'/'protected' functions */
69 static void modest_folder_view_class_init  (ModestFolderViewClass *klass);
70 static void modest_folder_view_init        (ModestFolderView *obj);
71 static void modest_folder_view_finalize    (GObject *obj);
72
73 static void         tny_account_store_view_init (gpointer g, 
74                                                  gpointer iface_data);
75
76 static void         modest_folder_view_set_account_store (TnyAccountStoreView *self, 
77                                                           TnyAccountStore     *account_store);
78
79 static void         on_selection_changed   (GtkTreeSelection *sel, gpointer data);
80
81 static void         on_account_removed     (TnyAccountStore *self, 
82                                             TnyAccount *account,
83                                             gpointer user_data);
84
85 static void         on_account_inserted    (TnyAccountStore *self, 
86                                             TnyAccount *account,
87                                             gpointer user_data);
88
89 static void         on_account_changed    (TnyAccountStore *self, 
90                                             TnyAccount *account,
91                                             gpointer user_data);
92
93 static gint         cmp_rows               (GtkTreeModel *tree_model, 
94                                             GtkTreeIter *iter1, 
95                                             GtkTreeIter *iter2,
96                                             gpointer user_data);
97
98 static gboolean     filter_row             (GtkTreeModel *model,
99                                             GtkTreeIter *iter,
100                                             gpointer data);
101
102 static gboolean     on_key_pressed         (GtkWidget *self,
103                                             GdkEventKey *event,
104                                             gpointer user_data);
105
106 static void         on_configuration_key_changed  (ModestConf* conf, 
107                                                    const gchar *key, 
108                                                    ModestConfEvent event,
109                                                    ModestConfNotificationId notification_id, 
110                                                    ModestFolderView *self);
111
112 /* DnD functions */
113 static void         on_drag_data_get       (GtkWidget *widget, 
114                                             GdkDragContext *context, 
115                                             GtkSelectionData *selection_data, 
116                                             guint info, 
117                                             guint time, 
118                                             gpointer data);
119
120 static void         on_drag_data_received  (GtkWidget *widget, 
121                                             GdkDragContext *context, 
122                                             gint x, 
123                                             gint y, 
124                                             GtkSelectionData *selection_data, 
125                                             guint info, 
126                                             guint time, 
127                                             gpointer data);
128
129 static gboolean     on_drag_motion         (GtkWidget      *widget,
130                                             GdkDragContext *context,
131                                             gint            x,
132                                             gint            y,
133                                             guint           time,
134                                             gpointer        user_data);
135
136 static void         expand_root_items (ModestFolderView *self);
137
138 static gint         expand_row_timeout     (gpointer data);
139
140 static void         setup_drag_and_drop    (GtkTreeView *self);
141
142 static gboolean     _clipboard_set_selected_data (ModestFolderView *folder_view, 
143                                                   gboolean delete);
144
145 static void         _clear_hidding_filter (ModestFolderView *folder_view);
146
147 static void         on_row_inserted_maybe_select_folder (GtkTreeModel     *tree_model, 
148                                                          GtkTreePath      *path, 
149                                                          GtkTreeIter      *iter,
150                                                          ModestFolderView *self);
151
152 static void         on_display_name_changed (ModestAccountMgr *self, 
153                                              const gchar *account,
154                                              gpointer user_data);
155
156 enum {
157         FOLDER_SELECTION_CHANGED_SIGNAL,
158         FOLDER_DISPLAY_NAME_CHANGED_SIGNAL,
159         LAST_SIGNAL
160 };
161
162 typedef struct _ModestFolderViewPrivate ModestFolderViewPrivate;
163 struct _ModestFolderViewPrivate {
164         TnyAccountStore      *account_store;
165         TnyFolderStore       *cur_folder_store;
166
167         TnyFolder            *folder_to_select; /* folder to select after the next update */
168
169         gulong                changed_signal;
170         gulong                account_inserted_signal;
171         gulong                account_removed_signal;
172         gulong                account_changed_signal;
173         gulong                conf_key_signal;
174         gulong                display_name_changed_signal;
175         
176         /* not unref this object, its a singlenton */
177         ModestEmailClipboard *clipboard;
178
179         /* Filter tree model */
180         gchar **hidding_ids;
181         guint n_selected;
182
183         TnyFolderStoreQuery  *query;
184         guint                 timer_expander;
185
186         gchar                *local_account_name;
187         gchar                *visible_account_id;
188         ModestFolderViewStyle style;
189
190         gboolean  reselect; /* we use this to force a reselection of the INBOX */
191         gboolean  show_non_move;
192         gboolean  reexpand; /* next time we expose, we'll expand all root folders */
193 };
194 #define MODEST_FOLDER_VIEW_GET_PRIVATE(o)                       \
195         (G_TYPE_INSTANCE_GET_PRIVATE((o),                       \
196                                      MODEST_TYPE_FOLDER_VIEW,   \
197                                      ModestFolderViewPrivate))
198 /* globals */
199 static GObjectClass *parent_class = NULL;
200
201 static guint signals[LAST_SIGNAL] = {0}; 
202
203 GType
204 modest_folder_view_get_type (void)
205 {
206         static GType my_type = 0;
207         if (!my_type) {
208                 static const GTypeInfo my_info = {
209                         sizeof(ModestFolderViewClass),
210                         NULL,           /* base init */
211                         NULL,           /* base finalize */
212                         (GClassInitFunc) modest_folder_view_class_init,
213                         NULL,           /* class finalize */
214                         NULL,           /* class data */
215                         sizeof(ModestFolderView),
216                         1,              /* n_preallocs */
217                         (GInstanceInitFunc) modest_folder_view_init,
218                         NULL
219                 };
220
221                 static const GInterfaceInfo tny_account_store_view_info = {
222                         (GInterfaceInitFunc) tny_account_store_view_init, /* interface_init */
223                         NULL,         /* interface_finalize */
224                         NULL          /* interface_data */
225                 };
226
227                                 
228                 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
229                                                   "ModestFolderView",
230                                                   &my_info, 0);
231
232                 g_type_add_interface_static (my_type, 
233                                              TNY_TYPE_ACCOUNT_STORE_VIEW, 
234                                              &tny_account_store_view_info);
235         }
236         return my_type;
237 }
238
239 static void
240 modest_folder_view_class_init (ModestFolderViewClass *klass)
241 {
242         GObjectClass *gobject_class;
243         gobject_class = (GObjectClass*) klass;
244
245         parent_class            = g_type_class_peek_parent (klass);
246         gobject_class->finalize = modest_folder_view_finalize;
247
248         g_type_class_add_private (gobject_class,
249                                   sizeof(ModestFolderViewPrivate));
250         
251         signals[FOLDER_SELECTION_CHANGED_SIGNAL] = 
252                 g_signal_new ("folder_selection_changed",
253                               G_TYPE_FROM_CLASS (gobject_class),
254                               G_SIGNAL_RUN_FIRST,
255                               G_STRUCT_OFFSET (ModestFolderViewClass,
256                                                folder_selection_changed),
257                               NULL, NULL,
258                               modest_marshal_VOID__POINTER_BOOLEAN,
259                               G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
260
261         /*
262          * This signal is emitted whenever the currently selected
263          * folder display name is computed. Note that the name could
264          * be different to the folder name, because we could append
265          * the unread messages count to the folder name to build the
266          * folder display name
267          */
268         signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL] = 
269                 g_signal_new ("folder-display-name-changed",
270                               G_TYPE_FROM_CLASS (gobject_class),
271                               G_SIGNAL_RUN_FIRST,
272                               G_STRUCT_OFFSET (ModestFolderViewClass,
273                                                folder_display_name_changed),
274                               NULL, NULL,
275                               g_cclosure_marshal_VOID__STRING,
276                               G_TYPE_NONE, 1, G_TYPE_STRING);
277 }
278
279 /* Simplify checks for NULLs: */
280 static gboolean
281 strings_are_equal (const gchar *a, const gchar *b)
282 {
283         if (!a && !b)
284                 return TRUE;
285         if (a && b)
286         {
287                 return (strcmp (a, b) == 0);
288         }
289         else
290                 return FALSE;
291 }
292
293 static gboolean
294 on_model_foreach_set_name(GtkTreeModel *model, GtkTreePath *path,  GtkTreeIter *iter, gpointer data)
295 {
296         GObject *instance = NULL;
297         
298         gtk_tree_model_get (model, iter,
299                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
300                             -1);
301                             
302         if (!instance)
303                 return FALSE; /* keep walking */
304                         
305         if (!TNY_IS_ACCOUNT (instance)) {
306                 g_object_unref (instance);
307                 return FALSE; /* keep walking */        
308         }    
309         
310         /* Check if this is the looked-for account: */
311         TnyAccount *this_account = TNY_ACCOUNT (instance);
312         TnyAccount *account = TNY_ACCOUNT (data);
313         
314         const gchar *this_account_id = tny_account_get_id(this_account);
315         const gchar *account_id = tny_account_get_id(account);
316         g_object_unref (instance);
317         instance = NULL;
318
319         /* printf ("DEBUG: %s: this_account_id=%s, account_id=%s\n", __FUNCTION__, this_account_id, account_id); */
320         if (strings_are_equal(this_account_id, account_id)) {
321                 /* Tell the model that the data has changed, so that
322                  * it calls the cell_data_func callbacks again: */
323                 /* TODO: This does not seem to actually cause the new string to be shown: */
324                 gtk_tree_model_row_changed (model, path, iter);
325                 
326                 return TRUE; /* stop walking */
327         }
328         
329         return FALSE; /* keep walking */
330 }
331
332 typedef struct 
333 {
334         ModestFolderView *self;
335         gchar *previous_name;
336 } GetMmcAccountNameData;
337
338 static void
339 on_get_mmc_account_name (TnyStoreAccount* account, gpointer user_data)
340 {
341         /* printf ("DEBU1G: %s: account name=%s\n", __FUNCTION__, tny_account_get_name (TNY_ACCOUNT(account))); */
342
343         GetMmcAccountNameData *data = (GetMmcAccountNameData*)user_data;
344         
345         if (!strings_are_equal (
346                 tny_account_get_name(TNY_ACCOUNT(account)), 
347                 data->previous_name)) {
348         
349                 /* Tell the model that the data has changed, so that 
350                  * it calls the cell_data_func callbacks again: */
351                 ModestFolderView *self = data->self;
352                 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
353                 if (model)
354                         gtk_tree_model_foreach(model, on_model_foreach_set_name, account);
355         }
356
357         g_free (data->previous_name);
358         g_slice_free (GetMmcAccountNameData, data);
359 }
360
361 static void
362 text_cell_data  (GtkTreeViewColumn *column,  
363                  GtkCellRenderer *renderer,
364                  GtkTreeModel *tree_model,  
365                  GtkTreeIter *iter,  
366                  gpointer data)
367 {
368         ModestFolderViewPrivate *priv;
369         GObject *rendobj = (GObject *) renderer;
370         gchar *fname = NULL;
371         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
372         GObject *instance = NULL;
373
374         gtk_tree_model_get (tree_model, iter,
375                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
376                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
377                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
378                             -1);
379
380         if (!fname)
381                 return;
382
383         if (!instance) {
384                 g_free (fname);
385                 return;
386         }
387
388         ModestFolderView *self = MODEST_FOLDER_VIEW (data);
389         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (self);
390         
391         gchar *item_name = NULL;
392         gint item_weight = 400;
393         
394         if (type != TNY_FOLDER_TYPE_ROOT) {
395                 gint number = 0;
396                 
397                 if (modest_tny_folder_is_local_folder (TNY_FOLDER (instance)) ||
398                     modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance))) {
399                         type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (instance));
400                         if (type != TNY_FOLDER_TYPE_UNKNOWN) {
401                                 g_free (fname);
402                                 fname = g_strdup (modest_local_folder_info_get_type_display_name (type));
403                         }
404                 }
405
406                 /* note: we cannot reliably get the counts from the tree model, we need
407                  * to use explicit calls on tny_folder for some reason.
408                  */
409                 /* Select the number to show: the unread or unsent messages. in case of outbox/drafts, show all */
410                 if ((type == TNY_FOLDER_TYPE_DRAFTS) ||
411                     (type == TNY_FOLDER_TYPE_OUTBOX) ||
412                     (type == TNY_FOLDER_TYPE_MERGE)) /* _OUTBOX actually returns _MERGE... */
413                         number = tny_folder_get_all_count (TNY_FOLDER(instance));
414                 else
415                         number = tny_folder_get_unread_count (TNY_FOLDER(instance));
416                                                                 
417                 /* Use bold font style if there are unread or unset messages */
418                 if (number > 0) {
419                         item_name = g_strdup_printf ("%s (%d)", fname, number);
420                         item_weight = 800;
421                 } else {
422                         item_name = g_strdup (fname);
423                         item_weight = 400;
424                 }
425                 
426         } else if (TNY_IS_ACCOUNT (instance)) {
427                 /* If it's a server account */
428                 if (modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (instance))) {
429                         item_name = g_strdup (priv->local_account_name);
430                         item_weight = 800;
431                 } else if (modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance))) {
432                         /* fname is only correct when the items are first 
433                          * added to the model, not when the account is 
434                          * changed later, so get the name from the account
435                          * instance: */
436                         item_name = g_strdup (tny_account_get_name (TNY_ACCOUNT (instance)));
437                         item_weight = 800;
438                 } else {
439                         item_name = g_strdup (fname);
440                         item_weight = 800;
441                 }
442         }
443         
444         if (!item_name)
445                 item_name = g_strdup ("unknown");
446                         
447         if (item_name && item_weight) {
448                 /* Set the name in the treeview cell: */
449                 g_object_set (rendobj,"text", item_name, "weight", item_weight, NULL);
450                 
451                 /* Notify display name observers */
452                 /* TODO: What listens for this signal, and how can it use only the new name? */
453                 if (((GObject *) priv->cur_folder_store) == instance) {
454                         g_signal_emit (G_OBJECT(self),
455                                                signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
456                                                item_name);
457                 }
458                 g_free (item_name);
459                 
460         }
461         
462         /* If it is a Memory card account, make sure that we have the correct name.
463          * This function will be trigerred again when the name has been retrieved: */
464         if (TNY_IS_STORE_ACCOUNT (instance) && 
465                 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance))) {
466
467                 /* Get the account name asynchronously: */
468                 GetMmcAccountNameData *callback_data = 
469                         g_slice_new0(GetMmcAccountNameData);
470                 callback_data->self = self;
471
472                 const gchar *name = tny_account_get_name (TNY_ACCOUNT(instance));
473                 if (name)
474                         callback_data->previous_name = g_strdup (name); 
475
476                 modest_tny_account_get_mmc_account_name (TNY_STORE_ACCOUNT (instance), 
477                                                          on_get_mmc_account_name, callback_data);
478         }
479                         
480         g_object_unref (G_OBJECT (instance));
481         g_free (fname);
482 }
483
484
485 typedef struct {
486         GdkPixbuf *pixbuf;
487         GdkPixbuf *pixbuf_open;
488         GdkPixbuf *pixbuf_close;
489 } ThreePixbufs;
490
491
492 static ThreePixbufs*
493 get_folder_icons (TnyFolderType type, GObject *instance)
494 {
495         GdkPixbuf *pixbuf = NULL;
496         GdkPixbuf *pixbuf_open = NULL;
497         GdkPixbuf *pixbuf_close = NULL;
498         ThreePixbufs *retval = g_slice_new (ThreePixbufs);
499
500         static GdkPixbuf *inbox_pixbuf = NULL, *outbox_pixbuf = NULL,
501                 *junk_pixbuf = NULL, *sent_pixbuf = NULL,
502                 *trash_pixbuf = NULL, *draft_pixbuf = NULL,
503                 *normal_pixbuf = NULL, *anorm_pixbuf = NULL, 
504                 *ammc_pixbuf = NULL, *avirt_pixbuf = NULL;
505
506         static GdkPixbuf *inbox_pixbuf_open = NULL, *outbox_pixbuf_open = NULL,
507                 *junk_pixbuf_open = NULL, *sent_pixbuf_open = NULL,
508                 *trash_pixbuf_open = NULL, *draft_pixbuf_open = NULL,
509                 *normal_pixbuf_open = NULL, *anorm_pixbuf_open = NULL, 
510                 *ammc_pixbuf_open = NULL, *avirt_pixbuf_open = NULL;
511
512         static GdkPixbuf *inbox_pixbuf_close = NULL, *outbox_pixbuf_close = NULL,
513                 *junk_pixbuf_close = NULL, *sent_pixbuf_close = NULL,
514                 *trash_pixbuf_close = NULL, *draft_pixbuf_close = NULL,
515                 *normal_pixbuf_close = NULL, *anorm_pixbuf_close = NULL, 
516                 *ammc_pixbuf_close = NULL, *avirt_pixbuf_close = NULL;
517
518
519         /* MERGE is not needed anymore as the folder now has the correct type jschmid */
520         /* We include the MERGE type here because it's used to create
521            the local OUTBOX folder */
522         if (type == TNY_FOLDER_TYPE_NORMAL || 
523             type == TNY_FOLDER_TYPE_UNKNOWN) {
524                 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));             
525         }
526
527         switch (type) {
528         case TNY_FOLDER_TYPE_INVALID:
529                 g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
530                 break;
531                 
532         case TNY_FOLDER_TYPE_ROOT:
533                 if (TNY_IS_ACCOUNT (instance)) {
534                         
535                         if (modest_tny_account_is_virtual_local_folders (
536                                 TNY_ACCOUNT (instance))) {
537
538                             if (!avirt_pixbuf)
539                                     avirt_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS));
540
541                             if (!avirt_pixbuf_open) {
542                                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
543                                 avirt_pixbuf_open = gdk_pixbuf_copy (avirt_pixbuf);
544                                 gdk_pixbuf_composite (emblem, avirt_pixbuf_open, 0, 0, 
545                                                       MIN (gdk_pixbuf_get_width (emblem), 
546                                                            gdk_pixbuf_get_width (avirt_pixbuf_open)),
547                                                       MIN (gdk_pixbuf_get_height (emblem), 
548                                                            gdk_pixbuf_get_height (avirt_pixbuf_open)),
549                                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
550                                 g_object_unref (emblem);
551                             }
552
553                             if (!avirt_pixbuf_close) {
554                                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
555                                 avirt_pixbuf_close = gdk_pixbuf_copy (avirt_pixbuf);
556                                 gdk_pixbuf_composite (emblem, avirt_pixbuf_close, 0, 0, 
557                                                       MIN (gdk_pixbuf_get_width (emblem), 
558                                                            gdk_pixbuf_get_width (avirt_pixbuf_close)),
559                                                       MIN (gdk_pixbuf_get_height (emblem), 
560                                                            gdk_pixbuf_get_height (avirt_pixbuf_close)),
561                                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
562                                 g_object_unref (emblem);
563                             }
564
565
566                             pixbuf = g_object_ref (avirt_pixbuf);
567                             pixbuf_open = g_object_ref (avirt_pixbuf_open);
568                             pixbuf_close = g_object_ref (avirt_pixbuf_close);
569
570                         }
571                         else {
572                                 const gchar *account_id = tny_account_get_id (TNY_ACCOUNT (instance));
573                                 
574                                 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {                                 
575                                     if (!ammc_pixbuf)
576                                             ammc_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_MMC));
577
578                                     if (!ammc_pixbuf_open) {
579                                         GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
580                                         ammc_pixbuf_open = gdk_pixbuf_copy (ammc_pixbuf);
581                                         gdk_pixbuf_composite (emblem, ammc_pixbuf_open, 0, 0, 
582                                                               MIN (gdk_pixbuf_get_width (emblem), 
583                                                                    gdk_pixbuf_get_width (ammc_pixbuf_open)),
584                                                               MIN (gdk_pixbuf_get_height (emblem), 
585                                                                    gdk_pixbuf_get_height (ammc_pixbuf_open)),
586                                                               0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
587                                         g_object_unref (emblem);
588                                     }
589
590                                     if (!ammc_pixbuf_close) {
591                                         GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
592                                         ammc_pixbuf_close = gdk_pixbuf_copy (ammc_pixbuf);
593                                         gdk_pixbuf_composite (emblem, ammc_pixbuf_close, 0, 0, 
594                                                               MIN (gdk_pixbuf_get_width (emblem), 
595                                                                    gdk_pixbuf_get_width (ammc_pixbuf_close)),
596                                                               MIN (gdk_pixbuf_get_height (emblem), 
597                                                                    gdk_pixbuf_get_height (ammc_pixbuf_close)),
598                                                               0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
599                                         g_object_unref (emblem);
600                                     }
601
602
603                                     pixbuf = g_object_ref (ammc_pixbuf);
604                                     pixbuf_open = g_object_ref (ammc_pixbuf_open);
605                                     pixbuf_close = g_object_ref (ammc_pixbuf_close);
606
607                                 } else {
608
609                                     if (!anorm_pixbuf)
610                                             anorm_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT));
611
612                                     if (!anorm_pixbuf_open) {
613                                         GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
614                                         anorm_pixbuf_open = gdk_pixbuf_copy (anorm_pixbuf);
615                                         gdk_pixbuf_composite (emblem, anorm_pixbuf_open, 0, 0, 
616                                                               MIN (gdk_pixbuf_get_width (emblem), 
617                                                                    gdk_pixbuf_get_width (anorm_pixbuf_open)),
618                                                               MIN (gdk_pixbuf_get_height (emblem), 
619                                                                    gdk_pixbuf_get_height (anorm_pixbuf_open)),
620                                                               0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
621                                         g_object_unref (emblem);
622                                     }
623
624                                     if (!anorm_pixbuf_close) {
625                                         GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
626                                         anorm_pixbuf_close = gdk_pixbuf_copy (anorm_pixbuf);
627                                         gdk_pixbuf_composite (emblem, anorm_pixbuf_close, 0, 0, 
628                                                               MIN (gdk_pixbuf_get_width (emblem), 
629                                                                    gdk_pixbuf_get_width (anorm_pixbuf_close)),
630                                                               MIN (gdk_pixbuf_get_height (emblem), 
631                                                                    gdk_pixbuf_get_height (anorm_pixbuf_close)),
632                                                               0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
633                                         g_object_unref (emblem);
634                                     }
635
636
637                                     pixbuf = g_object_ref (anorm_pixbuf);
638                                     pixbuf_open = g_object_ref (anorm_pixbuf_open);
639                                     pixbuf_close = g_object_ref (anorm_pixbuf_close);                             
640
641                                 }
642                         }
643                 }
644                 break;
645         case TNY_FOLDER_TYPE_INBOX:
646
647             if (!inbox_pixbuf)
648                     inbox_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX));
649
650             if (!inbox_pixbuf_open) {
651                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
652                 inbox_pixbuf_open = gdk_pixbuf_copy (inbox_pixbuf);
653                 gdk_pixbuf_composite (emblem, inbox_pixbuf_open, 0, 0, 
654                                       MIN (gdk_pixbuf_get_width (emblem), 
655                                            gdk_pixbuf_get_width (inbox_pixbuf_open)),
656                                       MIN (gdk_pixbuf_get_height (emblem), 
657                                            gdk_pixbuf_get_height (inbox_pixbuf_open)),
658                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
659                 g_object_unref (emblem);
660             }
661
662             if (!inbox_pixbuf_close) {
663                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
664                 inbox_pixbuf_close = gdk_pixbuf_copy (inbox_pixbuf);
665                 gdk_pixbuf_composite (emblem, inbox_pixbuf_close, 0, 0, 
666                                       MIN (gdk_pixbuf_get_width (emblem), 
667                                            gdk_pixbuf_get_width (inbox_pixbuf_close)),
668                                       MIN (gdk_pixbuf_get_height (emblem), 
669                                            gdk_pixbuf_get_height (inbox_pixbuf_close)),
670                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
671                 g_object_unref (emblem);
672             }
673
674
675             pixbuf = g_object_ref (inbox_pixbuf);
676             pixbuf_open = g_object_ref (inbox_pixbuf_open);
677             pixbuf_close = g_object_ref (inbox_pixbuf_close);
678
679             break;
680         case TNY_FOLDER_TYPE_OUTBOX:
681             if (!outbox_pixbuf)
682                 outbox_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX));
683
684             if (!outbox_pixbuf_open) {
685                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
686                 outbox_pixbuf_open = gdk_pixbuf_copy (outbox_pixbuf);
687                 gdk_pixbuf_composite (emblem, outbox_pixbuf_open, 0, 0, 
688                                       MIN (gdk_pixbuf_get_width (emblem), 
689                                            gdk_pixbuf_get_width (outbox_pixbuf_open)),
690                                       MIN (gdk_pixbuf_get_height (emblem), 
691                                            gdk_pixbuf_get_height (outbox_pixbuf_open)),
692                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
693                 g_object_unref (emblem);
694             }
695
696             if (!outbox_pixbuf_close) {
697                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
698                 outbox_pixbuf_close = gdk_pixbuf_copy (outbox_pixbuf);
699                 gdk_pixbuf_composite (emblem, outbox_pixbuf_close, 0, 0, 
700                                       MIN (gdk_pixbuf_get_width (emblem), 
701                                            gdk_pixbuf_get_width (outbox_pixbuf_close)),
702                                       MIN (gdk_pixbuf_get_height (emblem), 
703                                            gdk_pixbuf_get_height (outbox_pixbuf_close)),
704                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
705                 g_object_unref (emblem);
706             }
707
708
709             pixbuf = g_object_ref (outbox_pixbuf);
710             pixbuf_open = g_object_ref (outbox_pixbuf_open);
711             pixbuf_close = g_object_ref (outbox_pixbuf_close);
712
713             break;
714         case TNY_FOLDER_TYPE_JUNK:
715             if (!junk_pixbuf)
716                 junk_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK));
717
718             if (!junk_pixbuf_open) {
719                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
720                 junk_pixbuf_open = gdk_pixbuf_copy (junk_pixbuf);
721                 gdk_pixbuf_composite (emblem, junk_pixbuf_open, 0, 0, 
722                                       MIN (gdk_pixbuf_get_width (emblem), 
723                                            gdk_pixbuf_get_width (junk_pixbuf_open)),
724                                       MIN (gdk_pixbuf_get_height (emblem), 
725                                            gdk_pixbuf_get_height (junk_pixbuf_open)),
726                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
727                 g_object_unref (emblem);
728             }
729
730             if (!junk_pixbuf_close) {
731                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
732                 junk_pixbuf_close = gdk_pixbuf_copy (junk_pixbuf);
733                 gdk_pixbuf_composite (emblem, junk_pixbuf_close, 0, 0, 
734                                       MIN (gdk_pixbuf_get_width (emblem), 
735                                            gdk_pixbuf_get_width (junk_pixbuf_close)),
736                                       MIN (gdk_pixbuf_get_height (emblem), 
737                                            gdk_pixbuf_get_height (junk_pixbuf_close)),
738                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
739                 g_object_unref (emblem);
740             }
741
742
743             pixbuf = g_object_ref (junk_pixbuf);
744             pixbuf_open = g_object_ref (junk_pixbuf_open);
745             pixbuf_close = g_object_ref (junk_pixbuf_close);
746
747             break;
748         case TNY_FOLDER_TYPE_SENT:
749             if (!sent_pixbuf)
750                 sent_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_SENT));
751
752             if (!junk_pixbuf_open) {
753                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
754                 sent_pixbuf_open = gdk_pixbuf_copy (sent_pixbuf);
755                 gdk_pixbuf_composite (emblem, sent_pixbuf_open, 0, 0, 
756                                       MIN (gdk_pixbuf_get_width (emblem), 
757                                            gdk_pixbuf_get_width (sent_pixbuf_open)),
758                                       MIN (gdk_pixbuf_get_height (emblem), 
759                                            gdk_pixbuf_get_height (sent_pixbuf_open)),
760                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
761                 g_object_unref (emblem);
762             }
763
764             if (!sent_pixbuf_close) {
765                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
766                 sent_pixbuf_close = gdk_pixbuf_copy (sent_pixbuf);
767                 gdk_pixbuf_composite (emblem, sent_pixbuf_close, 0, 0, 
768                                       MIN (gdk_pixbuf_get_width (emblem), 
769                                            gdk_pixbuf_get_width (sent_pixbuf_close)),
770                                       MIN (gdk_pixbuf_get_height (emblem), 
771                                            gdk_pixbuf_get_height (sent_pixbuf_close)),
772                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
773                 g_object_unref (emblem);
774             }
775
776
777             pixbuf = g_object_ref (sent_pixbuf);
778             pixbuf_open = g_object_ref (sent_pixbuf_open);
779             pixbuf_close = g_object_ref (sent_pixbuf_close);
780
781             break;
782         case TNY_FOLDER_TYPE_TRASH:
783             if (!trash_pixbuf)
784                 trash_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH));
785
786             if (!junk_pixbuf_open) {
787                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
788                 trash_pixbuf_open = gdk_pixbuf_copy (trash_pixbuf);
789                 gdk_pixbuf_composite (emblem, trash_pixbuf_open, 0, 0, 
790                                       MIN (gdk_pixbuf_get_width (emblem), 
791                                            gdk_pixbuf_get_width (trash_pixbuf_open)),
792                                       MIN (gdk_pixbuf_get_height (emblem), 
793                                            gdk_pixbuf_get_height (trash_pixbuf_open)),
794                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
795                 g_object_unref (emblem);
796             }
797
798             if (!trash_pixbuf_close) {
799                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
800                 trash_pixbuf_close = gdk_pixbuf_copy (trash_pixbuf);
801                 gdk_pixbuf_composite (emblem, trash_pixbuf_close, 0, 0, 
802                                       MIN (gdk_pixbuf_get_width (emblem), 
803                                            gdk_pixbuf_get_width (trash_pixbuf_close)),
804                                       MIN (gdk_pixbuf_get_height (emblem), 
805                                            gdk_pixbuf_get_height (trash_pixbuf_close)),
806                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
807                 g_object_unref (emblem);
808             }
809
810
811             pixbuf = g_object_ref (trash_pixbuf);
812             pixbuf_open = g_object_ref (trash_pixbuf_open);
813             pixbuf_close = g_object_ref (trash_pixbuf_close);
814
815             break;
816         case TNY_FOLDER_TYPE_DRAFTS:
817            if (!draft_pixbuf)
818                 draft_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS));
819
820             if (!junk_pixbuf_open) {
821                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
822                 draft_pixbuf_open = gdk_pixbuf_copy (draft_pixbuf);
823                 gdk_pixbuf_composite (emblem, draft_pixbuf_open, 0, 0, 
824                                       MIN (gdk_pixbuf_get_width (emblem), 
825                                            gdk_pixbuf_get_width (draft_pixbuf_open)),
826                                       MIN (gdk_pixbuf_get_height (emblem), 
827                                            gdk_pixbuf_get_height (draft_pixbuf_open)),
828                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
829                 g_object_unref (emblem);
830             }
831
832             if (!draft_pixbuf_close) {
833                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
834                 draft_pixbuf_close = gdk_pixbuf_copy (draft_pixbuf);
835                 gdk_pixbuf_composite (emblem, draft_pixbuf_close, 0, 0, 
836                                       MIN (gdk_pixbuf_get_width (emblem), 
837                                            gdk_pixbuf_get_width (draft_pixbuf_close)),
838                                       MIN (gdk_pixbuf_get_height (emblem), 
839                                            gdk_pixbuf_get_height (draft_pixbuf_close)),
840                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
841                 g_object_unref (emblem);
842             }
843
844
845             pixbuf = g_object_ref (draft_pixbuf);
846             pixbuf_open = g_object_ref (draft_pixbuf_open);
847             pixbuf_close = g_object_ref (draft_pixbuf_close);
848
849             break;      
850         case TNY_FOLDER_TYPE_NORMAL:
851         default:
852             if (!normal_pixbuf)
853                 normal_pixbuf = gdk_pixbuf_copy (modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL));
854
855             if (!junk_pixbuf_open) {
856                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
857                 normal_pixbuf_open = gdk_pixbuf_copy (normal_pixbuf);
858                 gdk_pixbuf_composite (emblem, draft_pixbuf_open, 0, 0, 
859                                       MIN (gdk_pixbuf_get_width (emblem), 
860                                            gdk_pixbuf_get_width (normal_pixbuf_open)),
861                                       MIN (gdk_pixbuf_get_height (emblem), 
862                                            gdk_pixbuf_get_height (normal_pixbuf_open)),
863                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
864                 g_object_unref (emblem);
865             }
866
867             if (!normal_pixbuf_close) {
868                 GdkPixbuf *emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
869                 normal_pixbuf_close = gdk_pixbuf_copy (normal_pixbuf);
870                 gdk_pixbuf_composite (emblem, normal_pixbuf_close, 0, 0, 
871                                       MIN (gdk_pixbuf_get_width (emblem), 
872                                            gdk_pixbuf_get_width (normal_pixbuf_close)),
873                                       MIN (gdk_pixbuf_get_height (emblem), 
874                                            gdk_pixbuf_get_height (normal_pixbuf_close)),
875                                       0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
876                 g_object_unref (emblem);
877             }
878
879
880             pixbuf = g_object_ref (normal_pixbuf);
881             pixbuf_open = g_object_ref (normal_pixbuf_open);
882             pixbuf_close = g_object_ref (normal_pixbuf_close);
883
884             break;      
885
886         }
887
888         retval->pixbuf = pixbuf;
889         retval->pixbuf_open = pixbuf_open;
890         retval->pixbuf_close = pixbuf_close;
891
892         return retval;
893 }
894
895
896 static void
897 free_pixbufs (ThreePixbufs *pixbufs)
898 {
899         g_object_unref (pixbufs->pixbuf);
900         g_object_unref (pixbufs->pixbuf_open);
901         g_object_unref (pixbufs->pixbuf_close);
902         g_slice_free (ThreePixbufs, pixbufs);
903 }
904
905 static void
906 icon_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
907                  GtkTreeModel *tree_model,  GtkTreeIter *iter, gpointer data)
908 {
909         GObject *rendobj = (GObject *) renderer, *instance = NULL;
910         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
911         gboolean has_children;
912         ThreePixbufs *pixbufs;
913
914         gtk_tree_model_get (tree_model, iter,
915                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
916                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
917                             -1);
918
919         if (!instance) 
920                 return;
921
922         has_children = gtk_tree_model_iter_has_child (tree_model, iter);
923         pixbufs = get_folder_icons (type, instance);    
924         g_object_unref (instance);
925
926         /* Set pixbuf */
927         g_object_set (rendobj, "pixbuf", pixbufs->pixbuf, NULL);
928
929         if (has_children) {
930                 g_object_set (rendobj, "pixbuf-expander-open", pixbufs->pixbuf_open, NULL);
931                 g_object_set (rendobj, "pixbuf-expander-closed", pixbufs->pixbuf_close, NULL);
932         }
933
934         free_pixbufs (pixbufs);
935
936         return;
937 }
938
939 static void
940 add_columns (GtkWidget *treeview)
941 {
942         GtkTreeViewColumn *column;
943         GtkCellRenderer *renderer;
944         GtkTreeSelection *sel;
945
946         /* Create column */
947         column = gtk_tree_view_column_new ();   
948         
949         /* Set icon and text render function */
950         renderer = gtk_cell_renderer_pixbuf_new();
951         gtk_tree_view_column_pack_start (column, renderer, FALSE);
952         gtk_tree_view_column_set_cell_data_func(column, renderer,
953                                                 icon_cell_data, treeview, NULL);
954         
955         renderer = gtk_cell_renderer_text_new();
956         g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, 
957                         "ellipsize-set", TRUE, NULL);
958         gtk_tree_view_column_pack_start (column, renderer, TRUE);
959         gtk_tree_view_column_set_cell_data_func(column, renderer,
960                                                 text_cell_data, treeview, NULL);
961         
962         /* Set selection mode */
963         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
964         gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
965
966         /* Set treeview appearance */
967         gtk_tree_view_column_set_spacing (column, 2);
968         gtk_tree_view_column_set_resizable (column, TRUE);
969         gtk_tree_view_column_set_fixed_width (column, TRUE);            
970         gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
971         gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
972
973         /* Add column */
974         gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
975 }
976
977 static void
978 modest_folder_view_init (ModestFolderView *obj)
979 {
980         ModestFolderViewPrivate *priv;
981         ModestConf *conf;
982         
983         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
984         
985         priv->timer_expander = 0;
986         priv->account_store  = NULL;
987         priv->query          = NULL;
988         priv->style          = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
989         priv->cur_folder_store   = NULL;
990         priv->visible_account_id = NULL;
991         priv->folder_to_select = NULL;
992
993         priv->reexpand = TRUE;
994
995         /* Initialize the local account name */
996         conf = modest_runtime_get_conf();
997         priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
998
999         /* Init email clipboard */
1000         priv->clipboard = modest_runtime_get_email_clipboard ();
1001         priv->hidding_ids = NULL;
1002         priv->n_selected = 0;
1003         priv->reselect = FALSE;
1004         priv->show_non_move = TRUE;
1005
1006         /* Build treeview */
1007         add_columns (GTK_WIDGET (obj));
1008
1009         /* Setup drag and drop */
1010         setup_drag_and_drop (GTK_TREE_VIEW(obj));
1011
1012         /* Connect signals */
1013         g_signal_connect (G_OBJECT (obj), 
1014                           "key-press-event", 
1015                           G_CALLBACK (on_key_pressed), NULL);
1016
1017         priv->display_name_changed_signal = 
1018                 g_signal_connect (modest_runtime_get_account_mgr (),
1019                                   "display_name_changed",
1020                                   G_CALLBACK (on_display_name_changed),
1021                                   obj);
1022
1023         /*
1024          * Track changes in the local account name (in the device it
1025          * will be the device name)
1026          */
1027         priv->conf_key_signal = g_signal_connect (G_OBJECT(conf), 
1028                                                   "key_changed",
1029                                                   G_CALLBACK(on_configuration_key_changed), 
1030                                                   obj);
1031 }
1032
1033 static void
1034 tny_account_store_view_init (gpointer g, gpointer iface_data)
1035 {
1036         TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
1037
1038         klass->set_account_store_func = modest_folder_view_set_account_store;
1039
1040         return;
1041 }
1042
1043 static void
1044 modest_folder_view_finalize (GObject *obj)
1045 {
1046         ModestFolderViewPrivate *priv;
1047         GtkTreeSelection    *sel;
1048         
1049         g_return_if_fail (obj);
1050         
1051         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
1052
1053         if (priv->timer_expander != 0) {
1054                 g_source_remove (priv->timer_expander);
1055                 priv->timer_expander = 0;
1056         }
1057
1058         if (priv->account_store) {
1059                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1060                                              priv->account_inserted_signal);
1061                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1062                                              priv->account_removed_signal);
1063                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
1064                                              priv->account_changed_signal);
1065                 g_object_unref (G_OBJECT(priv->account_store));
1066                 priv->account_store = NULL;
1067         }
1068
1069         if (priv->query) {
1070                 g_object_unref (G_OBJECT (priv->query));
1071                 priv->query = NULL;
1072         }
1073
1074 /*      modest_folder_view_disable_next_folder_selection (MODEST_FOLDER_VIEW(obj)); */
1075         if (priv->folder_to_select) {
1076                 g_object_unref (G_OBJECT(priv->folder_to_select));
1077                 priv->folder_to_select = NULL;
1078         }
1079    
1080         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
1081         if (sel)
1082                 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
1083
1084         g_free (priv->local_account_name);
1085         g_free (priv->visible_account_id);
1086         
1087         if (priv->conf_key_signal) {
1088                 g_signal_handler_disconnect (modest_runtime_get_conf (),
1089                                              priv->conf_key_signal);
1090                 priv->conf_key_signal = 0;
1091         }
1092
1093         if (priv->cur_folder_store) {
1094                 if (TNY_IS_FOLDER(priv->cur_folder_store))
1095                         tny_folder_sync (TNY_FOLDER(priv->cur_folder_store), FALSE, NULL);
1096                         /* FALSE --> expunge the message */
1097
1098                 g_object_unref (priv->cur_folder_store);
1099                 priv->cur_folder_store = NULL;
1100         }
1101
1102         /* Clear hidding array created by cut operation */
1103         _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
1104
1105         G_OBJECT_CLASS(parent_class)->finalize (obj);
1106 }
1107
1108
1109 static void
1110 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
1111 {
1112         ModestFolderViewPrivate *priv;
1113         TnyDevice *device;
1114
1115         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1116         g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
1117
1118         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1119         device = tny_account_store_get_device (account_store);
1120
1121         if (G_UNLIKELY (priv->account_store)) {
1122
1123                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
1124                                                    priv->account_inserted_signal))
1125                         g_signal_handler_disconnect (G_OBJECT (priv->account_store),
1126                                                      priv->account_inserted_signal);
1127                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store), 
1128                                                    priv->account_removed_signal))
1129                         g_signal_handler_disconnect (G_OBJECT (priv->account_store), 
1130                                                      priv->account_removed_signal);
1131                 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store), 
1132                                                    priv->account_changed_signal))
1133                         g_signal_handler_disconnect (G_OBJECT (priv->account_store), 
1134                                                      priv->account_changed_signal);
1135                 g_object_unref (G_OBJECT (priv->account_store));
1136         }
1137
1138         priv->account_store = g_object_ref (G_OBJECT (account_store));
1139
1140         priv->account_removed_signal = 
1141                 g_signal_connect (G_OBJECT(account_store), "account_removed",
1142                                   G_CALLBACK (on_account_removed), self);
1143
1144         priv->account_inserted_signal =
1145                 g_signal_connect (G_OBJECT(account_store), "account_inserted",
1146                                   G_CALLBACK (on_account_inserted), self);
1147
1148         priv->account_changed_signal =
1149                 g_signal_connect (G_OBJECT(account_store), "account_changed",
1150                                   G_CALLBACK (on_account_changed), self);
1151
1152         modest_folder_view_update_model (MODEST_FOLDER_VIEW (self), account_store);
1153         
1154         g_object_unref (G_OBJECT (device));
1155 }
1156
1157 static void
1158 on_connection_status_changed (TnyAccount *self, 
1159                               TnyConnectionStatus status, 
1160                               gpointer user_data)
1161 {
1162         /* If the account becomes online then refresh it */
1163         if (status == TNY_CONNECTION_STATUS_CONNECTED) {
1164                 const gchar *acc_name;
1165                 GtkWidget *my_window;
1166
1167                 my_window = gtk_widget_get_ancestor (GTK_WIDGET (user_data), MODEST_TYPE_WINDOW);
1168                 acc_name = modest_tny_account_get_parent_modest_account_name_for_server_account (self);
1169                 modest_ui_actions_do_send_receive (acc_name, MODEST_WINDOW (my_window));
1170         }
1171 }
1172
1173 static void
1174 on_account_inserted (TnyAccountStore *account_store, 
1175                      TnyAccount *account,
1176                      gpointer user_data)
1177 {
1178         ModestFolderViewPrivate *priv;
1179         GtkTreeModel *sort_model, *filter_model;
1180
1181         /* Ignore transport account insertions, we're not showing them
1182            in the folder view */
1183         if (TNY_IS_TRANSPORT_ACCOUNT (account))
1184                 return;
1185
1186         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data);
1187
1188         /* If we're adding a new account, and there is no previous
1189            one, we need to select the visible server account */
1190         if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
1191             !priv->visible_account_id)
1192                 modest_widget_memory_restore (modest_runtime_get_conf(), 
1193                                               G_OBJECT (user_data),
1194                                               MODEST_CONF_FOLDER_VIEW_KEY);
1195
1196         /* Get the inner model */
1197         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data));
1198         sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
1199
1200         /* Insert the account in the model */
1201         tny_list_append (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))),
1202                          G_OBJECT (account));
1203
1204
1205         /* When the store account gets online refresh it */
1206         g_signal_connect (account, "connection_status_changed", 
1207                           G_CALLBACK (on_connection_status_changed), 
1208                           MODEST_FOLDER_VIEW (user_data));
1209
1210         /* Refilter the model */
1211         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1212 }
1213
1214
1215 static void
1216 on_account_changed (TnyAccountStore *account_store, 
1217                     TnyAccount *tny_account,
1218                     gpointer user_data)
1219 {
1220         /* do nothing */
1221         ModestFolderViewPrivate *priv;
1222         GtkTreeModel *sort_model, *filter_model;
1223
1224         /* Ignore transport account insertions, we're not showing them
1225            in the folder view */
1226         if (TNY_IS_TRANSPORT_ACCOUNT (tny_account))
1227                 return;
1228
1229         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data);
1230
1231         /* Get the inner model */
1232         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data));
1233         sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
1234         
1235         /* Remove the account from the model */
1236         tny_list_remove (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))),
1237                          G_OBJECT (tny_account));
1238
1239         /* Insert the account in the model */
1240         tny_list_append (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))),
1241                          G_OBJECT (tny_account));
1242
1243         /* Refilter the model */
1244         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1245 }
1246
1247
1248
1249 static void
1250 on_account_removed (TnyAccountStore *account_store, 
1251                     TnyAccount *account,
1252                     gpointer user_data)
1253 {
1254         ModestFolderView *self = NULL;
1255         ModestFolderViewPrivate *priv;
1256         GtkTreeModel *sort_model, *filter_model;
1257         GtkTreeSelection *sel = NULL;
1258
1259         /* Ignore transport account removals, we're not showing them
1260            in the folder view */
1261         if (TNY_IS_TRANSPORT_ACCOUNT (account))
1262                 return;
1263
1264         self = MODEST_FOLDER_VIEW (user_data);
1265         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1266
1267         /* Invalidate the cur_folder_store only if the selected folder
1268            belongs to the account that is being removed */
1269         if (priv->cur_folder_store) {
1270                 TnyAccount *selected_folder_account = NULL;
1271
1272                 if (TNY_IS_FOLDER (priv->cur_folder_store)) {
1273                         selected_folder_account = 
1274                                 tny_folder_get_account (TNY_FOLDER (priv->cur_folder_store));
1275                 } else {
1276                         selected_folder_account = 
1277                                 TNY_ACCOUNT (g_object_ref (priv->cur_folder_store));
1278                 }
1279
1280                 if (selected_folder_account == account) {
1281                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1282                         gtk_tree_selection_unselect_all (sel);
1283                 }
1284                 g_object_unref (selected_folder_account);
1285         }
1286
1287         /* Invalidate row to select only if the folder to select
1288            belongs to the account that is being removed*/
1289         if (priv->folder_to_select) {
1290                 TnyAccount *folder_to_select_account = NULL;
1291
1292                 folder_to_select_account = tny_folder_get_account (priv->folder_to_select);
1293                 if (folder_to_select_account == account) {
1294 /*                      modest_folder_view_disable_next_folder_selection (self); */
1295                         g_object_unref (priv->folder_to_select);
1296                         priv->folder_to_select = NULL;
1297                 }
1298                 g_object_unref (folder_to_select_account);
1299         }
1300
1301         /* Remove the account from the model */
1302         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1303         sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
1304         tny_list_remove (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))),
1305                          G_OBJECT (account));
1306
1307         /* If the removed account is the currently viewed one then
1308            clear the configuration value. The new visible account will be the default account */
1309         if (priv->visible_account_id &&
1310             !strcmp (priv->visible_account_id, tny_account_get_id (account))) {
1311
1312                 /* Clear the current visible account_id */
1313                 modest_folder_view_set_account_id_of_visible_server_account (self, NULL);
1314
1315                 /* Call the restore method, this will set the new visible account */
1316                 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
1317                                               MODEST_CONF_FOLDER_VIEW_KEY);
1318         }
1319
1320         /* Refilter the model */
1321         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));
1322
1323         /* Select the first INBOX if the currently selected folder
1324            belongs to the account that is being deleted */
1325         if (priv->cur_folder_store) {
1326                 TnyAccount *folder_selected_account;
1327
1328                 folder_selected_account = (TNY_IS_FOLDER (priv->cur_folder_store)) ?
1329                         modest_tny_folder_get_account (TNY_FOLDER (priv->cur_folder_store)) :
1330                         TNY_ACCOUNT (g_object_ref (priv->cur_folder_store));
1331                 if (account == folder_selected_account)
1332                         modest_folder_view_select_first_inbox_or_local (self);
1333                 g_object_unref (folder_selected_account);
1334         }
1335 }
1336
1337 void
1338 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
1339 {
1340         GtkTreeViewColumn *col;
1341         
1342         g_return_if_fail (self);
1343
1344         col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
1345         if (!col) {
1346                 g_printerr ("modest: failed get column for title\n");
1347                 return;
1348         }
1349
1350         gtk_tree_view_column_set_title (col, title);
1351         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
1352                                            title != NULL);
1353 }
1354
1355 static gboolean
1356 modest_folder_view_on_map (ModestFolderView *self, 
1357                            GdkEventExpose *event,
1358                            gpointer data)
1359 {
1360         ModestFolderViewPrivate *priv;
1361
1362         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1363
1364         /* This won't happen often */
1365         if (G_UNLIKELY (priv->reselect)) {
1366                 /* Select the first inbox or the local account if not found */
1367
1368                 /* TODO: this could cause a lock at startup, so we
1369                    comment it for the moment. We know that this will
1370                    be a bug, because the INBOX is not selected, but we
1371                    need to rewrite some parts of Modest to avoid the
1372                    deathlock situation */
1373                 /* TODO: check if this is still the case */
1374                 priv->reselect = FALSE;
1375                 modest_folder_view_select_first_inbox_or_local (self);
1376                 /* Notify the display name observers */
1377                 g_signal_emit (G_OBJECT(self),
1378                                signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1379                                NULL);
1380         }
1381
1382         if (priv->reexpand) {
1383                 expand_root_items (self); 
1384                 priv->reexpand = FALSE;
1385         }
1386
1387         return FALSE;
1388 }
1389
1390 GtkWidget*
1391 modest_folder_view_new (TnyFolderStoreQuery *query)
1392 {
1393         GObject *self;
1394         ModestFolderViewPrivate *priv;
1395         GtkTreeSelection *sel;
1396         
1397         self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, NULL));
1398         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
1399
1400         if (query)
1401                 priv->query = g_object_ref (query);
1402         
1403         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
1404         priv->changed_signal = g_signal_connect (sel, "changed",
1405                                                  G_CALLBACK (on_selection_changed), self);
1406
1407         g_signal_connect (self, "expose-event", G_CALLBACK (modest_folder_view_on_map), NULL);
1408
1409         return GTK_WIDGET(self);
1410 }
1411
1412 /* this feels dirty; any other way to expand all the root items? */
1413 static void
1414 expand_root_items (ModestFolderView *self)
1415 {
1416         GtkTreePath *path;
1417         GtkTreeModel *model;
1418         GtkTreeIter iter;
1419
1420         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1421         path = gtk_tree_path_new_first ();
1422
1423         /* all folders should have child items, so.. */
1424         do {
1425                 gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE);
1426                 gtk_tree_path_next (path);
1427         } while (gtk_tree_model_get_iter (model, &iter, path));
1428         
1429         gtk_tree_path_free (path);
1430 }
1431
1432 /*
1433  * We use this function to implement the
1434  * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
1435  * account in this case, and the local folders.
1436  */
1437 static gboolean 
1438 filter_row (GtkTreeModel *model,
1439             GtkTreeIter *iter,
1440             gpointer data)
1441 {
1442         ModestFolderViewPrivate *priv;
1443         gboolean retval = TRUE;
1444         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1445         GObject *instance = NULL;
1446         const gchar *id = NULL;
1447         guint i;
1448         gboolean found = FALSE;
1449         gboolean cleared = FALSE;
1450
1451         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE);
1452         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
1453
1454         gtk_tree_model_get (model, iter,
1455                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
1456                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
1457                             -1);
1458
1459         /* Do not show if there is no instance, this could indeed
1460            happen when the model is being modified while it's being
1461            drawn. This could occur for example when moving folders
1462            using drag&drop */
1463         if (!instance)
1464                 return FALSE;
1465
1466         if (type == TNY_FOLDER_TYPE_ROOT) {
1467                 /* TNY_FOLDER_TYPE_ROOT means that the instance is an
1468                    account instead of a folder. */
1469                 if (TNY_IS_ACCOUNT (instance)) {
1470                         TnyAccount *acc = TNY_ACCOUNT (instance);
1471                         const gchar *account_id = tny_account_get_id (acc);
1472         
1473                         /* If it isn't a special folder, 
1474                          * don't show it unless it is the visible account: */
1475                         if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
1476                             !modest_tny_account_is_virtual_local_folders (acc) &&
1477                             strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1478                                 
1479                                 /* Show only the visible account id */
1480                                 if (priv->visible_account_id) {
1481                                         if (strcmp (account_id, priv->visible_account_id))
1482                                                 retval = FALSE;
1483                                 } else {
1484                                         retval = FALSE;
1485                                 }                               
1486                         }
1487                         
1488                         /* Never show these to the user. They are merged into one folder 
1489                          * in the local-folders account instead: */
1490                         if (retval && MODEST_IS_TNY_OUTBOX_ACCOUNT (acc))
1491                                 retval = FALSE;
1492                 }
1493         }
1494
1495         /* Check hiding (if necessary) */
1496         cleared = modest_email_clipboard_cleared (priv->clipboard);            
1497         if ((retval) && (!cleared) && (TNY_IS_FOLDER (instance))) {
1498                 id = tny_folder_get_id (TNY_FOLDER(instance));
1499                 if (priv->hidding_ids != NULL)
1500                         for (i=0; i < priv->n_selected && !found; i++)
1501                                 if (priv->hidding_ids[i] != NULL && id != NULL)
1502                                         found = (!strcmp (priv->hidding_ids[i], id));
1503                 
1504                 retval = !found;
1505         }
1506         
1507         
1508         /* If this is a move to dialog, hide Sent, Outbox and Drafts
1509         folder as no message can be move there according to UI specs */
1510         if (!priv->show_non_move) {
1511                 switch (type) {
1512                         case TNY_FOLDER_TYPE_OUTBOX:
1513                         case TNY_FOLDER_TYPE_SENT:
1514                         case TNY_FOLDER_TYPE_DRAFTS:
1515                                 retval = FALSE;
1516                                 break;
1517                         case TNY_FOLDER_TYPE_UNKNOWN:
1518                         case TNY_FOLDER_TYPE_NORMAL:
1519                                 type = modest_tny_folder_guess_folder_type(TNY_FOLDER(instance));
1520                                 if (type == TNY_FOLDER_TYPE_INVALID)
1521                                         g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__);
1522                                 
1523                                 if (type == TNY_FOLDER_TYPE_OUTBOX || 
1524                                     type == TNY_FOLDER_TYPE_SENT
1525                                     || type == TNY_FOLDER_TYPE_DRAFTS)
1526                                         retval = FALSE;
1527                                 break;
1528                         default:
1529                                 break;
1530                 }
1531         }
1532         
1533         /* Free */
1534         g_object_unref (instance);
1535
1536         return retval;
1537 }
1538
1539
1540 gboolean
1541 modest_folder_view_update_model (ModestFolderView *self,
1542                                  TnyAccountStore *account_store)
1543 {
1544         ModestFolderViewPrivate *priv;
1545         GtkTreeModel *model /* , *old_model */;                                                    
1546         GtkTreeModel *filter_model = NULL, *sortable = NULL;
1547
1548         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
1549         g_return_val_if_fail (account_store, FALSE);
1550
1551         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1552         
1553         /* Notify that there is no folder selected */
1554         g_signal_emit (G_OBJECT(self), 
1555                        signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1556                        NULL, FALSE);
1557         if (priv->cur_folder_store) {
1558                 g_object_unref (priv->cur_folder_store);
1559                 priv->cur_folder_store = NULL;
1560         }
1561
1562         /* FIXME: the local accounts are not shown when the query
1563            selects only the subscribed folders */
1564         model        = tny_gtk_folder_store_tree_model_new (NULL);
1565
1566         /* Get the accounts: */
1567         tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
1568                                         TNY_LIST (model),
1569                                         TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
1570
1571         sortable = gtk_tree_model_sort_new_with_model (model);
1572         gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
1573                                               TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, 
1574                                               GTK_SORT_ASCENDING);
1575         gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
1576                                          TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1577                                          cmp_rows, NULL, NULL);
1578
1579         /* Create filter model */
1580         filter_model = gtk_tree_model_filter_new (sortable, NULL);
1581         gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
1582                                                 filter_row,
1583                                                 self,
1584                                                 NULL);
1585
1586         /* Set new model */
1587         gtk_tree_view_set_model (GTK_TREE_VIEW(self), filter_model);
1588         g_signal_connect (G_OBJECT(filter_model), "row-inserted",
1589                           (GCallback) on_row_inserted_maybe_select_folder, self);
1590
1591
1592         g_object_unref (model);
1593         g_object_unref (filter_model);          
1594         g_object_unref (sortable);
1595         
1596         /* Force a reselection of the INBOX next time the widget is shown */
1597         priv->reselect = TRUE;
1598                         
1599         return TRUE;
1600 }
1601
1602
1603 static void
1604 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
1605 {
1606         GtkTreeModel *model = NULL;
1607         TnyFolderStore *folder = NULL;
1608         GtkTreeIter iter;
1609         ModestFolderView *tree_view = NULL;
1610         ModestFolderViewPrivate *priv = NULL;
1611         gboolean selected = FALSE;
1612
1613         g_return_if_fail (sel);
1614         g_return_if_fail (user_data);
1615         
1616         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
1617
1618         selected = gtk_tree_selection_get_selected (sel, &model, &iter);
1619
1620         /* Notify the display name observers */
1621         g_signal_emit (G_OBJECT(user_data),
1622                        signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1623                        NULL);
1624
1625         tree_view = MODEST_FOLDER_VIEW (user_data);
1626
1627         if (selected) {
1628                 gtk_tree_model_get (model, &iter,
1629                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1630                                     -1);
1631
1632                 /* If the folder is the same do not notify */
1633                 if (folder && priv->cur_folder_store == folder) {
1634                         g_object_unref (folder);
1635                         return;
1636                 }
1637         }
1638         
1639         /* Current folder was unselected */
1640         if (priv->cur_folder_store) {
1641                 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1642                        priv->cur_folder_store, FALSE);
1643
1644                 if (TNY_IS_FOLDER(priv->cur_folder_store))
1645                         tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
1646                                                FALSE, NULL, NULL, NULL);
1647
1648                 /* FALSE --> don't expunge the messages */
1649
1650                 g_object_unref (priv->cur_folder_store);
1651                 priv->cur_folder_store = NULL;
1652         }
1653
1654         /* New current references */
1655         priv->cur_folder_store = folder;
1656
1657         /* New folder has been selected */
1658         g_signal_emit (G_OBJECT(tree_view),
1659                        signals[FOLDER_SELECTION_CHANGED_SIGNAL],
1660                        0, priv->cur_folder_store, TRUE);
1661 }
1662
1663 TnyFolderStore *
1664 modest_folder_view_get_selected (ModestFolderView *self)
1665 {
1666         ModestFolderViewPrivate *priv;
1667
1668         g_return_val_if_fail (self, NULL);
1669         
1670         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1671         if (priv->cur_folder_store)
1672                 g_object_ref (priv->cur_folder_store);
1673
1674         return priv->cur_folder_store;
1675 }
1676
1677 static gint
1678 get_cmp_rows_type_pos (GObject *folder)
1679 {
1680         /* Remote accounts -> Local account -> MMC account .*/
1681         /* 0, 1, 2 */
1682         
1683         if (TNY_IS_ACCOUNT (folder) && 
1684                 modest_tny_account_is_virtual_local_folders (
1685                         TNY_ACCOUNT (folder))) {
1686                 return 1;
1687         } else if (TNY_IS_ACCOUNT (folder)) {
1688                 TnyAccount *account = TNY_ACCOUNT (folder);
1689                 const gchar *account_id = tny_account_get_id (account);
1690                 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
1691                         return 2;
1692                 else
1693                         return 0;
1694         }
1695         else {
1696                 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
1697                 return -1; /* Should never happen */
1698         }
1699 }
1700
1701 static gint
1702 get_cmp_subfolder_type_pos (TnyFolderType t)
1703 {
1704         /* Inbox, Outbox, Drafts, Sent, User */
1705         /* 0, 1, 2, 3, 4 */
1706
1707         switch (t) {
1708         case TNY_FOLDER_TYPE_INBOX:
1709                 return 0;
1710                 break;
1711         case TNY_FOLDER_TYPE_OUTBOX:
1712                 return 1;
1713                 break;
1714         case TNY_FOLDER_TYPE_DRAFTS:
1715                 return 2;
1716                 break;
1717         case TNY_FOLDER_TYPE_SENT:
1718                 return 3;
1719                 break;
1720         default:
1721                 return 4;
1722         }
1723 }
1724
1725 /*
1726  * This function orders the mail accounts according to these rules:
1727  * 1st - remote accounts
1728  * 2nd - local account
1729  * 3rd - MMC account
1730  */
1731 static gint
1732 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
1733           gpointer user_data)
1734 {
1735         gint cmp = 0;
1736         gchar *name1 = NULL;
1737         gchar *name2 = NULL;
1738         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1739         TnyFolderType type2 = TNY_FOLDER_TYPE_UNKNOWN;
1740         GObject *folder1 = NULL;
1741         GObject *folder2 = NULL;
1742
1743         gtk_tree_model_get (tree_model, iter1,
1744                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
1745                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
1746                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
1747                             -1);
1748         gtk_tree_model_get (tree_model, iter2,
1749                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
1750                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type2,
1751                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
1752                             -1);
1753
1754         /* Return if we get no folder. This could happen when folder
1755            operations are happening. The model is updated after the
1756            folder copy/move actually occurs, so there could be
1757            situations where the model to be drawn is not correct */
1758         if (!folder1 || !folder2)
1759                 goto finish;
1760
1761         if (type == TNY_FOLDER_TYPE_ROOT) {
1762                 /* Compare the types, so that 
1763                  * Remote accounts -> Local account -> MMC account .*/
1764                 const gint pos1 = get_cmp_rows_type_pos (folder1);
1765                 const gint pos2 = get_cmp_rows_type_pos (folder2);
1766                 /* printf ("DEBUG: %s:\n  type1=%s, pos1=%d\n  type2=%s, pos2=%d\n", 
1767                         __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
1768                 if (pos1 <  pos2)
1769                         cmp = -1;
1770                 else if (pos1 > pos2)
1771                         cmp = 1;
1772                 else {
1773                         /* Compare items of the same type: */
1774                         
1775                         TnyAccount *account1 = NULL;
1776                         if (TNY_IS_ACCOUNT (folder1))
1777                                 account1 = TNY_ACCOUNT (folder1);
1778                                 
1779                         TnyAccount *account2 = NULL;
1780                         if (TNY_IS_ACCOUNT (folder2))
1781                                 account2 = TNY_ACCOUNT (folder2);
1782                                 
1783                         const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
1784                         const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
1785         
1786                         if (!account_id && !account_id2) {
1787                                 cmp = 0;
1788                         } else if (!account_id) {
1789                                 cmp = -1;
1790                         } else if (!account_id2) {
1791                                 cmp = +1;
1792                         } else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1793                                 cmp = +1;
1794                         } else {
1795                                 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1796                         }
1797                 }
1798         } else {
1799                 gint cmp1 = 0, cmp2 = 0;
1800                 /* get the parent to know if it's a local folder */
1801
1802                 GtkTreeIter parent;
1803                 gboolean has_parent;
1804                 has_parent = gtk_tree_model_iter_parent (tree_model, &parent, iter1);
1805                 if (has_parent) {
1806                         GObject *parent_folder;
1807                         TnyFolderType parent_type = TNY_FOLDER_TYPE_UNKNOWN;
1808                         gtk_tree_model_get (tree_model, &parent, 
1809                                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &parent_type,
1810                                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &parent_folder,
1811                                             -1);
1812                         if ((parent_type == TNY_FOLDER_TYPE_ROOT) &&
1813                             TNY_IS_ACCOUNT (parent_folder) &&
1814                             modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent_folder))) {
1815                                 cmp1 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type
1816                                                                    (TNY_FOLDER (folder1)));
1817                                 cmp2 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type
1818                                                                    (TNY_FOLDER (folder2)));
1819                         }
1820                         g_object_unref (parent_folder);
1821                 }
1822                 
1823                 /* if they are not local folders */
1824                 if (cmp1 == cmp2) {
1825                         cmp1 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder1)));
1826                         cmp2 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder2)));
1827                 }
1828
1829                 if (cmp1 == cmp2)
1830                         cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1831                 else 
1832                         cmp = (cmp1 - cmp2);
1833         }
1834
1835 finish: 
1836         if (folder1)
1837                 g_object_unref(G_OBJECT(folder1));
1838         if (folder2)
1839                 g_object_unref(G_OBJECT(folder2));
1840
1841         g_free (name1);
1842         g_free (name2);
1843
1844         return cmp;     
1845 }
1846
1847 /*****************************************************************************/
1848 /*                        DRAG and DROP stuff                                */
1849 /*****************************************************************************/
1850 /*
1851  * This function fills the #GtkSelectionData with the row and the
1852  * model that has been dragged. It's called when this widget is a
1853  * source for dnd after the event drop happened
1854  */
1855 static void
1856 on_drag_data_get (GtkWidget *widget, 
1857                   GdkDragContext *context, 
1858                   GtkSelectionData *selection_data, 
1859                   guint info, 
1860                   guint time, 
1861                   gpointer data)
1862 {
1863         GtkTreeSelection *selection;
1864         GtkTreeModel *model;
1865         GtkTreeIter iter;
1866         GtkTreePath *source_row;
1867
1868         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1869         if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1870
1871                 source_row = gtk_tree_model_get_path (model, &iter);
1872                 gtk_tree_set_row_drag_data (selection_data,
1873                                             model,
1874                                             source_row);
1875                 
1876                 gtk_tree_path_free (source_row);
1877         }
1878 }
1879
1880 typedef struct _DndHelper {
1881         gboolean delete_source;
1882         GtkTreePath *source_row;
1883         GdkDragContext *context;
1884         guint time;
1885 } DndHelper;
1886
1887
1888 /*
1889  * This function is the callback of the
1890  * modest_mail_operation_xfer_msgs () and
1891  * modest_mail_operation_xfer_folder() calls. We check here if the
1892  * message/folder was correctly asynchronously transferred. The reason
1893  * to use the same callback is that the code is the same, it only has
1894  * to check that the operation went fine and then finalize the drag
1895  * and drop action
1896  */
1897 static void
1898 xfer_cb (ModestMailOperation *mail_op, 
1899          gpointer user_data)
1900 {
1901         gboolean success;
1902         DndHelper *helper;
1903
1904         helper = (DndHelper *) user_data;
1905
1906         if (modest_mail_operation_get_status (mail_op) == 
1907             MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
1908                 success = TRUE;
1909         } else {
1910                 success = FALSE;
1911         }
1912
1913         /* Notify the drag source. Never call delete, the monitor will
1914            do the job if needed */
1915         gtk_drag_finish (helper->context, success, FALSE, helper->time);
1916
1917         /* Free the helper */
1918         gtk_tree_path_free (helper->source_row);
1919         g_slice_free (DndHelper, helper);
1920 }
1921
1922 /* get the folder for the row the treepath refers to. */
1923 /* folder must be unref'd */
1924 static TnyFolderStore *
1925 tree_path_to_folder (GtkTreeModel *model, GtkTreePath *path)
1926 {
1927         GtkTreeIter iter;
1928         TnyFolderStore *folder = NULL;
1929         
1930         if (gtk_tree_model_get_iter (model,&iter, path))
1931                 gtk_tree_model_get (model, &iter,
1932                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1933                                     -1);
1934         return folder;
1935 }
1936
1937 /*
1938  * This function is used by drag_data_received_cb to manage drag and
1939  * drop of a header, i.e, and drag from the header view to the folder
1940  * view.
1941  */
1942 static void
1943 drag_and_drop_from_header_view (GtkTreeModel *source_model,
1944                                 GtkTreeModel *dest_model,
1945                                 GtkTreePath  *dest_row,
1946                                 GtkSelectionData *selection_data,
1947                                 DndHelper    *helper)
1948 {
1949         TnyList *headers = NULL;
1950         TnyFolder *folder = NULL;
1951         TnyFolderType folder_type;
1952         ModestMailOperation *mail_op = NULL;
1953         GtkTreeIter source_iter, dest_iter;
1954         ModestWindowMgr *mgr = NULL;
1955         ModestWindow *main_win = NULL;
1956         gchar **uris, **tmp;
1957         gint response;
1958
1959         /* Build the list of headers */
1960         mgr = modest_runtime_get_window_mgr ();
1961         headers = tny_simple_list_new ();
1962         uris = modest_dnd_selection_data_get_paths (selection_data);
1963         tmp = uris;
1964
1965         while (*tmp != NULL) {
1966                 TnyHeader *header;
1967                 GtkTreePath *path;
1968
1969                 /* Get header */
1970                 path = gtk_tree_path_new_from_string (*tmp);
1971                 gtk_tree_model_get_iter (source_model, &source_iter, path);
1972                 gtk_tree_model_get (source_model, &source_iter, 
1973                                     TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, 
1974                                     &header, -1);
1975
1976                 /* Do not enable d&d of headers already opened */
1977                 if (!modest_window_mgr_find_registered_header(mgr, header, NULL))
1978                         tny_list_append (headers, G_OBJECT (header));
1979
1980                 /* Free and go on */
1981                 gtk_tree_path_free (path);
1982                 g_object_unref (header);
1983                 tmp++;
1984         }
1985         g_strfreev (uris);
1986
1987         /* Get the target folder */
1988         gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
1989         gtk_tree_model_get (dest_model, &dest_iter, 
1990                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1991                             &folder, -1);
1992         
1993         if (!folder || !TNY_IS_FOLDER(folder)) {
1994 /*              g_warning ("%s: not a valid target folder (%p)", __FUNCTION__, folder); */
1995                 goto cleanup;
1996         }
1997         
1998         folder_type = modest_tny_folder_guess_folder_type (folder);
1999         if (folder_type == TNY_FOLDER_TYPE_INVALID) {
2000 /*              g_warning ("%s: invalid target folder", __FUNCTION__); */
2001                 goto cleanup;  /* cannot move messages there */
2002         }
2003         
2004         if (modest_tny_folder_get_rules((TNY_FOLDER(folder))) & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2005 /*              g_warning ("folder not writable"); */
2006                 goto cleanup; /* verboten! */
2007         }
2008         
2009         /* Ask for confirmation to move */
2010         main_win = modest_window_mgr_get_main_window (mgr, FALSE); /* don't create */
2011         if (!main_win) {
2012                 g_warning ("%s: BUG: no main window found", __FUNCTION__);
2013                 goto cleanup;
2014         }
2015
2016         response = modest_ui_actions_msgs_move_to_confirmation (main_win, folder, 
2017                                                                 TRUE, headers);
2018         if (response == GTK_RESPONSE_CANCEL)
2019                 goto cleanup;
2020
2021         /* Transfer messages */
2022         mail_op = modest_mail_operation_new_with_error_handling ((GObject *) main_win,
2023                                                                  modest_ui_actions_move_folder_error_handler,
2024                                                                  NULL, NULL);
2025
2026         modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
2027                                          mail_op);
2028
2029         modest_mail_operation_xfer_msgs (mail_op,
2030                                          headers, 
2031                                          folder, 
2032                                          helper->delete_source, 
2033                                          xfer_cb, helper);
2034         
2035         /* Frees */
2036 cleanup:
2037         if (G_IS_OBJECT(mail_op))
2038                 g_object_unref (G_OBJECT (mail_op));
2039         if (G_IS_OBJECT(folder))
2040                 g_object_unref (G_OBJECT (folder));
2041         if (G_IS_OBJECT(headers))
2042                 g_object_unref (headers);
2043 }
2044
2045 /*
2046  * This function is used by drag_data_received_cb to manage drag and
2047  * drop of a folder, i.e, and drag from the folder view to the same
2048  * folder view.
2049  */
2050 static void
2051 drag_and_drop_from_folder_view (GtkTreeModel     *source_model,
2052                                 GtkTreeModel     *dest_model,
2053                                 GtkTreePath      *dest_row,
2054                                 GtkSelectionData *selection_data,
2055                                 DndHelper        *helper)
2056 {
2057         ModestMailOperation *mail_op = NULL;
2058         GtkTreeIter dest_iter, iter;
2059         TnyFolderStore *dest_folder = NULL;
2060         TnyFolderStore *folder = NULL;
2061         gboolean forbidden = FALSE;
2062         ModestWindow *win;
2063
2064         win = modest_window_mgr_get_main_window (modest_runtime_get_window_mgr(), FALSE); /* don't create */
2065         if (!win) {
2066                 g_warning ("%s: BUG: no main window", __FUNCTION__);
2067                 return;
2068         }
2069         
2070         if (!forbidden) {
2071                 /* check the folder rules for the destination */
2072                 folder = tree_path_to_folder (dest_model, dest_row);
2073                 if (TNY_IS_FOLDER(folder)) {
2074                         ModestTnyFolderRules rules =
2075                                 modest_tny_folder_get_rules (TNY_FOLDER (folder));
2076                         forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE;
2077                 } else if (TNY_IS_FOLDER_STORE(folder)) {
2078                         /* enable local root as destination for folders */
2079                         if (!MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (folder)
2080                                         && TNY_IS_ACCOUNT (folder))
2081                                 forbidden = TRUE;
2082                 }
2083                 g_object_unref (folder);
2084         }
2085         if (!forbidden) {
2086                 /* check the folder rules for the source */
2087                 folder = tree_path_to_folder (source_model, helper->source_row);
2088                 if (TNY_IS_FOLDER(folder)) {
2089                         ModestTnyFolderRules rules =
2090                                 modest_tny_folder_get_rules (TNY_FOLDER (folder));
2091                         forbidden = rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE;
2092                 } else
2093                         forbidden = TRUE;
2094                 g_object_unref (folder);
2095         }
2096
2097         
2098         /* Check if the drag is possible */
2099         if (forbidden || !gtk_tree_path_compare (helper->source_row, dest_row)) {
2100                 gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
2101                 gtk_tree_path_free (helper->source_row);        
2102                 g_slice_free (DndHelper, helper);
2103                 return;
2104         }
2105
2106         /* Get data */
2107         gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
2108         gtk_tree_model_get (dest_model, &dest_iter, 
2109                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, 
2110                             &dest_folder, -1);
2111         gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
2112         gtk_tree_model_get (source_model, &iter,
2113                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
2114                             &folder, -1);
2115
2116         /* Offer the connection dialog if necessary, for the destination parent folder and source folder: */
2117         if (modest_platform_connect_and_wait_if_network_folderstore (NULL, dest_folder) && 
2118             modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
2119         
2120                 /* Do the mail operation */
2121                 mail_op = modest_mail_operation_new_with_error_handling ((GObject *) win,
2122                                                                          modest_ui_actions_move_folder_error_handler,
2123                                                                          folder, NULL);
2124
2125                 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (), 
2126                                                  mail_op);
2127
2128                 modest_mail_operation_xfer_folder (mail_op, 
2129                                                    TNY_FOLDER (folder), 
2130                                                    dest_folder,
2131                                                    helper->delete_source,
2132                                                    xfer_cb,
2133                                                    helper);
2134
2135                 g_object_unref (G_OBJECT (mail_op));
2136         }
2137         
2138         /* Frees */
2139         g_object_unref (G_OBJECT (dest_folder));
2140         g_object_unref (G_OBJECT (folder));
2141 }
2142
2143 /*
2144  * This function receives the data set by the "drag-data-get" signal
2145  * handler. This information comes within the #GtkSelectionData. This
2146  * function will manage both the drags of folders of the treeview and
2147  * drags of headers of the header view widget.
2148  */
2149 static void 
2150 on_drag_data_received (GtkWidget *widget, 
2151                        GdkDragContext *context, 
2152                        gint x, 
2153                        gint y, 
2154                        GtkSelectionData *selection_data, 
2155                        guint target_type, 
2156                        guint time, 
2157                        gpointer data)
2158 {
2159         GtkWidget *source_widget;
2160         GtkTreeModel *dest_model, *source_model;
2161         GtkTreePath *source_row, *dest_row;
2162         GtkTreeViewDropPosition pos;
2163         gboolean success = FALSE, delete_source = FALSE;
2164         DndHelper *helper = NULL; 
2165
2166         /* Do not allow further process */
2167         g_signal_stop_emission_by_name (widget, "drag-data-received");
2168         source_widget = gtk_drag_get_source_widget (context);
2169
2170         /* Get the action */
2171         if (context->action == GDK_ACTION_MOVE) {
2172                 delete_source = TRUE;
2173
2174                 /* Notify that there is no folder selected. We need to
2175                    do this in order to update the headers view (and
2176                    its monitors, because when moving, the old folder
2177                    won't longer exist. We can not wait for the end of
2178                    the operation, because the operation won't start if
2179                    the folder is in use */
2180                 if (source_widget == widget) {
2181                         GtkTreeSelection *sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
2182                         gtk_tree_selection_unselect_all (sel);
2183                 }
2184         }
2185
2186         /* Check if the get_data failed */
2187         if (selection_data == NULL || selection_data->length < 0)
2188                 gtk_drag_finish (context, success, FALSE, time);
2189
2190         /* Select the destination model */
2191         dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));  
2192
2193         /* Get the path to the destination row. Can not call
2194            gtk_tree_view_get_drag_dest_row() because the source row
2195            is not selected anymore */
2196         gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
2197                                            &dest_row, &pos);
2198
2199         /* Only allow drops IN other rows */
2200         if (!dest_row || 
2201             pos == GTK_TREE_VIEW_DROP_BEFORE || 
2202             pos == GTK_TREE_VIEW_DROP_AFTER)
2203                 gtk_drag_finish (context, success, FALSE, time);
2204
2205         /* Create the helper */
2206         helper = g_slice_new0 (DndHelper);
2207         helper->delete_source = delete_source;
2208         helper->context = context;
2209         helper->time = time;
2210
2211         /* Drags from the header view */
2212         if (source_widget != widget) {
2213                 source_model = gtk_tree_view_get_model (GTK_TREE_VIEW (source_widget));
2214
2215                 drag_and_drop_from_header_view (source_model,
2216                                                 dest_model,
2217                                                 dest_row,
2218                                                 selection_data,
2219                                                 helper);
2220         } else {
2221                 /* Get the source model and row */
2222                 gtk_tree_get_row_drag_data (selection_data,
2223                                             &source_model,
2224                                             &source_row);
2225                 helper->source_row = gtk_tree_path_copy (source_row);
2226
2227                 drag_and_drop_from_folder_view (source_model,
2228                                                 dest_model,
2229                                                 dest_row,
2230                                                 selection_data, 
2231                                                 helper);
2232
2233                 gtk_tree_path_free (source_row);
2234         }
2235
2236         /* Frees */
2237         gtk_tree_path_free (dest_row);
2238 }
2239
2240 /*
2241  * We define a "drag-drop" signal handler because we do not want to
2242  * use the default one, because the default one always calls
2243  * gtk_drag_finish and we prefer to do it in the "drag-data-received"
2244  * signal handler, because there we have all the information available
2245  * to know if the dnd was a success or not.
2246  */
2247 static gboolean
2248 drag_drop_cb (GtkWidget      *widget,
2249               GdkDragContext *context,
2250               gint            x,
2251               gint            y,
2252               guint           time,
2253               gpointer        user_data) 
2254 {
2255         gpointer target;
2256
2257         if (!context->targets)
2258                 return FALSE;
2259
2260         /* Check if we're dragging a folder row */
2261         target = gtk_drag_dest_find_target (widget, context, NULL);
2262
2263         /* Request the data from the source. */
2264         gtk_drag_get_data(widget, context, target, time);
2265
2266     return TRUE;
2267 }
2268
2269 /*
2270  * This function expands a node of a tree view if it's not expanded
2271  * yet. Not sure why it needs the threads stuff, but gtk+`example code
2272  * does that, so that's why they're here.
2273  */
2274 static gint
2275 expand_row_timeout (gpointer data)
2276 {
2277         GtkTreeView *tree_view = data;
2278         GtkTreePath *dest_path = NULL;
2279         GtkTreeViewDropPosition pos;
2280         gboolean result = FALSE;
2281         
2282         GDK_THREADS_ENTER ();
2283         
2284         gtk_tree_view_get_drag_dest_row (tree_view,
2285                                          &dest_path,
2286                                          &pos);
2287         
2288         if (dest_path &&
2289             (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
2290              pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
2291                 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
2292                 gtk_tree_path_free (dest_path);
2293         }
2294         else {
2295                 if (dest_path)
2296                         gtk_tree_path_free (dest_path);
2297                 
2298                 result = TRUE;
2299         }
2300         
2301         GDK_THREADS_LEAVE ();
2302
2303         return result;
2304 }
2305
2306 /*
2307  * This function is called whenever the pointer is moved over a widget
2308  * while dragging some data. It installs a timeout that will expand a
2309  * node of the treeview if not expanded yet. This function also calls
2310  * gdk_drag_status in order to set the suggested action that will be
2311  * used by the "drag-data-received" signal handler to know if we
2312  * should do a move or just a copy of the data.
2313  */
2314 static gboolean
2315 on_drag_motion (GtkWidget      *widget,
2316                 GdkDragContext *context,
2317                 gint            x,
2318                 gint            y,
2319                 guint           time,
2320                 gpointer        user_data)  
2321 {
2322         GtkTreeViewDropPosition pos;
2323         GtkTreePath *dest_row;
2324         GtkTreeModel *dest_model;
2325         ModestFolderViewPrivate *priv;
2326         GdkDragAction suggested_action;
2327         gboolean valid_location = FALSE;
2328         TnyFolderStore *folder;
2329
2330         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
2331
2332         if (priv->timer_expander != 0) {
2333                 g_source_remove (priv->timer_expander);
2334                 priv->timer_expander = 0;
2335         }
2336
2337         gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
2338                                            x, y,
2339                                            &dest_row,
2340                                            &pos);
2341
2342         /* Do not allow drops between folders */
2343         if (!dest_row ||
2344             pos == GTK_TREE_VIEW_DROP_BEFORE ||
2345             pos == GTK_TREE_VIEW_DROP_AFTER) {
2346                 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
2347                 gdk_drag_status(context, 0, time);
2348                 valid_location = FALSE;
2349                 goto out;
2350         } else {
2351                 valid_location = TRUE;
2352         }
2353
2354         /* Check that the destination folder is writable */
2355         dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
2356         folder = tree_path_to_folder (dest_model, dest_row);
2357         if (folder && TNY_IS_FOLDER (folder)) {
2358                 ModestTnyFolderRules rules = modest_tny_folder_get_rules(TNY_FOLDER (folder));
2359
2360                 if (rules & MODEST_FOLDER_RULES_FOLDER_NON_WRITEABLE) {
2361                         valid_location = FALSE;
2362                         goto out;
2363                 }
2364         }
2365         g_object_unref (folder);
2366
2367         /* Expand the selected row after 1/2 second */
2368         if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
2369                 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
2370                 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
2371         }
2372
2373         /* Select the desired action. By default we pick MOVE */
2374         suggested_action = GDK_ACTION_MOVE;
2375
2376         if (context->actions == GDK_ACTION_COPY)
2377             gdk_drag_status(context, GDK_ACTION_COPY, time);
2378         else if (context->actions == GDK_ACTION_MOVE)
2379             gdk_drag_status(context, GDK_ACTION_MOVE, time);
2380         else if (context->actions & suggested_action)
2381             gdk_drag_status(context, suggested_action, time);
2382         else
2383             gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
2384
2385  out:
2386         if (dest_row)
2387                 gtk_tree_path_free (dest_row);
2388         g_signal_stop_emission_by_name (widget, "drag-motion");
2389
2390         return valid_location;
2391 }
2392
2393 /*
2394  * This function sets the treeview as a source and a target for dnd
2395  * events. It also connects all the requirede signals.
2396  */
2397 static void
2398 setup_drag_and_drop (GtkTreeView *self)
2399 {
2400         /* Set up the folder view as a dnd destination. Set only the
2401            highlight flag, otherwise gtk will have a different
2402            behaviour */
2403         gtk_drag_dest_set (GTK_WIDGET (self),
2404                            GTK_DEST_DEFAULT_HIGHLIGHT,
2405                            folder_view_drag_types,
2406                            G_N_ELEMENTS (folder_view_drag_types),
2407                            GDK_ACTION_MOVE | GDK_ACTION_COPY);
2408
2409         g_signal_connect (G_OBJECT (self),
2410                           "drag_data_received",
2411                           G_CALLBACK (on_drag_data_received),
2412                           NULL);
2413
2414
2415         /* Set up the treeview as a dnd source */
2416         gtk_drag_source_set (GTK_WIDGET (self),
2417                              GDK_BUTTON1_MASK,
2418                              folder_view_drag_types,
2419                              G_N_ELEMENTS (folder_view_drag_types),
2420                              GDK_ACTION_MOVE | GDK_ACTION_COPY);
2421
2422         g_signal_connect (G_OBJECT (self),
2423                           "drag_motion",
2424                           G_CALLBACK (on_drag_motion),
2425                           NULL);
2426         
2427         g_signal_connect (G_OBJECT (self),
2428                           "drag_data_get",
2429                           G_CALLBACK (on_drag_data_get),
2430                           NULL);
2431
2432         g_signal_connect (G_OBJECT (self),
2433                           "drag_drop",
2434                           G_CALLBACK (drag_drop_cb),
2435                           NULL);
2436 }
2437
2438 /*
2439  * This function manages the navigation through the folders using the
2440  * keyboard or the hardware keys in the device
2441  */
2442 static gboolean
2443 on_key_pressed (GtkWidget *self,
2444                 GdkEventKey *event,
2445                 gpointer user_data)
2446 {
2447         GtkTreeSelection *selection;
2448         GtkTreeIter iter;
2449         GtkTreeModel *model;
2450         gboolean retval = FALSE;
2451
2452         /* Up and Down are automatically managed by the treeview */
2453         if (event->keyval == GDK_Return) {
2454                 /* Expand/Collapse the selected row */
2455                 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2456                 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
2457                         GtkTreePath *path;
2458
2459                         path = gtk_tree_model_get_path (model, &iter);
2460
2461                         if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
2462                                 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
2463                         else
2464                                 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
2465                         gtk_tree_path_free (path);
2466                 }
2467                 /* No further processing */
2468                 retval = TRUE;
2469         }
2470
2471         return retval;
2472 }
2473
2474 /*
2475  * We listen to the changes in the local folder account name key,
2476  * because we want to show the right name in the view. The local
2477  * folder account name corresponds to the device name in the Maemo
2478  * version. We do this because we do not want to query gconf on each
2479  * tree view refresh. It's better to cache it and change whenever
2480  * necessary.
2481  */
2482 static void 
2483 on_configuration_key_changed (ModestConf* conf, 
2484                               const gchar *key, 
2485                               ModestConfEvent event,
2486                               ModestConfNotificationId id, 
2487                               ModestFolderView *self)
2488 {
2489         ModestFolderViewPrivate *priv;
2490
2491
2492         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
2493         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2494
2495         if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
2496                 g_free (priv->local_account_name);
2497
2498                 if (event == MODEST_CONF_EVENT_KEY_UNSET)
2499                         priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
2500                 else
2501                         priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
2502                                                                            MODEST_CONF_DEVICE_NAME, NULL);
2503
2504                 /* Force a redraw */
2505 #if GTK_CHECK_VERSION(2, 8, 0)
2506                 GtkTreeViewColumn * tree_column;
2507
2508                 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self), 
2509                                                         TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
2510                 gtk_tree_view_column_queue_resize (tree_column);
2511 #else
2512                 gtk_widget_queue_draw (GTK_WIDGET (self));
2513 #endif
2514         }
2515 }
2516
2517 void
2518 modest_folder_view_set_style (ModestFolderView *self,
2519                               ModestFolderViewStyle style)
2520 {
2521         ModestFolderViewPrivate *priv;
2522
2523         g_return_if_fail (self);
2524         
2525         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2526
2527         priv->style = style;
2528 }
2529
2530 void
2531 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
2532                                                              const gchar *account_id)
2533 {
2534         ModestFolderViewPrivate *priv;
2535         GtkTreeModel *model;
2536
2537         g_return_if_fail (self);
2538         
2539         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2540
2541         /* This will be used by the filter_row callback,
2542          * to decided which rows to show: */
2543         if (priv->visible_account_id) {
2544                 g_free (priv->visible_account_id);
2545                 priv->visible_account_id = NULL;
2546         }
2547         if (account_id)
2548                 priv->visible_account_id = g_strdup (account_id);
2549
2550         /* Refilter */
2551         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2552         if (GTK_IS_TREE_MODEL_FILTER (model))
2553                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2554
2555         /* Save settings to gconf */
2556         modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
2557                                    MODEST_CONF_FOLDER_VIEW_KEY);
2558 }
2559
2560 const gchar *
2561 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
2562 {
2563         ModestFolderViewPrivate *priv;
2564
2565         g_return_val_if_fail (self, NULL);
2566         
2567         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2568
2569         return (const gchar *) priv->visible_account_id;
2570 }
2571
2572 static gboolean
2573 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
2574 {
2575         do {
2576                 GtkTreeIter child;
2577                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2578
2579                 gtk_tree_model_get (model, iter, 
2580                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, 
2581                                     &type, -1);
2582                         
2583                 gboolean result = FALSE;
2584                 if (type == TNY_FOLDER_TYPE_INBOX) {
2585                         result = TRUE;
2586                 }               
2587                 if (result) {
2588                         *inbox_iter = *iter;
2589                         return TRUE;
2590                 }
2591
2592                 if (gtk_tree_model_iter_children (model, &child, iter)) {
2593                         if (find_inbox_iter (model, &child, inbox_iter))
2594                                 return TRUE;
2595                 }
2596
2597         } while (gtk_tree_model_iter_next (model, iter));
2598
2599         return FALSE;
2600 }
2601
2602
2603
2604
2605 void 
2606 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
2607 {
2608         GtkTreeModel *model;
2609         GtkTreeIter iter, inbox_iter;
2610         GtkTreeSelection *sel;
2611         GtkTreePath *path = NULL;
2612
2613         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2614         if (!model)
2615                 return;
2616
2617         expand_root_items (self);
2618         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2619
2620         if (!gtk_tree_model_get_iter_first (model, &iter)) {
2621                 g_warning ("%s: model is empty", __FUNCTION__);
2622                 return;
2623         }
2624
2625         if (find_inbox_iter (model, &iter, &inbox_iter))
2626                 path = gtk_tree_model_get_path (model, &inbox_iter);
2627         else
2628                 path = gtk_tree_path_new_first ();
2629
2630         /* Select the row and free */
2631         gtk_tree_view_set_cursor (GTK_TREE_VIEW (self), path, NULL, FALSE);
2632         gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self), path, NULL, FALSE, 0.0, 0.0);
2633         gtk_tree_path_free (path);
2634
2635         /* set focus */
2636         gtk_widget_grab_focus (GTK_WIDGET(self));
2637 }
2638
2639
2640 /* recursive */
2641 static gboolean
2642 find_folder_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *folder_iter, 
2643                   TnyFolder* folder)
2644 {
2645         do {
2646                 GtkTreeIter child;
2647                 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2648                 TnyFolder* a_folder;
2649                 gchar *name = NULL;
2650                 
2651                 gtk_tree_model_get (model, iter, 
2652                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &a_folder,
2653                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2654                                     TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type, 
2655                                     -1);                
2656                 g_free (name);
2657
2658                 if (folder == a_folder) {
2659                         g_object_unref (a_folder);
2660                         *folder_iter = *iter;
2661                         return TRUE;
2662                 }
2663                 g_object_unref (a_folder);
2664                 
2665                 if (gtk_tree_model_iter_children (model, &child, iter)) {
2666                         if (find_folder_iter (model, &child, folder_iter, folder)) 
2667                                 return TRUE;
2668                 }
2669
2670         } while (gtk_tree_model_iter_next (model, iter));
2671
2672         return FALSE;
2673 }
2674
2675
2676 static void
2677 on_row_inserted_maybe_select_folder (GtkTreeModel *tree_model, GtkTreePath  *path, GtkTreeIter *iter,
2678                                      ModestFolderView *self)
2679 {
2680         ModestFolderViewPrivate *priv = NULL;
2681         GtkTreeSelection *sel;
2682         TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2683         GObject *instance = NULL;
2684
2685         if (!MODEST_IS_FOLDER_VIEW(self))
2686                 return;
2687         
2688         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2689
2690         priv->reexpand = TRUE;
2691
2692         gtk_tree_model_get (tree_model, iter, 
2693                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
2694                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
2695                             -1);
2696         if (type == TNY_FOLDER_TYPE_INBOX && priv->folder_to_select == NULL) {
2697                 priv->folder_to_select = g_object_ref (instance);
2698         }
2699         g_object_unref (instance);
2700
2701         
2702         if (priv->folder_to_select) {
2703                 
2704                 if (!modest_folder_view_select_folder (self, priv->folder_to_select,
2705                                                        FALSE)) {
2706                         GtkTreePath *path;
2707                         path = gtk_tree_model_get_path (tree_model, iter);
2708                         gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2709                         
2710                         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2711
2712                         gtk_tree_selection_select_iter (sel, iter);
2713                         gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2714
2715                         gtk_tree_path_free (path);
2716                 
2717                 }
2718
2719                 /* Disable next */
2720                 modest_folder_view_disable_next_folder_selection (self);
2721 /*              g_object_unref (priv->folder_to_select); */
2722 /*              priv->folder_to_select = NULL; */
2723         }
2724 }
2725
2726
2727 void
2728 modest_folder_view_disable_next_folder_selection (ModestFolderView *self) 
2729 {
2730         ModestFolderViewPrivate *priv = NULL;
2731
2732         g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));        
2733         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2734
2735         if (priv->folder_to_select)
2736                 g_object_unref(priv->folder_to_select);
2737         
2738         priv->folder_to_select = NULL;
2739 }
2740
2741 gboolean
2742 modest_folder_view_select_folder (ModestFolderView *self, TnyFolder *folder, 
2743                                   gboolean after_change)
2744 {
2745         GtkTreeModel *model;
2746         GtkTreeIter iter, folder_iter;
2747         GtkTreeSelection *sel;
2748         ModestFolderViewPrivate *priv = NULL;
2749         
2750         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);     
2751         g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE);   
2752                 
2753         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2754
2755         if (after_change) {
2756
2757                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2758                 gtk_tree_selection_unselect_all (sel);
2759
2760                 if (priv->folder_to_select)
2761                         g_object_unref(priv->folder_to_select);
2762                 priv->folder_to_select = TNY_FOLDER(g_object_ref(folder));
2763                 return TRUE;
2764         }
2765                 
2766         model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2767         if (!model)
2768                 return FALSE;
2769
2770         if (!gtk_tree_model_get_iter_first (model, &iter)) {
2771                 g_warning ("%s: model is empty", __FUNCTION__);
2772                 return FALSE;
2773         }
2774         
2775         if (find_folder_iter (model, &iter, &folder_iter, folder)) {
2776                 GtkTreePath *path;
2777
2778                 path = gtk_tree_model_get_path (model, &folder_iter);
2779                 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2780
2781                 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2782                 gtk_tree_selection_select_iter (sel, &folder_iter);
2783                 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2784
2785                 gtk_tree_path_free (path);
2786                 return TRUE;
2787         }
2788         return FALSE;
2789 }
2790
2791
2792 void 
2793 modest_folder_view_copy_selection (ModestFolderView *folder_view)
2794 {
2795         /* Copy selection */
2796         _clipboard_set_selected_data (folder_view, FALSE);
2797 }
2798
2799 void 
2800 modest_folder_view_cut_selection (ModestFolderView *folder_view)
2801 {
2802         ModestFolderViewPrivate *priv = NULL;
2803         GtkTreeModel *model = NULL;
2804         const gchar **hidding = NULL;
2805         guint i, n_selected;
2806
2807         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2808         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2809
2810         /* Copy selection */
2811         if (!_clipboard_set_selected_data (folder_view, TRUE))
2812                 return;
2813
2814         /* Get hidding ids */
2815         hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected); 
2816         
2817         /* Clear hidding array created by previous cut operation */
2818         _clear_hidding_filter (MODEST_FOLDER_VIEW (folder_view));
2819
2820         /* Copy hidding array */
2821         priv->n_selected = n_selected;
2822         priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected);
2823         for (i=0; i < n_selected; i++) 
2824                 priv->hidding_ids[i] = g_strdup(hidding[i]);            
2825
2826         /* Hide cut folders */
2827         model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
2828         gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2829 }
2830
2831 void
2832 modest_folder_view_copy_model (ModestFolderView *folder_view_src,
2833                                ModestFolderView *folder_view_dst)
2834 {
2835         GtkTreeModel *filter_model = NULL;
2836         GtkTreeModel *model = NULL;
2837         GtkTreeModel *new_filter_model = NULL;
2838         
2839         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view_src));
2840         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view_dst));
2841
2842         /* Get src model*/
2843         filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view_src));
2844         model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(filter_model));
2845
2846         /* Build new filter model */
2847         new_filter_model = gtk_tree_model_filter_new (model, NULL);     
2848         gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (new_filter_model),
2849                                                 filter_row,
2850                                                 folder_view_dst,
2851                                                 NULL);
2852         /* Set copied model */
2853         gtk_tree_view_set_model (GTK_TREE_VIEW (folder_view_dst), new_filter_model);
2854         g_signal_connect (G_OBJECT(new_filter_model), "row-inserted",
2855                           (GCallback) on_row_inserted_maybe_select_folder, folder_view_dst);
2856
2857         /* Free */
2858         g_object_unref (new_filter_model);
2859 }
2860
2861 void
2862 modest_folder_view_show_non_move_folders (ModestFolderView *folder_view,
2863                                           gboolean show)
2864 {
2865         GtkTreeModel *model = NULL;
2866         ModestFolderViewPrivate* priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2867         priv->show_non_move = show;
2868 /*      modest_folder_view_update_model(folder_view, */
2869 /*                                      TNY_ACCOUNT_STORE(modest_runtime_get_account_store())); */
2870
2871         /* Hide special folders */
2872         model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
2873         if (GTK_IS_TREE_MODEL_FILTER (model)) {
2874                 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2875         }
2876 }
2877
2878 /* Returns FALSE if it did not selected anything */
2879 static gboolean
2880 _clipboard_set_selected_data (ModestFolderView *folder_view,
2881                               gboolean delete)
2882 {
2883         ModestFolderViewPrivate *priv = NULL;
2884         TnyFolderStore *folder = NULL;
2885         gboolean retval = FALSE;
2886
2887         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (folder_view), FALSE);
2888         priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2889                 
2890         /* Set selected data on clipboard   */
2891         g_return_val_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard), FALSE);
2892         folder = modest_folder_view_get_selected (folder_view);
2893
2894         /* Do not allow to select an account */
2895         if (TNY_IS_FOLDER (folder)) {
2896                 modest_email_clipboard_set_data (priv->clipboard, TNY_FOLDER(folder), NULL, delete);
2897                 retval = TRUE;
2898         }
2899
2900         /* Free */
2901         g_object_unref (folder);
2902
2903         return retval;
2904 }
2905
2906 static void
2907 _clear_hidding_filter (ModestFolderView *folder_view) 
2908 {
2909         ModestFolderViewPrivate *priv;
2910         guint i;
2911         
2912         g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view)); 
2913         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2914
2915         if (priv->hidding_ids != NULL) {
2916                 for (i=0; i < priv->n_selected; i++) 
2917                         g_free (priv->hidding_ids[i]);
2918                 g_free(priv->hidding_ids);
2919         }       
2920 }
2921
2922
2923 static void 
2924 on_display_name_changed (ModestAccountMgr *mgr, 
2925                          const gchar *account,
2926                          gpointer user_data)
2927 {
2928         ModestFolderView *self;
2929
2930         self = MODEST_FOLDER_VIEW (user_data);
2931
2932         /* Force a redraw */
2933 #if GTK_CHECK_VERSION(2, 8, 0)
2934         GtkTreeViewColumn * tree_column;
2935         
2936         tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self), 
2937                                                 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
2938         gtk_tree_view_column_queue_resize (tree_column);
2939 #else
2940         gtk_widget_queue_draw (GTK_WIDGET (self));
2941 #endif
2942 }