* Some initializations
[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
33 #include <tny-gtk-account-list-model.h>
34 #include <tny-gtk-folder-store-tree-model.h>
35 #include <tny-gtk-header-list-model.h>
36 #include <tny-account-store.h>
37 #include <tny-account.h>
38 #include <tny-folder.h>
39 #include <modest-tny-folder.h>
40 #include <modest-marshal.h>
41 #include <modest-icon-names.h>
42 #include <modest-icon-factory.h>
43 #include <modest-tny-account-store.h>
44 #include <modest-text-utils.h>
45
46 #include "modest-folder-view.h"
47
48 /* 'private'/'protected' functions */
49 static void modest_folder_view_class_init  (ModestFolderViewClass *klass);
50 static void modest_folder_view_init        (ModestFolderView *obj);
51 static void modest_folder_view_finalize    (GObject *obj);
52
53 static gboolean     update_model             (ModestFolderView *self,
54                                               ModestTnyAccountStore *account_store);
55 static gboolean     update_model_empty       (ModestFolderView *self);
56
57 static void         on_selection_changed     (GtkTreeSelection *sel, gpointer data);
58 static void         on_subscription_changed  (TnyStoreAccount *store_account, TnyFolder *folder,
59                                               ModestFolderView *self);
60
61 static gboolean     modest_folder_view_update_model     (ModestFolderView *self,
62                                                          TnyAccountStore *account_store);
63
64 static void         modest_folder_view_disconnect_store_account_handlers (GtkTreeView *self);
65
66 static gint         cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
67                               gpointer user_data);
68
69
70 enum {
71         FOLDER_SELECTION_CHANGED_SIGNAL,
72         LAST_SIGNAL
73 };
74
75 typedef struct _ModestFolderViewPrivate ModestFolderViewPrivate;
76 struct _ModestFolderViewPrivate {
77
78         TnyAccountStore     *account_store;
79         TnyFolder           *cur_folder;
80
81         gulong               sig1, sig2;
82         gulong              *store_accounts_handlers;
83         GMutex              *lock;
84         GtkTreeSelection    *cur_selection;
85         TnyFolderStoreQuery *query;
86
87 };
88 #define MODEST_FOLDER_VIEW_GET_PRIVATE(o)                               \
89         (G_TYPE_INSTANCE_GET_PRIVATE((o),                               \
90                                      MODEST_TYPE_FOLDER_VIEW,           \
91                                      ModestFolderViewPrivate))
92 /* globals */
93 static GObjectClass *parent_class = NULL;
94
95 static guint signals[LAST_SIGNAL] = {0}; 
96
97 GType
98 modest_folder_view_get_type (void)
99 {
100         static GType my_type = 0;
101         if (!my_type) {
102                 static const GTypeInfo my_info = {
103                         sizeof(ModestFolderViewClass),
104                         NULL,           /* base init */
105                         NULL,           /* base finalize */
106                         (GClassInitFunc) modest_folder_view_class_init,
107                         NULL,           /* class finalize */
108                         NULL,           /* class data */
109                         sizeof(ModestFolderView),
110                         1,              /* n_preallocs */
111                         (GInstanceInitFunc) modest_folder_view_init,
112                         NULL
113                 };
114                                 
115                 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
116                                                   "ModestFolderView",
117                                                   &my_info, 0);         
118         }
119         return my_type;
120 }
121
122 static void
123 modest_folder_view_class_init (ModestFolderViewClass *klass)
124 {
125         GObjectClass *gobject_class;
126         gobject_class = (GObjectClass*) klass;
127
128         parent_class            = g_type_class_peek_parent (klass);
129         gobject_class->finalize = modest_folder_view_finalize;
130         
131         klass->update_model = modest_folder_view_update_model;
132
133         g_type_class_add_private (gobject_class,
134                                   sizeof(ModestFolderViewPrivate));
135         
136         signals[FOLDER_SELECTION_CHANGED_SIGNAL] = 
137                 g_signal_new ("folder_selection_changed",
138                               G_TYPE_FROM_CLASS (gobject_class),
139                               G_SIGNAL_RUN_FIRST,
140                               G_STRUCT_OFFSET (ModestFolderViewClass,
141                                                folder_selection_changed),
142                               NULL, NULL,
143                               modest_marshal_VOID__POINTER_BOOLEAN,
144                               G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
145 }
146
147
148 static void
149 text_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
150                  GtkTreeModel *tree_model,  GtkTreeIter *iter,  gpointer data)
151 {
152         GObject *rendobj;
153         gchar *fname;
154         gint unread;
155         TnyFolderType type;
156         
157         g_return_if_fail (column);
158         g_return_if_fail (tree_model);
159
160         gtk_tree_model_get (tree_model, iter,
161                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
162                             TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
163                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
164                             -1);
165         rendobj = G_OBJECT(renderer);
166
167         if (!fname)
168                 return;
169
170         if (unread > 0) {
171                 gchar *folder_title = g_strdup_printf ("%s (%d)", fname, unread);
172                 g_object_set (rendobj,"text", folder_title,  "weight", 800, NULL);
173                 g_free (folder_title);
174         } else 
175                 g_object_set (rendobj,"text", fname, "weight", 400, NULL);
176                 
177         g_free (fname);
178 }
179
180
181
182 static void
183 icon_cell_data  (GtkTreeViewColumn *column,  GtkCellRenderer *renderer,
184                  GtkTreeModel *tree_model,  GtkTreeIter *iter, gpointer data)
185 {
186         GObject *rendobj;
187         GdkPixbuf *pixbuf;
188         TnyFolderType type;
189         gchar *fname = NULL;
190         gint unread;
191         
192         rendobj = G_OBJECT(renderer);
193         gtk_tree_model_get (tree_model, iter,
194                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
195                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
196                             TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread, -1);
197         rendobj = G_OBJECT(renderer);
198         
199         if (type == TNY_FOLDER_TYPE_NORMAL || type == TNY_FOLDER_TYPE_UNKNOWN)
200                 type = modest_tny_folder_guess_folder_type_from_name (fname);
201         g_free (fname);
202
203         switch (type) {
204         case TNY_FOLDER_TYPE_ROOT:
205                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
206                 break;
207         case TNY_FOLDER_TYPE_INBOX:
208                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_INBOX);
209                 break;
210         case TNY_FOLDER_TYPE_OUTBOX:
211                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_OUTBOX);
212                 break;
213         case TNY_FOLDER_TYPE_JUNK:
214                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_JUNK);
215                 break;
216         case TNY_FOLDER_TYPE_SENT:
217                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_SENT);
218                 break;
219         case TNY_FOLDER_TYPE_DRAFTS:
220                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_DRAFTS);
221                 break;
222         case TNY_FOLDER_TYPE_NOTES:
223                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_NOTES);
224                 break;
225         case TNY_FOLDER_TYPE_CALENDAR:
226                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_CALENDAR);
227                 break;
228         case TNY_FOLDER_TYPE_CONTACTS:
229                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_CONTACTS);
230                 break;
231         case TNY_FOLDER_TYPE_NORMAL:
232         default:
233                 pixbuf = modest_icon_factory_get_icon (MODEST_FOLDER_ICON_NORMAL);
234                 break;
235         }
236
237         g_object_set (rendobj,
238                       "pixbuf-expander-open",
239                       modest_icon_factory_get_icon (MODEST_FOLDER_ICON_OPEN),
240                       "pixbuf-expander-closed",
241                       modest_icon_factory_get_icon (MODEST_FOLDER_ICON_CLOSED),
242                       "pixbuf", pixbuf,
243                       NULL);
244 }
245
246 static void
247 modest_folder_view_init (ModestFolderView *obj)
248 {
249         ModestFolderViewPrivate *priv;
250         GtkTreeViewColumn *column;
251         GtkCellRenderer *renderer;
252         GtkTreeSelection *sel;
253         
254         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
255         
256         priv->account_store  = NULL;
257         priv->cur_folder     = NULL;
258         priv->query          = NULL;
259         priv->lock           = g_mutex_new ();
260         
261         column = gtk_tree_view_column_new ();   
262         gtk_tree_view_append_column (GTK_TREE_VIEW(obj),column);
263         
264         renderer = gtk_cell_renderer_pixbuf_new();
265         gtk_tree_view_column_pack_start (column, renderer, FALSE);
266         gtk_tree_view_column_set_cell_data_func(column, renderer,
267                                                 icon_cell_data, NULL, NULL);
268         
269         renderer = gtk_cell_renderer_text_new();
270         gtk_tree_view_column_pack_start (column, renderer, FALSE);
271         gtk_tree_view_column_set_cell_data_func(column, renderer,
272                                                 text_cell_data, NULL, NULL);
273         
274         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
275         gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
276
277         gtk_tree_view_column_set_spacing (column, 2);
278         gtk_tree_view_column_set_resizable (column, TRUE);
279         gtk_tree_view_column_set_fixed_width (column, TRUE);            
280         gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(obj), FALSE);
281         gtk_tree_view_set_enable_search     (GTK_TREE_VIEW(obj), FALSE);
282
283 }
284
285 static void
286 modest_folder_view_disconnect_store_account_handlers (GtkTreeView *self)
287 {
288         TnyIterator *iter;
289         ModestFolderViewPrivate *priv;
290         GtkTreeModel *model;
291         GtkTreeModelSort *sortable;
292         gint i = 0;
293
294         sortable = GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (self));
295         if (!sortable)
296                 return; 
297
298         model = gtk_tree_model_sort_get_model (sortable);
299         if (!model)
300                 return; 
301
302         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE (self);  
303         iter = tny_list_create_iterator (TNY_LIST (model));
304         while (!tny_iterator_is_done (iter)) {
305                 g_signal_handler_disconnect (G_OBJECT (tny_iterator_get_current (iter)),
306                                              priv->store_accounts_handlers [i++]);
307                 tny_iterator_next (iter);
308         }
309         g_object_unref (G_OBJECT (iter));
310 }
311
312
313 static void
314 modest_folder_view_finalize (GObject *obj)
315 {
316         ModestFolderViewPrivate *priv;
317         GtkTreeSelection    *sel;
318         
319         g_return_if_fail (obj);
320         
321         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
322         if (priv->account_store) {
323                 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
324                                              priv->sig1);
325                 g_object_unref (G_OBJECT(priv->account_store));
326                 priv->account_store = NULL;
327         }
328
329         if (priv->lock) {
330                 g_mutex_free (priv->lock);
331                 priv->lock = NULL;
332         }
333
334         if (priv->store_accounts_handlers) {
335                 modest_folder_view_disconnect_store_account_handlers (GTK_TREE_VIEW (obj));
336                 g_free (priv->store_accounts_handlers);
337                 priv->store_accounts_handlers = NULL;
338         }
339
340         if (priv->query) {
341                 g_object_unref (G_OBJECT (priv->query));
342                 priv->query = NULL;
343         }
344
345         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
346         if (sel)
347                 g_signal_handler_disconnect (G_OBJECT(sel), priv->sig2);
348         
349         G_OBJECT_CLASS(parent_class)->finalize (obj);
350 }
351
352
353 static void
354 on_account_update (TnyAccountStore *account_store, const gchar *account,
355                    gpointer user_data)
356 {
357         if (!update_model (MODEST_FOLDER_VIEW(user_data), 
358                            MODEST_TNY_ACCOUNT_STORE(account_store)))
359                 g_printerr ("modest: failed to update model for changes in '%s'",
360                             account);
361 }
362
363 void
364 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
365 {
366         GtkTreeViewColumn *col;
367         
368         g_return_if_fail (self);
369
370         col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
371         if (!col) {
372                 g_printerr ("modest: failed get column for title\n");
373                 return;
374         }
375
376         gtk_tree_view_column_set_title (col, title);
377         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
378                                            title != NULL);
379 }
380
381 GtkWidget*
382 modest_folder_view_new (ModestTnyAccountStore *account_store, 
383                         TnyFolderStoreQuery *query)
384 {
385         GObject *self;
386         ModestFolderViewPrivate *priv;
387         GtkTreeSelection *sel;
388         
389         g_return_val_if_fail (account_store, NULL);
390         
391         self = G_OBJECT(g_object_new(MODEST_TYPE_FOLDER_VIEW, NULL));
392         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
393         
394         priv->account_store = g_object_ref (G_OBJECT (account_store));
395         if (query)
396                 priv->query = g_object_ref (G_OBJECT (query));
397         
398         if (!update_model (MODEST_FOLDER_VIEW(self),
399                            MODEST_TNY_ACCOUNT_STORE(account_store)))
400                 g_printerr ("modest: failed to update model\n");
401         
402         priv->sig1 = g_signal_connect (G_OBJECT(account_store), "account_update",
403                                        G_CALLBACK (on_account_update), self);   
404         
405         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
406         priv->sig2 = g_signal_connect (sel, "changed",
407                                        G_CALLBACK(on_selection_changed), self);
408         return GTK_WIDGET(self);
409 }
410
411
412 static gboolean
413 update_model_empty (ModestFolderView *self)
414 {
415         ModestFolderViewPrivate *priv;
416         
417         g_return_val_if_fail (self, FALSE);
418         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
419
420         /* Disconnect old handlers */
421         if (priv->store_accounts_handlers) {
422                 modest_folder_view_disconnect_store_account_handlers (GTK_TREE_VIEW (self));
423                 g_free (priv->store_accounts_handlers);
424                 priv->store_accounts_handlers = NULL;
425         }
426
427         g_signal_emit (G_OBJECT(self), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
428                        NULL, TRUE);
429         return TRUE;
430 }
431
432
433 static void
434 update_store_account_handlers (ModestFolderView *self, TnyList *account_list)
435 {
436         ModestFolderViewPrivate *priv;
437         TnyIterator *iter;
438         guint len;
439         
440         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(self);
441
442         /* Listen to subscription changes */
443         len = tny_list_get_length (TNY_LIST (account_list));
444
445         g_assert (priv->store_accounts_handlers == NULL); /* don't leak */
446         priv->store_accounts_handlers = g_malloc0 (sizeof (guint) * len);
447         iter = tny_list_create_iterator (account_list);
448         
449         if (!tny_iterator_is_done (iter)) {
450                 gint i = 0;
451
452                 do  {
453                         
454                         priv->store_accounts_handlers [i++] =
455                                 g_signal_connect (G_OBJECT (tny_iterator_get_current (iter)),
456                                                   "subscription_changed",
457                                                   G_CALLBACK (on_subscription_changed),
458                                                   self);
459                         tny_iterator_next (iter);
460                 } while (!tny_iterator_is_done (iter));
461         }
462         g_object_unref (G_OBJECT (iter));       
463 }
464
465
466
467 static gboolean
468 update_model (ModestFolderView *self, ModestTnyAccountStore *account_store)
469 {
470         ModestFolderViewPrivate *priv;
471
472         TnyList          *account_list;
473         GtkTreeModel     *model, *sortable;
474
475         g_return_val_if_fail (account_store, FALSE);
476
477         update_model_empty (self);
478
479         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(self);
480         
481         model        = tny_gtk_folder_store_tree_model_new (FALSE, NULL);
482         account_list = TNY_LIST(model);
483
484         tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
485                                         account_list,
486                                         TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
487
488         
489         if (account_list) {
490                 sortable = gtk_tree_model_sort_new_with_model (model);
491                 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
492                                                       TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, 
493                                                       GTK_SORT_ASCENDING);
494                 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
495                                                  TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, 
496                                                  cmp_rows, NULL, NULL);
497                 gtk_tree_view_set_model (GTK_TREE_VIEW(self), sortable);
498                 update_store_account_handlers (self, account_list);
499         }
500         
501         g_object_unref (model);
502         return TRUE;
503 }
504
505
506 static void
507 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
508 {
509         GtkTreeModel            *model;
510         TnyFolder               *folder = NULL;
511         GtkTreeIter             iter;
512         ModestFolderView        *tree_view;
513         ModestFolderViewPrivate *priv;
514         gint                    type;
515
516         g_return_if_fail (sel);
517         g_return_if_fail (user_data);
518         
519         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
520         priv->cur_selection = sel;
521         
522         /* folder was _un_selected if true */
523         if (!gtk_tree_selection_get_selected (sel, &model, &iter)) {
524                 priv->cur_folder = NULL; /* FIXME: need this? */
525                return; 
526         }
527         
528         tree_view = MODEST_FOLDER_VIEW (user_data);
529         gtk_tree_model_get (model, &iter,
530                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
531                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
532                             -1);
533
534         if (type == TNY_FOLDER_TYPE_ROOT)
535                 return;
536         
537         /* emit 2 signals: one for the unselection of the old one,
538          * and one for the selection of the new on */
539         g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
540                        priv->cur_folder, FALSE);
541         g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
542                        folder, TRUE);
543         if (priv->cur_folder)
544                 tny_folder_expunge (priv->cur_folder, NULL); /* FIXME */
545         priv->cur_folder = folder;
546
547 }
548
549 static void 
550 on_subscription_changed  (TnyStoreAccount *store_account, 
551                           TnyFolder *folder,
552                           ModestFolderView *self)
553 {
554         /* TODO: probably we won't need a full reload, just the store
555            account or even the parent of the folder */
556
557         ModestFolderViewPrivate *priv;
558
559         priv =  MODEST_FOLDER_VIEW_GET_PRIVATE(self);
560         update_model (self, MODEST_TNY_ACCOUNT_STORE (priv->account_store));
561 }
562
563
564 static gboolean
565 modest_folder_view_update_model (ModestFolderView *self, TnyAccountStore *account_store)
566 {
567         g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
568
569         g_signal_emit (G_OBJECT(self), signals[FOLDER_SELECTION_CHANGED_SIGNAL],
570                        0, NULL, TRUE);
571         
572         return update_model (self, MODEST_TNY_ACCOUNT_STORE(account_store)); /* ugly */
573 }
574
575 TnyFolder *
576 modest_folder_view_get_selected (ModestFolderView *self)
577 {
578         ModestFolderViewPrivate *priv;
579
580         g_return_val_if_fail (self, NULL);
581         
582         priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
583         if (priv->cur_folder)
584                 g_object_ref (priv->cur_folder);
585
586         return priv->cur_folder;
587 }
588
589         
590 static gint
591 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
592           gpointer user_data)
593 {
594         gint cmp;
595         gchar         *name1, *name2;
596         TnyFolderType type;
597         TnyFolder     *folder1, *folder2;
598         
599         gtk_tree_model_get (tree_model, iter1,
600                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
601                             TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
602                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
603                             -1);
604         gtk_tree_model_get (tree_model, iter2,
605                             TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
606                             TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
607                             -1);
608
609         /* local_folders should be the last one */
610         if (type == TNY_FOLDER_TYPE_ROOT) {
611                 /* the account name is also the name of the root folder
612                  * in case of local folders */
613                 if (strcmp (name1, MODEST_LOCAL_FOLDERS_ACCOUNT_NAME) == 0)
614                         cmp = +1;
615                 else if (strcmp (name2, MODEST_LOCAL_FOLDERS_ACCOUNT_NAME) == 0)
616                         cmp = -1;
617                 else 
618                         cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
619         } else {
620                 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
621         }
622         g_free (name1);
623         g_free (name2);
624
625         return cmp;     
626 }