1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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.
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.
30 #include <glib/gi18n.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 <modest-tny-folder.h>
45 #include <modest-tny-local-folders-account.h>
46 #include <modest-marshal.h>
47 #include <modest-icon-names.h>
48 #include <modest-tny-account-store.h>
49 #include <modest-text-utils.h>
50 #include <modest-runtime.h>
51 #include "modest-folder-view.h"
52 #include <modest-dnd.h>
53 #include <modest-platform.h>
54 #include <modest-account-mgr-helpers.h>
55 #include <modest-widget-memory.h>
56 #include <modest-ui-actions.h>
58 /* 'private'/'protected' functions */
59 static void modest_folder_view_class_init (ModestFolderViewClass *klass);
60 static void modest_folder_view_init (ModestFolderView *obj);
61 static void modest_folder_view_finalize (GObject *obj);
63 static void tny_account_store_view_init (gpointer g,
66 static void modest_folder_view_set_account_store (TnyAccountStoreView *self,
67 TnyAccountStore *account_store);
69 static gboolean update_model (ModestFolderView *self,
70 ModestTnyAccountStore *account_store);
72 static void on_selection_changed (GtkTreeSelection *sel, gpointer data);
74 static void on_account_update (TnyAccountStore *account_store,
78 static void on_accounts_reloaded (TnyAccountStore *store,
81 static gint cmp_rows (GtkTreeModel *tree_model,
86 static gboolean filter_row (GtkTreeModel *model,
90 static gboolean on_key_pressed (GtkWidget *self,
94 static void on_configuration_key_changed (ModestConf* conf,
96 ModestConfEvent event,
97 ModestFolderView *self);
100 static void on_drag_data_get (GtkWidget *widget,
101 GdkDragContext *context,
102 GtkSelectionData *selection_data,
107 static void on_drag_data_received (GtkWidget *widget,
108 GdkDragContext *context,
111 GtkSelectionData *selection_data,
116 static gboolean on_drag_motion (GtkWidget *widget,
117 GdkDragContext *context,
123 static gint expand_row_timeout (gpointer data);
125 static void setup_drag_and_drop (GtkTreeView *self);
128 FOLDER_SELECTION_CHANGED_SIGNAL,
129 FOLDER_DISPLAY_NAME_CHANGED_SIGNAL,
133 typedef struct _ModestFolderViewPrivate ModestFolderViewPrivate;
134 struct _ModestFolderViewPrivate {
135 TnyAccountStore *account_store;
136 TnyFolderStore *cur_folder_store;
138 gulong account_update_signal;
139 gulong changed_signal;
140 gulong accounts_reloaded_signal;
142 TnyFolderStoreQuery *query;
143 guint timer_expander;
145 gchar *local_account_name;
146 gchar *visible_account_id;
147 ModestFolderViewStyle style;
149 #define MODEST_FOLDER_VIEW_GET_PRIVATE(o) \
150 (G_TYPE_INSTANCE_GET_PRIVATE((o), \
151 MODEST_TYPE_FOLDER_VIEW, \
152 ModestFolderViewPrivate))
154 static GObjectClass *parent_class = NULL;
156 static guint signals[LAST_SIGNAL] = {0};
159 modest_folder_view_get_type (void)
161 static GType my_type = 0;
163 static const GTypeInfo my_info = {
164 sizeof(ModestFolderViewClass),
165 NULL, /* base init */
166 NULL, /* base finalize */
167 (GClassInitFunc) modest_folder_view_class_init,
168 NULL, /* class finalize */
169 NULL, /* class data */
170 sizeof(ModestFolderView),
172 (GInstanceInitFunc) modest_folder_view_init,
176 static const GInterfaceInfo tny_account_store_view_info = {
177 (GInterfaceInitFunc) tny_account_store_view_init, /* interface_init */
178 NULL, /* interface_finalize */
179 NULL /* interface_data */
183 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
187 g_type_add_interface_static (my_type,
188 TNY_TYPE_ACCOUNT_STORE_VIEW,
189 &tny_account_store_view_info);
195 modest_folder_view_class_init (ModestFolderViewClass *klass)
197 GObjectClass *gobject_class;
198 gobject_class = (GObjectClass*) klass;
200 parent_class = g_type_class_peek_parent (klass);
201 gobject_class->finalize = modest_folder_view_finalize;
203 g_type_class_add_private (gobject_class,
204 sizeof(ModestFolderViewPrivate));
206 signals[FOLDER_SELECTION_CHANGED_SIGNAL] =
207 g_signal_new ("folder_selection_changed",
208 G_TYPE_FROM_CLASS (gobject_class),
210 G_STRUCT_OFFSET (ModestFolderViewClass,
211 folder_selection_changed),
213 modest_marshal_VOID__POINTER_BOOLEAN,
214 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
217 * This signal is emitted whenever the currently selected
218 * folder display name is computed. Note that the name could
219 * be different to the folder name, because we could append
220 * the unread messages count to the folder name to build the
221 * folder display name
223 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL] =
224 g_signal_new ("folder-display-name-changed",
225 G_TYPE_FROM_CLASS (gobject_class),
227 G_STRUCT_OFFSET (ModestFolderViewClass,
228 folder_display_name_changed),
230 g_cclosure_marshal_VOID__STRING,
231 G_TYPE_NONE, 1, G_TYPE_STRING);
235 text_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
236 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
238 ModestFolderViewPrivate *priv;
243 GObject *instance = NULL;
245 g_return_if_fail (column);
246 g_return_if_fail (tree_model);
248 gtk_tree_model_get (tree_model, iter,
249 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
250 TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN, &all,
251 TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
252 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
253 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
255 rendobj = G_OBJECT(renderer);
266 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
268 gchar *item_name = NULL;
269 gint item_weight = 400;
271 if (type != TNY_FOLDER_TYPE_ROOT) {
274 if (modest_tny_folder_is_local_folder (TNY_FOLDER (instance))) {
276 type = modest_tny_folder_get_local_folder_type (TNY_FOLDER (instance));
277 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
279 fname = g_strdup(modest_local_folder_info_get_type_display_name (type));
283 /* Select the number to show */
284 if ((type == TNY_FOLDER_TYPE_DRAFTS) || (type == TNY_FOLDER_TYPE_OUTBOX))
289 /* Use bold font style if there are unread messages */
291 item_name = g_strdup_printf ("%s (%d)", fname, unread);
294 item_name = g_strdup (fname);
298 } else if (TNY_IS_ACCOUNT (instance)) {
299 /* If it's a server account */
300 if (modest_tny_account_is_virtual_local_folders (
301 TNY_ACCOUNT (instance))) {
302 item_name = g_strdup (priv->local_account_name);
305 item_name = g_strdup (fname);
311 item_name = g_strdup ("unknown");
313 if (item_name && item_weight) {
314 /* Set the name in the treeview cell: */
315 g_object_set (rendobj,"text", item_name, "weight", item_weight, NULL);
317 /* Notify display name observers */
318 if (G_OBJECT (priv->cur_folder_store) == instance) {
319 g_signal_emit (G_OBJECT(data),
320 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
328 g_object_unref (G_OBJECT (instance));
335 icon_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
336 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
338 GObject *rendobj = NULL, *instance = NULL;
339 GdkPixbuf *pixbuf = NULL;
342 const gchar *account_id = NULL;
345 rendobj = G_OBJECT(renderer);
346 gtk_tree_model_get (tree_model, iter,
347 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
348 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
349 TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
350 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
361 if (type == TNY_FOLDER_TYPE_NORMAL || type == TNY_FOLDER_TYPE_UNKNOWN) {
362 type = modest_tny_folder_guess_folder_type_from_name (fname);
366 case TNY_FOLDER_TYPE_ROOT:
367 if (TNY_IS_ACCOUNT (instance)) {
369 if (modest_tny_account_is_virtual_local_folders (
370 TNY_ACCOUNT (instance))) {
371 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
374 account_id = tny_account_get_id (TNY_ACCOUNT (instance));
376 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
377 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
379 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
383 case TNY_FOLDER_TYPE_INBOX:
384 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
386 case TNY_FOLDER_TYPE_OUTBOX:
387 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
389 case TNY_FOLDER_TYPE_JUNK:
390 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
392 case TNY_FOLDER_TYPE_SENT:
393 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
395 case TNY_FOLDER_TYPE_TRASH:
396 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
398 case TNY_FOLDER_TYPE_DRAFTS:
399 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
401 case TNY_FOLDER_TYPE_NORMAL:
403 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
407 g_object_unref (G_OBJECT (instance));
411 g_object_set (rendobj, "pixbuf", pixbuf, NULL);
414 g_object_unref (pixbuf);
418 add_columns (GtkWidget *treeview)
420 GtkTreeViewColumn *column;
421 GtkCellRenderer *renderer;
422 GtkTreeSelection *sel;
425 column = gtk_tree_view_column_new ();
427 /* Set icon and text render function */
428 renderer = gtk_cell_renderer_pixbuf_new();
429 gtk_tree_view_column_pack_start (column, renderer, FALSE);
430 gtk_tree_view_column_set_cell_data_func(column, renderer,
431 icon_cell_data, treeview, NULL);
433 renderer = gtk_cell_renderer_text_new();
434 gtk_tree_view_column_pack_start (column, renderer, FALSE);
435 gtk_tree_view_column_set_cell_data_func(column, renderer,
436 text_cell_data, treeview, NULL);
438 /* Set selection mode */
439 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
440 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
442 /* Set treeview appearance */
443 gtk_tree_view_column_set_spacing (column, 2);
444 gtk_tree_view_column_set_resizable (column, TRUE);
445 gtk_tree_view_column_set_fixed_width (column, TRUE);
446 gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
447 gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
450 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
454 modest_folder_view_init (ModestFolderView *obj)
456 ModestFolderViewPrivate *priv;
459 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
461 priv->timer_expander = 0;
462 priv->account_store = NULL;
464 priv->style = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
465 priv->cur_folder_store = NULL;
466 priv->visible_account_id = NULL;
468 /* Initialize the local account name */
469 conf = modest_runtime_get_conf();
470 priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
473 add_columns (GTK_WIDGET (obj));
475 /* Setup drag and drop */
476 setup_drag_and_drop (GTK_TREE_VIEW(obj));
478 /* Connect signals */
479 g_signal_connect (G_OBJECT (obj),
481 G_CALLBACK (on_key_pressed), NULL);
484 * Track changes in the local account name (in the device it
485 * will be the device name)
487 g_signal_connect (G_OBJECT(conf),
489 G_CALLBACK(on_configuration_key_changed), obj);
494 tny_account_store_view_init (gpointer g, gpointer iface_data)
496 TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
498 klass->set_account_store_func = modest_folder_view_set_account_store;
504 modest_folder_view_finalize (GObject *obj)
506 ModestFolderViewPrivate *priv;
507 GtkTreeSelection *sel;
509 g_return_if_fail (obj);
511 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
513 if (priv->timer_expander != 0) {
514 g_source_remove (priv->timer_expander);
515 priv->timer_expander = 0;
518 if (priv->account_store) {
519 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
520 priv->account_update_signal);
521 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
522 priv->accounts_reloaded_signal);
523 g_object_unref (G_OBJECT(priv->account_store));
524 priv->account_store = NULL;
528 g_object_unref (G_OBJECT (priv->query));
532 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
534 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
536 g_free (priv->local_account_name);
537 g_free (priv->visible_account_id);
539 G_OBJECT_CLASS(parent_class)->finalize (obj);
544 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
546 ModestFolderViewPrivate *priv;
549 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
550 g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
552 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
553 device = tny_account_store_get_device (account_store);
555 if (G_UNLIKELY (priv->account_store)) {
557 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
558 priv->account_update_signal))
559 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
560 priv->account_update_signal);
561 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
562 priv->accounts_reloaded_signal))
563 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
564 priv->accounts_reloaded_signal);
566 g_object_unref (G_OBJECT (priv->account_store));
569 priv->account_store = g_object_ref (G_OBJECT (account_store));
571 priv->account_update_signal =
572 g_signal_connect (G_OBJECT(account_store), "account_update",
573 G_CALLBACK (on_account_update), self);
575 priv->accounts_reloaded_signal =
576 g_signal_connect (G_OBJECT(account_store), "accounts_reloaded",
577 G_CALLBACK (on_accounts_reloaded), self);
579 g_object_unref (G_OBJECT (device));
583 on_account_update (TnyAccountStore *account_store, const gchar *account,
586 if (!update_model (MODEST_FOLDER_VIEW(user_data),
587 MODEST_TNY_ACCOUNT_STORE(account_store)))
588 g_printerr ("modest: failed to update model for changes in '%s'",
593 on_accounts_reloaded (TnyAccountStore *account_store,
596 ModestConf *conf = modest_runtime_get_conf ();
598 modest_widget_memory_save (conf, G_OBJECT (user_data), MODEST_CONF_FOLDER_VIEW_KEY);
599 update_model (MODEST_FOLDER_VIEW (user_data),
600 MODEST_TNY_ACCOUNT_STORE(account_store));
601 modest_widget_memory_restore (conf, G_OBJECT (user_data), MODEST_CONF_FOLDER_VIEW_KEY);
605 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
607 GtkTreeViewColumn *col;
609 g_return_if_fail (self);
611 col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
613 g_printerr ("modest: failed get column for title\n");
617 gtk_tree_view_column_set_title (col, title);
618 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
623 modest_folder_view_new (TnyFolderStoreQuery *query)
626 ModestFolderViewPrivate *priv;
627 GtkTreeSelection *sel;
629 self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, NULL));
630 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
633 priv->query = g_object_ref (query);
635 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
636 priv->changed_signal = g_signal_connect (sel, "changed",
637 G_CALLBACK (on_selection_changed), self);
639 return GTK_WIDGET(self);
642 /* this feels dirty; any other way to expand all the root items? */
644 expand_root_items (ModestFolderView *self)
647 path = gtk_tree_path_new_first ();
649 /* all folders should have child items, so.. */
650 while (gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE))
651 gtk_tree_path_next (path);
653 gtk_tree_path_free (path);
657 * We use this function to implement the
658 * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
659 * account in this case, and the local folders.
662 filter_row (GtkTreeModel *model,
666 gboolean retval = TRUE;
668 GObject *instance = NULL;
670 gtk_tree_model_get (model, iter,
671 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
672 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
675 /* Do not show if there is no instance, this could indeed
676 happen when the model is being modified while it's being
677 drawn. This could occur for example when moving folders
682 if (type == TNY_FOLDER_TYPE_ROOT) {
683 /* TNY_FOLDER_TYPE_ROOT means that the instance is an account instead of a folder. */
684 if (TNY_IS_ACCOUNT (instance)) {
685 TnyAccount *acc = TNY_ACCOUNT (instance);
686 const gchar *account_id = tny_account_get_id (acc);
688 /* If it isn't a special folder,
689 * don't show it unless it is the visible account: */
690 if (!modest_tny_account_is_virtual_local_folders (acc) &&
691 strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
692 /* Show only the visible account id */
693 ModestFolderViewPrivate *priv =
694 MODEST_FOLDER_VIEW_GET_PRIVATE (data);
695 if (priv->visible_account_id && strcmp (account_id, priv->visible_account_id))
701 /* The virtual local-folders folder store is also shown by default. */
703 g_object_unref (instance);
709 static void on_tnylist_accounts_debug_print(gpointer data, gpointer user_data)
711 TnyAccount* account = TNY_ACCOUNT(data);
712 const gchar *prefix = (const gchar*)(user_data);
714 printf("%s account id=%s\n", prefix, tny_account_get_id (account));
719 update_model (ModestFolderView *self, ModestTnyAccountStore *account_store)
721 ModestFolderViewPrivate *priv;
722 GtkTreeModel *model /* , *old_model */;
723 /* TnyAccount *local_account; */
724 TnyList *model_as_list;
726 g_return_val_if_fail (account_store, FALSE);
728 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
730 /* Notify that there is no folder selected */
731 g_signal_emit (G_OBJECT(self),
732 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
735 /* Remove the old model as observer of the local folder account */
736 #if 0 /* Commented out until Sergio fixes the crash. */
738 modest_tny_account_store_get_tny_account_by_account (modest_runtime_get_account_store (),
739 MODEST_ACTUAL_LOCAL_FOLDERS_ACCOUNT_ID,
740 TNY_ACCOUNT_TYPE_STORE);
741 old_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
744 GtkTreeModel *sorted, *model;
746 if (GTK_IS_TREE_MODEL_FILTER (old_model))
747 sorted = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (old_model));
751 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sorted));
753 tny_folder_store_remove_observer (TNY_FOLDER_STORE (local_account),
754 TNY_FOLDER_STORE_OBSERVER (model));
758 /* FIXME: the local accounts are not shown when the query
759 selects only the subscribed folders. */
760 /* model = tny_gtk_folder_store_tree_model_new (TRUE, priv->query); */
761 model = tny_gtk_folder_store_tree_model_new (TRUE, NULL);
763 /* Deal with the model via its TnyList Interface,
764 * filling the TnyList via a get_accounts() call: */
765 model_as_list = TNY_LIST(model);
767 /* Get the accounts: */
768 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
770 TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
772 #if 0 /* Commented out until Sergio fixes the crash. */
773 /* Set the folder view as an account observer in order to let
774 us see the UI changes automatically when creating and
775 deleting folders just under the local account */
776 tny_folder_store_add_observer (TNY_FOLDER_STORE (local_account),
777 TNY_FOLDER_STORE_OBSERVER (model));
778 g_object_unref (local_account);
781 g_object_unref (model_as_list);
782 model_as_list = NULL;
786 tny_list_foreach (account_list, on_tnylist_accounts_debug_print, "update_model: ");
789 GtkTreeModel *filter_model = NULL, *sortable = NULL;
791 sortable = gtk_tree_model_sort_new_with_model (model);
792 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
793 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
795 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
796 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
797 cmp_rows, NULL, NULL);
799 /* Create filter model */
800 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE) {
801 filter_model = gtk_tree_model_filter_new (sortable, NULL);
802 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
809 gtk_tree_view_set_model (GTK_TREE_VIEW(self),
810 (filter_model) ? filter_model : sortable);
811 expand_root_items (self); /* expand all account folders */
814 g_object_unref (model);
817 g_object_unref (filter_model);
819 g_object_unref (sortable);
826 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
829 TnyFolderStore *folder = NULL;
831 ModestFolderView *tree_view;
832 ModestFolderViewPrivate *priv;
835 g_return_if_fail (sel);
836 g_return_if_fail (user_data);
838 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
840 /* folder was _un_selected if true */
841 if (!gtk_tree_selection_get_selected (sel, &model, &iter)) {
842 if (priv->cur_folder_store)
843 g_object_unref (priv->cur_folder_store);
844 priv->cur_folder_store = NULL;
846 /* Notify the display name observers */
847 g_signal_emit (G_OBJECT(user_data),
848 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
853 tree_view = MODEST_FOLDER_VIEW (user_data);
855 gtk_tree_model_get (model, &iter,
856 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
857 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
860 /* If the folder is the same do not notify */
861 if (priv->cur_folder_store == folder) {
862 g_object_unref (folder);
866 /* Current folder was unselected */
867 if (priv->cur_folder_store) {
868 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
869 priv->cur_folder_store, FALSE);
870 g_object_unref (priv->cur_folder_store);
873 /* New current references */
874 priv->cur_folder_store = folder;
876 /* New folder has been selected */
877 g_signal_emit (G_OBJECT(tree_view),
878 signals[FOLDER_SELECTION_CHANGED_SIGNAL],
883 modest_folder_view_get_selected (ModestFolderView *self)
885 ModestFolderViewPrivate *priv;
887 g_return_val_if_fail (self, NULL);
889 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
890 if (priv->cur_folder_store)
891 g_object_ref (priv->cur_folder_store);
893 return priv->cur_folder_store;
897 get_cmp_rows_type_pos (GObject *folder)
899 /* Remote accounts -> Local account -> MMC account .*/
902 if (TNY_IS_ACCOUNT (folder) &&
903 modest_tny_account_is_virtual_local_folders (
904 TNY_ACCOUNT (folder))) {
906 } else if (TNY_IS_ACCOUNT (folder)) {
907 TnyAccount *account = TNY_ACCOUNT (folder);
908 const gchar *account_id = tny_account_get_id (account);
909 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
915 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
916 return -1; /* Should never happen */
921 * This function orders the mail accounts according to these rules:
922 * 1st - remote accounts
923 * 2nd - local account
927 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
931 gchar *name1, *name2;
933 GObject *folder1 = NULL;
934 GObject *folder2 = NULL;
936 gtk_tree_model_get (tree_model, iter1,
937 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
938 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
939 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
941 gtk_tree_model_get (tree_model, iter2,
942 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
943 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
946 if (type == TNY_FOLDER_TYPE_ROOT) {
947 /* Compare the types, so that
948 * Remote accounts -> Local account -> MMC account .*/
949 const gint pos1 = get_cmp_rows_type_pos (folder1);
950 const gint pos2 = get_cmp_rows_type_pos (folder2);
951 /* printf ("DEBUG: %s:\n type1=%s, pos1=%d\n type2=%s, pos2=%d\n",
952 __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
955 else if (pos1 > pos2)
958 /* Compare items of the same type: */
960 TnyAccount *account1 = NULL;
961 if (TNY_IS_ACCOUNT (folder1))
962 account1 = TNY_ACCOUNT (folder1);
964 TnyAccount *account2 = NULL;
965 if (TNY_IS_ACCOUNT (folder2))
966 account2 = TNY_ACCOUNT (folder2);
968 const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
969 const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
971 if (!account_id && !account_id2)
973 else if (!account_id)
975 else if (!account_id2)
977 else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
980 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
983 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
987 g_object_unref(G_OBJECT(folder1));
989 g_object_unref(G_OBJECT(folder2));
997 /*****************************************************************************/
998 /* DRAG and DROP stuff */
999 /*****************************************************************************/
1002 * This function fills the #GtkSelectionData with the row and the
1003 * model that has been dragged. It's called when this widget is a
1004 * source for dnd after the event drop happened
1007 on_drag_data_get (GtkWidget *widget,
1008 GdkDragContext *context,
1009 GtkSelectionData *selection_data,
1014 GtkTreeSelection *selection;
1015 GtkTreeModel *model;
1017 GtkTreePath *source_row;
1019 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1020 gtk_tree_selection_get_selected (selection, &model, &iter);
1021 source_row = gtk_tree_model_get_path (model, &iter);
1023 gtk_tree_set_row_drag_data (selection_data,
1027 gtk_tree_path_free (source_row);
1030 typedef struct _DndHelper {
1031 gboolean delete_source;
1032 GtkTreePath *source_row;
1033 GdkDragContext *context;
1039 * This function is the callback of the
1040 * modest_mail_operation_xfer_msgs () and
1041 * modest_mail_operation_xfer_folder() calls. We check here if the
1042 * message/folder was correctly asynchronously transferred. The reason
1043 * to use the same callback is that the code is the same, it only has
1044 * to check that the operation went fine and then finalize the drag
1048 on_progress_changed (ModestMailOperation *mail_op,
1049 ModestMailOperationState *state,
1055 helper = (DndHelper *) user_data;
1057 if (!state->finished)
1060 if (state->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
1066 /* Notify the drag source. Never call delete, the monitor will
1067 do the job if needed */
1068 gtk_drag_finish (helper->context, success, FALSE, helper->time);
1070 /* Free the helper */
1071 gtk_tree_path_free (helper->source_row);
1072 g_slice_free (DndHelper, helper);
1076 * This function is used by drag_data_received_cb to manage drag and
1077 * drop of a header, i.e, and drag from the header view to the folder
1081 drag_and_drop_from_header_view (GtkTreeModel *source_model,
1082 GtkTreeModel *dest_model,
1083 GtkTreePath *dest_row,
1089 ModestMailOperation *mail_op;
1090 GtkTreeIter source_iter, dest_iter;
1093 gtk_tree_model_get_iter (source_model, &source_iter, helper->source_row);
1094 gtk_tree_model_get (source_model, &source_iter,
1095 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1099 gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
1100 gtk_tree_model_get (dest_model, &dest_iter,
1101 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1104 /* Transfer message */
1105 mail_op = modest_mail_operation_new (MODEST_MAIL_OPERATION_TYPE_RECEIVE, NULL);
1107 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1109 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1110 G_CALLBACK (on_progress_changed), helper);
1112 headers = tny_simple_list_new ();
1113 tny_list_append (headers, G_OBJECT (header));
1114 modest_mail_operation_xfer_msgs (mail_op,
1117 helper->delete_source,
1121 g_object_unref (G_OBJECT (mail_op));
1122 g_object_unref (G_OBJECT (header));
1123 g_object_unref (G_OBJECT (folder));
1124 g_object_unref (headers);
1128 * This function is used by drag_data_received_cb to manage drag and
1129 * drop of a folder, i.e, and drag from the folder view to the same
1133 drag_and_drop_from_folder_view (GtkTreeModel *source_model,
1134 GtkTreeModel *dest_model,
1135 GtkTreePath *dest_row,
1136 GtkSelectionData *selection_data,
1139 ModestMailOperation *mail_op;
1140 GtkTreeIter parent_iter, iter;
1141 TnyFolderStore *parent_folder;
1144 /* Check if the drag is possible */
1145 /* if (!gtk_tree_path_compare (helper->source_row, dest_row) || */
1146 /* !gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (dest_model), */
1148 /* selection_data)) { */
1149 if (!gtk_tree_path_compare (helper->source_row, dest_row)) {
1151 gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
1152 gtk_tree_path_free (helper->source_row);
1153 g_slice_free (DndHelper, helper);
1158 gtk_tree_model_get_iter (source_model, &parent_iter, dest_row);
1159 gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
1160 gtk_tree_model_get (source_model, &parent_iter,
1161 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1162 &parent_folder, -1);
1163 gtk_tree_model_get (source_model, &iter,
1164 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1167 /* Do the mail operation */
1168 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1170 modest_ui_actions_move_folder_error_handler,
1172 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1174 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1175 G_CALLBACK (on_progress_changed), helper);
1177 modest_mail_operation_xfer_folder (mail_op,
1180 helper->delete_source);
1183 g_object_unref (G_OBJECT (parent_folder));
1184 g_object_unref (G_OBJECT (folder));
1185 g_object_unref (G_OBJECT (mail_op));
1189 * This function receives the data set by the "drag-data-get" signal
1190 * handler. This information comes within the #GtkSelectionData. This
1191 * function will manage both the drags of folders of the treeview and
1192 * drags of headers of the header view widget.
1195 on_drag_data_received (GtkWidget *widget,
1196 GdkDragContext *context,
1199 GtkSelectionData *selection_data,
1204 GtkWidget *source_widget;
1205 GtkTreeModel *dest_model, *source_model;
1206 GtkTreePath *source_row, *dest_row;
1207 GtkTreeViewDropPosition pos;
1208 gboolean success = FALSE, delete_source = FALSE;
1209 DndHelper *helper = NULL;
1211 /* Do not allow further process */
1212 g_signal_stop_emission_by_name (widget, "drag-data-received");
1213 source_widget = gtk_drag_get_source_widget (context);
1215 /* Get the action */
1216 if (context->action == GDK_ACTION_MOVE) {
1217 delete_source = TRUE;
1219 /* Notify that there is no folder selected. We need to
1220 do this in order to update the headers view (and
1221 its monitors, because when moving, the old folder
1222 won't longer exist. We can not wait for the end of
1223 the operation, because the operation won't start if
1224 the folder is in use */
1225 if (source_widget == widget)
1226 g_signal_emit (G_OBJECT (widget),
1227 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0, NULL, TRUE);
1230 /* Check if the get_data failed */
1231 if (selection_data == NULL || selection_data->length < 0)
1232 gtk_drag_finish (context, success, FALSE, time);
1234 /* Get the models */
1235 gtk_tree_get_row_drag_data (selection_data,
1239 /* Select the destination model */
1240 if (source_widget == widget) {
1241 dest_model = source_model;
1243 dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1246 /* Get the path to the destination row. Can not call
1247 gtk_tree_view_get_drag_dest_row() because the source row
1248 is not selected anymore */
1249 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
1252 /* Only allow drops IN other rows */
1253 if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER)
1254 gtk_drag_finish (context, success, FALSE, time);
1256 /* Create the helper */
1257 helper = g_slice_new0 (DndHelper);
1258 helper->delete_source = delete_source;
1259 helper->source_row = gtk_tree_path_copy (source_row);
1260 helper->context = context;
1261 helper->time = time;
1263 /* Drags from the header view */
1264 if (source_widget != widget) {
1266 drag_and_drop_from_header_view (source_model,
1273 drag_and_drop_from_folder_view (source_model,
1281 gtk_tree_path_free (source_row);
1282 gtk_tree_path_free (dest_row);
1286 * We define a "drag-drop" signal handler because we do not want to
1287 * use the default one, because the default one always calls
1288 * gtk_drag_finish and we prefer to do it in the "drag-data-received"
1289 * signal handler, because there we have all the information available
1290 * to know if the dnd was a success or not.
1293 drag_drop_cb (GtkWidget *widget,
1294 GdkDragContext *context,
1302 if (!context->targets)
1305 /* Check if we're dragging a folder row */
1306 target = gtk_drag_dest_find_target (widget, context, NULL);
1308 /* Request the data from the source. */
1309 gtk_drag_get_data(widget, context, target, time);
1315 * This function expands a node of a tree view if it's not expanded
1316 * yet. Not sure why it needs the threads stuff, but gtk+`example code
1317 * does that, so that's why they're here.
1320 expand_row_timeout (gpointer data)
1322 GtkTreeView *tree_view = data;
1323 GtkTreePath *dest_path = NULL;
1324 GtkTreeViewDropPosition pos;
1325 gboolean result = FALSE;
1327 GDK_THREADS_ENTER ();
1329 gtk_tree_view_get_drag_dest_row (tree_view,
1334 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
1335 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
1336 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
1337 gtk_tree_path_free (dest_path);
1341 gtk_tree_path_free (dest_path);
1346 GDK_THREADS_LEAVE ();
1352 * This function is called whenever the pointer is moved over a widget
1353 * while dragging some data. It installs a timeout that will expand a
1354 * node of the treeview if not expanded yet. This function also calls
1355 * gdk_drag_status in order to set the suggested action that will be
1356 * used by the "drag-data-received" signal handler to know if we
1357 * should do a move or just a copy of the data.
1360 on_drag_motion (GtkWidget *widget,
1361 GdkDragContext *context,
1367 GtkTreeViewDropPosition pos;
1368 GtkTreePath *dest_row;
1369 ModestFolderViewPrivate *priv;
1370 GdkDragAction suggested_action;
1371 gboolean valid_location = FALSE;
1373 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1375 if (priv->timer_expander != 0) {
1376 g_source_remove (priv->timer_expander);
1377 priv->timer_expander = 0;
1380 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
1385 /* Do not allow drops between folders */
1387 pos == GTK_TREE_VIEW_DROP_BEFORE ||
1388 pos == GTK_TREE_VIEW_DROP_AFTER) {
1389 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
1390 gdk_drag_status(context, 0, time);
1391 valid_location = FALSE;
1394 valid_location = TRUE;
1397 /* Expand the selected row after 1/2 second */
1398 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
1399 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
1400 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
1403 /* Select the desired action. By default we pick MOVE */
1404 suggested_action = GDK_ACTION_MOVE;
1406 if (context->actions == GDK_ACTION_COPY)
1407 gdk_drag_status(context, GDK_ACTION_COPY, time);
1408 else if (context->actions == GDK_ACTION_MOVE)
1409 gdk_drag_status(context, GDK_ACTION_MOVE, time);
1410 else if (context->actions & suggested_action)
1411 gdk_drag_status(context, suggested_action, time);
1413 gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
1417 gtk_tree_path_free (dest_row);
1418 g_signal_stop_emission_by_name (widget, "drag-motion");
1419 return valid_location;
1423 /* Folder view drag types */
1424 const GtkTargetEntry folder_view_drag_types[] =
1426 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
1427 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
1431 * This function sets the treeview as a source and a target for dnd
1432 * events. It also connects all the requirede signals.
1435 setup_drag_and_drop (GtkTreeView *self)
1437 /* Set up the folder view as a dnd destination. Set only the
1438 highlight flag, otherwise gtk will have a different
1440 gtk_drag_dest_set (GTK_WIDGET (self),
1441 GTK_DEST_DEFAULT_HIGHLIGHT,
1442 folder_view_drag_types,
1443 G_N_ELEMENTS (folder_view_drag_types),
1444 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1446 g_signal_connect (G_OBJECT (self),
1447 "drag_data_received",
1448 G_CALLBACK (on_drag_data_received),
1452 /* Set up the treeview as a dnd source */
1453 gtk_drag_source_set (GTK_WIDGET (self),
1455 folder_view_drag_types,
1456 G_N_ELEMENTS (folder_view_drag_types),
1457 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1459 g_signal_connect (G_OBJECT (self),
1461 G_CALLBACK (on_drag_motion),
1464 g_signal_connect (G_OBJECT (self),
1466 G_CALLBACK (on_drag_data_get),
1469 g_signal_connect (G_OBJECT (self),
1471 G_CALLBACK (drag_drop_cb),
1476 * This function manages the navigation through the folders using the
1477 * keyboard or the hardware keys in the device
1480 on_key_pressed (GtkWidget *self,
1484 GtkTreeSelection *selection;
1486 GtkTreeModel *model;
1487 gboolean retval = FALSE;
1489 /* Up and Down are automatically managed by the treeview */
1490 if (event->keyval == GDK_Return) {
1491 /* Expand/Collapse the selected row */
1492 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1493 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1496 path = gtk_tree_model_get_path (model, &iter);
1498 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
1499 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
1501 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
1502 gtk_tree_path_free (path);
1504 /* No further processing */
1512 * We listen to the changes in the local folder account name key,
1513 * because we want to show the right name in the view. The local
1514 * folder account name corresponds to the device name in the Maemo
1515 * version. We do this because we do not want to query gconf on each
1516 * tree view refresh. It's better to cache it and change whenever
1520 on_configuration_key_changed (ModestConf* conf,
1522 ModestConfEvent event,
1523 ModestFolderView *self)
1525 ModestFolderViewPrivate *priv;
1530 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1531 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1533 if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
1534 g_free (priv->local_account_name);
1536 if (event == MODEST_CONF_EVENT_KEY_UNSET)
1537 priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
1539 priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
1540 MODEST_CONF_DEVICE_NAME, NULL);
1542 /* Force a redraw */
1543 #if GTK_CHECK_VERSION(2, 8, 0) /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
1544 GtkTreeViewColumn * tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
1545 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
1546 gtk_tree_view_column_queue_resize (tree_column);
1552 modest_folder_view_set_style (ModestFolderView *self,
1553 ModestFolderViewStyle style)
1555 ModestFolderViewPrivate *priv;
1557 g_return_if_fail (self);
1559 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1561 priv->style = style;
1565 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
1566 const gchar *account_id)
1568 ModestFolderViewPrivate *priv;
1569 GtkTreeModel *model;
1571 g_return_if_fail (self);
1573 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1575 /* This will be used by the filter_row callback,
1576 * to decided which rows to show: */
1577 if (priv->visible_account_id)
1578 g_free (priv->visible_account_id);
1579 priv->visible_account_id = g_strdup (account_id);
1582 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1583 if (GTK_IS_TREE_MODEL_FILTER (model))
1584 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
1588 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
1590 ModestFolderViewPrivate *priv;
1592 g_return_val_if_fail (self, NULL);
1594 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1596 return (const gchar *) priv->visible_account_id;
1600 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
1606 gtk_tree_model_get (model, iter,
1607 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN,
1610 if (type == TNY_FOLDER_TYPE_INBOX) {
1611 *inbox_iter = *iter;
1615 if (gtk_tree_model_iter_children (model, &child, iter)) {
1616 if (find_inbox_iter (model, &child, inbox_iter))
1620 } while (gtk_tree_model_iter_next (model, iter));
1628 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
1630 GtkTreeModel *model;
1631 GtkTreeIter iter, inbox_iter;
1632 GtkTreeSelection *sel;
1634 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1638 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1640 gtk_tree_model_get_iter_first (model, &iter);
1641 if (find_inbox_iter (model, &iter, &inbox_iter))
1642 gtk_tree_selection_select_iter (sel, &inbox_iter);
1644 gtk_tree_model_get_iter_first (model, &iter);
1645 gtk_tree_selection_select_iter (sel, &iter);