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-account.h>
45 #include <modest-tny-folder.h>
46 #include <modest-tny-local-folders-account.h>
47 #include <modest-tny-outbox-account.h>
48 #include <modest-marshal.h>
49 #include <modest-icon-names.h>
50 #include <modest-tny-account-store.h>
51 #include <modest-text-utils.h>
52 #include <modest-runtime.h>
53 #include "modest-folder-view.h"
54 #include <modest-dnd.h>
55 #include <modest-platform.h>
56 #include <modest-widget-memory.h>
57 #include <modest-ui-actions.h>
59 /* 'private'/'protected' functions */
60 static void modest_folder_view_class_init (ModestFolderViewClass *klass);
61 static void modest_folder_view_init (ModestFolderView *obj);
62 static void modest_folder_view_finalize (GObject *obj);
64 static void tny_account_store_view_init (gpointer g,
67 static void modest_folder_view_set_account_store (TnyAccountStoreView *self,
68 TnyAccountStore *account_store);
70 static void on_selection_changed (GtkTreeSelection *sel, gpointer data);
72 static void on_account_update (TnyAccountStore *account_store,
76 static void on_account_removed (TnyAccountStore *self,
80 static void on_accounts_reloaded (TnyAccountStore *store,
83 static gint cmp_rows (GtkTreeModel *tree_model,
88 static gboolean filter_row (GtkTreeModel *model,
92 static gboolean on_key_pressed (GtkWidget *self,
96 static void on_configuration_key_changed (ModestConf* conf,
98 ModestConfEvent event,
99 ModestFolderView *self);
102 static void on_drag_data_get (GtkWidget *widget,
103 GdkDragContext *context,
104 GtkSelectionData *selection_data,
109 static void on_drag_data_received (GtkWidget *widget,
110 GdkDragContext *context,
113 GtkSelectionData *selection_data,
118 static gboolean on_drag_motion (GtkWidget *widget,
119 GdkDragContext *context,
125 static gint expand_row_timeout (gpointer data);
127 static void setup_drag_and_drop (GtkTreeView *self);
129 static gboolean _clipboard_set_selected_data (ModestFolderView *folder_view,
132 static void _clear_hidding_filter (ModestFolderView *folder_view);
134 static void on_row_changed_maybe_select_folder (GtkTreeModel *tree_model,
137 ModestFolderView *self);
140 FOLDER_SELECTION_CHANGED_SIGNAL,
141 FOLDER_DISPLAY_NAME_CHANGED_SIGNAL,
145 typedef struct _ModestFolderViewPrivate ModestFolderViewPrivate;
146 struct _ModestFolderViewPrivate {
147 TnyAccountStore *account_store;
148 TnyFolderStore *cur_folder_store;
150 TnyFolder *folder_to_select; /* folder to select after the next update */
152 gulong account_update_signal;
153 gulong changed_signal;
154 gulong accounts_reloaded_signal;
155 gulong account_removed_signal;
156 gulong conf_key_signal;
158 /* not unref this object, its a singlenton */
159 ModestEmailClipboard *clipboard;
161 /* Filter tree model */
165 TnyFolderStoreQuery *query;
166 guint timer_expander;
168 gchar *local_account_name;
169 gchar *visible_account_id;
170 ModestFolderViewStyle style;
172 gboolean reselect; /* we use this to force a reselection of the INBOX */
173 gboolean show_non_move;
175 #define MODEST_FOLDER_VIEW_GET_PRIVATE(o) \
176 (G_TYPE_INSTANCE_GET_PRIVATE((o), \
177 MODEST_TYPE_FOLDER_VIEW, \
178 ModestFolderViewPrivate))
180 static GObjectClass *parent_class = NULL;
182 static guint signals[LAST_SIGNAL] = {0};
185 modest_folder_view_get_type (void)
187 static GType my_type = 0;
189 static const GTypeInfo my_info = {
190 sizeof(ModestFolderViewClass),
191 NULL, /* base init */
192 NULL, /* base finalize */
193 (GClassInitFunc) modest_folder_view_class_init,
194 NULL, /* class finalize */
195 NULL, /* class data */
196 sizeof(ModestFolderView),
198 (GInstanceInitFunc) modest_folder_view_init,
202 static const GInterfaceInfo tny_account_store_view_info = {
203 (GInterfaceInitFunc) tny_account_store_view_init, /* interface_init */
204 NULL, /* interface_finalize */
205 NULL /* interface_data */
209 my_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
213 g_type_add_interface_static (my_type,
214 TNY_TYPE_ACCOUNT_STORE_VIEW,
215 &tny_account_store_view_info);
221 modest_folder_view_class_init (ModestFolderViewClass *klass)
223 GObjectClass *gobject_class;
224 gobject_class = (GObjectClass*) klass;
226 parent_class = g_type_class_peek_parent (klass);
227 gobject_class->finalize = modest_folder_view_finalize;
229 g_type_class_add_private (gobject_class,
230 sizeof(ModestFolderViewPrivate));
232 signals[FOLDER_SELECTION_CHANGED_SIGNAL] =
233 g_signal_new ("folder_selection_changed",
234 G_TYPE_FROM_CLASS (gobject_class),
236 G_STRUCT_OFFSET (ModestFolderViewClass,
237 folder_selection_changed),
239 modest_marshal_VOID__POINTER_BOOLEAN,
240 G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN);
243 * This signal is emitted whenever the currently selected
244 * folder display name is computed. Note that the name could
245 * be different to the folder name, because we could append
246 * the unread messages count to the folder name to build the
247 * folder display name
249 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL] =
250 g_signal_new ("folder-display-name-changed",
251 G_TYPE_FROM_CLASS (gobject_class),
253 G_STRUCT_OFFSET (ModestFolderViewClass,
254 folder_display_name_changed),
256 g_cclosure_marshal_VOID__STRING,
257 G_TYPE_NONE, 1, G_TYPE_STRING);
260 /* Simplify checks for NULLs: */
261 static gboolean strings_are_equal (const gchar *a, const gchar *b)
267 return (strcmp (a, b) == 0);
273 static gboolean on_model_foreach_set_name(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
275 GObject *instance = NULL;
277 gtk_tree_model_get (model, iter,
278 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
282 return FALSE; /* keep walking */
284 if (!TNY_IS_ACCOUNT (instance)) {
285 g_object_unref (instance);
286 return FALSE; /* keep walking */
289 /* Check if this is the looked-for account: */
290 TnyAccount *this_account = TNY_ACCOUNT (instance);
291 TnyAccount *account = TNY_ACCOUNT (data);
293 const gchar *this_account_id = tny_account_get_id(this_account);
294 const gchar *account_id = tny_account_get_id(account);
295 g_object_unref (instance);
298 /* printf ("DEBUG: %s: this_account_id=%s, account_id=%s\n", __FUNCTION__, this_account_id, account_id); */
299 if (strings_are_equal(this_account_id, account_id)) {
300 /* Tell the model that the data has changed, so that
301 * it calls the cell_data_func callbacks again: */
302 /* TODO: This does not seem to actually cause the new string to be shown: */
303 gtk_tree_model_row_changed (model, path, iter);
305 return TRUE; /* stop walking */
308 return FALSE; /* keep walking */
313 ModestFolderView *self;
314 gchar *previous_name;
315 } GetMmcAccountNameData;
317 static void on_get_mmc_account_name (TnyStoreAccount* account, gpointer user_data)
319 /* printf ("DEBU1G: %s: account name=%s\n", __FUNCTION__, tny_account_get_name (TNY_ACCOUNT(account))); */
321 GetMmcAccountNameData *data = (GetMmcAccountNameData*)user_data;
323 if (!strings_are_equal (
324 tny_account_get_name(TNY_ACCOUNT(account)),
325 data->previous_name)) {
327 /* Tell the model that the data has changed, so that
328 * it calls the cell_data_func callbacks again: */
329 ModestFolderView *self = data->self;
330 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
332 gtk_tree_model_foreach(model, on_model_foreach_set_name, account);
335 g_free (data->previous_name);
336 g_slice_free (GetMmcAccountNameData, data);
340 text_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
341 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
343 ModestFolderViewPrivate *priv;
348 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
349 GObject *instance = NULL;
351 g_return_if_fail (column);
352 g_return_if_fail (tree_model);
354 gtk_tree_model_get (tree_model, iter,
355 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
356 TNY_GTK_FOLDER_STORE_TREE_MODEL_ALL_COLUMN, &all,
357 TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
358 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
359 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
361 rendobj = G_OBJECT(renderer);
371 ModestFolderView *self = MODEST_FOLDER_VIEW (data);
372 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
374 gchar *item_name = NULL;
375 gint item_weight = 400;
377 if (type != TNY_FOLDER_TYPE_ROOT) {
380 if (modest_tny_folder_is_local_folder (TNY_FOLDER (instance))) {
381 type = modest_tny_folder_get_local_folder_type (TNY_FOLDER (instance));
382 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
384 fname = g_strdup(modest_local_folder_info_get_type_display_name (type));
388 /* Select the number to show: the unread or unsent messages */
389 if ((type == TNY_FOLDER_TYPE_DRAFTS) || (type == TNY_FOLDER_TYPE_OUTBOX))
394 /* Use bold font style if there are unread or unset messages */
396 item_name = g_strdup_printf ("%s (%d)", fname, number);
399 item_name = g_strdup (fname);
403 } else if (TNY_IS_ACCOUNT (instance)) {
404 /* If it's a server account */
405 if (modest_tny_account_is_virtual_local_folders (
406 TNY_ACCOUNT (instance))) {
407 item_name = g_strdup (priv->local_account_name);
409 } else if (modest_tny_account_is_memory_card_account (
410 TNY_ACCOUNT (instance))) {
411 /* fname is only correct when the items are first
412 * added to the model, not when the account is
413 * changed later, so get the name from the account
415 item_name = g_strdup (tny_account_get_name (
416 TNY_ACCOUNT (instance)));
419 item_name = g_strdup (fname);
425 item_name = g_strdup ("unknown");
427 if (item_name && item_weight) {
428 /* Set the name in the treeview cell: */
429 g_object_set (rendobj,"text", item_name, "weight", item_weight, NULL);
431 /* Notify display name observers */
432 /* TODO: What listens for this signal, and how can it use only the new name? */
433 if (G_OBJECT (priv->cur_folder_store) == instance) {
434 g_signal_emit (G_OBJECT(self),
435 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
443 /* If it is a Memory card account, make sure that we have the correct name.
444 * This function will be trigerred again when the name has been retrieved: */
445 if (TNY_IS_STORE_ACCOUNT (instance) &&
446 modest_tny_account_is_memory_card_account (TNY_ACCOUNT (instance))) {
448 /* Get the account name asynchronously: */
449 GetMmcAccountNameData *callback_data =
450 g_slice_new0(GetMmcAccountNameData);
451 callback_data->self = self;
453 const gchar *name = tny_account_get_name (TNY_ACCOUNT(instance));
455 callback_data->previous_name = g_strdup (name);
457 modest_tny_account_get_mmc_account_name (TNY_STORE_ACCOUNT (instance),
458 on_get_mmc_account_name, callback_data);
461 g_object_unref (G_OBJECT (instance));
468 icon_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
469 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
471 GObject *rendobj = NULL, *instance = NULL;
472 GdkPixbuf *pixbuf = NULL;
473 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
475 const gchar *account_id = NULL;
477 gboolean has_children;
479 rendobj = G_OBJECT(renderer);
480 gtk_tree_model_get (tree_model, iter,
481 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
482 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
483 TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
484 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
486 has_children = gtk_tree_model_iter_has_child (tree_model, iter);
496 /* MERGE is not needed anymore as the folder now has the correct type jschmid */
497 /* We include the MERGE type here because it's used to create
498 the local OUTBOX folder */
499 if (type == TNY_FOLDER_TYPE_NORMAL ||
500 type == TNY_FOLDER_TYPE_UNKNOWN) {
501 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
505 case TNY_FOLDER_TYPE_ROOT:
506 if (TNY_IS_ACCOUNT (instance)) {
508 if (modest_tny_account_is_virtual_local_folders (
509 TNY_ACCOUNT (instance))) {
510 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
513 account_id = tny_account_get_id (TNY_ACCOUNT (instance));
515 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
516 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
518 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
522 case TNY_FOLDER_TYPE_INBOX:
523 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
525 case TNY_FOLDER_TYPE_OUTBOX:
526 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
528 case TNY_FOLDER_TYPE_JUNK:
529 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
531 case TNY_FOLDER_TYPE_SENT:
532 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
534 case TNY_FOLDER_TYPE_TRASH:
535 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
537 case TNY_FOLDER_TYPE_DRAFTS:
538 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
540 case TNY_FOLDER_TYPE_NORMAL:
542 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
546 g_object_unref (G_OBJECT (instance));
550 g_object_set (rendobj, "pixbuf", pixbuf, NULL);
551 if (has_children && (pixbuf != NULL)) {
552 GdkPixbuf *open_pixbuf, *closed_pixbuf;
553 GdkPixbuf *open_emblem, *closed_emblem;
554 open_pixbuf = gdk_pixbuf_copy (pixbuf);
555 closed_pixbuf = gdk_pixbuf_copy (pixbuf);
556 open_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
557 closed_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
560 gdk_pixbuf_composite (open_emblem, open_pixbuf, 0, 0,
561 MIN (gdk_pixbuf_get_width (open_emblem),
562 gdk_pixbuf_get_width (open_pixbuf)),
563 MIN (gdk_pixbuf_get_height (open_emblem),
564 gdk_pixbuf_get_height (open_pixbuf)),
565 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
566 g_object_set (rendobj, "pixbuf-expander-open", open_pixbuf, NULL);
567 g_object_unref (open_emblem);
570 gdk_pixbuf_composite (closed_emblem, closed_pixbuf, 0, 0,
571 MIN (gdk_pixbuf_get_width (closed_emblem),
572 gdk_pixbuf_get_width (closed_pixbuf)),
573 MIN (gdk_pixbuf_get_height (closed_emblem),
574 gdk_pixbuf_get_height (closed_pixbuf)),
575 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
576 g_object_set (rendobj, "pixbuf-expander-closed", closed_pixbuf, NULL);
577 g_object_unref (closed_emblem);
580 g_object_unref (closed_pixbuf);
582 g_object_unref (open_pixbuf);
586 g_object_unref (pixbuf);
590 add_columns (GtkWidget *treeview)
592 GtkTreeViewColumn *column;
593 GtkCellRenderer *renderer;
594 GtkTreeSelection *sel;
597 column = gtk_tree_view_column_new ();
599 /* Set icon and text render function */
600 renderer = gtk_cell_renderer_pixbuf_new();
601 gtk_tree_view_column_pack_start (column, renderer, FALSE);
602 gtk_tree_view_column_set_cell_data_func(column, renderer,
603 icon_cell_data, treeview, NULL);
605 renderer = gtk_cell_renderer_text_new();
606 gtk_tree_view_column_pack_start (column, renderer, FALSE);
607 gtk_tree_view_column_set_cell_data_func(column, renderer,
608 text_cell_data, treeview, NULL);
610 /* Set selection mode */
611 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
612 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
614 /* Set treeview appearance */
615 gtk_tree_view_column_set_spacing (column, 2);
616 gtk_tree_view_column_set_resizable (column, TRUE);
617 gtk_tree_view_column_set_fixed_width (column, TRUE);
618 gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
619 gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
622 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
626 modest_folder_view_init (ModestFolderView *obj)
628 ModestFolderViewPrivate *priv;
631 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
633 priv->timer_expander = 0;
634 priv->account_store = NULL;
636 priv->style = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
637 priv->cur_folder_store = NULL;
638 priv->visible_account_id = NULL;
639 priv->folder_to_select = NULL;
641 /* Initialize the local account name */
642 conf = modest_runtime_get_conf();
643 priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
645 /* Init email clipboard */
646 priv->clipboard = modest_runtime_get_email_clipboard ();
647 priv->hidding_ids = NULL;
648 priv->n_selected = 0;
649 priv->reselect = FALSE;
650 priv->show_non_move = TRUE;
653 add_columns (GTK_WIDGET (obj));
655 /* Setup drag and drop */
656 setup_drag_and_drop (GTK_TREE_VIEW(obj));
658 /* Connect signals */
659 g_signal_connect (G_OBJECT (obj),
661 G_CALLBACK (on_key_pressed), NULL);
664 * Track changes in the local account name (in the device it
665 * will be the device name)
667 priv->conf_key_signal =
668 g_signal_connect (G_OBJECT(conf),
670 G_CALLBACK(on_configuration_key_changed), obj);
674 tny_account_store_view_init (gpointer g, gpointer iface_data)
676 TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
678 klass->set_account_store_func = modest_folder_view_set_account_store;
684 modest_folder_view_finalize (GObject *obj)
686 ModestFolderViewPrivate *priv;
687 GtkTreeSelection *sel;
689 g_return_if_fail (obj);
691 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
693 if (priv->timer_expander != 0) {
694 g_source_remove (priv->timer_expander);
695 priv->timer_expander = 0;
698 if (priv->account_store) {
699 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
700 priv->account_update_signal);
701 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
702 priv->accounts_reloaded_signal);
703 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
704 priv->account_removed_signal);
705 g_object_unref (G_OBJECT(priv->account_store));
706 priv->account_store = NULL;
710 g_object_unref (G_OBJECT (priv->query));
714 if (priv->folder_to_select) {
715 g_object_unref (G_OBJECT(priv->folder_to_select));
716 priv->folder_to_select = NULL;
719 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
721 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
723 g_free (priv->local_account_name);
724 g_free (priv->visible_account_id);
726 if (priv->conf_key_signal) {
727 g_signal_handler_disconnect (modest_runtime_get_conf (),
728 priv->conf_key_signal);
729 priv->conf_key_signal = 0;
732 if (priv->cur_folder_store) {
733 if (TNY_IS_FOLDER(priv->cur_folder_store))
734 tny_folder_sync (TNY_FOLDER(priv->cur_folder_store), FALSE, NULL);
735 /* FALSE --> expunge the message */
737 g_object_unref (priv->cur_folder_store);
738 priv->cur_folder_store = NULL;
741 /* Clear hidding array created by cut operation */
742 _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
744 G_OBJECT_CLASS(parent_class)->finalize (obj);
749 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
751 ModestFolderViewPrivate *priv;
754 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
755 g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
757 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
758 device = tny_account_store_get_device (account_store);
760 if (G_UNLIKELY (priv->account_store)) {
762 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
763 priv->account_update_signal))
764 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
765 priv->account_update_signal);
766 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
767 priv->accounts_reloaded_signal))
768 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
769 priv->accounts_reloaded_signal);
770 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
771 priv->account_removed_signal))
772 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
773 priv->account_removed_signal);
775 g_object_unref (G_OBJECT (priv->account_store));
778 priv->account_store = g_object_ref (G_OBJECT (account_store));
780 priv->account_update_signal =
781 g_signal_connect (G_OBJECT(account_store), "account_update",
782 G_CALLBACK (on_account_update), self);
784 priv->account_removed_signal =
785 g_signal_connect (G_OBJECT(account_store), "account_removed",
786 G_CALLBACK (on_account_removed), self);
788 priv->accounts_reloaded_signal =
789 g_signal_connect (G_OBJECT(account_store), "accounts_reloaded",
790 G_CALLBACK (on_accounts_reloaded), self);
792 g_signal_connect (G_OBJECT(account_store), "connecting_finished",
793 G_CALLBACK (on_accounts_reloaded), self);
795 on_accounts_reloaded (account_store, (gpointer ) self);
797 g_object_unref (G_OBJECT (device));
801 on_account_removed (TnyAccountStore *account_store,
805 ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
806 ModestFolderViewPrivate *priv;
808 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
810 /* If the removed account is the currently viewed one then
811 clear the configuration value. The new visible account will be the default account */
812 if (priv->visible_account_id &&
813 !strcmp (priv->visible_account_id, tny_account_get_id (account))) {
815 /* Clear the current visible account_id */
816 modest_folder_view_set_account_id_of_visible_server_account (self, NULL);
818 /* Call the restore method, this will set the new visible account */
819 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
820 MODEST_CONF_FOLDER_VIEW_KEY);
822 /* Select the INBOX */
823 modest_folder_view_select_first_inbox_or_local (self);
828 on_account_update (TnyAccountStore *account_store,
829 const gchar *account,
832 ModestFolderView *self = NULL;
833 ModestFolderViewPrivate *priv;
835 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
836 self = MODEST_FOLDER_VIEW (user_data);
837 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
839 /* If we're adding a new account, and there is no previous
840 one, we need to select the visible server account */
841 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
842 !priv->visible_account_id)
843 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
844 MODEST_CONF_FOLDER_VIEW_KEY);
846 if (!modest_folder_view_update_model (self, account_store))
847 g_printerr ("modest: failed to update model for changes in '%s'",
852 on_accounts_reloaded (TnyAccountStore *account_store,
855 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
856 modest_folder_view_update_model (MODEST_FOLDER_VIEW (user_data), account_store);
860 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
862 GtkTreeViewColumn *col;
864 g_return_if_fail (self);
866 col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
868 g_printerr ("modest: failed get column for title\n");
872 gtk_tree_view_column_set_title (col, title);
873 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
878 modest_folder_view_on_map (ModestFolderView *self,
879 GdkEventExpose *event,
882 ModestFolderViewPrivate *priv;
884 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
886 /* This won't happen often */
887 if (G_UNLIKELY (priv->reselect)) {
888 /* Select the first inbox or the local account if not found */
890 /* TODO: this could cause a lock at startup, so we
891 comment it for the moment. We know that this will
892 be a bug, because the INBOX is not selected, but we
893 need to rewrite some parts of Modest to avoid the
894 deathlock situation */
895 /* TODO: check if this is still the case */
896 priv->reselect = FALSE;
897 modest_folder_view_select_first_inbox_or_local (self);
903 modest_folder_view_new (TnyFolderStoreQuery *query)
906 ModestFolderViewPrivate *priv;
907 GtkTreeSelection *sel;
909 self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, NULL));
910 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
913 priv->query = g_object_ref (query);
915 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
916 priv->changed_signal = g_signal_connect (sel, "changed",
917 G_CALLBACK (on_selection_changed), self);
919 g_signal_connect (self, "expose-event", G_CALLBACK (modest_folder_view_on_map), NULL);
921 return GTK_WIDGET(self);
924 /* this feels dirty; any other way to expand all the root items? */
926 expand_root_items (ModestFolderView *self)
929 path = gtk_tree_path_new_first ();
931 /* all folders should have child items, so.. */
932 while (gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE))
933 gtk_tree_path_next (path);
935 gtk_tree_path_free (path);
939 * We use this function to implement the
940 * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
941 * account in this case, and the local folders.
944 filter_row (GtkTreeModel *model,
948 ModestFolderViewPrivate *priv;
949 gboolean retval = TRUE;
950 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
951 GObject *instance = NULL;
952 const gchar *id = NULL;
954 gboolean found = FALSE;
955 gboolean cleared = FALSE;
957 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE);
958 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
960 gtk_tree_model_get (model, iter,
961 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
962 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
965 /* Do not show if there is no instance, this could indeed
966 happen when the model is being modified while it's being
967 drawn. This could occur for example when moving folders
972 if (type == TNY_FOLDER_TYPE_ROOT) {
973 /* TNY_FOLDER_TYPE_ROOT means that the instance is an
974 account instead of a folder. */
975 if (TNY_IS_ACCOUNT (instance)) {
976 TnyAccount *acc = TNY_ACCOUNT (instance);
977 const gchar *account_id = tny_account_get_id (acc);
979 /* If it isn't a special folder,
980 * don't show it unless it is the visible account: */
981 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
982 !modest_tny_account_is_virtual_local_folders (acc) &&
983 strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
985 /* Show only the visible account id */
986 if (priv->visible_account_id) {
987 if (strcmp (account_id, priv->visible_account_id))
994 /* Never show these to the user. They are merged into one folder
995 * in the local-folders account instead: */
996 if (retval && MODEST_IS_TNY_OUTBOX_ACCOUNT (acc))
1001 /* Check hiding (if necessary) */
1002 cleared = modest_email_clipboard_cleared (priv->clipboard);
1003 if ((retval) && (!cleared) && (TNY_IS_FOLDER (instance))) {
1004 id = tny_folder_get_id (TNY_FOLDER(instance));
1005 if (priv->hidding_ids != NULL)
1006 for (i=0; i < priv->n_selected && !found; i++)
1007 if (priv->hidding_ids[i] != NULL && id != NULL)
1008 found = (!strcmp (priv->hidding_ids[i], id));
1014 /* If this is a move to dialog, hide Sent, Outbox and Drafts
1015 folder as no message can be move there according to UI specs */
1016 if (!priv->show_non_move)
1020 case TNY_FOLDER_TYPE_OUTBOX:
1021 case TNY_FOLDER_TYPE_SENT:
1022 case TNY_FOLDER_TYPE_DRAFTS:
1025 case TNY_FOLDER_TYPE_UNKNOWN:
1026 case TNY_FOLDER_TYPE_NORMAL:
1027 type = modest_tny_folder_guess_folder_type(TNY_FOLDER(instance));
1028 if (type == TNY_FOLDER_TYPE_OUTBOX || type == TNY_FOLDER_TYPE_SENT
1029 || type == TNY_FOLDER_TYPE_DRAFTS)
1040 g_object_unref (instance);
1047 modest_folder_view_update_model (ModestFolderView *self,
1048 TnyAccountStore *account_store)
1050 ModestFolderViewPrivate *priv;
1051 GtkTreeModel *model /* , *old_model */;
1052 /* TnyAccount *local_account; */
1053 TnyList *model_as_list;
1055 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
1056 g_return_val_if_fail (account_store, FALSE);
1058 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1060 /* Notify that there is no folder selected */
1061 g_signal_emit (G_OBJECT(self),
1062 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1064 if (priv->cur_folder_store) {
1065 g_object_unref (priv->cur_folder_store);
1066 priv->cur_folder_store = NULL;
1069 /* FIXME: the local accounts are not shown when the query
1070 selects only the subscribed folders. */
1071 /* model = tny_gtk_folder_store_tree_model_new (TRUE, priv->query); */
1072 model = tny_gtk_folder_store_tree_model_new (TRUE, NULL);
1074 /* Deal with the model via its TnyList Interface,
1075 * filling the TnyList via a get_accounts() call: */
1076 model_as_list = TNY_LIST(model);
1078 /* Get the accounts: */
1079 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
1081 TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
1082 g_object_unref (model_as_list);
1083 model_as_list = NULL;
1085 GtkTreeModel *filter_model = NULL, *sortable = NULL;
1087 sortable = gtk_tree_model_sort_new_with_model (model);
1088 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
1089 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1090 GTK_SORT_ASCENDING);
1091 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
1092 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1093 cmp_rows, NULL, NULL);
1095 /* Create filter model */
1096 filter_model = gtk_tree_model_filter_new (sortable, NULL);
1097 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
1103 gtk_tree_view_set_model (GTK_TREE_VIEW(self), filter_model);
1104 g_signal_connect (G_OBJECT(filter_model), "row-changed",
1105 (GCallback)on_row_changed_maybe_select_folder, self);
1106 g_signal_connect (G_OBJECT(filter_model), "row-inserted",
1107 (GCallback)on_row_changed_maybe_select_folder, self);
1110 g_object_unref (model);
1111 g_object_unref (filter_model);
1112 g_object_unref (sortable);
1114 /* Force a reselection of the INBOX next time the widget is shown */
1115 priv->reselect = TRUE;
1122 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
1124 GtkTreeModel *model;
1125 TnyFolderStore *folder = NULL;
1127 ModestFolderView *tree_view;
1128 ModestFolderViewPrivate *priv;
1130 g_return_if_fail (sel);
1131 g_return_if_fail (user_data);
1133 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
1135 if(!gtk_tree_selection_get_selected (sel, &model, &iter))
1138 /* Notify the display name observers */
1139 g_signal_emit (G_OBJECT(user_data),
1140 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1143 tree_view = MODEST_FOLDER_VIEW (user_data);
1144 gtk_tree_model_get (model, &iter,
1145 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1148 /* If the folder is the same do not notify */
1149 if (priv->cur_folder_store == folder && folder) {
1150 g_object_unref (folder);
1154 /* Current folder was unselected */
1155 if (priv->cur_folder_store) {
1156 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1157 priv->cur_folder_store, FALSE);
1159 if (TNY_IS_FOLDER(priv->cur_folder_store))
1160 tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
1161 FALSE, NULL, NULL, NULL);
1162 /* FALSE --> don't expunge the messages */
1164 g_object_unref (priv->cur_folder_store);
1165 priv->cur_folder_store = NULL;
1168 /* New current references */
1169 priv->cur_folder_store = folder;
1171 /* New folder has been selected */
1172 g_signal_emit (G_OBJECT(tree_view),
1173 signals[FOLDER_SELECTION_CHANGED_SIGNAL],
1174 0, priv->cur_folder_store, TRUE);
1178 modest_folder_view_get_selected (ModestFolderView *self)
1180 ModestFolderViewPrivate *priv;
1182 g_return_val_if_fail (self, NULL);
1184 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1185 if (priv->cur_folder_store)
1186 g_object_ref (priv->cur_folder_store);
1188 return priv->cur_folder_store;
1192 get_cmp_rows_type_pos (GObject *folder)
1194 /* Remote accounts -> Local account -> MMC account .*/
1197 if (TNY_IS_ACCOUNT (folder) &&
1198 modest_tny_account_is_virtual_local_folders (
1199 TNY_ACCOUNT (folder))) {
1201 } else if (TNY_IS_ACCOUNT (folder)) {
1202 TnyAccount *account = TNY_ACCOUNT (folder);
1203 const gchar *account_id = tny_account_get_id (account);
1204 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
1210 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
1211 return -1; /* Should never happen */
1216 get_cmp_subfolder_type_pos (TnyFolderType t)
1218 /* Inbox, Outbox, Drafts, Sent, User */
1222 case TNY_FOLDER_TYPE_INBOX:
1225 case TNY_FOLDER_TYPE_OUTBOX:
1228 case TNY_FOLDER_TYPE_DRAFTS:
1231 case TNY_FOLDER_TYPE_SENT:
1240 * This function orders the mail accounts according to these rules:
1241 * 1st - remote accounts
1242 * 2nd - local account
1246 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
1250 gchar *name1 = NULL;
1251 gchar *name2 = NULL;
1252 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1253 TnyFolderType type2 = TNY_FOLDER_TYPE_UNKNOWN;
1254 GObject *folder1 = NULL;
1255 GObject *folder2 = NULL;
1257 gtk_tree_model_get (tree_model, iter1,
1258 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
1259 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
1260 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
1262 gtk_tree_model_get (tree_model, iter2,
1263 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
1264 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type2,
1265 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
1268 /* Return if we get no folder. This could happen when folder
1269 operations are happening. The model is updated after the
1270 folder copy/move actually occurs, so there could be
1271 situations where the model to be drawn is not correct */
1272 if (!folder1 || !folder2)
1275 if (type == TNY_FOLDER_TYPE_ROOT) {
1276 /* Compare the types, so that
1277 * Remote accounts -> Local account -> MMC account .*/
1278 const gint pos1 = get_cmp_rows_type_pos (folder1);
1279 const gint pos2 = get_cmp_rows_type_pos (folder2);
1280 /* printf ("DEBUG: %s:\n type1=%s, pos1=%d\n type2=%s, pos2=%d\n",
1281 __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
1284 else if (pos1 > pos2)
1287 /* Compare items of the same type: */
1289 TnyAccount *account1 = NULL;
1290 if (TNY_IS_ACCOUNT (folder1))
1291 account1 = TNY_ACCOUNT (folder1);
1293 TnyAccount *account2 = NULL;
1294 if (TNY_IS_ACCOUNT (folder2))
1295 account2 = TNY_ACCOUNT (folder2);
1297 const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
1298 const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
1300 if (!account_id && !account_id2) {
1302 } else if (!account_id) {
1304 } else if (!account_id2) {
1306 } else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1309 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1313 gint cmp1 = 0, cmp2 = 0;
1314 /* get the parent to know if it's a local folder */
1317 gboolean has_parent;
1318 has_parent = gtk_tree_model_iter_parent (tree_model, &parent, iter1);
1320 GObject *parent_folder;
1321 TnyFolderType parent_type = TNY_FOLDER_TYPE_UNKNOWN;
1322 gtk_tree_model_get (tree_model, &parent,
1323 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &parent_type,
1324 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &parent_folder,
1326 if ((parent_type == TNY_FOLDER_TYPE_ROOT) &&
1327 TNY_IS_ACCOUNT (parent_folder) &&
1328 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent_folder))) {
1329 cmp1 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_folder_type (TNY_FOLDER (folder1)));
1330 cmp2 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_folder_type (TNY_FOLDER (folder2)));
1332 g_object_unref (parent_folder);
1335 /* if they are not local folders */
1337 cmp1 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder1)));
1338 cmp2 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder2)));
1342 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1344 cmp = (cmp1 - cmp2);
1349 g_object_unref(G_OBJECT(folder1));
1351 g_object_unref(G_OBJECT(folder2));
1359 /*****************************************************************************/
1360 /* DRAG and DROP stuff */
1361 /*****************************************************************************/
1364 * This function fills the #GtkSelectionData with the row and the
1365 * model that has been dragged. It's called when this widget is a
1366 * source for dnd after the event drop happened
1369 on_drag_data_get (GtkWidget *widget,
1370 GdkDragContext *context,
1371 GtkSelectionData *selection_data,
1376 GtkTreeSelection *selection;
1377 GtkTreeModel *model;
1379 GtkTreePath *source_row;
1381 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1382 gtk_tree_selection_get_selected (selection, &model, &iter);
1383 source_row = gtk_tree_model_get_path (model, &iter);
1385 gtk_tree_set_row_drag_data (selection_data,
1389 gtk_tree_path_free (source_row);
1392 typedef struct _DndHelper {
1393 gboolean delete_source;
1394 GtkTreePath *source_row;
1395 GdkDragContext *context;
1401 * This function is the callback of the
1402 * modest_mail_operation_xfer_msgs () and
1403 * modest_mail_operation_xfer_folder() calls. We check here if the
1404 * message/folder was correctly asynchronously transferred. The reason
1405 * to use the same callback is that the code is the same, it only has
1406 * to check that the operation went fine and then finalize the drag
1410 on_progress_changed (ModestMailOperation *mail_op,
1411 ModestMailOperationState *state,
1417 helper = (DndHelper *) user_data;
1419 if (!state->finished)
1422 if (state->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
1428 /* Notify the drag source. Never call delete, the monitor will
1429 do the job if needed */
1430 gtk_drag_finish (helper->context, success, FALSE, helper->time);
1432 /* Free the helper */
1433 gtk_tree_path_free (helper->source_row);
1434 g_slice_free (DndHelper, helper);
1438 * This function is used by drag_data_received_cb to manage drag and
1439 * drop of a header, i.e, and drag from the header view to the folder
1443 drag_and_drop_from_header_view (GtkTreeModel *source_model,
1444 GtkTreeModel *dest_model,
1445 GtkTreePath *dest_row,
1448 TnyList *headers = NULL;
1449 TnyHeader *header = NULL;
1450 TnyFolder *folder = NULL;
1451 ModestMailOperation *mail_op = NULL;
1452 GtkTreeIter source_iter, dest_iter;
1454 g_return_if_fail (GTK_IS_TREE_MODEL(source_model));
1455 g_return_if_fail (GTK_IS_TREE_MODEL(dest_model));
1456 g_return_if_fail (dest_row);
1457 g_return_if_fail (helper);
1460 gtk_tree_model_get_iter (source_model, &source_iter, helper->source_row);
1461 gtk_tree_model_get (source_model, &source_iter,
1462 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1464 if (!TNY_IS_HEADER(header)) {
1465 g_warning ("BUG: %s could not get a valid header", __FUNCTION__);
1470 gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
1471 gtk_tree_model_get (dest_model, &dest_iter,
1472 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1475 if (!TNY_IS_FOLDER(folder)) {
1476 g_warning ("BUG: %s could not get a valid folder", __FUNCTION__);
1480 /* Transfer message */
1481 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1483 modest_ui_actions_move_folder_error_handler,
1485 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1487 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1488 G_CALLBACK (on_progress_changed), helper);
1490 headers = tny_simple_list_new ();
1491 tny_list_append (headers, G_OBJECT (header));
1492 modest_mail_operation_xfer_msgs (mail_op,
1495 helper->delete_source,
1500 if (G_IS_OBJECT(mail_op))
1501 g_object_unref (G_OBJECT (mail_op));
1502 if (G_IS_OBJECT(header))
1503 g_object_unref (G_OBJECT (header));
1504 if (G_IS_OBJECT(folder))
1505 g_object_unref (G_OBJECT (folder));
1506 if (G_IS_OBJECT(headers))
1507 g_object_unref (headers);
1511 * This function is used by drag_data_received_cb to manage drag and
1512 * drop of a folder, i.e, and drag from the folder view to the same
1516 drag_and_drop_from_folder_view (GtkTreeModel *source_model,
1517 GtkTreeModel *dest_model,
1518 GtkTreePath *dest_row,
1519 GtkSelectionData *selection_data,
1522 ModestMailOperation *mail_op = NULL;
1523 GtkTreeIter parent_iter, iter;
1524 TnyFolderStore *parent_folder = NULL;
1525 TnyFolder *folder = NULL;
1527 /* Check if the drag is possible */
1528 /* if (!gtk_tree_path_compare (helper->source_row, dest_row) || */
1529 /* !gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (dest_model), */
1531 /* selection_data)) { */
1532 if (!gtk_tree_path_compare (helper->source_row, dest_row)) {
1534 gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
1535 gtk_tree_path_free (helper->source_row);
1536 g_slice_free (DndHelper, helper);
1541 gtk_tree_model_get_iter (source_model, &parent_iter, dest_row);
1542 gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
1543 gtk_tree_model_get (source_model, &parent_iter,
1544 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1545 &parent_folder, -1);
1546 gtk_tree_model_get (source_model, &iter,
1547 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1550 /* Offer the connection dialog if necessary, for the destination parent folder and source folder: */
1551 if (modest_platform_connect_and_wait_if_network_folderstore (NULL, parent_folder) &&
1552 modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
1553 /* Do the mail operation */
1554 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1556 modest_ui_actions_move_folder_error_handler,
1558 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1560 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1561 G_CALLBACK (on_progress_changed), helper);
1563 modest_mail_operation_xfer_folder (mail_op,
1566 helper->delete_source,
1570 g_object_unref (G_OBJECT (mail_op));
1574 g_object_unref (G_OBJECT (parent_folder));
1575 g_object_unref (G_OBJECT (folder));
1579 * This function receives the data set by the "drag-data-get" signal
1580 * handler. This information comes within the #GtkSelectionData. This
1581 * function will manage both the drags of folders of the treeview and
1582 * drags of headers of the header view widget.
1585 on_drag_data_received (GtkWidget *widget,
1586 GdkDragContext *context,
1589 GtkSelectionData *selection_data,
1594 GtkWidget *source_widget;
1595 GtkTreeModel *dest_model, *source_model;
1596 GtkTreePath *source_row, *dest_row;
1597 GtkTreeViewDropPosition pos;
1598 gboolean success = FALSE, delete_source = FALSE;
1599 DndHelper *helper = NULL;
1601 /* Do not allow further process */
1602 g_signal_stop_emission_by_name (widget, "drag-data-received");
1603 source_widget = gtk_drag_get_source_widget (context);
1605 /* Get the action */
1606 if (context->action == GDK_ACTION_MOVE) {
1607 delete_source = TRUE;
1609 /* Notify that there is no folder selected. We need to
1610 do this in order to update the headers view (and
1611 its monitors, because when moving, the old folder
1612 won't longer exist. We can not wait for the end of
1613 the operation, because the operation won't start if
1614 the folder is in use */
1615 if (source_widget == widget) {
1616 ModestFolderViewPrivate *priv;
1618 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1619 if (priv->cur_folder_store) {
1620 g_object_unref (priv->cur_folder_store);
1621 priv->cur_folder_store = NULL;
1624 g_signal_emit (G_OBJECT (widget),
1625 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0, NULL, FALSE);
1629 /* Check if the get_data failed */
1630 if (selection_data == NULL || selection_data->length < 0)
1631 gtk_drag_finish (context, success, FALSE, time);
1633 /* Get the models */
1634 gtk_tree_get_row_drag_data (selection_data,
1638 /* Select the destination model */
1639 if (source_widget == widget) {
1640 dest_model = source_model;
1642 dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1645 /* Get the path to the destination row. Can not call
1646 gtk_tree_view_get_drag_dest_row() because the source row
1647 is not selected anymore */
1648 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
1651 /* Only allow drops IN other rows */
1652 if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER)
1653 gtk_drag_finish (context, success, FALSE, time);
1655 /* Create the helper */
1656 helper = g_slice_new0 (DndHelper);
1657 helper->delete_source = delete_source;
1658 helper->source_row = gtk_tree_path_copy (source_row);
1659 helper->context = context;
1660 helper->time = time;
1662 /* Drags from the header view */
1663 if (source_widget != widget) {
1665 drag_and_drop_from_header_view (source_model,
1672 drag_and_drop_from_folder_view (source_model,
1680 gtk_tree_path_free (source_row);
1681 gtk_tree_path_free (dest_row);
1685 * We define a "drag-drop" signal handler because we do not want to
1686 * use the default one, because the default one always calls
1687 * gtk_drag_finish and we prefer to do it in the "drag-data-received"
1688 * signal handler, because there we have all the information available
1689 * to know if the dnd was a success or not.
1692 drag_drop_cb (GtkWidget *widget,
1693 GdkDragContext *context,
1701 if (!context->targets)
1704 /* Check if we're dragging a folder row */
1705 target = gtk_drag_dest_find_target (widget, context, NULL);
1707 /* Request the data from the source. */
1708 gtk_drag_get_data(widget, context, target, time);
1714 * This function expands a node of a tree view if it's not expanded
1715 * yet. Not sure why it needs the threads stuff, but gtk+`example code
1716 * does that, so that's why they're here.
1719 expand_row_timeout (gpointer data)
1721 GtkTreeView *tree_view = data;
1722 GtkTreePath *dest_path = NULL;
1723 GtkTreeViewDropPosition pos;
1724 gboolean result = FALSE;
1726 GDK_THREADS_ENTER ();
1728 gtk_tree_view_get_drag_dest_row (tree_view,
1733 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
1734 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
1735 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
1736 gtk_tree_path_free (dest_path);
1740 gtk_tree_path_free (dest_path);
1745 GDK_THREADS_LEAVE ();
1751 * This function is called whenever the pointer is moved over a widget
1752 * while dragging some data. It installs a timeout that will expand a
1753 * node of the treeview if not expanded yet. This function also calls
1754 * gdk_drag_status in order to set the suggested action that will be
1755 * used by the "drag-data-received" signal handler to know if we
1756 * should do a move or just a copy of the data.
1759 on_drag_motion (GtkWidget *widget,
1760 GdkDragContext *context,
1766 GtkTreeViewDropPosition pos;
1767 GtkTreePath *dest_row;
1768 ModestFolderViewPrivate *priv;
1769 GdkDragAction suggested_action;
1770 gboolean valid_location = FALSE;
1772 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1774 if (priv->timer_expander != 0) {
1775 g_source_remove (priv->timer_expander);
1776 priv->timer_expander = 0;
1779 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
1784 /* Do not allow drops between folders */
1786 pos == GTK_TREE_VIEW_DROP_BEFORE ||
1787 pos == GTK_TREE_VIEW_DROP_AFTER) {
1788 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
1789 gdk_drag_status(context, 0, time);
1790 valid_location = FALSE;
1793 valid_location = TRUE;
1796 /* Expand the selected row after 1/2 second */
1797 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
1798 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
1799 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
1802 /* Select the desired action. By default we pick MOVE */
1803 suggested_action = GDK_ACTION_MOVE;
1805 if (context->actions == GDK_ACTION_COPY)
1806 gdk_drag_status(context, GDK_ACTION_COPY, time);
1807 else if (context->actions == GDK_ACTION_MOVE)
1808 gdk_drag_status(context, GDK_ACTION_MOVE, time);
1809 else if (context->actions & suggested_action)
1810 gdk_drag_status(context, suggested_action, time);
1812 gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
1816 gtk_tree_path_free (dest_row);
1817 g_signal_stop_emission_by_name (widget, "drag-motion");
1818 return valid_location;
1822 /* Folder view drag types */
1823 const GtkTargetEntry folder_view_drag_types[] =
1825 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
1826 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
1830 * This function sets the treeview as a source and a target for dnd
1831 * events. It also connects all the requirede signals.
1834 setup_drag_and_drop (GtkTreeView *self)
1836 /* Set up the folder view as a dnd destination. Set only the
1837 highlight flag, otherwise gtk will have a different
1839 gtk_drag_dest_set (GTK_WIDGET (self),
1840 GTK_DEST_DEFAULT_HIGHLIGHT,
1841 folder_view_drag_types,
1842 G_N_ELEMENTS (folder_view_drag_types),
1843 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1845 g_signal_connect (G_OBJECT (self),
1846 "drag_data_received",
1847 G_CALLBACK (on_drag_data_received),
1851 /* Set up the treeview as a dnd source */
1852 gtk_drag_source_set (GTK_WIDGET (self),
1854 folder_view_drag_types,
1855 G_N_ELEMENTS (folder_view_drag_types),
1856 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1858 g_signal_connect (G_OBJECT (self),
1860 G_CALLBACK (on_drag_motion),
1863 g_signal_connect (G_OBJECT (self),
1865 G_CALLBACK (on_drag_data_get),
1868 g_signal_connect (G_OBJECT (self),
1870 G_CALLBACK (drag_drop_cb),
1875 * This function manages the navigation through the folders using the
1876 * keyboard or the hardware keys in the device
1879 on_key_pressed (GtkWidget *self,
1883 GtkTreeSelection *selection;
1885 GtkTreeModel *model;
1886 gboolean retval = FALSE;
1888 /* Up and Down are automatically managed by the treeview */
1889 if (event->keyval == GDK_Return) {
1890 /* Expand/Collapse the selected row */
1891 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1892 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1895 path = gtk_tree_model_get_path (model, &iter);
1897 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
1898 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
1900 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
1901 gtk_tree_path_free (path);
1903 /* No further processing */
1911 * We listen to the changes in the local folder account name key,
1912 * because we want to show the right name in the view. The local
1913 * folder account name corresponds to the device name in the Maemo
1914 * version. We do this because we do not want to query gconf on each
1915 * tree view refresh. It's better to cache it and change whenever
1919 on_configuration_key_changed (ModestConf* conf,
1921 ModestConfEvent event,
1922 ModestFolderView *self)
1924 ModestFolderViewPrivate *priv;
1929 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1930 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1932 if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
1933 g_free (priv->local_account_name);
1935 if (event == MODEST_CONF_EVENT_KEY_UNSET)
1936 priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
1938 priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
1939 MODEST_CONF_DEVICE_NAME, NULL);
1941 /* Force a redraw */
1942 #if GTK_CHECK_VERSION(2, 8, 0) /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
1943 GtkTreeViewColumn * tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
1944 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
1945 gtk_tree_view_column_queue_resize (tree_column);
1951 modest_folder_view_set_style (ModestFolderView *self,
1952 ModestFolderViewStyle style)
1954 ModestFolderViewPrivate *priv;
1956 g_return_if_fail (self);
1958 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1960 priv->style = style;
1964 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
1965 const gchar *account_id)
1967 ModestFolderViewPrivate *priv;
1968 GtkTreeModel *model;
1970 g_return_if_fail (self);
1972 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1974 /* This will be used by the filter_row callback,
1975 * to decided which rows to show: */
1976 if (priv->visible_account_id) {
1977 g_free (priv->visible_account_id);
1978 priv->visible_account_id = NULL;
1981 priv->visible_account_id = g_strdup (account_id);
1984 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1985 if (GTK_IS_TREE_MODEL_FILTER (model))
1986 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
1988 /* Save settings to gconf */
1989 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
1990 MODEST_CONF_FOLDER_VIEW_KEY);
1994 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
1996 ModestFolderViewPrivate *priv;
1998 g_return_val_if_fail (self, NULL);
2000 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2002 return (const gchar *) priv->visible_account_id;
2006 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
2010 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2013 gtk_tree_model_get (model, iter,
2014 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2015 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN,
2018 gboolean result = FALSE;
2019 if (type == TNY_FOLDER_TYPE_INBOX) {
2021 } else if (type == TNY_FOLDER_TYPE_NORMAL) {
2022 /* tinymail's camel implementation only provides TNY_FOLDER_TYPE_NORMAL
2023 * when getting folders from the cache, before connectin, so we do
2024 * an extra check. We could fix this in tinymail, but it's easier
2027 if (strcmp (name, "Inbox") == 0)
2034 *inbox_iter = *iter;
2038 if (gtk_tree_model_iter_children (model, &child, iter)) {
2039 if (find_inbox_iter (model, &child, inbox_iter))
2043 } while (gtk_tree_model_iter_next (model, iter));
2052 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
2054 GtkTreeModel *model;
2055 GtkTreeIter iter, inbox_iter;
2056 GtkTreeSelection *sel;
2058 /* /\* Do not set it if the folder view was not painted *\/ */
2059 /* if (!GTK_WIDGET_MAPPED (self)) */
2062 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2066 expand_root_items (self);
2067 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2069 gtk_tree_model_get_iter_first (model, &iter);
2070 gtk_tree_selection_unselect_all (sel);
2072 if (find_inbox_iter (model, &iter, &inbox_iter)) {
2073 gtk_tree_selection_select_iter (sel, &inbox_iter);
2076 gtk_tree_model_get_iter_first (model, &iter);
2077 gtk_tree_selection_select_iter (sel, &iter);
2084 find_folder_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *folder_iter,
2089 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2090 TnyFolder* a_folder;
2093 gtk_tree_model_get (model, iter,
2094 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &a_folder,
2095 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2096 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
2099 g_debug ("===> %s (%p ---- %p)", name, a_folder, folder);
2102 if (folder == a_folder) {
2103 g_object_unref (a_folder);
2104 *folder_iter = *iter;
2107 g_object_unref (a_folder);
2109 if (gtk_tree_model_iter_children (model, &child, iter)) {
2110 if (find_folder_iter (model, &child, folder_iter, folder))
2114 } while (gtk_tree_model_iter_next (model, iter));
2121 on_row_changed_maybe_select_folder (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter,
2122 ModestFolderView *self)
2124 ModestFolderViewPrivate *priv = NULL;
2125 GtkTreeSelection *sel;
2127 if (!MODEST_IS_FOLDER_VIEW(self))
2130 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2132 if (priv->folder_to_select) {
2134 if (!modest_folder_view_select_folder (self, priv->folder_to_select,
2137 path = gtk_tree_model_get_path (tree_model, iter);
2138 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2140 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2142 gtk_tree_selection_select_iter (sel, iter);
2143 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2145 gtk_tree_path_free (path);
2148 g_object_unref (priv->folder_to_select);
2149 priv->folder_to_select = NULL;
2155 modest_folder_view_select_folder (ModestFolderView *self, TnyFolder *folder,
2156 gboolean after_change)
2158 GtkTreeModel *model;
2159 GtkTreeIter iter, folder_iter;
2160 GtkTreeSelection *sel;
2161 ModestFolderViewPrivate *priv = NULL;
2163 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
2164 g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE);
2166 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2170 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2171 gtk_tree_selection_unselect_all (sel);
2173 if (priv->folder_to_select)
2174 g_object_unref(priv->folder_to_select);
2175 priv->folder_to_select = TNY_FOLDER(g_object_ref(folder));
2179 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2184 gtk_tree_model_get_iter_first (model, &iter);
2185 if (find_folder_iter (model, &iter, &folder_iter, folder)) {
2188 path = gtk_tree_model_get_path (model, &folder_iter);
2189 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2191 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2192 gtk_tree_selection_select_iter (sel, &folder_iter);
2193 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2195 gtk_tree_path_free (path);
2203 modest_folder_view_copy_selection (ModestFolderView *folder_view)
2205 /* Copy selection */
2206 _clipboard_set_selected_data (folder_view, FALSE);
2210 modest_folder_view_cut_selection (ModestFolderView *folder_view)
2212 ModestFolderViewPrivate *priv = NULL;
2213 GtkTreeModel *model = NULL;
2214 const gchar **hidding = NULL;
2215 guint i, n_selected;
2217 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2218 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2220 /* Copy selection */
2221 if (!_clipboard_set_selected_data (folder_view, TRUE))
2224 /* Get hidding ids */
2225 hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected);
2227 /* Clear hidding array created by previous cut operation */
2228 _clear_hidding_filter (MODEST_FOLDER_VIEW (folder_view));
2230 /* Copy hidding array */
2231 priv->n_selected = n_selected;
2232 priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected);
2233 for (i=0; i < n_selected; i++)
2234 priv->hidding_ids[i] = g_strdup(hidding[i]);
2236 /* Hide cut folders */
2237 model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
2238 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2242 modest_folder_view_show_non_move_folders (ModestFolderView *folder_view,
2245 ModestFolderViewPrivate* priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2246 priv->show_non_move = show;
2247 modest_folder_view_update_model(folder_view,
2248 TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
2251 /* Returns FALSE if it did not selected anything */
2253 _clipboard_set_selected_data (ModestFolderView *folder_view,
2256 ModestFolderViewPrivate *priv = NULL;
2257 TnyFolderStore *folder = NULL;
2258 gboolean retval = FALSE;
2260 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (folder_view), FALSE);
2261 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2263 /* Set selected data on clipboard */
2264 g_return_val_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard), FALSE);
2265 folder = modest_folder_view_get_selected (folder_view);
2267 /* Do not allow to select an account */
2268 if (TNY_IS_FOLDER (folder)) {
2269 modest_email_clipboard_set_data (priv->clipboard, TNY_FOLDER(folder), NULL, delete);
2274 g_object_unref (folder);
2280 _clear_hidding_filter (ModestFolderView *folder_view)
2282 ModestFolderViewPrivate *priv;
2285 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2286 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2288 if (priv->hidding_ids != NULL) {
2289 for (i=0; i < priv->n_selected; i++)
2290 g_free (priv->hidding_ids[i]);
2291 g_free(priv->hidding_ids);