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 modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance))) {
382 type = modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (instance));
383 if (type != TNY_FOLDER_TYPE_UNKNOWN) {
385 fname = g_strdup(modest_local_folder_info_get_type_display_name (type));
389 /* Select the number to show: the unread or unsent messages */
390 if ((type == TNY_FOLDER_TYPE_DRAFTS) || (type == TNY_FOLDER_TYPE_OUTBOX))
395 /* Use bold font style if there are unread or unset messages */
397 item_name = g_strdup_printf ("%s (%d)", fname, number);
400 item_name = g_strdup (fname);
404 } else if (TNY_IS_ACCOUNT (instance)) {
405 /* If it's a server account */
406 if (modest_tny_account_is_virtual_local_folders (
407 TNY_ACCOUNT (instance))) {
408 item_name = g_strdup (priv->local_account_name);
410 } else if (modest_tny_account_is_memory_card_account (
411 TNY_ACCOUNT (instance))) {
412 /* fname is only correct when the items are first
413 * added to the model, not when the account is
414 * changed later, so get the name from the account
416 item_name = g_strdup (tny_account_get_name (
417 TNY_ACCOUNT (instance)));
420 item_name = g_strdup (fname);
426 item_name = g_strdup ("unknown");
428 if (item_name && item_weight) {
429 /* Set the name in the treeview cell: */
430 g_object_set (rendobj,"text", item_name, "weight", item_weight, NULL);
432 /* Notify display name observers */
433 /* TODO: What listens for this signal, and how can it use only the new name? */
434 if (G_OBJECT (priv->cur_folder_store) == instance) {
435 g_signal_emit (G_OBJECT(self),
436 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));
466 icon_cell_data (GtkTreeViewColumn *column, GtkCellRenderer *renderer,
467 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
469 GObject *rendobj = NULL, *instance = NULL;
470 GdkPixbuf *pixbuf = NULL;
471 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
473 const gchar *account_id = NULL;
475 gboolean has_children;
477 rendobj = G_OBJECT(renderer);
478 gtk_tree_model_get (tree_model, iter,
479 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
480 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &fname,
481 TNY_GTK_FOLDER_STORE_TREE_MODEL_UNREAD_COLUMN, &unread,
482 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
484 has_children = gtk_tree_model_iter_has_child (tree_model, iter);
494 /* MERGE is not needed anymore as the folder now has the correct type jschmid */
495 /* We include the MERGE type here because it's used to create
496 the local OUTBOX folder */
497 if (type == TNY_FOLDER_TYPE_NORMAL ||
498 type == TNY_FOLDER_TYPE_UNKNOWN) {
499 type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
503 case TNY_FOLDER_TYPE_ROOT:
504 if (TNY_IS_ACCOUNT (instance)) {
506 if (modest_tny_account_is_virtual_local_folders (
507 TNY_ACCOUNT (instance))) {
508 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_LOCAL_FOLDERS);
511 account_id = tny_account_get_id (TNY_ACCOUNT (instance));
513 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
514 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_MMC);
516 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_ACCOUNT);
520 case TNY_FOLDER_TYPE_INBOX:
521 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_INBOX);
523 case TNY_FOLDER_TYPE_OUTBOX:
524 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_OUTBOX);
526 case TNY_FOLDER_TYPE_JUNK:
527 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_JUNK);
529 case TNY_FOLDER_TYPE_SENT:
530 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_SENT);
532 case TNY_FOLDER_TYPE_TRASH:
533 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_TRASH);
535 case TNY_FOLDER_TYPE_DRAFTS:
536 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_DRAFTS);
538 case TNY_FOLDER_TYPE_NORMAL:
540 pixbuf = modest_platform_get_icon (MODEST_FOLDER_ICON_NORMAL);
544 g_object_unref (G_OBJECT (instance));
548 g_object_set (rendobj, "pixbuf", pixbuf, NULL);
549 if (has_children && (pixbuf != NULL)) {
550 GdkPixbuf *open_pixbuf, *closed_pixbuf;
551 GdkPixbuf *open_emblem, *closed_emblem;
552 open_pixbuf = gdk_pixbuf_copy (pixbuf);
553 closed_pixbuf = gdk_pixbuf_copy (pixbuf);
554 open_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_exp");
555 closed_emblem = modest_platform_get_icon ("qgn_list_gene_fldr_clp");
558 gdk_pixbuf_composite (open_emblem, open_pixbuf, 0, 0,
559 MIN (gdk_pixbuf_get_width (open_emblem),
560 gdk_pixbuf_get_width (open_pixbuf)),
561 MIN (gdk_pixbuf_get_height (open_emblem),
562 gdk_pixbuf_get_height (open_pixbuf)),
563 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
564 g_object_set (rendobj, "pixbuf-expander-open", open_pixbuf, NULL);
565 g_object_unref (open_emblem);
568 gdk_pixbuf_composite (closed_emblem, closed_pixbuf, 0, 0,
569 MIN (gdk_pixbuf_get_width (closed_emblem),
570 gdk_pixbuf_get_width (closed_pixbuf)),
571 MIN (gdk_pixbuf_get_height (closed_emblem),
572 gdk_pixbuf_get_height (closed_pixbuf)),
573 0, 0, 1, 1, GDK_INTERP_NEAREST, 255);
574 g_object_set (rendobj, "pixbuf-expander-closed", closed_pixbuf, NULL);
575 g_object_unref (closed_emblem);
578 g_object_unref (closed_pixbuf);
580 g_object_unref (open_pixbuf);
584 g_object_unref (pixbuf);
588 add_columns (GtkWidget *treeview)
590 GtkTreeViewColumn *column;
591 GtkCellRenderer *renderer;
592 GtkTreeSelection *sel;
595 column = gtk_tree_view_column_new ();
597 /* Set icon and text render function */
598 renderer = gtk_cell_renderer_pixbuf_new();
599 gtk_tree_view_column_pack_start (column, renderer, FALSE);
600 gtk_tree_view_column_set_cell_data_func(column, renderer,
601 icon_cell_data, treeview, NULL);
603 renderer = gtk_cell_renderer_text_new();
604 gtk_tree_view_column_pack_start (column, renderer, FALSE);
605 gtk_tree_view_column_set_cell_data_func(column, renderer,
606 text_cell_data, treeview, NULL);
608 /* Set selection mode */
609 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(treeview));
610 gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
612 /* Set treeview appearance */
613 gtk_tree_view_column_set_spacing (column, 2);
614 gtk_tree_view_column_set_resizable (column, TRUE);
615 gtk_tree_view_column_set_fixed_width (column, TRUE);
616 gtk_tree_view_set_headers_clickable (GTK_TREE_VIEW(treeview), FALSE);
617 gtk_tree_view_set_enable_search (GTK_TREE_VIEW(treeview), FALSE);
620 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview),column);
624 modest_folder_view_init (ModestFolderView *obj)
626 ModestFolderViewPrivate *priv;
629 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
631 priv->timer_expander = 0;
632 priv->account_store = NULL;
634 priv->style = MODEST_FOLDER_VIEW_STYLE_SHOW_ALL;
635 priv->cur_folder_store = NULL;
636 priv->visible_account_id = NULL;
637 priv->folder_to_select = NULL;
639 /* Initialize the local account name */
640 conf = modest_runtime_get_conf();
641 priv->local_account_name = modest_conf_get_string (conf, MODEST_CONF_DEVICE_NAME, NULL);
643 /* Init email clipboard */
644 priv->clipboard = modest_runtime_get_email_clipboard ();
645 priv->hidding_ids = NULL;
646 priv->n_selected = 0;
647 priv->reselect = FALSE;
648 priv->show_non_move = TRUE;
651 add_columns (GTK_WIDGET (obj));
653 /* Setup drag and drop */
654 setup_drag_and_drop (GTK_TREE_VIEW(obj));
656 /* Connect signals */
657 g_signal_connect (G_OBJECT (obj),
659 G_CALLBACK (on_key_pressed), NULL);
662 * Track changes in the local account name (in the device it
663 * will be the device name)
665 priv->conf_key_signal =
666 g_signal_connect (G_OBJECT(conf),
668 G_CALLBACK(on_configuration_key_changed), obj);
672 tny_account_store_view_init (gpointer g, gpointer iface_data)
674 TnyAccountStoreViewIface *klass = (TnyAccountStoreViewIface *)g;
676 klass->set_account_store_func = modest_folder_view_set_account_store;
682 modest_folder_view_finalize (GObject *obj)
684 ModestFolderViewPrivate *priv;
685 GtkTreeSelection *sel;
687 g_return_if_fail (obj);
689 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(obj);
691 if (priv->timer_expander != 0) {
692 g_source_remove (priv->timer_expander);
693 priv->timer_expander = 0;
696 if (priv->account_store) {
697 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
698 priv->account_update_signal);
699 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
700 priv->accounts_reloaded_signal);
701 g_signal_handler_disconnect (G_OBJECT(priv->account_store),
702 priv->account_removed_signal);
703 g_object_unref (G_OBJECT(priv->account_store));
704 priv->account_store = NULL;
708 g_object_unref (G_OBJECT (priv->query));
712 if (priv->folder_to_select) {
713 g_object_unref (G_OBJECT(priv->folder_to_select));
714 priv->folder_to_select = NULL;
717 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(obj));
719 g_signal_handler_disconnect (G_OBJECT(sel), priv->changed_signal);
721 g_free (priv->local_account_name);
722 g_free (priv->visible_account_id);
724 if (priv->conf_key_signal) {
725 g_signal_handler_disconnect (modest_runtime_get_conf (),
726 priv->conf_key_signal);
727 priv->conf_key_signal = 0;
730 if (priv->cur_folder_store) {
731 if (TNY_IS_FOLDER(priv->cur_folder_store))
732 tny_folder_sync (TNY_FOLDER(priv->cur_folder_store), FALSE, NULL);
733 /* FALSE --> expunge the message */
735 g_object_unref (priv->cur_folder_store);
736 priv->cur_folder_store = NULL;
739 /* Clear hidding array created by cut operation */
740 _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
742 G_OBJECT_CLASS(parent_class)->finalize (obj);
747 modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore *account_store)
749 ModestFolderViewPrivate *priv;
752 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
753 g_return_if_fail (TNY_IS_ACCOUNT_STORE (account_store));
755 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
756 device = tny_account_store_get_device (account_store);
758 if (G_UNLIKELY (priv->account_store)) {
760 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
761 priv->account_update_signal))
762 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
763 priv->account_update_signal);
764 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
765 priv->accounts_reloaded_signal))
766 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
767 priv->accounts_reloaded_signal);
768 if (g_signal_handler_is_connected (G_OBJECT (priv->account_store),
769 priv->account_removed_signal))
770 g_signal_handler_disconnect (G_OBJECT (priv->account_store),
771 priv->account_removed_signal);
773 g_object_unref (G_OBJECT (priv->account_store));
776 priv->account_store = g_object_ref (G_OBJECT (account_store));
778 priv->account_update_signal =
779 g_signal_connect (G_OBJECT(account_store), "account_update",
780 G_CALLBACK (on_account_update), self);
782 priv->account_removed_signal =
783 g_signal_connect (G_OBJECT(account_store), "account_removed",
784 G_CALLBACK (on_account_removed), self);
786 priv->accounts_reloaded_signal =
787 g_signal_connect (G_OBJECT(account_store), "accounts_reloaded",
788 G_CALLBACK (on_accounts_reloaded), self);
790 g_signal_connect (G_OBJECT(account_store), "connecting_finished",
791 G_CALLBACK (on_accounts_reloaded), self);
793 on_accounts_reloaded (account_store, (gpointer ) self);
795 g_object_unref (G_OBJECT (device));
799 on_account_removed (TnyAccountStore *account_store,
803 ModestFolderView *self = MODEST_FOLDER_VIEW (user_data);
804 ModestFolderViewPrivate *priv;
806 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
808 /* If the removed account is the currently viewed one then
809 clear the configuration value. The new visible account will be the default account */
810 if (priv->visible_account_id &&
811 !strcmp (priv->visible_account_id, tny_account_get_id (account))) {
813 /* Clear the current visible account_id */
814 modest_folder_view_set_account_id_of_visible_server_account (self, NULL);
816 /* Call the restore method, this will set the new visible account */
817 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
818 MODEST_CONF_FOLDER_VIEW_KEY);
820 /* Select the INBOX */
821 modest_folder_view_select_first_inbox_or_local (self);
826 on_account_update (TnyAccountStore *account_store,
827 const gchar *account,
830 ModestFolderView *self = NULL;
831 ModestFolderViewPrivate *priv;
833 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
834 self = MODEST_FOLDER_VIEW (user_data);
835 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
837 /* If we're adding a new account, and there is no previous
838 one, we need to select the visible server account */
839 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
840 !priv->visible_account_id)
841 modest_widget_memory_restore (modest_runtime_get_conf(), G_OBJECT(self),
842 MODEST_CONF_FOLDER_VIEW_KEY);
844 if (!modest_folder_view_update_model (self, account_store))
845 g_printerr ("modest: failed to update model for changes in '%s'",
850 on_accounts_reloaded (TnyAccountStore *account_store,
853 g_return_if_fail (MODEST_IS_FOLDER_VIEW (user_data));
854 modest_folder_view_update_model (MODEST_FOLDER_VIEW (user_data), account_store);
858 modest_folder_view_set_title (ModestFolderView *self, const gchar *title)
860 GtkTreeViewColumn *col;
862 g_return_if_fail (self);
864 col = gtk_tree_view_get_column (GTK_TREE_VIEW(self), 0);
866 g_printerr ("modest: failed get column for title\n");
870 gtk_tree_view_column_set_title (col, title);
871 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(self),
876 modest_folder_view_on_map (ModestFolderView *self,
877 GdkEventExpose *event,
880 ModestFolderViewPrivate *priv;
882 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
884 /* This won't happen often */
885 if (G_UNLIKELY (priv->reselect)) {
886 /* Select the first inbox or the local account if not found */
888 /* TODO: this could cause a lock at startup, so we
889 comment it for the moment. We know that this will
890 be a bug, because the INBOX is not selected, but we
891 need to rewrite some parts of Modest to avoid the
892 deathlock situation */
893 /* TODO: check if this is still the case */
894 priv->reselect = FALSE;
895 modest_folder_view_select_first_inbox_or_local (self);
896 /* Notify the display name observers */
897 g_signal_emit (G_OBJECT(self),
898 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
905 modest_folder_view_new (TnyFolderStoreQuery *query)
908 ModestFolderViewPrivate *priv;
909 GtkTreeSelection *sel;
911 self = G_OBJECT (g_object_new (MODEST_TYPE_FOLDER_VIEW, NULL));
912 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
915 priv->query = g_object_ref (query);
917 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
918 priv->changed_signal = g_signal_connect (sel, "changed",
919 G_CALLBACK (on_selection_changed), self);
921 g_signal_connect (self, "expose-event", G_CALLBACK (modest_folder_view_on_map), NULL);
923 return GTK_WIDGET(self);
926 /* this feels dirty; any other way to expand all the root items? */
928 expand_root_items (ModestFolderView *self)
931 path = gtk_tree_path_new_first ();
933 /* all folders should have child items, so.. */
934 while (gtk_tree_view_expand_row (GTK_TREE_VIEW(self), path, FALSE))
935 gtk_tree_path_next (path);
937 gtk_tree_path_free (path);
941 * We use this function to implement the
942 * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
943 * account in this case, and the local folders.
946 filter_row (GtkTreeModel *model,
950 ModestFolderViewPrivate *priv;
951 gboolean retval = TRUE;
952 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
953 GObject *instance = NULL;
954 const gchar *id = NULL;
956 gboolean found = FALSE;
957 gboolean cleared = FALSE;
959 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE);
960 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data);
962 gtk_tree_model_get (model, iter,
963 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
964 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &instance,
967 /* Do not show if there is no instance, this could indeed
968 happen when the model is being modified while it's being
969 drawn. This could occur for example when moving folders
974 if (type == TNY_FOLDER_TYPE_ROOT) {
975 /* TNY_FOLDER_TYPE_ROOT means that the instance is an
976 account instead of a folder. */
977 if (TNY_IS_ACCOUNT (instance)) {
978 TnyAccount *acc = TNY_ACCOUNT (instance);
979 const gchar *account_id = tny_account_get_id (acc);
981 /* If it isn't a special folder,
982 * don't show it unless it is the visible account: */
983 if (priv->style == MODEST_FOLDER_VIEW_STYLE_SHOW_ONE &&
984 !modest_tny_account_is_virtual_local_folders (acc) &&
985 strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
987 /* Show only the visible account id */
988 if (priv->visible_account_id) {
989 if (strcmp (account_id, priv->visible_account_id))
996 /* Never show these to the user. They are merged into one folder
997 * in the local-folders account instead: */
998 if (retval && MODEST_IS_TNY_OUTBOX_ACCOUNT (acc))
1003 /* Check hiding (if necessary) */
1004 cleared = modest_email_clipboard_cleared (priv->clipboard);
1005 if ((retval) && (!cleared) && (TNY_IS_FOLDER (instance))) {
1006 id = tny_folder_get_id (TNY_FOLDER(instance));
1007 if (priv->hidding_ids != NULL)
1008 for (i=0; i < priv->n_selected && !found; i++)
1009 if (priv->hidding_ids[i] != NULL && id != NULL)
1010 found = (!strcmp (priv->hidding_ids[i], id));
1016 /* If this is a move to dialog, hide Sent, Outbox and Drafts
1017 folder as no message can be move there according to UI specs */
1018 if (!priv->show_non_move)
1022 case TNY_FOLDER_TYPE_OUTBOX:
1023 case TNY_FOLDER_TYPE_SENT:
1024 case TNY_FOLDER_TYPE_DRAFTS:
1027 case TNY_FOLDER_TYPE_UNKNOWN:
1028 case TNY_FOLDER_TYPE_NORMAL:
1029 type = modest_tny_folder_guess_folder_type(TNY_FOLDER(instance));
1030 if (type == TNY_FOLDER_TYPE_OUTBOX || type == TNY_FOLDER_TYPE_SENT
1031 || type == TNY_FOLDER_TYPE_DRAFTS)
1042 g_object_unref (instance);
1049 modest_folder_view_update_model (ModestFolderView *self,
1050 TnyAccountStore *account_store)
1052 ModestFolderViewPrivate *priv;
1053 GtkTreeModel *model /* , *old_model */;
1054 /* TnyAccount *local_account; */
1055 TnyList *model_as_list;
1057 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
1058 g_return_val_if_fail (account_store, FALSE);
1060 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1062 /* Notify that there is no folder selected */
1063 g_signal_emit (G_OBJECT(self),
1064 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1066 if (priv->cur_folder_store) {
1067 g_object_unref (priv->cur_folder_store);
1068 priv->cur_folder_store = NULL;
1071 /* FIXME: the local accounts are not shown when the query
1072 selects only the subscribed folders. */
1073 /* model = tny_gtk_folder_store_tree_model_new (TRUE, priv->query); */
1074 model = tny_gtk_folder_store_tree_model_new (TRUE, NULL);
1076 /* Deal with the model via its TnyList Interface,
1077 * filling the TnyList via a get_accounts() call: */
1078 model_as_list = TNY_LIST(model);
1080 /* Get the accounts: */
1081 tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store),
1083 TNY_ACCOUNT_STORE_STORE_ACCOUNTS);
1084 g_object_unref (model_as_list);
1085 model_as_list = NULL;
1087 GtkTreeModel *filter_model = NULL, *sortable = NULL;
1089 sortable = gtk_tree_model_sort_new_with_model (model);
1090 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(sortable),
1091 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1092 GTK_SORT_ASCENDING);
1093 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sortable),
1094 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN,
1095 cmp_rows, NULL, NULL);
1097 /* Create filter model */
1098 filter_model = gtk_tree_model_filter_new (sortable, NULL);
1099 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
1105 gtk_tree_view_set_model (GTK_TREE_VIEW(self), filter_model);
1106 g_signal_connect (G_OBJECT(filter_model), "row-changed",
1107 (GCallback)on_row_changed_maybe_select_folder, self);
1108 g_signal_connect (G_OBJECT(filter_model), "row-inserted",
1109 (GCallback)on_row_changed_maybe_select_folder, self);
1112 g_object_unref (model);
1113 g_object_unref (filter_model);
1114 g_object_unref (sortable);
1116 /* Force a reselection of the INBOX next time the widget is shown */
1117 priv->reselect = TRUE;
1124 on_selection_changed (GtkTreeSelection *sel, gpointer user_data)
1126 GtkTreeModel *model;
1127 TnyFolderStore *folder = NULL;
1129 ModestFolderView *tree_view;
1130 ModestFolderViewPrivate *priv;
1132 g_return_if_fail (sel);
1133 g_return_if_fail (user_data);
1135 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(user_data);
1137 if(!gtk_tree_selection_get_selected (sel, &model, &iter))
1140 /* Notify the display name observers */
1141 g_signal_emit (G_OBJECT(user_data),
1142 signals[FOLDER_DISPLAY_NAME_CHANGED_SIGNAL], 0,
1145 tree_view = MODEST_FOLDER_VIEW (user_data);
1146 gtk_tree_model_get (model, &iter,
1147 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder,
1150 /* If the folder is the same do not notify */
1151 if (priv->cur_folder_store == folder && folder) {
1152 g_object_unref (folder);
1156 /* Current folder was unselected */
1157 if (priv->cur_folder_store) {
1158 g_signal_emit (G_OBJECT(tree_view), signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0,
1159 priv->cur_folder_store, FALSE);
1161 if (TNY_IS_FOLDER(priv->cur_folder_store))
1162 tny_folder_sync_async (TNY_FOLDER(priv->cur_folder_store),
1163 FALSE, NULL, NULL, NULL);
1164 /* FALSE --> don't expunge the messages */
1166 g_object_unref (priv->cur_folder_store);
1167 priv->cur_folder_store = NULL;
1170 /* New current references */
1171 priv->cur_folder_store = folder;
1173 /* New folder has been selected */
1174 g_signal_emit (G_OBJECT(tree_view),
1175 signals[FOLDER_SELECTION_CHANGED_SIGNAL],
1176 0, priv->cur_folder_store, TRUE);
1180 modest_folder_view_get_selected (ModestFolderView *self)
1182 ModestFolderViewPrivate *priv;
1184 g_return_val_if_fail (self, NULL);
1186 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1187 if (priv->cur_folder_store)
1188 g_object_ref (priv->cur_folder_store);
1190 return priv->cur_folder_store;
1194 get_cmp_rows_type_pos (GObject *folder)
1196 /* Remote accounts -> Local account -> MMC account .*/
1199 if (TNY_IS_ACCOUNT (folder) &&
1200 modest_tny_account_is_virtual_local_folders (
1201 TNY_ACCOUNT (folder))) {
1203 } else if (TNY_IS_ACCOUNT (folder)) {
1204 TnyAccount *account = TNY_ACCOUNT (folder);
1205 const gchar *account_id = tny_account_get_id (account);
1206 if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID))
1212 printf ("DEBUG: %s: unexpected type.\n", __FUNCTION__);
1213 return -1; /* Should never happen */
1218 get_cmp_subfolder_type_pos (TnyFolderType t)
1220 /* Inbox, Outbox, Drafts, Sent, User */
1224 case TNY_FOLDER_TYPE_INBOX:
1227 case TNY_FOLDER_TYPE_OUTBOX:
1230 case TNY_FOLDER_TYPE_DRAFTS:
1233 case TNY_FOLDER_TYPE_SENT:
1242 * This function orders the mail accounts according to these rules:
1243 * 1st - remote accounts
1244 * 2nd - local account
1248 cmp_rows (GtkTreeModel *tree_model, GtkTreeIter *iter1, GtkTreeIter *iter2,
1252 gchar *name1 = NULL;
1253 gchar *name2 = NULL;
1254 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
1255 TnyFolderType type2 = TNY_FOLDER_TYPE_UNKNOWN;
1256 GObject *folder1 = NULL;
1257 GObject *folder2 = NULL;
1259 gtk_tree_model_get (tree_model, iter1,
1260 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name1,
1261 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
1262 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder1,
1264 gtk_tree_model_get (tree_model, iter2,
1265 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name2,
1266 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type2,
1267 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &folder2,
1270 /* Return if we get no folder. This could happen when folder
1271 operations are happening. The model is updated after the
1272 folder copy/move actually occurs, so there could be
1273 situations where the model to be drawn is not correct */
1274 if (!folder1 || !folder2)
1277 if (type == TNY_FOLDER_TYPE_ROOT) {
1278 /* Compare the types, so that
1279 * Remote accounts -> Local account -> MMC account .*/
1280 const gint pos1 = get_cmp_rows_type_pos (folder1);
1281 const gint pos2 = get_cmp_rows_type_pos (folder2);
1282 /* printf ("DEBUG: %s:\n type1=%s, pos1=%d\n type2=%s, pos2=%d\n",
1283 __FUNCTION__, G_OBJECT_TYPE_NAME(folder1), pos1, G_OBJECT_TYPE_NAME(folder2), pos2); */
1286 else if (pos1 > pos2)
1289 /* Compare items of the same type: */
1291 TnyAccount *account1 = NULL;
1292 if (TNY_IS_ACCOUNT (folder1))
1293 account1 = TNY_ACCOUNT (folder1);
1295 TnyAccount *account2 = NULL;
1296 if (TNY_IS_ACCOUNT (folder2))
1297 account2 = TNY_ACCOUNT (folder2);
1299 const gchar *account_id = account1 ? tny_account_get_id (account1) : NULL;
1300 const gchar *account_id2 = account2 ? tny_account_get_id (account2) : NULL;
1302 if (!account_id && !account_id2) {
1304 } else if (!account_id) {
1306 } else if (!account_id2) {
1308 } else if (!strcmp (account_id, MODEST_MMC_ACCOUNT_ID)) {
1311 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1315 gint cmp1 = 0, cmp2 = 0;
1316 /* get the parent to know if it's a local folder */
1319 gboolean has_parent;
1320 has_parent = gtk_tree_model_iter_parent (tree_model, &parent, iter1);
1322 GObject *parent_folder;
1323 TnyFolderType parent_type = TNY_FOLDER_TYPE_UNKNOWN;
1324 gtk_tree_model_get (tree_model, &parent,
1325 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &parent_type,
1326 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &parent_folder,
1328 if ((parent_type == TNY_FOLDER_TYPE_ROOT) &&
1329 TNY_IS_ACCOUNT (parent_folder) &&
1330 modest_tny_account_is_virtual_local_folders (TNY_ACCOUNT (parent_folder))) {
1331 cmp1 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (folder1)));
1332 cmp2 = get_cmp_subfolder_type_pos (modest_tny_folder_get_local_or_mmc_folder_type (TNY_FOLDER (folder2)));
1334 g_object_unref (parent_folder);
1337 /* if they are not local folders */
1339 cmp1 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder1)));
1340 cmp2 = get_cmp_subfolder_type_pos (tny_folder_get_folder_type (TNY_FOLDER (folder2)));
1344 cmp = modest_text_utils_utf8_strcmp (name1, name2, TRUE);
1346 cmp = (cmp1 - cmp2);
1351 g_object_unref(G_OBJECT(folder1));
1353 g_object_unref(G_OBJECT(folder2));
1361 /*****************************************************************************/
1362 /* DRAG and DROP stuff */
1363 /*****************************************************************************/
1366 * This function fills the #GtkSelectionData with the row and the
1367 * model that has been dragged. It's called when this widget is a
1368 * source for dnd after the event drop happened
1371 on_drag_data_get (GtkWidget *widget,
1372 GdkDragContext *context,
1373 GtkSelectionData *selection_data,
1378 GtkTreeSelection *selection;
1379 GtkTreeModel *model;
1381 GtkTreePath *source_row;
1383 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
1384 gtk_tree_selection_get_selected (selection, &model, &iter);
1385 source_row = gtk_tree_model_get_path (model, &iter);
1387 gtk_tree_set_row_drag_data (selection_data,
1391 gtk_tree_path_free (source_row);
1394 typedef struct _DndHelper {
1395 gboolean delete_source;
1396 GtkTreePath *source_row;
1397 GdkDragContext *context;
1403 * This function is the callback of the
1404 * modest_mail_operation_xfer_msgs () and
1405 * modest_mail_operation_xfer_folder() calls. We check here if the
1406 * message/folder was correctly asynchronously transferred. The reason
1407 * to use the same callback is that the code is the same, it only has
1408 * to check that the operation went fine and then finalize the drag
1412 on_progress_changed (ModestMailOperation *mail_op,
1413 ModestMailOperationState *state,
1419 helper = (DndHelper *) user_data;
1421 if (!state->finished)
1424 if (state->status == MODEST_MAIL_OPERATION_STATUS_SUCCESS) {
1430 /* Notify the drag source. Never call delete, the monitor will
1431 do the job if needed */
1432 gtk_drag_finish (helper->context, success, FALSE, helper->time);
1434 /* Free the helper */
1435 gtk_tree_path_free (helper->source_row);
1436 g_slice_free (DndHelper, helper);
1440 * This function is used by drag_data_received_cb to manage drag and
1441 * drop of a header, i.e, and drag from the header view to the folder
1445 drag_and_drop_from_header_view (GtkTreeModel *source_model,
1446 GtkTreeModel *dest_model,
1447 GtkTreePath *dest_row,
1450 TnyList *headers = NULL;
1451 TnyHeader *header = NULL;
1452 TnyFolder *folder = NULL;
1453 ModestMailOperation *mail_op = NULL;
1454 GtkTreeIter source_iter, dest_iter;
1456 g_return_if_fail (GTK_IS_TREE_MODEL(source_model));
1457 g_return_if_fail (GTK_IS_TREE_MODEL(dest_model));
1458 g_return_if_fail (dest_row);
1459 g_return_if_fail (helper);
1462 gtk_tree_model_get_iter (source_model, &source_iter, helper->source_row);
1463 gtk_tree_model_get (source_model, &source_iter,
1464 TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN,
1466 if (!TNY_IS_HEADER(header)) {
1467 g_warning ("BUG: %s could not get a valid header", __FUNCTION__);
1472 gtk_tree_model_get_iter (dest_model, &dest_iter, dest_row);
1473 gtk_tree_model_get (dest_model, &dest_iter,
1474 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1477 if (!TNY_IS_FOLDER(folder)) {
1478 g_warning ("BUG: %s could not get a valid folder", __FUNCTION__);
1482 /* Transfer message */
1483 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1485 modest_ui_actions_move_folder_error_handler,
1487 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1489 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1490 G_CALLBACK (on_progress_changed), helper);
1492 headers = tny_simple_list_new ();
1493 tny_list_append (headers, G_OBJECT (header));
1494 modest_mail_operation_xfer_msgs (mail_op,
1497 helper->delete_source,
1502 if (G_IS_OBJECT(mail_op))
1503 g_object_unref (G_OBJECT (mail_op));
1504 if (G_IS_OBJECT(header))
1505 g_object_unref (G_OBJECT (header));
1506 if (G_IS_OBJECT(folder))
1507 g_object_unref (G_OBJECT (folder));
1508 if (G_IS_OBJECT(headers))
1509 g_object_unref (headers);
1513 * This function is used by drag_data_received_cb to manage drag and
1514 * drop of a folder, i.e, and drag from the folder view to the same
1518 drag_and_drop_from_folder_view (GtkTreeModel *source_model,
1519 GtkTreeModel *dest_model,
1520 GtkTreePath *dest_row,
1521 GtkSelectionData *selection_data,
1524 ModestMailOperation *mail_op = NULL;
1525 GtkTreeIter parent_iter, iter;
1526 TnyFolderStore *parent_folder = NULL;
1527 TnyFolder *folder = NULL;
1529 /* Check if the drag is possible */
1530 /* if (!gtk_tree_path_compare (helper->source_row, dest_row) || */
1531 /* !gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (dest_model), */
1533 /* selection_data)) { */
1534 if (!gtk_tree_path_compare (helper->source_row, dest_row)) {
1536 gtk_drag_finish (helper->context, FALSE, FALSE, helper->time);
1537 gtk_tree_path_free (helper->source_row);
1538 g_slice_free (DndHelper, helper);
1543 gtk_tree_model_get_iter (source_model, &parent_iter, dest_row);
1544 gtk_tree_model_get_iter (source_model, &iter, helper->source_row);
1545 gtk_tree_model_get (source_model, &parent_iter,
1546 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1547 &parent_folder, -1);
1548 gtk_tree_model_get (source_model, &iter,
1549 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN,
1552 /* Offer the connection dialog if necessary, for the destination parent folder and source folder: */
1553 if (modest_platform_connect_and_wait_if_network_folderstore (NULL, parent_folder) &&
1554 modest_platform_connect_and_wait_if_network_folderstore (NULL, TNY_FOLDER_STORE (folder))) {
1555 /* Do the mail operation */
1556 mail_op = modest_mail_operation_new_with_error_handling (MODEST_MAIL_OPERATION_TYPE_RECEIVE,
1558 modest_ui_actions_move_folder_error_handler,
1560 modest_mail_operation_queue_add (modest_runtime_get_mail_operation_queue (),
1562 g_signal_connect (G_OBJECT (mail_op), "progress-changed",
1563 G_CALLBACK (on_progress_changed), helper);
1565 modest_mail_operation_xfer_folder (mail_op,
1568 helper->delete_source,
1572 g_object_unref (G_OBJECT (mail_op));
1576 g_object_unref (G_OBJECT (parent_folder));
1577 g_object_unref (G_OBJECT (folder));
1581 * This function receives the data set by the "drag-data-get" signal
1582 * handler. This information comes within the #GtkSelectionData. This
1583 * function will manage both the drags of folders of the treeview and
1584 * drags of headers of the header view widget.
1587 on_drag_data_received (GtkWidget *widget,
1588 GdkDragContext *context,
1591 GtkSelectionData *selection_data,
1596 GtkWidget *source_widget;
1597 GtkTreeModel *dest_model, *source_model;
1598 GtkTreePath *source_row, *dest_row;
1599 GtkTreeViewDropPosition pos;
1600 gboolean success = FALSE, delete_source = FALSE;
1601 DndHelper *helper = NULL;
1603 /* Do not allow further process */
1604 g_signal_stop_emission_by_name (widget, "drag-data-received");
1605 source_widget = gtk_drag_get_source_widget (context);
1607 /* Get the action */
1608 if (context->action == GDK_ACTION_MOVE) {
1609 delete_source = TRUE;
1611 /* Notify that there is no folder selected. We need to
1612 do this in order to update the headers view (and
1613 its monitors, because when moving, the old folder
1614 won't longer exist. We can not wait for the end of
1615 the operation, because the operation won't start if
1616 the folder is in use */
1617 if (source_widget == widget) {
1618 ModestFolderViewPrivate *priv;
1620 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1621 if (priv->cur_folder_store) {
1622 g_object_unref (priv->cur_folder_store);
1623 priv->cur_folder_store = NULL;
1626 g_signal_emit (G_OBJECT (widget),
1627 signals[FOLDER_SELECTION_CHANGED_SIGNAL], 0, NULL, FALSE);
1631 /* Check if the get_data failed */
1632 if (selection_data == NULL || selection_data->length < 0)
1633 gtk_drag_finish (context, success, FALSE, time);
1635 /* Get the models */
1636 gtk_tree_get_row_drag_data (selection_data,
1640 /* Select the destination model */
1641 if (source_widget == widget) {
1642 dest_model = source_model;
1644 dest_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
1647 /* Get the path to the destination row. Can not call
1648 gtk_tree_view_get_drag_dest_row() because the source row
1649 is not selected anymore */
1650 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget), x, y,
1653 /* Only allow drops IN other rows */
1654 if (!dest_row || pos == GTK_TREE_VIEW_DROP_BEFORE || pos == GTK_TREE_VIEW_DROP_AFTER)
1655 gtk_drag_finish (context, success, FALSE, time);
1657 /* Create the helper */
1658 helper = g_slice_new0 (DndHelper);
1659 helper->delete_source = delete_source;
1660 helper->source_row = gtk_tree_path_copy (source_row);
1661 helper->context = context;
1662 helper->time = time;
1664 /* Drags from the header view */
1665 if (source_widget != widget) {
1667 drag_and_drop_from_header_view (source_model,
1674 drag_and_drop_from_folder_view (source_model,
1682 gtk_tree_path_free (source_row);
1683 gtk_tree_path_free (dest_row);
1687 * We define a "drag-drop" signal handler because we do not want to
1688 * use the default one, because the default one always calls
1689 * gtk_drag_finish and we prefer to do it in the "drag-data-received"
1690 * signal handler, because there we have all the information available
1691 * to know if the dnd was a success or not.
1694 drag_drop_cb (GtkWidget *widget,
1695 GdkDragContext *context,
1703 if (!context->targets)
1706 /* Check if we're dragging a folder row */
1707 target = gtk_drag_dest_find_target (widget, context, NULL);
1709 /* Request the data from the source. */
1710 gtk_drag_get_data(widget, context, target, time);
1716 * This function expands a node of a tree view if it's not expanded
1717 * yet. Not sure why it needs the threads stuff, but gtk+`example code
1718 * does that, so that's why they're here.
1721 expand_row_timeout (gpointer data)
1723 GtkTreeView *tree_view = data;
1724 GtkTreePath *dest_path = NULL;
1725 GtkTreeViewDropPosition pos;
1726 gboolean result = FALSE;
1728 GDK_THREADS_ENTER ();
1730 gtk_tree_view_get_drag_dest_row (tree_view,
1735 (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
1736 pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)) {
1737 gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
1738 gtk_tree_path_free (dest_path);
1742 gtk_tree_path_free (dest_path);
1747 GDK_THREADS_LEAVE ();
1753 * This function is called whenever the pointer is moved over a widget
1754 * while dragging some data. It installs a timeout that will expand a
1755 * node of the treeview if not expanded yet. This function also calls
1756 * gdk_drag_status in order to set the suggested action that will be
1757 * used by the "drag-data-received" signal handler to know if we
1758 * should do a move or just a copy of the data.
1761 on_drag_motion (GtkWidget *widget,
1762 GdkDragContext *context,
1768 GtkTreeViewDropPosition pos;
1769 GtkTreePath *dest_row;
1770 ModestFolderViewPrivate *priv;
1771 GdkDragAction suggested_action;
1772 gboolean valid_location = FALSE;
1774 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (widget);
1776 if (priv->timer_expander != 0) {
1777 g_source_remove (priv->timer_expander);
1778 priv->timer_expander = 0;
1781 gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW (widget),
1786 /* Do not allow drops between folders */
1788 pos == GTK_TREE_VIEW_DROP_BEFORE ||
1789 pos == GTK_TREE_VIEW_DROP_AFTER) {
1790 gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW (widget), NULL, 0);
1791 gdk_drag_status(context, 0, time);
1792 valid_location = FALSE;
1795 valid_location = TRUE;
1798 /* Expand the selected row after 1/2 second */
1799 if (!gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), dest_row)) {
1800 gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), dest_row, pos);
1801 priv->timer_expander = g_timeout_add (500, expand_row_timeout, widget);
1804 /* Select the desired action. By default we pick MOVE */
1805 suggested_action = GDK_ACTION_MOVE;
1807 if (context->actions == GDK_ACTION_COPY)
1808 gdk_drag_status(context, GDK_ACTION_COPY, time);
1809 else if (context->actions == GDK_ACTION_MOVE)
1810 gdk_drag_status(context, GDK_ACTION_MOVE, time);
1811 else if (context->actions & suggested_action)
1812 gdk_drag_status(context, suggested_action, time);
1814 gdk_drag_status(context, GDK_ACTION_DEFAULT, time);
1818 gtk_tree_path_free (dest_row);
1819 g_signal_stop_emission_by_name (widget, "drag-motion");
1820 return valid_location;
1824 /* Folder view drag types */
1825 const GtkTargetEntry folder_view_drag_types[] =
1827 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, MODEST_FOLDER_ROW },
1828 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW }
1832 * This function sets the treeview as a source and a target for dnd
1833 * events. It also connects all the requirede signals.
1836 setup_drag_and_drop (GtkTreeView *self)
1838 /* Set up the folder view as a dnd destination. Set only the
1839 highlight flag, otherwise gtk will have a different
1841 gtk_drag_dest_set (GTK_WIDGET (self),
1842 GTK_DEST_DEFAULT_HIGHLIGHT,
1843 folder_view_drag_types,
1844 G_N_ELEMENTS (folder_view_drag_types),
1845 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1847 g_signal_connect (G_OBJECT (self),
1848 "drag_data_received",
1849 G_CALLBACK (on_drag_data_received),
1853 /* Set up the treeview as a dnd source */
1854 gtk_drag_source_set (GTK_WIDGET (self),
1856 folder_view_drag_types,
1857 G_N_ELEMENTS (folder_view_drag_types),
1858 GDK_ACTION_MOVE | GDK_ACTION_COPY);
1860 g_signal_connect (G_OBJECT (self),
1862 G_CALLBACK (on_drag_motion),
1865 g_signal_connect (G_OBJECT (self),
1867 G_CALLBACK (on_drag_data_get),
1870 g_signal_connect (G_OBJECT (self),
1872 G_CALLBACK (drag_drop_cb),
1877 * This function manages the navigation through the folders using the
1878 * keyboard or the hardware keys in the device
1881 on_key_pressed (GtkWidget *self,
1885 GtkTreeSelection *selection;
1887 GtkTreeModel *model;
1888 gboolean retval = FALSE;
1890 /* Up and Down are automatically managed by the treeview */
1891 if (event->keyval == GDK_Return) {
1892 /* Expand/Collapse the selected row */
1893 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
1894 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
1897 path = gtk_tree_model_get_path (model, &iter);
1899 if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (self), path))
1900 gtk_tree_view_collapse_row (GTK_TREE_VIEW (self), path);
1902 gtk_tree_view_expand_row (GTK_TREE_VIEW (self), path, FALSE);
1903 gtk_tree_path_free (path);
1905 /* No further processing */
1913 * We listen to the changes in the local folder account name key,
1914 * because we want to show the right name in the view. The local
1915 * folder account name corresponds to the device name in the Maemo
1916 * version. We do this because we do not want to query gconf on each
1917 * tree view refresh. It's better to cache it and change whenever
1921 on_configuration_key_changed (ModestConf* conf,
1923 ModestConfEvent event,
1924 ModestFolderView *self)
1926 ModestFolderViewPrivate *priv;
1931 g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
1932 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1934 if (!strcmp (key, MODEST_CONF_DEVICE_NAME)) {
1935 g_free (priv->local_account_name);
1937 if (event == MODEST_CONF_EVENT_KEY_UNSET)
1938 priv->local_account_name = g_strdup (MODEST_LOCAL_FOLDERS_DEFAULT_DISPLAY_NAME);
1940 priv->local_account_name = modest_conf_get_string (modest_runtime_get_conf(),
1941 MODEST_CONF_DEVICE_NAME, NULL);
1943 /* Force a redraw */
1944 #if GTK_CHECK_VERSION(2, 8, 0) /* gtk_tree_view_column_queue_resize is only available in GTK+ 2.8 */
1945 GtkTreeViewColumn * tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW (self),
1946 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN);
1947 gtk_tree_view_column_queue_resize (tree_column);
1953 modest_folder_view_set_style (ModestFolderView *self,
1954 ModestFolderViewStyle style)
1956 ModestFolderViewPrivate *priv;
1958 g_return_if_fail (self);
1960 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1962 priv->style = style;
1966 modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *self,
1967 const gchar *account_id)
1969 ModestFolderViewPrivate *priv;
1970 GtkTreeModel *model;
1972 g_return_if_fail (self);
1974 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
1976 /* This will be used by the filter_row callback,
1977 * to decided which rows to show: */
1978 if (priv->visible_account_id) {
1979 g_free (priv->visible_account_id);
1980 priv->visible_account_id = NULL;
1983 priv->visible_account_id = g_strdup (account_id);
1986 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
1987 if (GTK_IS_TREE_MODEL_FILTER (model))
1988 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
1990 /* Save settings to gconf */
1991 modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
1992 MODEST_CONF_FOLDER_VIEW_KEY);
1996 modest_folder_view_get_account_id_of_visible_server_account (ModestFolderView *self)
1998 ModestFolderViewPrivate *priv;
2000 g_return_val_if_fail (self, NULL);
2002 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(self);
2004 return (const gchar *) priv->visible_account_id;
2008 find_inbox_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *inbox_iter)
2012 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2015 gtk_tree_model_get (model, iter,
2016 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2017 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN,
2020 gboolean result = FALSE;
2021 if (type == TNY_FOLDER_TYPE_INBOX) {
2023 } else if (type == TNY_FOLDER_TYPE_NORMAL) {
2024 /* tinymail's camel implementation only provides TNY_FOLDER_TYPE_NORMAL
2025 * when getting folders from the cache, before connectin, so we do
2026 * an extra check. We could fix this in tinymail, but it's easier
2029 if (strcmp (name, "Inbox") == 0)
2036 *inbox_iter = *iter;
2040 if (gtk_tree_model_iter_children (model, &child, iter)) {
2041 if (find_inbox_iter (model, &child, inbox_iter))
2045 } while (gtk_tree_model_iter_next (model, iter));
2054 modest_folder_view_select_first_inbox_or_local (ModestFolderView *self)
2056 GtkTreeModel *model;
2057 GtkTreeIter iter, inbox_iter;
2058 GtkTreeSelection *sel;
2060 /* /\* Do not set it if the folder view was not painted *\/ */
2061 /* if (!GTK_WIDGET_MAPPED (self)) */
2064 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2068 expand_root_items (self);
2069 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2071 gtk_tree_model_get_iter_first (model, &iter);
2072 gtk_tree_selection_unselect_all (sel);
2074 if (find_inbox_iter (model, &iter, &inbox_iter)) {
2075 gtk_tree_selection_select_iter (sel, &inbox_iter);
2078 gtk_tree_model_get_iter_first (model, &iter);
2079 gtk_tree_selection_select_iter (sel, &iter);
2086 find_folder_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *folder_iter,
2091 TnyFolderType type = TNY_FOLDER_TYPE_UNKNOWN;
2092 TnyFolder* a_folder;
2095 gtk_tree_model_get (model, iter,
2096 TNY_GTK_FOLDER_STORE_TREE_MODEL_INSTANCE_COLUMN, &a_folder,
2097 TNY_GTK_FOLDER_STORE_TREE_MODEL_NAME_COLUMN, &name,
2098 TNY_GTK_FOLDER_STORE_TREE_MODEL_TYPE_COLUMN, &type,
2101 g_debug ("===> %s (%p ---- %p)", name, a_folder, folder);
2104 if (folder == a_folder) {
2105 g_object_unref (a_folder);
2106 *folder_iter = *iter;
2109 g_object_unref (a_folder);
2111 if (gtk_tree_model_iter_children (model, &child, iter)) {
2112 if (find_folder_iter (model, &child, folder_iter, folder))
2116 } while (gtk_tree_model_iter_next (model, iter));
2123 on_row_changed_maybe_select_folder (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter,
2124 ModestFolderView *self)
2126 ModestFolderViewPrivate *priv = NULL;
2127 GtkTreeSelection *sel;
2129 if (!MODEST_IS_FOLDER_VIEW(self))
2132 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2134 if (priv->folder_to_select) {
2136 if (!modest_folder_view_select_folder (self, priv->folder_to_select,
2139 path = gtk_tree_model_get_path (tree_model, iter);
2140 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2142 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2144 gtk_tree_selection_select_iter (sel, iter);
2145 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2147 gtk_tree_path_free (path);
2150 g_object_unref (priv->folder_to_select);
2151 priv->folder_to_select = NULL;
2157 modest_folder_view_select_folder (ModestFolderView *self, TnyFolder *folder,
2158 gboolean after_change)
2160 GtkTreeModel *model;
2161 GtkTreeIter iter, folder_iter;
2162 GtkTreeSelection *sel;
2163 ModestFolderViewPrivate *priv = NULL;
2165 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
2166 g_return_val_if_fail (TNY_IS_FOLDER (folder), FALSE);
2168 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
2172 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2173 gtk_tree_selection_unselect_all (sel);
2175 if (priv->folder_to_select)
2176 g_object_unref(priv->folder_to_select);
2177 priv->folder_to_select = TNY_FOLDER(g_object_ref(folder));
2181 model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
2186 gtk_tree_model_get_iter_first (model, &iter);
2187 if (find_folder_iter (model, &iter, &folder_iter, folder)) {
2190 path = gtk_tree_model_get_path (model, &folder_iter);
2191 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(self), path);
2193 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
2194 gtk_tree_selection_select_iter (sel, &folder_iter);
2195 gtk_tree_view_set_cursor (GTK_TREE_VIEW(self), path, NULL, FALSE);
2197 gtk_tree_path_free (path);
2205 modest_folder_view_copy_selection (ModestFolderView *folder_view)
2207 /* Copy selection */
2208 _clipboard_set_selected_data (folder_view, FALSE);
2212 modest_folder_view_cut_selection (ModestFolderView *folder_view)
2214 ModestFolderViewPrivate *priv = NULL;
2215 GtkTreeModel *model = NULL;
2216 const gchar **hidding = NULL;
2217 guint i, n_selected;
2219 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2220 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2222 /* Copy selection */
2223 if (!_clipboard_set_selected_data (folder_view, TRUE))
2226 /* Get hidding ids */
2227 hidding = modest_email_clipboard_get_hidding_ids (priv->clipboard, &n_selected);
2229 /* Clear hidding array created by previous cut operation */
2230 _clear_hidding_filter (MODEST_FOLDER_VIEW (folder_view));
2232 /* Copy hidding array */
2233 priv->n_selected = n_selected;
2234 priv->hidding_ids = g_malloc0(sizeof(gchar *) * n_selected);
2235 for (i=0; i < n_selected; i++)
2236 priv->hidding_ids[i] = g_strdup(hidding[i]);
2238 /* Hide cut folders */
2239 model = gtk_tree_view_get_model (GTK_TREE_VIEW (folder_view));
2240 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
2244 modest_folder_view_show_non_move_folders (ModestFolderView *folder_view,
2247 ModestFolderViewPrivate* priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2248 priv->show_non_move = show;
2249 modest_folder_view_update_model(folder_view,
2250 TNY_ACCOUNT_STORE(modest_runtime_get_account_store()));
2253 /* Returns FALSE if it did not selected anything */
2255 _clipboard_set_selected_data (ModestFolderView *folder_view,
2258 ModestFolderViewPrivate *priv = NULL;
2259 TnyFolderStore *folder = NULL;
2260 gboolean retval = FALSE;
2262 g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (folder_view), FALSE);
2263 priv = MODEST_FOLDER_VIEW_GET_PRIVATE (folder_view);
2265 /* Set selected data on clipboard */
2266 g_return_val_if_fail (MODEST_IS_EMAIL_CLIPBOARD (priv->clipboard), FALSE);
2267 folder = modest_folder_view_get_selected (folder_view);
2269 /* Do not allow to select an account */
2270 if (TNY_IS_FOLDER (folder)) {
2271 modest_email_clipboard_set_data (priv->clipboard, TNY_FOLDER(folder), NULL, delete);
2276 g_object_unref (folder);
2282 _clear_hidding_filter (ModestFolderView *folder_view)
2284 ModestFolderViewPrivate *priv;
2287 g_return_if_fail (MODEST_IS_FOLDER_VIEW (folder_view));
2288 priv = MODEST_FOLDER_VIEW_GET_PRIVATE(folder_view);
2290 if (priv->hidding_ids != NULL) {
2291 for (i=0; i < priv->n_selected; i++)
2292 g_free (priv->hidding_ids[i]);
2293 g_free(priv->hidding_ids);